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