最近遇到一個(gè)需求,客戶錄音試聽一下可以,就繼續(xù)向下錄制,當(dāng)客戶錄制完成后,需要把前面錄制的試聽音頻和后面的音頻進(jìn)行合并.
最初想到的方法,使用NSData對(duì)兩個(gè)音頻文件進(jìn)行合并,但是合并后,音頻文件確實(shí)變大了,但是只能播放第一個(gè)音頻. 這應(yīng)該怎么辦呢?
其實(shí)AVFoundation框架提供音視頻剪輯,合成等功能. 我在這里僅僅介紹下音頻合并,希望能起到拋磚引玉的效果.
這里需要使用到三個(gè)核心類
AVMutableComposition: 用于對(duì)音視頻軌道的添加和刪除
AVMutableCompositionTrack: 代表著一個(gè)音頻/視頻 的軌道,可以添加音頻/視頻資源
AVAssetExportSession:用于導(dǎo)出處理后的音視頻文件.
步驟
- 創(chuàng)建
AVMutableComposition - 給
AVMutableComposition添加一個(gè)新音頻的軌道,并返回音頻軌道 - 循環(huán)添加需要的音頻資源
- 導(dǎo)出合并的音頻文件
代碼
//
// HMAudioComposition.m
// HMAVAudoTools
//
// Created by 傳智.小飛燕 on 16/7/25.
// Copyright ? 2016年 itheima. All rights reserved.
#import "HMAudioComposition.h"
#import <AVFoundation/AVFoundation.h>
@implementation HMAudioComposition
/// 合并音頻文件
/// @param sourceURLs 需要合并的多個(gè)音頻文件
/// @param toURL 合并后音頻文件的存放地址
/// 注意:導(dǎo)出的文件是:m4a格式的.
+ (void) sourceURLs:(NSArray *) sourceURLs composeToURL:(NSURL *) toURL completed:(void (^)(NSError *error)) completed{
NSAssert(sourceURLs.count > 1,@"源文件不足兩個(gè)無需合并");
// 1. 創(chuàng)建`AVMutableComposition `,用于合并所有的音視頻文件
AVMutableComposition* mixComposition = [AVMutableComposition composition];
// 2. 給`AVMutableComposition` 添加一個(gè)新音頻的軌道,并返回音頻軌道
AVMutableCompositionTrack *compositionAudioTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
// 3. 循環(huán)添加需要的音頻資源
// 3.1 音頻插入的開始時(shí)間,用于記錄每次添加音頻文件的開始時(shí)間
CMTime beginTime = kCMTimeZero;
// 3.2 用于記錄錯(cuò)誤的對(duì)象
NSError *error = nil;
// 3.3 循環(huán)添加音頻資源
for (NSURL *sourceURL in sourceURLs) {
// 3.3.1 音頻文件資源
AVURLAsset *audioAsset = [[AVURLAsset alloc]initWithURL:sourceURL options:nil];
// 3.3.2 需要合并的音頻文件的播放的時(shí)間區(qū)間
CMTimeRange audio_timeRange = CMTimeRangeMake(kCMTimeZero, audioAsset.duration);
// 3.3.3 添加音頻文件
// 參數(shù)說明:
// insertTimeRange:源錄音文件的的區(qū)間
// ofTrack:插入音頻的內(nèi)容
// atTime:源音頻插入到目標(biāo)文件開始時(shí)間
// error: 插入失敗記錄錯(cuò)誤
// 返回:YES表示插入成功,`NO`表示插入失敗
BOOL success = [compositionAudioTrack insertTimeRange:audio_timeRange ofTrack:[[audioAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0] atTime:beginTime error:&error];
// 3.3.4 如果插入失敗,打印插入失敗信息
if (!success) {
NSLog(@"插入音頻失敗: %@",error);
completed(error);
return;
}
// 3.3.5 記錄下次音頻文件插入的開始時(shí)間
beginTime = CMTimeAdd(beginTime, audioAsset.duration);
}
// 4. 導(dǎo)出合并的音頻文件
// 4.0 創(chuàng)建一個(gè)導(dǎo)入M4A格式的音頻的導(dǎo)出對(duì)象
AVAssetExportSession* assetExport = [[AVAssetExportSession alloc] initWithAsset:mixComposition presetName:AVAssetExportPresetAppleM4A];
// 4.2 設(shè)置導(dǎo)入音視頻的URL
assetExport.outputURL = toURL;
// 導(dǎo)出音視頻的文件格式
assetExport.outputFileType = @"com.apple.m4a-audio";
// 4.3 導(dǎo)入出
[assetExport exportAsynchronouslyWithCompletionHandler:^{
// 4.5 分發(fā)到主線程
dispatch_async(dispatch_get_main_queue(), ^{
completed(assetExport.error);
});
}];
}
@end