1. 程式人生 > >iOS 使用GPUImage為本地視訊新增濾鏡

iOS 使用GPUImage為本地視訊新增濾鏡

這裡介紹使用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