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