]> git.sesse.net Git - vlc/blob - plugins/ac3_spdif/ac3_spdif.c
466803f419432d4e02922a8564611707082383cd
[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.4 2001/11/28 15:08:05 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 "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  ac3_spdif_Probe       ( probedata_t * );
66 static int  ac3_spdif_Run         ( decoder_config_t * );
67 static int  ac3_spdif_Init        ( ac3_spdif_thread_t * );
68 static void ac3_spdif_ErrorThread ( ac3_spdif_thread_t * );
69 static void ac3_spdif_EndThread   ( ac3_spdif_thread_t * );
70 static void BitstreamCallback( bit_stream_t *, boolean_t );
71
72 /*****************************************************************************
73  * Capabilities
74  *****************************************************************************/
75 void _M( adec_getfunctions )( function_list_t * p_function_list )
76 {
77     p_function_list->pf_probe = ac3_spdif_Probe;
78     p_function_list->functions.dec.pf_RunThread = ac3_spdif_Run;
79 }
80
81 /*****************************************************************************
82  * Build configuration tree.
83  *****************************************************************************/
84 MODULE_CONFIG_START
85 ADD_WINDOW( "Configuration for ac3 spdif decoder module" )
86     ADD_COMMENT( "Nothing to configure" )
87 MODULE_CONFIG_STOP
88
89 MODULE_INIT_START
90     p_module->i_capabilities = MODULE_CAPABILITY_DEC;
91     p_module->psz_longname = "Ac3 SPDIF decoder for AC3 pass-through";
92 MODULE_INIT_STOP
93
94 MODULE_ACTIVATE_START
95     _M( adec_getfunctions )( &p_module->p_functions->dec );
96 MODULE_ACTIVATE_STOP
97
98 MODULE_DEACTIVATE_START
99 MODULE_DEACTIVATE_STOP
100
101 /*****************************************************************************
102  * ac3_spdif_Probe: probe the decoder and return score
103  *****************************************************************************
104  * Tries to launch a decoder and return score so that the interface is able 
105  * to chose.
106  *****************************************************************************/
107 static int ac3_spdif_Probe( probedata_t *p_data )
108 {
109     if( main_GetIntVariable( AOUT_SPDIF_VAR, 0 ) && 
110         p_data->i_type == AC3_AUDIO_ES )
111         return( 100 );
112     else
113         return( 0 );
114 }
115
116
117 /****************************************************************************
118  * ac3_spdif_Run: the whole thing
119  ****************************************************************************
120  * This function is called just after the thread is launched.
121  ****************************************************************************/
122 static int ac3_spdif_Run( decoder_config_t * p_config )
123 {
124     ac3_spdif_thread_t *   p_spdif;
125     mtime_t     i_frame_time;
126     boolean_t   b_sync;
127     /* PTS of the current frame */
128     mtime_t     i_current_pts = 0;
129
130     intf_DbgMsg( "spdif debug: ac3_spdif thread created, initializing." );
131
132     /* Allocate the memory needed to store the thread's structure */
133     p_spdif = malloc( sizeof(ac3_spdif_thread_t) );
134
135     if( p_spdif == NULL )
136     {
137         intf_ErrMsg ( "spdif error: not enough memory "
138                       "for spdif_CreateThread() to create the new thread");
139         return( -1 );
140     }
141   
142     p_spdif->p_config = p_config; 
143     
144     if (ac3_spdif_Init( p_spdif ) )
145     {
146         intf_ErrMsg( "spdif error: could not initialize thread" );
147         return( -1 );
148     }
149
150     /* Compute the theorical duration of an ac3 frame */
151     i_frame_time = 1000000 * AC3_FRAME_SIZE /
152                              p_spdif->ac3_info.i_sample_rate;
153     
154     intf_DbgMsg( "spdif debug: ac3_spdif thread (%p) initialized", p_spdif );
155
156     while( !p_spdif->p_fifo->b_die && !p_spdif->p_fifo->b_error )
157     {
158         /* Handle the dates */
159         if( p_spdif->i_real_pts )
160         {
161             mtime_t     i_delta = p_spdif->i_real_pts - i_current_pts -
162                                   i_frame_time;
163             if( i_delta > i_frame_time || i_delta < -i_frame_time )
164             {
165                 intf_WarnMsg( 3, "spdif warning: date discontinuity (%d)",
166                               i_delta );
167             }
168             i_current_pts = p_spdif->i_real_pts;
169             p_spdif->i_real_pts = 0;
170         }
171         else
172         {
173             i_current_pts += i_frame_time;
174         }
175
176         /* if we're late here the output won't have to play the frame */
177         if( i_current_pts > mdate() )
178         {
179             p_spdif->p_aout_fifo->date[p_spdif->p_aout_fifo->l_end_frame] =
180                 i_current_pts;
181     
182             /* Write in the first free packet of aout fifo */
183             p_spdif->p_iec = ((u8*)(p_spdif->p_aout_fifo->buffer) + 
184                 (p_spdif->p_aout_fifo->l_end_frame * SPDIF_FRAME_SIZE ));
185     
186             /* Build burst to be sent to hardware decoder */
187             ac3_iec958_build_burst( p_spdif );
188     
189             vlc_mutex_lock (&p_spdif->p_aout_fifo->data_lock);
190             p_spdif->p_aout_fifo->l_end_frame = 
191                     (p_spdif->p_aout_fifo->l_end_frame + 1 ) & AOUT_FIFO_SIZE;
192             vlc_mutex_unlock (&p_spdif->p_aout_fifo->data_lock);
193         }
194
195         /* Find syncword again in case of stream discontinuity */
196         /* Here we have p_spdif->i_pts == 0
197          * Therefore a non-zero value after a call to GetBits() means the PES
198          * has changed. */
199         b_sync = 0;
200         while( !b_sync )
201         {
202             while( GetBits( &p_spdif->bit_stream, 8 ) != 0x0b );
203             p_spdif->i_real_pts = p_spdif->i_pts;
204             p_spdif->i_pts = 0;
205             b_sync = ( ShowBits( &p_spdif->bit_stream, 8 ) == 0x77 );
206         }
207         RemoveBits( &p_spdif->bit_stream, 8 );
208
209         /* Read data from bitstream */
210         GetChunk( &p_spdif->bit_stream, p_spdif->p_ac3 + 2,
211                   p_spdif->ac3_info.i_frame_size - 2 );
212     }
213
214     /* If b_error is set, the ac3 spdif thread enters the error loop */
215     if( p_spdif->p_fifo->b_error )
216     {
217         ac3_spdif_ErrorThread( p_spdif );
218     }
219
220     /* End of the ac3 decoder thread */
221     ac3_spdif_EndThread( p_spdif );
222     
223     return( 0 );
224 }
225
226 /****************************************************************************
227  * ac3_spdif_Init: initialize thread data and create output fifo
228  ****************************************************************************/
229 static int ac3_spdif_Init( ac3_spdif_thread_t * p_spdif )
230 {
231     boolean_t b_sync = 0;
232
233     /* Temporary buffer to store ac3 frames to be transformed */
234     p_spdif->p_ac3 = malloc( SPDIF_FRAME_SIZE );
235
236     if( p_spdif->p_ac3 == NULL )
237     {
238         free( p_spdif->p_ac3 );
239         return( -1 );
240     }
241
242     /*
243      * Initialize the thread properties
244      */
245     p_spdif->p_fifo = p_spdif->p_config->p_decoder_fifo;
246
247     p_spdif->p_config->pf_init_bit_stream(
248             &p_spdif->bit_stream,
249             p_spdif->p_config->p_decoder_fifo,
250             BitstreamCallback, (void*)p_spdif );
251
252     /* Creating the audio output fifo */
253     p_spdif->p_aout_fifo = aout_CreateFifo( AOUT_ADEC_SPDIF_FIFO, 1, 48000, 0,
254                                             SPDIF_FRAME_SIZE, NULL );
255
256     if( p_spdif->p_aout_fifo == NULL )
257     {
258         return( -1 );
259     }
260
261     intf_WarnMsg( 3, "spdif: aout fifo #%d created",
262                      p_spdif->p_aout_fifo->i_fifo );
263
264     /* Sync word */
265     p_spdif->p_ac3[0] = 0x0b;
266     p_spdif->p_ac3[1] = 0x77;
267
268     /* Find syncword */
269     while( !b_sync )
270     {
271         while( GetBits( &p_spdif->bit_stream, 8 ) != 0x0b );
272         p_spdif->i_real_pts = p_spdif->i_pts;
273         p_spdif->i_pts = 0;
274         b_sync = ( ShowBits( &p_spdif->bit_stream, 8 ) == 0x77 );
275     }
276     RemoveBits( &p_spdif->bit_stream, 8 );
277
278     /* Check stream properties */
279     if( ac3_iec958_parse_syncinfo( p_spdif ) < 0 )
280     {
281         intf_ErrMsg( "spdif error: stream not valid");
282
283         aout_DestroyFifo( p_spdif->p_aout_fifo );
284         return( -1 );
285     }
286
287     /* Check that we can handle the rate 
288      * FIXME: we should check that we have the same rate for all fifos 
289      * but all rates should be supported by the decoder (32, 44.1, 48) */
290     if( p_spdif->ac3_info.i_sample_rate != 48000 )
291     {
292         intf_ErrMsg( "spdif error: Only 48000 Hz streams supported");
293
294         aout_DestroyFifo( p_spdif->p_aout_fifo );
295         return -1;
296     }
297     p_spdif->p_aout_fifo->l_rate = p_spdif->ac3_info.i_sample_rate;
298
299     GetChunk( &p_spdif->bit_stream, p_spdif->p_ac3 + sizeof(sync_frame_t),
300         p_spdif->ac3_info.i_frame_size - sizeof(sync_frame_t) );
301
302     return( 0 );
303 }
304
305
306 /*****************************************************************************
307  * ac3_spdif_ErrorThread : ac3 spdif's RunThread() error loop
308  *****************************************************************************/
309 static void ac3_spdif_ErrorThread( ac3_spdif_thread_t * p_spdif )
310 {
311     /* We take the lock, because we are going to read/write the start/end
312      * indexes of the decoder fifo */
313     vlc_mutex_lock (&p_spdif->p_fifo->data_lock);
314
315     /* Wait until a `die' order is sent */
316     while( !p_spdif->p_fifo->b_die )
317     {
318         /* Trash all received PES packets */
319         while( !DECODER_FIFO_ISEMPTY( *p_spdif->p_fifo ) )
320         {
321             p_spdif->p_fifo->pf_delete_pes(p_spdif->p_fifo->p_packets_mgt,
322                     DECODER_FIFO_START( *p_spdif->p_fifo ) );
323             DECODER_FIFO_INCSTART( *p_spdif->p_fifo );
324         }
325
326         /* Waiting for the input thread to put new PES packets in the fifo */
327         vlc_cond_wait( &p_spdif->p_fifo->data_wait,
328                        &p_spdif->p_fifo->data_lock );
329     }
330
331     /* We can release the lock before leaving */
332     vlc_mutex_unlock( &p_spdif->p_fifo->data_lock );
333 }
334
335 /*****************************************************************************
336  * ac3_spdif_EndThread : ac3 spdif thread destruction
337  *****************************************************************************/
338 static void ac3_spdif_EndThread( ac3_spdif_thread_t * p_spdif )
339 {
340     intf_DbgMsg( "spdif debug: destroying thread %p", p_spdif );
341
342     /* If the audio output fifo was created, we destroy it */
343     if( p_spdif->p_aout_fifo != NULL )
344     {
345         aout_DestroyFifo( p_spdif->p_aout_fifo );
346
347         /* Make sure the output thread leaves the NextFrame() function */
348         vlc_mutex_lock( &(p_spdif->p_aout_fifo->data_lock ) );
349         vlc_cond_signal( &(p_spdif->p_aout_fifo->data_wait ) );
350         vlc_mutex_unlock( &(p_spdif->p_aout_fifo->data_lock ) );
351         
352     }
353
354     /* Destroy descriptor */
355     free( p_spdif->p_ac3 );
356     free( p_spdif );
357     
358     intf_DbgMsg ("spdif debug: thread %p destroyed", p_spdif );
359 }
360
361 /*****************************************************************************
362  * BitstreamCallback: Import parameters from the new data/PES packet
363  *****************************************************************************
364  * This function is called by input's NextDataPacket.
365  *****************************************************************************/
366 static void BitstreamCallback ( bit_stream_t * p_bit_stream,
367                                         boolean_t b_new_pes)
368 {
369     ac3_spdif_thread_t *    p_spdif;
370
371     if( b_new_pes )
372     {
373         p_spdif = (ac3_spdif_thread_t *)p_bit_stream->p_callback_arg;
374
375         p_bit_stream->p_byte += 3;
376
377         p_spdif->i_pts =
378             DECODER_FIFO_START( *p_bit_stream->p_decoder_fifo )->i_pts;
379         DECODER_FIFO_START( *p_bit_stream->p_decoder_fifo )->i_pts = 0;
380     }
381 }