core: Set mpctx->chapters to NULL at uninit
[mplayer.git] / libmpcodecs / ad_libmad.c
blobfb20f2a77f59cf00bfd521872af8b16cd837dd4f
1 // SAMPLE audio decoder - you can use this file as template when creating new codec!
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <unistd.h>
7 #include "config.h"
9 #include "ad_internal.h"
11 static const ad_info_t info = {
12 "libmad mpeg audio decoder",
13 "libmad",
14 "A'rpi",
15 "libmad...",
16 "based on Xine's libmad/xine_decoder.c"
19 LIBAD_EXTERN(libmad)
21 #include <mad.h>
23 typedef struct mad_decoder_s {
25 struct mad_synth synth;
26 struct mad_stream stream;
27 struct mad_frame frame;
29 int have_frame;
31 int output_sampling_rate;
32 int output_open;
33 int output_mode;
35 } mad_decoder_t;
37 static int preinit(sh_audio_t *sh){
39 mad_decoder_t *this = (mad_decoder_t *) malloc(sizeof(mad_decoder_t));
40 memset(this,0,sizeof(mad_decoder_t));
41 sh->context = this;
43 mad_synth_init (&this->synth);
44 mad_stream_init (&this->stream);
45 mad_frame_init (&this->frame);
47 sh->audio_out_minsize=2*4608;
48 sh->audio_in_minsize=4096;
50 return 1;
53 static int read_frame(sh_audio_t *sh){
54 mad_decoder_t *this = (mad_decoder_t *) sh->context;
55 int len;
57 while((len=demux_read_data(sh->ds,&sh->a_in_buffer[sh->a_in_buffer_len],
58 sh->a_in_buffer_size-sh->a_in_buffer_len))>0){
59 sh->a_in_buffer_len+=len;
60 while(1){
61 int ret;
62 mad_stream_buffer (&this->stream, sh->a_in_buffer, sh->a_in_buffer_len);
63 ret=mad_frame_decode (&this->frame, &this->stream);
64 if (this->stream.next_frame) {
65 int num_bytes =
66 (char*)sh->a_in_buffer+sh->a_in_buffer_len - (char*)this->stream.next_frame;
67 memmove(sh->a_in_buffer, this->stream.next_frame, num_bytes);
68 mp_msg(MSGT_DECAUDIO,MSGL_DBG2,"libmad: %d bytes processed\n",sh->a_in_buffer_len-num_bytes);
69 sh->a_in_buffer_len = num_bytes;
71 if (ret == 0) return 1; // OK!!!
72 // error! try to resync!
73 if(this->stream.error==MAD_ERROR_BUFLEN) break;
76 mp_msg(MSGT_DECAUDIO,MSGL_INFO,"Cannot sync MAD frame\n");
77 return 0;
80 static int init(sh_audio_t *sh){
81 mad_decoder_t *this = (mad_decoder_t *) sh->context;
83 this->have_frame=read_frame(sh);
84 if(!this->have_frame) return 0; // failed to sync...
86 sh->channels=(this->frame.header.mode == MAD_MODE_SINGLE_CHANNEL) ? 1 : 2;
87 sh->samplerate=this->frame.header.samplerate;
88 sh->i_bps=this->frame.header.bitrate/8;
89 sh->samplesize=2;
91 return 1;
94 static void uninit(sh_audio_t *sh){
95 mad_decoder_t *this = (mad_decoder_t *) sh->context;
96 mad_synth_finish (&this->synth);
97 mad_frame_finish (&this->frame);
98 mad_stream_finish(&this->stream);
99 free(sh->context);
102 /* utility to scale and round samples to 16 bits */
103 static inline signed int scale(mad_fixed_t sample) {
104 /* round */
105 sample += (1L << (MAD_F_FRACBITS - 16));
107 /* clip */
108 if (sample >= MAD_F_ONE)
109 sample = MAD_F_ONE - 1;
110 else if (sample < -MAD_F_ONE)
111 sample = -MAD_F_ONE;
113 /* quantize */
114 return sample >> (MAD_F_FRACBITS + 1 - 16);
117 static int decode_audio(sh_audio_t *sh,unsigned char *buf,int minlen,int maxlen){
118 mad_decoder_t *this = (mad_decoder_t *) sh->context;
119 int len=0;
121 while(len<minlen && len+4608<=maxlen){
122 if(!this->have_frame) this->have_frame=read_frame(sh);
123 if(!this->have_frame) break; // failed to sync... or EOF
124 this->have_frame=0;
126 mad_synth_frame (&this->synth, &this->frame);
128 { unsigned int nchannels, nsamples;
129 mad_fixed_t const *left_ch, *right_ch;
130 struct mad_pcm *pcm = &this->synth.pcm;
131 uint16_t *output = (uint16_t*) buf;
133 nchannels = pcm->channels;
134 nsamples = pcm->length;
135 left_ch = pcm->samples[0];
136 right_ch = pcm->samples[1];
138 len+=2*nchannels*nsamples;
139 buf+=2*nchannels*nsamples;
141 while (nsamples--) {
142 /* output sample(s) in 16-bit signed little-endian PCM */
144 *output++ = scale(*left_ch++);
146 if (nchannels == 2)
147 *output++ = scale(*right_ch++);
153 return len?len:-1;
156 static int control(sh_audio_t *sh,int cmd,void* arg, ...){
157 mad_decoder_t *this = (mad_decoder_t *) sh->context;
158 // various optional functions you MAY implement:
159 switch(cmd){
160 case ADCTRL_RESYNC_STREAM:
161 this->have_frame=0;
162 mad_synth_init (&this->synth);
163 mad_stream_init (&this->stream);
164 mad_frame_init (&this->frame);
165 return CONTROL_TRUE;
166 case ADCTRL_SKIP_FRAME:
167 this->have_frame=read_frame(sh);
168 return CONTROL_TRUE;
170 return CONTROL_UNKNOWN;