1 /*****************************************************************************
2 * generic_decoder.c : generic decoder thread
4 *****************************************************************************
5 * This decoder provides a way to parse packets which do not belong to any
6 * known stream type, or to redirect packets to files. It can extract PES files
7 * from a multiplexed stream, identify automatically ES in a stream missing
8 * stream informations (i.e. a TS stream without PSI) and update ES tables in
9 * its input thread, or just print informations about what it receives in DEBUG
11 * A single generic decoder is able to handle several ES, therefore it can be
12 * used as a 'default' decoder by the input thread.
13 *****************************************************************************/
15 /*****************************************************************************
17 *****************************************************************************/
24 #include <sys/types.h>
25 #include <sys/socket.h>
26 #include <netinet/in.h>
32 #include "vlc_thread.h"
39 #include "input_netlist.h"
40 #include "decoder_fifo.h"
42 #include "generic_decoder.h"
45 #include "video_output.h"
46 #include "video_decoder.h"*/
51 static int CheckConfiguration ( gdec_cfg_t *p_cfg );
52 static int InitThread ( gdec_thread_t *p_gdec );
53 static void RunThread ( gdec_thread_t *p_gdec );
54 static void ErrorThread ( gdec_thread_t *p_gdec );
55 static void EndThread ( gdec_thread_t *p_gdec );
57 static void IdentifyPES ( gdec_thread_t *p_gdec, pes_packet_t *p_pes,
59 static void PrintPES ( pes_packet_t *p_pes, int i_stream_id );
61 /*****************************************************************************
62 * gdec_CreateThread: create a generic decoder thread
63 *****************************************************************************
64 * This function creates a new generic decoder thread, and returns a pointer
65 * to its description. On error, it returns NULL.
66 * Following configuration properties are used:
67 * GDEC_CFG_ACTIONS (required)
69 *****************************************************************************/
70 gdec_thread_t * gdec_CreateThread( gdec_cfg_t *p_cfg, input_thread_t *p_input,
73 gdec_thread_t * p_gdec; /* thread descriptor */
74 int i_status; /* thread status */
79 if( CheckConfiguration( p_cfg ) )
84 /* Allocate descriptor and initialize flags */
85 p_gdec = (gdec_thread_t *) malloc( sizeof(gdec_thread_t) );
86 if( p_gdec == NULL ) /* error */
91 /* Copy configuration */
92 p_gdec->i_actions = p_cfg->i_actions;
96 p_gdec->pi_status = (pi_status != NULL) ? pi_status : &i_status;
97 *p_gdec->pi_status = THREAD_CREATE;
99 /* Initialize flags */
102 p_gdec->b_active = 1;
105 if( vlc_thread_create( &p_gdec->thread_id, "generic decoder", (vlc_thread_func)RunThread, (void *) p_gdec) )
107 intf_ErrMsg("gdec error: %s\n", strerror(ENOMEM));
108 intf_DbgMsg("failed\n");
113 /* If status is NULL, wait until the thread is created */
114 if( pi_status == NULL )
118 msleep( THREAD_SLEEP );
119 }while( (i_status != THREAD_READY) && (i_status != THREAD_ERROR)
120 && (i_status != THREAD_FATAL) );
121 if( i_status != THREAD_READY )
123 intf_DbgMsg("failed\n");
128 intf_DbgMsg("succeeded -> %p\n", p_gdec);
132 /*****************************************************************************
133 * gdec_DestroyThread: destroy a generic decoder thread
134 *****************************************************************************
135 * Destroy a terminated thread. This function will return 0 if the thread could
136 * be destroyed, and non 0 else. The last case probably means that the thread
137 * was still active, and another try may succeed.
138 *****************************************************************************/
139 void gdec_DestroyThread( gdec_thread_t *p_gdec, int *pi_status )
141 int i_status; /* thread status */
144 p_gdec->pi_status = (pi_status != NULL) ? pi_status : &i_status;
145 *p_gdec->pi_status = THREAD_DESTROY;
147 /* Request thread destruction */
149 /* Make sure the decoder thread leaves the GetByte() function */
150 vlc_mutex_lock( &(p_gdec->fifo.data_lock) );
151 vlc_cond_signal( &(p_gdec->fifo.data_wait) );
152 vlc_mutex_unlock( &(p_gdec->fifo.data_lock) );
154 /* If status is NULL, wait until thread has been destroyed */
159 msleep( THREAD_SLEEP );
160 }while( (i_status != THREAD_OVER) && (i_status != THREAD_ERROR)
161 && (i_status != THREAD_FATAL) );
164 intf_DbgMsg("%p -> succeeded\n", p_gdec);
167 /* following functions are local */
169 /*****************************************************************************
170 * CheckConfiguration: check gdec_CreateThread() configuration
171 *****************************************************************************
172 * Set default parameters where required. In DEBUG mode, check if configuration
174 *****************************************************************************/
175 static int CheckConfiguration( gdec_cfg_t *p_cfg )
178 /* Actions (required) */
179 if( !(p_cfg->i_properties & GDEC_CFG_ACTIONS) )
188 /*****************************************************************************
189 * InitThread: initialize gdec thread
190 *****************************************************************************
191 * This function is called from RunThread and performs the second step of the
192 * initialization. It returns 0 on success. Note that the thread's flag are not
193 * modified inside this function.
194 *****************************************************************************/
195 static int InitThread( gdec_thread_t *p_gdec )
200 *p_gdec->pi_status = THREAD_START;
202 /* Initialize other properties */
205 p_gdec->c_idle_loops = 0;
209 /* Mark thread as running and return */
210 *p_gdec->pi_status = THREAD_READY;
211 intf_DbgMsg("%p -> succeeded\n", p_gdec);
215 /*****************************************************************************
216 * RunThread: generic decoder thread
217 *****************************************************************************
218 * Generic decoder thread. This function does only returns when the thread is
220 *****************************************************************************/
221 static void RunThread( gdec_thread_t *p_gdec )
223 pes_packet_t * p_pes; /* current packet */
224 int i_stream_id; /* PES stream id */
227 * Initialize thread and free configuration
229 p_gdec->b_error = InitThread( p_gdec );
230 if( p_gdec->b_error )
232 free( p_gdec ); /* destroy descriptor */
237 * Main loop - it is not executed if an error occured during
240 while( (!p_gdec->b_die) && (!p_gdec->b_error) )
242 /* FIXME: locks à rajouter ?? - vérifier les macros (transformer en inline ?) */
243 /* on idle loop, increment c_idle_loops */
244 while( !DECODER_FIFO_ISEMPTY( p_gdec->fifo ) )
246 p_pes = DECODER_FIFO_START( p_gdec->fifo );
247 DECODER_FIFO_INCSTART( p_gdec->fifo );
249 /* Extract stream id from packet if required - stream id is used
250 * by GDEC_IDENTIFY, GDEC_SAVE_DEMUX and GDEC_PRINT */
251 if( p_gdec->i_actions & (GDEC_IDENTIFY | GDEC_SAVE_DEMUX | GDEC_PRINT) )
253 i_stream_id = p_pes->p_pes_header[3];
256 /* PES identification */
257 if( p_gdec->i_actions & GDEC_IDENTIFY )
259 IdentifyPES( p_gdec, p_pes, i_stream_id );
262 /* PES multiplexed stream saving */
263 if( p_gdec->i_actions & GDEC_SAVE )
268 /* PES demultiplexed stream saving */
269 if( p_gdec->i_actions & GDEC_SAVE_DEMUX )
274 /* PES information printing */
275 if( p_gdec->i_actions & GDEC_PRINT )
277 PrintPES( p_pes, i_stream_id );
280 /* Trash PES packet (give it back to fifo) */
281 input_NetlistFreePES( p_gdec->p_input, p_pes );
295 if( p_gdec->b_error )
297 ErrorThread( p_gdec );
304 /*****************************************************************************
305 * ErrorThread: RunThread() error loop
306 *****************************************************************************
307 * This function is called when an error occured during thread main's loop. The
308 * thread can still receive feed, but must be ready to terminate as soon as
310 *****************************************************************************/
311 static void ErrorThread( gdec_thread_t *p_gdec )
313 pes_packet_t * p_pes; /* pes packet */
315 /* Wait until a `die' order */
316 while( !p_gdec->b_die )
318 /* Trash all received PES packets */
319 while( !DECODER_FIFO_ISEMPTY( p_gdec->fifo ) )
321 p_pes = DECODER_FIFO_START( p_gdec->fifo );
322 DECODER_FIFO_INCSTART( p_gdec->fifo );
323 input_NetlistFreePES( p_gdec->p_input, p_pes );
327 msleep( GDEC_IDLE_SLEEP );
331 /*****************************************************************************
332 * EndThread: thread destruction
333 *****************************************************************************
334 * This function is called when the thread ends after a sucessfull
336 *****************************************************************************/
337 static void EndThread( gdec_thread_t *p_gdec )
339 int * pi_status; /* thread status */
342 pi_status = p_gdec->pi_status;
343 *pi_status = THREAD_END;
346 /* Check for remaining PES packets */
350 /* Destroy thread structures allocated by InitThread */
351 free( p_gdec ); /* destroy descriptor */
353 *pi_status = THREAD_OVER;
354 intf_DbgMsg("%p\n", p_gdec);
357 /*****************************************************************************
358 * IdentifyPES: identify a PES packet
359 *****************************************************************************
360 * Update ES tables in the input thread according to the stream_id value. See
361 * ISO 13818-1, table 2-18.
362 *****************************************************************************/
363 static void IdentifyPES( gdec_thread_t *p_gdec, pes_packet_t *p_pes, int i_stream_id )
365 int i_id; /* stream id in es table */
366 int i_type; /* stream type according ISO/IEC 13818-1 table 2-29 */
368 /* Search where the elementary stream id does come from */
369 switch( p_gdec->p_input->i_method )
371 case INPUT_METHOD_TS_FILE: /* TS methods: id is TS PID */
372 case INPUT_METHOD_TS_UCAST:
373 case INPUT_METHOD_TS_BCAST:
374 case INPUT_METHOD_TS_VLAN_BCAST:
375 /* XXX?? since PID is extracted by demux, it could be usefull to store it
376 * in a readable place, i.e. the TS packet descriptor, rather than to
377 * re-extract it now */
378 i_id = U16_AT(&p_pes->p_first_ts->buffer[1]) & 0x1fff;
382 default: /* unknown id origin */
383 intf_DbgMsg("unable to identify PES using input method %d\n",
384 p_gdec->p_input->i_method );
389 /* Try to identify PES stream_id - see ISO 13818-1 table 2-18 */
390 if( i_stream_id == 0xbd )
392 /* Dolby AC-3 stream - might be specific to DVD PS streams */
393 i_type = MPEG2_AUDIO_ES;
394 intf_DbgMsg("PES %p identified as AUDIO AC3\n", p_pes);
396 else if( (i_stream_id & 0xe0) == 0xc0 )
398 /* ISO/IEC 13818-3 or ISO/IEC 11172-3 audio stream - since there is no
399 * way to make the difference between the two possibilities, and since
400 * an ISO/IEC 13818-3 is capable of decoding an ISO/IEC 11172-3 stream,
401 * the first one is used */
402 i_type = MPEG2_AUDIO_ES;
403 intf_DbgMsg("PES %p identified as AUDIO MPEG\n", p_pes);
405 else if( (i_stream_id & 0xf0) == 0xe0 )
407 /* ISO/IEC 13818-2 or ISO/IEC 11172-2 video stream - since there is no
408 * way to make the difference between the two possibilities, and since
409 * an ISO/IEC 13818-2 is capable of decoding an ISO/IEC 11172-2 stream,
410 * the first one is used */
411 i_type = MPEG2_VIDEO_ES;
412 intf_DbgMsg("PES %p identified as VIDEO\n", p_pes);
416 /* The stream could not be identified - just return */
417 intf_DbgMsg("PES %p could not be identified\n", p_pes);
421 /* Update ES table */
425 /*****************************************************************************
426 * PrintPES: print informations about a PES packet
427 *****************************************************************************
428 * This function will print information about a received PES packet. It is
429 * probably usefull only for debugging purposes, or before demultiplexing a
430 * stream. It has two different formats, depending of the presence of the DEBUG
432 *****************************************************************************/
433 static void PrintPES( pes_packet_t *p_pes, int i_stream_id )
435 char psz_pes[128]; /* descriptor buffer */
438 /* PES informations, long (DEBUG) format - this string is maximum 70 bytes
440 sprintf(psz_pes, "id 0x%x, %d bytes (%d TS): %p %c%c%c%c",
441 i_stream_id, p_pes->i_pes_size, p_pes->i_ts_packets,
443 p_pes->b_data_loss ? 'l' : '-', p_pes->b_data_alignment ? 'a' : '-',
444 p_pes->b_random_access ? 'r' : '-', p_pes->b_discard_payload ? 'd' : '-' );
446 /* PES informations, short format */
447 sprintf(psz_pes, "id 0x%x, %d bytes",
448 i_stream_id, p_pes->i_pes_size );
450 intf_Msg("gdec: PES %s\n", psz_pes );