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