]> git.sesse.net Git - vlc/blob - src/ac3_spdif/ac3_spdif.c
* Fixed a few warnings with gcc 3.0.
[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.3 2001/05/06 04:32:02 sam 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( /*ac3_info.i_frame_size*/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, 0, 0,
130                                             SPDIF_FRAME_SIZE, NULL );
131
132     if( p_spdif->p_aout_fifo == NULL )
133     {
134         return -1;
135     }
136
137     intf_WarnMsg( 1, "spdif: aout fifo created" );
138
139     /* Check stream properties */
140     if( ac3_iec958_parse_syncinfo( p_spdif ) < 0 )
141     {
142         intf_ErrMsg( "spdif error: stream not valid");
143
144         aout_DestroyFifo( p_spdif->p_aout_fifo );
145         return -1;
146     }
147
148     /* Check that we can handle the rate */
149     if( p_spdif->ac3_info.i_sample_rate != 48000 )
150     {
151         intf_ErrMsg( "spdif error: Only 48000 Hz streams supported");
152
153         aout_DestroyFifo( p_spdif->p_aout_fifo );
154         return -1;
155     }
156
157     GetChunk( &p_spdif->bit_stream, p_spdif->p_ac3 + sizeof(sync_frame_t),
158         p_spdif->ac3_info.i_frame_size - sizeof(sync_frame_t) );
159     
160     vlc_cond_signal( &p_spdif->p_aout_fifo->data_wait );
161
162     return 0;
163 }
164
165 /****************************************************************************
166  * RunThread: loop that reads ac3 ES and transform it to
167  * an spdif compliant stream.
168  ****************************************************************************/
169 static void RunThread( ac3_spdif_thread_t * p_spdif )
170 {
171     /* Initializing the spdif decoder thread */
172     if( InitThread( p_spdif ) )
173     {
174          p_spdif->p_fifo->b_error = 1;
175     }
176
177     while( !p_spdif->p_fifo->b_die && !p_spdif->p_fifo->b_error )
178     {
179         /* Handle the dates */
180         if(DECODER_FIFO_START(*p_spdif->p_fifo)->i_pts)
181         {
182             p_spdif->p_aout_fifo->date[p_spdif->p_aout_fifo->l_end_frame] =
183                 DECODER_FIFO_START(*p_spdif->p_fifo)->i_pts;
184             DECODER_FIFO_START(*p_spdif->p_fifo)->i_pts = 0;
185         }
186         else
187         {
188             p_spdif->p_aout_fifo->date[p_spdif->p_aout_fifo->l_end_frame] =
189                 LAST_MDATE;
190         }
191
192         /* Write in the first free packet of aout fifo */
193         p_spdif->p_iec = (p_spdif->p_aout_fifo->buffer) + 
194             (p_spdif->p_aout_fifo->l_end_frame * SPDIF_FRAME_SIZE );
195
196         /* Build burst to be sent to hardware decoder */
197         ac3_iec958_build_burst( p_spdif );
198
199         vlc_mutex_lock (&p_spdif->p_aout_fifo->data_lock);
200
201         p_spdif->p_aout_fifo->l_end_frame = 
202                 (p_spdif->p_aout_fifo->l_end_frame + 1 ) & AOUT_FIFO_SIZE;
203
204         vlc_mutex_unlock (&p_spdif->p_aout_fifo->data_lock);
205
206         /* Find syncword */
207         while( ShowBits( &p_spdif->bit_stream, 16 ) != 0xb77 ) 
208         {
209             RemoveBits( &p_spdif->bit_stream, 8 );
210         }
211
212         /* Read data from bitstream */
213         GetChunk( &p_spdif->bit_stream, p_spdif->p_ac3,
214                   p_spdif->ac3_info.i_frame_size );
215     }
216
217     /* If b_error is set, the ac3 spdif thread enters the error loop */
218     if( p_spdif->p_fifo->b_error )
219     {
220         ErrorThread( p_spdif );
221     }
222
223     /* End of the ac3 decoder thread */
224     EndThread( p_spdif );
225
226     return;
227 }
228
229 /*****************************************************************************
230  * ErrorThread : ac3 spdif's RunThread() error loop
231  *****************************************************************************/
232 static void ErrorThread( ac3_spdif_thread_t * p_spdif )
233 {
234     /* We take the lock, because we are going to read/write the start/end
235      * indexes of the decoder fifo */
236     vlc_mutex_lock (&p_spdif->p_fifo->data_lock);
237
238     /* Wait until a `die' order is sent */
239     while( !p_spdif->p_fifo->b_die )
240     {
241         /* Trash all received PES packets */
242         while( !DECODER_FIFO_ISEMPTY( *p_spdif->p_fifo ) )
243         {
244             p_spdif->p_fifo->pf_delete_pes(p_spdif->p_fifo->p_packets_mgt,
245                     DECODER_FIFO_START( *p_spdif->p_fifo ) );
246             DECODER_FIFO_INCSTART( *p_spdif->p_fifo );
247         }
248
249         /* Waiting for the input thread to put new PES packets in the fifo */
250         vlc_cond_wait( &p_spdif->p_fifo->data_wait,
251                        &p_spdif->p_fifo->data_lock );
252     }
253
254     /* We can release the lock before leaving */
255     vlc_mutex_unlock( &p_spdif->p_fifo->data_lock );
256 }
257
258 /*****************************************************************************
259  * EndThread : ac3 spdif thread destruction
260  *****************************************************************************/
261 static void EndThread( ac3_spdif_thread_t * p_spdif )
262 {
263     intf_DbgMsg( "spdif debug: destroying thread %p", p_spdif );
264
265     /* If the audio output fifo was created, we destroy it */
266     if( p_spdif->p_aout_fifo != NULL )
267     {
268         aout_DestroyFifo( p_spdif->p_aout_fifo );
269
270         /* Make sure the output thread leaves the NextFrame() function */
271         vlc_mutex_lock( &(p_spdif->p_aout_fifo->data_lock ) );
272         vlc_cond_signal( &(p_spdif->p_aout_fifo->data_wait ) );
273         vlc_mutex_unlock( &(p_spdif->p_aout_fifo->data_lock ) );
274         
275     }
276
277     /* Destroy descriptor */
278     free( p_spdif->p_config );
279     free( p_spdif->p_ac3 );
280     free( p_spdif );
281
282     intf_DbgMsg ("spdif debug: thread %p destroyed", p_spdif );
283 }
284
285 /*****************************************************************************
286  * BitstreamCallback: Import parameters from the new data/PES packet
287  *****************************************************************************
288  * This function is called by input's NextDataPacket.
289  *****************************************************************************/
290 static void BitstreamCallback ( bit_stream_t * p_bit_stream,
291                                         boolean_t b_new_pes)
292 {
293     if( b_new_pes )
294     {
295         p_bit_stream->p_byte += 3;
296     }
297 }