關(guān)鍵字:AVFoundation,AVAsset,AVComposition,AVVideoComposition,AVVideoCompositionInstruction,AVVideoCompositionLayerInstruction
最近做了一個(gè)關(guān)于視頻處理的項(xiàng)目释牺,剛開始的需求大概只有:
- 對(duì)視頻制定區(qū)域進(jìn)行裁剪
- 對(duì)幾段視頻進(jìn)行裁剪拼接
- 對(duì)視頻及音頻進(jìn)行拼接
遇到不會(huì)做的需求陵叽,很習(xí)慣就是Google一下別人的Demo是怎么做的要尔,然后大概看一下是如何實(shí)現(xiàn)的晌畅,然后拿過(guò)來(lái)修改一下挂据。嗯踢故,按照我后來(lái)學(xué)習(xí)了一下AVFoundation這個(gè)庫(kù)之后孝常,感覺(jué)我第一階段的工作自己應(yīng)該是幾乎沒(méi)弄懂什么状共。好了,工作又有進(jìn)一步的需求了:
- 實(shí)現(xiàn)視頻間的過(guò)渡效果
- 實(shí)現(xiàn)多段視頻分屏顯示的效果
- 實(shí)現(xiàn)視頻添加字幕尘应,以及字幕動(dòng)畫效果
這些內(nèi)容Google出來(lái)的內(nèi)容惶凝,很難明白到底是怎么實(shí)現(xiàn)的,已經(jīng)其實(shí)什么都沒(méi)說(shuō)出來(lái)犬钢,很多的都是這個(gè)復(fù)制另一個(gè)的代碼苍鲜,修改一下,這完全不能做到讓你學(xué)會(huì)使用玷犹,大多都是讓你學(xué)會(huì)搬磚混滔。
還好我找到一本書AVFoundation秘籍
對(duì)于媒體的編輯,主要看熟里面的第九章以及第十一章,進(jìn)階的是在第十二章坯屿。
媒體的組合和編輯
在iOS中油湖,所有的音視頻都被抽象成AVAsset
對(duì)象,這樣一來(lái)就可以簡(jiǎn)化了不同格式的媒體领跛,并且可以將所有的音視頻都是用統(tǒng)一的接口進(jìn)行處理肺魁,這很符合面向?qū)ο蟮牧?xí)慣。
如果我們有使用過(guò)一些音視頻剪切的工具隔节,其實(shí)可以看到在處理剪切合成的時(shí)候鹅经,你的每一段素材,在進(jìn)行剪切以及合并之后怎诫,其實(shí)仍然是可以進(jìn)行單獨(dú)播放已經(jīng)繼續(xù)編輯的一個(gè)實(shí)體瘾晃,這個(gè)原理跟iOS的媒體組合和編輯是差不多的。
其實(shí)可以簡(jiǎn)單的理解成:
- 我們平時(shí)播放的
AVAsset
幻妓,是由多段完整的AVAssetTrack
蹦误,其中最簡(jiǎn)單的就是包含一段完整AVMediaTypeVideo
類型的AVAssetTrack
,以及一段完整AVMediaTypeAudio
類型的AVAssetTrack
肉津。 -
AVAssetTrack
用于提供接口對(duì)媒體的軌道進(jìn)行操作强胰。 -
AVComposition
這個(gè)組合
的類,顧名思義是用于負(fù)責(zé)描述多個(gè)AVAssetTrack
組合的關(guān)系妹沙,由于他是繼承于AVAsset
的偶洋,因此他也是可以單獨(dú)作為AVAsset
來(lái)使用,這里非常重要距糖。 -
AVCompositionTrackSegment
玄窝,軌道的片段,不過(guò)目前我還沒(méi)有需要使用悍引。
于是使用上面類圖恩脂,我們能做什么呢?我們能簡(jiǎn)單的將幾個(gè)視頻首尾拼接成一個(gè)視頻進(jìn)行播放導(dǎo)出趣斤,以及將音頻視頻進(jìn)行簡(jiǎn)單的拼接處理(ps:這里的視頻拼接不能在同一時(shí)刻有另外的視頻在播放俩块,不然會(huì)出現(xiàn)黑屏的現(xiàn)象,解決方法會(huì)在后面出現(xiàn))浓领。
//首先定義兩個(gè)需要操作的資源
AVAsset *assetA = [AVAsset assetWithURL:[NSURL URLWithString:@"A"]];
AVAsset *assetB = [AVAsset assetWithURL:[NSURL URLWithString:@"B"]];
//定義兩個(gè)資源的軌道
AVAssetTrack *trackA = [assetA tracksWithMediaType:AVMediaTypeVideo].firstObject;
AVAssetTrack *trackB = [assetB tracksWithMediaType:AVMediaTypeVideo].firstObject;
//定義一個(gè)用于操作資源組合的可變資源
AVMutableComposition *composition = [AVMutableComposition composition];
//定義兩個(gè)資源的組合軌道
AVMutableCompositionTrack *compositionTrackA = [composition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
AVMutableCompositionTrack *compositionTrackB = [composition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
//為兩個(gè)組合軌道分別插入0s-3s段的資源玉凯,a在0-3s播放,b在3-6s播放
[compositionTrackA insertTimeRange:CMTimeRangeMake(kCMTimeZero, CMTimeMakeWithSeconds(3, NSEC_PER_SEC)) ofTrack:trackA atTime:kCMTimeZero error:nil];
[compositionTrackB insertTimeRange:CMTimeRangeMake(kCMTimeZero, CMTimeMakeWithSeconds(3, NSEC_PER_SEC)) ofTrack:trackB atTime:CMTimeMakeWithSeconds(3, NSEC_PER_SEC) error:nil];
//到這里就可以直接使用composition進(jìn)行播放
AVPlayerItem *playerItem = [AVPlayerItem playerItemWithAsset:composition];
AVPlayer *player = [AVPlayer playerWithPlayerItem:playerItem];
創(chuàng)建視頻的過(guò)渡效果
上面的AVComposition
是以資源軌道
為單位的對(duì)不同媒體資源進(jìn)行組合镊逝,然后對(duì)于音頻
和視頻
還有更進(jìn)一步的細(xì)分壮啊,這也為創(chuàng)建更多視頻效果提供了方便嫉鲸。下面先說(shuō)對(duì)于視頻的組合撑蒜。
以視頻添加過(guò)渡效果為例,還記得上面說(shuō)的兩個(gè)視頻,不能重疊在一起播放的問(wèn)題嗎座菠?這里就以這個(gè)為例狸眼。不過(guò)需要先引入一些概念。
-
AVVideoComposition
浴滴,視頻組合類拓萌,類似上面的AVComposition
概念,不過(guò)這里是對(duì)一個(gè)媒體資源中升略,負(fù)責(zé)所有視頻
資源組合關(guān)系的一個(gè)類微王,跟AVComposition
是一點(diǎn)關(guān)系都沒(méi)有。這個(gè)類除了可以包含視頻組合信息之外品嚣,還能配置視頻的渲染尺寸
炕倘,縮放
,和幀時(shí)長(zhǎng)
等屬性翰撑。 -
AVVideoCompositionInstruction
,AVVideoCompostion
是由一組AVVideoCompositionInstruction
對(duì)象格式定義的指令組成的罩旋。這個(gè)對(duì)象提供的最關(guān)鍵的信息是組合對(duì)象時(shí)間軸內(nèi)的時(shí)間范圍信息,其實(shí)就是表明這個(gè)視頻組合的開始時(shí)間和持續(xù)時(shí)間眶诈。要執(zhí)行的組合特質(zhì)是通過(guò)AVVideoCompositionLayerInstruction
-
AVVideoCompositionLayerInstruction
涨醋,用于定義給定視頻軌道應(yīng)用的模糊,變形和裁剪效果逝撬。
PS:AVVideoComposition
并不直接與AVCompostion
相關(guān)浴骂,相反看上面視頻組合類.png
,這些對(duì)象是和類似AVPlayItem
等客戶端相關(guān)聯(lián)宪潮,在播放組合或進(jìn)行其他處理時(shí)使用這些對(duì)象靠闭。
下面的例子,其實(shí)我們可以對(duì)于每一段AVVideoCompositionInstrction
都自行定義坎炼,但是有更簡(jiǎn)便的方法愧膀,為何不用呢?
AVMutableVideoComposition *videoCompostion = [AVMutableVideoComposition videoCompositionWithPropertiesOfAsset:composition];
當(dāng)你使用這段代碼的時(shí)候谣光,會(huì)自動(dòng)生成一個(gè)默認(rèn)的AVVideoComposition
檩淋,并且會(huì)自動(dòng)生成默認(rèn)的AVVideoCompositionInstruction
,AVVideoCompostionLayerInstruction
萄金。那么它這個(gè)自動(dòng)生成的規(guī)則是怎么樣的呢蟀悦?多嘗試幾次不一樣的視頻組合,不難發(fā)現(xiàn):
- 在時(shí)間軸延伸的方向氧敢,只要某一時(shí)刻的視頻組合數(shù)量發(fā)生變化日戈,那么就會(huì)產(chǎn)生一個(gè)新的
AVVideoCompositionInstruction
對(duì)象
例如:現(xiàn)在有三個(gè)視頻軌道,A孙乖,B浙炼,C(有數(shù)字的時(shí)刻代表視頻在該時(shí)間段有內(nèi)容份氧,#代表空)
軌道A:1 2 3 4 5 6 7 8 9
軌道B:1 2 3 # # # # # #
軌道C:1 2 3 4 5 6 # # #
- 軌道A,B弯屈,C在1~3s內(nèi)都是有內(nèi)容的蜗帜,因此這會(huì)生成第一個(gè)
AVVideoCompositionInstruction
- 軌道A,C在3~6s內(nèi)有內(nèi)容资厉,由于這個(gè)時(shí)間段內(nèi)厅缺,視頻組合數(shù)量發(fā)生了改變,因此這里是第二個(gè)
AVVideoCompositionInstruction
- 最后在6-9s宴偿,只有軌道A有視頻湘捎,因此這里是第三個(gè)
AVVideoCompositionInstruction
在我們生成了AVVideoCompositionInstruction
之后,我們需要對(duì)里面的AVVideoCompositionLayerInstruction
進(jìn)行自定義窄刘,具體這個(gè)過(guò)渡效果要什么樣子消痛,靠你自己組合視頻的數(shù)量,以及改變視頻的模糊都哭,變形和裁剪效果秩伞,這里就不一一實(shí)現(xiàn)了。
以上面3個(gè)軌道例子中的第3-6s作為演示
最終的效果是軌道A在3-6s播放的時(shí)候會(huì)漸漸模糊
AVMutableVideoComposition *videoCompostion = [AVMutableVideoComposition videoCompositionWithPropertiesOfAsset:composition];
for (AVMutableVideoCompositionInstruction *vci in videoCompostion.instructions) {
if (vci.layerInstructions.count == 2) {
AVMutableVideoCompositionLayerInstruction *fromLayerInstruction = (AVMutableVideoCompositionLayerInstruction *)vci.layerInstructions.firstObject;
// AVVideoCompositionLayerInstruction *toLayerInstruction = vci.layerInstructions.firstObject;
CMTimeRange timeRange = vci.timeRange;
//漸變效果
[fromLayerInstruction setOpacityRampFromStartOpacity:1.0 toEndOpacity:0 timeRange:timeRange];
}
}