2018-06-19AVFoundation开发秘籍笔记-010混合音频初接触

直接组合音频会有一些问题:

  • 1、音乐轨道刚开始播放时音量就很大,在组合资源结束时突然停止。如果可以开始逐渐增加,结束的时候逐渐减小会提升体验。
  • 2、画外音轨道的处理。音乐轨道声音完全父爱画外音的声音,几乎听不到画外音。

框架提供AVAudioMix来解决上面的两个问题。

AVAudioMix用来在组合音频轨道中进行自定义音频的处理。

AVAudioMix所具有的音频处理方法是由它的输入参数集定义的。参数是AVAudioMixInputParameters类型对象。

AVAudioMixAVAudioMixInputParameters都是不可变对象,他们适用于AVPlayerItem和AVAssetExportSession之类的客户端提供相关数据,不过不能操作其状态。

如果需要创建自电影音频混合,需要用AVMutableAudioMixAVMutableAudioMixInputParameters

(一)、音量

一个组合资源播放或导出时,默认以最大音量或正常音量播放音频轨道。只有一个但音频轨道时,这样的方法比较容易接收。如果一个组合资源包含多个音频资源,对于多音频轨道,每个声音都在争夺空间,就会导致一些声音无法被听到。

AVFoundation将音量定义为一个标准化的浮点型数值:0.0(静音)-1.0(最大音量)。

(二)、添加设置

两种方式:

  • setVolume:(float)volume atTime:(CMTime)time --在time这个时间点将该轨道音频音量调至volume。

  • setVolumeRampFromStartVolume:(float)startVolume toEndVolume:(float)endVolume timeRange:(CMTimeRange)timeRange --在timeRange这个时间范围内,将该轨道音频的音量由startVolume平缓变动到endVolume。


//创建新的AVMutableComposition并添加AVCompositionTrack对象。
self.composition = [AVMutableComposition composition];
[self addCompositionTrackOfType:AVMediaTypeVideo withMediaItems:self.timeline.videos];
[self addCompositionTrackOfType:AVMediaTypeAudio withMediaItems:self.timeline.voiceOvers];
    
AVMutableCompositionTrack *musicTrack = [self addCompositionTrackOfType:AVMediaTypeAudio withMediaItems:self.timeline.musicItems];

//创建实例,保存输入参数
self.audioMix = [AVMutableAudioMix audioMix];
//创建AVMutableAudioMixInputParameters实例
//将它与传递给方法的AVCompositionTrack进行关联
AVMutableAudioMixInputParameters *parameters = [AVMutableAudioMixInputParameters audioMixInputParametersWithTrack: musicTrack];
[parameters setVolumeRampFromStartVolume:automation.startVolume toEndVolume:automation.endVolume timeRange:automation.timeRange];
self.audioMix.inputParameters = @[parameters];

// 播放资源对象, 关联混合音频
- (AVPlayerItem *)makePlayable {

    // Listing 10.2
    //创建一个带有AVComposition实例的AVPlayerItem。
    AVPlayerItem *playerItem = [AVPlayerItem playerItemWithAsset:[self.composition copy]];
    //设置audioMix对象作为播放器条目的audioMix属性。就可以在应用程序视频播放器中播放音频时应用音频处理
    playerItem.audioMix = self.audioMix;
    return playerItem;
}

//导出会话 关联混合音频
- (AVAssetExportSession *)makeExportable {

    // Listing 10.2
    NSString *preset = AVAssetExportPresetHighestQuality;
    AVAssetExportSession *session = [AVAssetExportSession exportSessionWithAsset:[self.composition copy] presetName:preset];
    session.audioMix = self.audioMix;

    return session;
}

找到对应的音频轨道,修改该音频轨道的audioMix

这里的示例使用单音频轨道的视频,对于多音频轨道混合音频处理,还需要深入学习。

示例代码:

@interface THAudioMixCompositionBuilder ()
@property (strong, nonatomic) THTimeline *timeline;
@property (strong, nonatomic) AVMutableComposition *composition;
@end

@implementation THAudioMixCompositionBuilder

- (id)initWithTimeline:(THTimeline *)timeline {
    self = [super init];
    if (self) {
        _timeline = timeline;
    }
    return self;
}

- (id <THComposition>)buildComposition {

    // Listing 10.4
    
    //创建新的AVMutableComposition并添加AVCompositionTrack对象。
    self.composition = [AVMutableComposition composition];
    [self addCompositionTrackOfType:AVMediaTypeVideo withMediaItems:self.timeline.videos];
    [self addCompositionTrackOfType:AVMediaTypeAudio withMediaItems:self.timeline.voiceOvers];
    
    AVMutableCompositionTrack *musicTrack = [self addCompositionTrackOfType:AVMediaTypeAudio withMediaItems:self.timeline.musicItems];
    
    // 创建AVAudioMix实例,接收引用音量调整的轨道的引用
    AVAudioMix *audioMix = [self buildAudioMixWithTrack:musicTrack];
    //返回一个THAudioMixComposition,传递给组合和音频混合
    return [THAudioMixComposition compositionWithComposition:self.composition audioMix:audioMix];;
}

- (AVAudioMix *)buildAudioMixWithTrack:(AVCompositionTrack *)track {

    // Listing 10.5
    // 从时间轴得到音乐轨道的THAudioItem实例。示例中止允许添加一个单独的音乐轨道,所以可以取第一个
    THAudioItem *item = [self.timeline.musicItems firstObject];
    if (item) {
        //创建实例,保存输入参数
        AVMutableAudioMix *audioMix = [AVMutableAudioMix audioMix];
        //创建AVMutableAudioMixInputParameters实例,将它与传递给方法的AVCompositionTrack进行关联
        AVMutableAudioMixInputParameters *parameters = [AVMutableAudioMixInputParameters audioMixInputParametersWithTrack:track];
        for (THVolumeAutomation *automation in item.volumeAutomation) {
            //遍历音频条目,对每个实例在parameters对象对象上定义一个音量渐变。
            [parameters setVolumeRampFromStartVolume:automation.startVolume toEndVolume:automation.endVolume timeRange:automation.timeRange];
//            [parameters setVolume:automation.endVolume atTime:CMTimeMake(3, 1)];
        }
        // 将parameters对象封装在NSArray中,设置他为音频混合的inputParameters
        audioMix.inputParameters = @[parameters];
        return audioMix;
    }

    return nil;
}

- (AVMutableCompositionTrack *)addCompositionTrackOfType:(NSString *)type   // 5
                                          withMediaItems:(NSArray *)mediaItems {

    if (!THIsEmpty(mediaItems)) {

        CMPersistentTrackID trackID = kCMPersistentTrackID_Invalid;

        AVMutableCompositionTrack *compositionTrack =
            [self.composition addMutableTrackWithMediaType:type
                                          preferredTrackID:trackID];
        // Set insert cursor to 0
        CMTime cursorTime = kCMTimeZero;

        for (THMediaItem *item in mediaItems) {

            if (CMTIME_COMPARE_INLINE(item.startTimeInTimeline,
                                      !=,
                                      kCMTimeInvalid)) {
                cursorTime = item.startTimeInTimeline;
            }

            AVAssetTrack *assetTrack =
                [[item.asset tracksWithMediaType:type] firstObject];

            [compositionTrack insertTimeRange:item.timeRange
                                      ofTrack:assetTrack
                                       atTime:cursorTime
                                        error:nil];

            // Move cursor to next item time
            cursorTime = CMTimeAdd(cursorTime, item.timeRange.duration);
        }

        return compositionTrack;
    }

    return nil;
}

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

推荐阅读更多精彩内容