]> git.sesse.net Git - vlc/blob - src/ac3_spdif/ac3_spdif.c
* Mandatory step for video output IV and the audio output quality
[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.2 2001/05/01 04:18:18 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 <fcntl.h>
34 #include <unistd.h>
35
36 #include "config.h"
37 #include "common.h"
38 #include "threads.h"
39 #include "mtime.h"
40
41 #include "intf_msg.h"                        /* intf_DbgMsg(), intf_ErrMsg() */
42
43 #include "stream_control.h"
44 #include "input_ext-dec.h"
45
46 #include "audio_output.h"
47
48 #include "ac3_spdif.h"
49 #include "ac3_iec958.h"
50
51 #define FRAME_NB 8
52
53 /****************************************************************************
54  * Local Prototypes
55  ****************************************************************************/
56 static int  InitThread       ( ac3_spdif_thread_t * );
57 static void RunThread        ( ac3_spdif_thread_t * );
58 static void ErrorThread      ( ac3_spdif_thread_t * );
59 static void EndThread        ( ac3_spdif_thread_t * );
60 static void BitstreamCallback( bit_stream_t *, boolean_t );
61
62 /****************************************************************************
63  * spdif_CreateThread: initialize the spdif thread
64  ****************************************************************************/
65 vlc_thread_t spdif_CreateThread( adec_config_t * p_config )
66 {
67     ac3_spdif_thread_t *   p_spdif;
68
69     intf_DbgMsg( "spdif debug: creating ac3 pass-through thread" );
70
71     /* Allocate the memory needed to store the thread's structure */
72     p_spdif = malloc( sizeof(ac3_spdif_thread_t) );
73
74     if( p_spdif == NULL )
75     {
76         intf_ErrMsg ( "spdif error: not enough memory "
77                       "for spdif_CreateThread() to create the new thread");
78         return 0;
79     }
80     
81     /* Temporary buffer to store ac3 frames to be transformed */
82     p_spdif->p_ac3 = malloc( /*ac3_info.i_frame_size*/SPDIF_FRAME_SIZE );
83
84     if( p_spdif->p_ac3 == NULL )
85     {
86         free( p_spdif->p_ac3 );
87         return 0;
88     }
89
90     /*
91      * Initialize the thread properties
92      */
93     p_spdif->p_config = p_config;
94     p_spdif->p_fifo = p_config->decoder_config.p_decoder_fifo;
95
96     p_spdif->p_aout_fifo = NULL;
97
98     /* Spawn the ac3 to spdif thread */
99     if (vlc_thread_create(&p_spdif->thread_id, "spdif", 
100                 (vlc_thread_func_t)RunThread, (void *)p_spdif))
101     {
102         intf_ErrMsg( "spdif error: can't spawn spdif thread" );
103         free( p_spdif->p_ac3 );
104         free( p_spdif );
105         return 0;
106     }
107
108     intf_DbgMsg( "spdif debug: spdif thread (%p) created", p_spdif );
109
110     return p_spdif->thread_id;
111 }
112
113 /*
114  * Local functions
115  */
116
117 /****************************************************************************
118  * InitThread: initialize thread data and create output fifo
119  ****************************************************************************/
120 static int InitThread( ac3_spdif_thread_t * p_spdif )
121 {
122     p_spdif->p_config->decoder_config.pf_init_bit_stream(
123             &p_spdif->bit_stream,
124             p_spdif->p_config->decoder_config.p_decoder_fifo,
125             BitstreamCallback, (void*)p_spdif );
126
127     /* Creating the audio output fifo */
128     p_spdif->p_aout_fifo = aout_CreateFifo( AOUT_ADEC_SPDIF_FIFO, 1, 0, 0,
129                                             SPDIF_FRAME_SIZE, NULL );
130
131     if( p_spdif->p_aout_fifo == NULL )
132     {
133         return -1;
134     }
135
136     intf_WarnMsg( 1, "spdif: aout fifo created" );
137
138     /* Check stream properties */
139     if( ac3_iec958_parse_syncinfo( p_spdif ) < 0 )
140     {
141         intf_ErrMsg( "spdif error: stream not valid");
142
143         aout_DestroyFifo( p_spdif->p_aout_fifo );
144         return -1;
145     }
146
147     /* Check that we can handle the rate */
148     if( p_spdif->ac3_info.i_sample_rate != 48000 )
149     {
150         intf_ErrMsg( "spdif error: Only 48000 Hz streams supported");
151
152         aout_DestroyFifo( p_spdif->p_aout_fifo );
153         return -1;
154     }
155
156     GetChunk( &p_spdif->bit_stream, p_spdif->p_ac3 + sizeof(sync_frame_t),
157         p_spdif->ac3_info.i_frame_size - sizeof(sync_frame_t) );
158     
159     vlc_cond_signal( &p_spdif->p_aout_fifo->data_wait );
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
200         p_spdif->p_aout_fifo->l_end_frame = 
201                 (p_spdif->p_aout_fifo->l_end_frame + 1 ) & AOUT_FIFO_SIZE;
202
203         vlc_mutex_unlock (&p_spdif->p_aout_fifo->data_lock);
204
205         /* Find syncword */
206         while( ShowBits( &p_spdif->bit_stream, 16 ) != 0xb77 ) 
207         {
208             RemoveBits( &p_spdif->bit_stream, 8 );
209         }
210
211         /* Read data from bitstream */
212         GetChunk( &p_spdif->bit_stream, p_spdif->p_ac3,
213                   p_spdif->ac3_info.i_frame_size );
214     }
215
216     /* If b_error is set, the ac3 spdif thread enters the error loop */
217     if( p_spdif->p_fifo->b_error )
218     {
219         ErrorThread( p_spdif );
220     }
221
222     /* End of the ac3 decoder thread */
223     EndThread( p_spdif );
224
225     return;
226 }
227
228 /*****************************************************************************
229  * ErrorThread : ac3 spdif's RunThread() error loop
230  *****************************************************************************/
231 static void ErrorThread( ac3_spdif_thread_t * p_spdif )
232 {
233     /* We take the lock, because we are going to read/write the start/end
234      * indexes of the decoder fifo */
235     vlc_mutex_lock (&p_spdif->p_fifo->data_lock);
236
237     /* Wait until a `die' order is sent */
238     while( !p_spdif->p_fifo->b_die )
239     {
240         /* Trash all received PES packets */
241         while( !DECODER_FIFO_ISEMPTY( *p_spdif->p_fifo ) )
242         {
243             p_spdif->p_fifo->pf_delete_pes(p_spdif->p_fifo->p_packets_mgt,
244                     DECODER_FIFO_START( *p_spdif->p_fifo ) );
245             DECODER_FIFO_INCSTART( *p_spdif->p_fifo );
246         }
247
248         /* Waiting for the input thread to put new PES packets in the fifo */
249         vlc_cond_wait( &p_spdif->p_fifo->data_wait,
250                        &p_spdif->p_fifo->data_lock );
251     }
252
253     /* We can release the lock before leaving */
254     vlc_mutex_unlock( &p_spdif->p_fifo->data_lock );
255 }
256
257 /*****************************************************************************
258  * EndThread : ac3 spdif thread destruction
259  *****************************************************************************/
260 static void EndThread( ac3_spdif_thread_t * p_spdif )
261 {
262     intf_DbgMsg( "spdif debug: destroying thread %p", p_spdif );
263
264     /* If the audio output fifo was created, we destroy it */
265     if( p_spdif->p_aout_fifo != NULL )
266     {
267         aout_DestroyFifo( p_spdif->p_aout_fifo );
268
269         /* Make sure the output thread leaves the NextFrame() function */
270         vlc_mutex_lock( &(p_spdif->p_aout_fifo->data_lock ) );
271         vlc_cond_signal( &(p_spdif->p_aout_fifo->data_wait ) );
272         vlc_mutex_unlock( &(p_spdif->p_aout_fifo->data_lock ) );
273         
274     }
275
276     /* Destroy descriptor */
277     free( p_spdif->p_config );
278     free( p_spdif->p_ac3 );
279     free( p_spdif );
280
281     intf_DbgMsg ("spdif debug: thread %p destroyed", p_spdif );
282 }
283
284 /*****************************************************************************
285  * BitstreamCallback: Import parameters from the new data/PES packet
286  *****************************************************************************
287  * This function is called by input's NextDataPacket.
288  *****************************************************************************/
289 static void BitstreamCallback ( bit_stream_t * p_bit_stream,
290                                         boolean_t b_new_pes)
291 {
292     if( b_new_pes )
293     {
294         p_bit_stream->p_byte += 3;
295     }
296 }