美文网首页直播JC专题Ios开发学习
AVFoundation详细解析(一)视频合并与混音

AVFoundation详细解析(一)视频合并与混音

作者: 落影loyinglin | 来源:发表于2016-06-29 14:21 被阅读2650次

    回顾

    在上一篇GPUImage详细解析(八)视频合并混音介绍了如何使用GPUImage进行视频的合并,以及混音。这次使用AVFoundation框架来实现这个功能。

    概念

    • AVPlayer 视频播放类,本身不显示视频,需创建一个AVPlayerLayer层,添加到视图
    • AVAssetTrack 资源轨道,包括音频轨道和视频轨道
    • AVAsset 媒体信息
    • AVURLAsset 根据URL路径创建的媒体信息
    • AVPlayerItem媒体资源管理对象,管理视频的基本信息和状态
    • AVMutableVideoCompositionInstruction 视频操作指令
    • AVMutableVideoCompositionLayerInstruction视频轨道操作指令,需要添加到AVMutableVideoCompositionInstruction
    • AVMutableAudioMixInputParameters音频操作参数
    • AVMutableComposition 包含多个轨道的媒体信息,可以添加、删除轨道
    • AVMutableVideoComposition视频操作指令集合

    效果

    视频效果如下,音频效果可运行demo

    核心思路

    分别加载多个AVURLAsset,用GCD保证异步加载完成后回调,调用Editor类配置轨道信息、视频操作指令和音频指令参数。


    具体细节

    流程图如下


    a、配置轨道信息

    • 1,计算变化的长度,确保变换的长度不大于最小的视频的长度的一半;

    思考1:demo中是如何计算小于一半,为何要小于一半?

    • 2,添加两个视频轨道,两个音频轨道;
    • 3,在视频索引对应的轨道(%2),插入视频轨道信息和音频轨道信息;

    思考2:当多个视频在同一个音轨插入多个信息,如何保证不重叠?

    • 4,计算直接播放和变换的时间;
        // 确保最后合并后的视频,变换长度不会超过最小长度的一半
        CMTime transitionDuration = self.transitionDuration;
        for (i = 0; i < clipsCount; i++ ) {
            NSValue *clipTimeRange = [self.clipTimeRanges objectAtIndex:i];
            if (clipTimeRange) {
                CMTime halfClipDuration = [clipTimeRange CMTimeRangeValue].duration;
                halfClipDuration.timescale *= 2;
                transitionDuration = CMTimeMinimum(transitionDuration, halfClipDuration);
            }
        }
        AVMutableCompositionTrack *compositionVideoTracks[2];
        AVMutableCompositionTrack *compositionAudioTracks[2];
        compositionVideoTracks[0] = [composition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid]; // 添加视频轨道0
        compositionVideoTracks[1] = [composition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid]; // 添加视频轨道1
        compositionAudioTracks[0] = [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid]; // 添加音频轨道0
        compositionAudioTracks[1] = [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid]; // 添加音频轨道1
    

    b、配置视频操作指令

    • 1,新建视频操作指令集合;
    • 2,根据视频所在对应的轨道(%2),新建视频操作指令passThroughInstruction,长度为passThroughTimeRanges,同时定义passThroughLayer直接播放的视频轨道操作指令,并设置passThroughLayer为passThroughInstruction的视频轨道操作指令集合;
    • 3,根据视频所在对应轨道,新建视频操作指令transitionInstruction,长度为transitionTimeRanges,同时根据轨道定义视频轨道操作指令fromLayer和toLayer,并设置fromLayer和toLayer的变换方式与时间;
    • 4,把passThroughInstruction和transitionInstruction添加到视频指令集合;
            AVMutableVideoCompositionInstruction *passThroughInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction]; // 新建指令
            passThroughInstruction.timeRange = passThroughTimeRanges[i]; // 直接播放
            AVMutableVideoCompositionLayerInstruction *passThroughLayer = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:compositionVideoTracks[alternatingIndex]]; // 视频轨道操作指令
            
            passThroughInstruction.layerInstructions = [NSArray arrayWithObject:passThroughLayer];
            [instructions addObject:passThroughInstruction]; // 添加到指令集合
            
            if (i+1 < clipsCount) { // 不是最后一个
                AVMutableVideoCompositionInstruction *transitionInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction]; // 新建指令
                transitionInstruction.timeRange = transitionTimeRanges[i]; // 变换时间
                AVMutableVideoCompositionLayerInstruction *fromLayer = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:compositionVideoTracks[alternatingIndex]]; // 视频轨道操作指令
                AVMutableVideoCompositionLayerInstruction *toLayer = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:compositionVideoTracks[1-alternatingIndex]]; // 新的轨道指令
                // 1 dao 0
                [fromLayer setOpacityRampFromStartOpacity:1.0 toEndOpacity:0.0 timeRange:transitionTimeRanges[i]];
                // 目的轨道,从0到1
                [toLayer setOpacityRampFromStartOpacity:0.0 toEndOpacity:1.0 timeRange:transitionTimeRanges[i]];
                
                transitionInstruction.layerInstructions = [NSArray arrayWithObjects:toLayer, fromLayer, nil];
                [instructions addObject:transitionInstruction];
            }
    

    c、配置音频轨道参数

    • 1,新建音频轨道参数集合;
    • 2,根据视频所在索引,新建当前音轨的参数trackMix1,设置变换时间内音量从1.0到0.0;
    • 3,根据视频所在索引,新建另外一条音轨的参数trackMix2,设置变换时间内音量从0.0到1.0;设置直接播放时间内音量一直为1.0;
    • 4,把参数trackMix1和trackMix2添加到音频轨道参数集合;
    AVMutableAudioMixInputParameters *trackMix1 = [AVMutableAudioMixInputParameters audioMixInputParametersWithTrack:compositionAudioTracks[alternatingIndex]]; // 音轨0的参数
    [trackMix1 setVolumeRampFromStartVolume:1.0 toEndVolume:0.0 timeRange:transitionTimeRanges[i]]; // 音轨0,变换期间音量从1.0到0.0
    [trackMixArray addObject:trackMix1];
    AVMutableAudioMixInputParameters *trackMix2 = [AVMutableAudioMixInputParameters audioMixInputParametersWithTrack:compositionAudioTracks[1 - alternatingIndex]]; // 音轨1的参数
    [trackMix2 setVolumeRampFromStartVolume:0.0 toEndVolume:1.0 timeRange:transitionTimeRanges[i]]; // 变换期间音量从0.0到1.0           
    [trackMixArray addObject:trackMix2];
    

    总结

    AVPlayer通过KVO监听rate属性,status属性,用notification来监听播放完成;
    AVPlayer和AVPlayerItem的使用不复杂,解析集中在SimpleEditor类如何配置轨道信息和音视频操作指令。
    代码地址可以点这里

    思考

    思考1

    通过timescale*2,再用CMTimeMinimum;处于中间的视频要经历两次变换,故而变换的长度不能大于最小视频长度的一半;

    思考2

    音轨插入的函数有开始点和持续时间,只要保证区间不重叠,音频就不会重叠;

    相关文章

      网友评论

      • bc049a7130d1:想问下楼主,多段视频合并为同一个视频,可以只用一个AVMutableCompositionTrack吗?还是有几段视频就用几个AVMutableCompositionTrack?
      • GeniusWong:你好, 我现在在做一个视频录制的功能 。 一个视频在屏幕上播放, 可以在视频上画线,同时要录屏。 最后生成一个视频。 但是 AVPlayer 不允许被录制 。
        GeniusWong:@落影loyinglin 但是视频是可以用进度条拖动的,可以暂停,录音, 就是教学的场景。 只能用录屏啊。 其实我要实现的 跟这个App 一样: Hudl Technique Golf: Slow Motion Swing Analysis 作者是 UberSense Inc
        https://appsto.re/cn/XopRI.i
        落影loyinglin:@GeniusWong 如果是播放,划线,然后用录屏的方式,cpu会过载的
        落影loyinglin:@GeniusWong 播放和划线分开吧。最后把划线的视频和播放的视频混合。
      • 4d4aa2a610a2:楼主,请问下avplayer是不是不能直接播放mov格式,avi格式的视频,是不是直接支持MP4
        格式的视频
        落影loyinglin:@筱筱吖6002 应该也行的
        4d4aa2a610a2:@落影loyinglin 那mov格式的是不能直接播放吗?需要ffempg转码吗?
        落影loyinglin:@筱筱吖6002 可以播放avi格式的,
      • youngyunxing:大牛,请受小弟一拜

      本文标题:AVFoundation详细解析(一)视频合并与混音

      本文链接:https://www.haomeiwen.com/subject/hjntjttx.html