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