iOS pcm轉(zhuǎn)mp3出現(xiàn)尖銳聲

項(xiàng)目中需要將pcm音頻文件轉(zhuǎn)碼為mp3格式后上傳, 在網(wǎng)上查找轉(zhuǎn)碼mp3的資料, 應(yīng)用時(shí)轉(zhuǎn)碼出來的mp3音頻聲音比較尖銳(像機(jī)器聲音/女聲), 最后發(fā)現(xiàn)是聲道數(shù)不統(tǒng)一導(dǎo)致的.

項(xiàng)目中使用的單聲道, 16000的采樣率進(jìn)行錄音, 網(wǎng)上資料默認(rèn)使用的 lame_encode_buffer_interleaved 這個(gè)方法進(jìn)行轉(zhuǎn)碼, 導(dǎo)致出現(xiàn)上述問題

lame.h 中說明如下:

/*
 * input pcm data, output (maybe) mp3 frames.
 * This routine handles all buffering, resampling and filtering for you.
 *
 * return code     number of bytes output in mp3buf. Can be 0
 *                 -1:  mp3buf was too small
 *                 -2:  malloc() problem
 *                 -3:  lame_init_params() not called
 *                 -4:  psycho acoustic problems
 *
 * The required mp3buf_size can be computed from num_samples,
 * samplerate and encoding rate, but here is a worst case estimate:
 *
 * mp3buf_size in bytes = 1.25*num_samples + 7200
 *
 * I think a tighter bound could be:  (mt, March 2000)
 * MPEG1:
 *    num_samples*(bitrate/8)/samplerate + 4*1152*(bitrate/8)/samplerate + 512
 * MPEG2:
 *    num_samples*(bitrate/8)/samplerate + 4*576*(bitrate/8)/samplerate + 256
 *
 * but test first if you use that!
 *
 * set mp3buf_size = 0 and LAME will not check if mp3buf_size is
 * large enough.
 *
 * NOTE:
 * if gfp->num_channels=2, but gfp->mode = 3 (mono), the L & R channels
 * will be averaged into the L channel before encoding only the L channel
 * This will overwrite the data in buffer_l[] and buffer_r[].
 *
*/
int CDECL lame_encode_buffer (
        lame_global_flags*  gfp,           /* global context handle         */
        const short int     buffer_l [],   /* PCM data for left channel     */
        const short int     buffer_r [],   /* PCM data for right channel    */
        const int           nsamples,      /* number of samples per channel */
        unsigned char*      mp3buf,        /* pointer to encoded MP3 stream */
        const int           mp3buf_size ); /* number of valid octets in this
                                              stream                        */

/*
 * as above, but input has L & R channel data interleaved.
 * NOTE:
 * num_samples = number of samples in the L (or R)
 * channel, not the total number of samples in pcm[]
 */
int CDECL lame_encode_buffer_interleaved(
        lame_global_flags*  gfp,           /* global context handlei        */
        short int           pcm[],         /* PCM data for left and right
                                              channel, interleaved          */
        int                 num_samples,   /* number of samples per channel,
                                              _not_ number of samples in
                                              pcm[]                         */
        unsigned char*      mp3buf,        /* pointer to encoded MP3 stream */
        int                 mp3buf_size ); /* number of valid octets in this
                                              stream                        */

lame_encode_buffer_interleaved 左右聲道數(shù)據(jù)交替?zhèn)魅脒M(jìn)行轉(zhuǎn)碼

轉(zhuǎn)碼核心代碼如下:

/***
 * pcm 文件轉(zhuǎn)mp3文件
 */
- (BOOL)convertPcm:(NSString *)pcmPath toMp3:(NSString *)mp3Path {
    @try {
        FILE *fpcm = fopen([pcmPath cStringUsingEncoding:NSASCIIStringEncoding], "rb");
        if (fpcm == NULL) {
            return false;
        }
//        fseek(fpcm, 1024*4, SEEK_CUR); //跳過源文件的信息頭,不然在開頭會(huì)有爆破音
        FILE *fmp3 = fopen([mp3Path cStringUsingEncoding:NSASCIIStringEncoding], "wb");
        
        int channelCount = 1;   // 聲道數(shù), 跟錄音時(shí)配置一樣的
        
        lame = lame_init();
        lame_set_in_samplerate(lame, 16000); //設(shè)置采樣率, 需要跟錄音時(shí)的采樣率相同
        lame_set_num_channels(lame, channelCount); //聲道,不設(shè)置默認(rèn)為雙聲道
        lame_set_VBR(lame, vbr_default);
//        lame_set_mode(lame, 0);
        lame_set_quality(lame, 2);
        lame_init_params(lame);
        
        const int PCM_SIZE = 8192;//
        const int MP3_SIZE = 8192; //
        short int pcm_buffer[PCM_SIZE*channelCount];
        unsigned char mp3_buffer[MP3_SIZE];
        
        int read, write;
        do {
            read = fread(pcm_buffer, channelCount*sizeof(short int), PCM_SIZE, fpcm);
            if (read == 0) {
                write = lame_encode_flush(lame, mp3_buffer, MP3_SIZE);
            } else {
                if (channelCount == 1) {
                    write = lame_encode_buffer(lame, pcm_buffer, NULL, read, mp3_buffer, MP3_SIZE); // 單聲道音頻轉(zhuǎn)碼
                } else {
                    write = lame_encode_buffer_interleaved(lame, pcm_buffer, read, mp3_buffer, MP3_SIZE); // 多聲道音頻轉(zhuǎn)碼
                }
            }
            fwrite(mp3_buffer, write, 1, fmp3);
        } while (read != 0);
        lame_mp3_tags_fid(lame, fmp3);
        lame_close(lame);
        fclose(fmp3);
        fclose(fpcm);
    } @catch (NSException *exception) {
        NSLog(@"catch exception, %@", exception);
        return false;
    } @finally {
        return true;
    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末将宪,一起剝皮案震驚了整個(gè)濱河市可很,隨后出現(xiàn)的幾起案子知态,更是在濱河造成了極大的恐慌识腿,老刑警劉巖折欠,帶你破解...
    沈念sama閱讀 216,591評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件励烦,死亡現(xiàn)場離奇詭異谓着,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)坛掠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評論 3 392
  • 文/潘曉璐 我一進(jìn)店門赊锚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人屉栓,你說我怎么就攤上這事舷蒲。” “怎么了友多?”我有些...
    開封第一講書人閱讀 162,823評論 0 353
  • 文/不壞的土叔 我叫張陵牲平,是天一觀的道長。 經(jīng)常有香客問我域滥,道長纵柿,這世上最難降的妖魔是什么蜈抓? 我笑而不...
    開封第一講書人閱讀 58,204評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮昂儒,結(jié)果婚禮上沟使,老公的妹妹穿的比我還像新娘。我一直安慰自己渊跋,他們只是感情好腊嗡,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,228評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著刹枉,像睡著了一般叽唱。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上微宝,一...
    開封第一講書人閱讀 51,190評論 1 299
  • 那天棺亭,我揣著相機(jī)與錄音,去河邊找鬼蟋软。 笑死镶摘,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的岳守。 我是一名探鬼主播凄敢,決...
    沈念sama閱讀 40,078評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼湿痢!你這毒婦竟也來了涝缝?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,923評論 0 274
  • 序言:老撾萬榮一對情侶失蹤譬重,失蹤者是張志新(化名)和其女友劉穎拒逮,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體臀规,經(jīng)...
    沈念sama閱讀 45,334評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡滩援,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,550評論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了塔嬉。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片玩徊。...
    茶點(diǎn)故事閱讀 39,727評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖谨究,靈堂內(nèi)的尸體忽然破棺而出恩袱,到底是詐尸還是另有隱情,我是刑警寧澤胶哲,帶...
    沈念sama閱讀 35,428評論 5 343
  • 正文 年R本政府宣布憎蛤,位于F島的核電站,受9級特大地震影響纪吮,放射性物質(zhì)發(fā)生泄漏俩檬。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,022評論 3 326
  • 文/蒙蒙 一碾盟、第九天 我趴在偏房一處隱蔽的房頂上張望棚辽。 院中可真熱鬧,春花似錦冰肴、人聲如沸屈藐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,672評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽联逻。三九已至,卻和暖如春检痰,著一層夾襖步出監(jiān)牢的瞬間包归,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,826評論 1 269
  • 我被黑心中介騙來泰國打工铅歼, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留公壤,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,734評論 2 368
  • 正文 我出身青樓椎椰,卻偏偏與公主長得像厦幅,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子慨飘,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,619評論 2 354

推薦閱讀更多精彩內(nèi)容