下載
1幸撕、下載編譯腳本:https://github.com/kewlbear/lame-ios-build
2他巨、下載lame:http://lame.sourceforge.net
3、新建文件夾用來(lái)存放下載下來(lái)的lame
和腳本文件
4呢簸、在新建的文件夾下運(yùn)行:./build-lame.sh
苔咪,運(yùn)行結(jié)果如下圖
編譯完成后生成fat-lame
文件夾,將fat-lame
文件夾中的lame.h
和libmp3lame.a
導(dǎo)入工程即可
使用
將編譯完成后的lame
庫(kù)加入到工程中
注意:
1刀闷、初始化lame
的時(shí)候熊泵,要設(shè)置1為單通道仰迁。設(shè)置單聲道會(huì)更大程度減少壓縮后文件的體積。
lame_set_num_channels(lame,1); //設(shè)置1為單通道顽分,默認(rèn)為2雙通道
2徐许、lame_close(lame);
之前需要添加:
lame_mp3_tags_fid(lame, mp3);
// 可解決獲取時(shí)長(zhǎng)不準(zhǔn)的問(wèn)題
引入庫(kù)頭文件
//ConvertAudioFile.m
#import "lame.h"
錄制完成后轉(zhuǎn)碼
//這是錄完再轉(zhuǎn)碼的方法, 如果錄音時(shí)間比較長(zhǎng)的話,會(huì)要等待幾秒...
+ (void)conventToMp3WithCafFilePath:(NSString *)cafFilePath
mp3FilePath:(NSString *)mp3FilePath
sampleRate:(int)sampleRate
callback:(void(^)(BOOL result))callback
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
@try {
int read, write;
FILE *pcm = fopen([cafFilePath cStringUsingEncoding:1], "rb"); //source 被轉(zhuǎn)換的音頻文件位置
fseek(pcm, 4*1024, SEEK_CUR); //skip file header
FILE *mp3 = fopen([mp3FilePath cStringUsingEncoding:1], "wb+"); //output 輸出生成的Mp3文件位置
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_num_channels(lame,1);//設(shè)置1為單通道,默認(rèn)為2雙通道
lame_set_in_samplerate(lame, sampleRate);
lame_set_VBR(lame, vbr_default);
lame_init_params(lame);
do {
read = (int)fread(pcm_buffer, 2*sizeof(short int), 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_mp3_tags_fid(lame, mp3);
lame_close(lame);
fclose(mp3);
fclose(pcm);
}
@catch (NSException *exception) {
NSLog(@"%@",[exception description]);
if (callback) {
callback(NO);
}
}
@finally {
NSLog(@"-----\n MP3生成成功: %@ ----- \n", mp3FilePath);
if (callback) {
callback(YES);
}
}
});
調(diào)用
[ConvertAudioFile conventToMp3WithCafFilePath:self.cafPathmp3FilePath:self.mp3Path
{
sampleRate:ETRECORD_RATE callback:^(BOOL result)
NSLog(@"---- 轉(zhuǎn)碼完成 --- result %d ---- ", result);}];
邊錄制邊轉(zhuǎn)碼
通常我們是在錄制結(jié)束之后, 再進(jìn)行轉(zhuǎn)碼; 當(dāng)錄制的時(shí)間較長(zhǎng) , 會(huì)消耗的時(shí)間比較長(zhǎng)卒蘸,用戶需要等待轉(zhuǎn)碼結(jié)束后,才能操作; 但是如果我們使用邊錄制雌隅,邊轉(zhuǎn)碼的方式, 開另外開個(gè)線程同時(shí)進(jìn)行轉(zhuǎn)碼,則幾乎沒(méi)有等待的時(shí)間。
具體實(shí)現(xiàn)方法:當(dāng)錄音進(jìn)行中時(shí), 會(huì)持續(xù)讀取到指定大小文件來(lái)進(jìn)行編碼缸沃,讀取不到澄步,則線程休眠在while
的條件中, 我們收到錄音結(jié)束的條件,則會(huì)結(jié)束do while
的循環(huán)和泌。我們需要在錄制結(jié)束后發(fā)送個(gè)信號(hào), 讓 do while
跳出循環(huán)村缸。
- (void)conventToMp3WithCafFilePath:(NSString *)cafFilePath
mp3FilePath:(NSString *)mp3FilePath
sampleRate:(int)sampleRate
callback:(void(^)(BOOL result))callback
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
@try {
int read, write;
FILE *pcm = fopen([cafFilePath cStringUsingEncoding:1], "rb"); //source 被轉(zhuǎn)換的音頻文件位置
FILE *mp3 = fopen([mp3FilePath cStringUsingEncoding:1], "wb+"); //output 輸出生成的Mp3文件位置
const int PCM_SIZE = 8192;
const int MP3_SIZE = 8192;
short int pcm_buffer[PCM_SIZE*2];
unsigned char mp3_buffer[MP3_SIZE];
//這里要注意,lame的配置要跟AVAudioRecorder的配置一致武氓,否則會(huì)造成轉(zhuǎn)換不成功
lame_t lame = lame_init();
lame_set_num_channels(lame,1);//設(shè)置1為單通道梯皿,默認(rèn)為2雙通道 設(shè)置單聲道會(huì)更大程度減少壓縮后文件的體積
lame_set_in_samplerate(lame, sampleRate);//采樣率
lame_set_VBR(lame, vbr_default);
lame_init_params(lame);
BOOL isSkipPCMHeader = NO;
__weak typeof(self) weakSelf = self;
do {
long curpos = ftell(pcm);
long startPos = ftell(pcm);
fseek(pcm, 0, SEEK_END);
long endPos = ftell(pcm);
long length = endPos - startPos;
fseek(pcm, curpos, SEEK_SET);
if (length > PCM_SIZE * 2 * sizeof(short int)) {
if (!isSkipPCMHeader) {
//Uump audio file header, If you do not skip file header
//you will heard some noise at the beginning!!!
fseek(pcm, 4 * 1024, SEEK_CUR);
isSkipPCMHeader = YES;
NSLog(@"skip pcm file header !!!!!!!!!!");
}
read = (int)fread(pcm_buffer, 2 * sizeof(short int), PCM_SIZE, pcm);
write = lame_encode_buffer_interleaved(lame, pcm_buffer, read, mp3_buffer,
MP3_SIZE);
fwrite(mp3_buffer, write, 1, mp3);
NSLog(@"read %d bytes", write);}
else {
[NSThread sleepForTimeInterval:0.05];
// MyLog(@"sleep");
}
} while (! weakSelf.stopRecord);
lame_mp3_tags_fid(lame, mp3);// 解決獲取時(shí)長(zhǎng)不準(zhǔn)的問(wèn)題
lame_close(lame);
fclose(mp3);
fclose(pcm);
}
@catch (NSException *exception) {
MyLog(@"%@",[exception description]);
if (callback) {
callback(NO);
}
}
@finally {
MyLog(@"-----\n MP3生成成功: %@ ----- \n", mp3FilePath);
if (callback) {
callback(YES);
}
}
});
}
調(diào)用
[[ConvertAudioFile sharedInstance] conventToMp3WithCafFilePath:self.cafPathmp3FilePath:self.mp3Path
sampleRate:ETRECORD_RATE callback:^(BOOL result)
{
NSLog(@"---- 轉(zhuǎn)碼完成 --- result %d ---- ", result);
}];
參考:
https://blog.csdn.net/u011270282/article/details/77483359
https://blog.csdn.net/lovechris00/article/details/79034036
https://blog.csdn.net/ysy441088327/article/details/7392842
https://blog.csdn.net/lovechris00/article/details/52033555