成人在线亚洲_国产日韩视频一区二区三区_久久久国产精品_99国内精品久久久久久久

您的位置:首頁技術(shù)文章
文章詳情頁

在iOS中給視頻添加濾鏡的方法示例

瀏覽:2日期:2022-09-17 10:54:50

「眾所周知,視頻可以 P」,今天我們來學(xué)習(xí)怎么給視頻添加濾鏡。

在 iOS 中,對視頻進(jìn)行圖像處理一般有兩種方式: GPUImage 和 AVFoundation 。

一、GPUImage

在之前的文章中,我們對 GPUImage 已經(jīng)有了一定的了解。之前一般使用它對攝像頭采集的圖像數(shù)據(jù)進(jìn)行處理,然而,它對本地視頻的處理也一樣方便。

直接看代碼:

// movieNSString *path = [[NSBundle mainBundle] pathForResource:@'sample' ofType:@'mp4'];NSURL *url = [NSURL fileURLWithPath:path];GPUImageMovie *movie = [[GPUImageMovie alloc] initWithURL:url];// filterGPUImageSmoothToonFilter *filter = [[GPUImageSmoothToonFilter alloc] init];// viewGPUImageView *imageView = [[GPUImageView alloc] initWithFrame:CGRectMake(0, 80, self.view.frame.size.width, self.view.frame.size.width)];[self.view addSubview:imageView];// chain[movie addTarget:filter];[filter addTarget:imageView];// processing[movie startProcessing];

核心代碼一共就幾行。 GPUImageMovie 負(fù)責(zé)視頻文件的讀取, GPUImageSmoothToonFilter 負(fù)責(zé)濾鏡效果處理, GPUImageView 負(fù)責(zé)最終圖像的展示。

通過濾鏡鏈將三者串起來,然后調(diào)用 GPUImageMovie 的 startProcessing 方法開始處理。

雖然 GPUImage 在使用上簡單,但是存在著 沒有聲音 、 在非主線程調(diào)用 UI 、 導(dǎo)出文件麻煩 、 無法進(jìn)行播放控制 等諸多缺點(diǎn)。

小結(jié):GPUImage 雖然使用很方便,但是存在諸多缺點(diǎn),不滿足生產(chǎn)環(huán)境需要。

二、AVFoundation

1、 AVPlayer 的使用

首先來復(fù)習(xí)一下 AVPlayer 最簡單的使用方式:

NSURL *url = [[NSBundle mainBundle] URLForResource:@'sample' withExtension:@'mp4'];AVURLAsset *asset = [AVURLAsset assetWithURL:url];AVPlayerItem *playerItem = [[AVPlayerItem alloc] initWithAsset:asset]; AVPlayer *player = [[AVPlayer alloc] initWithPlayerItem:playerItem];AVPlayerLayer *playerLayer = [AVPlayerLayer playerLayerWithPlayer:player];

第一步先構(gòu)建 AVPlayerItem ,然后通過 AVPlayerItem 創(chuàng)建 AVPlayer ,最后通過 AVPlayer 創(chuàng)建 AVPlayerLayer 。

AVPlayerLayer 是 CALayer 的子類,可以把它添加到任意的 Layer 上。當(dāng) AVPlayer 調(diào)用 play 方法時(shí), AVPlayerLayer 上就能將圖像渲染出來。

AVPlayer 的使用方式十分簡單。但是,按照上面的方式,最終只能在 AVPlayerLayer 上渲染出最原始的圖像。如果我們希望在播放的同時(shí),對原始圖像進(jìn)行處理,則需要修改 AVPlayer 的渲染過程。

2、修改 AVPlayer 的渲染過程

修改 AVPlayer 的渲染過程,要從 AVPlayerItem 下手,主要分為 四步 :

第一步:自定義 AVVideoCompositing 類

AVVideoCompositing 是一個(gè)協(xié)議,我們的自定義類要實(shí)現(xiàn)這個(gè)協(xié)議。在這個(gè)自定義類中,可以獲取到每一幀的原始圖像,進(jìn)行處理并輸出。

在這個(gè)協(xié)議中,最關(guān)鍵是 startVideoCompositionRequest 方法的實(shí)現(xiàn):

// CustomVideoCompositing.m- (void)startVideoCompositionRequest:(AVAsynchronousVideoCompositionRequest *)asyncVideoCompositionRequest { dispatch_async(self.renderingQueue, ^{ @autoreleasepool { if (self.shouldCancelAllRequests) {[asyncVideoCompositionRequest finishCancelledRequest]; } else {CVPixelBufferRef resultPixels = [self newRenderdPixelBufferForRequest:asyncVideoCompositionRequest];if (resultPixels) { [asyncVideoCompositionRequest finishWithComposedVideoFrame:resultPixels]; CVPixelBufferRelease(resultPixels);} else { // print error} } } });}

通過 newRenderdPixelBufferForRequest 方法從 AVAsynchronousVideoCompositionRequest 中獲取到處理后的 CVPixelBufferRef 后輸出,看下這個(gè)方法的實(shí)現(xiàn):

// CustomVideoCompositing.m- (CVPixelBufferRef)newRenderdPixelBufferForRequest:(AVAsynchronousVideoCompositionRequest *)request { CustomVideoCompositionInstruction *videoCompositionInstruction = (CustomVideoCompositionInstruction *)request.videoCompositionInstruction; NSArray<AVVideoCompositionLayerInstruction *> *layerInstructions = videoCompositionInstruction.layerInstructions; CMPersistentTrackID trackID = layerInstructions.firstObject.trackID; CVPixelBufferRef sourcePixelBuffer = [request sourceFrameByTrackID:trackID]; CVPixelBufferRef resultPixelBuffer = [videoCompositionInstruction applyPixelBuffer:sourcePixelBuffer]; if (!resultPixelBuffer) { CVPixelBufferRef emptyPixelBuffer = [self createEmptyPixelBuffer]; return emptyPixelBuffer; } else { return resultPixelBuffer; }}

在這個(gè)方法中,我們通過 trackID 從 AVAsynchronousVideoCompositionRequest 中獲取到 sourcePixelBuffer ,也就是當(dāng)前幀的原始圖像。

然后調(diào)用 videoCompositionInstruction 的 applyPixelBuffer 方法,將 sourcePixelBuffer 作為輸入,得到處理后的結(jié)果 resultPixelBuffer 。也就是說,我們對圖像的處理操作,都發(fā)生在 applyPixelBuffer 方法中。

在 newRenderdPixelBufferForRequest 這個(gè)方法中,我們已經(jīng)拿到了當(dāng)前幀的原始圖像 sourcePixelBuffer ,其實(shí)也可以直接在這個(gè)方法中對圖像進(jìn)行處理。

那為什么還需要把處理操作放在 CustomVideoCompositionInstruction 中呢?

因?yàn)樵趯?shí)際渲染的時(shí)候,自定義 AVVideoCompositing 類的實(shí)例創(chuàng)建是系統(tǒng)內(nèi)部完成的。也就是說,我們訪問不到最終的 AVVideoCompositing 對象。所以無法進(jìn)行一些渲染參數(shù)的動(dòng)態(tài)修改。而從 AVAsynchronousVideoCompositionRequest 中,可以獲取到 AVVideoCompositionInstruction 對象,所以我們需要自定義 AVVideoCompositionInstruction ,這樣就可以間接地通過修改 AVVideoCompositionInstruction 的屬性,來動(dòng)態(tài)修改渲染參數(shù)。

第二步:自定義 AVVideoCompositionInstruction

這個(gè)類的關(guān)鍵點(diǎn)是 applyPixelBuffer 方法的實(shí)現(xiàn):

// CustomVideoCompositionInstruction.m- (CVPixelBufferRef)applyPixelBuffer:(CVPixelBufferRef)pixelBuffer { self.filter.pixelBuffer = pixelBuffer; CVPixelBufferRef outputPixelBuffer = self.filter.outputPixelBuffer; CVPixelBufferRetain(outputPixelBuffer); return outputPixelBuffer;}

這里把 OpenGL ES 的處理細(xì)節(jié)都封裝到了 filter 中。這個(gè)類的實(shí)現(xiàn)細(xì)節(jié)可以先忽略,只需要知道它接受 原始的 CVPixelBufferRef ,返回 處理后的 CVPixelBufferRef 。

第三步:構(gòu)建 AVMutableVideoComposition

構(gòu)建的代碼如下:

self.videoComposition = [self createVideoCompositionWithAsset:self.asset];self.videoComposition.customVideoCompositorClass = [CustomVideoCompositing class];- (AVMutableVideoComposition *)createVideoCompositionWithAsset:(AVAsset *)asset { AVMutableVideoComposition *videoComposition = [AVMutableVideoComposition videoCompositionWithPropertiesOfAsset:asset]; NSArray *instructions = videoComposition.instructions; NSMutableArray *newInstructions = [NSMutableArray array]; for (AVVideoCompositionInstruction *instruction in instructions) { NSArray *layerInstructions = instruction.layerInstructions; // TrackIDs NSMutableArray *trackIDs = [NSMutableArray array]; for (AVVideoCompositionLayerInstruction *layerInstruction in layerInstructions) { [trackIDs addObject:@(layerInstruction.trackID)]; } CustomVideoCompositionInstruction *newInstruction = [[CustomVideoCompositionInstruction alloc] initWithSourceTrackIDs:trackIDs timeRange:instruction.timeRange]; newInstruction.layerInstructions = instruction.layerInstructions; [newInstructions addObject:newInstruction]; } videoComposition.instructions = newInstructions; return videoComposition;}

構(gòu)建 AVMutableVideoComposition 的過程 主要做兩件事情 。

第一件事情,把 videoComposition 的 customVideoCompositorClass 屬性,設(shè)置為我們自定義的 CustomVideoCompositing 。

第二件事情,首先通過系統(tǒng)提供的方法 videoCompositionWithPropertiesOfAsset 構(gòu)建出 AVMutableVideoComposition 對象,然后將它的 instructions 屬性修改為自定義的 CustomVideoCompositionInstruction 類型。(就像「第一步」提到的,后續(xù)可以在 CustomVideoCompositing 中,拿到 CustomVideoCompositionInstruction 對象。)

注意:這里可以把 CustomVideoCompositionInstruction 保存下來,然后通過修改它的屬性,去修改渲染參數(shù)。

第四步:構(gòu)建 AVPlayerItem

有了 AVMutableVideoComposition 之后,后面的事情就簡單多了。

只需要在創(chuàng)建 AVPlayerItem 的時(shí)候,多賦值一個(gè) videoComposition 屬性。

self.playerItem = [[AVPlayerItem alloc] initWithAsset:self.asset];self.playerItem.videoComposition = self.videoComposition;

這樣,整條鏈路就串起來了, AVPlayer 在播放時(shí),就能在 CustomVideoCompositionInstruction 的 applyPixelBuffer 方法中接收到 原始圖像的 CVPixelBufferRef 。

3、應(yīng)用濾鏡效果

這一步要做的事情是: 在 CVPixelBufferRef 上添加濾鏡效果,并輸出處理后的 CVPixelBufferRef 。

要做到這件事情,有很多種方式。包括但不限定于: OpenGL ES 、 CIImage 、 Metal 、 GPUImage 等。

為了同樣使用前面用到的 GPUImageSmoothToonFilter ,這里介紹一下 GPUImage 的方式。

關(guān)鍵代碼如下:

- (CVPixelBufferRef)renderByGPUImage:(CVPixelBufferRef)pixelBuffer { CVPixelBufferRetain(pixelBuffer); __block CVPixelBufferRef output = nil; runSynchronouslyOnVideoProcessingQueue(^{ [GPUImageContext useImageProcessingContext];// (1) GLuint textureID = [self.pixelBufferHelper convertYUVPixelBufferToTexture:pixelBuffer]; CGSize size = CGSizeMake(CVPixelBufferGetWidth(pixelBuffer), CVPixelBufferGetHeight(pixelBuffer));[GPUImageContext setActiveShaderProgram:nil]; // (2) GPUImageTextureInput *textureInput = [[GPUImageTextureInput alloc] initWithTexture:textureID size:size]; GPUImageSmoothToonFilter *filter = [[GPUImageSmoothToonFilter alloc] init]; [textureInput addTarget:filter]; GPUImageTextureOutput *textureOutput = [[GPUImageTextureOutput alloc] init]; [filter addTarget:textureOutput]; [textureInput processTextureWithFrameTime:kCMTimeZero];// (3) output = [self.pixelBufferHelper convertTextureToPixelBuffer:textureOutput.texture textureSize:size];[textureOutput doneWithTexture];glDeleteTextures(1, &textureID); }); CVPixelBufferRelease(pixelBuffer); return output;}

(1)一開始讀入的視頻幀是 YUV 格式的,首先把 YUV 格式的 CVPixelBufferRef 轉(zhuǎn)成 OpenGL 紋理。

(2)通過 GPUImageTextureInput 來構(gòu)造濾鏡鏈起點(diǎn), GPUImageSmoothToonFilter 來添加濾鏡效果, GPUImageTextureOutput 來構(gòu)造濾鏡鏈終點(diǎn),最終也是輸出 OpenGL 紋理。

(3)將處理后的 OpenGL 紋理轉(zhuǎn)化為 CVPixelBufferRef 。

另外,由于 CIImage 使用簡單,也順便提一下用法。

關(guān)鍵代碼如下:

- (CVPixelBufferRef)renderByCIImage:(CVPixelBufferRef)pixelBuffer { CVPixelBufferRetain(pixelBuffer); CGSize size = CGSizeMake(CVPixelBufferGetWidth(pixelBuffer), CVPixelBufferGetHeight(pixelBuffer)); // (1) CIImage *image = [[CIImage alloc] initWithCVPixelBuffer:pixelBuffer]; // (2) CIImage *filterImage = [CIImage imageWithColor:[CIColor colorWithRed:255.0 / 255 green:245.0 / 255 blue:215.0 / 255 alpha:0.1]]; // (3) image = [filterImage imageByCompositingOverImage:image]; // (4) CVPixelBufferRef output = [self.pixelBufferHelper createPixelBufferWithSize:size]; [self.context render:image toCVPixelBuffer:output]; CVPixelBufferRelease(pixelBuffer); return output;}

(1)將 CVPixelBufferRef 轉(zhuǎn)化為 CIImage 。

(2)創(chuàng)建一個(gè)帶透明度的 CIImage 。

(3)用系統(tǒng)方法將 CIImage 進(jìn)行疊加。

(4)將疊加后的 CIImage 轉(zhuǎn)化為 CVPixelBufferRef 。

4、導(dǎo)出處理后的視頻

視頻處理完成后,最終都希望能導(dǎo)出并保存。

導(dǎo)出的代碼也很簡單:

self.exportSession = [[AVAssetExportSession alloc] initWithAsset:self.asset presetName:AVAssetExportPresetHighestQuality];self.exportSession.videoComposition = self.videoComposition;self.exportSession.outputFileType = AVFileTypeMPEG4;self.exportSession.outputURL = [NSURL fileURLWithPath:self.exportPath];[self.exportSession exportAsynchronouslyWithCompletionHandler:^{ // 保存到相冊 // ...}];

這里關(guān)鍵的地方在于將 videoComposition 設(shè)置為前面構(gòu)造的 AVMutableVideoComposition 對象,然后設(shè)置好輸出路徑和文件格式后就可以開始導(dǎo)出。導(dǎo)出成功后,可以將視頻文件轉(zhuǎn)存到相冊中。

小結(jié): AVFoundation 雖然使用比較繁瑣,但是功能強(qiáng)大,可以很方便地導(dǎo)出視頻處理的結(jié)果,是用來做視頻處理的不二之選。

源碼

請到 GitHub 上查看完整代碼。

到此這篇關(guān)于在iOS中給視頻添加濾鏡的方法示例的文章就介紹到這了,更多相關(guān)iOS 視頻添加濾鏡內(nèi)容請搜索好吧啦網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持好吧啦網(wǎng)!

標(biāo)簽: IOS
相關(guān)文章:
成人在线亚洲_国产日韩视频一区二区三区_久久久国产精品_99国内精品久久久久久久
一区二区三区在线视频观看| 亚洲国产一区二区精品专区| 91社区在线播放| 欧美日韩免费不卡视频一区二区三区| 午夜久久久影院| 亚洲制服少妇| 成人免费在线播放视频| 欧美久久久久| 久久婷婷成人综合色| 成人av网址在线观看| 日韩免费一区二区| 国产一区二区三区最好精华液| 色婷婷一区二区三区四区| 亚洲国产另类精品专区| 自拍偷拍国产精品| 91片在线免费观看| 婷婷久久综合九色综合绿巨人| 国产一区二区中文字幕免费看| 久久久精品国产99久久精品芒果| 成人黄色在线网站| 国产精品视频免费看| 国产精品正在播放| 欧美日本在线看| 国产福利不卡视频| 欧美一级xxx| 不卡视频在线看| 久久蜜桃香蕉精品一区二区三区| eeuss影院一区二区三区| 久久夜色精品一区| 国产精品swag| 亚洲激情中文1区| 亚洲欧美日韩国产| 免播放器亚洲一区| 欧美色偷偷大香| 国产不卡一区视频| 久久综合成人精品亚洲另类欧美| 成人av电影在线网| 久久久精品tv| 女女同性精品视频| 国产精品国模大尺度视频| 一区三区视频| 亚洲国产三级在线| 日本精品视频一区二区| 久久狠狠亚洲综合| 欧美一区二区久久| 99re热视频精品| 国产精品福利av| 中文亚洲欧美| 午夜久久久久久电影| 欧美亚洲国产一区二区三区va| 久久av资源站| 欧美一区中文字幕| 91亚洲精品久久久蜜桃| 国产网站一区二区| 国产精品手机在线| 奇米影视在线99精品| 欧美日高清视频| 国产福利一区二区三区视频| 久久久精品tv| 一级成人国产| 久久99久国产精品黄毛片色诱| 欧美日韩另类一区| 成人a区在线观看| 亚洲图片你懂的| 91国偷自产一区二区开放时间 | 成人一区二区三区中文字幕| 国产喂奶挤奶一区二区三区| 在线天堂一区av电影| 蜜臀va亚洲va欧美va天堂| 51午夜精品国产| 91在线精品一区二区三区| 亚洲三级理论片| 一本大道久久精品懂色aⅴ| 精品一区二区三区在线播放| 精品盗摄一区二区三区| 国产自产在线视频一区| 日韩av中文字幕一区二区三区| 欧美人体做爰大胆视频| 成人福利视频在线看| 国产精品久久免费看| 亚洲免费网址| 国产麻豆视频一区二区| 久久精品亚洲麻豆av一区二区| 狠狠综合久久| 午夜不卡在线视频| 精品国产免费人成在线观看| 在线免费观看欧美| 免费的国产精品| 亚洲精品一区二区三区蜜桃下载| 在线精品亚洲一区二区| 免费成人你懂的| 久久夜色精品国产欧美乱极品| 亚洲黑丝在线| 美国十次综合导航| 国产午夜精品福利| 色天天综合久久久久综合片| 国产.精品.日韩.另类.中文.在线.播放| 国产欧美va欧美不卡在线| 国产伦精品一区二区| 极品瑜伽女神91| 日韩欧美国产午夜精品| 精品av久久久久电影| 麻豆精品一区二区| 欧美韩国日本一区| 欧美视频中文一区二区三区在线观看| 91网址在线看| 天堂成人国产精品一区| 日韩免费福利电影在线观看| 韩国一区二区三区美女美女秀| 轻轻草成人在线| 中文字幕巨乱亚洲| 精品视频1区2区3区| 欧美日韩精选| 久久99热狠狠色一区二区| 亚洲国产成人在线| 欧美无乱码久久久免费午夜一区| 欧美午夜影院| 九一久久久久久| 日韩理论片在线| 欧美一级精品大片| 欧美一区=区| 91亚洲男人天堂| 日本成人超碰在线观看| 久久久综合视频| 色偷偷88欧美精品久久久| 欧美日本韩国一区二区三区| 捆绑变态av一区二区三区| 中文字幕日韩一区二区| 91麻豆精品国产自产在线观看一区 | 中文字幕不卡在线观看| 欧美性猛交xxxxxx富婆| 一区二区在线不卡| 国产传媒日韩欧美成人| 一区二区三区免费看视频| 欧美本精品男人aⅴ天堂| 久久精品网址| 好吊日精品视频| 国产高清精品网站| 日本视频中文字幕一区二区三区| 亚洲视频一区在线观看| 精品国产露脸精彩对白| 在线日韩国产精品| 日韩亚洲欧美精品| 91老师片黄在线观看| 日本麻豆一区二区三区视频| 亚洲欧美综合色| 亚洲精品一区二区三区蜜桃下载| 欧美性高清videossexo| 亚洲一区二区免费看| 色综合久久中文综合久久牛| 999在线观看精品免费不卡网站| 国产一区二区三区不卡在线观看 | 欧美视频一区二区在线观看| 亚洲日本黄色| 91麻豆6部合集magnet| 国产精品一区二区在线播放| 午夜激情久久久| 亚洲欧美激情插| 国产亚洲欧美一级| 日韩精品一区二区三区中文不卡| 日本韩国欧美三级| 国产欧美欧美| 国内精品久久久久久久97牛牛| 成年人国产精品| 国产剧情av麻豆香蕉精品| 日本视频在线一区| 亚洲aⅴ怡春院| 国产午夜精品美女毛片视频| 欧美一级高清片| 欧美日韩精品一区二区三区 | 成人精品国产一区二区4080| 激情综合色综合久久综合| 日韩国产欧美一区二区三区| 一级做a爱片久久| 亚洲精品videosex极品| 亚洲视频一区二区在线观看| 中文字幕一区视频| 国产精品视频一二| 亚洲国产成人自拍| 国产欧美精品一区二区色综合朱莉| 日韩一区二区麻豆国产| 欧美一级理论片| 欧美一区二区三区免费视频| 欧美日本乱大交xxxxx| 欧美性做爰猛烈叫床潮| 色就色 综合激情| 久久国产一二区| 性刺激综合网| 久久大逼视频| 久久精品官网| 久久人人97超碰人人澡爱香蕉 | 91精品蜜臀在线一区尤物| 欧美三级视频在线播放| 老司机精品导航| 色噜噜狠狠色综合欧洲selulu| 久久中文字幕一区二区三区| 巨乳诱惑日韩免费av| 在线视频一区二区三| 欧美天堂亚洲电影院在线播放| 欧美性猛交xxxxxx富婆|