最近在做音频合并这块需求,然后遇见了几种形式,这里做一个总结。
第一种 可网络可本地 ,可调整音量,范围等 定制化还比较高
1.基本类介绍
refer:https://docs.microsoft.com/en-us/dotnet/api/avfoundation.avcomposition?view=xamarin-ios-sdk-12
- AVAsset 媒体信息
- AVURLAsset 根据URL路径创建的媒体信息
- AVAssetTrack 资源轨道,包括音频轨道和视频轨道
- AVMutableAudioMixInputParameters音频操作参数
- AVMutableComposition 继承自AVComposition,用于从现有Asset创建新合成的可变对象。包含多个轨道的媒体信息,可以添加、删除轨道
- AVAssetExportSession 导出
具体实现如下:
#pragma mark - 音频与音频的合并
+ (void)mixOriginalAudio:(NSURL *)originalAudioPath
originalAudioVolume:(float)originalAudioVolume
bgAudioPath:(NSURL *)bgAudioPath
bgAudioVolume:(float)bgAudioVolume
outPutFileName:(NSString *)fileName
completionBlock:(CompletionBlock)completionBlock
{
if (originalAudioPath == nil) {
return;
}
if (bgAudioPath == nil) {
return;
}
if (originalAudioVolume > 1.0) {
originalAudioVolume = 1.0f;
}
if (originalAudioVolume < 0) {
originalAudioVolume = 0.0f;
}
if (bgAudioVolume > 1.0) {
bgAudioVolume = 1.0f;
}
if (bgAudioVolume < 0) {
bgAudioVolume = 0.0f;
}
dispatch_async(dispatch_get_global_queue(0, 0), ^{
AVURLAsset *originalAudioAsset = [AVURLAsset assetWithURL:originalAudioPath];
AVURLAsset *bgAudioAsset = [AVURLAsset assetWithURL:bgAudioPath];
AVMutableComposition *compostion = [AVMutableComposition composition];
AVMutableCompositionTrack *originalAudio = [compostion addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:0];
[originalAudio insertTimeRange:CMTimeRangeMake(kCMTimeZero, originalAudioAsset.duration) ofTrack:[originalAudioAsset tracksWithMediaType:AVMediaTypeAudio].firstObject atTime:kCMTimeZero error:nil];
AVMutableCompositionTrack *bgAudio = [compostion addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:0];
[bgAudio insertTimeRange:CMTimeRangeMake(kCMTimeZero, originalAudioAsset.duration) ofTrack:[bgAudioAsset tracksWithMediaType:AVMediaTypeAudio].firstObject atTime:kCMTimeZero error:nil];
//播放速率会受影响
NSUInteger originalAudioAssetTotalSeconds = CMTimeGetSeconds(originalAudioAsset.duration);
NSUInteger bgAudioAssetTotalSeconds = CMTimeGetSeconds(bgAudioAsset.duration);
if (originalAudioAssetTotalSeconds>bgAudioAssetTotalSeconds) {
[bgAudio scaleTimeRange:CMTimeRangeMake(kCMTimeZero, bgAudioAsset.duration) toDuration:originalAudioAsset.duration];
}
/** 得到对应轨道中的音频声音信息,并更改 */
AVMutableAudioMixInputParameters *originalAudioParameters = [AVMutableAudioMixInputParameters audioMixInputParametersWithTrack:originalAudio];
[originalAudioParameters setVolume:originalAudioVolume atTime:kCMTimeZero];
AVMutableAudioMixInputParameters *bgAudioParameters = [AVMutableAudioMixInputParameters audioMixInputParametersWithTrack:bgAudio];
[bgAudioParameters setVolume:bgAudioVolume atTime:kCMTimeZero];
/** 赋给对应的类 */
AVMutableAudioMix *audioMix = [AVMutableAudioMix audioMix];
audioMix.inputParameters = @[ originalAudioParameters, bgAudioParameters ];
AVAssetExportSession *session = [[AVAssetExportSession alloc] initWithAsset:compostion presetName:AVAssetExportPresetAppleM4A];
/** 设置输出路径 */
NSURL *outputPath = [self exporterAudioPathWithFileName:fileName];
session.audioMix = audioMix;
session.outputURL = outputPath;
session.outputFileType = AVFileTypeAppleM4A;
session.shouldOptimizeForNetworkUse = YES;
[session exportAsynchronouslyWithCompletionHandler:^{
dispatch_async(dispatch_get_main_queue(), ^{
switch ([session status]) {
case AVAssetExportSessionStatusFailed: {
NSLog(@"合成失败:%@", [[session error] description]);
completionBlock(NO, outputPath);
} break;
case AVAssetExportSessionStatusCancelled: {
completionBlock(NO, outputPath);
} break;
case AVAssetExportSessionStatusCompleted: {
completionBlock(YES, outputPath);
} break;
default: {
completionBlock(NO, outputPath);
} break;
}
});
}];
});
}
⚠️压缩时长
- 更改给定时间范围内所有轨道的时长。
- (void)scaleTimeRange:(CMTimeRange)timeRange
toDuration:(CMTime)duration;
参数timeRange:要缩放的合成轨道的时间范围。
参数duration:新的时长。
受缩放操作影响的每个轨道段将以等于其结果时间映射的source.duration/target.duration的速率呈现。
⚠️设置背景音乐时长和插入时间
[bgAudio insertTimeRange:CMTimeRangeMake(kCMTimeZero, originalAudioAsset.duration) ofTrack:[bgAudioAsset tracksWithMediaType:AVMediaTypeAudio].firstObject atTime:kCMTimeZero error:nil];
因为我的需求是加入背景音乐给录音,所以将背景音乐从头插入kCMTimeZero 插入时长为录音的时长 originalAudioAsset.duration
⚠️注意导出格式
首先是输出路径,切记切记这里的后缀一定要和上面选择的呼应,比如我写的格式为AVAssetExportPresetAppleM4A那么我的文件后缀就需要为.m4a,如果用.MP3这种的话是无法正确生成出文件的,有可能会出现空文件的存在.一定要注意!!!
⚠️传入网络链接的时候 需要将网络链接下载下来转成本地路径进行传入。
refer: https://github.com/Anny-github/AudioPlayerManager
第二种 本地音频合并,可以调整音量
https://github.com/daybreak1024/ZLMMixAudio