给视频配音

2018-03-05  本文已影响17人  Double_Chen

代码如下,导入框架#import <AVFoundation/AVFoundation.h>

//给视频配音,startTime表示开始时刻,取值范围 0-1
+ (void)dubForVideoWith:(NSURL *)fileUrl
               audioUrl:(NSURL *)audioUrl
              startTime:(CGFloat)startTime
                success:(void(^)(NSURL *url))success
                   fail:(void(^)(NSString *error))fail {
    //先检测文件是否存在
    NSFileManager *fileManager = [NSFileManager defaultManager];
    if (![fileManager fileExistsAtPath:fileUrl.path] || ![fileManager fileExistsAtPath:audioUrl.path]) {
        if (fail) {
            fail(@"不存在该资源,无法合成");
        }
        return;
    }
    
    //开始合成
    
    //获取资源
    AVAsset *videoAsset = [AVAsset assetWithURL:fileUrl];
    AVAsset *audioAsset = [AVAsset assetWithURL:audioUrl];
    
    //剪辑操作类
    AVMutableComposition *mixComposition = [[AVMutableComposition alloc] init];
    
    //视音频轨道的插入、删除和拓展接口
    AVMutableCompositionTrack *videoTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
    
    AVMutableCompositionTrack *audioTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
    
    //插入视频,此时视频是没有声音的,只有画面
    [videoTrack insertTimeRange:CMTimeRangeFromTimeToTime(kCMTimeZero, videoAsset.duration) ofTrack:[videoAsset tracksWithMediaType:AVMediaTypeVideo].firstObject atTime:kCMTimeZero error:nil];
    
    //插入音频,当音频时长小于视频时长时候会导致视频后半段没有声音
    CGFloat totalTime = audioAsset.duration.value / audioAsset.duration.timescale;  //音频总时长
    CGFloat startValue = totalTime * startTime;    //第几秒开始
    CGFloat timeScale = audioAsset.duration.timescale;  //帧率
    
    //保护
    startValue = MAX(startValue, 0);
    startValue = MIN(startValue, audioAsset.duration.value);
    
    //计算出插入时间
    CMTime atTime = CMTimeMakeWithSeconds(startValue, timeScale);
    
    //在计算出的插入时间开始插入音频
    [audioTrack insertTimeRange:CMTimeRangeFromTimeToTime(kCMTimeZero, audioAsset.duration) ofTrack:[audioAsset tracksWithMediaType:AVMediaTypeAudio].firstObject atTime:atTime error:nil];
    
    //输出路径
    NSTimeInterval current = [[NSDate date] timeIntervalSince1970];
    NSString *outputPath = [NSString stringWithFormat:@"%@/tmp/%ld.mp4",NSHomeDirectory(),(NSInteger)current];  //临时文件路径
    unlink([outputPath UTF8String]);
    NSURL *outputUrl = [NSURL fileURLWithPath:outputPath];

    //导出
    AVAssetExportSession *exporter = [[AVAssetExportSession alloc] initWithAsset:mixComposition
                                                                      presetName:AVAssetExportPresetHighestQuality];
    exporter.outputURL=outputUrl;
    exporter.outputFileType = AVFileTypeQuickTimeMovie;
    exporter.shouldOptimizeForNetworkUse = YES;
    
    [exporter exportAsynchronouslyWithCompletionHandler:^{
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"导出操作完成");
            
            if ([fileManager fileExistsAtPath:outputPath]) {
                NSLog(@"合成成功");
                if (success) {
                    success(outputUrl);
                }
            }else {
                if (fail) {
                    fail(@"文件不存在,合成失败,请在合成代码中寻找原因");
                }
            }
            
        });
    }];
}

GitHub链接

上一篇下一篇

猜你喜欢

热点阅读