/**
ConvertMp3
@param cafFilePath caf FilePath
@param mp3FilePath mp3 FilePath
@param sampleRate sampleRate (same record sampleRate set)我傳的8000.0
*/
- (void)conventToMp3WithCafFilePath:(NSString *)cafFilePath
mp3FilePath:(NSString *)mp3FilePath
sampleRate:(int)sampleRate
{
@try {
int read, write;
//source 被轉(zhuǎn)換的音頻文件位置
FILE *pcm = fopen([wavPath cStringUsingEncoding:NSASCIIStringEncoding], "rb");
//output 輸出生成的Mp3文件位置
FILE *mp3 = fopen([mp3Path cStringUsingEncoding:NSASCIIStringEncoding], "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, 8000.0);
lame_set_VBR(lame, vbr_default);
lame_init_params(lame);
long curpos;
BOOL isSkipPCMHeader = NO;
do {
curpos = ftell(pcm);
fseek(pcm, 0, SEEK_END);
fseek(pcm, curpos, SEEK_SET);
if (!isSkipPCMHeader) {
//Uump audio file header, If you do not skip file header
//you will heard some noise at the beginning!!!
//skip file header 跳過 PCM header 能保證錄音的開頭沒有噪音
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);
} while (read != 0);
read = (int)fread(pcm_buffer, 2 * sizeof(short int), PCM_SIZE, pcm);
write = lame_encode_flush(lame, mp3_buffer, MP3_SIZE);
// NSLog(@"read %d bytes and flush to mp3 file", write);
lame_mp3_tags_fid(lame, mp3);
lame_close(lame);
fclose(mp3);
fclose(pcm);
}
@catch (NSException *exception) {
NSLog(@"%@",[exception description]);
}
@finally {
[[NSFileManager defaultManager] removeItemAtPath:wavPath error:nil];
self.filePath = mp3Path;
// 這個(gè)是自己定義的一些方法
if (self.delegate &&[self.delegate respondsToSelector:@selector(voiceRecordHasBeenStoped)]) {
[self.delegate voiceRecordHasBeenStoped];
}
}
}
下面是一些說明:
C 語言的 文件打開模式(fopen)
w+以純文本方式讀寫,而wb+是以二進(jìn)制方式進(jìn)行讀寫。
mode說明:
w 打開只寫文件,若文件存在則文件長度清為0邦邦,即該文件內(nèi)容會(huì)消失。若文件不存在則建立該文件醉蚁。
w+ 打開可讀寫文件燃辖,若文件存在則文件長度清為零,即該文件內(nèi)容會(huì)消失网棍。若文件不存在則建立該文件黔龟。
wb 只寫方式打開或新建一個(gè)二進(jìn)制文件,只允許寫數(shù)據(jù)滥玷。
wb+ 讀寫方式打開或建立一個(gè)二進(jìn)制文件氏身,允許讀和寫。
r 打開只讀文件惑畴,該文件必須存在蛋欣,否則報(bào)錯(cuò)。
r+ 打開可讀寫的文件桨菜,該文件必須存在豁状,否則報(bào)錯(cuò)捉偏。
rb+ 讀寫方式打開一個(gè)二進(jìn)制文件倒得,只允許讀寫數(shù)據(jù)。
a 以附加的方式打開只寫文件夭禽。若文件不存在霞掺,則會(huì)建立該文件,如果文件存在讹躯,寫入的數(shù)據(jù)會(huì)被加到文件尾菩彬,即文件原先的內(nèi)容會(huì)被保留缠劝。(EOF符保留)
a+ 以附加方式打開可讀寫的文件。若文件不存在骗灶,則會(huì)建立該文件惨恭,如果文件存在,寫入的數(shù)據(jù)會(huì)被加到文件尾后耙旦,即文件原先的內(nèi)容會(huì)被保留脱羡。 (原來的EOF符不保留)
ab+ 讀寫打開一個(gè)二進(jìn)制文件,允許讀或在文件末追加數(shù)據(jù)免都。
加入b 字符用來告訴函數(shù)庫打開的文件為二進(jìn)制文件锉罐,而非純文字文件。
然后是lame_init()來初始化,lame_set_num_channels(lame,1)默認(rèn)轉(zhuǎn)碼為2雙通道, 設(shè)置單聲道會(huì)更大程度減少壓縮后文件的體積.
接下來 是執(zhí)行一個(gè) do while 的循環(huán)來反復(fù)讀取FILE* stream, 直到 read != 0 , 結(jié)束轉(zhuǎn)碼,釋放lame_close(lame); fclose(mp3); fclose(pcm);