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