]> git.sesse.net Git - vlc/blob - src/input/input_programs.c
* ./configure.ac.in: removed -W in favour of -Wtraditional.
[vlc] / src / input / input_programs.c
1 /*****************************************************************************
2  * input_programs.c: es_descriptor_t, pgrm_descriptor_t management
3  *****************************************************************************
4  * Copyright (C) 1999-2002 VideoLAN
5  * $Id: input_programs.c,v 1.99 2002/12/06 16:34:08 sam Exp $
6  *
7  * Authors: Christophe Massiot <massiot@via.ecp.fr>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <stdlib.h>
28 #include <string.h>                                    /* memcpy(), memset() */
29
30 #include <vlc/vlc.h>
31
32 #include "stream_control.h"
33 #include "input_ext-intf.h"
34 #include "input_ext-dec.h"
35 #include "input_ext-plugins.h"
36
37 /*
38  * NOTICE : all of these functions expect you to have taken the lock on
39  * p_input->stream.lock
40  */
41
42 /*****************************************************************************
43  * input_InitStream: init the stream descriptor of the given input
44  *****************************************************************************/
45 int input_InitStream( input_thread_t * p_input, size_t i_data_len )
46 {
47
48     p_input->stream.i_stream_id = 0;
49
50     /* initialized to 0 since we don't give the signal to the interface
51      * before the end of input initialization */
52     p_input->stream.b_changed = 0;
53     p_input->stream.pp_es = NULL;
54     p_input->stream.pp_selected_es = NULL;
55     p_input->stream.p_removed_es = NULL;
56     p_input->stream.p_newly_selected_es = NULL;
57     p_input->stream.pp_programs = NULL;
58     p_input->stream.p_selected_program = NULL;
59     p_input->stream.p_new_program = NULL;
60
61     if( i_data_len )
62     {
63         if ( (p_input->stream.p_demux_data = malloc( i_data_len )) == NULL )
64         {
65             msg_Err( p_input, "out of memory" );
66             return 1;
67         }
68         memset( p_input->stream.p_demux_data, 0, i_data_len );
69     }
70     else
71     {
72         p_input->stream.p_demux_data = NULL;
73     }
74
75     return 0;
76 }
77
78 /*****************************************************************************
79  * input_EndStream: free all stream descriptors
80  *****************************************************************************/
81 void input_EndStream( input_thread_t * p_input )
82 {
83     /* Free all programs and associated ES, and associated decoders. */
84     while( p_input->stream.i_pgrm_number )
85     {
86         input_DelProgram( p_input, p_input->stream.pp_programs[0] );
87     }
88
89     /* Free standalone ES */
90     while( p_input->stream.i_es_number )
91     {
92         input_DelES( p_input, p_input->stream.pp_es[0] );
93     }
94
95     /* Free all areas */
96     while( p_input->stream.i_area_nb )
97     {
98         input_DelArea( p_input, p_input->stream.pp_areas[0] );
99     }
100
101     /* Free selected ES */
102     if( p_input->stream.pp_selected_es != NULL )
103     {
104         free( p_input->stream.pp_selected_es );
105     }
106
107     if( p_input->stream.p_demux_data != NULL )
108     {
109         free( p_input->stream.p_demux_data );
110     }
111 }
112
113 /*****************************************************************************
114  * input_FindProgram: returns a pointer to a program described by its ID
115  *****************************************************************************/
116 pgrm_descriptor_t * input_FindProgram( input_thread_t * p_input,
117                                        uint16_t i_pgrm_id )
118 {
119     unsigned int i;
120
121     for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
122     {
123         if( p_input->stream.pp_programs[i]->i_number == i_pgrm_id )
124         {
125             return p_input->stream.pp_programs[i];
126         }
127     }
128
129     return NULL;
130 }
131
132 /*****************************************************************************
133  * input_AddProgram: add and init a program descriptor
134  *****************************************************************************
135  * This program descriptor will be referenced in the given stream descriptor
136  *****************************************************************************/
137 pgrm_descriptor_t * input_AddProgram( input_thread_t * p_input,
138                                       u16 i_pgrm_id, size_t i_data_len )
139 {
140     /* Where to add the pgrm */
141     pgrm_descriptor_t * p_pgrm = malloc( sizeof(pgrm_descriptor_t) );
142
143     if( p_pgrm == NULL )
144     {
145         msg_Err( p_input, "out of memory" );
146         return NULL;
147     }
148
149     /* Init this entry */
150     p_pgrm->i_number = i_pgrm_id;
151     p_pgrm->b_is_ok = 0;
152     p_pgrm->i_version = 0;
153
154     p_pgrm->i_es_number = 0;
155     p_pgrm->pp_es = NULL;
156
157     input_ClockInit( p_pgrm );
158
159     p_pgrm->i_synchro_state = SYNCHRO_START;
160
161     if( i_data_len )
162     {
163         p_pgrm->p_demux_data = malloc( i_data_len );
164         if( p_pgrm->p_demux_data == NULL )
165         {
166             msg_Err( p_input, "out of memory" );
167             return NULL;
168         }
169         memset( p_pgrm->p_demux_data, 0, i_data_len );
170     }
171     else
172     {
173         p_pgrm->p_demux_data = NULL;
174     }
175
176     /* Add an entry to the list of program associated with the stream */
177     INSERT_ELEM( p_input->stream.pp_programs,
178                  p_input->stream.i_pgrm_number,
179                  p_input->stream.i_pgrm_number,
180                  p_pgrm );
181
182     return p_pgrm;
183 }
184
185 /*****************************************************************************
186  * input_DelProgram: destroy a program descriptor
187  *****************************************************************************
188  * All ES descriptions referenced in the descriptor will be deleted.
189  *****************************************************************************/
190 void input_DelProgram( input_thread_t * p_input, pgrm_descriptor_t * p_pgrm )
191 {
192     unsigned int i_pgrm_index;
193
194     /* Find the program in the programs table */
195     for( i_pgrm_index = 0; i_pgrm_index < p_input->stream.i_pgrm_number;
196          i_pgrm_index++ )
197     {
198         if( p_input->stream.pp_programs[i_pgrm_index] == p_pgrm )
199             break;
200     }
201
202     /* If the program wasn't found, do nothing */
203     if( i_pgrm_index == p_input->stream.i_pgrm_number )
204     {
205         msg_Err( p_input, "program does not belong to this input" );
206         return;
207     }
208
209     /* Free the structures that describe the es that belongs to that program */
210     while( p_pgrm->i_es_number )
211     {
212         input_DelES( p_input, p_pgrm->pp_es[0] );
213     }
214
215     /* Free the demux data */
216     if( p_pgrm->p_demux_data != NULL )
217     {
218         free( p_pgrm->p_demux_data );
219     }
220
221     /* Remove this program from the stream's list of programs */
222     REMOVE_ELEM( p_input->stream.pp_programs,
223                  p_input->stream.i_pgrm_number,
224                  i_pgrm_index );
225
226     /* Free the description of this program */
227     free( p_pgrm );
228 }
229
230 /*****************************************************************************
231  * input_AddArea: add and init an area descriptor
232  *****************************************************************************
233  * This area descriptor will be referenced in the given stream descriptor
234  *****************************************************************************/
235 input_area_t * input_AddArea( input_thread_t * p_input )
236 {
237     /* Where to add the pgrm */
238     input_area_t * p_area = malloc( sizeof(input_area_t) );
239
240     if( p_area == NULL )
241     {
242         msg_Err( p_input, "out of memory" );
243         return NULL;
244     }
245
246     /* Init this entry */
247     p_area->i_id = 0;
248     p_area->i_start = 0;
249     p_area->i_size = 0;
250     p_area->i_tell = 0;
251     p_area->i_seek = NO_SEEK;
252     p_area->i_part_nb = 1;
253     p_area->i_part= 0;
254
255     /* Add an entry to the list of program associated with the stream */
256     INSERT_ELEM( p_input->stream.pp_areas,
257                  p_input->stream.i_area_nb,
258                  p_input->stream.i_area_nb,
259                  p_area );
260
261     return p_area;
262 }
263
264 /*****************************************************************************
265  * input_SetProgram: changes the current program
266  *****************************************************************************/
267 int input_SetProgram( input_thread_t * p_input, pgrm_descriptor_t * p_new_prg )
268 {
269     unsigned int i_es_index;
270     unsigned int i_required_audio_es;
271     unsigned int i_required_spu_es;
272     unsigned int i_audio_es = 0;
273     unsigned int i_spu_es = 0;
274
275     if ( p_input->stream.p_selected_program )
276     {
277         for ( i_es_index = 1 ; /* 0 should be the PMT */
278                 i_es_index < p_input->stream.p_selected_program->
279                 i_es_number ;
280                 i_es_index ++ )
281         {
282 #define p_es p_input->stream.p_selected_program->pp_es[i_es_index]
283             if ( p_es->p_decoder_fifo ) /* if the ES was selected */
284             {
285                 input_UnselectES( p_input , p_es );
286             }
287 #undef p_es
288         }
289     }
290     /* Get the number of the required audio stream */
291     if( config_GetInt( p_input, "audio" ) )
292     {
293         /* Default is the first one */
294         i_required_audio_es = config_GetInt( p_input, "audio-channel" );
295         if( i_required_audio_es < 0 )
296         {
297             i_required_audio_es = 1;
298         }
299     }
300     else
301     {
302         i_required_audio_es = 0;
303     }
304
305     /* Same thing for subtitles */
306     if( config_GetInt( p_input, "video" ) )
307     {
308         /* for spu, default is none */
309         i_required_spu_es = config_GetInt( p_input, "spu-channel" );
310         if( i_required_spu_es < 0 )
311         {
312             i_required_spu_es = 0;
313         }
314     }
315     else
316     {
317         i_required_spu_es = 0;
318     }
319
320     for( i_es_index = 0 ; i_es_index < p_new_prg->i_es_number ; i_es_index ++ )
321     {
322         switch( p_new_prg->pp_es[i_es_index]->i_cat )
323         {
324             case VIDEO_ES:
325                 msg_Dbg( p_input, "selecting ES %x",
326                          p_new_prg->pp_es[i_es_index]->i_id );
327                 input_SelectES( p_input, p_new_prg->pp_es[i_es_index] );
328                 break;
329             case AUDIO_ES:
330                 i_audio_es += 1;
331                 if( i_audio_es <= i_required_audio_es )
332                 {
333                     msg_Dbg( p_input, "selecting ES %x",
334                              p_new_prg->pp_es[i_es_index]->i_id );
335                     input_SelectES( p_input, p_new_prg->pp_es[i_es_index]);
336                 }
337                 break;
338             /* Not sure this one is fully specification-compliant */
339             case SPU_ES :
340                 i_spu_es += 1;
341                 if( i_spu_es <= i_required_spu_es )
342                 {
343                     msg_Dbg( p_input, "selecting ES %x",
344                              p_new_prg->pp_es[i_es_index]->i_id );
345                     input_SelectES( p_input, p_new_prg->pp_es[i_es_index] );
346                 }
347             break;
348             default :
349                 msg_Dbg( p_input, "ES %x has unknown type",
350                          p_new_prg->pp_es[i_es_index]->i_id );
351                 break;
352         }
353
354     }
355
356
357     p_input->stream.p_selected_program = p_new_prg;
358
359     return( 0 );
360 }
361
362
363 /*****************************************************************************
364  * input_DelArea: destroy a area descriptor
365  *****************************************************************************
366  * All ES descriptions referenced in the descriptor will be deleted.
367  *****************************************************************************/
368 void input_DelArea( input_thread_t * p_input, input_area_t * p_area )
369 {
370     unsigned int i_area_index;
371
372     /* Find the area in the areas table */
373     for( i_area_index = 0; i_area_index < p_input->stream.i_area_nb;
374          i_area_index++ )
375     {
376         if( p_input->stream.pp_areas[i_area_index] == p_area )
377             break;
378     }
379
380     /* If the area wasn't found, do nothing */
381     if( i_area_index == p_input->stream.i_area_nb )
382     {
383         msg_Err( p_input, "area does not belong to this input" );
384         return;
385     }
386
387     /* Remove this area from the stream's list of areas */
388     REMOVE_ELEM( p_input->stream.pp_areas,
389                  p_input->stream.i_area_nb,
390                  i_area_index );
391
392     /* Free the description of this area */
393     free( p_area );
394 }
395
396
397 /*****************************************************************************
398  * input_FindES: returns a pointer to an ES described by its ID
399  *****************************************************************************/
400 es_descriptor_t * input_FindES( input_thread_t * p_input, uint16_t i_es_id )
401 {
402     unsigned int i;
403
404     for( i = 0; i < p_input->stream.i_es_number; i++ )
405     {
406         if( p_input->stream.pp_es[i]->i_id == i_es_id )
407         {
408             return p_input->stream.pp_es[i];
409         }
410     }
411
412     return NULL;
413 }
414
415 /*****************************************************************************
416  * input_AddES:
417  *****************************************************************************
418  * Reserve a slot in the table of ES descriptors for the ES and add it to the
419  * list of ES of p_pgrm. If p_pgrm if NULL, then the ES is considered as stand
420  * alone (PSI ?)
421  *****************************************************************************/
422 es_descriptor_t * input_AddES( input_thread_t * p_input,
423                                pgrm_descriptor_t * p_pgrm, u16 i_es_id,
424                                size_t i_data_len )
425 {
426     es_descriptor_t * p_es;
427
428     p_es = (es_descriptor_t *)malloc( sizeof(es_descriptor_t) );
429     if( p_es == NULL )
430     {
431         msg_Err( p_input, "out of memory" );
432         return( NULL);
433     }
434
435     INSERT_ELEM( p_input->stream.pp_es,
436                  p_input->stream.i_es_number,
437                  p_input->stream.i_es_number,
438                  p_es );
439
440     /* Init its values */
441     p_es->i_id = i_es_id;
442     p_es->psz_desc[0] = '\0';
443     p_es->p_pes = NULL;
444     p_es->p_decoder_fifo = NULL;
445     p_es->i_cat = UNKNOWN_ES;
446     p_es->i_demux_fd = 0;
447     p_es->c_packets = 0;
448     p_es->c_invalid_packets = 0;
449
450     if( i_data_len )
451     {
452         p_es->p_demux_data = malloc( i_data_len );
453         if( p_es->p_demux_data == NULL )
454         {
455             msg_Err( p_input, "out of memory" );
456             return( NULL );
457         }
458         memset( p_es->p_demux_data, 0, i_data_len );
459     }
460     else
461     {
462         p_es->p_demux_data = NULL;
463     }
464
465     /* Add this ES to the program definition if one is given */
466     if( p_pgrm )
467     {
468         INSERT_ELEM( p_pgrm->pp_es,
469                      p_pgrm->i_es_number,
470                      p_pgrm->i_es_number,
471                      p_es );
472         p_es->p_pgrm = p_pgrm;
473     }
474     else
475     {
476         p_es->p_pgrm = NULL;
477     }
478
479     return p_es;
480 }
481
482 /*****************************************************************************
483  * input_DelES:
484  *****************************************************************************/
485 void input_DelES( input_thread_t * p_input, es_descriptor_t * p_es )
486 {
487     unsigned int            i_index, i_es_index;
488     pgrm_descriptor_t *     p_pgrm;
489
490     /* Find the ES in the ES table */
491     for( i_es_index = 0; i_es_index < p_input->stream.i_es_number;
492          i_es_index++ )
493     {
494         if( p_input->stream.pp_es[i_es_index] == p_es )
495             break;
496     }
497
498     /* If the ES wasn't found, do nothing */
499     if( i_es_index == p_input->stream.i_es_number )
500     {
501         msg_Err( p_input, "ES does not belong to this input" );
502         return;
503     }
504
505     p_pgrm = p_es->p_pgrm;
506
507     /* Kill associated decoder, if any. */
508     if( p_es->p_decoder_fifo != NULL )
509     {
510         input_EndDecoder( p_input, p_es );
511     }
512
513     /* Remove this ES from the description of the program if it is associated to
514      * one */
515     if( p_pgrm )
516     {
517         for( i_index = 0; i_index < p_pgrm->i_es_number; i_index++ )
518         {
519             if( p_pgrm->pp_es[i_index] == p_es )
520             {
521                 REMOVE_ELEM( p_pgrm->pp_es,
522                              p_pgrm->i_es_number,
523                              i_index );
524                 break;
525             }
526         }
527     }
528
529     /* Free the demux data */
530     if( p_es->p_demux_data != NULL )
531     {
532         free( p_es->p_demux_data );
533     }
534
535     /* Find the ES in the ES table */
536     for( i_es_index = 0; i_es_index < p_input->stream.i_es_number;
537          i_es_index++ )
538     {
539         if( p_input->stream.pp_es[i_es_index] == p_es )
540             break;
541     }
542
543     /* Remove this ES from the stream's list of ES */
544     REMOVE_ELEM( p_input->stream.pp_es,
545                  p_input->stream.i_es_number,
546                  i_es_index );
547
548     /* Free the ES */
549     free( p_es );
550 }
551
552 /*****************************************************************************
553  * input_SelectES: selects an ES and spawns the associated decoder
554  *****************************************************************************
555  * Remember we are still supposed to have stream_lock when entering this
556  * function ?
557  *****************************************************************************/
558 int input_SelectES( input_thread_t * p_input, es_descriptor_t * p_es )
559 {
560     if( p_es == NULL )
561     {
562         msg_Err( p_input, "nothing to do in input_SelectES" );
563         return -1;
564     }
565
566     if( ((p_es->i_cat == VIDEO_ES) || (p_es->i_cat == SPU_ES))
567         && !config_GetInt( p_input, "video" ) )
568     {
569         msg_Dbg( p_input,
570                  "video is disabled, not selecting ES 0x%x", p_es->i_id );
571         return -1;
572     }
573
574     if( (p_es->i_cat == AUDIO_ES) && !config_GetInt( p_input, "audio" ) )
575     {
576         msg_Dbg( p_input,
577                  "audio is disabled, not selecting ES 0x%x", p_es->i_id );
578         return -1;
579     }
580
581     msg_Dbg( p_input, "selecting ES 0x%x", p_es->i_id );
582
583     if( p_es->p_decoder_fifo != NULL )
584     {
585         msg_Err( p_input, "ES 0x%x is already selected", p_es->i_id );
586         return -1;
587     }
588
589     /* Release the lock, not to block the input thread during
590      * the creation of the thread. */
591     vlc_mutex_unlock( &p_input->stream.stream_lock );
592     p_es->p_decoder_fifo = input_RunDecoder( p_input, p_es );
593     vlc_mutex_lock( &p_input->stream.stream_lock );
594
595     if( p_es->p_decoder_fifo == NULL )
596     {
597         return -1;
598     }
599
600     return 0;
601 }
602
603 /*****************************************************************************
604  * input_UnselectES: removes an ES from the list of selected ES
605  *****************************************************************************/
606 int input_UnselectES( input_thread_t * p_input, es_descriptor_t * p_es )
607 {
608
609     unsigned int i_index = 0;
610
611     if( p_es == NULL )
612     {
613         msg_Err( p_input, "nothing to do in input_UnselectES" );
614         return -1;
615     }
616
617     msg_Dbg( p_input, "unselecting ES 0x%x", p_es->i_id );
618
619     if( p_es->p_decoder_fifo == NULL )
620     {
621         msg_Err( p_input, "ES 0x%x is not selected", p_es->i_id );
622         return( -1 );
623     }
624
625     input_EndDecoder( p_input, p_es );
626     p_es->p_pes = NULL;
627
628     if( ( p_es->p_decoder_fifo == NULL ) &&
629         ( p_input->stream.i_selected_es_number > 0 ) )
630     {
631         while( ( i_index < p_input->stream.i_selected_es_number - 1 ) &&
632                ( p_input->stream.pp_selected_es[i_index] != p_es ) )
633         {
634             i_index++;
635         }
636
637         /* XXX: no need to memmove, we have unsorted data */
638         REMOVE_ELEM( p_input->stream.pp_selected_es,
639                      p_input->stream.i_selected_es_number,
640                      i_index );
641
642         if( p_input->stream.i_selected_es_number == 0 )
643         {
644             msg_Dbg( p_input, "no more selected ES" );
645             return 1;
646         }
647     }
648
649     return 0;
650 }