Mercurial > mplayer.hg
comparison libmpcodecs/ad_libmad.c @ 5479:22b289d7f87f
libmad support, rewritten from scratch using Xine decoder as sample
author | arpi |
---|---|
date | Wed, 03 Apr 2002 20:14:18 +0000 |
parents | |
children | 4bae3caef7a9 |
comparison
equal
deleted
inserted
replaced
5478:1212d2f92a42 | 5479:22b289d7f87f |
---|---|
1 // SAMPLE audio decoder - you can use this file as template when creating new codec! | |
2 | |
3 #include <stdio.h> | |
4 #include <stdlib.h> | |
5 #include <unistd.h> | |
6 | |
7 #include "config.h" | |
8 | |
9 #ifdef USE_LIBMAD | |
10 | |
11 #include "ad_internal.h" | |
12 | |
13 static ad_info_t info = { | |
14 "libmad mpeg audio decoder", | |
15 "libmad", | |
16 AFM_MAD, | |
17 "A'rpi", | |
18 "libmad...", | |
19 "based on Xine's libmad/xine_decoder.c" | |
20 }; | |
21 | |
22 LIBAD_EXTERN(libmad) | |
23 | |
24 #include <mad.h> | |
25 | |
26 typedef struct mad_decoder_s { | |
27 | |
28 struct mad_synth synth; | |
29 struct mad_stream stream; | |
30 struct mad_frame frame; | |
31 | |
32 int have_frame; | |
33 | |
34 int output_sampling_rate; | |
35 int output_open; | |
36 int output_mode; | |
37 | |
38 } mad_decoder_t; | |
39 | |
40 static int preinit(sh_audio_t *sh){ | |
41 | |
42 mad_decoder_t *this = (mad_decoder_t *) malloc(sizeof(mad_decoder_t)); | |
43 memset(this,0,sizeof(mad_decoder_t)); | |
44 sh->context = this; | |
45 | |
46 mad_synth_init (&this->synth); | |
47 mad_stream_init (&this->stream); | |
48 mad_frame_init (&this->frame); | |
49 | |
50 sh->audio_out_minsize=2*4608; | |
51 sh->audio_in_minsize=4096; | |
52 | |
53 return 1; | |
54 } | |
55 | |
56 static int read_frame(sh_audio_t *sh){ | |
57 mad_decoder_t *this = (mad_decoder_t *) sh->context; | |
58 int len; | |
59 | |
60 while((len=demux_read_data(sh->ds,&sh->a_in_buffer[sh->a_in_buffer_len], | |
61 sh->a_in_buffer_size-sh->a_in_buffer_len))>0){ | |
62 sh->a_in_buffer_len+=len; | |
63 while(1){ | |
64 int ret; | |
65 mad_stream_buffer (&this->stream, sh->a_in_buffer, sh->a_in_buffer_len); | |
66 ret=mad_frame_decode (&this->frame, &this->stream); | |
67 if (this->stream.next_frame) { | |
68 int num_bytes = | |
69 (char*)sh->a_in_buffer+sh->a_in_buffer_len - (char*)this->stream.next_frame; | |
70 memmove(sh->a_in_buffer, this->stream.next_frame, num_bytes); | |
71 mp_msg(MSGT_DECAUDIO,MSGL_DBG2,"libmad: %d bytes processed\n",sh->a_in_buffer_len-num_bytes); | |
72 sh->a_in_buffer_len = num_bytes; | |
73 } | |
74 if (ret == 0) return 1; // OK!!! | |
75 // error! try to resync! | |
76 if(this->stream.error==MAD_ERROR_BUFLEN) break; | |
77 } | |
78 } | |
79 mp_msg(MSGT_DECAUDIO,MSGL_INFO,"Cannot sync MAD frame\n"); | |
80 return 0; | |
81 } | |
82 | |
83 static int init(sh_audio_t *sh){ | |
84 mad_decoder_t *this = (mad_decoder_t *) sh->context; | |
85 | |
86 this->have_frame=read_frame(sh); | |
87 if(!this->have_frame) return 0; // failed to sync... | |
88 | |
89 sh->channels=(this->frame.header.mode == MAD_MODE_SINGLE_CHANNEL) ? 1 : 2; | |
90 sh->samplerate=this->frame.header.samplerate; | |
91 sh->i_bps=this->frame.header.bitrate/8; | |
92 | |
93 return 1; | |
94 } | |
95 | |
96 static void uninit(sh_audio_t *sh){ | |
97 mad_decoder_t *this = (mad_decoder_t *) sh->context; | |
98 mad_synth_finish (&this->synth); | |
99 mad_frame_finish (&this->frame); | |
100 mad_stream_finish(&this->stream); | |
101 free(sh->context); | |
102 } | |
103 | |
104 /* utility to scale and round samples to 16 bits */ | |
105 static inline signed int scale(mad_fixed_t sample) { | |
106 /* round */ | |
107 sample += (1L << (MAD_F_FRACBITS - 16)); | |
108 | |
109 /* clip */ | |
110 if (sample >= MAD_F_ONE) | |
111 sample = MAD_F_ONE - 1; | |
112 else if (sample < -MAD_F_ONE) | |
113 sample = -MAD_F_ONE; | |
114 | |
115 /* quantize */ | |
116 return sample >> (MAD_F_FRACBITS + 1 - 16); | |
117 } | |
118 | |
119 static int decode_audio(sh_audio_t *sh,unsigned char *buf,int minlen,int maxlen){ | |
120 mad_decoder_t *this = (mad_decoder_t *) sh->context; | |
121 int len=0; | |
122 | |
123 while(len<minlen && len+4608<=maxlen){ | |
124 if(!this->have_frame) this->have_frame=read_frame(sh); | |
125 if(!this->have_frame) break; // failed to sync... or EOF | |
126 this->have_frame=0; | |
127 | |
128 mad_synth_frame (&this->synth, &this->frame); | |
129 | |
130 { unsigned int nchannels, nsamples; | |
131 mad_fixed_t const *left_ch, *right_ch; | |
132 struct mad_pcm *pcm = &this->synth.pcm; | |
133 uint16_t *output = (uint16_t*) buf; | |
134 | |
135 nchannels = pcm->channels; | |
136 nsamples = pcm->length; | |
137 left_ch = pcm->samples[0]; | |
138 right_ch = pcm->samples[1]; | |
139 | |
140 len+=2*nchannels*nsamples; | |
141 buf+=2*nchannels*nsamples; | |
142 | |
143 while (nsamples--) { | |
144 /* output sample(s) in 16-bit signed little-endian PCM */ | |
145 | |
146 *output++ = scale(*left_ch++); | |
147 | |
148 if (nchannels == 2) | |
149 *output++ = scale(*right_ch++); | |
150 | |
151 } | |
152 } | |
153 } | |
154 | |
155 return len?len:-1; | |
156 } | |
157 | |
158 static int control(sh_audio_t *sh,int cmd,void* arg, ...){ | |
159 mad_decoder_t *this = (mad_decoder_t *) sh->context; | |
160 // various optional functions you MAY implement: | |
161 switch(cmd){ | |
162 case ADCTRL_RESYNC_STREAM: | |
163 sh->a_in_buffer_len=0; // clear audio input buffer | |
164 this->have_frame=0; | |
165 mad_synth_init (&this->synth); | |
166 mad_stream_init (&this->stream); | |
167 mad_frame_init (&this->frame); | |
168 return CONTROL_TRUE; | |
169 case ADCTRL_SKIP_FRAME: | |
170 this->have_frame=read_frame(sh); | |
171 return CONTROL_TRUE; | |
172 } | |
173 return CONTROL_UNKNOWN; | |
174 } | |
175 #endif |