libmad MP3解码
来源:互联网 发布:java工程师的简历模板 编辑:程序博客网 时间:2024/05/22 04:43
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <mad.h>
#include <alsa/asoundlib.h>
#include <sys/mman.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#define INPUT_BUFFER_SIZE (5*8192)
#define OUTPUT_BUFFER_SIZE 4096
snd_pcm_t *handle;
char *buffer;
snd_pcm_uframes_t frames;
unsigned char *play_finish;
unsigned char *play_buffer;
/****************************************************************************
Converts a sample from mad's fixed point number format to an unsigned short(16bits).
****************************************************************************/
static unsigned short MadFixedToUshort(mad_fixed_t Fixed)
{
Fixed=Fixed>>(MAD_F_FRACBITS-15);
return((unsigned short)Fixed);
}
int snd_init() {
int dir;
unsigned int val;
snd_pcm_hw_params_t *params;
int rc;
printf("my music player %s\n",__TIME__);
rc=snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0);
snd_pcm_hw_params_alloca(¶ms);
snd_pcm_hw_params_any(handle, params);
snd_pcm_hw_params_set_access(handle, params,SND_PCM_ACCESS_RW_INTERLEAVED);
snd_pcm_hw_params_set_format(handle, params,SND_PCM_FORMAT_S16_LE);
snd_pcm_hw_params_set_channels(handle, params, 2);
val = 44000;
snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir);
frames =1024;
snd_pcm_hw_params_set_period_size_near(handle,params, &frames, &dir);
rc=snd_pcm_hw_params(handle, params);
if (rc < 0) {
printf("Unable to set hw params for playback: %s\n", snd_strerror(rc));
return rc;
}
return 0;
}
int decode(FILE *mp3file_fp){
struct mad_stream Stream;
struct mad_frame Frame;
struct mad_synth Synth;
mad_timer_t Timer;
unsigned char Mp3_InputBuffer[INPUT_BUFFER_SIZE];
unsigned char OutputBuffer[OUTPUT_BUFFER_SIZE];
unsigned char *OutputPtr=OutputBuffer;
const unsigned char *OutputBufferEnd=OutputBuffer+OUTPUT_BUFFER_SIZE;
int Status=0;
int i;
unsigned long FrameCount=0;
/* libmad 初始化 */
mad_stream_init(&Stream);
mad_frame_init(&Frame);
mad_synth_init(&Synth);
mad_timer_reset(&Timer);
/* 开始解码*/
do
{
/*如果缓冲区空了或者太小了,那就往里填充*/
if(Stream.buffer==NULL || Stream.error==MAD_ERROR_BUFLEN)
{
size_t BufferSize; /*缓冲区大小*/
size_t Remaining; /*帧剩余数据*/
unsigned char *BufferStart; /*头指针*/
if(Stream.next_frame!=NULL)
{ /*把剩余没解码完的数据补充的这次的缓冲区中*/
Remaining=Stream.bufend-Stream.next_frame;
memmove(Mp3_InputBuffer,Stream.next_frame,Remaining);
BufferStart=Mp3_InputBuffer+Remaining;
BufferSize=INPUT_BUFFER_SIZE-Remaining;
}
else{ /* 填充第一段数据到缓冲区 */
BufferSize=INPUT_BUFFER_SIZE;
BufferStart=Mp3_InputBuffer;
Remaining=0;
/*设置了缓冲区地址,但是还没填充数据*/
}
/* 开始从文件中读取数据 */
BufferSize=fread(BufferStart,1,BufferSize,mp3file_fp);
if(BufferSize<=0) break;
mad_stream_buffer(&Stream,Mp3_InputBuffer,BufferSize+Remaining);
Stream.error=0;
}
/*解码帧数据*/
if(mad_frame_decode(&Frame,&Stream)){
if(MAD_RECOVERABLE(Stream.error))
{
fprintf(stderr,"可恢复的小错误\n");
fflush(stderr);
continue;
}else{
if(Stream.error==MAD_ERROR_BUFLEN){
continue; /*buffer解码光了,需要继续填充了*/
}else{
fprintf(stderr,"严重错误,停止解码\n");
Status=1;
break;
}
}
}
/*如果是第一帧,我们要从里面拿出音频的具体信息来初始化声卡*/
FrameCount++; /*记录解码了多少帧*/
mad_timer_add(&Timer,Frame.header.duration); /*设置每帧的播放时间*/
mad_synth_frame(&Synth,&Frame);/*解码成音频数据*/
/* 把解码后的音频数据转换成16位的数据*/
for(i=0;i<Synth.pcm.length;i++)
{
unsigned short Sample;
Sample=MadFixedToUshort(Synth.pcm.samples[0][i]);
*(OutputPtr++)=Sample>>8;
*(OutputPtr++)=Sample&0xff;
if(MAD_NCHANNELS(&Frame.header)==2)
Sample=MadFixedToUshort(Synth.pcm.samples[1][i]);
*(OutputPtr++)=Sample>>8;
*(OutputPtr++)=Sample&0xff;
/* 满了 */
if(OutputPtr==OutputBufferEnd)
{
while(*play_finish==0) usleep(100);//等待播放完
memcpy(play_buffer,OutputBuffer,OutputBufferEnd-OutputBuffer);
*play_finish=0;
OutputPtr=OutputBuffer;/*重头开始再填数据*/
}
}
}while(1);
/* 结束收工~~~~~~*/
mad_synth_finish(&Synth);
mad_frame_finish(&Frame);
mad_stream_finish(&Stream);
return(Status);
}
int main(int argc, char *argv[])
{
FILE* mp3_fp;
pid_t pid;
play_finish=mmap(NULL,sizeof(unsigned char),PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANONYMOUS,0,0);
play_buffer=mmap(NULL,OUTPUT_BUFFER_SIZE,PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANONYMOUS,0,0);
*play_finish=1;
if(!argv[1]){
printf("plz input mp3 document\n");
exit(-1);
}
mp3_fp=fopen(argv[1],"r");
snd_init();
pid=fork();
if(pid>0){
sleep(1);
while(*play_finish==0){
snd_pcm_writei(handle, play_buffer+1, frames);
*play_finish=1;
while(*play_finish);
}
}
decode(mp3_fp);
return 0;
}
- 利用libmad解码mp3
- 利用libmad解码mp3
- libmad MP3解码
- libmad解码mp3生成pcm文件
- 基于libmad编写mp3解码程序
- MP3解码库libmad到OpenCore的移植
- libmad解码MP3——/dev/dsp播放
- libmad解码MP3——/dev/dsp播放
- 关于libmad开源mp3音频解码库的使用
- 使用LibMad解码MP3,Windows上播放MP3,MP3转WAV实例代码
- 让终端支持播放mp3,移植mp3解码库libmad和madplay到嵌入式linux
- MyMinimad ── Linux下用libmad写的mp3解码播放程序
- MyMinimad ── Linux下用libmad写的mp3解码播放程序(二)
- MyMinimad ── Linux下用libmad写的mp3解码播放程序
- linux下使用libmad库实现mp3文件的解码、播放
- 基于bsd socket传输libmad解码,alsa驱动的mp3流媒体播放器
- linux下使用libmad库实现mp3文件的解码、播放
- linux 基于alsa 使用libmad 解码库实现MP3文件的播放
- iOS 多线程 锁 互斥 同步
- ios 国际化(项目名和内容)
- 探索Android 下拉刷新效果的实现
- Silverlight5在Tomcat上的部署
- MotionEvent事件在onInterceptTouchEvent()、onTouchEvent()中的传递顺序
- libmad MP3解码
- HDU2955--Robberies--动态规划
- 获取iPhone通话记录(需越狱)
- C程序中内存布局&Union大小尾端
- Windows系统获取系统的启动时间
- javascript美化下拉框js
- AS3中的元数据标签
- 最好的 调试函数 dump 取自 thinkphp
- 适配器模式(Adepter)