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