]> git.sesse.net Git - vlc/blob - plugins/ac3_spdif/ac3_spdif.c
* Changed the way decoder_fifo_t works ;
[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.8 2001/12/27 01:49:34 massiot 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 "common.h"
44 #include "intf_msg.h"                        /* intf_DbgMsg(), intf_ErrMsg() */
45 #include "threads.h"
46 #include "mtime.h"
47
48 #include "audio_output.h"
49
50 #include "stream_control.h"
51 #include "input_ext-dec.h"
52
53 #include "ac3_spdif.h"
54 #include "ac3_iec958.h"
55
56 #include "modules.h"
57 #include "modules_export.h"
58
59 #define FRAME_NB 8
60
61 /****************************************************************************
62  * Local Prototypes
63  ****************************************************************************/
64 static int  ac3_spdif_Probe       ( probedata_t * );
65 static int  ac3_spdif_Run         ( decoder_config_t * );
66 static int  ac3_spdif_Init        ( ac3_spdif_thread_t * );
67 static void ac3_spdif_ErrorThread ( ac3_spdif_thread_t * );
68 static void ac3_spdif_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 = ac3_spdif_Probe;
77     p_function_list->functions.dec.pf_run = ac3_spdif_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  * ac3_spdif_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 ac3_spdif_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  * ac3_spdif_Run: the whole thing
118  ****************************************************************************
119  * This function is called just after the thread is launched.
120  ****************************************************************************/
121 static int ac3_spdif_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         return( -1 );
139     }
140   
141     p_spdif->p_config = p_config; 
142     
143     if (ac3_spdif_Init( p_spdif ) )
144     {
145         intf_ErrMsg( "spdif error: could not initialize thread" );
146         return( -1 );
147     }
148
149     /* Compute the theorical duration of an ac3 frame */
150     i_frame_time = 1000000 * AC3_FRAME_SIZE /
151                              p_spdif->ac3_info.i_sample_rate;
152     
153     intf_DbgMsg( "spdif debug: ac3_spdif thread (%p) initialized", p_spdif );
154
155     while( !p_spdif->p_fifo->b_die && !p_spdif->p_fifo->b_error )
156     {
157         /* Handle the dates */
158         if( p_spdif->i_real_pts )
159         {
160             mtime_t     i_delta = p_spdif->i_real_pts - i_current_pts -
161                                   i_frame_time;
162             if( i_delta > i_frame_time || i_delta < -i_frame_time )
163             {
164                 intf_WarnMsg( 3, "spdif warning: date discontinuity (%d)",
165                               i_delta );
166             }
167             i_current_pts = p_spdif->i_real_pts;
168             p_spdif->i_real_pts = 0;
169         }
170         else
171         {
172             i_current_pts += i_frame_time;
173         }
174
175         /* if we're late here the output won't have to play the frame */
176         if( i_current_pts > mdate() )
177         {
178             p_spdif->p_aout_fifo->date[p_spdif->p_aout_fifo->l_end_frame] =
179                 i_current_pts;
180     
181             /* Write in the first free packet of aout fifo */
182             p_spdif->p_iec = ((u8*)(p_spdif->p_aout_fifo->buffer) + 
183                 (p_spdif->p_aout_fifo->l_end_frame * SPDIF_FRAME_SIZE ));
184     
185             /* Build burst to be sent to hardware decoder */
186             ac3_iec958_build_burst( p_spdif );
187     
188             vlc_mutex_lock (&p_spdif->p_aout_fifo->data_lock);
189             p_spdif->p_aout_fifo->l_end_frame = 
190                     (p_spdif->p_aout_fifo->l_end_frame + 1 ) & AOUT_FIFO_SIZE;
191             vlc_mutex_unlock (&p_spdif->p_aout_fifo->data_lock);
192         }
193
194         /* Find syncword again in case of stream discontinuity */
195         /* Here we have p_spdif->i_pts == 0
196          * Therefore a non-zero value after a call to GetBits() means the PES
197          * has changed. */
198         b_sync = 0;
199         while( !b_sync )
200         {
201             while( GetBits( &p_spdif->bit_stream, 8 ) != 0x0b );
202             p_spdif->i_real_pts = p_spdif->i_pts;
203             p_spdif->i_pts = 0;
204             b_sync = ( ShowBits( &p_spdif->bit_stream, 8 ) == 0x77 );
205         }
206         RemoveBits( &p_spdif->bit_stream, 8 );
207
208         /* Read data from bitstream */
209         GetChunk( &p_spdif->bit_stream, p_spdif->p_ac3 + 2,
210                   p_spdif->ac3_info.i_frame_size - 2 );
211     }
212
213     /* If b_error is set, the ac3 spdif thread enters the error loop */
214     if( p_spdif->p_fifo->b_error )
215     {
216         ac3_spdif_ErrorThread( p_spdif );
217     }
218
219     /* End of the ac3 decoder thread */
220     ac3_spdif_EndThread( p_spdif );
221     
222     return( 0 );
223 }
224
225 /****************************************************************************
226  * ac3_spdif_Init: initialize thread data and create output fifo
227  ****************************************************************************/
228 static int ac3_spdif_Init( ac3_spdif_thread_t * p_spdif )
229 {
230     boolean_t b_sync = 0;
231
232     /* Temporary buffer to store ac3 frames to be transformed */
233     p_spdif->p_ac3 = malloc( SPDIF_FRAME_SIZE );
234
235     if( p_spdif->p_ac3 == NULL )
236     {
237         free( p_spdif->p_ac3 );
238         return( -1 );
239     }
240
241     /*
242      * Initialize the thread properties
243      */
244     p_spdif->p_fifo = p_spdif->p_config->p_decoder_fifo;
245
246     p_spdif->p_config->pf_init_bit_stream(
247             &p_spdif->bit_stream,
248             p_spdif->p_config->p_decoder_fifo,
249             BitstreamCallback, (void*)p_spdif );
250
251     /* Creating the audio output fifo */
252     p_spdif->p_aout_fifo = aout_CreateFifo( AOUT_ADEC_SPDIF_FIFO, 1, 48000, 0,
253                                             SPDIF_FRAME_SIZE, NULL );
254
255     if( p_spdif->p_aout_fifo == NULL )
256     {
257         return( -1 );
258     }
259
260     intf_WarnMsg( 3, "spdif: aout fifo #%d created",
261                      p_spdif->p_aout_fifo->i_fifo );
262
263     /* Sync word */
264     p_spdif->p_ac3[0] = 0x0b;
265     p_spdif->p_ac3[1] = 0x77;
266
267     /* Find syncword */
268     while( !b_sync )
269     {
270         while( GetBits( &p_spdif->bit_stream, 8 ) != 0x0b );
271         p_spdif->i_real_pts = p_spdif->i_pts;
272         p_spdif->i_pts = 0;
273         b_sync = ( ShowBits( &p_spdif->bit_stream, 8 ) == 0x77 );
274     }
275     RemoveBits( &p_spdif->bit_stream, 8 );
276
277     /* Check stream properties */
278     if( ac3_iec958_parse_syncinfo( p_spdif ) < 0 )
279     {
280         intf_ErrMsg( "spdif error: stream not valid");
281
282         aout_DestroyFifo( p_spdif->p_aout_fifo );
283         return( -1 );
284     }
285
286     /* Check that we can handle the rate 
287      * FIXME: we should check that we have the same rate for all fifos 
288      * but all rates should be supported by the decoder (32, 44.1, 48) */
289     if( p_spdif->ac3_info.i_sample_rate != 48000 )
290     {
291         intf_ErrMsg( "spdif error: Only 48000 Hz streams supported");
292
293         aout_DestroyFifo( p_spdif->p_aout_fifo );
294         return -1;
295     }
296     p_spdif->p_aout_fifo->l_rate = p_spdif->ac3_info.i_sample_rate;
297
298     GetChunk( &p_spdif->bit_stream, p_spdif->p_ac3 + sizeof(sync_frame_t),
299         p_spdif->ac3_info.i_frame_size - sizeof(sync_frame_t) );
300
301     return( 0 );
302 }
303
304
305 /*****************************************************************************
306  * ac3_spdif_ErrorThread : ac3 spdif's RunThread() error loop
307  *****************************************************************************/
308 static void ac3_spdif_ErrorThread( ac3_spdif_thread_t * p_spdif )
309 {
310     /* We take the lock, because we are going to read/write the start/end
311      * indexes of the decoder fifo */
312     vlc_mutex_lock (&p_spdif->p_fifo->data_lock);
313
314     /* Wait until a `die' order is sent */
315     while( !p_spdif->p_fifo->b_die )
316     {
317         /* Trash all received PES packets */
318         p_spdif->p_fifo->pf_delete_pes(
319                         p_spdif->p_fifo->p_packets_mgt,
320                         p_spdif->p_fifo->p_first );
321
322         /* Waiting for the input thread to put new PES packets in the fifo */
323         vlc_cond_wait( &p_spdif->p_fifo->data_wait,
324                        &p_spdif->p_fifo->data_lock );
325     }
326
327     /* We can release the lock before leaving */
328     vlc_mutex_unlock( &p_spdif->p_fifo->data_lock );
329 }
330
331 /*****************************************************************************
332  * ac3_spdif_EndThread : ac3 spdif thread destruction
333  *****************************************************************************/
334 static void ac3_spdif_EndThread( ac3_spdif_thread_t * p_spdif )
335 {
336     intf_DbgMsg( "spdif debug: destroying thread %p", p_spdif );
337
338     /* If the audio output fifo was created, we destroy it */
339     if( p_spdif->p_aout_fifo != NULL )
340     {
341         aout_DestroyFifo( p_spdif->p_aout_fifo );
342
343         /* Make sure the output thread leaves the NextFrame() function */
344         vlc_mutex_lock( &(p_spdif->p_aout_fifo->data_lock ) );
345         vlc_cond_signal( &(p_spdif->p_aout_fifo->data_wait ) );
346         vlc_mutex_unlock( &(p_spdif->p_aout_fifo->data_lock ) );
347         
348     }
349
350     /* Destroy descriptor */
351     free( p_spdif->p_ac3 );
352     free( p_spdif );
353     
354     intf_DbgMsg ("spdif debug: thread %p destroyed", p_spdif );
355 }
356
357 /*****************************************************************************
358  * BitstreamCallback: Import parameters from the new data/PES packet
359  *****************************************************************************
360  * This function is called by input's NextDataPacket.
361  *****************************************************************************/
362 static void BitstreamCallback ( bit_stream_t * p_bit_stream,
363                                         boolean_t b_new_pes)
364 {
365     ac3_spdif_thread_t *    p_spdif;
366
367     if( b_new_pes )
368     {
369         p_spdif = (ac3_spdif_thread_t *)p_bit_stream->p_callback_arg;
370
371         p_bit_stream->p_byte += 3;
372
373         p_spdif->i_pts =
374             p_bit_stream->p_decoder_fifo->p_first->i_pts;
375         p_bit_stream->p_decoder_fifo->p_first->i_pts = 0;
376     }
377 }