Added compiler and link flags to --enable-opie (not tested).
[vlc.git] / modules / codec / a52old / a52old.c
1 /*****************************************************************************
2  * a52old.c: A52 decoder module main file
3  *****************************************************************************
4  * Copyright (C) 1999-2001 VideoLAN
5  * $Id: a52old.c,v 1.6 2002/08/30 22:22:24 massiot Exp $
6  *
7  * Authors: Michel Lespinasse <walken@zoy.org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  * 
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <stdlib.h>                                      /* malloc(), free() */
28 #include <string.h>                                              /* memset() */
29
30 #include <vlc/vlc.h>
31 #include <vlc/aout.h>
32 #include <vlc/decoder.h>
33
34 #include "aout_internal.h"
35
36 #ifdef HAVE_UNISTD_H
37 #   include <unistd.h>                                           /* getpid() */
38 #endif
39
40 #include "imdct.h"
41 #include "downmix.h"
42 #include "adec.h"
43
44 #define A52DEC_FRAME_SIZE 1536
45
46 /*****************************************************************************
47  * Local prototypes
48  *****************************************************************************/
49 static int  OpenDecoder       ( vlc_object_t * );
50 static int  RunDecoder        ( decoder_fifo_t * );
51 static int  InitThread        ( a52dec_t * );
52 static void EndThread         ( a52dec_t * );
53 static void BitstreamCallback ( bit_stream_t *, vlc_bool_t );
54
55 /*****************************************************************************
56  * Module descriptor
57  *****************************************************************************/
58 vlc_module_begin();
59     add_category_hint( N_("Miscellaneous"), NULL );
60     add_module  ( "a52-downmix", "downmix", NULL, NULL,
61                   N_("A52 downmix module"), NULL );
62     add_module  ( "a52-imdct", "imdct", NULL, NULL,
63                   N_("A52 IMDCT module"), NULL );
64     set_description( _("software A52 decoder") );
65     set_capability( "decoder", 50 );
66     set_callbacks( OpenDecoder, NULL );
67     add_shortcut( "a52" );
68 vlc_module_end();         
69
70 /*****************************************************************************
71  * OpenDecoder: probe the decoder and return score
72  *****************************************************************************
73  * Tries to launch a decoder and return score so that the interface is able 
74  * to chose.
75  *****************************************************************************/
76 static int OpenDecoder( vlc_object_t *p_this )
77 {
78     decoder_fifo_t *p_fifo = (decoder_fifo_t*) p_this;
79     
80     if( p_fifo->i_fourcc != VLC_FOURCC('a','5','2',' ')
81          && p_fifo->i_fourcc != VLC_FOURCC('a','5','2','b') )
82     {   
83         return VLC_EGENERIC;
84     }
85
86     p_fifo->pf_run = RunDecoder;
87     return VLC_SUCCESS;
88 }
89
90 /*****************************************************************************
91  * RunDecoder: this function is called just after the thread is created
92  *****************************************************************************/
93 static int RunDecoder( decoder_fifo_t *p_fifo )
94 {
95     a52dec_t *   p_a52dec;
96     void *       p_orig;                          /* pointer before memalign */
97     vlc_bool_t   b_sync = 0;
98
99     mtime_t i_pts = 0;
100     aout_buffer_t *p_aout_buffer;
101     audio_sample_format_t output_format;
102     audio_date_t end_date;
103
104     /* Allocate the memory needed to store the thread's structure */
105     p_a52dec = (a52dec_t *)vlc_memalign( &p_orig, 16, sizeof(a52dec_t) );
106     memset( p_a52dec, 0, sizeof( a52dec_t ) );
107
108     if( p_a52dec == NULL )
109     {
110         msg_Err( p_fifo, "out of memory" );
111         DecoderError( p_fifo );
112         return( -1 );
113     }
114
115     /*
116      * Initialize the thread properties
117      */
118     p_a52dec->p_fifo = p_fifo;
119     if( InitThread( p_a52dec ) )
120     {
121         msg_Err( p_fifo, "could not initialize thread" );
122         DecoderError( p_fifo );
123         free( p_orig );
124         return( -1 );
125     }
126
127     /* A52 decoder thread's main loop */
128     /* FIXME : do we have enough room to store the decoded frames ?? */
129     while ((!p_a52dec->p_fifo->b_die) && (!p_a52dec->p_fifo->b_error))
130     {
131         sync_info_t sync_info;
132
133         if( !b_sync )
134         {
135              int i_sync_ptr;
136 #define p_bit_stream (&p_a52dec->bit_stream)
137
138              /* Go to the next PES packet and jump to sync_ptr */
139              do {
140                 BitstreamNextDataPacket( p_bit_stream );
141              } while( !p_bit_stream->p_decoder_fifo->b_die
142                        && !p_bit_stream->p_decoder_fifo->b_error
143                        && p_bit_stream->p_data !=
144                           p_bit_stream->p_decoder_fifo->p_first->p_first );
145              i_sync_ptr = *(p_bit_stream->p_byte - 2) << 8
146                             | *(p_bit_stream->p_byte - 1);
147              p_bit_stream->p_byte += i_sync_ptr;
148
149              /* Empty the bit FIFO and realign the bit stream */
150              p_bit_stream->fifo.buffer = 0;
151              p_bit_stream->fifo.i_available = 0;
152              AlignWord( p_bit_stream );
153              b_sync = 1;
154 #undef p_bit_stream
155         }
156
157         if (sync_frame (p_a52dec, &sync_info))
158         {
159             b_sync = 0;
160             continue;
161         }
162
163         if( ( p_a52dec->p_aout_input == NULL )||
164             ( output_format.i_rate != sync_info.sample_rate ) )
165         {
166             if( p_a52dec->p_aout_input )
167             {
168                 /* Delete old output */
169                 msg_Warn( p_a52dec->p_fifo, "opening a new aout" );
170                 aout_InputDelete( p_a52dec->p_aout, p_a52dec->p_aout_input );
171             }
172
173             /* Set output configuration */
174             output_format.i_format   = AOUT_FMT_S16_NE;
175             output_format.i_channels = 2; /* FIXME ! */
176             output_format.i_rate     = sync_info.sample_rate;
177             aout_DateInit( &end_date, output_format.i_rate );
178             p_a52dec->p_aout_input = aout_InputNew( p_a52dec->p_fifo,
179                                                     &p_a52dec->p_aout,
180                                                     &output_format );
181         }
182
183         if( p_a52dec->p_aout_input == NULL )
184         {
185             msg_Err( p_a52dec->p_fifo, "failed to create aout fifo" );
186             p_a52dec->p_fifo->b_error = 1;
187             continue;
188         }
189
190         NextPTS( &p_a52dec->bit_stream, &i_pts, NULL );
191         if( i_pts != 0 && i_pts != aout_DateGet( &end_date ) )
192         {
193             aout_DateSet( &end_date, i_pts );
194         }
195
196         if( !aout_DateGet( &end_date ) )
197         {
198             continue;
199         }
200
201         p_aout_buffer = aout_BufferNew( p_a52dec->p_aout,
202                                         p_a52dec->p_aout_input,
203                                         A52DEC_FRAME_SIZE );
204         if( !p_aout_buffer )
205         {
206             msg_Err( p_a52dec->p_fifo, "cannot get aout buffer" );
207             p_a52dec->p_fifo->b_error = 1;
208             continue;
209         }
210
211         p_aout_buffer->start_date = aout_DateGet( &end_date );
212         p_aout_buffer->end_date = aout_DateIncrement( &end_date,
213                                                       A52DEC_FRAME_SIZE );
214
215         if (decode_frame (p_a52dec, (s16*)p_aout_buffer->p_buffer))
216         {
217             b_sync = 0;
218             aout_BufferDelete( p_a52dec->p_aout, p_a52dec->p_aout_input,
219                                                  p_aout_buffer );
220             continue;
221         }
222         else
223         {
224             aout_BufferPlay( p_a52dec->p_aout, p_a52dec->p_aout_input,
225                                                p_aout_buffer );
226         }
227
228         RealignBits(&p_a52dec->bit_stream);
229     }
230
231     /* If b_error is set, the A52 decoder thread enters the error loop */
232     if (p_a52dec->p_fifo->b_error)
233     {
234         DecoderError( p_a52dec->p_fifo );
235     }
236
237     /* End of the A52 decoder thread */
238     EndThread (p_a52dec);
239
240     free( p_orig );
241
242     return( 0 );
243 }
244
245 /*****************************************************************************
246  * InitThread: initialize data before entering main loop
247  *****************************************************************************/
248 static int InitThread( a52dec_t * p_a52dec )
249 {
250     /*
251      * Choose the best downmix module
252      */
253     p_a52dec->p_downmix = vlc_object_create( p_a52dec->p_fifo,
254                                              sizeof( downmix_t ) );
255     p_a52dec->p_downmix->psz_object_name = "downmix";
256
257     p_a52dec->p_downmix->p_module =
258                 module_Need( p_a52dec->p_downmix, "downmix", "$a52-downmix" );
259
260     if( p_a52dec->p_downmix->p_module == NULL )
261     {
262         msg_Err( p_a52dec->p_fifo, "no suitable downmix module" );
263         vlc_object_destroy( p_a52dec->p_downmix );
264         return( -1 );
265     }
266
267     /*
268      * Choose the best IMDCT module
269      */
270     p_a52dec->p_imdct = vlc_object_create( p_a52dec->p_fifo,
271                                            sizeof( imdct_t ) );
272     
273 #define IMDCT p_a52dec->p_imdct
274     p_a52dec->p_imdct->p_module =
275                    module_Need( p_a52dec->p_imdct, "imdct", "$a52-imdct" );
276
277     if( p_a52dec->p_imdct->p_module == NULL )
278     {
279         msg_Err( p_a52dec->p_fifo, "no suitable IMDCT module" );
280         vlc_object_destroy( p_a52dec->p_imdct );
281         module_Unneed( p_a52dec->p_downmix, p_a52dec->p_downmix->p_module );
282         vlc_object_destroy( p_a52dec->p_downmix );
283         return( -1 );
284     }
285
286     /* Initialize the A52 decoder structures */
287     p_a52dec->samples = vlc_memalign( &p_a52dec->samples_orig,
288                                       16, 6 * 256 * sizeof(float) );
289
290     IMDCT->buf    = vlc_memalign( &IMDCT->buf_orig,
291                                   16, N/4 * sizeof(complex_t) );
292     IMDCT->delay  = vlc_memalign( &IMDCT->delay_orig,
293                                   16, 6 * 256 * sizeof(float) );
294     IMDCT->delay1 = vlc_memalign( &IMDCT->delay1_orig,
295                                   16, 6 * 256 * sizeof(float) );
296     IMDCT->xcos1  = vlc_memalign( &IMDCT->xcos1_orig,
297                                   16, N/4 * sizeof(float) );
298     IMDCT->xsin1  = vlc_memalign( &IMDCT->xsin1_orig,
299                                   16, N/4 * sizeof(float) );
300     IMDCT->xcos2  = vlc_memalign( &IMDCT->xcos2_orig,
301                                   16, N/8 * sizeof(float) );
302     IMDCT->xsin2  = vlc_memalign( &IMDCT->xsin2_orig,
303                                   16, N/8 * sizeof(float) );
304     IMDCT->xcos_sin_sse = vlc_memalign( &IMDCT->xcos_sin_sse_orig,
305                                         16, 128 * 4 * sizeof(float) );
306     IMDCT->w_1    = vlc_memalign( &IMDCT->w_1_orig,
307                                   16, 1  * sizeof(complex_t) );
308     IMDCT->w_2    = vlc_memalign( &IMDCT->w_2_orig,
309                                   16, 2  * sizeof(complex_t) );
310     IMDCT->w_4    = vlc_memalign( &IMDCT->w_4_orig,
311                                   16, 4  * sizeof(complex_t) );
312     IMDCT->w_8    = vlc_memalign( &IMDCT->w_8_orig,
313                                   16, 8  * sizeof(complex_t) );
314     IMDCT->w_16   = vlc_memalign( &IMDCT->w_16_orig,
315                                   16, 16 * sizeof(complex_t) );
316     IMDCT->w_32   = vlc_memalign( &IMDCT->w_32_orig,
317                                   16, 32 * sizeof(complex_t) );
318     IMDCT->w_64   = vlc_memalign( &IMDCT->w_64_orig,
319                                   16, 64 * sizeof(complex_t) );
320 #undef IMDCT
321
322     E_( a52_init )( p_a52dec );
323
324     /*
325      * Initialize the output properties
326      */
327     p_a52dec->p_aout = NULL;
328     p_a52dec->p_aout_input = NULL;
329
330     /*
331      * Bit stream
332      */
333     InitBitstream( &p_a52dec->bit_stream, p_a52dec->p_fifo,
334                    BitstreamCallback, (void *) p_a52dec );
335     
336     return( 0 );
337 }
338
339 /*****************************************************************************
340  * EndThread : A52 decoder thread destruction
341  *****************************************************************************/
342 static void EndThread (a52dec_t * p_a52dec)
343 {
344     /* If the audio output fifo was created, we destroy it */
345     if( p_a52dec->p_aout_input )
346     {
347         aout_InputDelete( p_a52dec->p_aout, p_a52dec->p_aout_input );
348     }
349
350     /* Free allocated structures */
351 #define IMDCT p_a52dec->p_imdct
352     free( IMDCT->w_1_orig );
353     free( IMDCT->w_64_orig );
354     free( IMDCT->w_32_orig );
355     free( IMDCT->w_16_orig );
356     free( IMDCT->w_8_orig );
357     free( IMDCT->w_4_orig );
358     free( IMDCT->w_2_orig );
359     free( IMDCT->xcos_sin_sse_orig );
360     free( IMDCT->xsin2_orig );
361     free( IMDCT->xcos2_orig );
362     free( IMDCT->xsin1_orig );
363     free( IMDCT->xcos1_orig );
364     free( IMDCT->delay1_orig );
365     free( IMDCT->delay_orig );
366     free( IMDCT->buf_orig );
367 #undef IMDCT
368
369     free( p_a52dec->samples_orig );
370
371     /* Unlock the modules */
372     module_Unneed( p_a52dec->p_downmix, p_a52dec->p_downmix->p_module );
373     vlc_object_destroy( p_a52dec->p_downmix );
374
375     module_Unneed( p_a52dec->p_imdct, p_a52dec->p_imdct->p_module );
376     vlc_object_destroy( p_a52dec->p_imdct );
377
378     /* Free what's left of the decoder */
379     free( p_a52dec->imdct_orig );
380 }
381
382 /*****************************************************************************
383  * BitstreamCallback: Import parameters from the new data/PES packet
384  *****************************************************************************
385  * This function is called by input's NextDataPacket.
386  *****************************************************************************/
387 static void BitstreamCallback ( bit_stream_t * p_bit_stream,
388                                 vlc_bool_t b_new_pes )
389 {
390     if( b_new_pes )
391     {
392         /* Drop special A52 header */
393 /*        p_bit_stream->p_byte += 3; */
394     }
395 }
396