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