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