一個視頻文件中包含了很多軌道(Track)霸奕,比如一個或多個音頻軌道溜宽,一個或多個視頻軌道。我們可以對這些軌道中的數(shù)據(jù)進(jìn)行各種操作(裁剪质帅、拼接坑质、旋轉(zhuǎn)等)。
本次我用到的視頻打點(diǎn)裁剪相關(guān)功能用到的類如下:
AVAsset:素材临梗,比如出相冊中取出的數(shù)據(jù)
AVAssetTrack:素材的軌道
AVMutableComposition:視頻的工程文件(是AVAsset的子類涡扼,可以用來直接播放)
AVMutableCompositionTrack:工程文件對應(yīng)的軌道
這里我的需求是要裁剪調(diào)一個視頻素材的頭尾,第一步需要獲取到素材的視頻軌道和音頻軌道
AVAssetTrack *videoAssetTrack = [[videoAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
AVAssetTrack *audioAssetTrack = [[videoAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0];
第二步盟庞,創(chuàng)建工程文件吃沪,將素材的軌道數(shù)據(jù)導(dǎo)入到工程文件的軌道中
AVMutableComposition *mutableComposition = [AVMutableComposition composition];
AVMutableCompositionTrack *audioTrack = [mutableComposition addMutableTrackWithMediaType:AVMediaTypeAudio
preferredTrackID:kCMPersistentTrackID_Invalid];
AVMutableCompositionTrack *videoTrack = [mutableComposition addMutableTrackWithMediaType:AVMediaTypeVideo
preferredTrackID:kCMPersistentTrackID_Invalid];
NSError *errorAudio;
[audioTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, videoAsset.duration) ofTrack:audioAssetTrack atTime:kCMTimeZero error:&errorAudio];
NSError *errorVideo;
[videoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, videoAsset.duration) ofTrack:videoAssetTrack atTime:kCMTimeZero error:&errorVideo];
第三步,計(jì)算需要裁剪的頭和尾的range什猖,然后將音頻軌道和視頻軌道都進(jìn)行裁剪
CMTime start = CMTimeMakeWithSeconds(self.startTime, videoAsset.duration.timescale);
CMTime end = CMTimeMakeWithSeconds(self.stopTime - self.startTime, videoAsset.duration.timescale);
CMTime duration = CMTimeMakeWithSeconds(videoAsset.duration.value - self.stopTime, videoAsset.duration.timescale);
CMTimeRange range = CMTimeRangeMake(kCMTimeZero, start);
CMTimeRange range2 = CMTimeRangeMake(end, duration);
[videoTrack removeTimeRange: range];
[audioTrack removeTimeRange: range];
[videoTrack removeTimeRange: range2];
[audioTrack removeTimeRange: range2];
到這里票彪,我們已經(jīng)將工程文件中的視頻進(jìn)行了裁剪,我們可以直接使用AVPlayer進(jìn)行播放看裁剪成功沒有
AVPlayerViewController *playerController = [[AVPlayerViewController alloc] init];
AVPlayerItem *playerItem = [[AVPlayerItem alloc] initWithAsset:mutableComposition];
AVPlayer *player = [[AVPlayer alloc] initWithPlayerItem:playerItem];
playerController.player = player;
[self presentViewController:playerController animated:true completion:nil];
當(dāng)然不狮,更多的是需要使用AVAssetExportSession將工程文件轉(zhuǎn)碼導(dǎo)出降铸,代碼如下:
AVAssetExportSession* exportSession = [[AVAssetExportSession alloc] initWithAsset:mutableComposition presetName:AVAssetExportPresetPassthrough];
NSURL *fileUrl = [NSURL fileURLWithPath:self.tempPath];
exportSession.outputURL = fileUrl;
exportSession.outputFileType = AVFileTypeQuickTimeMovie;
[exportSession exportAsynchronouslyWithCompletionHandler:
^(void ) {
switch ([exportSession status]) {
case AVAssetExportSessionStatusFailed:
NSLog(@"failed: %@", [[exportSession error] localizedDescription]);
break;
case AVAssetExportSessionStatusCancelled:
NSLog(@"canceled");
break;
default:
NSLog(@"success");
break;
}
}
];
至此,整個裁剪功能的主要代碼已經(jīng)完成摇零。
遇到的坑
最初我參考別人的demo發(fā)現(xiàn)可以使用AVAssetExportSession的timeRange來實(shí)現(xiàn)裁剪推掸。
CMTimeRange range = CMTimeRangeMake(start, duration);
self.exportSession.timeRange = range;
但是當(dāng)裁剪的視頻時長比較長時,這種方法在從頭開始裁剪和裁剪視頻后半部分在耗時上差別巨大。
比如我測試了30分鐘的視頻谅畅,我裁剪0-10分鐘大概耗時8秒登渣,但是裁剪20-30分鐘耗時達(dá)到了驚人的60秒。我不清楚這個是因?yàn)榈讓觼磙D(zhuǎn)碼時選擇轉(zhuǎn)碼范圍的算法導(dǎo)致了這一現(xiàn)象還是其他什么原因毡泻。
最終我選擇了使用上文中提到的切割軌道數(shù)據(jù)的方式基本做到了在30分鐘的視頻中切割10分鐘胜茧,無論切割哪一段視頻,都可以保持8秒完成切割和轉(zhuǎn)碼導(dǎo)出仇味。
如有問題呻顽,請指正。