利用AVFoundation中的AVAudioMix实现混音

正如可以用AVVideoComposition实现视频的混合一样,也可以用AVAudioMix实现音频的混合,用法也跟AVVideoComposition很相似,
Demo见https://github.com/Phelthas/TEST_XMLCommon

首先创建一个AVMutableComposition,将需要混音的视频或者音频轨道添加进去

    AVAssetTrack *videoTrack = [videoAsset tracksWithMediaType:AVMediaTypeVideo].firstObject;
    AVAssetTrack *audioTrack1 = [videoAsset tracksWithMediaType:AVMediaTypeAudio].firstObject;
    AVAssetTrack *audioTrack2 = [audioAsset tracksWithMediaType:AVMediaTypeAudio].firstObject;
    AVMutableComposition *composition = [AVMutableComposition composition];
    AVMutableCompositionTrack *videoCompositionTrack = [composition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
    [videoCompositionTrack insertTimeRange:videoTimeRange ofTrack:videoTrack atTime:kCMTimeZero error:nil];
    AVMutableCompositionTrack *audioCompositionTrack1 = [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
    [audioCompositionTrack1 insertTimeRange:videoTimeRange ofTrack:audioTrack1 atTime:kCMTimeZero error:nil];
    AVMutableCompositionTrack *audioCompositionTrack2 = [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
    [audioCompositionTrack2 insertTimeRange:CMTimeRangeMake(kCMTimeZero, audioAsset.duration) ofTrack:audioTrack2 atTime:kCMTimeZero error:nil];
    self.composition = composition;

然后创建AVMutableAudioMix,创建对应音轨的AVMutableAudioMixInputParameters并设置音量,赋值给AVMutableAudioMix的inputParameters即可。

注意这里最好用添加到composition中的AVMutableCompositionTrack来初始化AVMutableAudioMixInputParameters,否则还需要手动设置trackID。(每个track的trackID必须不一样)

    AVMutableAudioMix *audioMix = [AVMutableAudioMix audioMix];
    // 注意:这里必须要用audioCompositionTrack1而不能用audioTrack1,否则会因为trackId不一致而不生效
    AVMutableAudioMixInputParameters *inputParameters1 = [AVMutableAudioMixInputParameters audioMixInputParametersWithTrack:audioCompositionTrack1];
    [inputParameters1 setVolume:1 atTime:kCMTimeZero];
    AVMutableAudioMixInputParameters *inputParameters2 = [AVMutableAudioMixInputParameters audioMixInputParametersWithTrack:audioCompositionTrack2];
    [inputParameters2 setVolume:0.5 atTime:kCMTimeZero];
    audioMix.inputParameters = @[inputParameters1, inputParameters2];
    self.audioMix = audioMix;

最后将audioMix赋值给playerItem即可

    AVPlayerItem *playerItem = [AVPlayerItem playerItemWithAsset:composition];
    playerItem.audioMix = audioMix;
    self.playerItem = playerItem;
    AVPlayer *player = [AVPlayer playerWithPlayerItem:playerItem];
    self.player = player;
    [player play];

完成~

如果需要实时修改混音的音量(比如用slider分别控制音轨的音量),需要每次都重新生成AVAudioMix才行,且里面的inputParameters也需要重新生成或者mutableCopy,直接修改原来的音量再赋值是不行的

    AVMutableAudioMix *audioMix = [AVMutableAudioMix audioMix];
    AVMutableAudioMixInputParameters *parameters1 = [[self.audioMix.inputParameters objectAtIndex:0] mutableCopy];
    [parameters1 setVolume:self.slider1.value atTime:kCMTimeZero];
    AVMutableAudioMixInputParameters *parameters2 = [[self.audioMix.inputParameters objectAtIndex:1] mutableCopy];
    [parameters2 setVolume:self.slider2.value atTime:kCMTimeZero];
    audioMix.inputParameters = @[parameters1, parameters2];
    self.playerItem.audioMix = audioMix;

导出时只需要将AudioMix赋值给exportSession即可,其他完全一样
注意:导出后多个音轨会合并成一个

    NSString *userCacheDirectory = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0];
    NSString *outputURLString = [NSString stringWithFormat:@"%@/audioMixOutput.mp4", userCacheDirectory];
    NSLog(outputURLString);
    [kLXMFileManager removeItemAtPath:outputURLString error:nil];
    AVAssetExportSession *exportSession = [AVAssetExportSession exportSessionWithAsset:self.composition presetName:AVAssetExportPresetHighestQuality];
    exportSession.outputFileType = AVFileTypeMPEG4;
    exportSession.outputURL = [NSURL fileURLWithPath:outputURLString];
    exportSession.shouldOptimizeForNetworkUse = YES;
    exportSession.audioMix = self.audioMix;
    [exportSession exportAsynchronouslyWithCompletionHandler:^{
        if (exportSession.status == AVAssetExportSessionStatusCompleted) {
            NSLog(@"export success");
        } else {
            NSLog(@"export failed: %@", exportSession.error);
        }
    }];

完整Demo

你可能感兴趣的:(利用AVFoundation中的AVAudioMix实现混音)