lame编程:MP3解码

1. MP3文件格式解析:http://blog.csdn.net/sunshine1314/archive/2008/06/05/2514322.aspx

2. MP3帧结构:http://book.51cto.com/art/200912/173832.htm


MP3帧体的大小由MPEG版本号、比特率、抽样率和填充位4个因素确定。计算公式为:

帧大小= ((MPEG版本号== 1?144:72) * 比特率)/抽样率 + 填充位

位率为64kbps,采样频率为44.1kHz,padding(帧长调节)为1时,帧长为210字节。

位率为128kbps,采样频率为44.1kHz,padding(帧长调节)为0时,帧长为418字节。

解析MP3帧是较复杂的,且直接关系到后面分割MP3文件的工作。对于不变比特率的情况比较简单,不需要完全解析整个MP3文件就可以知道帧数、帧的大小等信息。但是,对于可变比特率的情况就显得比较复杂了,必须逐个分析MP3帧才能确定帧的大小,也只有分析了整个MP3文件才能确定帧的数量。为了能兼顾可变和不变比特率两种情况,我们考虑解析整个MP3文件,然后把每个帧的大小和在文件中的位移存储在一个Vector中,这样就可以通过时间来定位到帧的位置,便于切割MP3文件。通常一个MP3文件可能包含10000多个帧,如果所有帧都存储在Vector中,将消耗很大的内存空间,且Vector中的元素越多,查询的速度也就越慢。为了优化程序,把10个帧作为一个大帧存储在Vector中,这样在切割时依然可以精确到260ms,甚至还可以把20个帧作为一个整体,这样的效率会更高一些,内存使用更少一些,只是会丧失一些切割的精度。

解码播放程序:

/*
gcc -I./lame-3.98.4/include/ -L ./lame-3.98.4/libmp3lame/.libs/ -o mp3_play mp3_play.c -lmp3lame -lm -Wl,-rpath=./lame-3.98.4/libmp3lame/.libs/
*/
#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) + 7200

static 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;
hip_global_flags* hip;
short *right_buff, *left_buff, *ouput_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_WRONLY)) < 0){
fprintf(stderr, "open audio device error: %s", strerror(errno));
status = -1;
goto exit;
}

if((fd_f = open(argv[1], O_RDONLY)) < 0){
fprintf(stderr, "open file error: %s", strerror(errno));
status = -1;
goto exit;
}

if (SetFormat(snd_f, 16, 1, 44100) < 0) {
fprintf(stderr, "cannot set /dev/dsp in bit 16, channel 2, speed 44100/n");
status = -1;
goto exit;
}

hip = hip_decode_init();
if ( hip == NULL) {
printf("lame_init failed/n");
status = -1;
goto exit;
}

right_buff = (short *)malloc(INBUFF_SIZE);
left_buff = (short *)malloc(INBUFF_SIZE);
ouput_buff = (short *)malloc(INBUFF_SIZE*2);
mp3_buff = (char *)malloc(MP3BUFF_SIZE);

int samples;
int mp3_bytes;
int write_bytes;
while(run){
memset(right_buff, 0 , INBUFF_SIZE);
memset(left_buff, 0 , INBUFF_SIZE);
memset(ouput_buff, 0 , INBUFF_SIZE*2);
memset(mp3_buff, 0 , MP3BUFF_SIZE);

//seek(fd_f, )
samples = read(fd_f, mp3_buff, 418);
if (samples <= 0) {
fprintf(stderr, "read over!/n");
status = -1;
goto free_buffers;
}
fprintf(stderr, "samples is %d./n", samples);
mp3_bytes = hip_decode(hip, mp3_buff, 418, left_buff, right_buff);
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;
}

int i;
/*for( i= 0; i < mp3_bytes; i += 16){
memcpy(ouput_buff+2*i, left_buff+i, 16);
memcpy(ouput_buff+2*i+16, left_buff+i, 16);
}
write_bytes = write(snd_f, ouput_buff, mp3_bytes*2);*/
for( i= 0; i < mp3_bytes; i ++){
ouput_buff[i] = (right_buff[i] + left_buff[i])/2;
}
write_bytes = write(snd_f, ouput_buff, mp3_bytes);
//fprintf(stderr, "write_bytes is %d./n", write_bytes);
if(write_bytes < 0){
perror("play sound data file failed");
status = -1;
goto free_buffers;
}
}

free_buffers:
free(mp3_buff);
free(right_buff);
free(left_buff);

close(snd_f);
close(fd_f);
close_lame:
hip_decode_exit(hip);
exit:
return status;
}

Powered by Zoundry Raven

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值