合成视频标准写法
// 获取视频
AVURLAsset* videoAsset = [[AVURLAsset alloc]initWithURL:_videoURL options:nil];
// 视频混合
AVMutableComposition *mixComposition = [AVMutableComposition composition];
// 视频轨道
AVMutableCompositionTrack *compositionVideoTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
// 音频轨道
AVMutableCompositionTrack *compositionAudioTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
// 插入视频轨道
[compositionVideoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, CMTimeMake(videoAsset.duration.value, videoAsset.duration.timescale)) ofTrack:[[videoAsset tracksWithMediaType:AVMediaTypeVideo] firstObject] atTime:kCMTimeZero error:nil];
// [compositionVideoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, videoAsset.duration) ofTrack:[[videoAsset tracksWithMediaType:AVMediaTypeVideo] firstObject] atTime:kCMTimeZero error:nil];
// 插入音频轨道
[compositionAudioTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, CMTimeMake(videoAsset.duration.value, videoAsset.duration.timescale)) ofTrack:[[videoAsset tracksWithMediaType:AVMediaTypeAudio] firstObject] atTime:kCMTimeZero error:nil];
// [compositionAudioTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, videoAsset.duration) ofTrack:[[videoAsset tracksWithMediaType:AVMediaTypeAudio] firstObject] atTime:kCMTimeZero error:nil];
for (int i = 0; i < self.audioArray.count; i++) {
AudioRecordData *data = _audioArray[i];
NSLog(@"starTime = %f",data.startTime);
AVURLAsset *audioAsset = [AVURLAsset URLAssetWithURL:[NSURL fileURLWithPath:data.audioPath] options:nil];
CMTime startTime = CMTimeMakeWithSeconds(data.startTime, audioAsset.duration.timescale);
compositionAudioTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
[compositionVideoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, CMTimeMake(videoAsset.duration.value, videoAsset.duration.timescale)) ofTrack:[[videoAsset tracksWithMediaType:AVMediaTypeVideo] firstObject] atTime:startTime error:nil];
[compositionAudioTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, CMTimeMake(audioAsset.duration.value, videoAsset.duration.timescale)) ofTrack:[audioAsset tracksWithMediaType:AVMediaTypeAudio].firstObject atTime:startTime error:nil];
}
//调节音量
AVMutableAudioMix *audioMix = [AVMutableAudioMix audioMix];
AVMutableAudioMixInputParameters *audioInputParams = [AVMutableAudioMixInputParameters audioMixInputParametersWithTrack:compositionAudioTrack] ;
[audioInputParams setVolumeRampFromStartVolume:self.videoVolume toEndVolume:.0f timeRange:CMTimeRangeMake(kCMTimeZero, CMTimeMake(videoAsset.duration.value, videoAsset.duration.timescale))];
[audioInputParams setTrackID:compositionAudioTrack.trackID];
audioMix.inputParameters = [NSArray arrayWithObject:audioInputParams];
// 配置导出
AVAssetExportSession* _assetExport = [[AVAssetExportSession alloc] initWithAsset:mixComposition presetName:AVAssetExportPreset1280x720];
// 导出视频的临时保存路径
NSString *exportPath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"tmpMov.mov"];
unlink([exportPath UTF8String]);
NSURL *exportUrl = [NSURL fileURLWithPath:exportPath];
// 导出视频的格式 .MOV
_assetExport.outputFileType = AVFileTypeQuickTimeMovie;
_assetExport.outputURL = exportUrl;
_assetExport.audioMix = audioMix;
_assetExport.shouldOptimizeForNetworkUse = YES;
_assetExport.timeRange = CMTimeRangeMake(kCMTimeZero, CMTimeMake(videoAsset.duration.value, videoAsset.duration.timescale));
// 导出视频
[_assetExport exportAsynchronouslyWithCompletionHandler: ^(void ) {
switch ([_assetExport status]) {
case AVAssetExportSessionStatusFailed:
NSLog(@"Export failed: %@", [[_assetExport error] localizedDescription]);
break;
case AVAssetExportSessionStatusCancelled:
NSLog(@"Export canceled");
break;
default:
NSLog(@"NONE");
dispatch_async(dispatch_get_main_queue(), ^{
[MBProgressHUD hideHUDForView:self.view animated:YES];
NSURL *movieUrl = [NSURL URLWithString:exportPath];
UISaveVideoAtPathToSavedPhotosAlbum([movieUrl relativePath], self,@selector(video:didFinishSavingWithError:contextInfo:), nil);
});
break;
}
}];