]> git.sesse.net Git - vlc/blob - src/generic_decoder/generic_decoder.c
* Added IDEALX developer documentation into main CVS - PLEASE UPDATE
[vlc] / src / generic_decoder / generic_decoder.c
1 /*****************************************************************************
2  * generic_decoder.c : generic decoder thread
3  * This decoder provides a way to parse packets which do not belong to any
4  * known stream type, or to redirect packets to files. It can extract PES files
5  * from a multiplexed stream, identify automatically ES in a stream missing
6  * stream informations (i.e. a TS stream without PSI) and update ES tables in
7  * its input thread, or just print informations about what it receives in DEBUG
8  * mode.
9  * A single generic decoder is able to handle several ES, therefore it can be
10  * used as a 'default' decoder by the input thread.
11  *****************************************************************************
12  * Copyright (C) 1998, 1999, 2000 VideoLAN
13  * $Id: generic_decoder.c,v 1.18 2001/03/21 13:42:34 sam Exp $
14  *
15  * Authors: Vincent Seguin <seguin@via.ecp.fr>
16  *
17  * This program is free software; you can redistribute it and/or modify
18  * it under the terms of the GNU General Public License as published by
19  * the Free Software Foundation; either version 2 of the License, or
20  * (at your option) any later version.
21  * 
22  * This program is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25  * GNU General Public License for more details.
26  *
27  * You should have received a copy of the GNU General Public License
28  * along with this program; if not, write to the Free Software
29  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
30  *****************************************************************************/
31
32 /*****************************************************************************
33  * Preamble
34  *****************************************************************************/
35 #include "defs.h"
36
37 #include <errno.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <stdio.h>
41 #include <sys/types.h>
42 #include <sys/socket.h>
43
44 #include "config.h"
45 #include "common.h"
46 #include "mtime.h"
47 #include "threads.h"
48 #include "threads.h"
49
50 #include "intf_msg.h"
51 #include "debug.h"
52
53 #include "input.h"
54 #include "input_netlist.h"
55 #include "decoder_fifo.h"
56
57 #include "generic_decoder.h"
58
59 /*
60  * Local prototypes
61  */
62 static int      CheckConfiguration  ( gdec_cfg_t *p_cfg );
63 static int      InitThread          ( gdec_thread_t *p_gdec );
64 static void     RunThread           ( gdec_thread_t *p_gdec );
65 static void     ErrorThread         ( gdec_thread_t *p_gdec );
66 static void     EndThread           ( gdec_thread_t *p_gdec );
67
68 static void     IdentifyPES         ( gdec_thread_t *p_gdec, pes_packet_t *p_pes,
69                                       int i_stream_id );
70 static void     PrintPES            ( pes_packet_t *p_pes, int i_stream_id );
71
72 /*****************************************************************************
73  * gdec_CreateThread: create a generic decoder thread
74  *****************************************************************************
75  * This function creates a new generic decoder thread, and returns a pointer
76  * to its description. On error, it returns NULL.
77  * Following configuration properties are used:
78  *  GDEC_CFG_ACTIONS    (required)
79  * XXX??
80  *****************************************************************************/
81 gdec_thread_t * gdec_CreateThread( gdec_cfg_t *p_cfg, input_thread_t *p_input,
82                                    int *pi_status )
83 {
84     gdec_thread_t * p_gdec;                             /* thread descriptor */
85     int             i_status;                               /* thread status */
86
87     /*
88      * Check configuration
89      */
90     if( CheckConfiguration( p_cfg ) )
91     {
92         return( NULL );
93     }
94
95     /* Allocate descriptor and initialize flags */
96     p_gdec = (gdec_thread_t *) malloc( sizeof(gdec_thread_t) );
97     if( p_gdec == NULL )                                            /* error */
98     {
99         return( NULL );
100     }
101
102     /* Copy configuration */
103     p_gdec->i_actions = p_cfg->i_actions;
104     /* XXX?? */
105
106     /* Set status */
107     p_gdec->pi_status = (pi_status != NULL) ? pi_status : &i_status;
108     *p_gdec->pi_status = THREAD_CREATE;
109
110     /* Initialize flags */
111     p_gdec->b_die = 0;
112     p_gdec->b_error = 0;
113     p_gdec->b_active = 1;
114
115     /* Create thread */
116     if( vlc_thread_create( &p_gdec->thread_id, "generic decoder", (vlc_thread_func)RunThread, (void *) p_gdec) )
117     {
118         intf_ErrMsg("gdec error: %s", strerror(ENOMEM));
119         intf_DbgMsg("failed");
120         free( p_gdec );
121         return( NULL );
122     }
123
124     /* If status is NULL, wait until the thread is created */
125     if( pi_status == NULL )
126     {
127         do
128         {
129             msleep( THREAD_SLEEP );
130         }while( (i_status != THREAD_READY) && (i_status != THREAD_ERROR)
131                 && (i_status != THREAD_FATAL) );
132         if( i_status != THREAD_READY )
133         {
134             intf_DbgMsg("failed");
135             return( NULL );
136         }
137     }
138
139     intf_DbgMsg("succeeded -> %p", p_gdec);
140     return( p_gdec );
141 }
142
143 /*****************************************************************************
144  * gdec_DestroyThread: destroy a generic decoder thread
145  *****************************************************************************
146  * Destroy a terminated thread. This function will return 0 if the thread could
147  * be destroyed, and non 0 else. The last case probably means that the thread
148  * was still active, and another try may succeed.
149  *****************************************************************************/
150 void gdec_DestroyThread( gdec_thread_t *p_gdec, int *pi_status )
151 {
152     int     i_status;                                       /* thread status */
153
154     /* Set status */
155     p_gdec->pi_status = (pi_status != NULL) ? pi_status : &i_status;
156     *p_gdec->pi_status = THREAD_DESTROY;
157
158     /* Request thread destruction */
159     p_gdec->b_die = 1;
160     /* Make sure the decoder thread leaves the GetByte() function */
161     vlc_mutex_lock( &(p_gdec->fifo.data_lock) );
162     vlc_cond_signal( &(p_gdec->fifo.data_wait) );
163     vlc_mutex_unlock( &(p_gdec->fifo.data_lock) );
164
165     /* If status is NULL, wait until thread has been destroyed */
166     if( pi_status )
167     {
168         do
169         {
170             msleep( THREAD_SLEEP );
171         }while( (i_status != THREAD_OVER) && (i_status != THREAD_ERROR)
172                 && (i_status != THREAD_FATAL) );
173     }
174
175     intf_DbgMsg("%p -> succeeded", p_gdec);
176 }
177
178 /* following functions are local */
179
180 /*****************************************************************************
181  * CheckConfiguration: check gdec_CreateThread() configuration
182  *****************************************************************************
183  * Set default parameters where required. In DEBUG mode, check if configuration
184  * is valid.
185  *****************************************************************************/
186 static int CheckConfiguration( gdec_cfg_t *p_cfg )
187 {
188 #ifdef DEBUG
189     /* Actions (required) */
190     if( !(p_cfg->i_properties & GDEC_CFG_ACTIONS) )
191     {
192         return( 1 );
193     }
194 #endif
195
196     return( 0 );
197 }
198
199 /*****************************************************************************
200  * InitThread: initialize gdec thread
201  *****************************************************************************
202  * This function is called from RunThread and performs the second step of the
203  * initialization. It returns 0 on success. Note that the thread's flag are not
204  * modified inside this function.
205  *****************************************************************************/
206 static int InitThread( gdec_thread_t *p_gdec )
207 {
208     /* XXX?? */
209
210     /* Update status */
211     *p_gdec->pi_status = THREAD_START;
212
213     /* Initialize other properties */
214 #ifdef STATS
215     p_gdec->c_loops = 0;
216     p_gdec->c_idle_loops = 0;
217     p_gdec->c_pes = 0;
218 #endif
219
220     /* Mark thread as running and return */
221     *p_gdec->pi_status = THREAD_READY;
222     intf_DbgMsg("%p -> succeeded", p_gdec);
223     return(0);
224 }
225
226 /*****************************************************************************
227  * RunThread: generic decoder thread
228  *****************************************************************************
229  * Generic decoder thread. This function does only returns when the thread is
230  * terminated.
231  *****************************************************************************/
232 static void RunThread( gdec_thread_t *p_gdec )
233 {
234     pes_packet_t *  p_pes;                                 /* current packet */
235     int             i_stream_id;                            /* PES stream id */
236
237     /*
238      * Initialize thread and free configuration
239      */
240     p_gdec->b_error = InitThread( p_gdec );
241     if( p_gdec->b_error )
242     {
243         free( p_gdec );                                /* destroy descriptor */
244         return;
245     }
246
247     /*
248      * Main loop - it is not executed if an error occured during
249      * initialization
250      */
251     while( (!p_gdec->b_die) && (!p_gdec->b_error) )
252     {
253         /* FIXME: locks à rajouter ?? - vérifier les macros (transformer en inline ?) */
254         /* on idle loop, increment c_idle_loops */
255         while( !DECODER_FIFO_ISEMPTY( p_gdec->fifo ) )
256         {
257             p_pes = DECODER_FIFO_START( p_gdec->fifo );
258             DECODER_FIFO_INCSTART( p_gdec->fifo );
259
260             /* Extract stream id from packet if required - stream id is used
261              * by GDEC_IDENTIFY, GDEC_SAVE_DEMUX and GDEC_PRINT */
262             if( p_gdec->i_actions & (GDEC_IDENTIFY | GDEC_SAVE_DEMUX | GDEC_PRINT) )
263             {
264                 i_stream_id = p_pes->p_pes_header[3];
265             }
266
267             /* PES identification */
268             if( p_gdec->i_actions & GDEC_IDENTIFY )
269             {
270                 IdentifyPES( p_gdec, p_pes, i_stream_id );
271             }
272
273             /* PES multiplexed stream saving */
274             if( p_gdec->i_actions & GDEC_SAVE )
275             {
276                 /* XXX?? */
277             }
278
279             /* PES demultiplexed stream saving */
280             if( p_gdec->i_actions & GDEC_SAVE_DEMUX )
281             {
282                 /* XXX?? */
283             }
284
285             /* PES information printing */
286             if( p_gdec->i_actions & GDEC_PRINT )
287             {
288                 PrintPES( p_pes, i_stream_id );
289             }
290
291             /* Trash PES packet (give it back to fifo) */
292             input_NetlistFreePES( p_gdec->p_input, p_pes );
293
294 #ifdef STATS
295             p_gdec->c_pes++;
296 #endif
297         }
298 #ifdef STATS
299         p_gdec->c_loops++;
300 #endif
301     }
302
303     /*
304      * Error loop
305      */
306     if( p_gdec->b_error )
307     {
308         ErrorThread( p_gdec );
309     }
310
311     /* End of thread */
312     EndThread( p_gdec );
313 }
314
315 /*****************************************************************************
316  * ErrorThread: RunThread() error loop
317  *****************************************************************************
318  * This function is called when an error occured during thread main's loop. The
319  * thread can still receive feed, but must be ready to terminate as soon as
320  * possible.
321  *****************************************************************************/
322 static void ErrorThread( gdec_thread_t *p_gdec )
323 {
324     pes_packet_t *  p_pes;                                     /* pes packet */
325
326     /* Wait until a `die' order */
327     while( !p_gdec->b_die )
328     {
329         /* Trash all received PES packets */
330         while( !DECODER_FIFO_ISEMPTY( p_gdec->fifo ) )
331         {
332             p_pes = DECODER_FIFO_START( p_gdec->fifo );
333             DECODER_FIFO_INCSTART( p_gdec->fifo );
334             input_NetlistFreePES( p_gdec->p_input, p_pes );
335         }
336
337         /* Sleep a while */
338         msleep( GDEC_IDLE_SLEEP );
339     }
340 }
341
342 /*****************************************************************************
343  * EndThread: thread destruction
344  *****************************************************************************
345  * This function is called when the thread ends after a sucessful
346  * initialization.
347  *****************************************************************************/
348 static void EndThread( gdec_thread_t *p_gdec )
349 {
350     int *   pi_status;                                      /* thread status */
351
352     /* Store status */
353     pi_status = p_gdec->pi_status;
354     *pi_status = THREAD_END;
355
356 #ifdef DEBUG
357     /* Check for remaining PES packets */
358     /* XXX?? */
359 #endif
360
361     /* Destroy thread structures allocated by InitThread */
362     free( p_gdec );                                    /* destroy descriptor */
363
364     *pi_status = THREAD_OVER;
365     intf_DbgMsg("%p", p_gdec);
366 }
367
368 /*****************************************************************************
369  * IdentifyPES: identify a PES packet
370  *****************************************************************************
371  * Update ES tables in the input thread according to the stream_id value. See
372  * ISO 13818-1, table 2-18.
373  *****************************************************************************/
374 static void IdentifyPES( gdec_thread_t *p_gdec, pes_packet_t *p_pes, int i_stream_id )
375 {
376     int i_id;                                       /* stream id in es table */
377     int i_type;          /* stream type according ISO/IEC 13818-1 table 2-29 */
378
379     /* Search where the elementary stream id does come from */
380     switch( p_gdec->p_input->i_method )
381     {
382     case INPUT_METHOD_TS_FILE:                   /* TS methods: id is TS PID */
383     case INPUT_METHOD_TS_UCAST:
384     case INPUT_METHOD_TS_BCAST:
385     case INPUT_METHOD_TS_VLAN_BCAST:
386         /* XXX?? since PID is extracted by demux, it could be useful to store it
387          * in a readable place, i.e. the TS packet descriptor, rather than to
388          * re-extract it now */
389         i_id = U16_AT(&p_pes->p_first_ts->buffer[1]) & 0x1fff;
390         break;
391
392 #ifdef DEBUG
393     default:                                            /* unknown id origin */
394         intf_DbgMsg("unable to identify PES using input method %d",
395                     p_gdec->p_input->i_method );
396         break;
397 #endif
398     }
399
400     /* Try to identify PES stream_id - see ISO 13818-1 table 2-18 */
401     if( i_stream_id == 0xbd )
402     {
403         /* Dolby AC-3 stream - might be specific to DVD PS streams */
404         i_type = MPEG2_AUDIO_ES;
405         intf_DbgMsg("PES %p identified as AUDIO AC3", p_pes);
406     }
407     else if( (i_stream_id & 0xe0) == 0xc0 )
408     {
409         /* ISO/IEC 13818-3 or ISO/IEC 11172-3 audio stream - since there is no
410          * way to make the difference between the two possibilities, and since
411          * an ISO/IEC 13818-3 is capable of decoding an ISO/IEC 11172-3 stream,
412          * the first one is used */
413         i_type = MPEG2_AUDIO_ES;
414         intf_DbgMsg("PES %p identified as AUDIO MPEG", p_pes);
415     }
416     else if( (i_stream_id & 0xf0) == 0xe0 )
417     {
418         /* ISO/IEC 13818-2 or ISO/IEC 11172-2 video stream - since there is no
419          * way to make the difference between the two possibilities, and since
420          * an ISO/IEC 13818-2 is capable of decoding an ISO/IEC 11172-2 stream,
421          * the first one is used */
422         i_type = MPEG2_VIDEO_ES;
423         intf_DbgMsg("PES %p identified as VIDEO", p_pes);
424     }
425     else
426     {
427         /* The stream could not be identified - just return */
428         intf_DbgMsg("PES %p could not be identified", p_pes);
429         return;
430     }
431
432     /* Update ES table */
433     /* XXX?? */
434 }
435
436 /*****************************************************************************
437  * PrintPES: print informations about a PES packet
438  *****************************************************************************
439  * This function will print information about a received PES packet. It is
440  * probably useful only for debugging purposes, or before demultiplexing a
441  * stream. It has two different formats, depending of the presence of the DEBUG
442  * symbol.
443  *****************************************************************************/
444 static void PrintPES( pes_packet_t *p_pes, int i_stream_id )
445 {
446     char psz_pes[128];                                  /* descriptor buffer */
447
448 #ifdef DEBUG
449     /* PES informations, long (DEBUG) format - this string is maximum 70 bytes
450      * long */
451     sprintf(psz_pes, "id 0x%x, %d bytes (%d TS): %p %c%c%c%c",
452             i_stream_id, p_pes->i_pes_size, p_pes->i_ts_packets,
453             p_pes,
454             p_pes->b_data_loss ? 'l' : '-', p_pes->b_data_alignment ? 'a' : '-',
455             p_pes->b_random_access ? 'r' : '-', p_pes->b_discard_payload ? 'd' : '-' );
456 #else
457     /* PES informations, short format */
458     sprintf(psz_pes, "id 0x%x, %d bytes",
459             i_stream_id, p_pes->i_pes_size );
460 #endif
461     intf_Msg("gdec: PES %s", psz_pes );
462 }