1、README
前言
本demo是使用开源项目lame来将MP3数据解码成PCM数据。(环境:x86_64 Ubuntu16.04 64位)
注:在下面【参考文章】中的第1篇里面提到解码出现过异常情况(hip: bitstream problem, resyncing skipping xxx bytes…),或许是因为我屏蔽了main.c中第88行的fseek(…)函数,在目前demo中提供的MP3文件以及网络下载的其他MP3文件解码均未发现此提示。
a. 编译使用
lame的编译:(源码下载地址:https://sourceforge.net/projects/lame/files/lame/)
tar xzf lame-3.100.tar.gz
cd lame-3.100/
./configure --prefix=$PWD/_install --enable-decoder
make
make install
本demo的编译与使用:
$ make clean && make DEBUG=1
$
$ ./mp32pcm
Usage:
./mp32pcm <in MP3 file> <out PCM file>
Examples:
./mp32pcm audio/test1_44100_stereo.mp3 out1_44100_16bit_stereo.pcm
./mp32pcm audio/test2_22050_stereo.mp3 out2_22050_16bit_stereo.pcm
./mp32pcm audio/test3_22050_mono.mp3 out3_22050_16bit_mono.pcm
./mp32pcm audio/test4_8000_mono.mp3 out4_8000_16bit_mono.pcm
b. 参考文章
c. demo目录架构
$ tree
.
├── audio
│ ├── out1_44100_16bit_stereo.pcm
│ ├── out2_22050_16bit_stereo.pcm
│ ├── out3_22050_16bit_mono.pcm
│ ├── out4_8000_16bit_mono.pcm
│ ├── test1_44100_stereo.mp3
│ ├── test2_22050_stereo.mp3
│ ├── test3_22050_mono.mp3
│ └── test4_8000_mono.mp3
├── docs
│ ├── lame mp3解码 - 小小程序员001 - 博客园.mhtml
│ └── 使用lame解码mp3_Griza_J的博客-CSDN博客_lame 解码.mhtml
├── include
│ └── lame
│ └── lame.h
├── lib
│ └── libmp3lame.a
├── main.c
├── Makefile
└── README.md
2、主要代码片段
main.c
#include <stdio.h>
#include <stdlib.h>
#include "lame/lame.h"
/* just for debug */
#ifdef ENABLE_DEBUG
#define DEBUG(fmt, args...) printf(fmt, ##args)
#else
#define DEBUG(fmt, args...)
#endif
#define INBUF_SIZE (4096)
#define BUF_SIZE (512)
#define MP3BUF_SIZE ((int)(1.25 * BUF_SIZE) + 7200)
int main(int argc, char *argv[])
{
char *inMp3FileName = NULL;
char *outPcmFileName = NULL;
FILE *fpInMP3 = NULL;
FILE *fpOutPcm = NULL;
short pcm_l[INBUF_SIZE];
short pcm_r[INBUF_SIZE];
unsigned char mp3Buf[MP3BUF_SIZE];
hip_t hip = NULL;
if (argc != 3)
{
printf("Usage: \n"
" %s <in MP3 file> <out PCM file>\n"
"Examples: \n"
" %s audio/test1_44100_stereo.mp3 out1_44100_16bit_stereo.pcm\n"
" %s audio/test2_22050_stereo.mp3 out2_22050_16bit_stereo.pcm\n"
" %s audio/test3_22050_mono.mp3 out3_22050_16bit_mono.pcm\n"
" %s audio/test4_8000_mono.mp3 out4_8000_16bit_mono.pcm\n",
argv[0], argv[0], argv[0], argv[0], argv[0]);
return -1;
}
else
{
inMp3FileName = argv[1];
outPcmFileName = argv[2];
}
fpInMP3 = fopen(inMp3FileName, "rb");
if(!fpInMP3)
{
perror("open input MP3 file failed");
goto exit;
}
fpOutPcm = fopen(outPcmFileName, "wb");
if(!fpOutPcm)
{
perror("open output PCM file failed");
goto exit;
}
/* MP3 decode 1/4: init handler */
hip = hip_decode_init();
if(!hip)
{
printf("init mp3 decoder failed!\n");
goto exit;
}
int readMP3Bytes = -1;
int samples = -1;
int samplesRate = -1;
int channels = -1;
mp3data_struct mp3Info = {};
/* MP3 decode 2/4: read MP3 header info */
do{
readMP3Bytes = fread(mp3Buf, 1, 16, fpInMP3);
hip_decode_headers(hip, mp3Buf, readMP3Bytes, pcm_l, pcm_r, &mp3Info);
samplesRate = mp3Info.samplerate;
channels = mp3Info.stereo;
}while(!mp3Info.header_parsed && readMP3Bytes > 0);
// don't need to reset file position
//fseek(fpInMP3, 0, SEEK_SET);
printf("Input MP3 Info: \n"
" samplesRate: %d\n"
" channels: %d\n",
samplesRate, channels);
while(1)
{
readMP3Bytes = fread(mp3Buf, 1, 418, fpInMP3);
if(readMP3Bytes <= 0)
break;
/* MP3 decode 3/4: decode MP3 data */
samples = hip_decode(hip, mp3Buf, readMP3Bytes, pcm_l, pcm_r);
if(samples > 0)
{
DEBUG("read MP3 bytes: %d \t decode output samples: %d\n", readMP3Bytes, samples);
for(int i = 0; i < samples; i++)
{
fwrite(pcm_l + i, 2, 1, fpOutPcm); /* pcm_l/pcm_r type is 'short', so the 'i' don't to multi 2 */
if(channels == 2)
{
fwrite(pcm_r + i, 2, 1, fpOutPcm);
}
}
}
}
printf("\e[32m%s -> %s success\e[0m\n", inMp3FileName, outPcmFileName);
exit:
/* MP3 decode 4/4: decode exit */
if(hip) hip_decode_exit(hip);
if(fpOutPcm) {fflush(fpOutPcm);fclose(fpOutPcm);}
if(fpInMP3) fclose(fpInMP3);
return 0;
}