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