音频demo:使用开源项目lame来将MP3数据解码出PCM数据

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;
}

3、demo下载地址(任选一个)

相关推荐

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-09 20:24:08       66 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-09 20:24:08       70 阅读
  3. 在Django里面运行非项目文件

    2024-07-09 20:24:08       57 阅读
  4. Python语言-面向对象

    2024-07-09 20:24:08       68 阅读

热门阅读

  1. Linux Conda 入门案例教程

    2024-07-09 20:24:08       23 阅读
  2. HTTP Client

    2024-07-09 20:24:08       32 阅读
  3. `mysql`常用的的CIL命令行工具

    2024-07-09 20:24:08       45 阅读
  4. 在 Windows PowerShell 中模拟 Unix/Linux 的 touch 命令

    2024-07-09 20:24:08       23 阅读
  5. LVS+keepalived群集

    2024-07-09 20:24:08       28 阅读
  6. qt udp通讯应用举例

    2024-07-09 20:24:08       29 阅读
  7. Vuetify3:v-data-table增加下拉筛选

    2024-07-09 20:24:08       17 阅读
  8. 通过升级tomcat完美解决服务器的tomcat漏洞

    2024-07-09 20:24:08       24 阅读
  9. unity 使用UnityWebRequest从服务器下载

    2024-07-09 20:24:08       20 阅读
  10. el-table 树状表格查询符合条件的数据

    2024-07-09 20:24:08       24 阅读