当前位置: 首页 > 工具软件 > LAME > 使用案例 >

linux编译libmp3lame,使用libmp3lame库编码mp3

鄢修德
2023-12-01

使用libmp3lame库编码mp3

LAME

lame是一个有名的开源mp3编码库,但是目前网上使用lame库的教程基本都是直接贴一篇代码,没有任何的解释,而每个使用者需要编码的需求都不一样,这些所谓的教程基本没什么作用。

这篇文章将会介绍如何调用lame库的接口编码出mp3。不同于目前网上的大多数lame教程,本文不会干巴巴的贴一屏幕代码,而是尽量对lame库提供的各种参数设置的接口做讲解。让读者能够举一反三,根据自己的需求编码出各种格式的mp3。

lame库编译

lame对linux的编译支持比较好,但是对于vc的支持基本停留在10年以前。所幸编码库的代码只有几个文件(下载的代码还包括命令行程序代码和gui程序代码,我们在此只需要编码库的代码,在libmp3lame目录中),自己新建个项目包含进来编译就行。

MP3

mp3(MPEG Layer III)这种格式在生活中很常见,但是mp3有很多种参数,这里讨论一下mp3编码所必须知道的一些参数。

采样率(sampleRate):采样率越高声音的还原度越好。

比特率(bitrate):每秒钟的数据量,越高音质越好。

声道数(channels):声道的数量,通常只有单声道和双声道,双声道即所谓的立体声。

比特率控制模式:ABR、VBR、CBR,这3中模式含义很容易查询到,不在赘述。

MPEG Layer III

MPEG有几个版本的协议,不同版本的协议能够支持的参数能力是不同的。编码库的使用者必须清楚不同版本的区别才能正确的设置参数。

有以下3个版本的协议,MPEG1、MPEG2、MPEG2.5。其中MPEG2.5是非官方的标准,但是流传广泛,所以基本也都支持。他们的区别主要集中在支持的比特率和采样率不同。

采样率支持(Hz)

MPEG1

MPEG2

MPEG2.5

44100

22050

11025

48000

24000

12000

32000

16000

8000

比特率支持(bit/s)

MPEG1

MPEG2

MPEG2.5

32

8

8

40

16

16

48

24

24

56

32

32

64

40

40

80

48

48

96

56

56

112

64

64

128

80

160

96

192

112

224

128

256

144

320

160

编码

流程

使用lame库只需要包含lame.h头文件,编码mp3基本上遵循以下的流程,

初始化编码参数

lame_init:初始化一个编码参数的数据结构,给使用者用来设置参数。

设置编码参数

lame_set_in_samplerate:设置被输入编码器的原始数据的采样率。

lame_set_out_samplerate:设置最终mp3编码输出的声音的采样率,如果不设置则和输入采样率一样。

lame_set_num_channels :设置被输入编码器的原始数据的声道数。

lame_set_mode :设置最终mp3编码输出的声道模式,如果不设置则和输入声道数一样。参数是枚举,STEREO代表双声道,MONO代表单声道。

lame_set_VBR:设置比特率控制模式,默认是CBR,但是通常我们都会设置VBR。参数是枚举,vbr_off代表CBR,vbr_abr代表ABR(因为ABR不常见,所以本文不对ABR做讲解)vbr_mtrh代表VBR。

lame_set_brate:设置CBR的比特率,只有在CBR模式下才生效。

lame_set_VBR_mean_bitrate_kbps:设置VBR的比特率,只有在VBR模式下才生效。

其中每个参数都有默认的配置,如非必要可以不设置。这里只介绍了几个关键的设置接口,还有其他的设置接口可以参考lame.h(lame的文档里只有命令行程序的用法,没有库接口的用法)。

初始化编码器器

lame_init_params:根据上面设置好的参数建立编码器

编码PCM数据

lame_encode_buffer或lame_encode_buffer_interleaved:将PCM数据送入编码器,获取编码出的mp3数据。这些数据写入文件就是mp3文件。

其中lame_encode_buffer输入的参数中是双声道的数据分别输入的,lame_encode_buffer_interleaved输入的参数中双声道数据是交错在一起输入的。具体使用哪个需要看采集到的数据是哪种格式的,不过现在的设备采集到的数据大部分都是双声道数据是交错在一起。

单声道输入只能使用lame_encode_buffer,把单声道数据当成左声道数据传入,右声道传NULL即可。

调用这两个函数时需要传入一块内存来获取编码器出的数据,这块内存的大小lame给出了一种建议的计算方式:采样率/20+7200。

结束编码

lame_encode_flush:结束编码,获取编码出的结束数据。这部分数据也需要写入mp3文件。

销毁编码器

lame_close销毁编码器,释放资源。

参数的有效性

不规范的参数

对于编码器的参数设置,所能接受的参数值并不是任意的。上一节的表格中列出了编码器器能够支持的参数值,如果我们设置的参数值不在其中,那么编码器会自动帮我们选择一个最近的值。

不一致的版本

但是如果仔细看了上面表格中的参数后会发现一个问题,每个版本支持的参数范围不一致,假如设置了MPEG2的比特率又设置了MPEG1的采样率那么会发生什么?

这里先给结论,lame库会优先服从采样率(这里指的是输出采样率)设置,根据采样率选择协议版本,然后在这个版本所能支持的比特率中选一个和设置比特率最接近的。

这个结论是我研究了lame的源码后分析得到的,lame的文档中并没有对此有任何描述,网上也没有任何相关的资料描述这一问题,接下来给出源码分析,如果不关心的可以跳过这一节。

/*

* 0: MPEG-2 LSF

* 1: MPEG-1

* 2: MPEG-2.5 LSF FhG extention (1995-07-11 shn)

*/

typedef enum {

MPEG_2 = 0,

MPEG_1 = 1,

MPEG_25 = 2

} MPEG_t;

const int bitrate_table[3][16] = {

{0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, -1}, /* MPEG 2 */

{0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, -1}, /* MPEG 1 */

{0, 8, 16, 24, 32, 40, 48, 56, 64, -1, -1, -1, -1, -1, -1, -1}, /* MPEG 2.5 */

};

const int samplerate_table[3][4] = {

{22050, 24000, 16000, -1}, /* MPEG 2 */

{44100, 48000, 32000, -1}, /* MPEG 1 */

{11025, 12000, 8000, -1}, /* MPEG 2.5 */

};

这是lame库中的参数能力表,lame库最终会从表中选择和设置值最接近的值。

下面的代码是在CBR模式下确定比特率的代码

if (gfp->VBR == vbr_off && gfp->compression_ratio > 0) {

if (gfp->samplerate_out == 0)

gfp->samplerate_out = map2MP3Frequency((int) (0.97 * gfp->samplerate_in)); /* round up with a margin of 3% */

/* choose a bitrate for the output samplerate which achieves * specified compression ratio */

gfp->brate = gfp->samplerate_out * 16 * cfg->channels_out / (1.e3 * gfp->compression_ratio);

/* we need the version for the bitrate table look up */

cfg->samplerate_index = SmpFrqIndex(gfp->samplerate_out, &cfg->version);

if (!cfg->free_format) /* for non Free Format find the nearest allowed bitrate */

gfp->brate = FindNearestBitrate(gfp->brate, cfg->version, gfp->samplerate_out);

}

int

map2MP3Frequency(int freq)

{

if (freq <= 8000)

return 8000;

if (freq <= 11025)

return 11025;

if (freq <= 12000)

return 12000;

if (freq <= 16000)

return 16000;

if (freq <= 22050)

return 22050;

if (freq <= 24000)

return 24000;

if (freq <= 32000)

return 32000;

if (freq <= 44100)

return 44100;

return 48000;

}

int

BitrateIndex(int bRate, /* legal rates from 32 to 448 kbps */

int version, /* MPEG-1 or MPEG-2/2.5 LSF */

int samplerate)

{ /* convert bitrate in kbps to index */

int i;

if (samplerate < 16000)

version = 2;

for (i = 0; i <= 14; i++) {

if (bitrate_table[version][i] > 0) {

if (bitrate_table[version][i] == bRate) {

return i;

}

}

}

return -1;

}

/* convert samp freq in Hz to index */

int

SmpFrqIndex(int sample_freq, int *const version)

{

switch (sample_freq) {

case 44100:

*version = 1;

return 0;

case 48000:

*version = 1;

return 1;

case 32000:

*version = 1;

return 2;

case 22050:

*version = 0;

return 0;

case 24000:

*version = 0;

return 1;

case 16000:

*version = 0;

return 2;

case 11025:

*version = 0;

return 0;

case 12000:

*version = 0;

return 1;

case 8000:

*version = 0;

return 2;

default:

*version = 0;

return -1;

}

}

可以看到首先如果没有设置输出采样率,调用map2MP3Frequency根据输入采样率算出输出采样率,默认和输入采样率一致的。

然后根据输出采样率调用SmpFrqIndex计算出MPEG版本,这里注意将MPEG2和MPEG2.5都视为MPEG2。

根据已经设置的比特率、输出采样率、版本调用FindNearestBitrate去寻找合适的比特率。FindNearestBitrate在相应的版本的能力范围中找一个最接近的值的索引。

接下来分析一下VBR情况下的处理

if (gfp->samplerate_out) {

if (gfp->samplerate_out < 16000) {

gfp->VBR_mean_bitrate_kbps = Max(gfp->VBR_mean_bitrate_kbps, 8);

gfp->VBR_mean_bitrate_kbps = Min(gfp->VBR_mean_bitrate_kbps, 64);

}

else if (gfp->samplerate_out < 32000) {

gfp->VBR_mean_bitrate_kbps = Max(gfp->VBR_mean_bitrate_kbps, 8);

gfp->VBR_mean_bitrate_kbps = Min(gfp->VBR_mean_bitrate_kbps, 160);

}

else {

gfp->VBR_mean_bitrate_kbps = Max(gfp->VBR_mean_bitrate_kbps, 32);

gfp->VBR_mean_bitrate_kbps = Min(gfp->VBR_mean_bitrate_kbps, 320);

}

}

可以看到这里没有查表,直接是和采样率对应的版本允许的比特率的范围比较。这是因为VBR模式下比特率不固定,只要不超出范围即可。

感想

我在使用lame库的过程中发现资料很少,大部分博客也是不负责任的直接贴一篇代码,所以我把自己使用lame库种总结出的一些心得和体会在此分享出来,希望能帮助其他使用lame库的人。

 类似资料: