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
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
14 * Authors: Vincent Seguin <seguin@via.ecp.fr>
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.
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.
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 *****************************************************************************/
31 /*****************************************************************************
33 *****************************************************************************/
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 */
56 #include "input_netlist.h"
57 #include "decoder_fifo.h"
59 #include "generic_decoder.h"
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 );
70 static void IdentifyPES ( gdec_thread_t *p_gdec, pes_packet_t *p_pes,
72 static void PrintPES ( pes_packet_t *p_pes, int i_stream_id );
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)
82 *****************************************************************************/
83 gdec_thread_t * gdec_CreateThread( gdec_cfg_t *p_cfg, input_thread_t *p_input,
86 gdec_thread_t * p_gdec; /* thread descriptor */
87 int i_status; /* thread status */
92 if( CheckConfiguration( p_cfg ) )
97 /* Allocate descriptor and initialize flags */
98 p_gdec = (gdec_thread_t *) malloc( sizeof(gdec_thread_t) );
99 if( p_gdec == NULL ) /* error */
104 /* Copy configuration */
105 p_gdec->i_actions = p_cfg->i_actions;
109 p_gdec->pi_status = (pi_status != NULL) ? pi_status : &i_status;
110 *p_gdec->pi_status = THREAD_CREATE;
112 /* Initialize flags */
115 p_gdec->b_active = 1;
118 if( vlc_thread_create( &p_gdec->thread_id, "generic decoder", (vlc_thread_func)RunThread, (void *) p_gdec) )
120 intf_ErrMsg("gdec error: %s\n", strerror(ENOMEM));
121 intf_DbgMsg("failed\n");
126 /* If status is NULL, wait until the thread is created */
127 if( pi_status == NULL )
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 )
136 intf_DbgMsg("failed\n");
141 intf_DbgMsg("succeeded -> %p\n", p_gdec);
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 )
154 int i_status; /* thread status */
157 p_gdec->pi_status = (pi_status != NULL) ? pi_status : &i_status;
158 *p_gdec->pi_status = THREAD_DESTROY;
160 /* Request thread destruction */
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) );
167 /* If status is NULL, wait until thread has been destroyed */
172 msleep( THREAD_SLEEP );
173 }while( (i_status != THREAD_OVER) && (i_status != THREAD_ERROR)
174 && (i_status != THREAD_FATAL) );
177 intf_DbgMsg("%p -> succeeded\n", p_gdec);
180 /* following functions are local */
182 /*****************************************************************************
183 * CheckConfiguration: check gdec_CreateThread() configuration
184 *****************************************************************************
185 * Set default parameters where required. In DEBUG mode, check if configuration
187 *****************************************************************************/
188 static int CheckConfiguration( gdec_cfg_t *p_cfg )
191 /* Actions (required) */
192 if( !(p_cfg->i_properties & GDEC_CFG_ACTIONS) )
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 )
213 *p_gdec->pi_status = THREAD_START;
215 /* Initialize other properties */
218 p_gdec->c_idle_loops = 0;
222 /* Mark thread as running and return */
223 *p_gdec->pi_status = THREAD_READY;
224 intf_DbgMsg("%p -> succeeded\n", p_gdec);
228 /*****************************************************************************
229 * RunThread: generic decoder thread
230 *****************************************************************************
231 * Generic decoder thread. This function does only returns when the thread is
233 *****************************************************************************/
234 static void RunThread( gdec_thread_t *p_gdec )
236 pes_packet_t * p_pes; /* current packet */
237 int i_stream_id; /* PES stream id */
240 * Initialize thread and free configuration
242 p_gdec->b_error = InitThread( p_gdec );
243 if( p_gdec->b_error )
245 free( p_gdec ); /* destroy descriptor */
250 * Main loop - it is not executed if an error occured during
253 while( (!p_gdec->b_die) && (!p_gdec->b_error) )
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 ) )
259 p_pes = DECODER_FIFO_START( p_gdec->fifo );
260 DECODER_FIFO_INCSTART( p_gdec->fifo );
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) )
266 i_stream_id = p_pes->p_pes_header[3];
269 /* PES identification */
270 if( p_gdec->i_actions & GDEC_IDENTIFY )
272 IdentifyPES( p_gdec, p_pes, i_stream_id );
275 /* PES multiplexed stream saving */
276 if( p_gdec->i_actions & GDEC_SAVE )
281 /* PES demultiplexed stream saving */
282 if( p_gdec->i_actions & GDEC_SAVE_DEMUX )
287 /* PES information printing */
288 if( p_gdec->i_actions & GDEC_PRINT )
290 PrintPES( p_pes, i_stream_id );
293 /* Trash PES packet (give it back to fifo) */
294 input_NetlistFreePES( p_gdec->p_input, p_pes );
308 if( p_gdec->b_error )
310 ErrorThread( p_gdec );
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
323 *****************************************************************************/
324 static void ErrorThread( gdec_thread_t *p_gdec )
326 pes_packet_t * p_pes; /* pes packet */
328 /* Wait until a `die' order */
329 while( !p_gdec->b_die )
331 /* Trash all received PES packets */
332 while( !DECODER_FIFO_ISEMPTY( p_gdec->fifo ) )
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 );
340 msleep( GDEC_IDLE_SLEEP );
344 /*****************************************************************************
345 * EndThread: thread destruction
346 *****************************************************************************
347 * This function is called when the thread ends after a sucessful
349 *****************************************************************************/
350 static void EndThread( gdec_thread_t *p_gdec )
352 int * pi_status; /* thread status */
355 pi_status = p_gdec->pi_status;
356 *pi_status = THREAD_END;
359 /* Check for remaining PES packets */
363 /* Destroy thread structures allocated by InitThread */
364 free( p_gdec ); /* destroy descriptor */
366 *pi_status = THREAD_OVER;
367 intf_DbgMsg("%p\n", p_gdec);
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 )
378 int i_id; /* stream id in es table */
379 int i_type; /* stream type according ISO/IEC 13818-1 table 2-29 */
381 /* Search where the elementary stream id does come from */
382 switch( p_gdec->p_input->i_method )
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;
395 default: /* unknown id origin */
396 intf_DbgMsg("unable to identify PES using input method %d\n",
397 p_gdec->p_input->i_method );
402 /* Try to identify PES stream_id - see ISO 13818-1 table 2-18 */
403 if( i_stream_id == 0xbd )
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);
409 else if( (i_stream_id & 0xe0) == 0xc0 )
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);
418 else if( (i_stream_id & 0xf0) == 0xe0 )
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);
429 /* The stream could not be identified - just return */
430 intf_DbgMsg("PES %p could not be identified\n", p_pes);
434 /* Update ES table */
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
445 *****************************************************************************/
446 static void PrintPES( pes_packet_t *p_pes, int i_stream_id )
448 char psz_pes[128]; /* descriptor buffer */
451 /* PES informations, long (DEBUG) format - this string is maximum 70 bytes
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,
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' : '-' );
459 /* PES informations, short format */
460 sprintf(psz_pes, "id 0x%x, %d bytes",
461 i_stream_id, p_pes->i_pes_size );
463 intf_Msg("gdec: PES %s\n", psz_pes );