ios 边录音边放_iOS 录音、音频的拼接剪切以及边录边压缩转码
總體內(nèi)容
1、錄音實(shí)現(xiàn)
2、錄音的編輯 (拼接音頻:可以設(shè)置多段,音頻的剪切:按照時(shí)間段剪切)
3、lame靜態(tài)庫進(jìn)行壓縮轉(zhuǎn)碼
一、錄音實(shí)現(xiàn)
1.1、導(dǎo)入 AVFoundation 框架,多媒體的處理, 基本上都使用這個(gè)框架#import?
1.2、使用 AVAudioRecorder 進(jìn)行錄音,定義一個(gè)JKAudioTool 管理錄音的類
(1)、定義一個(gè)錄音對(duì)象,懶加載@property?(nonatomic,?strong)?AVAudioRecorder?*audioRecorder;
-(AVAudioRecorder?*)audioRecorder
{
if?(!_audioRecorder)?{
//?0.?設(shè)置錄音會(huì)話
/**
AVAudioSessionCategoryPlayAndRecord:?可以邊播放邊錄音(也就是平時(shí)看到的背景音樂)
*/
[[AVAudioSession?sharedInstance]?setCategory:AVAudioSessionCategoryPlayAndRecord?error:nil];
//?啟動(dòng)會(huì)話
[[AVAudioSession?sharedInstance]?setActive:YES?error:nil];
//?1.?確定錄音存放的位置
NSURL?*url?=?[NSURL?URLWithString:self.recordPath];
//?2.?設(shè)置錄音參數(shù)
NSMutableDictionary?*recordSettings?=?[[NSMutableDictionary?alloc]?init];
//?設(shè)置編碼格式
/**
kAudioFormatLinearPCM:?無損壓縮,內(nèi)容非常大
kAudioFormatMPEG4AAC
*/
[recordSettings?setValue?:[NSNumber?numberWithInt:?kAudioFormatLinearPCM]?forKey:?AVFormatIDKey];
//?采樣率(通過測(cè)試的數(shù)據(jù),根據(jù)公司的要求可以再去調(diào)整),必須保證和轉(zhuǎn)碼設(shè)置的相同
[recordSettings?setValue?:[NSNumber?numberWithFloat:11025.0]?forKey:?AVSampleRateKey];
//?通道數(shù)(必須設(shè)置為雙聲道,?不然轉(zhuǎn)碼生成的?MP3?會(huì)聲音尖銳變聲.)
[recordSettings?setValue?:[NSNumber?numberWithInt:2]?forKey:?AVNumberOfChannelsKey];
//音頻質(zhì)量,采樣質(zhì)量(音頻質(zhì)量越高,文件的大小也就越大)
[recordSettings?setValue:[NSNumber?numberWithInt:AVAudioQualityMin]?forKey:AVEncoderAudioQualityKey];
//?3.?創(chuàng)建錄音對(duì)象
_audioRecorder?=?[[AVAudioRecorder?alloc]?initWithURL:url?settings:recordSettings?error:nil];
_audioRecorder.meteringEnabled?=?YES;
}
return?_audioRecorder;
}提示:設(shè)置 AVAudioSessionCategoryPlayAndRecord: 可以邊播放邊錄音(也就是平時(shí)看到的背景音樂)[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];
AVSampleRateKey 必須保證和轉(zhuǎn)碼設(shè)置的相同.
AVNumberOfChannelsKey 必須設(shè)置為雙聲道, 不然轉(zhuǎn)碼生成的 MP3 會(huì)聲音尖銳變聲.
(2)、開始錄音-?(void)beginRecordWithRecordPath:?(NSString?*)recordPath?{
//?記錄錄音地址
_recordPath?=?recordPath;
//?準(zhǔn)備錄音
[self.audioRecorder?prepareToRecord];
//?開始錄音
[self.audioRecorder?record];
}
(3)、結(jié)束錄音-?(void)endRecord?{
[self.audioRecorder?stop];
}
(4)、暫停錄音-?(void)pauseRecord?{
[self.audioRecorder?pause];
}
(5)、刪除錄音-?(void)deleteRecord?{
[self.audioRecorder?stop];
[self.audioRecorder?deleteRecording];
}
(6)、重新錄音-?(void)reRecord?{
self.audioRecorder?=?nil;
[self?beginRecordWithRecordPath:self.recordPath];
}
(7)、更新音頻測(cè)量值-(void)updateMeters
{
[self.audioRecorder?updateMeters];
}提示:更新音頻測(cè)量值,注意如果要更新音頻測(cè)量值必須設(shè)置meteringEnabled為YES,通過音頻測(cè)量值可以即時(shí)獲得音頻分貝等信息
@property(getter=isMeteringEnabled) BOOL meteringEnabled:是否啟用音頻測(cè)量,默認(rèn)為NO,一旦啟用音頻測(cè)量可以通過updateMeters方法更新測(cè)量值
(8)、獲得指定聲道的分貝峰值-?(float)peakPowerForChannel0{
[self.audioRecorder?updateMeters];
return?[self.audioRecorder?peakPowerForChannel:0];
}提示:獲得指定聲道的分貝峰值,注意如果要獲得分貝峰值必須在此之前調(diào)用updateMeters方法
二、錄音的編輯
2.1、理論基礎(chǔ)AVAsset:音頻源
AVAssetTrack:素材的軌道
AVMutableComposition :一個(gè)用來合成視頻的"合成器"
AVMutableCompositionTrack :"合成器"中的軌道,里面可以插入各種對(duì)應(yīng)的素材
2.2、拼接錄音#pragma?mark?音頻的拼接:追加某個(gè)音頻在某個(gè)音頻的后面
/**
音頻的拼接
@param?fromPath?前段音頻路徑
@param?toPath?后段音頻路徑
@param?outputPath?拼接后的音頻路徑
*/
+(void)addAudio:(NSString?*)fromPath?toAudio:(NSString?*)toPath?outputPath:(NSString?*)outputPath{
//?1.?獲取兩個(gè)音頻源
AVURLAsset?*audioAsset1?=?[AVURLAsset?assetWithURL:[NSURL?fileURLWithPath:fromPath]];
AVURLAsset?*audioAsset2?=?[AVURLAsset?assetWithURL:[NSURL?fileURLWithPath:toPath]];
//?2.?獲取兩個(gè)音頻素材中的素材軌道
AVAssetTrack?*audioAssetTrack1?=?[[audioAsset1?tracksWithMediaType:AVMediaTypeAudio]?firstObject];
AVAssetTrack?*audioAssetTrack2?=?[[audioAsset2?tracksWithMediaType:AVMediaTypeAudio]?firstObject];
//?3.?向音頻合成器,?添加一個(gè)空的素材容器
AVMutableComposition?*composition?=?[AVMutableComposition?composition];
AVMutableCompositionTrack?*audioTrack?=?[composition?addMutableTrackWithMediaType:AVMediaTypeAudio?preferredTrackID:0];
//?4.?向素材容器中,?插入音軌素材
[audioTrack?insertTimeRange:CMTimeRangeMake(kCMTimeZero,?audioAsset2.duration)?ofTrack:audioAssetTrack2?atTime:kCMTimeZero?error:nil];
[audioTrack?insertTimeRange:CMTimeRangeMake(kCMTimeZero,?audioAsset1.duration)?ofTrack:audioAssetTrack1?atTime:audioAsset2.duration?error:nil];
//?5.?根據(jù)合成器,?創(chuàng)建一個(gè)導(dǎo)出對(duì)象,?并設(shè)置導(dǎo)出參數(shù)
AVAssetExportSession?*session?=?[[AVAssetExportSession?alloc]?initWithAsset:composition?presetName:AVAssetExportPresetAppleM4A];
session.outputURL?=?[NSURL?fileURLWithPath:outputPath];
//?導(dǎo)出類型
session.outputFileType?=?AVFileTypeAppleM4A;
//?6.?開始導(dǎo)出數(shù)據(jù)
[session?exportAsynchronouslyWithCompletionHandler:^{
AVAssetExportSessionStatus?status?=?session.status;
/**
AVAssetExportSessionStatusUnknown,
AVAssetExportSessionStatusWaiting,
AVAssetExportSessionStatusExporting,
AVAssetExportSessionStatusCompleted,
AVAssetExportSessionStatusFailed,
AVAssetExportSessionStatusCancelled
*/
switch?(status)?{
case?AVAssetExportSessionStatusUnknown:
NSLog(@"未知狀態(tài)");
break;
case?AVAssetExportSessionStatusWaiting:
NSLog(@"等待導(dǎo)出");
break;
case?AVAssetExportSessionStatusExporting:
NSLog(@"導(dǎo)出中");
break;
case?AVAssetExportSessionStatusCompleted:{
NSLog(@"導(dǎo)出成功,路徑是:%@",?outputPath);
}
break;
case?AVAssetExportSessionStatusFailed:
NSLog(@"導(dǎo)出失敗");
break;
case?AVAssetExportSessionStatusCancelled:
NSLog(@"取消導(dǎo)出");
break;
default:
break;
}
}];
}
2.3、音頻的剪切/**
音頻的剪切
@param?audioPath?要剪切的音頻路徑
@param?fromTime?開始剪切的時(shí)間點(diǎn)
@param?toTime?結(jié)束剪切的時(shí)間點(diǎn)
@param?outputPath?剪切成功后的音頻路徑
*/
+(void)cutAudio:(NSString?*)audioPath?fromTime:(NSTimeInterval)fromTime?toTime:(NSTimeInterval)toTime?outputPath:(NSString?*)outputPath{
//?1.?獲取音頻源
AVURLAsset?*asset?=?[AVURLAsset?assetWithURL:[NSURL?fileURLWithPath:audioPath]];
//?2.?創(chuàng)建一個(gè)音頻會(huì)話,?并且,設(shè)置相應(yīng)的配置
AVAssetExportSession?*session?=?[AVAssetExportSession?exportSessionWithAsset:asset?presetName:AVAssetExportPresetAppleM4A];
session.outputFileType?=?AVFileTypeAppleM4A;
session.outputURL?=?[NSURL?fileURLWithPath:outputPath];
CMTime?startTime?=?CMTimeMake(fromTime,?1);
CMTime?endTime?=?CMTimeMake(toTime,?1);
session.timeRange?=?CMTimeRangeFromTimeToTime(startTime,?endTime);
//?3.?導(dǎo)出
[session?exportAsynchronouslyWithCompletionHandler:^{
AVAssetExportSessionStatus?status?=?session.status;
if?(status?==?AVAssetExportSessionStatusCompleted)
{
NSLog(@"導(dǎo)出成功");
}
}];
}
三、lame靜態(tài)庫
3.1、lame 靜態(tài)庫簡(jiǎn)介
LAME 是一個(gè)開源的MP3音頻壓縮軟件。LAME是一個(gè)遞歸縮寫,來自LAME Ain't an MP3 Encoder(LAME不是MP3編碼器)。它自1998年以來由一個(gè)開源社區(qū)開發(fā),目前是公認(rèn)有損品質(zhì)MP3中壓縮效果最好的編碼器。
Lame 的轉(zhuǎn)碼壓縮, 是把錄制的 PCM 轉(zhuǎn)碼成 MP3, 所以錄制的 AVFormatIDKey 設(shè)置成 kAudioFormatLinearPCM(無損壓縮,內(nèi)容非常大) , 生成的文件可以是 caf 或者 wav.
3.2、如何使用lame
第一步: 下載 lame 的最新版本并解壓
第二步: 把下載的 lame 生成靜態(tài)庫,我們使用腳本
下載 build 的腳本
創(chuàng)建一個(gè)文件夾放 腳本 與 下載的lame
修改腳本里面的 SOURCE="lame" 名字與 下載的lame名字一致,也可以把 下載的lame名字 改為 lame,那么就不需要改腳本的內(nèi)容
修改腳本里面的 `SOURCE="lame"` 名字與 下載的lame名字一致,也可以把 下載的lame名字 改為 `lame`,那么就不需要改腳本的內(nèi)容
改腳本為可執(zhí)行腳本chmod?+x?build-lame.sh
執(zhí)行腳本./build-lame.sh
執(zhí)行腳本的結(jié)果如下:生成三個(gè)文件
執(zhí)行腳本的結(jié)果如下:生成三個(gè)文件提示:我們要的是支持多種架構(gòu)的 fat-lame 文件,把 fat-lame 里面的 lame.h 與 libmp3lame.a 拖走即可
第三步: 導(dǎo)入靜態(tài)庫到工程, 開始使用,我們把代碼都寫在 JKLameTool 類里面,具體的分析放在 3.3
3.3、lame 的使用,代碼都在 JKLameTool 里面
<1>、錄完音頻 統(tǒng)一 caf 轉(zhuǎn) mp3,核心代碼如下/**
caf?轉(zhuǎn)?mp3
如果錄音時(shí)間比較長(zhǎng)的話,會(huì)要等待幾秒...
@param?sourcePath?轉(zhuǎn)?mp3?的caf?路徑
@param?isDelete?是否刪除原來的?caf?文件,YES:刪除、NO:不刪除
@param?success?成功的回調(diào)
@param?fail?失敗的回調(diào)
*/
+?(void)audioToMP3:(NSString?*)sourcePath?isDeleteSourchFile:?(BOOL)isDelete?withSuccessBack:(void(^)(NSString?*resultPath))success?withFailBack:(void(^)(NSString?*error))fail{
dispatch_async(dispatch_get_global_queue(0,?0),?^{
//?輸入路徑
NSString?*inPath?=?sourcePath;
//?判斷輸入路徑是否存在
NSFileManager?*fm?=?[NSFileManager?defaultManager];
if?(![fm?fileExistsAtPath:sourcePath])
{
if?(fail)?{
fail(@"文件不存在");
}
return;
}
//?輸出路徑
NSString?*outPath?=?[[sourcePath?stringByDeletingPathExtension]?stringByAppendingString:@".mp3"];
@try?{
int?read,?write;
//source?被轉(zhuǎn)換的音頻文件位置
FILE?*pcm?=?fopen([inPath?cStringUsingEncoding:1],?"rb");
//skip?file?header
fseek(pcm,?4*1024,?SEEK_CUR);
//output?輸出生成的Mp3文件位置
FILE?*mp3?=?fopen([outPath?cStringUsingEncoding:1],?"wb");
const?int?PCM_SIZE?=?8192;
const?int?MP3_SIZE?=?8192;
short?int?pcm_buffer[PCM_SIZE*2];
unsigned?char?mp3_buffer[MP3_SIZE];
lame_t?lame?=?lame_init();
lame_set_in_samplerate(lame,?11025.0);
lame_set_VBR(lame,?vbr_default);
lame_init_params(lame);
do?{
size_t?size?=?(size_t)(2?*?sizeof(short?int));
read?=?(int)fread(pcm_buffer,?size,?PCM_SIZE,?pcm);
if?(read?==?0)
write?=?lame_encode_flush(lame,?mp3_buffer,?MP3_SIZE);
else
write?=?lame_encode_buffer_interleaved(lame,?pcm_buffer,?read,?mp3_buffer,?MP3_SIZE);
fwrite(mp3_buffer,?write,?1,?mp3);
}?while?(read?!=?0);
lame_close(lame);
fclose(mp3);
fclose(pcm);
}
@catch?(NSException?*exception)?{
NSLog(@"%@",[exception?description]);
}
@finally?{
if?(isDelete)?{
NSError?*error;
[fm?removeItemAtPath:sourcePath?error:&error];
if?(error?==?nil)
{
//?NSLog(@"刪除源文件成功");
}
}
if?(success)?{
success(outPath);
}
}
});
}
<2>、caf 轉(zhuǎn) mp3 : 錄音的同時(shí)轉(zhuǎn)碼,這個(gè)是學(xué)習(xí)iOS 使用 Lame 轉(zhuǎn)碼 MP3 的最正確姿勢(shì),代碼結(jié)構(gòu)上在此基礎(chǔ)上進(jìn)行了封裝和改進(jìn),具體的請(qǐng)看 JKLameTool 類,在此不再重復(fù),核心思想如下:邊錄邊轉(zhuǎn)碼, 只是我們?cè)诳梢凿浿坪?重新開一個(gè)線程來進(jìn)行文件的轉(zhuǎn)碼
當(dāng)錄音進(jìn)行中時(shí), 會(huì)持續(xù)讀取到指定大小文件,進(jìn)行編碼, 讀取不到,則線程休眠
在 while 的條件中, 我們收到 錄音結(jié)束的條件,則會(huì)結(jié)束 do while 的循環(huán).
我們需要在錄制結(jié)束后發(fā)送一個(gè)信號(hào), 讓 do while 跳出循環(huán)
四、上面那么的內(nèi)容封裝之后使用方式如下
4.1、導(dǎo)入 #import "JKRecorderKit.h",錄音都存在 /Library/Caches/JKRecorder 里面
4.2、使用 JKAudioTool 類進(jìn)行調(diào)用 錄音的一系列操作,如下
開始錄音//?目前使用?caf?格式,?test2:錄音的名字??caf:錄音的格式
[[JKAudioTool?shareJKAudioTool]beginRecordWithRecordName:@"test2"?withRecordType:@"caf"?withIsConventToMp3:YES];
完成錄音[[JKAudioTool?shareJKAudioTool]endRecord];
暫停錄音[[JKAudioTool?shareJKAudioTool]pauseRecord];
刪除錄音[[JKAudioTool?shareJKAudioTool]deleteRecord];
caf 轉(zhuǎn) mp3,第一個(gè)參數(shù)是原音頻的路徑,第二個(gè)參數(shù)是轉(zhuǎn)換為 MP3 后是否刪除原來的路徑[JKLameTool?audioToMP3:[cachesRecorderPath?stringByAppendingPathComponent:@"test2.caf"]?isDeleteSourchFile:YES?withSuccessBack:^(NSString?*?_Nonnull?resultPath)?{
NSLog(@"轉(zhuǎn)為MP3后的路徑=%@",resultPath);
}?withFailBack:^(NSString?*?_Nonnull?error)?{
NSLog(@"轉(zhuǎn)換失敗:%@",error);
}];提示:更多的內(nèi)容請(qǐng)看demo里面的封裝
補(bǔ)充:封裝類的說明JKLameTool:對(duì) lame靜態(tài)庫的使用
JKSingle:單利的封裝
JKAudioTool:錄音的封裝
JKAudioFileTool:錄音文件的操作,音頻拼接,剪切,m4a格式轉(zhuǎn)caf格式,caf格式轉(zhuǎn)m4a格式
JKAudioPlayerTool:音頻的簡(jiǎn)單播放封裝
JKAudioFilePathTool:沙盒路徑的一些操作
最后:測(cè)試的 demo
推薦博客如下:作者:IIronMan
鏈接:https://www.jianshu.com/p/1a752b92070b
總結(jié)
以上是生活随笔為你收集整理的ios 边录音边放_iOS 录音、音频的拼接剪切以及边录边压缩转码的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 状态空间搜索
- 下一篇: 大唐杯 5G协议与信令 任务六、任务七(