視頻合成
視頻合成中依然用到了AVMutableComposition震缭,思路依然很簡單,取出視頻軌和音頻軌數(shù)據(jù)加入到可變軌道之中战虏。不多說拣宰,還是貼代碼吧:
NSArray *videosPathArray =@[@"",
@""];
AVMutableComposition *mixComposition = [[AVMutableComposition alloc] init];
AVMutableCompositionTrack *audioTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio
preferredTrackID:kCMPersistentTrackID_Invalid];
AVMutableCompositionTrack *videoTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo
preferredTrackID:kCMPersistentTrackID_Invalid];
CMTime totalDuration = kCMTimeZero;
for (int i = 0; i < videosPathArray.count; i++) {
NSDictionary* options = @{AVURLAssetPreferPreciseDurationAndTimingKey:@YES
};
//網(wǎng)絡(luò)視頻 URLWithString: 本地視頻 fileURLWithPath:
AVURLAsset *asset =[AVURLAsset URLAssetWithURL:[NSURL URLWithString:videosPathArray[i]] options:options];
NSError *erroraudio = nil;
//獲取AVAsset中的音頻 或者視頻
AVAssetTrack *assetAudioTrack = [[asset tracksWithMediaType:AVMediaTypeAudio] firstObject];
//向通道內(nèi)加入音頻或者視頻
BOOL ba = [audioTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, asset.duration)
ofTrack:assetAudioTrack
atTime:totalDuration
error:&erroraudio];
NSLog(@"erroraudio:%@%d",erroraudio,ba);
NSError *errorVideo = nil;
AVAssetTrack *assetVideoTrack = [[asset tracksWithMediaType:AVMediaTypeVideo] firstObject];
BOOL bl = [videoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, asset.duration)
ofTrack:assetVideoTrack
atTime:totalDuration
error:&errorVideo];
NSLog(@"errorVideo:%@%d",errorVideo,bl);
totalDuration = CMTimeAdd(totalDuration, asset.duration);
}
LYAVPlayerView *playerView =[[LYAVPlayerView alloc]init];
// CGFloat scale =_composition.naturalSize.width/_composition.naturalSize.height;
playerView.frame =CGRectMake(0,100,ScreenWidth,ScreenHeight-160);
playerView.videoGravity =AVLayerVideoGravityResizeAspect;
[playerView setPlayerItem:[[AVPlayerItem alloc]initWithAsset:mixComposition]];
[self.view addSubview:playerView];
[playerView play];
注:創(chuàng)建AVURLAsset時党涕,如果是本地視頻則用fileURLWithPath:
函數(shù),如果是網(wǎng)絡(luò)視頻巡社,則調(diào)用URLWithString
函數(shù)遣鼓。多個網(wǎng)絡(luò)視頻合成后,效果就跟播放一個視頻一樣重贺,用戶體驗非常不錯。CMTimeAdd的用法參考另一篇文章短視頻從無到有 (三)CMTime詳解回懦。
視頻壓縮和轉(zhuǎn)換
視頻合成后即可導(dǎo)出到本地或者手機相冊气笙,思路依然很簡單,使用AVAssetExportSession即可怯晕。代碼如下:
unlink([outPath UTF8String]);
NSURL *compressionFileURL = [NSURL fileURLWithPath:outPath];
if ([[NSFileManager defaultManager] fileExistsAtPath:outPath]) {
[[NSFileManager defaultManager] removeItemAtPath:outPath error:nil];
}
// 創(chuàng)建AVAsset對象
AVAsset* asset = [AVAsset assetWithURL:[NSURL fileURLWithPath:videoPath]];
// 創(chuàng)建AVAssetExportSession對象
AVAssetExportSession * exporter = [[AVAssetExportSession alloc] initWithAsset:asset presetName:presetName];
//優(yōu)化網(wǎng)絡(luò)
exporter.shouldOptimizeForNetworkUse = YES;
//設(shè)置輸出路徑
exporter.outputURL =compressionFileURL;
//設(shè)置輸出類型
exporter.outputFileType = outputFileType;
[exporter exportAsynchronouslyWithCompletionHandler:^{
dispatch_async(dispatch_get_main_queue(), ^{
switch (exporter.status) {
case AVAssetExportSessionStatusFailed:{
if (completeBlock) {
completeBlock(exporter.error,compressionFileURL);
}
break;
}
case AVAssetExportSessionStatusCancelled:{
NSLog(@"Export Status: Cancell");
break;
}
case AVAssetExportSessionStatusCompleted: {
if (completeBlock) {
completeBlock(nil,compressionFileURL);
}
break;
}
case AVAssetExportSessionStatusUnknown: {
NSLog(@"Export Status: Unknown");
break;
}
case AVAssetExportSessionStatusExporting : {
NSLog(@"Export Status: Exporting");
break;
}
case AVAssetExportSessionStatusWaiting: {
NSLog(@"Export Status: Wating");
break;
}
};
});
}];
注:導(dǎo)出過程中設(shè)置exporter
的presetName(分辨率)
和outputFileType(視頻封裝格式)
即可完成視頻轉(zhuǎn)換和壓縮潜圃。當(dāng)然,更深層次的處理靠這些是遠(yuǎn)遠(yuǎn)不夠的舟茶,還要依靠更多的框架來處理谭期,譬如ffmpeg
等,這些以后再做討論吧凉,今兒就先到這隧出。