Moves volume icon update in the timer
[vlc.git] / modules / audio_filter / converter / mpgatofixed32.c
1 /*****************************************************************************
2  * mpgatofixed32.c: MPEG-1 & 2 audio layer I, II, III + MPEG 2.5 decoder,
3  * using MAD (MPEG Audio Decoder)
4  *****************************************************************************
5  * Copyright (C) 2001-2005 the VideoLAN team
6  * $Id$
7  *
8  * Authors: Christophe Massiot <massiot@via.ecp.fr>
9  *          Jean-Paul Saman <jpsaman _at_ videolan _dot_ org>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  * 
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24  *****************************************************************************/
25
26 /*****************************************************************************
27  * Preamble
28  *****************************************************************************/
29
30 #include <mad.h>
31
32 #include <vlc/vlc.h>
33 #include <vlc_aout.h>
34 #include <vlc_block.h>
35 #include "vlc_filter.h"
36
37 /*****************************************************************************
38  * Local prototypes
39  *****************************************************************************/
40 static int  Create    ( vlc_object_t * );
41 static void Destroy   ( vlc_object_t * );
42 static void DoWork    ( aout_instance_t *, aout_filter_t *, aout_buffer_t *,  
43                         aout_buffer_t * );
44
45 static int  OpenFilter ( vlc_object_t * );
46 static void CloseFilter( vlc_object_t * );
47 static block_t *Convert( filter_t *, block_t * );
48
49 /*****************************************************************************
50  * Local structures
51  *****************************************************************************/
52 struct filter_sys_t
53 {
54     struct mad_stream mad_stream;
55     struct mad_frame  mad_frame;
56     struct mad_synth  mad_synth;
57
58     int               i_reject_count;
59 };
60
61 /*****************************************************************************
62  * Module descriptor
63  *****************************************************************************/
64 vlc_module_begin();
65     set_category( CAT_INPUT );
66     set_subcategory( SUBCAT_INPUT_ACODEC );
67     set_description( _("MPEG audio decoder") );
68     set_capability( "audio filter", 100 );
69     set_callbacks( Create, Destroy );
70
71     add_submodule();
72     set_description( _("MPEG audio decoder") );
73     set_capability( "audio filter2", 100 );
74     set_callbacks( OpenFilter, CloseFilter );
75 vlc_module_end();
76
77 /*****************************************************************************
78  * Create: 
79  *****************************************************************************/
80 static int Create( vlc_object_t *p_this )
81 {
82     aout_filter_t *p_filter = (aout_filter_t *)p_this;
83     struct filter_sys_t *p_sys;
84
85     if ( (p_filter->input.i_format != VLC_FOURCC('m','p','g','a')
86            && p_filter->input.i_format != VLC_FOURCC('m','p','g','3'))
87             || (p_filter->output.i_format != VLC_FOURCC('f','l','3','2')
88                  && p_filter->output.i_format != VLC_FOURCC('f','i','3','2')) )
89     {
90         return -1;
91     }
92
93     if ( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
94     {
95         return -1;
96     }
97
98     /* Allocate the memory needed to store the module's structure */
99     p_sys = malloc( sizeof(filter_sys_t) );
100     p_filter->p_sys = (struct aout_filter_sys_t *)p_sys;
101     if( p_sys == NULL )
102     {
103         msg_Err( p_filter, "out of memory" );
104         return -1;
105     }
106
107     /* Initialize libmad */
108     mad_stream_init( &p_sys->mad_stream );
109     mad_frame_init( &p_sys->mad_frame );
110     mad_synth_init( &p_sys->mad_synth );
111     mad_stream_options( &p_sys->mad_stream, MAD_OPTION_IGNORECRC );
112     p_sys->i_reject_count = 0;
113
114     p_filter->pf_do_work = DoWork;
115     p_filter->b_in_place = 0;
116
117     return 0;
118 }
119
120 /*****************************************************************************
121  * DoWork: decode an MPEG audio frame.
122  *****************************************************************************/
123 static void DoWork( aout_instance_t * p_aout, aout_filter_t * p_filter,
124                     aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
125 {
126     filter_sys_t *p_sys = (filter_sys_t *)p_filter->p_sys;
127
128     p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
129     p_out_buf->i_nb_bytes = p_in_buf->i_nb_samples * sizeof(vlc_fixed_t) * 
130                                aout_FormatNbChannels( &p_filter->output );
131
132     /* Do the actual decoding now. */
133     mad_stream_buffer( &p_sys->mad_stream, p_in_buf->p_buffer,
134                        p_in_buf->i_nb_bytes );
135     if ( mad_frame_decode( &p_sys->mad_frame, &p_sys->mad_stream ) == -1 )
136     {
137         msg_Dbg( p_aout, "libmad error: %s",
138                   mad_stream_errorstr( &p_sys->mad_stream ) );
139         p_sys->i_reject_count = 3;
140     }
141     else if( p_in_buf->b_discontinuity )
142     {
143         p_sys->i_reject_count = 3;
144     }
145
146     if( p_sys->i_reject_count > 0 )
147     {
148         if( p_filter->output.i_format == VLC_FOURCC('f','l','3','2') )
149         {
150             int i;
151             int i_size = p_out_buf->i_nb_bytes / sizeof(float);
152
153             float * a = (float *)p_out_buf->p_buffer;
154             for ( i = 0 ; i < i_size ; i++ )
155                 *a++ = 0.0;
156         }
157         else
158         {
159             memset( p_out_buf->p_buffer, 0, p_out_buf->i_nb_bytes );
160         }
161         p_sys->i_reject_count--;
162         return;
163     }
164
165
166     mad_synth_frame( &p_sys->mad_synth, &p_sys->mad_frame );
167
168     if ( p_filter->output.i_format == VLC_FOURCC('f','i','3','2') )
169     {
170         /* Interleave and keep buffers in mad_fixed_t format */
171         mad_fixed_t * p_samples = (mad_fixed_t *)p_out_buf->p_buffer;
172         struct mad_pcm * p_pcm = &p_sys->mad_synth.pcm;
173         unsigned int i_samples = p_pcm->length;
174         mad_fixed_t const * p_left = p_pcm->samples[0];
175         mad_fixed_t const * p_right = p_pcm->samples[1];
176
177         switch ( p_pcm->channels )
178         {
179         case 2:
180             if ( p_filter->output.i_physical_channels == AOUT_CHAN_CENTER )
181             {
182                 while ( i_samples-- )
183                 {
184                     *p_samples++ = (*p_left++ >> 1) + (*p_right++ >> 1);
185                 }
186             }
187             else if ( p_filter->output.i_original_channels == AOUT_CHAN_LEFT )
188             {
189                 while ( i_samples-- )
190                 {
191                     *p_samples++ = *p_left;
192                     *p_samples++ = *p_left++;
193                 }
194             }
195             else if ( p_filter->output.i_original_channels == AOUT_CHAN_RIGHT )
196             {
197                 while ( i_samples-- )
198                 {
199                     *p_samples++ = *p_right;
200                     *p_samples++ = *p_right++;
201                 }
202             }
203             else
204             {
205                 while ( i_samples-- )
206                 {
207                     *p_samples++ = *p_left++;
208                     *p_samples++ = *p_right++;
209                 }
210             }
211             break;
212
213         case 1:
214             p_filter->p_libvlc->pf_memcpy( p_samples, p_left,
215                                         i_samples * sizeof(mad_fixed_t) );
216             break;
217
218         default:
219             msg_Err( p_aout, "cannot interleave %i channels",
220                      p_pcm->channels );
221         }
222     }
223     else
224     {
225         /* float32 */
226         float * p_samples = (float *)p_out_buf->p_buffer;
227         struct mad_pcm * p_pcm = &p_sys->mad_synth.pcm;
228         unsigned int i_samples = p_pcm->length;
229         mad_fixed_t const * p_left = p_pcm->samples[0];
230         mad_fixed_t const * p_right = p_pcm->samples[1];
231         float f_temp = (float)FIXED32_ONE;
232
233         switch ( p_pcm->channels )
234         {
235         case 2:
236             if ( p_filter->output.i_physical_channels == AOUT_CHAN_CENTER )
237             {
238                 while ( i_samples-- )
239                 {
240                     *p_samples++ = (float)*p_left++ / f_temp / 2 +
241                                    (float)*p_right++ / f_temp / 2;
242                 }
243             }
244             else if ( p_filter->output.i_original_channels == AOUT_CHAN_LEFT )
245             {
246                 while ( i_samples-- )
247                 {
248                     *p_samples++ = (float)*p_left / f_temp;
249                     *p_samples++ = (float)*p_left++ / f_temp;
250                 }
251             }
252             else if ( p_filter->output.i_original_channels == AOUT_CHAN_RIGHT )
253             {
254                 while ( i_samples-- )
255                 {
256                     *p_samples++ = (float)*p_right / f_temp;
257                     *p_samples++ = (float)*p_right++ / f_temp;
258                 }
259             }
260             else
261             {
262                 while ( i_samples-- )
263                 {
264                     *p_samples++ = (float)*p_left++ / f_temp;
265                     *p_samples++ = (float)*p_right++ / f_temp;
266                 }
267             }
268             break;
269
270         case 1:
271             while ( i_samples-- )
272             {
273                 *p_samples++ = (float)*p_left++ / f_temp;
274             }
275             break;
276
277         default:
278             msg_Err( p_aout, "cannot interleave %i channels",
279                      p_pcm->channels );
280         }
281     }
282 }
283
284 /*****************************************************************************
285  * Destroy : deallocate data structures
286  *****************************************************************************/
287 static void Destroy( vlc_object_t *p_this )
288 {
289     aout_filter_t *p_filter = (aout_filter_t *)p_this;
290     filter_sys_t *p_sys = (filter_sys_t *)p_filter->p_sys;
291
292     mad_synth_finish( &p_sys->mad_synth );
293     mad_frame_finish( &p_sys->mad_frame );
294     mad_stream_finish( &p_sys->mad_stream );
295     free( p_sys );
296 }
297
298 /*****************************************************************************
299  * OpenFilter: 
300  *****************************************************************************/
301 static int OpenFilter( vlc_object_t *p_this )
302 {
303     filter_t *p_filter = (filter_t *)p_this;
304     filter_sys_t *p_sys;
305
306     if( p_filter->fmt_in.i_codec != VLC_FOURCC('m','p','g','a') &&
307         p_filter->fmt_in.i_codec != VLC_FOURCC('m','p','g','3') )
308     {
309         return VLC_EGENERIC;
310     }
311
312     /* Allocate the memory needed to store the module's structure */
313     p_sys = p_filter->p_sys = malloc( sizeof(filter_sys_t) );
314     if( p_sys == NULL )
315     {
316         msg_Err( p_filter, "out of memory" );
317         return -1;
318     }
319     p_sys->i_reject_count = 0;
320
321     p_filter->pf_audio_filter = Convert;
322
323     /* Initialize libmad */
324     mad_stream_init( &p_sys->mad_stream );
325     mad_frame_init( &p_sys->mad_frame );
326     mad_synth_init( &p_sys->mad_synth );
327     mad_stream_options( &p_sys->mad_stream, MAD_OPTION_IGNORECRC );
328
329     if( vlc_CPU() & CPU_CAPABILITY_FPU )
330         p_filter->fmt_out.i_codec = VLC_FOURCC('f','l','3','2');
331     else
332         p_filter->fmt_out.i_codec = VLC_FOURCC('f','i','3','2');
333     p_filter->fmt_out.audio.i_format = p_filter->fmt_out.i_codec;
334
335     p_filter->fmt_out.audio.i_rate = p_filter->fmt_in.audio.i_rate;
336
337     msg_Dbg( p_this, "%4.4s->%4.4s, bits per sample: %i",
338              (char *)&p_filter->fmt_in.i_codec,
339              (char *)&p_filter->fmt_out.i_codec,
340              p_filter->fmt_in.audio.i_bitspersample );
341
342     return 0;
343 }
344
345 /*****************************************************************************
346  * CloseFilter : deallocate data structures
347  *****************************************************************************/
348 static void CloseFilter( vlc_object_t *p_this )
349 {
350     filter_t *p_filter = (filter_t *)p_this;
351     filter_sys_t *p_sys = p_filter->p_sys;
352
353     mad_synth_finish( &p_sys->mad_synth );
354     mad_frame_finish( &p_sys->mad_frame );
355     mad_stream_finish( &p_sys->mad_stream );
356     free( p_sys );
357 }
358
359 static block_t *Convert( filter_t *p_filter, block_t *p_block )
360 {
361     aout_filter_t aout_filter;
362     aout_buffer_t in_buf, out_buf;
363     block_t *p_out;
364     int i_out_size;
365
366     if( !p_block || !p_block->i_samples )
367     {
368         if( p_block ) p_block->pf_release( p_block );
369         return NULL;
370     }
371
372     i_out_size = p_block->i_samples *
373       p_filter->fmt_out.audio.i_bitspersample *
374         p_filter->fmt_out.audio.i_channels / 8;
375
376     p_out = p_filter->pf_audio_buffer_new( p_filter, i_out_size );
377     if( !p_out )
378     {
379         msg_Warn( p_filter, "can't get output buffer" );
380         p_block->pf_release( p_block );
381         return NULL;
382     }
383
384     p_out->i_samples = p_block->i_samples;
385     p_out->i_dts = p_block->i_dts;
386     p_out->i_pts = p_block->i_pts;
387     p_out->i_length = p_block->i_length;
388
389     aout_filter.p_sys = (struct aout_filter_sys_t *)p_filter->p_sys;
390     aout_filter.input = p_filter->fmt_in.audio;
391     aout_filter.input.i_format = p_filter->fmt_in.i_codec;
392     aout_filter.output = p_filter->fmt_out.audio;
393     aout_filter.output.i_format = p_filter->fmt_out.i_codec;
394
395     in_buf.p_buffer = p_block->p_buffer;
396     in_buf.b_discontinuity = VLC_FALSE;
397     in_buf.i_nb_bytes = p_block->i_buffer;
398     in_buf.i_nb_samples = p_block->i_samples;
399     out_buf.p_buffer = p_out->p_buffer;
400     out_buf.i_nb_bytes = p_out->i_buffer;
401     out_buf.i_nb_samples = p_out->i_samples;
402
403     DoWork( (aout_instance_t *)p_filter, &aout_filter, &in_buf, &out_buf );
404
405     p_block->pf_release( p_block );
406
407     p_out->i_buffer = out_buf.i_nb_bytes;
408     p_out->i_samples = out_buf.i_nb_samples;
409
410     return p_out;
411 }