当前位置:   article > 正文

iOS开发--AVFoundation视频合成(添加背景音乐)_trackswithmediatype

trackswithmediatype

前言

当下音视频处理的技术的重要性不言而喻, FFmpeg的强大不可撼动, 但是, 确实难啃. 由简递难, 我们来看看苹果原生的API如何做到对视频素材进行处理的.

AVFoundation既可以对视频进行播放, 同时也可以对视频素材进行处理, 此类合成共分为两章:

  1. 简单视频合成
  2. 视频与音频的合成

正文

知识点
  1. AVMutableComposition 合成工具
  2. AVMutableCompositionTrack 合成工具中的轨道
  3. AVAsset 视频素材的载体
  4. AVAssetTrack 素材轨道
  5. 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);
        }
    }];
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86

添加背景音乐

添加背景音乐, 其实就是再添加一条音轨.

	// 背景音乐 合成轨道
	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];
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/382006
推荐阅读
相关标签
  

闽ICP备14008679号