美文网首页程序员
2018-06-19AVFoundation开发秘籍笔记-010

2018-06-19AVFoundation开发秘籍笔记-010

作者: 竹与豆 | 来源:发表于2018-06-19 14:45 被阅读39次

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

    • 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;
    }
    
    

    相关文章

      网友评论

        本文标题:2018-06-19AVFoundation开发秘籍笔记-010

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