]> git.sesse.net Git - vlc/blob - src/ac3_decoder/ac3_decoder_thread.c
. portage des vlc_threads aux cthreads de Mach pour GNU/Hurd
[vlc] / src / ac3_decoder / ac3_decoder_thread.c
1 /*****************************************************************************
2  * ac3_decoder_thread.c: ac3 decoder thread
3  * (c)1999 VideoLAN
4  *****************************************************************************/
5
6 /*
7  * TODO :
8  *
9  * - vérifier l'état de la fifo de sortie avant d'y stocker les samples
10  *   décodés ;
11  * - vlc_cond_signal() / vlc_cond_wait()
12  *
13  */
14
15 /*****************************************************************************
16  * Preamble
17  *****************************************************************************/
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 #include <fcntl.h>
21
22 #include <unistd.h>                                              /* getpid() */
23
24 #include <stdio.h>                                           /* "intf_msg.h" */
25 #include <stdlib.h>                                      /* malloc(), free() */
26 #include <sys/uio.h>                                            /* "input.h" */
27
28 #include "common.h"
29 #include "config.h"
30 #include "mtime.h"
31 #include "vlc_thread.h"
32 #include "debug.h"                                      /* "input_netlist.h" */
33
34 #include "intf_msg.h"                        /* intf_DbgMsg(), intf_ErrMsg() */
35
36 #include "input.h"                                           /* pes_packet_t */
37 #include "input_netlist.h"                         /* input_NetlistFreePES() */
38 #include "decoder_fifo.h"         /* DECODER_FIFO_(ISEMPTY|START|INCSTART)() */
39
40 #include "audio_output.h"
41
42 #include "ac3_decoder.h"
43 #include "ac3_decoder_thread.h"
44
45 #define AC3DEC_FRAME_SIZE (2*1536) 
46 typedef s16 ac3dec_frame_t[ AC3DEC_FRAME_SIZE ];
47
48 /*****************************************************************************
49  * Local prototypes
50  *****************************************************************************/
51 static int      InitThread              ( ac3dec_thread_t * p_adec );
52 static void     RunThread               ( ac3dec_thread_t * p_adec );
53 static void     ErrorThread             ( ac3dec_thread_t * p_adec );
54 static void     EndThread               ( ac3dec_thread_t * p_adec );
55
56 /*****************************************************************************
57  * ac3dec_CreateThread: creates an ac3 decoder thread
58  *****************************************************************************/
59 ac3dec_thread_t * ac3dec_CreateThread( input_thread_t * p_input )
60 {
61     ac3dec_thread_t *   p_ac3dec;
62
63     intf_DbgMsg("ac3dec debug: creating ac3 decoder thread\n");
64
65     /* Allocate the memory needed to store the thread's structure */
66     if ( (p_ac3dec = (ac3dec_thread_t *)malloc( sizeof(ac3dec_thread_t) )) == NULL )
67     {
68         intf_ErrMsg("ac3dec error: not enough memory for ac3dec_CreateThread() to create the new thread\n");
69         return( NULL );
70     }
71
72     /*
73      * Initialize the thread properties
74      */
75     p_ac3dec->b_die = 0;
76     p_ac3dec->b_error = 0;
77
78     /*
79      * Initialize the input properties
80      */
81     /* Initialize the decoder fifo's data lock and conditional variable and set
82      * its buffer as empty */
83     vlc_mutex_init( &p_ac3dec->fifo.data_lock );
84     vlc_cond_init( &p_ac3dec->fifo.data_wait );
85     p_ac3dec->fifo.i_start = 0;
86     p_ac3dec->fifo.i_end = 0;
87
88     /* Initialize the ac3 decoder structures */
89     ac3_init (&p_ac3dec->ac3_decoder);
90
91     /* Initialize the bit stream structure */
92     p_ac3dec->p_input = p_input;
93
94     /*
95      * Initialize the output properties
96      */
97     p_ac3dec->p_aout = p_input->p_aout;
98     p_ac3dec->p_aout_fifo = NULL;
99
100     /* Spawn the ac3 decoder thread */
101     if ( vlc_thread_create(&p_ac3dec->thread_id, "ac3 decoder", (vlc_thread_func_t)RunThread, (void *)p_ac3dec) )
102     {
103         intf_ErrMsg( "ac3dec error: can't spawn ac3 decoder thread\n" );
104         free( p_ac3dec );
105         return( NULL );
106     }
107
108     intf_DbgMsg( "ac3dec debug: ac3 decoder thread (%p) created\n", p_ac3dec );
109     return( p_ac3dec );
110 }
111
112 /*****************************************************************************
113  * ac3dec_DestroyThread: destroys an ac3 decoder thread
114  *****************************************************************************/
115 void ac3dec_DestroyThread( ac3dec_thread_t * p_ac3dec )
116 {
117     intf_DbgMsg( "ac3dec debug: requesting termination of ac3 decoder thread %p\n", p_ac3dec );
118
119     /* Ask thread to kill itself */
120     p_ac3dec->b_die = 1;
121
122     /* Make sure the decoder thread leaves the GetByte() function */
123     vlc_mutex_lock( &(p_ac3dec->fifo.data_lock) );
124     vlc_cond_signal( &(p_ac3dec->fifo.data_wait) );
125     vlc_mutex_unlock( &(p_ac3dec->fifo.data_lock) );
126
127     /* Waiting for the decoder thread to exit */
128     /* Remove this as soon as the "status" flag is implemented */
129     vlc_thread_join( p_ac3dec->thread_id );
130 }
131
132 /* Following functions are local */
133
134 /*****************************************************************************
135  * InitThread : initialize an ac3 decoder thread
136  *****************************************************************************/
137 static int InitThread( ac3dec_thread_t * p_ac3dec )
138 {
139     aout_fifo_t         aout_fifo;
140     ac3_byte_stream_t * byte_stream;
141
142     intf_DbgMsg( "ac3dec debug: initializing ac3 decoder thread %p\n", p_ac3dec );
143
144     /* Our first job is to initialize the bit stream structure with the
145      * beginning of the input stream */
146     vlc_mutex_lock( &p_ac3dec->fifo.data_lock );
147     while ( DECODER_FIFO_ISEMPTY(p_ac3dec->fifo) )
148     {
149         if ( p_ac3dec->b_die )
150         {
151             vlc_mutex_unlock( &p_ac3dec->fifo.data_lock );
152             return( -1 );
153         }
154         vlc_cond_wait( &p_ac3dec->fifo.data_wait, &p_ac3dec->fifo.data_lock );
155     }
156     p_ac3dec->p_ts = DECODER_FIFO_START( p_ac3dec->fifo )->p_first_ts;
157     byte_stream = ac3_byte_stream (&p_ac3dec->ac3_decoder);
158     byte_stream->p_byte =
159         p_ac3dec->p_ts->buffer + p_ac3dec->p_ts->i_payload_start;
160     byte_stream->p_end =
161         p_ac3dec->p_ts->buffer + p_ac3dec->p_ts->i_payload_end;
162     byte_stream->info = p_ac3dec;
163     vlc_mutex_unlock( &p_ac3dec->fifo.data_lock );
164
165     aout_fifo.i_type = AOUT_ADEC_STEREO_FIFO;
166     aout_fifo.i_channels = 2;
167     aout_fifo.b_stereo = 1;
168
169     aout_fifo.l_frame_size = AC3DEC_FRAME_SIZE;
170
171     /* Creating the audio output fifo */
172     if ( (p_ac3dec->p_aout_fifo = aout_CreateFifo(p_ac3dec->p_aout, &aout_fifo)) == NULL )
173     {
174         return( -1 );
175     }
176
177     intf_DbgMsg( "ac3dec debug: ac3 decoder thread %p initialized\n", p_ac3dec );
178     return( 0 );
179 }
180
181 /*****************************************************************************
182  * RunThread : ac3 decoder thread
183  *****************************************************************************/
184 static void RunThread( ac3dec_thread_t * p_ac3dec )
185 {
186     int sync;
187
188     intf_DbgMsg( "ac3dec debug: running ac3 decoder thread (%p) (pid == %i)\n", p_ac3dec, getpid() );
189
190     msleep( INPUT_PTS_DELAY );
191
192     /* Initializing the ac3 decoder thread */
193     if ( InitThread(p_ac3dec) ) /* XXX?? */
194     {
195         p_ac3dec->b_error = 1;
196     }
197
198     sync = 0;
199     p_ac3dec->sync_ptr = 0;
200
201     /* ac3 decoder thread's main loop */
202     /* FIXME : do we have enough room to store the decoded frames ?? */
203     while ( (!p_ac3dec->b_die) && (!p_ac3dec->b_error) )
204     {
205         s16 * buffer;
206         ac3_sync_info_t sync_info;
207
208         if (!sync) { /* have to find a synchro point */
209
210             int ptr;
211             ac3_byte_stream_t * p_byte_stream;
212
213             p_byte_stream = ac3_byte_stream (&p_ac3dec->ac3_decoder);
214
215             /* first read till next ac3 magic header */
216             do {
217                 ac3_byte_stream_next (p_byte_stream);
218             } while ((!p_ac3dec->sync_ptr) &&
219                      (!p_ac3dec->b_die) &&
220                      (!p_ac3dec->b_error));
221             /* skip the specified number of bytes */
222
223             ptr = p_ac3dec->sync_ptr;
224             while (--ptr && (!p_ac3dec->b_die) && (!p_ac3dec->b_error)) {
225                 if (p_byte_stream->p_byte >= p_byte_stream->p_end) {
226                     ac3_byte_stream_next (p_byte_stream);                   
227                 }
228                 p_byte_stream->p_byte++;
229             }
230
231             /* we are in sync now */
232
233             sync = 1;
234             p_ac3dec->sync_ptr = 0;
235         }
236
237         if ( DECODER_FIFO_START(p_ac3dec->fifo)->b_has_pts )
238         {
239                 p_ac3dec->p_aout_fifo->date[p_ac3dec->p_aout_fifo->l_end_frame] = DECODER_FIFO_START(p_ac3dec->fifo)->i_pts;
240                 DECODER_FIFO_START(p_ac3dec->fifo)->b_has_pts = 0;
241         }
242         else
243         {
244                 p_ac3dec->p_aout_fifo->date[p_ac3dec->p_aout_fifo->l_end_frame] = LAST_MDATE;
245         }
246
247         if (ac3_sync_frame (&p_ac3dec->ac3_decoder, &sync_info)) {
248             sync = 0;
249             goto bad_frame;
250         }
251
252         p_ac3dec->p_aout_fifo->l_rate = sync_info.sample_rate;
253
254         buffer = ((ac3dec_frame_t *)p_ac3dec->p_aout_fifo->buffer)[ p_ac3dec->p_aout_fifo->l_end_frame ];
255
256         if (ac3_decode_frame (&p_ac3dec->ac3_decoder, buffer)) {
257             sync = 0;
258             goto bad_frame;
259         }
260
261         vlc_mutex_lock( &p_ac3dec->p_aout_fifo->data_lock );
262         p_ac3dec->p_aout_fifo->l_end_frame = (p_ac3dec->p_aout_fifo->l_end_frame + 1) & AOUT_FIFO_SIZE;
263         vlc_cond_signal( &p_ac3dec->p_aout_fifo->data_wait );
264         vlc_mutex_unlock( &p_ac3dec->p_aout_fifo->data_lock );
265
266 bad_frame:
267     }
268
269     /* If b_error is set, the ac3 decoder thread enters the error loop */
270     if ( p_ac3dec->b_error )
271     {
272         ErrorThread( p_ac3dec );
273     }
274
275     /* End of the ac3 decoder thread */
276     EndThread( p_ac3dec );
277 }
278
279 /*****************************************************************************
280  * ErrorThread : ac3 decoder's RunThread() error loop
281  *****************************************************************************/
282 static void ErrorThread( ac3dec_thread_t * p_ac3dec )
283 {
284     /* We take the lock, because we are going to read/write the start/end
285      * indexes of the decoder fifo */
286     vlc_mutex_lock( &p_ac3dec->fifo.data_lock );
287
288     /* Wait until a `die' order is sent */
289     while( !p_ac3dec->b_die )
290     {
291         /* Trash all received PES packets */
292         while( !DECODER_FIFO_ISEMPTY(p_ac3dec->fifo) )
293         {
294             input_NetlistFreePES( p_ac3dec->p_input, DECODER_FIFO_START(p_ac3dec->fifo) );
295             DECODER_FIFO_INCSTART( p_ac3dec->fifo );
296         }
297
298         /* Waiting for the input thread to put new PES packets in the fifo */
299         vlc_cond_wait( &p_ac3dec->fifo.data_wait, &p_ac3dec->fifo.data_lock );
300     }
301
302     /* We can release the lock before leaving */
303     vlc_mutex_unlock( &p_ac3dec->fifo.data_lock );
304 }
305
306 /*****************************************************************************
307  * EndThread : ac3 decoder thread destruction
308  *****************************************************************************/
309 static void EndThread( ac3dec_thread_t * p_ac3dec )
310 {
311     intf_DbgMsg( "ac3dec debug: destroying ac3 decoder thread %p\n", p_ac3dec );
312
313     /* If the audio output fifo was created, we destroy it */
314     if ( p_ac3dec->p_aout_fifo != NULL )
315     {
316         aout_DestroyFifo( p_ac3dec->p_aout_fifo );
317
318         /* Make sure the output thread leaves the NextFrame() function */
319         vlc_mutex_lock( &(p_ac3dec->p_aout_fifo->data_lock) );
320         vlc_cond_signal( &(p_ac3dec->p_aout_fifo->data_wait) );
321         vlc_mutex_unlock( &(p_ac3dec->p_aout_fifo->data_lock) );
322     }
323
324     /* Destroy descriptor */
325     free( p_ac3dec );
326
327     intf_DbgMsg( "ac3dec debug: ac3 decoder thread %p destroyed\n", p_ac3dec );
328 }
329
330 void ac3_byte_stream_next (ac3_byte_stream_t * p_byte_stream)
331 {
332     ac3dec_thread_t * p_ac3dec = p_byte_stream->info;
333
334     /* We are looking for the next TS packet that contains real data,
335      * and not just a PES header */
336     do {
337         /* We were reading the last TS packet of this PES packet... It's
338          * time to jump to the next PES packet */
339         if (p_ac3dec->p_ts->p_next_ts == NULL) {
340             int ptr;
341
342             /* We are going to read/write the start and end indexes of the 
343              * decoder fifo and to use the fifo's conditional variable, 
344              * that's why we need to take the lock before */ 
345             vlc_mutex_lock (&p_ac3dec->fifo.data_lock);
346             
347             /* Is the input thread dying ? */
348             if (p_ac3dec->p_input->b_die) {
349                 vlc_mutex_unlock (&(p_ac3dec->fifo.data_lock));
350                 return;
351             }
352
353             /* We should increase the start index of the decoder fifo, but
354              * if we do this now, the input thread could overwrite the
355              * pointer to the current PES packet, and we weren't able to
356              * give it back to the netlist. That's why we free the PES
357              * packet first. */
358             input_NetlistFreePES (p_ac3dec->p_input, DECODER_FIFO_START(p_ac3dec->fifo) );
359
360             DECODER_FIFO_INCSTART (p_ac3dec->fifo);
361
362             while (DECODER_FIFO_ISEMPTY(p_ac3dec->fifo)) {
363                 vlc_cond_wait (&p_ac3dec->fifo.data_wait, &p_ac3dec->fifo.data_lock );
364
365                 if (p_ac3dec->p_input->b_die) {
366                     vlc_mutex_unlock (&(p_ac3dec->fifo.data_lock));
367                     return;
368                 }
369             }
370
371             /* The next byte could be found in the next PES packet */
372             p_ac3dec->p_ts = DECODER_FIFO_START (p_ac3dec->fifo)->p_first_ts;
373
374             /* parse ac3 magic header */
375             ptr = p_ac3dec->p_ts->buffer [p_ac3dec->p_ts->i_payload_start+2];
376             ptr <<= 8;
377             ptr |= p_ac3dec->p_ts->buffer [p_ac3dec->p_ts->i_payload_start+3];
378             p_ac3dec->sync_ptr = ptr;
379             p_ac3dec->p_ts->i_payload_start += 4;
380
381             /* We can release the fifo's data lock */
382             vlc_mutex_unlock (&p_ac3dec->fifo.data_lock);
383         }
384
385         /* Perhaps the next TS packet of the current PES packet contains 
386          * real data (ie its payload's size is greater than 0) */
387         else {
388             p_ac3dec->p_ts = p_ac3dec->p_ts->p_next_ts;
389         }
390     } while (p_ac3dec->p_ts->i_payload_start == p_ac3dec->p_ts->i_payload_end);
391     p_byte_stream->p_byte =
392         p_ac3dec->p_ts->buffer + p_ac3dec->p_ts->i_payload_start; 
393     p_byte_stream->p_end =
394         p_ac3dec->p_ts->buffer + p_ac3dec->p_ts->i_payload_end; 
395 }