赞
踩
当下音视频处理的技术的重要性不言而喻, FFmpeg
的强大不可撼动, 但是, 确实难啃. 由简递难, 我们来看看苹果原生的API如何做到对视频素材进行处理的.
AVFoundation
既可以对视频进行播放, 同时也可以对视频素材进行处理, 此类合成共分为两章:
AVMutableComposition
合成工具AVMutableCompositionTrack
合成工具中的轨道AVAsset
视频素材的载体AVAssetTrack
素材轨道AVAssetExportSession
输出工具过程简单而言, 就是将素材
中的素材轨道
, 按照自定义顺序或者形式, 放到合成工具
的对应的轨道
, 最后, 设定好参数, 通过输出工具
将合成工具中的内容一键合成并且输出
.
下面是核心代码, 详细的请参考 Demo_AVFoundationCompound
// 这里将video的内容倒叙操作,为了后面将视频 逐个插入0的位置 videoPaths = [[videoPaths reverseObjectEnumerator] allObjects]; // 合成工具 AVMutableComposition *composition = [AVMutableComposition composition]; // 创建获取素材参数, 这个可以直接为nil, 下方的参数含义是获取素材参数的时间为非精准, 默认为精准 NSDictionary *optDict = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:AVURLAssetPreferPreciseDurationAndTimingKey]; // 合成工具的视频轨道 __block AVMutableCompositionTrack *compositionVideoTrack = [composition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid]; // 合成工具的音频轨道 __block AVMutableCompositionTrack *compositionAudioTrack = [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid]; // 遍历视频资源 [videoPaths enumerateObjectsUsingBlock:^(NSURL *videoPath, NSUInteger idx, BOOL * _Nonnull stop) { // 素材 AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:videoPath options:optDict]; // 获取素材中的轨道_视频 NSArray<AVAssetTrack *> *videoTracks = [asset tracksWithMediaType:AVMediaTypeVideo]; if (videoTracks <= 0) { *stop = YES; completedBlock(NO, @"合成失败"); return; } // 获取当前视频的时间长度 CMTimeRange timeRange = CMTimeRangeMake(kCMTimeZero, asset.duration); // 素材的视频轨道 AVAssetTrack *videoCompositionTrack = videoTracks.firstObject; // 设置合成工具的preferredTransform [compositionVideoTrack setPreferredTransform:videoCompositionTrack.preferredTransform]; // 将素材的视频轨道添加到合成工具的视频轨道 [compositionVideoTrack insertTimeRange:timeRange ofTrack:videoTracks.firstObject atTime:kCMTimeZero error:nil]; // 下面是处理原视频中的音频, 静音的话, 可以不处理 NSArray *audioTracks = [asset tracksWithMediaType:AVMediaTypeAudio]; if (audioTracks.count > 0) { // 将素材的音频轨道添加到合成工具的音频轨道 [compositionAudioTrack insertTimeRange:timeRange ofTrack:audioTracks.firstObject atTime:kCMTimeZero error:nil]; } }]; // 存在旧数据, 删除旧数据 if ([[NSFileManager defaultManager] fileExistsAtPath:compoundVideoPath]) { NSError *error; [[NSFileManager defaultManager] removeItemAtPath:compoundVideoPath error:&error]; } NSURL *outUrl = [NSURL fileURLWithPath:compoundVideoPath]; // 输出工具 AVAssetExportSession *exporter = [[AVAssetExportSession alloc] initWithAsset:composition presetName:AVAssetExportPresetMediumQuality]; // 输出类型 exporter.outputFileType = AVFileTypeMPEG4; // 输出路径 exporter.outputURL = outUrl; // 优化 exporter.shouldOptimizeForNetworkUse = YES; [exporter exportAsynchronouslyWithCompletionHandler:^{ BOOL isSuccess = NO; NSString *msg = @"合并完成"; switch (exporter.status) { case AVAssetExportSessionStatusFailed: NSLog(@"MediaManager -> combinationVidesError: %@", exporter.error.localizedDescription); NSLog(@"%@", exporter.error); msg = @"合并失败"; break; case AVAssetExportSessionStatusUnknown: case AVAssetExportSessionStatusCancelled: break; case AVAssetExportSessionStatusWaiting: break; case AVAssetExportSessionStatusExporting: break; case AVAssetExportSessionStatusCompleted: isSuccess = YES; break; } if (completedBlock) { completedBlock(isSuccess, msg); } }];
添加背景音乐, 其实就是再添加一条音轨
.
// 背景音乐 合成轨道
AVMutableCompositionTrack *compositionBGMAudioTrack = [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
// 背景音乐
AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:audioPath options:optDict];
CMTimeRange timeRange = CMTimeRangeMake(kCMTimeZero, allTime);
NSArray *bgmTracks = [asset tracksWithMediaType:AVMediaTypeAudio];
[compositionBGMAudioTrack insertTimeRange:timeRange
ofTrack:bgmTracks.firstObject
atTime:kCMTimeZero
error:nil];
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。