AVFoundation开发秘籍笔记-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;
}

猜你喜欢

转载自blog.csdn.net/fengzhixinfei/article/details/80733723
今日推荐