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(&params);
        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;
}

原创粉丝点击