]> git.sesse.net Git - vlc/blob - src/ac3_spdif/ac3_spdif.c
-Changes and bugfixes to make network work in VLAN Broadcast mode.
[vlc] / src / 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.6 2001/05/30 05:19:03 stef 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 "defs.h"
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>                                              /* memcpy() */
34 #include <fcntl.h>
35 #include <unistd.h>
36
37 #include "config.h"
38 #include "common.h"
39 #include "threads.h"
40 #include "mtime.h"
41
42 #include "intf_msg.h"                        /* intf_DbgMsg(), intf_ErrMsg() */
43
44 #include "stream_control.h"
45 #include "input_ext-dec.h"
46
47 #include "audio_output.h"
48
49 #include "ac3_spdif.h"
50 #include "ac3_iec958.h"
51
52 #define FRAME_NB 8
53
54 /****************************************************************************
55  * Local Prototypes
56  ****************************************************************************/
57 static int  InitThread       ( ac3_spdif_thread_t * );
58 static void RunThread        ( ac3_spdif_thread_t * );
59 static void ErrorThread      ( ac3_spdif_thread_t * );
60 static void EndThread        ( ac3_spdif_thread_t * );
61 static void BitstreamCallback( bit_stream_t *, boolean_t );
62
63 /****************************************************************************
64  * spdif_CreateThread: initialize the spdif thread
65  ****************************************************************************/
66 vlc_thread_t spdif_CreateThread( adec_config_t * p_config )
67 {
68     ac3_spdif_thread_t *   p_spdif;
69
70     intf_DbgMsg( "spdif debug: creating ac3 pass-through thread" );
71
72     /* Allocate the memory needed to store the thread's structure */
73     p_spdif = malloc( sizeof(ac3_spdif_thread_t) );
74
75     if( p_spdif == NULL )
76     {
77         intf_ErrMsg ( "spdif error: not enough memory "
78                       "for spdif_CreateThread() to create the new thread");
79         return 0;
80     }
81     
82     /* Temporary buffer to store ac3 frames to be transformed */
83     p_spdif->p_ac3 = malloc( SPDIF_FRAME_SIZE );
84
85     if( p_spdif->p_ac3 == NULL )
86     {
87         free( p_spdif->p_ac3 );
88         return 0;
89     }
90
91     /*
92      * Initialize the thread properties
93      */
94     p_spdif->p_config = p_config;
95     p_spdif->p_fifo = p_config->decoder_config.p_decoder_fifo;
96
97     p_spdif->p_aout_fifo = NULL;
98
99     /* Spawn the ac3 to spdif thread */
100     if (vlc_thread_create(&p_spdif->thread_id, "spdif", 
101                 (vlc_thread_func_t)RunThread, (void *)p_spdif))
102     {
103         intf_ErrMsg( "spdif error: can't spawn spdif thread" );
104         free( p_spdif->p_ac3 );
105         free( p_spdif );
106         return 0;
107     }
108
109     intf_DbgMsg( "spdif debug: spdif thread (%p) created", p_spdif );
110
111     return p_spdif->thread_id;
112 }
113
114 /*
115  * Local functions
116  */
117
118 /****************************************************************************
119  * InitThread: initialize thread data and create output fifo
120  ****************************************************************************/
121 static int InitThread( ac3_spdif_thread_t * p_spdif )
122 {
123     p_spdif->p_config->decoder_config.pf_init_bit_stream(
124             &p_spdif->bit_stream,
125             p_spdif->p_config->decoder_config.p_decoder_fifo,
126             BitstreamCallback, (void*)p_spdif );
127
128     /* Creating the audio output fifo */
129     p_spdif->p_aout_fifo = aout_CreateFifo( AOUT_ADEC_SPDIF_FIFO, 1, 48000, 0,
130                                             SPDIF_FRAME_SIZE, NULL );
131
132     if( p_spdif->p_aout_fifo == NULL )
133     {
134         return -1;
135     }
136
137     intf_WarnMsg( 3, "spdif: aout fifo #%d created",
138                      p_spdif->p_aout_fifo->i_fifo );
139
140     /* Check stream properties */
141     if( ac3_iec958_parse_syncinfo( p_spdif ) < 0 )
142     {
143         intf_ErrMsg( "spdif error: stream not valid");
144
145         aout_DestroyFifo( p_spdif->p_aout_fifo );
146         return -1;
147     }
148
149     
150     /* Check that we can handle the rate 
151      * FIXME: we should check that we have the same rate for all fifos 
152      * but all rates should be supported by the decoder (32, 44.1, 48) */
153     if( p_spdif->ac3_info.i_sample_rate != 48000 )
154     {
155         intf_ErrMsg( "spdif error: Only 48000 Hz streams supported");
156
157         aout_DestroyFifo( p_spdif->p_aout_fifo );
158         return -1;
159     }
160     p_spdif->p_aout_fifo->l_rate = p_spdif->ac3_info.i_sample_rate;
161
162     GetChunk( &p_spdif->bit_stream, p_spdif->p_ac3 + sizeof(sync_frame_t),
163         p_spdif->ac3_info.i_frame_size - sizeof(sync_frame_t) );
164
165     return 0;
166 }
167
168 /****************************************************************************
169  * RunThread: loop that reads ac3 ES and transform it to
170  * an spdif compliant stream.
171  ****************************************************************************/
172 static void RunThread( ac3_spdif_thread_t * p_spdif )
173 {
174     mtime_t     m_last_pts = 0;
175     mtime_t     m_frame_time;
176
177     /* Initializing the spdif decoder thread */
178     if( InitThread( p_spdif ) )
179     {
180          p_spdif->p_fifo->b_error = 1;
181     }
182
183     /* Compute the theorical duration of an ac3 frame */
184     m_frame_time = 1000000 * AC3_FRAME_SIZE /
185                              p_spdif->ac3_info.i_sample_rate;
186
187     while( !p_spdif->p_fifo->b_die && !p_spdif->p_fifo->b_error )
188     {
189         /* Handle the dates */
190         if(DECODER_FIFO_START(*p_spdif->p_fifo)->i_pts)
191         {
192             m_last_pts = DECODER_FIFO_START(*p_spdif->p_fifo)->i_pts;
193             DECODER_FIFO_START(*p_spdif->p_fifo)->i_pts = 0;
194         }
195         else
196         {
197             m_last_pts += m_frame_time;
198         }
199
200         /* if we're late here the output won't have to play the frame */
201         if( m_last_pts > mdate() )
202         {
203             p_spdif->p_aout_fifo->date[p_spdif->p_aout_fifo->l_end_frame] =
204                 m_last_pts;
205     
206             /* Write in the first free packet of aout fifo */
207             p_spdif->p_iec = (p_spdif->p_aout_fifo->buffer) + 
208                 (p_spdif->p_aout_fifo->l_end_frame * SPDIF_FRAME_SIZE );
209     
210             /* Build burst to be sent to hardware decoder */
211             ac3_iec958_build_burst( p_spdif );
212     
213             vlc_mutex_lock (&p_spdif->p_aout_fifo->data_lock);
214             p_spdif->p_aout_fifo->l_end_frame = 
215                     (p_spdif->p_aout_fifo->l_end_frame + 1 ) & AOUT_FIFO_SIZE;
216             vlc_mutex_unlock (&p_spdif->p_aout_fifo->data_lock);
217         }
218
219         /* Find syncword again in case of stream discontinuity */
220         while( ShowBits( &p_spdif->bit_stream, 16 ) != 0xb77 ) 
221         {
222             RemoveBits( &p_spdif->bit_stream, 8 );
223         }
224
225         /* Read data from bitstream */
226         GetChunk( &p_spdif->bit_stream, p_spdif->p_ac3,
227                   p_spdif->ac3_info.i_frame_size );
228     }
229
230     /* If b_error is set, the ac3 spdif thread enters the error loop */
231     if( p_spdif->p_fifo->b_error )
232     {
233         ErrorThread( p_spdif );
234     }
235
236     /* End of the ac3 decoder thread */
237     EndThread( p_spdif );
238
239     return;
240 }
241
242 /*****************************************************************************
243  * ErrorThread : ac3 spdif's RunThread() error loop
244  *****************************************************************************/
245 static void ErrorThread( ac3_spdif_thread_t * p_spdif )
246 {
247     /* We take the lock, because we are going to read/write the start/end
248      * indexes of the decoder fifo */
249     vlc_mutex_lock (&p_spdif->p_fifo->data_lock);
250
251     /* Wait until a `die' order is sent */
252     while( !p_spdif->p_fifo->b_die )
253     {
254         /* Trash all received PES packets */
255         while( !DECODER_FIFO_ISEMPTY( *p_spdif->p_fifo ) )
256         {
257             p_spdif->p_fifo->pf_delete_pes(p_spdif->p_fifo->p_packets_mgt,
258                     DECODER_FIFO_START( *p_spdif->p_fifo ) );
259             DECODER_FIFO_INCSTART( *p_spdif->p_fifo );
260         }
261
262         /* Waiting for the input thread to put new PES packets in the fifo */
263         vlc_cond_wait( &p_spdif->p_fifo->data_wait,
264                        &p_spdif->p_fifo->data_lock );
265     }
266
267     /* We can release the lock before leaving */
268     vlc_mutex_unlock( &p_spdif->p_fifo->data_lock );
269 }
270
271 /*****************************************************************************
272  * EndThread : ac3 spdif thread destruction
273  *****************************************************************************/
274 static void EndThread( ac3_spdif_thread_t * p_spdif )
275 {
276     intf_DbgMsg( "spdif debug: destroying thread %p", p_spdif );
277
278     /* If the audio output fifo was created, we destroy it */
279     if( p_spdif->p_aout_fifo != NULL )
280     {
281         aout_DestroyFifo( p_spdif->p_aout_fifo );
282
283         /* Make sure the output thread leaves the NextFrame() function */
284         vlc_mutex_lock( &(p_spdif->p_aout_fifo->data_lock ) );
285         vlc_cond_signal( &(p_spdif->p_aout_fifo->data_wait ) );
286         vlc_mutex_unlock( &(p_spdif->p_aout_fifo->data_lock ) );
287         
288     }
289
290     /* Destroy descriptor */
291     free( p_spdif->p_config );
292     free( p_spdif->p_ac3 );
293     free( p_spdif );
294
295     intf_DbgMsg ("spdif debug: thread %p destroyed", p_spdif );
296 }
297
298 /*****************************************************************************
299  * BitstreamCallback: Import parameters from the new data/PES packet
300  *****************************************************************************
301  * This function is called by input's NextDataPacket.
302  *****************************************************************************/
303 static void BitstreamCallback ( bit_stream_t * p_bit_stream,
304                                         boolean_t b_new_pes)
305 {
306     if( b_new_pes )
307     {
308         p_bit_stream->p_byte += 3;
309     }
310 }