GPUImage详细解析(八)视频合并混音

回顾

GPUImage源码解析、图片模糊、视频滤镜、视频水印、文字水印和动态图片水印GPUImage的大多数功能已经介绍完毕,这次的demo是源于简书的一位简友问我如何用GPUImage进行混音,他需要对视频添加水印背景音乐
经过一番研究,找到了一个解决方案,下面我们按照这个方案进行实践,并学习如何进行混音

知识储备

1、AVFoundation

  • AVAssetReader 从原始数据里获取音视频数据
  • AVAssetReaderTrackOutput 读取每帧的CMSampleBufferRef
  • AVAssetTrack 视频轨迹,视频来源
  • AVAsset 主要用于获取多媒体信息,抽象类不能直接使用
  • AVURLAsset AVAsset的子类,根据URL路径创建包含媒体信息的AVURLAsset对象
  • AVPlayerItem媒体资源管理对象,管理视频的基本信息和状态

2、GCD

  • dispatch_group_notify 等待group里面所有任务结束后调用
  • dispatch_group_enter 开始一个group任务
  • dispatch_group_leave 结束一个group任务

用处:在dispatch_queue中开始一个group任务,当group里面所有任务完成调用再执行最后的任务。
在demo主要用于等待异步加载Reader等待视频合并完成

核心思路

  • 1、异步初始化音视频的AVAssetReader;
  • 2、调用dispatch_group_leave通知异步加载完成;
  • 3、通过dispatch_group_notify开始录制;
  • 4、开始异步合并视频信息、音频信息;
  • 5、调用dispatch_group_leave通知合并完成;
  • 6、录制结束,并回调completionBlock;


具体细节

1、音频流解析

  • 1、根据movieFile的url创建AVAsset对象;
  • 2、根据asset加载轨道信息;
  • 3、分别添加AVMutableCompositionTrack到AVMutableComposition对象上;
  • 4、为音频assetReader设置mixComposition对象;
  • 5、把assetAudioReaderTrackOutput设置为音频信息的输出;


    多个音轨合并为一的流程图

2、视频流解析

视频流的解析在解析六解析七已经详细介绍过。

3、THImageMovieWriter对象解析

THImageMovieWriter对象和GPUImageMovieWriter非常类似,核心的逻辑也是分为音频信息写入和视频信息写入。


代码解析

右边是代码地址

THImageMovie

添加了renderNextFrame方法。如果还有下一帧视频信息,那么返回Yes,如果没有则返回No。

- (BOOL)renderNextFrame {
    __unsafe_unretained THImageMovie *weakSelf = self;
    if (reader.status == AVAssetReaderStatusReading && (!_shouldRepeat || keepLooping))
    {

        return [weakSelf readNextVideoFrameFromOutput:readerVideoTrackOutput];
    }

    if (reader.status == AVAssetWriterStatusCompleted) {
        NSLog(@"movie: %@ reading is done", self.url.lastPathComponent);
        [reader cancelReading];

        [weakSelf endProcessing];
    }
    return NO;
}

THImageMovieWriter

下面是核心的逻辑,设置多个音轨的合并信息,并通过AVMutableComposition设置为AVAssetReader的输入。

/**
 *  设置读取音频信息的Reader
 */
- (void)setupAudioAssetReader {
    
    NSMutableArray *audioTracks = [NSMutableArray array];
    
    for(THImageMovie *movie in self.movies){
        AVAsset *asset = movie.asset;
        if(asset){
            NSArray *_audioTracks = [asset tracksWithMediaType:AVMediaTypeAudio];
            if(_audioTracks.count > 0){
                [audioTracks addObject:_audioTracks.firstObject];
            }
        }
    }
    AVMutableComposition* mixComposition = [AVMutableComposition composition];
    
    for(AVAssetTrack *track in audioTracks){
        if(![track isKindOfClass:[NSNull class]]){
            NSLog(@"track url: %@ duration: %.2f", track.asset, CMTimeGetSeconds(track.asset.duration));
            AVMutableCompositionTrack *compositionCommentaryTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio
                                                                     
                                                                                                preferredTrackID:kCMPersistentTrackID_Invalid];
            [compositionCommentaryTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, track.asset.duration)
                                                ofTrack:track
                                                 atTime:kCMTimeZero error:nil];
        }
    }
    
    self.assetAudioReader = [AVAssetReader assetReaderWithAsset:mixComposition error:nil];
    self.assetAudioReaderTrackOutput =
    [[AVAssetReaderAudioMixOutput alloc] initWithAudioTracks:[mixComposition tracksWithMediaType:AVMediaTypeAudio]
                                               audioSettings:nil];
    
    [self.assetAudioReader addOutput:self.assetAudioReaderTrackOutput];
}

总结

为什么GPUImage没有支持音轨合并?
GPUImage的核心是响应链,通过GPU对图像进行加工,并且download下来。
而音频信息没有这么流畅的操作,作者没有进行支持。

苹果的官方有纯AVFoundation实现的视频合并和音频合并,但是学习的成本非常高,研究了几天还是没有吃透。而且和GPUImage没有关系,就不写入本次教程,留待以后单开一篇。

AVFoundation的内容还不够熟悉,这次很多时间是花在理解和消化音轨相关的知识。

留下一个思考题:

GPUImage做出来的视频有时候会遇到视频特别长,或者是没有声音的情况,可能是什么原因导致的?

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,406评论 5 475
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,976评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,302评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,366评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,372评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,457评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,872评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,521评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,717评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,523评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,590评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,299评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,859评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,883评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,127评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,760评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,290评论 2 342

推荐阅读更多精彩内容