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