]> git.sesse.net Git - vlc/blob - plugins/a52/a52.c
video output has better handling of settings. it remembers flags like fullscreen...
[vlc] / plugins / a52 / a52.c
1 /*****************************************************************************
2  * a52.c: ATSC A/52 aka AC-3 decoder plugin for vlc.
3  *   This plugin makes use of liba52 to decode A/52 audio
4  *   (http://liba52.sf.net/).
5  *****************************************************************************
6  * Copyright (C) 2001 VideoLAN
7  * $Id: a52.c,v 1.14.2.3 2002/09/25 23:11:51 massiot Exp $
8  *
9  * Authors: Gildas Bazin <gbazin@netcourrier.com>
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., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
24  *****************************************************************************/
25
26 /*****************************************************************************
27  * Preamble
28  *****************************************************************************/
29 #include <stdlib.h>                                      /* malloc(), free() */
30 #include <string.h>                                              /* strdup() */
31
32 #include <videolan/vlc.h>
33
34 #ifdef HAVE_STDINT_H
35 #   include <stdint.h>                                         /* int16_t .. */
36 #elif HAVE_INTTYPES_H
37 #   include <inttypes.h>                                       /* int16_t .. */
38 #endif
39
40 #include "audio_output.h"
41
42 #include "stream_control.h"
43 #include "input_ext-dec.h"
44
45 #ifdef USE_A52DEC_TREE                                 /* liba52 header file */
46 #include "include/a52.h"
47 #else
48 #include "a52dec/a52.h"
49 #endif
50
51 #include "a52.h"
52
53 #define AC3DEC_FRAME_SIZE 1536 
54
55 /*****************************************************************************
56  * Local prototypes
57  *****************************************************************************/
58 static int  decoder_Probe  ( u8 * );
59 static int  decoder_Run    ( decoder_config_t * );
60 static int  DecodeFrame    ( a52_adec_thread_t * );
61 static int  InitThread     ( a52_adec_thread_t * );
62 static void EndThread      ( a52_adec_thread_t * );
63
64 static void               BitstreamCallback ( bit_stream_t *, boolean_t );
65 static void               float2s16_2       ( float *, int16_t * );
66 static inline int16_t     convert   ( int32_t );
67
68 /*****************************************************************************
69  * Capabilities
70  *****************************************************************************/
71 void _M( adec_getfunctions )( function_list_t * p_function_list )
72 {
73     p_function_list->functions.dec.pf_probe = decoder_Probe;
74     p_function_list->functions.dec.pf_run   = decoder_Run;
75 }
76
77 /*****************************************************************************
78  * Build configuration structure.
79  *****************************************************************************/
80 #define DYNRNG_TEXT N_("A/52 dynamic range compression")
81 #define DYNRNG_LONGTEXT N_( \
82     "Dynamic range compression makes the loud sounds softer, and the soft " \
83     "sounds louder, so you can more easily listen to the stream in a noisy " \
84     "environment without disturbing anyone.\nIf you disable the dynamic range"\
85     " compression the playback will be more adapted to a movie theater or a " \
86     "listening room.")
87
88 MODULE_CONFIG_START
89 ADD_CATEGORY_HINT( N_("Miscellaneous"), NULL )
90 ADD_BOOL    ( "a52-dynrng", 1, NULL, DYNRNG_TEXT, DYNRNG_LONGTEXT )
91 MODULE_CONFIG_STOP
92
93 MODULE_INIT_START
94     SET_DESCRIPTION( _("a52 ATSC A/52 aka AC-3 audio decoder module") )
95     ADD_CAPABILITY( DECODER, 40 )
96     ADD_SHORTCUT( "a52" )
97 MODULE_INIT_STOP
98
99 MODULE_ACTIVATE_START
100     _M( adec_getfunctions )( &p_module->p_functions->dec );
101 MODULE_ACTIVATE_STOP
102
103 MODULE_DEACTIVATE_START
104 MODULE_DEACTIVATE_STOP
105
106 /*****************************************************************************
107  * decoder_Probe: probe the decoder and return score
108  *****************************************************************************
109  * Tries to launch a decoder and return score so that the interface is able
110  * to choose.
111  *****************************************************************************/
112 static int decoder_Probe( u8 *pi_type )
113 {
114     return ( (*pi_type == AC3_AUDIO_ES || *pi_type == A52B_AUDIO_ES) ? 0 : -1 );
115 }
116
117 /*****************************************************************************
118  * decoder_Run: this function is called just after the thread is created
119  *****************************************************************************/
120 static int decoder_Run ( decoder_config_t *p_config )
121 {
122     a52_adec_thread_t *p_a52_adec;
123
124     /* Allocate the memory needed to store the thread's structure */
125     p_a52_adec =
126         (a52_adec_thread_t *)malloc( sizeof(a52_adec_thread_t) );
127     if (p_a52_adec == NULL)
128     {
129         intf_ErrMsg ( "a52 error: not enough memory "
130                       "for decoder_Run() to allocate p_a52_adec" );
131         DecoderError( p_config->p_decoder_fifo );
132         return( -1 );
133     }
134
135     /* FIXME */
136     p_a52_adec->i_channels = 2;
137
138     /*
139      * Initialize the thread properties
140      */
141     p_a52_adec->p_aout_fifo = NULL;
142     p_a52_adec->p_config = p_config;
143     p_a52_adec->p_fifo = p_a52_adec->p_config->p_decoder_fifo;
144     if( InitThread( p_a52_adec ) )
145     {
146         intf_ErrMsg( "a52 error: could not initialize thread" );
147         DecoderError( p_config->p_decoder_fifo );
148         free( p_a52_adec );
149         return( -1 );
150     }
151
152     /* liba52 decoder thread's main loop */
153     while( !p_a52_adec->p_fifo->b_die && !p_a52_adec->p_fifo->b_error )
154     {
155
156         /* look for sync word - should be 0x0b77 */
157         RealignBits(&p_a52_adec->bit_stream);
158         while( (ShowBits( &p_a52_adec->bit_stream, 16 ) ) != 0x0b77 && 
159                (!p_a52_adec->p_fifo->b_die) && (!p_a52_adec->p_fifo->b_error))
160         {
161             RemoveBits( &p_a52_adec->bit_stream, 8 );
162         }
163
164         /* get a52 frame header */
165         GetChunk( &p_a52_adec->bit_stream, p_a52_adec->p_frame_buffer, 7 );
166         if( p_a52_adec->p_fifo->b_die ) break;
167
168         /* check if frame is valid and get frame info */
169         p_a52_adec->frame_size = a52_syncinfo( p_a52_adec->p_frame_buffer,
170                                                &p_a52_adec->flags,
171                                                &p_a52_adec->sample_rate,
172                                                &p_a52_adec->bit_rate );
173
174         if( !p_a52_adec->frame_size )
175         {
176             intf_WarnMsg( 3, "a52: a52_syncinfo failed" );
177             continue;
178         }
179
180         if( DecodeFrame( p_a52_adec ) && !p_a52_adec->p_fifo->b_die )
181         {
182             DecoderError( p_config->p_decoder_fifo );
183             free( p_a52_adec );
184             return( -1 );
185         }
186
187     }
188
189     /* If b_error is set, the decoder thread enters the error loop */
190     if( p_a52_adec->p_fifo->b_error )
191     {
192         DecoderError( p_a52_adec->p_fifo );
193     }
194
195     /* End of the liba52 decoder thread */
196     EndThread( p_a52_adec );
197
198     return( 0 );
199 }
200
201 /*****************************************************************************
202  * InitThread: initialize data before entering main loop
203  *****************************************************************************/
204 static int InitThread( a52_adec_thread_t * p_a52_adec )
205 {
206     intf_WarnMsg( 3, "a52: InitThread" );
207
208     /* Initialize liba52 */
209     p_a52_adec->p_a52_state = a52_init( 0 );
210     if( p_a52_adec->p_a52_state == NULL )
211     {
212         intf_ErrMsg ( "a52 error: InitThread() unable to initialize "
213                       "liba52" );
214         return -1;
215     }
216
217     p_a52_adec->b_dynrng = config_GetIntVariable( "a52-dynrng" );
218
219     /* Init the BitStream */
220     InitBitstream( &p_a52_adec->bit_stream,
221                    p_a52_adec->p_fifo,
222                    BitstreamCallback, NULL );
223
224     return( 0 );
225 }
226
227 /*****************************************************************************
228  * DecodeFrame: decodes an ATSC A/52 frame.
229  *****************************************************************************/
230 static int DecodeFrame( a52_adec_thread_t * p_a52_adec )
231 {
232     sample_t sample_level = 1;
233     byte_t   *p_buffer;
234     int i;
235
236     if( ( p_a52_adec->p_aout_fifo != NULL ) &&
237         ( p_a52_adec->p_aout_fifo->i_rate != p_a52_adec->sample_rate ) )
238     {
239         /* Make sure the output thread leaves the NextFrame() function */
240         vlc_mutex_lock (&(p_a52_adec->p_aout_fifo->data_lock));
241         aout_DestroyFifo (p_a52_adec->p_aout_fifo);
242         vlc_cond_signal (&(p_a52_adec->p_aout_fifo->data_wait));
243         vlc_mutex_unlock (&(p_a52_adec->p_aout_fifo->data_lock));
244
245         p_a52_adec->p_aout_fifo = NULL;
246     }
247
248     /* Creating the audio output fifo if not created yet */
249     if( p_a52_adec->p_aout_fifo == NULL )
250     {
251         p_a52_adec->p_aout_fifo = aout_CreateFifo( AOUT_FIFO_PCM,
252                                     p_a52_adec->i_channels,
253                                     p_a52_adec->sample_rate,
254                                     AC3DEC_FRAME_SIZE * p_a52_adec->i_channels,
255                                     NULL );
256
257         if ( p_a52_adec->p_aout_fifo == NULL )
258         { 
259             return( -1 );
260         }
261     }
262
263     /* Set the Presentation Time Stamp */
264     CurrentPTS( &p_a52_adec->bit_stream,
265                 &p_a52_adec->p_aout_fifo->date[
266                     p_a52_adec->p_aout_fifo->i_end_frame],
267                 NULL );
268
269     if( !p_a52_adec->p_aout_fifo->date[
270             p_a52_adec->p_aout_fifo->i_end_frame] )
271     {
272         p_a52_adec->p_aout_fifo->date[
273             p_a52_adec->p_aout_fifo->i_end_frame] = LAST_MDATE;
274     }
275
276
277
278     p_buffer = ((byte_t *)p_a52_adec->p_aout_fifo->buffer) +
279         ( p_a52_adec->p_aout_fifo->i_end_frame * AC3DEC_FRAME_SIZE *
280           p_a52_adec->i_channels * sizeof(s16) );
281
282     /* FIXME */
283     p_a52_adec->flags = A52_STEREO | A52_ADJUST_LEVEL;
284
285     /* Get the complete frame */
286     GetChunk( &p_a52_adec->bit_stream, p_a52_adec->p_frame_buffer + 7,
287               p_a52_adec->frame_size - 7 );
288     if( p_a52_adec->p_fifo->b_die ) return( -1 );
289
290     /* do the actual decoding now */
291     a52_frame( p_a52_adec->p_a52_state, p_a52_adec->p_frame_buffer,
292                &p_a52_adec->flags, &sample_level, 384 );
293
294     if( !p_a52_adec->b_dynrng )
295         a52_dynrng( p_a52_adec->p_a52_state, NULL, NULL );
296
297     for( i = 0; i < 6; i++ )
298     {
299         if( a52_block( p_a52_adec->p_a52_state ) )
300             intf_WarnMsg( 5, "a52: a52_block failed for block %i", i );
301
302         float2s16_2( a52_samples( p_a52_adec->p_a52_state ),
303                      ((int16_t *)p_buffer) + i * 256 * p_a52_adec->i_channels );
304     }
305
306
307     vlc_mutex_lock( &p_a52_adec->p_aout_fifo->data_lock );
308     p_a52_adec->p_aout_fifo->i_end_frame = 
309       (p_a52_adec->p_aout_fifo->i_end_frame + 1) & AOUT_FIFO_SIZE;
310     vlc_cond_signal (&p_a52_adec->p_aout_fifo->data_wait);
311     vlc_mutex_unlock (&p_a52_adec->p_aout_fifo->data_lock);
312
313     return 0;
314 }
315
316 /*****************************************************************************
317  * EndThread : liba52 decoder thread destruction
318  *****************************************************************************/
319 static void EndThread (a52_adec_thread_t *p_a52_adec)
320 {
321     intf_WarnMsg ( 3, "a52: EndThread" );
322
323     /* If the audio output fifo was created, we destroy it */
324     if (p_a52_adec->p_aout_fifo != NULL)
325     {
326         aout_DestroyFifo (p_a52_adec->p_aout_fifo);
327
328         /* Make sure the output thread leaves the NextFrame() function */
329         vlc_mutex_lock (&(p_a52_adec->p_aout_fifo->data_lock));
330         vlc_cond_signal (&(p_a52_adec->p_aout_fifo->data_wait));
331         vlc_mutex_unlock (&(p_a52_adec->p_aout_fifo->data_lock));
332     }
333
334     a52_free( p_a52_adec->p_a52_state );
335     free( p_a52_adec );
336
337 }
338
339 /*****************************************************************************
340  * float2s16_2 : converts floats to ints using a trick based on the IEEE
341  *               floating-point format
342  *****************************************************************************/
343 static inline int16_t convert (int32_t i)
344 {
345     if (i > 0x43c07fff)
346         return 32767;
347     else if (i < 0x43bf8000)
348         return -32768;
349     else
350         return i - 0x43c00000;
351 }
352
353 static void float2s16_2 (float * _f, int16_t * s16)
354 {
355     int i;
356     int32_t * f = (int32_t *) _f;
357
358     for (i = 0; i < 256; i++) {
359       s16[2*i] = convert (f[i]);
360         s16[2*i+1] = convert (f[i+256]);
361     }
362 }
363
364 /*****************************************************************************
365  * BitstreamCallback: Import parameters from the new data/PES packet
366  *****************************************************************************
367  * This function is called by input's NextDataPacket.
368  *****************************************************************************/
369 static void BitstreamCallback ( bit_stream_t * p_bit_stream,
370                                 boolean_t b_new_pes )
371 {
372     if( b_new_pes )
373     {
374         /* Drop special AC3 header */
375 /*        p_bit_stream->p_byte += 3; */
376     }
377 }