input_programs.c 26.2 KB
Newer Older
1
2
3
/*****************************************************************************
 * input_programs.c: es_descriptor_t, pgrm_descriptor_t management
 *****************************************************************************
4
 * Copyright (C) 1999-2002 VideoLAN
gbazin's avatar
   
gbazin committed
5
 * $Id: input_programs.c,v 1.105 2003/05/04 22:42:17 gbazin Exp $
6
 *
7
 * Authors: Christophe Massiot <massiot@via.ecp.fr>
8
9
10
11
12
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
13
 *
14
15
16
17
18
19
20
21
22
23
24
25
26
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
27
#include <stdlib.h>
Sam Hocevar's avatar
   
Sam Hocevar committed
28
#include <string.h>                                    /* memcpy(), memset() */
29

30
#include <vlc/vlc.h>
31
32
33
34

#include "stream_control.h"
#include "input_ext-intf.h"
#include "input_ext-dec.h"
35
#include "input_ext-plugins.h"
36
37
38
39
40

/*
 * NOTICE : all of these functions expect you to have taken the lock on
 * p_input->stream.lock
 */
41

gbazin's avatar
   
gbazin committed
42
43
44
45
46
47
48
49
50
51
/* Navigation callbacks */
static int ProgramCallback( vlc_object_t *, char const *,
                            vlc_value_t, vlc_value_t, void * );
static int TitleCallback( vlc_object_t *, char const *,
                          vlc_value_t, vlc_value_t, void * );
static int ChapterCallback( vlc_object_t *, char const *,
                            vlc_value_t, vlc_value_t, void * );
static int NavigationCallback( vlc_object_t *, char const *,
                               vlc_value_t, vlc_value_t, void * );

52
53
54
/*****************************************************************************
 * input_InitStream: init the stream descriptor of the given input
 *****************************************************************************/
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
61
62

    /* initialized to 0 since we don't give the signal to the interface
     * before the end of input initialization */
    p_input->stream.b_changed = 0;
63
64
    p_input->stream.pp_es = NULL;
    p_input->stream.pp_selected_es = NULL;
65
66
    p_input->stream.p_removed_es = NULL;
    p_input->stream.p_newly_selected_es = NULL;
67
    p_input->stream.pp_programs = NULL;
68
69
    p_input->stream.p_selected_program = NULL;
    p_input->stream.p_new_program = NULL;
70

71
72
    if( i_data_len )
    {
Henri Fallon's avatar
   
Henri Fallon committed
73
74
        if ( (p_input->stream.p_demux_data = malloc( i_data_len )) == NULL )
        {
75
            msg_Err( p_input, "out of memory" );
76
            return 1;
Henri Fallon's avatar
   
Henri Fallon committed
77
        }
78
79
        memset( p_input->stream.p_demux_data, 0, i_data_len );
    }
80
81
82
83
    else
    {
        p_input->stream.p_demux_data = NULL;
    }
84

gbazin's avatar
   
gbazin committed
85
86
87
88
89
90
91
92
93
    /* Create a few object variables used for navigation in the interfaces */
    var_Create( p_input, "program", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
    var_Create( p_input, "title", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
    var_Create( p_input, "chapter", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
    var_Create( p_input, "navigation", VLC_VAR_VARIABLE | VLC_VAR_HASCHOICE );
    var_AddCallback( p_input, "program", ProgramCallback, NULL );
    var_AddCallback( p_input, "title", TitleCallback, NULL );
    var_AddCallback( p_input, "chapter", ChapterCallback, NULL );

94
    return 0;
95
96
}

97
98
99
100
101
/*****************************************************************************
 * input_EndStream: free all stream descriptors
 *****************************************************************************/
void input_EndStream( input_thread_t * p_input )
{
gbazin's avatar
   
gbazin committed
102
103
104
105
106
    /* Free navigation variables */
    var_Destroy( p_input, "program" );
    var_Destroy( p_input, "title" );
    var_Destroy( p_input, "chapter" );

107
    /* Free all programs and associated ES, and associated decoders. */
108
    while( p_input->stream.i_pgrm_number )
109
    {
110
111
        input_DelProgram( p_input, p_input->stream.pp_programs[0] );
    }
112

113
    /* Free standalone ES */
114
    while( p_input->stream.i_es_number )
115
116
117
    {
        input_DelES( p_input, p_input->stream.pp_es[0] );
    }
118

119
120
121
122
123
124
    /* Free all areas */
    while( p_input->stream.i_area_nb )
    {
        input_DelArea( p_input, p_input->stream.pp_areas[0] );
    }

125
126
127
128
129
    /* Free selected ES */
    if( p_input->stream.pp_selected_es != NULL )
    {
        free( p_input->stream.pp_selected_es );
    }
130

131
132
133
134
    if( p_input->stream.p_demux_data != NULL )
    {
        free( p_input->stream.p_demux_data );
    }
135
136
137
138
139
}

/*****************************************************************************
 * input_FindProgram: returns a pointer to a program described by its ID
 *****************************************************************************/
140
141
pgrm_descriptor_t * input_FindProgram( input_thread_t * p_input,
                                       uint16_t i_pgrm_id )
142
{
143
    unsigned int i;
144
145
146
147

    for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
    {
        if( p_input->stream.pp_programs[i]->i_number == i_pgrm_id )
148
        {
149
            return p_input->stream.pp_programs[i];
150
151
        }
    }
152

gbazin's avatar
   
gbazin committed
153
    return NULL;
154
155
}

156
157
158
159
160
161
/*****************************************************************************
 * input_AddProgram: add and init a program descriptor
 *****************************************************************************
 * This program descriptor will be referenced in the given stream descriptor
 *****************************************************************************/
pgrm_descriptor_t * input_AddProgram( input_thread_t * p_input,
162
                                      u16 i_pgrm_id, size_t i_data_len )
163
{
164
    /* Where to add the pgrm */
165
    pgrm_descriptor_t * p_pgrm = malloc( sizeof(pgrm_descriptor_t) );
gbazin's avatar
   
gbazin committed
166
    vlc_value_t val;
167

168
    if( p_pgrm == NULL )
Henri Fallon's avatar
   
Henri Fallon committed
169
    {
170
        msg_Err( p_input, "out of memory" );
171
        return NULL;
Henri Fallon's avatar
   
Henri Fallon committed
172
    }
gbazin's avatar
   
gbazin committed
173

174
    /* Init this entry */
175
176
177
    p_pgrm->i_number = i_pgrm_id;
    p_pgrm->b_is_ok = 0;
    p_pgrm->i_version = 0;
178

179
180
    p_pgrm->i_es_number = 0;
    p_pgrm->pp_es = NULL;
181

182
    input_ClockInit( p_pgrm );
183

184
    p_pgrm->i_synchro_state = SYNCHRO_START;
185

186
187
    if( i_data_len )
    {
188
189
        p_pgrm->p_demux_data = malloc( i_data_len );
        if( p_pgrm->p_demux_data == NULL )
Henri Fallon's avatar
   
Henri Fallon committed
190
        {
191
            msg_Err( p_input, "out of memory" );
192
            return NULL;
Henri Fallon's avatar
   
Henri Fallon committed
193
        }
194
        memset( p_pgrm->p_demux_data, 0, i_data_len );
195
    }
196
197
    else
    {
198
        p_pgrm->p_demux_data = NULL;
199
    }
200

201
202
203
204
205
206
    /* Add an entry to the list of program associated with the stream */
    INSERT_ELEM( p_input->stream.pp_programs,
                 p_input->stream.i_pgrm_number,
                 p_input->stream.i_pgrm_number,
                 p_pgrm );

gbazin's avatar
   
gbazin committed
207
    val.i_int = i_pgrm_id;
gbazin's avatar
   
gbazin committed
208
    var_Change( p_input, "program", VLC_VAR_ADDCHOICE, &val, NULL );
gbazin's avatar
   
gbazin committed
209

210
    return p_pgrm;
211
212
213
214
215
216
217
}

/*****************************************************************************
 * input_DelProgram: destroy a program descriptor
 *****************************************************************************
 * All ES descriptions referenced in the descriptor will be deleted.
 *****************************************************************************/
218
void input_DelProgram( input_thread_t * p_input, pgrm_descriptor_t * p_pgrm )
219
{
220
    unsigned int i_pgrm_index;
gbazin's avatar
   
gbazin committed
221
    vlc_value_t val;
222

gbazin's avatar
   
gbazin committed
223
224
225
226
227
228
229
230
231
232
233
    /* Find the program in the programs table */
    for( i_pgrm_index = 0; i_pgrm_index < p_input->stream.i_pgrm_number;
         i_pgrm_index++ )
    {
        if( p_input->stream.pp_programs[i_pgrm_index] == p_pgrm )
            break;
    }

    /* If the program wasn't found, do nothing */
    if( i_pgrm_index == p_input->stream.i_pgrm_number )
    {
234
        msg_Err( p_input, "program does not belong to this input" );
gbazin's avatar
   
gbazin committed
235
236
        return;
    }
237

gbazin's avatar
   
gbazin committed
238
    val.i_int = i_pgrm_index;
gbazin's avatar
   
gbazin committed
239
    var_Change( p_input, "program", VLC_VAR_DELCHOICE, &val, NULL );
gbazin's avatar
   
gbazin committed
240

241
    /* Free the structures that describe the es that belongs to that program */
242
    while( p_pgrm->i_es_number )
243
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
244
        input_DelES( p_input, p_pgrm->pp_es[0] );
245
246
    }

247
248
249
250
251
252
    /* Free the demux data */
    if( p_pgrm->p_demux_data != NULL )
    {
        free( p_pgrm->p_demux_data );
    }

253
    /* Remove this program from the stream's list of programs */
254
255
256
    REMOVE_ELEM( p_input->stream.pp_programs,
                 p_input->stream.i_pgrm_number,
                 i_pgrm_index );
257

258
259
260
261
    /* Free the description of this program */
    free( p_pgrm );
}

Stéphane Borel's avatar
   
Stéphane Borel committed
262
263
264
265
266
/*****************************************************************************
 * input_AddArea: add and init an area descriptor
 *****************************************************************************
 * This area descriptor will be referenced in the given stream descriptor
 *****************************************************************************/
gbazin's avatar
   
gbazin committed
267
268
input_area_t * input_AddArea( input_thread_t * p_input,
                              uint16_t i_area_id, uint16_t i_part_nb )
Stéphane Borel's avatar
   
Stéphane Borel committed
269
270
{
    /* Where to add the pgrm */
271
    input_area_t * p_area = malloc( sizeof(input_area_t) );
gbazin's avatar
   
gbazin committed
272
273
    vlc_value_t val;
    int i;
Stéphane Borel's avatar
   
Stéphane Borel committed
274

275
    if( p_area == NULL )
Stéphane Borel's avatar
   
Stéphane Borel committed
276
    {
277
        msg_Err( p_input, "out of memory" );
278
        return NULL;
Stéphane Borel's avatar
   
Stéphane Borel committed
279
    }
gbazin's avatar
   
gbazin committed
280

Stéphane Borel's avatar
   
Stéphane Borel committed
281
    /* Init this entry */
gbazin's avatar
   
gbazin committed
282
283
284
    p_area->i_id = i_area_id;
    p_area->i_part_nb = i_part_nb;
    p_area->i_part= 0;
285
286
287
288
289
290
291
292
293
294
295
    p_area->i_start = 0;
    p_area->i_size = 0;
    p_area->i_tell = 0;
    p_area->i_seek = NO_SEEK;

    /* Add an entry to the list of program associated with the stream */
    INSERT_ELEM( p_input->stream.pp_areas,
                 p_input->stream.i_area_nb,
                 p_input->stream.i_area_nb,
                 p_area );

gbazin's avatar
   
gbazin committed
296
297
298
299
300
301
    /* Don't add empty areas */
    if( i_part_nb == 0 )
        return NULL;

    /* Take care of the navigation variables */
    val.i_int = i_area_id;
gbazin's avatar
   
gbazin committed
302
    var_Change( p_input, "title", VLC_VAR_ADDCHOICE, &val, NULL );
gbazin's avatar
   
gbazin committed
303
304
305
306
307
308
309
310
311
312
313
314
315

    val.psz_string = malloc( sizeof("title ") + 5 );
    if( val.psz_string )
    {
        vlc_value_t val2;

        sprintf( val.psz_string, "title %2i", i_area_id );
	var_Destroy( p_input, val.psz_string );
	var_Create( p_input, val.psz_string, VLC_VAR_INTEGER |
		    VLC_VAR_HASCHOICE | VLC_VAR_ISCOMMAND );
	var_AddCallback( p_input, val.psz_string, NavigationCallback,
			 (void *)(int)i_area_id );

gbazin's avatar
   
gbazin committed
316
	var_Change( p_input, "navigation", VLC_VAR_ADDCHOICE, &val, NULL );
gbazin's avatar
   
gbazin committed
317
318
319
320

	for( i = 1; i <= i_part_nb; i++ )
	{
	    val2.i_int = i;
gbazin's avatar
   
gbazin committed
321
322
	    var_Change( p_input, val.psz_string,
                        VLC_VAR_ADDCHOICE, &val2, NULL );
gbazin's avatar
   
gbazin committed
323
324
325
	}
    }

326
    return p_area;
Stéphane Borel's avatar
   
Stéphane Borel committed
327
328
}

329
330
331
332
333
/*****************************************************************************
 * input_SetProgram: changes the current program
 *****************************************************************************/
int input_SetProgram( input_thread_t * p_input, pgrm_descriptor_t * p_new_prg )
{
334
    unsigned int i_es_index;
335
336
337
338
    int i_required_audio_es;
    int i_required_spu_es;
    int i_audio_es = 0;
    int i_spu_es = 0;
gbazin's avatar
   
gbazin committed
339
    vlc_value_t val;
Johan Bilien's avatar
   
Johan Bilien committed
340

Johan Bilien's avatar
   
Johan Bilien committed
341
    if ( p_input->stream.p_selected_program )
342
    {
Johan Bilien's avatar
   
Johan Bilien committed
343
344
345
        for ( i_es_index = 1 ; /* 0 should be the PMT */
                i_es_index < p_input->stream.p_selected_program->
                i_es_number ;
Johan Bilien's avatar
   
Johan Bilien committed
346
347
                i_es_index ++ )
        {
Johan Bilien's avatar
   
Johan Bilien committed
348
#define p_es p_input->stream.p_selected_program->pp_es[i_es_index]
349
            if ( p_es->p_decoder_fifo ) /* if the ES was selected */
Johan Bilien's avatar
   
Johan Bilien committed
350
            {
Johan Bilien's avatar
   
Johan Bilien committed
351
                input_UnselectES( p_input , p_es );
Johan Bilien's avatar
   
Johan Bilien committed
352
            }
Johan Bilien's avatar
   
Johan Bilien committed
353
#undef p_es
Johan Bilien's avatar
   
Johan Bilien committed
354
        }
Johan Bilien's avatar
   
Johan Bilien committed
355
356
    }
    /* Get the number of the required audio stream */
357
    if( config_GetInt( p_input, "audio" ) )
Johan Bilien's avatar
   
Johan Bilien committed
358
359
    {
        /* Default is the first one */
360
        i_required_audio_es = config_GetInt( p_input, "audio-channel" );
Johan Bilien's avatar
   
Johan Bilien committed
361
        if( i_required_audio_es < 0 )
Johan Bilien's avatar
   
Johan Bilien committed
362
        {
Johan Bilien's avatar
   
Johan Bilien committed
363
            i_required_audio_es = 1;
Johan Bilien's avatar
   
Johan Bilien committed
364
        }
Johan Bilien's avatar
   
Johan Bilien committed
365
366
367
368
369
    }
    else
    {
        i_required_audio_es = 0;
    }
Johan Bilien's avatar
   
Johan Bilien committed
370

Johan Bilien's avatar
   
Johan Bilien committed
371
    /* Same thing for subtitles */
372
    if( config_GetInt( p_input, "video" ) )
Johan Bilien's avatar
   
Johan Bilien committed
373
374
    {
        /* for spu, default is none */
375
        i_required_spu_es = config_GetInt( p_input, "spu-channel" );
Johan Bilien's avatar
   
Johan Bilien committed
376
        if( i_required_spu_es < 0 )
Johan Bilien's avatar
   
Johan Bilien committed
377
378
379
        {
            i_required_spu_es = 0;
        }
Johan Bilien's avatar
   
Johan Bilien committed
380
381
382
383
384
385
    }
    else
    {
        i_required_spu_es = 0;
    }

386
    for( i_es_index = 0 ; i_es_index < p_new_prg->i_es_number ; i_es_index ++ )
Johan Bilien's avatar
   
Johan Bilien committed
387
    {
Johan Bilien's avatar
   
Johan Bilien committed
388
        switch( p_new_prg->pp_es[i_es_index]->i_cat )
389
390
        {
            case VIDEO_ES:
391
392
                msg_Dbg( p_input, "selecting ES %x",
                         p_new_prg->pp_es[i_es_index]->i_id );
393
394
395
396
397
398
                input_SelectES( p_input, p_new_prg->pp_es[i_es_index] );
                break;
            case AUDIO_ES:
                i_audio_es += 1;
                if( i_audio_es <= i_required_audio_es )
                {
399
400
                    msg_Dbg( p_input, "selecting ES %x",
                             p_new_prg->pp_es[i_es_index]->i_id );
401
402
403
404
405
406
407
408
                    input_SelectES( p_input, p_new_prg->pp_es[i_es_index]);
                }
                break;
            /* Not sure this one is fully specification-compliant */
            case SPU_ES :
                i_spu_es += 1;
                if( i_spu_es <= i_required_spu_es )
                {
409
410
                    msg_Dbg( p_input, "selecting ES %x",
                             p_new_prg->pp_es[i_es_index]->i_id );
411
412
413
414
                    input_SelectES( p_input, p_new_prg->pp_es[i_es_index] );
                }
            break;
            default :
415
416
                msg_Dbg( p_input, "ES %x has unknown type",
                         p_new_prg->pp_es[i_es_index]->i_id );
417
418
                break;
        }
Johan Bilien's avatar
   
Johan Bilien committed
419

420
    }
Johan Bilien's avatar
   
Johan Bilien committed
421

422
423
424

    p_input->stream.p_selected_program = p_new_prg;

gbazin's avatar
   
gbazin committed
425
426
    /* Update the navigation variables without triggering a callback */
    val.i_int = p_new_prg->i_number;
gbazin's avatar
   
gbazin committed
427
    var_Change( p_input, "program", VLC_VAR_SETVALUE, &val, NULL );
gbazin's avatar
   
gbazin committed
428

429
430
431
    return( 0 );
}

Stéphane Borel's avatar
   
Stéphane Borel committed
432
433
434
435
436
437
438
/*****************************************************************************
 * input_DelArea: destroy a area descriptor
 *****************************************************************************
 * All ES descriptions referenced in the descriptor will be deleted.
 *****************************************************************************/
void input_DelArea( input_thread_t * p_input, input_area_t * p_area )
{
439
    unsigned int i_area_index;
gbazin's avatar
   
gbazin committed
440
    vlc_value_t val;
Stéphane Borel's avatar
   
Stéphane Borel committed
441
442
443
444
445
446
447
448
449

    /* Find the area in the areas table */
    for( i_area_index = 0; i_area_index < p_input->stream.i_area_nb;
         i_area_index++ )
    {
        if( p_input->stream.pp_areas[i_area_index] == p_area )
            break;
    }

gbazin's avatar
   
gbazin committed
450
451
452
    /* If the area wasn't found, do nothing */
    if( i_area_index == p_input->stream.i_area_nb )
    {
453
        msg_Err( p_input, "area does not belong to this input" );
gbazin's avatar
   
gbazin committed
454
455
456
        return;
    }

gbazin's avatar
   
gbazin committed
457
458
459
460
461
    /* Take care of the navigation variables */
    val.psz_string = malloc( sizeof("title ") + 5 );
    if( val.psz_string )
    {
        sprintf( val.psz_string, "title %i", p_area->i_id );
gbazin's avatar
   
gbazin committed
462
	var_Change( p_input, "navigation", VLC_VAR_DELCHOICE, &val, NULL );
gbazin's avatar
   
gbazin committed
463
464
465
	var_Destroy( p_input, val.psz_string );
    }

Stéphane Borel's avatar
   
Stéphane Borel committed
466
    /* Remove this area from the stream's list of areas */
467
468
469
    REMOVE_ELEM( p_input->stream.pp_areas,
                 p_input->stream.i_area_nb,
                 i_area_index );
Stéphane Borel's avatar
   
Stéphane Borel committed
470
471
472
473
474
475

    /* Free the description of this area */
    free( p_area );
}


476
477
478
/*****************************************************************************
 * input_FindES: returns a pointer to an ES described by its ID
 *****************************************************************************/
479
es_descriptor_t * input_FindES( input_thread_t * p_input, uint16_t i_es_id )
480
{
481
    unsigned int i;
482
483
484
485
486
487
488
489
490

    for( i = 0; i < p_input->stream.i_es_number; i++ )
    {
        if( p_input->stream.pp_es[i]->i_id == i_es_id )
        {
            return p_input->stream.pp_es[i];
        }
    }

gbazin's avatar
   
gbazin committed
491
    return NULL;
492
493
494
495
496
497
498
499
500
501
}

/*****************************************************************************
 * input_AddES:
 *****************************************************************************
 * Reserve a slot in the table of ES descriptors for the ES and add it to the
 * list of ES of p_pgrm. If p_pgrm if NULL, then the ES is considered as stand
 * alone (PSI ?)
 *****************************************************************************/
es_descriptor_t * input_AddES( input_thread_t * p_input,
502
503
                               pgrm_descriptor_t * p_pgrm, u16 i_es_id,
                               size_t i_data_len )
504
{
505
    es_descriptor_t * p_es;
506

507
    p_es = (es_descriptor_t *)malloc( sizeof(es_descriptor_t) );
Henri Fallon's avatar
   
Henri Fallon committed
508
509
    if( p_es == NULL )
    {
510
        msg_Err( p_input, "out of memory" );
Henri Fallon's avatar
   
Henri Fallon committed
511
        return( NULL);
Henri Fallon's avatar
   
Henri Fallon committed
512
    }
gbazin's avatar
   
gbazin committed
513

514
515
516
517
    INSERT_ELEM( p_input->stream.pp_es,
                 p_input->stream.i_es_number,
                 p_input->stream.i_es_number,
                 p_es );
518

519
    /* Init its values */
520
    p_es->i_id = i_es_id;
521
    p_es->psz_desc[0] = '\0';
522
523
    p_es->p_pes = NULL;
    p_es->p_decoder_fifo = NULL;
Stéphane Borel's avatar
Stéphane Borel committed
524
    p_es->i_cat = UNKNOWN_ES;
525
    p_es->i_demux_fd = 0;
526
527
    p_es->c_packets = 0;
    p_es->c_invalid_packets = 0;
528
    p_es->b_force_decoder = VLC_FALSE;
529
530

    if( i_data_len )
531
    {
532
        p_es->p_demux_data = malloc( i_data_len );
Henri Fallon's avatar
   
Henri Fallon committed
533
534
        if( p_es->p_demux_data == NULL )
        {
535
            msg_Err( p_input, "out of memory" );
Henri Fallon's avatar
   
Henri Fallon committed
536
            return( NULL );
Henri Fallon's avatar
   
Henri Fallon committed
537
        }
538
539
        memset( p_es->p_demux_data, 0, i_data_len );
    }
540
541
542
543
    else
    {
        p_es->p_demux_data = NULL;
    }
544
545
    p_es->p_waveformatex     = NULL;
    p_es->p_bitmapinfoheader = NULL;
546
547
548
549

    /* Add this ES to the program definition if one is given */
    if( p_pgrm )
    {
550
551
552
553
        INSERT_ELEM( p_pgrm->pp_es,
                     p_pgrm->i_es_number,
                     p_pgrm->i_es_number,
                     p_es );
554
        p_es->p_pgrm = p_pgrm;
555
556
557
    }
    else
    {
558
        p_es->p_pgrm = NULL;
559
560
561
562
563
564
565
566
    }

    return p_es;
}

/*****************************************************************************
 * input_DelES:
 *****************************************************************************/
567
void input_DelES( input_thread_t * p_input, es_descriptor_t * p_es )
568
{
569
    unsigned int            i_index, i_es_index;
570
    pgrm_descriptor_t *     p_pgrm;
571

gbazin's avatar
   
gbazin committed
572
573
574
575
576
577
578
579
580
581
582
    /* Find the ES in the ES table */
    for( i_es_index = 0; i_es_index < p_input->stream.i_es_number;
         i_es_index++ )
    {
        if( p_input->stream.pp_es[i_es_index] == p_es )
            break;
    }

    /* If the ES wasn't found, do nothing */
    if( i_es_index == p_input->stream.i_es_number )
    {
583
        msg_Err( p_input, "ES does not belong to this input" );
gbazin's avatar
   
gbazin committed
584
585
586
        return;
    }

587
588
589
590
    p_pgrm = p_es->p_pgrm;

    /* Kill associated decoder, if any. */
    if( p_es->p_decoder_fifo != NULL )
591
    {
592
        input_EndDecoder( p_input, p_es );
593
594
595
596
597
598
    }

    /* Remove this ES from the description of the program if it is associated to
     * one */
    if( p_pgrm )
    {
599
        for( i_index = 0; i_index < p_pgrm->i_es_number; i_index++ )
600
        {
601
            if( p_pgrm->pp_es[i_index] == p_es )
602
            {
603
604
605
                REMOVE_ELEM( p_pgrm->pp_es,
                             p_pgrm->i_es_number,
                             i_index );
606
607
608
609
610
                break;
            }
        }
    }

611
612
613
614
615
    /* Free the demux data */
    if( p_es->p_demux_data != NULL )
    {
        free( p_es->p_demux_data );
    }
616
617
618
619
620
621
622
623
    if( p_es->p_waveformatex )
    {
        free( p_es->p_waveformatex );
    }
    if( p_es->p_bitmapinfoheader )
    {
        free( p_es->p_bitmapinfoheader );
    }
624

625
626
627
628
629
630
631
632
    /* Find the ES in the ES table */
    for( i_es_index = 0; i_es_index < p_input->stream.i_es_number;
         i_es_index++ )
    {
        if( p_input->stream.pp_es[i_es_index] == p_es )
            break;
    }

gbazin's avatar
   
gbazin committed
633
    /* Remove this ES from the stream's list of ES */
634
635
636
637
    REMOVE_ELEM( p_input->stream.pp_es,
                 p_input->stream.i_es_number,
                 i_es_index );

gbazin's avatar
   
gbazin committed
638
639
    /* Free the ES */
    free( p_es );
640
641
642
643
}

/*****************************************************************************
 * input_SelectES: selects an ES and spawns the associated decoder
644
645
646
 *****************************************************************************
 * Remember we are still supposed to have stream_lock when entering this
 * function ?
647
648
649
 *****************************************************************************/
int input_SelectES( input_thread_t * p_input, es_descriptor_t * p_es )
{
650
651
    if( p_es == NULL )
    {
652
        msg_Err( p_input, "nothing to do in input_SelectES" );
653
654
655
        return -1;
    }

gbazin's avatar
   
gbazin committed
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
    if( ((p_es->i_cat == VIDEO_ES) || (p_es->i_cat == SPU_ES))
        && !config_GetInt( p_input, "video" ) )
    {
        msg_Dbg( p_input,
                 "video is disabled, not selecting ES 0x%x", p_es->i_id );
        return -1;
    }

    if( (p_es->i_cat == AUDIO_ES) && !config_GetInt( p_input, "audio" ) )
    {
        msg_Dbg( p_input,
                 "audio is disabled, not selecting ES 0x%x", p_es->i_id );
        return -1;
    }

671
    msg_Dbg( p_input, "selecting ES 0x%x", p_es->i_id );
672
673
674

    if( p_es->p_decoder_fifo != NULL )
    {
675
        msg_Err( p_input, "ES 0x%x is already selected", p_es->i_id );
676
        return -1;
677
678
    }

679
680
681
    /* Release the lock, not to block the input thread during
     * the creation of the thread. */
    vlc_mutex_unlock( &p_input->stream.stream_lock );
682
    p_es->p_decoder_fifo = input_RunDecoder( p_input, p_es );
683
    vlc_mutex_lock( &p_input->stream.stream_lock );
gbazin's avatar
   
gbazin committed
684

685
    if( p_es->p_decoder_fifo == NULL )
686
    {
687
        return -1;
688
689
    }

690
    return 0;
691
}
692
693

/*****************************************************************************
694
 * input_UnselectES: removes an ES from the list of selected ES
695
 *****************************************************************************/
696
int input_UnselectES( input_thread_t * p_input, es_descriptor_t * p_es )
697
698
{

699
    unsigned int i_index = 0;
700

701
702
    if( p_es == NULL )
    {
703
        msg_Err( p_input, "nothing to do in input_UnselectES" );
704
705
706
        return -1;
    }

707
    msg_Dbg( p_input, "unselecting ES 0x%x", p_es->i_id );
708
709
710

    if( p_es->p_decoder_fifo == NULL )
    {
711
        msg_Err( p_input, "ES 0x%x is not selected", p_es->i_id );
712
713
714
715
        return( -1 );
    }

    input_EndDecoder( p_input, p_es );
Johan Bilien's avatar
   
Johan Bilien committed
716
    p_es->p_pes = NULL;
717

718
719
    if( ( p_es->p_decoder_fifo == NULL ) &&
        ( p_input->stream.i_selected_es_number > 0 ) )
720
    {
721
        while( ( i_index < p_input->stream.i_selected_es_number - 1 ) &&
722
723
724
725
726
               ( p_input->stream.pp_selected_es[i_index] != p_es ) )
        {
            i_index++;
        }

727
        /* XXX: no need to memmove, we have unsorted data */
728
729
730
        REMOVE_ELEM( p_input->stream.pp_selected_es,
                     p_input->stream.i_selected_es_number,
                     i_index );
731

732
        if( p_input->stream.i_selected_es_number == 0 )
733
        {
734
            msg_Dbg( p_input, "no more selected ES" );
735
            return 1;
736
737
        }
    }
738

739
    return 0;
740
}
gbazin's avatar
   
gbazin committed
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757

/*****************************************************************************
 * Navigation callback: a bunch of navigation variables are used as an
 *  alternative to the navigation API.
 *****************************************************************************/
static int ProgramCallback( vlc_object_t *p_this, char const *psz_cmd,
                  vlc_value_t oldval, vlc_value_t newval, void *p_data )
{
    input_thread_t *p_input = (input_thread_t *)p_this;

    if( oldval.i_int == newval.i_int )
       return VLC_SUCCESS;

    vlc_mutex_lock( &p_input->stream.stream_lock );
    if( ( newval.i_int > 0 ) )
    {
        vlc_mutex_unlock( &p_input->stream.stream_lock );
758
        input_ChangeProgram( p_input, (uint16_t)newval.i_int );
gbazin's avatar
   
gbazin committed
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
        input_SetStatus( p_input, INPUT_STATUS_PLAY );
        vlc_mutex_lock( &p_input->stream.stream_lock );
    }
    vlc_mutex_unlock( &p_input->stream.stream_lock );

    return VLC_SUCCESS;
}

static int TitleCallback( vlc_object_t *p_this, char const *psz_cmd,
                  vlc_value_t oldval, vlc_value_t newval, void *p_data )
{
    input_thread_t *p_input = (input_thread_t *)p_this;
    input_area_t *p_area;

    if( oldval.i_int == newval.i_int )
       return VLC_SUCCESS;

    /* Sanity check should have already be done by var_Set(). */
    vlc_mutex_lock( &p_input->stream.stream_lock );
    p_area = p_input->stream.pp_areas[newval.i_int];
    p_area->i_part = 1;
    vlc_mutex_unlock( &p_input->stream.stream_lock );
    input_ChangeArea( p_input, p_area );
    input_SetStatus( p_input, INPUT_STATUS_PLAY );

    return VLC_SUCCESS;
}

static int ChapterCallback( vlc_object_t *p_this, char const *psz_cmd,
                  vlc_value_t oldval, vlc_value_t newval, void *p_data )
{
    input_thread_t *p_input = (input_thread_t *)p_this;
    input_area_t *p_area;

    if( oldval.i_int == newval.i_int )
       return VLC_SUCCESS;

    /* Sanity check will have already be done by var_Set(). */
    vlc_mutex_lock( &p_input->stream.stream_lock );
    p_area = p_input->stream.p_selected_area;
    p_input->stream.p_selected_area->i_part = newval.i_int;
    vlc_mutex_unlock( &p_input->stream.stream_lock );

    input_ChangeArea( p_input, p_area );
    input_SetStatus( p_input, INPUT_STATUS_PLAY );

    return VLC_SUCCESS;
}

static int NavigationCallback( vlc_object_t *p_this, char const *psz_cmd,
                  vlc_value_t oldval, vlc_value_t newval, void *p_data )
{
    input_thread_t *p_input = (input_thread_t *)p_this;
    uint16_t i_area_id = (int)p_data;

    vlc_mutex_lock( &p_input->stream.stream_lock );

    if( p_input->stream.p_selected_area->i_id == i_area_id &&
        oldval.i_int == newval.i_int )
    {
        /* Nothing to do */
        vlc_mutex_unlock( &p_input->stream.stream_lock );
        return VLC_SUCCESS;
    }

    if( ( i_area_id < p_input->stream.i_area_nb ) && ( newval.i_int > 0 ) &&
        ( (uint16_t)newval.i_int <=
          p_input->stream.pp_areas[i_area_id]->i_part_nb ) )
    {
        input_area_t *p_area = p_input->stream.pp_areas[i_area_id];
        p_input->stream.p_selected_area->i_part = newval.i_int;
        vlc_mutex_unlock( &p_input->stream.stream_lock );
        input_ChangeArea( p_input, p_area );
        input_SetStatus( p_input, INPUT_STATUS_PLAY );
        vlc_mutex_lock( &p_input->stream.stream_lock );
    }
    vlc_mutex_unlock( &p_input->stream.stream_lock );

    return VLC_SUCCESS;
}