iOS 使用GPUImage為本地視訊新增濾鏡
阿新 • • 發佈:2019-02-14
這裡介紹使用GPUImage為本地視訊新增濾鏡,下面會對GPUImage使用過程進行介紹並說明一些需要注意的東西:
工程中需要的檔案可以到文章最後連結下載
首先把gpuimage.a和放置GPUImage標頭檔案的資料夾usr新增到專案中
然後需要在info.plist檔案中新增鍵值獲取照片庫訪問許可權:
NSPhotoLibraryUsageDescription
是否允許此App訪問你的媒體資料庫?
然後匯入 AssetsLibrary框架
這裡是獲取了系統照片庫第一個視訊檔案,所以執行的時候記得隨便錄製一個視訊檔案在系統照片庫
獲取GPUImage標頭檔案的引用
import GPUImage.h
下面介紹主要使用到的內容
GPUImageMovie 接收需要新增濾鏡的視訊
GPUImageView 預覽視訊效果
GPUImageOutput 視訊輸入輸出配置,這裡承載濾鏡
GPUImageMovieWriter 新增濾鏡及輸出視訊
//
// ViewController.m
// VideoFilterText
//
//
#import "ViewController.h"
#import "GPUImage.h"
#import <AssetsLibrary/AssetsLibrary.h>
#define WIDTH [UIScreen mainScreen].bounds.size.width
#define HEIGHT [UIScreen mainScreen].bounds.size.height
#define WINDOW [[UIApplication sharedApplication] keyWindow]
@interface ViewController ()
@property (nonatomic,strong)GPUImageMovie * gpuMovie;//接管視訊資料
@property (nonatomic,strong)GPUImageView * gpuView;//預覽視訊內容
@property (nonatomic ,strong)GPUImageOutput<GPUImageInput> * pixellateFilter;//視訊濾鏡
@property (nonatomic,strong)GPUImageMovieWriter * movieWriter;//視訊處理輸出
@property (nonatomic,strong)UIScrollView * EditView;//濾鏡選擇檢視
@property (nonatomic,strong)NSArray * GPUImgArr;//存放濾鏡陣列
@property (nonatomic,copy)NSURL * filePath;//照片庫第一個視訊路徑
@property (nonatomic,copy)NSString * fileSavePath;//視訊合成後儲存路徑
@property (nonatomic,strong)NSMutableDictionary * dic;//存放上個濾鏡filter
@property (nonatomic,assign)NSTimer * timer;//設定計時器,因為重複合成同一個濾鏡時間會很長超時後重新建立
@property (nonatomic,assign)int timeNum;//記時時間
@property (nonatomic,strong)UIView * hudView;//載入框
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
_dic = [[NSMutableDictionary alloc]initWithDictionary:@{@"filter":@""}];
[self getVideoUrl];//獲取系統照片庫第一個視訊檔案
// Do any additional setup after loading the view, typically from a nib.
}
-(void)getVideoUrl{
NSString *tipTextWhenNoPhotosAuthorization; // 提示語
// 獲取當前應用對照片的訪問授權狀態
ALAuthorizationStatus authorizationStatus = [ALAssetsLibrary authorizationStatus];
// 如果沒有獲取訪問授權,或者訪問授權狀態已經被明確禁止,則顯示提示語,引導使用者開啟授權
if (authorizationStatus == ALAuthorizationStatusRestricted || authorizationStatus == ALAuthorizationStatusDenied) {
NSDictionary *mainInfoDictionary = [[NSBundle mainBundle] infoDictionary];
NSString *appName = [mainInfoDictionary objectForKey:@"CFBundleDisplayName"];
tipTextWhenNoPhotosAuthorization = [NSString stringWithFormat:@"請在裝置的\"設定-隱私-照片\"選項中,允許%@訪問你的手機相簿", appName];
// 展示提示語
}
ALAssetsLibrary *assetsLibrary = [[ALAssetsLibrary alloc] init];
[assetsLibrary enumerateGroupsWithTypes:ALAssetsGroupAll usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
if (group) {
[group setAssetsFilter:[ALAssetsFilter allVideos]];
if (group.numberOfAssets > 0) {
[group enumerateAssetsUsingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) {
static int i = 1;
if (i == 1) {
i++;
NSDateFormatter* dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setTimeZone:[NSTimeZone localTimeZone]];
[dateFormatter setDateFormat:@"yyyyMMddHHmmss"]; //注意時間的格式:MM表示月份,mm表示分鐘,HH用24小時制,小hh是12小時制。
NSString* dateString = [dateFormatter stringFromDate:[result valueForProperty:ALAssetPropertyDate]];
if (dateString) {
_filePath = result.defaultRepresentation.url;
[self createUI];
}
}
}];
}
}
} failureBlock:^(NSError *error) {
NSLog(@"Asset group not found!\n");
}];
}
-(void)createUI{
_gpuView = [[GPUImageView alloc]initWithFrame:CGRectMake(0, 0, WIDTH, HEIGHT-200)];
//設定展示頁面的旋轉
// [_gpuView setInputRotation:kGPUImageRotateRight atIndex:0];
[self.view addSubview:_gpuView];
NSLog(@"filePath = %@",_filePath);
_gpuMovie = [[GPUImageMovie alloc]initWithURL:_filePath];
_gpuMovie.shouldRepeat = YES;//迴圈
[_gpuMovie addTarget:_gpuView];
[_gpuMovie startProcessing];
[self createEditView];
UIButton * composeBtn = [UIButton buttonWithType:UIButtonTypeCustom];
composeBtn.frame = CGRectMake(30, HEIGHT-80, WIDTH-60, 40);
composeBtn.backgroundColor = [UIColor blackColor];
[composeBtn setTitle:@"合成" forState:UIControlStateNormal];
[composeBtn addTarget:self action:@selector(composeBtnClick:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:composeBtn];
}
#pragma mark ---------------------------選擇濾鏡----------------------------
-(void)effectImgClick:(UIButton *)button{
for (int i = 0 ; i<_GPUImgArr.count ;i++) {
UIButton *btn = [_EditView viewWithTag:1000+i];
btn.layer.borderWidth = 0;
btn.userInteractionEnabled = YES;
}
button.userInteractionEnabled = NO;
button.layer.borderWidth = 2;
button.layer.borderColor = [UIColor redColor].CGColor;
[_gpuMovie cancelProcessing];
[_gpuMovie removeAllTargets];
_gpuMovie = [[GPUImageMovie alloc]initWithURL:_filePath];
if (button.tag == 1000) {
_pixellateFilter = nil;
[_gpuMovie addTarget:_gpuView];
}else{
_pixellateFilter = (GPUImageOutput<GPUImageInput> *)[_GPUImgArr[button.tag-1000] objectForKey:@"filter"];
[_gpuMovie addTarget:_pixellateFilter];
[_pixellateFilter addTarget:_gpuView];
}
[_gpuMovie startProcessing];
}
#pragma mark ----------------------------合成視訊點選事件-------------------------
-(void)composeBtnClick:(UIButton *)btn{
NSLog(@"開始合成");
if ((_pixellateFilter == nil)|| (_pixellateFilter == _dic[@"filter"] )) {
NSLog(@"未選擇濾鏡、或者與上個濾鏡重複。請換個濾鏡");
}else{
[self createHudView];
_timeNum = 0;
_timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timeRun) userInfo:nil repeats:YES];
NSURL *movieURL = [NSURL fileURLWithPath:self.fileSavePath];
_movieWriter = [[GPUImageMovieWriter alloc] initWithMovieURL:movieURL size:CGSizeMake(WIDTH, WIDTH*744/720-30)];
[_pixellateFilter addTarget:_movieWriter];
_movieWriter.shouldPassthroughAudio = YES;
[_gpuMovie enableSynchronizedEncodingUsingMovieWriter:_movieWriter];
[_movieWriter startRecording];
__weak ViewController * weakSelf = self;
[_movieWriter setFailureBlock:^(NSError *error) {
NSLog(@"合成失敗 173:error = %@",error.description);
dispatch_async(dispatch_get_main_queue(), ^{
weakSelf.hudView.hidden = YES;
[weakSelf.pixellateFilter removeTarget:weakSelf.movieWriter];
[weakSelf.dic setObject:weakSelf.pixellateFilter forKey:@"filter"];
[weakSelf.movieWriter finishRecording];
[weakSelf.timer setFireDate:[NSDate distantFuture]];
});
}];
[_movieWriter setCompletionBlock:^{
NSLog(@"視訊合成結束: 188 ");
dispatch_async(dispatch_get_main_queue(), ^{
weakSelf.hudView.hidden = YES;
[weakSelf.pixellateFilter removeTarget:weakSelf.movieWriter];
[weakSelf.dic setObject:weakSelf.pixellateFilter forKey:@"filter"];
[weakSelf.movieWriter finishRecording];
[weakSelf.timer setFireDate:[NSDate distantFuture]];
});
}];
}
}
pragma mark -----------------------計時器--------------------------
-(void)timeRun{
_timeNum += 1;
if (_timeNum >= 60) {
NSLog(@"視訊處理超時");
[_timer invalidate];
_hudView.hidden = YES;
[self createUI];
}
}
#pragma mark -----------------------------建立載入框------------------------
-(void)createHudView{
if (!_hudView) {
_hudView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, WIDTH, HEIGHT)];
_hudView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.6];
UIView * huV = [[UIView alloc]initWithFrame:CGRectMake(WIDTH/2-50, HEIGHT/2-50, 100, 100)];
huV.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.6];
huV.layer.cornerRadius = 5;
huV.clipsToBounds = YES;
UIActivityIndicatorView * activityView = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
activityView.frame = CGRectMake(0, 0,huV.frame.size.width, huV.frame.size.height);
[activityView startAnimating];
[huV addSubview:activityView];
[_hudView addSubview:huV];
[WINDOW addSubview:_hudView];
}else{
_hudView.hidden = NO;
}
}
#pragma mark -----------------------------視訊存放位置------------------------
-(NSString *)fileSavePath{
NSFileManager* fileManager = [NSFileManager defaultManager];
NSString *pathDocuments = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *createPath = [NSString stringWithFormat:@"%@/myVidio/333.mp4", pathDocuments];//視訊存放位置
NSString *createPath2 = [NSString stringWithFormat:@"%@/myVidio", pathDocuments];//視訊存放資料夾
//判斷視訊檔案是否存在,存在刪除
BOOL blHave=[[NSFileManager defaultManager] fileExistsAtPath:createPath];
if (blHave) {
BOOL blDele= [fileManager removeItemAtPath:createPath error:nil];
if (!blDele) {
[fileManager removeItemAtPath:createPath error:nil];
}
}
//判斷視訊存放資料夾是否存在,不存在建立
BOOL blHave1=[[NSFileManager defaultManager] fileExistsAtPath:createPath2];
if (!blHave1) {
[fileManager createDirectoryAtPath:createPath2 withIntermediateDirectories:YES attributes:nil error:nil];
}
_fileSavePath = createPath;
NSLog(@"視訊輸出地址 fileSavePath = %@",_fileSavePath);
return _fileSavePath;
}
#pragma mark ---------------------------建立選擇濾鏡檢視----------------------------
-(void)createEditView{
_EditView = [[UIScrollView alloc]initWithFrame:CGRectMake(0, HEIGHT-190, WIDTH, 100)];
_EditView.showsVerticalScrollIndicator = NO;
AVURLAsset * myAsset = [AVURLAsset assetWithURL:_filePath];
//初始化AVAssetImageGenerator
AVAssetImageGenerator * imageGenerator = [AVAssetImageGenerator assetImageGeneratorWithAsset:myAsset];
imageGenerator.appliesPreferredTrackTransform = YES;
UIImage *inputImage = [[UIImage alloc]init];
// First image
//建立第一張預覽圖
CGImageRef halfWayImage = [imageGenerator copyCGImageAtTime:kCMTimeZero actualTime:nil error:nil];
if (halfWayImage != NULL) {
inputImage = [[UIImage alloc] initWithCGImage:halfWayImage];
}
_GPUImgArr = [self CreateGPUArr];
for (int i = 0; i<_GPUImgArr.count; i++) {
UIButton * effectImg = [UIButton buttonWithType:UIButtonTypeCustom];
effectImg.frame = CGRectMake(10+i*((WIDTH-10)/5), 10, (WIDTH-10)/5-10, (WIDTH-10)/5-10);
[effectImg setImage:inputImage forState:UIControlStateNormal];
if (i>0) {
GPUImageOutput<GPUImageInput> * disFilter = (GPUImageOutput<GPUImageInput> *)[_GPUImgArr[i] objectForKey:@"filter"];
//設定要渲染的區域
[disFilter useNextFrameForImageCapture];
//獲取資料來源
GPUImagePicture *stillImageSource = [[GPUImagePicture alloc]initWithImage:inputImage];
//新增上濾鏡
[stillImageSource addTarget:disFilter];
//開始渲染
[stillImageSource processImage];
//獲取渲染後的圖片
UIImage *newImage = [disFilter imageFromCurrentFramebuffer];
[effectImg setImage:newImage forState:UIControlStateNormal];
}
effectImg.layer.cornerRadius = ((WIDTH-10)/5-10)/2;
effectImg.layer.masksToBounds = YES;
effectImg.tag = 1000+i;
[effectImg addTarget:self action:@selector(effectImgClick:) forControlEvents:UIControlEventTouchUpInside];
if (i == 0) {
effectImg.layer.borderWidth = 2;
effectImg.layer.borderColor = [UIColor redColor].CGColor;
}
UILabel * effectName = [[UILabel alloc]initWithFrame:CGRectMake(effectImg.frame.origin.x, CGRectGetMaxY(effectImg.frame)+10, effectImg.frame.size.width, 20)];
effectName.textColor = [UIColor blackColor];
effectName.textAlignment = NSTextAlignmentCenter;
effectName.font = [UIFont systemFontOfSize:12];
effectName.text = _GPUImgArr[i][@"name"];
[_EditView addSubview:effectImg];
[_EditView addSubview:effectName];
_EditView.contentSize = CGSizeMake(_GPUImgArr.count*(WIDTH-10)/5+10, _EditView.frame.size.height);
}
[self.view addSubview:_EditView];
}
pragma mark ------------------------濾鏡陣列-----------------------
//濾鏡檔案很多,可以自行查詢,這裡為了方便只寫了下面幾個
-(NSArray *)CreateGPUArr{
NSMutableArray * arr = [[NSMutableArray alloc]init];
NSString * title0 = @"原圖";
NSDictionary * dic0 = [NSDictionary dictionaryWithObjectsAndKeys:@"",@"filter",title0,@"name", nil];
[arr addObject:dic0];
GPUImageOutput<GPUImageInput> * Filter5 = [[GPUImageGammaFilter alloc] init];
[(GPUImageGammaFilter *)Filter5 setGamma:1.5];
NSString * title5 = @"伽馬線";
NSDictionary * dic5 = [NSDictionary dictionaryWithObjectsAndKeys:Filter5,@"filter",title5,@"name", nil];
[arr addObject:dic5];
GPUImageOutput<GPUImageInput> * Filter6 = [[GPUImageColorInvertFilter alloc] init];
NSString * title6 = @"反色";
NSDictionary * dic6 = [NSDictionary dictionaryWithObjectsAndKeys:Filter6,@"filter",title6,@"name", nil];
[arr addObject:dic6];
GPUImageOutput<GPUImageInput> * Filter7 = [[GPUImageSepiaFilter alloc] init];
NSString * title7 = @"褐色懷舊";
NSDictionary * dic7 = [NSDictionary dictionaryWithObjectsAndKeys:Filter7,@"filter",title7,@"name", nil];
[arr addObject:dic7];
GPUImageOutput<GPUImageInput> * Filter8 = [[GPUImageGrayscaleFilter alloc] init];
NSString * title8 = @"灰度";
NSDictionary * dic8 = [NSDictionary dictionaryWithObjectsAndKeys:Filter8,@"filter",title8,@"name", nil];
[arr addObject:dic8];
GPUImageOutput<GPUImageInput> * Filter9 = [[GPUImageHistogramGenerator alloc] init];
NSString * title9 = @"色彩直方圖?";
NSDictionary * dic9 = [NSDictionary dictionaryWithObjectsAndKeys:Filter9,@"filter",title9,@"name", nil];
[arr addObject:dic9];
GPUImageOutput<GPUImageInput> * Filter10 = [[GPUImageRGBFilter alloc] init];
NSString * title10 = @"RGB";
[(GPUImageRGBFilter *)Filter10 setRed:0.8];
[(GPUImageRGBFilter *)Filter10 setGreen:0.3];
[(GPUImageRGBFilter *)Filter10 setBlue:0.5];
NSDictionary * dic10 = [NSDictionary dictionaryWithObjectsAndKeys:Filter10,@"filter",title10,@"name", nil];
[arr addObject:dic10];
GPUImageOutput<GPUImageInput> * Filter11 = [[GPUImageMonochromeFilter alloc] init];
[(GPUImageMonochromeFilter *)Filter11 setColorRed:0.3 green:0.5 blue:0.8];
NSString * title11 = @"單色";
NSDictionary * dic11 = [NSDictionary dictionaryWithObjectsAndKeys:Filter11,@"filter",title11,@"name", nil];
[arr addObject:dic11];
GPUImageOutput<GPUImageInput> * Filter12 = [[GPUImageBoxBlurFilter alloc] init];
// [(GPUImageMonochromeFilter *)Filter11 setColorRed:0.3 green:0.5 blue:0.8];
NSString * title12 = @"單色";
NSDictionary * dic12 = [NSDictionary dictionaryWithObjectsAndKeys:Filter12,@"filter",title12,@"name", nil];
[arr addObject:dic12];
GPUImageOutput<GPUImageInput> * Filter13 = [[GPUImageSobelEdgeDetectionFilter alloc] init];
// [(GPUImageSobelEdgeDetectionFilter *)Filter13 ];
NSString * title13 = @"漫畫反色";
NSDictionary * dic13 = [NSDictionary dictionaryWithObjectsAndKeys:Filter13,@"filter",title13,@"name", nil];
[arr addObject:dic13];
GPUImageOutput<GPUImageInput> * Filter14 = [[GPUImageXYDerivativeFilter alloc] init];
// [(GPUImageSobelEdgeDetectionFilter *)Filter13 ];
NSString * title14 = @"藍綠邊緣";
NSDictionary * dic14 = [NSDictionary dictionaryWithObjectsAndKeys:Filter14,@"filter",title14,@"name", nil];
[arr addObject:dic14];
GPUImageOutput<GPUImageInput> * Filter15 = [[GPUImageSketchFilter alloc] init];
// [(GPUImageSobelEdgeDetectionFilter *)Filter13 ];
NSString * title15 = @"素描";
NSDictionary * dic15 = [NSDictionary dictionaryWithObjectsAndKeys:Filter15,@"filter",title15,@"name", nil];
[arr addObject:dic15];
GPUImageOutput<GPUImageInput> * Filter16 = [[GPUImageSmoothToonFilter alloc] init];
// [(GPUImageSobelEdgeDetectionFilter *)Filter13 ];
NSString * title16 = @"卡通";
NSDictionary * dic16 = [NSDictionary dictionaryWithObjectsAndKeys:Filter16,@"filter",title16,@"name", nil];
[arr addObject:dic16];
GPUImageOutput<GPUImageInput> * Filter17 = [[GPUImageColorPackingFilter alloc] init];
// [(GPUImageSobelEdgeDetectionFilter *)Filter13 ];
NSString * title17 = @"監控";
NSDictionary * dic17 = [NSDictionary dictionaryWithObjectsAndKeys:Filter17,@"filter",title17,@"name", nil];
[arr addObject:dic17];
return arr;
}
@end