]> git.sesse.net Git - vlc/blob - plugins/ac3_spdif/ac3_spdif.c
* Backported the DecoderError() patch.
[vlc] / plugins / ac3_spdif / ac3_spdif.c
1 /*****************************************************************************
2  * ac3_spdif.c: ac3 pass-through to external decoder with enabled soundcard
3  *****************************************************************************
4  * Copyright (C) 2001 VideoLAN
5  * $Id: ac3_spdif.c,v 1.5.2.1 2001/12/30 06:06:00 sam Exp $
6  *
7  * Authors: Stéphane Borel <stef@via.ecp.fr>
8  *          Juha Yrjola <jyrjola@cc.hut.fi>
9  *          German Gomez Garcia <german@piraos.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 #define MODULE_NAME ac3_spdif
27 #include "modules_inner.h"
28
29 /*****************************************************************************
30  * Preamble
31  *****************************************************************************/
32 #include "defs.h"
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>                                              /* memcpy() */
37 #include <fcntl.h>
38
39 #ifdef HAVE_UNISTD_H
40 #include <unistd.h>
41 #endif
42
43 #include "config.h"
44 #include "common.h"
45 #include "intf_msg.h"                        /* intf_DbgMsg(), intf_ErrMsg() */
46 #include "threads.h"
47 #include "mtime.h"
48
49 #include "audio_output.h"
50
51 #include "modules.h"
52 #include "modules_export.h"
53
54 #include "stream_control.h"
55 #include "input_ext-dec.h"
56
57 #include "ac3_spdif.h"
58 #include "ac3_iec958.h"
59
60 #define FRAME_NB 8
61
62 /****************************************************************************
63  * Local Prototypes
64  ****************************************************************************/
65 static int  decoder_Probe     ( probedata_t * );
66 static int  decoder_Run       ( decoder_config_t * );
67 static int  InitThread        ( ac3_spdif_thread_t * );
68 static void EndThread         ( ac3_spdif_thread_t * );
69 static void BitstreamCallback ( bit_stream_t *, boolean_t );
70
71 /*****************************************************************************
72  * Capabilities
73  *****************************************************************************/
74 void _M( adec_getfunctions )( function_list_t * p_function_list )
75 {
76     p_function_list->pf_probe = decoder_Probe;
77     p_function_list->functions.dec.pf_run = decoder_Run;
78 }
79
80 /*****************************************************************************
81  * Build configuration tree.
82  *****************************************************************************/
83 MODULE_CONFIG_START
84 ADD_WINDOW( "Configuration for ac3 spdif decoder module" )
85     ADD_COMMENT( "Nothing to configure" )
86 MODULE_CONFIG_STOP
87
88 MODULE_INIT_START
89     p_module->i_capabilities = MODULE_CAPABILITY_DEC;
90     p_module->psz_longname = "Ac3 SPDIF decoder for AC3 pass-through";
91 MODULE_INIT_STOP
92
93 MODULE_ACTIVATE_START
94     _M( adec_getfunctions )( &p_module->p_functions->dec );
95 MODULE_ACTIVATE_STOP
96
97 MODULE_DEACTIVATE_START
98 MODULE_DEACTIVATE_STOP
99
100 /*****************************************************************************
101  * decoder_Probe: probe the decoder and return score
102  *****************************************************************************
103  * Tries to launch a decoder and return score so that the interface is able 
104  * to chose.
105  *****************************************************************************/
106 static int decoder_Probe( probedata_t *p_data )
107 {
108     if( main_GetIntVariable( AOUT_SPDIF_VAR, 0 ) && 
109         p_data->i_type == AC3_AUDIO_ES )
110         return( 100 );
111     else
112         return( 0 );
113 }
114
115
116 /****************************************************************************
117  * decoder_Run: the whole thing
118  ****************************************************************************
119  * This function is called just after the thread is launched.
120  ****************************************************************************/
121 static int decoder_Run( decoder_config_t * p_config )
122 {
123     ac3_spdif_thread_t *   p_spdif;
124     mtime_t     i_frame_time;
125     boolean_t   b_sync;
126     /* PTS of the current frame */
127     mtime_t     i_current_pts = 0;
128
129     intf_DbgMsg( "spdif debug: ac3_spdif thread created, initializing." );
130
131     /* Allocate the memory needed to store the thread's structure */
132     p_spdif = malloc( sizeof(ac3_spdif_thread_t) );
133
134     if( p_spdif == NULL )
135     {
136         intf_ErrMsg ( "spdif error: not enough memory "
137                       "for spdif_CreateThread() to create the new thread");
138         DecoderError( p_config->p_decoder_fifo );
139         return( -1 );
140     }
141   
142     p_spdif->p_config = p_config; 
143     
144     if (InitThread( p_spdif ) )
145     {
146         intf_ErrMsg( "spdif error: could not initialize thread" );
147         DecoderError( p_config->p_decoder_fifo );
148         free( p_spdif );
149         return( -1 );
150     }
151
152     /* Compute the theorical duration of an ac3 frame */
153     i_frame_time = 1000000 * AC3_FRAME_SIZE /
154                              p_spdif->ac3_info.i_sample_rate;
155     
156     intf_DbgMsg( "spdif debug: ac3_spdif thread (%p) initialized", p_spdif );
157
158     while( !p_spdif->p_fifo->b_die && !p_spdif->p_fifo->b_error )
159     {
160         /* Handle the dates */
161         if( p_spdif->i_real_pts )
162         {
163             mtime_t     i_delta = p_spdif->i_real_pts - i_current_pts -
164                                   i_frame_time;
165             if( i_delta > i_frame_time || i_delta < -i_frame_time )
166             {
167                 intf_WarnMsg( 3, "spdif warning: date discontinuity (%d)",
168                               i_delta );
169             }
170             i_current_pts = p_spdif->i_real_pts;
171             p_spdif->i_real_pts = 0;
172         }
173         else
174         {
175             i_current_pts += i_frame_time;
176         }
177
178         /* if we're late here the output won't have to play the frame */
179         if( i_current_pts > mdate() )
180         {
181             p_spdif->p_aout_fifo->date[p_spdif->p_aout_fifo->l_end_frame] =
182                 i_current_pts;
183     
184             /* Write in the first free packet of aout fifo */
185             p_spdif->p_iec = ((u8*)(p_spdif->p_aout_fifo->buffer) + 
186                 (p_spdif->p_aout_fifo->l_end_frame * SPDIF_FRAME_SIZE ));
187     
188             /* Build burst to be sent to hardware decoder */
189             ac3_iec958_build_burst( p_spdif );
190     
191             vlc_mutex_lock (&p_spdif->p_aout_fifo->data_lock);
192             p_spdif->p_aout_fifo->l_end_frame = 
193                     (p_spdif->p_aout_fifo->l_end_frame + 1 ) & AOUT_FIFO_SIZE;
194             vlc_mutex_unlock (&p_spdif->p_aout_fifo->data_lock);
195         }
196
197         /* Find syncword again in case of stream discontinuity */
198         /* Here we have p_spdif->i_pts == 0
199          * Therefore a non-zero value after a call to GetBits() means the PES
200          * has changed. */
201         b_sync = 0;
202         while( !b_sync )
203         {
204             while( GetBits( &p_spdif->bit_stream, 8 ) != 0x0b );
205             p_spdif->i_real_pts = p_spdif->i_pts;
206             p_spdif->i_pts = 0;
207             b_sync = ( ShowBits( &p_spdif->bit_stream, 8 ) == 0x77 );
208         }
209         RemoveBits( &p_spdif->bit_stream, 8 );
210
211         /* Read data from bitstream */
212         GetChunk( &p_spdif->bit_stream, p_spdif->p_ac3 + 2,
213                   p_spdif->ac3_info.i_frame_size - 2 );
214     }
215
216     /* If b_error is set, the ac3 spdif thread enters the error loop */
217     if( p_spdif->p_fifo->b_error )
218     {
219         DecoderError( p_spdif->p_fifo );
220     }
221
222     /* End of the ac3 decoder thread */
223     EndThread( p_spdif );
224     
225     return( 0 );
226 }
227
228 /****************************************************************************
229  * InitThread: initialize thread data and create output fifo
230  ****************************************************************************/
231 static int InitThread( ac3_spdif_thread_t * p_spdif )
232 {
233     boolean_t b_sync = 0;
234
235     /* Temporary buffer to store ac3 frames to be transformed */
236     p_spdif->p_ac3 = malloc( SPDIF_FRAME_SIZE );
237
238     if( p_spdif->p_ac3 == NULL )
239     {
240         free( p_spdif->p_ac3 );
241         return( -1 );
242     }
243
244     /*
245      * Initialize the thread properties
246      */
247     p_spdif->p_fifo = p_spdif->p_config->p_decoder_fifo;
248
249     p_spdif->p_config->pf_init_bit_stream(
250             &p_spdif->bit_stream,
251             p_spdif->p_config->p_decoder_fifo,
252             BitstreamCallback, (void*)p_spdif );
253
254     /* Creating the audio output fifo */
255     p_spdif->p_aout_fifo = aout_CreateFifo( AOUT_ADEC_SPDIF_FIFO, 1, 48000, 0,
256                                             SPDIF_FRAME_SIZE, NULL );
257
258     if( p_spdif->p_aout_fifo == NULL )
259     {
260         return( -1 );
261     }
262
263     intf_WarnMsg( 3, "spdif: aout fifo #%d created",
264                      p_spdif->p_aout_fifo->i_fifo );
265
266     /* Sync word */
267     p_spdif->p_ac3[0] = 0x0b;
268     p_spdif->p_ac3[1] = 0x77;
269
270     /* Find syncword */
271     while( !b_sync )
272     {
273         while( GetBits( &p_spdif->bit_stream, 8 ) != 0x0b );
274         p_spdif->i_real_pts = p_spdif->i_pts;
275         p_spdif->i_pts = 0;
276         b_sync = ( ShowBits( &p_spdif->bit_stream, 8 ) == 0x77 );
277     }
278     RemoveBits( &p_spdif->bit_stream, 8 );
279
280     /* Check stream properties */
281     if( ac3_iec958_parse_syncinfo( p_spdif ) < 0 )
282     {
283         intf_ErrMsg( "spdif error: stream not valid");
284
285         aout_DestroyFifo( p_spdif->p_aout_fifo );
286         return( -1 );
287     }
288
289     /* Check that we can handle the rate 
290      * FIXME: we should check that we have the same rate for all fifos 
291      * but all rates should be supported by the decoder (32, 44.1, 48) */
292     if( p_spdif->ac3_info.i_sample_rate != 48000 )
293     {
294         intf_ErrMsg( "spdif error: Only 48000 Hz streams supported");
295
296         aout_DestroyFifo( p_spdif->p_aout_fifo );
297         return -1;
298     }
299     p_spdif->p_aout_fifo->l_rate = p_spdif->ac3_info.i_sample_rate;
300
301     GetChunk( &p_spdif->bit_stream, p_spdif->p_ac3 + sizeof(sync_frame_t),
302         p_spdif->ac3_info.i_frame_size - sizeof(sync_frame_t) );
303
304     return( 0 );
305 }
306
307 /*****************************************************************************
308  * EndThread : ac3 spdif thread destruction
309  *****************************************************************************/
310 static void EndThread( ac3_spdif_thread_t * p_spdif )
311 {
312     intf_DbgMsg( "spdif debug: destroying thread %p", p_spdif );
313
314     /* If the audio output fifo was created, we destroy it */
315     if( p_spdif->p_aout_fifo != NULL )
316     {
317         aout_DestroyFifo( p_spdif->p_aout_fifo );
318
319         /* Make sure the output thread leaves the NextFrame() function */
320         vlc_mutex_lock( &(p_spdif->p_aout_fifo->data_lock ) );
321         vlc_cond_signal( &(p_spdif->p_aout_fifo->data_wait ) );
322         vlc_mutex_unlock( &(p_spdif->p_aout_fifo->data_lock ) );
323         
324     }
325
326     /* Destroy descriptor */
327     free( p_spdif->p_ac3 );
328     free( p_spdif );
329     
330     intf_DbgMsg ("spdif debug: thread %p destroyed", p_spdif );
331 }
332
333 /*****************************************************************************
334  * BitstreamCallback: Import parameters from the new data/PES packet
335  *****************************************************************************
336  * This function is called by input's NextDataPacket.
337  *****************************************************************************/
338 static void BitstreamCallback ( bit_stream_t * p_bit_stream,
339                                         boolean_t b_new_pes)
340 {
341     ac3_spdif_thread_t *    p_spdif;
342
343     if( b_new_pes )
344     {
345         p_spdif = (ac3_spdif_thread_t *)p_bit_stream->p_callback_arg;
346
347         p_bit_stream->p_byte += 3;
348
349         p_spdif->i_pts =
350             DECODER_FIFO_START( *p_bit_stream->p_decoder_fifo )->i_pts;
351         DECODER_FIFO_START( *p_bit_stream->p_decoder_fifo )->i_pts = 0;
352     }
353 }