]> git.sesse.net Git - vlc/blob - plugins/ac3_spdif/ac3_spdif.c
* Closing Debian bug #119369 which was fixed a while ago.
[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.1 2001/11/13 12:09:17 henri 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 "threads.h"
46 #include "mtime.h"
47 #include "intf_msg.h"                        /* intf_DbgMsg(), intf_ErrMsg() */
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             if(i_current_pts + i_frame_time != p_spdif->i_real_pts)
162             {
163                 intf_WarnMsg( 2, "spdif warning: date discontinuity (%d)",
164                               p_spdif->i_real_pts - i_current_pts -
165                               i_frame_time );
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         while( !DECODER_FIFO_ISEMPTY( *p_spdif->p_fifo ) )
319         {
320             p_spdif->p_fifo->pf_delete_pes(p_spdif->p_fifo->p_packets_mgt,
321                     DECODER_FIFO_START( *p_spdif->p_fifo ) );
322             DECODER_FIFO_INCSTART( *p_spdif->p_fifo );
323         }
324
325         /* Waiting for the input thread to put new PES packets in the fifo */
326         vlc_cond_wait( &p_spdif->p_fifo->data_wait,
327                        &p_spdif->p_fifo->data_lock );
328     }
329
330     /* We can release the lock before leaving */
331     vlc_mutex_unlock( &p_spdif->p_fifo->data_lock );
332 }
333
334 /*****************************************************************************
335  * ac3_spdif_EndThread : ac3 spdif thread destruction
336  *****************************************************************************/
337 static void ac3_spdif_EndThread( ac3_spdif_thread_t * p_spdif )
338 {
339     intf_DbgMsg( "spdif debug: destroying thread %p", p_spdif );
340
341     /* If the audio output fifo was created, we destroy it */
342     if( p_spdif->p_aout_fifo != NULL )
343     {
344         aout_DestroyFifo( p_spdif->p_aout_fifo );
345
346         /* Make sure the output thread leaves the NextFrame() function */
347         vlc_mutex_lock( &(p_spdif->p_aout_fifo->data_lock ) );
348         vlc_cond_signal( &(p_spdif->p_aout_fifo->data_wait ) );
349         vlc_mutex_unlock( &(p_spdif->p_aout_fifo->data_lock ) );
350         
351     }
352
353     /* Destroy descriptor */
354     free( p_spdif->p_config );
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 }