Mercurial > mplayer.hg
changeset 5479:22b289d7f87f
libmad support, rewritten from scratch using Xine decoder as sample
author | arpi |
---|---|
date | Wed, 03 Apr 2002 20:14:18 +0000 |
parents | 1212d2f92a42 |
children | df12f6eb80e3 |
files | libmpcodecs/Makefile libmpcodecs/ad.c libmpcodecs/ad_libmad.c |
diffstat | 3 files changed, 180 insertions(+), 1 deletions(-) [+] |
line wrap: on
line diff
--- a/libmpcodecs/Makefile Wed Apr 03 19:09:55 2002 +0000 +++ b/libmpcodecs/Makefile Wed Apr 03 20:14:18 2002 +0000 @@ -3,7 +3,7 @@ LIBNAME = libmpcodecs.a -AUDIO_SRCS=dec_audio.c ad.c ad_a52.c ad_acm.c ad_alaw.c ad_dk3adpcm.c ad_dshow.c ad_dvdpcm.c ad_ffmpeg.c ad_hwac3.c ad_imaadpcm.c ad_mp3.c ad_msadpcm.c ad_pcm.c ad_roqaudio.c ad_msgsm.c ad_faad.c ad_vorbis.c +AUDIO_SRCS=dec_audio.c ad.c ad_a52.c ad_acm.c ad_alaw.c ad_dk3adpcm.c ad_dshow.c ad_dvdpcm.c ad_ffmpeg.c ad_hwac3.c ad_imaadpcm.c ad_mp3.c ad_msadpcm.c ad_pcm.c ad_roqaudio.c ad_msgsm.c ad_faad.c ad_vorbis.c ad_libmad.c VIDEO_SRCS=dec_video.c vd.c vd_null.c vd_cinepak.c vd_qtrpza.c vd_ffmpeg.c vd_dshow.c vd_vfw.c vd_odivx.c vd_divx4.c vd_raw.c vd_xanim.c vd_msvidc.c vd_fli.c vd_qtrle.c vd_qtsmc.c vd_roqvideo.c vd_cyuv.c vd_nuv.c vd_libmpeg2.c vd_msrle.c vd_huffyuv.c vd_zlib.c vd_mpegpes.c ifeq ($(PNG),yes)
--- a/libmpcodecs/ad.c Wed Apr 03 19:09:55 2002 +0000 +++ b/libmpcodecs/ad.c Wed Apr 03 20:14:18 2002 +0000 @@ -32,6 +32,7 @@ extern ad_functions_t mpcodecs_ad_msgsm; extern ad_functions_t mpcodecs_ad_faad; extern ad_functions_t mpcodecs_ad_vorbis; +extern ad_functions_t mpcodecs_ad_libmad; ad_functions_t* mpcodecs_ad_drivers[] = { @@ -62,5 +63,8 @@ #ifdef HAVE_OGGVORBIS &mpcodecs_ad_vorbis, #endif +#ifdef USE_LIBMAD + &mpcodecs_ad_libmad, +#endif NULL };
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmpcodecs/ad_libmad.c Wed Apr 03 20:14:18 2002 +0000 @@ -0,0 +1,175 @@ +// SAMPLE audio decoder - you can use this file as template when creating new codec! + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include "config.h" + +#ifdef USE_LIBMAD + +#include "ad_internal.h" + +static ad_info_t info = { + "libmad mpeg audio decoder", + "libmad", + AFM_MAD, + "A'rpi", + "libmad...", + "based on Xine's libmad/xine_decoder.c" +}; + +LIBAD_EXTERN(libmad) + +#include <mad.h> + +typedef struct mad_decoder_s { + + struct mad_synth synth; + struct mad_stream stream; + struct mad_frame frame; + + int have_frame; + + int output_sampling_rate; + int output_open; + int output_mode; + +} mad_decoder_t; + +static int preinit(sh_audio_t *sh){ + + mad_decoder_t *this = (mad_decoder_t *) malloc(sizeof(mad_decoder_t)); + memset(this,0,sizeof(mad_decoder_t)); + sh->context = this; + + mad_synth_init (&this->synth); + mad_stream_init (&this->stream); + mad_frame_init (&this->frame); + + sh->audio_out_minsize=2*4608; + sh->audio_in_minsize=4096; + + return 1; +} + +static int read_frame(sh_audio_t *sh){ + mad_decoder_t *this = (mad_decoder_t *) sh->context; + int len; + +while((len=demux_read_data(sh->ds,&sh->a_in_buffer[sh->a_in_buffer_len], + sh->a_in_buffer_size-sh->a_in_buffer_len))>0){ + sh->a_in_buffer_len+=len; + while(1){ + int ret; + mad_stream_buffer (&this->stream, sh->a_in_buffer, sh->a_in_buffer_len); + ret=mad_frame_decode (&this->frame, &this->stream); + if (this->stream.next_frame) { + int num_bytes = + (char*)sh->a_in_buffer+sh->a_in_buffer_len - (char*)this->stream.next_frame; + memmove(sh->a_in_buffer, this->stream.next_frame, num_bytes); + mp_msg(MSGT_DECAUDIO,MSGL_DBG2,"libmad: %d bytes processed\n",sh->a_in_buffer_len-num_bytes); + sh->a_in_buffer_len = num_bytes; + } + if (ret == 0) return 1; // OK!!! + // error! try to resync! + if(this->stream.error==MAD_ERROR_BUFLEN) break; + } +} +mp_msg(MSGT_DECAUDIO,MSGL_INFO,"Cannot sync MAD frame\n"); +return 0; +} + +static int init(sh_audio_t *sh){ + mad_decoder_t *this = (mad_decoder_t *) sh->context; + + this->have_frame=read_frame(sh); + if(!this->have_frame) return 0; // failed to sync... + + sh->channels=(this->frame.header.mode == MAD_MODE_SINGLE_CHANNEL) ? 1 : 2; + sh->samplerate=this->frame.header.samplerate; + sh->i_bps=this->frame.header.bitrate/8; + + return 1; +} + +static void uninit(sh_audio_t *sh){ + mad_decoder_t *this = (mad_decoder_t *) sh->context; + mad_synth_finish (&this->synth); + mad_frame_finish (&this->frame); + mad_stream_finish(&this->stream); + free(sh->context); +} + +/* utility to scale and round samples to 16 bits */ +static inline signed int scale(mad_fixed_t sample) { + /* round */ + sample += (1L << (MAD_F_FRACBITS - 16)); + + /* clip */ + if (sample >= MAD_F_ONE) + sample = MAD_F_ONE - 1; + else if (sample < -MAD_F_ONE) + sample = -MAD_F_ONE; + + /* quantize */ + return sample >> (MAD_F_FRACBITS + 1 - 16); +} + +static int decode_audio(sh_audio_t *sh,unsigned char *buf,int minlen,int maxlen){ + mad_decoder_t *this = (mad_decoder_t *) sh->context; + int len=0; + + while(len<minlen && len+4608<=maxlen){ + if(!this->have_frame) this->have_frame=read_frame(sh); + if(!this->have_frame) break; // failed to sync... or EOF + this->have_frame=0; + + mad_synth_frame (&this->synth, &this->frame); + + { unsigned int nchannels, nsamples; + mad_fixed_t const *left_ch, *right_ch; + struct mad_pcm *pcm = &this->synth.pcm; + uint16_t *output = (uint16_t*) buf; + + nchannels = pcm->channels; + nsamples = pcm->length; + left_ch = pcm->samples[0]; + right_ch = pcm->samples[1]; + + len+=2*nchannels*nsamples; + buf+=2*nchannels*nsamples; + + while (nsamples--) { + /* output sample(s) in 16-bit signed little-endian PCM */ + + *output++ = scale(*left_ch++); + + if (nchannels == 2) + *output++ = scale(*right_ch++); + + } + } + } + + return len?len:-1; +} + +static int control(sh_audio_t *sh,int cmd,void* arg, ...){ + mad_decoder_t *this = (mad_decoder_t *) sh->context; + // various optional functions you MAY implement: + switch(cmd){ + case ADCTRL_RESYNC_STREAM: + sh->a_in_buffer_len=0; // clear audio input buffer + this->have_frame=0; + mad_synth_init (&this->synth); + mad_stream_init (&this->stream); + mad_frame_init (&this->frame); + return CONTROL_TRUE; + case ADCTRL_SKIP_FRAME: + this->have_frame=read_frame(sh); + return CONTROL_TRUE; + } + return CONTROL_UNKNOWN; +} +#endif