linux下mp3编码库libmp3lame的开发使用
一、LAME介紹
? ? lame是一個(gè)有名的開源mp3編碼庫,這篇文章將會(huì)介紹如何調(diào)用lame庫的接口編碼出mp3。
二、lame庫編譯
? ? 查看博客:linux下MP3編碼庫libmp3lame的移植
三、MP3叫介紹
? ? mp3(MPEG Layer III)這種格式在生活中很常見,但是mp3有很多種參數(shù),這里討論一下mp3編碼所必須知道的一些參數(shù)。
- 采樣率(sampleRate):采樣率越高聲音的還原度越好。
- 比特率(bitrate):每秒鐘的數(shù)據(jù)量,越高音質(zhì)越好。
- 聲道數(shù)(channels):聲道的數(shù)量,通常只有單聲道和雙聲道,雙聲道即所謂的立體聲。
- 比特率控制模式:ABR、VBR、CBR,這3中模式含義很容易查詢到,不在贅述。
四、MPEG Layer III
? ? MPEG有幾個(gè)版本的協(xié)議,不同版本的協(xié)議能夠支持的參數(shù)能力是不同的。編碼庫的使用者必須清楚不同版本的區(qū)別才能正確的設(shè)置參數(shù)。
? ? 有以下3個(gè)版本的協(xié)議,MPEG1、MPEG2、MPEG2.5。其中MPEG2.5是非官方的標(biāo)準(zhǔn),但是流傳廣泛,所以基本也都支持。他們的區(qū)別主要集中在支持的比特率和采樣率不同。
4.1 采樣率支持(Hz)
4.2 比特率支持(bit/s)
五、編碼流程
? ? 使用lame庫只需要包含lame.h頭文件,編碼mp3基本上遵循以下的流程,
5.1 初始化編碼參數(shù)
- lame_init:初始化一個(gè)編碼參數(shù)的數(shù)據(jù)結(jié)構(gòu),給使用者用來設(shè)置參數(shù)。
5.2 設(shè)置編碼參數(shù)
- lame_set_in_samplerate:設(shè)置被輸入編碼器的原始數(shù)據(jù)的采樣率。
- lame_set_out_samplerate:設(shè)置最終mp3編碼輸出的聲音的采樣率,如果不設(shè)置則和輸入采樣率一樣。
- lame_set_num_channels?:設(shè)置被輸入編碼器的原始數(shù)據(jù)的聲道數(shù)。
- lame_set_mode?:設(shè)置最終mp3編碼輸出的聲道模式,如果不設(shè)置則和輸入聲道數(shù)一樣。參數(shù)是枚舉,STEREO代表雙聲道,MONO代表單聲道。
- lame_set_VBR:設(shè)置比特率控制模式,默認(rèn)是CBR,但是通常我們都會(huì)設(shè)置VBR。參數(shù)是枚舉,vbr_off代表CBR,vbr_abr代表ABR(因?yàn)锳BR不常見,所以本文不對(duì)ABR做講解)vbr_mtrh代表VBR。
- lame_set_brate:設(shè)置CBR的比特率,只有在CBR模式下才生效。
- lame_set_VBR_mean_bitrate_kbps:設(shè)置VBR的比特率,只有在VBR模式下才生效。
其中每個(gè)參數(shù)都有默認(rèn)的配置,如非必要可以不設(shè)置。這里只介紹了幾個(gè)關(guān)鍵的設(shè)置接口,還有其他的設(shè)置接口可以參考lame.h(lame的文檔里只有命令行程序的用法,沒有庫接口的用法)。
5.3 初始化編碼器
lame_init_params:根據(jù)上面設(shè)置好的參數(shù)建立編碼器
5.4?編碼PCM數(shù)據(jù)
- lame_encode_buffer或lame_encode_buffer_interleaved:將PCM數(shù)據(jù)送入編碼器,獲取編碼出的mp3數(shù)據(jù)。這些數(shù)據(jù)寫入文件就是mp3文件。
- 其中l(wèi)ame_encode_buffer輸入的參數(shù)中是雙聲道的數(shù)據(jù)分別輸入的,lame_encode_buffer_interleaved輸入的參數(shù)中雙聲道數(shù)據(jù)是交錯(cuò)在一起輸入的。具體使用哪個(gè)需要看采集到的數(shù)據(jù)是哪種格式的,不過現(xiàn)在的設(shè)備采集到的數(shù)據(jù)大部分都是雙聲道數(shù)據(jù)是交錯(cuò)在一起。
- 單聲道輸入只能使用lame_encode_buffer,把單聲道數(shù)據(jù)當(dāng)成左聲道數(shù)據(jù)傳入,右聲道傳NULL即可。
- 調(diào)用這兩個(gè)函數(shù)時(shí)需要傳入一塊內(nèi)存來獲取編碼器出的數(shù)據(jù),這塊內(nèi)存的大小lame給出了一種建議的計(jì)算方式:采樣率/20+7200。
5.5?結(jié)束編碼
- lame_encode_flush:結(jié)束編碼,獲取編碼出的結(jié)束數(shù)據(jù)。這部分?jǐn)?shù)據(jù)也需要寫入mp3文件。
5.6?銷毀編碼器
- lame_close銷毀編碼器,釋放資源。
六、實(shí)例代碼
6.1? wav轉(zhuǎn)MP3示例程序代碼:
/* gcc -I /usr/include/lame/ lame_test.c -lmp3lame -o lame_test -lm */ #include <stdio.h> #include <stdlib.h> #include <lame.h>#define INBUFSIZE 4096 #define MP3BUFSIZE (int) (1.25 * INBUFSIZE) + 7200int encode(char* inPath, char* outPath) {int status = 0;lame_global_flags* gfp;int ret_code;FILE* infp;FILE* outfp;short* input_buffer;int input_samples;char* mp3_buffer;int mp3_bytes;gfp = lame_init();if (gfp == NULL) {printf("lame_init failed/n");status = -1;goto exit;}ret_code = lame_init_params(gfp);if (ret_code < 0) {printf("lame_init_params returned %d/n",ret_code);status = -1;goto close_lame;}infp = fopen(inPath, "rb");outfp = fopen(outPath, "wb");input_buffer = (short*)malloc(INBUFSIZE*2);mp3_buffer = (char*)malloc(MP3BUFSIZE);do{input_samples = fread(input_buffer, 2, INBUFSIZE, infp);//fprintf(stderr, "input_samples is %d./n", input_samples);mp3_bytes = lame_encode_buffer_interleaved(gfp, input_buffer,input_samples/2,mp3_buffer, MP3BUFSIZE);//fprintf(stderr, "mp3_bytes is %d./n", mp3_bytes);if (mp3_bytes < 0){printf("lame_encode_buffer_interleaved returned %d/n", mp3_bytes);status = -1;goto free_buffers;} else if(mp3_bytes > 0){fwrite(mp3_buffer, 1, mp3_bytes, outfp);}}while (input_samples == INBUFSIZE);mp3_bytes = lame_encode_flush(gfp, mp3_buffer, sizeof(mp3_buffer));if (mp3_bytes > 0) {printf("writing %d mp3 bytes/n", mp3_bytes);fwrite(mp3_buffer, 1, mp3_bytes, outfp);}free_buffers:free(mp3_buffer);free(input_buffer);fclose(outfp);fclose(infp);close_lame:lame_close(gfp);exit:return status; } int main(int argc, char** argv) {if (argc < 3) {printf("usage: lame_test rawinfile mp3outfile/n");}encode(argv[1], argv[2]);return 0; }6.2. 錄音成MP3格式程序代碼
/* gcc -I /usr/include/lame/ -lmp3lame -o mp3_record mp3_record.c -lm */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <errno.h> #include <signal.h> #include <sys/ioctl.h> #include <memory.h> #include <linux/soundcard.h>#include "lame.h"#define BUFF_SIZE 512 #define INBUFF_SIZE 4096 #define MP3BUFF_SIZE (int) (1.25 * INBUFF_SIZE) + 7200static int run=1;static void stop(int signum) {fprintf(stderr, "exit/n");run=0; }int SetFormat(int fd, unsigned int bit, unsigned int channel, unsigned int hz) {int ioctl_val;/* set bit format */ioctl_val = bit;if(ioctl(fd, SNDCTL_DSP_SETFMT, &ioctl_val) < 0){fprintf(stderr, "Set fmt to bit %d failed:%s/n", bit, strerror(errno));return -1;}if (ioctl_val != bit) {fprintf(stderr, "do not support bit %d, supported %d/n", bit,ioctl_val);return (-1);}/*set channel */ioctl_val = channel;if ((ioctl(fd, SNDCTL_DSP_CHANNELS, &ioctl_val)) == -1){fprintf(stderr, "Set Audio Channels %d failed:%s/n", channel, strerror(errno));return (-1);}if (ioctl_val != channel){fprintf(stderr, "do not support channel %d,supported %d/n", channel, ioctl_val);return (-1);}/*set speed */ioctl_val = hz;if (ioctl(fd, SNDCTL_DSP_SPEED, &ioctl_val) == -1) {fprintf(stderr, "Set speed to %d failed:%s/n", hz, strerror(errno));return (-1);}if (ioctl_val != hz) {fprintf(stderr, "do not support speed %d,supported is %d/n", hz,ioctl_val);return (-1);}return 0; }int main(int argc, char **argv) {int status =0;int snd_f;int fd_f;lame_global_flags* gfp;short *input_buff;char *mp3_buff;if(argc !=2){fprintf(stderr, "useage: ./mp3_record test.mp3/n");return -1;}signal(SIGINT,stop);if((snd_f = open("/dev/dsp", O_RDONLY)) < 0){fprintf(stderr, "open audio device error: %s", strerror(errno));status = -1;goto exit;}if((fd_f = open(argv[1], O_CREAT | O_WRONLY)) < 0){fprintf(stderr, "open file error: %s", strerror(errno));status = -1;goto exit;}if (SetFormat(snd_f, 16, 2, 44100) < 0){fprintf(stderr, "cannot set /dev/dsp in bit 16, channel 2, speed 44100/n");status = -1;goto exit;}gfp = lame_init();if (gfp == NULL) {printf("lame_init failed/n");status = -1;goto exit;}int ret_code = lame_init_params(gfp);if (ret_code < 0){printf("lame_init_params returned %d/n",ret_code);status = -1;goto close_lame;}input_buff = (short *)malloc(INBUFF_SIZE*2);mp3_buff = (char *)malloc(MP3BUFF_SIZE);int samples;int mp3_bytes;int write_bytes;int n=100;while(run){//while(n>0){//n--;//fprintf(stderr, "n is %d./n", n);memset(input_buff, 0 , INBUFF_SIZE*2);memset(mp3_buff, 0 , MP3BUFF_SIZE);samples = read(snd_f, input_buff, INBUFF_SIZE*2);if (samples < 0){perror("read sound device failed");status = -1;goto free_buffers;}// fprintf(stderr, "samples is %d./n", samples);mp3_bytes = lame_encode_buffer_interleaved(gfp, input_buff, samples/4, mp3_buff, MP3BUFF_SIZE);//fprintf(stderr, "mp3_bytes is %d./n", mp3_bytes);if (mp3_bytes < 0){printf("lame_encode_buffer_interleaved returned %d/n", mp3_bytes);status = -1;goto free_buffers;}write_bytes = write(fd_f, mp3_buff, mp3_bytes);//fprintf(stderr, "write_bytes is %d./n", write_bytes);if(write_bytes < 0){perror("write sound data file failed");status = -1;goto free_buffers;}}mp3_bytes = lame_encode_flush(gfp, mp3_buff, sizeof(mp3_buff));if (mp3_bytes > 0){fprintf(stderr, "writing %d mp3 bytes/n", mp3_bytes);if(write(fd_f, mp3_buff, mp3_bytes) <0)fprintf(stderr, "'writing mp3 bytes error/n");}else{fprintf(stderr, "writing mp3 bytes 0/n");}free_buffers:free(mp3_buff);mp3_buff = NULL;free(input_buff);input_buff = NULL;close(snd_f);close(fd_f);close_lame:lame_close(gfp);exit:return status; }?
總結(jié)
以上是生活随笔為你收集整理的linux下mp3编码库libmp3lame的开发使用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: error C4716 必须返回一个值
- 下一篇: Linux下3种常用的网络测速工具