input_programs.c 29.7 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.106 2003/05/05 22:23:42 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
/* 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 * );
gbazin's avatar
   
gbazin committed
51
52
static int ESCallback( vlc_object_t *, char const *,
                       vlc_value_t, vlc_value_t, void * );
gbazin's avatar
   
gbazin committed
53

54
55
56
/*****************************************************************************
 * input_InitStream: init the stream descriptor of the given input
 *****************************************************************************/
57
int input_InitStream( input_thread_t * p_input, size_t i_data_len )
58
{
gbazin's avatar
   
gbazin committed
59
    vlc_value_t text;
60

61
    p_input->stream.i_stream_id = 0;
62
63
64
65

    /* 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;
66
67
    p_input->stream.pp_es = NULL;
    p_input->stream.pp_selected_es = NULL;
68
69
    p_input->stream.p_removed_es = NULL;
    p_input->stream.p_newly_selected_es = NULL;
70
    p_input->stream.pp_programs = NULL;
71
72
    p_input->stream.p_selected_program = NULL;
    p_input->stream.p_new_program = NULL;
73

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

gbazin's avatar
   
gbazin committed
88
89
    /* Create a few object variables used for navigation in the interfaces */
    var_Create( p_input, "program", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
gbazin's avatar
   
gbazin committed
90
91
    text.psz_string = _("Program");
    var_Change( p_input, "program", VLC_VAR_SETTEXT, &text, NULL );
gbazin's avatar
   
gbazin committed
92
    var_Create( p_input, "title", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
gbazin's avatar
   
gbazin committed
93
94
    text.psz_string = _("Title");
    var_Change( p_input, "title", VLC_VAR_SETTEXT, &text, NULL );
gbazin's avatar
   
gbazin committed
95
    var_Create( p_input, "chapter", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
gbazin's avatar
   
gbazin committed
96
97
    text.psz_string = _("Chapter");
    var_Change( p_input, "chapter", VLC_VAR_SETTEXT, &text, NULL );
gbazin's avatar
   
gbazin committed
98
    var_Create( p_input, "navigation", VLC_VAR_VARIABLE | VLC_VAR_HASCHOICE );
gbazin's avatar
   
gbazin committed
99
100
101
102
103
104
105
106
107
108
109
110
    text.psz_string = _("Navigation");
    var_Change( p_input, "navigation", VLC_VAR_SETTEXT, &text, NULL );
    var_Create( p_input, "video-es", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
    text.psz_string = _("Video track");
    var_Change( p_input, "video-es", VLC_VAR_SETTEXT, &text, NULL );
    var_Create( p_input, "audio-es", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
    text.psz_string = _("Audio track");
    var_Change( p_input, "audio-es", VLC_VAR_SETTEXT, &text, NULL );
    var_Create( p_input, "spu-es", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
    text.psz_string = _("Subtitle track");
    var_Change( p_input, "spu-es", VLC_VAR_SETTEXT, &text, NULL );

gbazin's avatar
   
gbazin committed
111
112
113
    var_AddCallback( p_input, "program", ProgramCallback, NULL );
    var_AddCallback( p_input, "title", TitleCallback, NULL );
    var_AddCallback( p_input, "chapter", ChapterCallback, NULL );
gbazin's avatar
   
gbazin committed
114
115
116
    var_AddCallback( p_input, "video-es", ESCallback, NULL );
    var_AddCallback( p_input, "audio-es", ESCallback, NULL );
    var_AddCallback( p_input, "spu-es", ESCallback, NULL );
gbazin's avatar
   
gbazin committed
117

118
    return 0;
119
120
}

121
122
123
124
125
/*****************************************************************************
 * input_EndStream: free all stream descriptors
 *****************************************************************************/
void input_EndStream( input_thread_t * p_input )
{
126
    /* Free all programs and associated ES, and associated decoders. */
127
    while( p_input->stream.i_pgrm_number )
128
    {
129
130
        input_DelProgram( p_input, p_input->stream.pp_programs[0] );
    }
131

132
    /* Free standalone ES */
133
    while( p_input->stream.i_es_number )
134
135
136
    {
        input_DelES( p_input, p_input->stream.pp_es[0] );
    }
137

138
139
140
141
142
143
    /* Free all areas */
    while( p_input->stream.i_area_nb )
    {
        input_DelArea( p_input, p_input->stream.pp_areas[0] );
    }

144
145
146
147
148
    /* Free selected ES */
    if( p_input->stream.pp_selected_es != NULL )
    {
        free( p_input->stream.pp_selected_es );
    }
149

150
151
152
153
    if( p_input->stream.p_demux_data != NULL )
    {
        free( p_input->stream.p_demux_data );
    }
gbazin's avatar
   
gbazin committed
154
155
156
157
158
159
160
161

    /* Free navigation variables */
    var_Destroy( p_input, "program" );
    var_Destroy( p_input, "title" );
    var_Destroy( p_input, "chapter" );
    var_Destroy( p_input, "video-es" );
    var_Destroy( p_input, "audio-es" );
    var_Destroy( p_input, "spu-es" );
162
163
164
165
166
}

/*****************************************************************************
 * input_FindProgram: returns a pointer to a program described by its ID
 *****************************************************************************/
167
168
pgrm_descriptor_t * input_FindProgram( input_thread_t * p_input,
                                       uint16_t i_pgrm_id )
169
{
170
    unsigned int i;
171
172
173
174

    for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
    {
        if( p_input->stream.pp_programs[i]->i_number == i_pgrm_id )
175
        {
176
            return p_input->stream.pp_programs[i];
177
178
        }
    }
179

gbazin's avatar
   
gbazin committed
180
    return NULL;
181
182
}

183
184
185
186
187
188
/*****************************************************************************
 * 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,
189
                                      u16 i_pgrm_id, size_t i_data_len )
190
{
191
    /* Where to add the pgrm */
192
    pgrm_descriptor_t * p_pgrm = malloc( sizeof(pgrm_descriptor_t) );
gbazin's avatar
   
gbazin committed
193
    vlc_value_t val;
194

195
    if( p_pgrm == NULL )
Henri Fallon's avatar
   
Henri Fallon committed
196
    {
197
        msg_Err( p_input, "out of memory" );
198
        return NULL;
Henri Fallon's avatar
   
Henri Fallon committed
199
    }
gbazin's avatar
   
gbazin committed
200

201
    /* Init this entry */
202
203
204
    p_pgrm->i_number = i_pgrm_id;
    p_pgrm->b_is_ok = 0;
    p_pgrm->i_version = 0;
205

206
207
    p_pgrm->i_es_number = 0;
    p_pgrm->pp_es = NULL;
208

209
    input_ClockInit( p_pgrm );
210

211
    p_pgrm->i_synchro_state = SYNCHRO_START;
212

213
214
    if( i_data_len )
    {
215
216
        p_pgrm->p_demux_data = malloc( i_data_len );
        if( p_pgrm->p_demux_data == NULL )
Henri Fallon's avatar
   
Henri Fallon committed
217
        {
218
            msg_Err( p_input, "out of memory" );
219
            return NULL;
Henri Fallon's avatar
   
Henri Fallon committed
220
        }
221
        memset( p_pgrm->p_demux_data, 0, i_data_len );
222
    }
223
224
    else
    {
225
        p_pgrm->p_demux_data = NULL;
226
    }
227

228
229
230
231
232
233
    /* 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
234
    val.i_int = i_pgrm_id;
gbazin's avatar
   
gbazin committed
235
    var_Change( p_input, "program", VLC_VAR_ADDCHOICE, &val, NULL );
gbazin's avatar
   
gbazin committed
236

237
    return p_pgrm;
238
239
240
241
242
243
244
}

/*****************************************************************************
 * input_DelProgram: destroy a program descriptor
 *****************************************************************************
 * All ES descriptions referenced in the descriptor will be deleted.
 *****************************************************************************/
245
void input_DelProgram( input_thread_t * p_input, pgrm_descriptor_t * p_pgrm )
246
{
247
    unsigned int i_pgrm_index;
gbazin's avatar
   
gbazin committed
248
    vlc_value_t val;
249

gbazin's avatar
   
gbazin committed
250
251
252
253
254
255
256
257
258
259
260
    /* 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 )
    {
261
        msg_Err( p_input, "program does not belong to this input" );
gbazin's avatar
   
gbazin committed
262
263
        return;
    }
264

gbazin's avatar
   
gbazin committed
265
    val.i_int = i_pgrm_index;
gbazin's avatar
   
gbazin committed
266
    var_Change( p_input, "program", VLC_VAR_DELCHOICE, &val, NULL );
gbazin's avatar
   
gbazin committed
267

268
    /* Free the structures that describe the es that belongs to that program */
269
    while( p_pgrm->i_es_number )
270
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
271
        input_DelES( p_input, p_pgrm->pp_es[0] );
272
273
    }

274
275
276
277
278
279
    /* Free the demux data */
    if( p_pgrm->p_demux_data != NULL )
    {
        free( p_pgrm->p_demux_data );
    }

280
    /* Remove this program from the stream's list of programs */
281
282
283
    REMOVE_ELEM( p_input->stream.pp_programs,
                 p_input->stream.i_pgrm_number,
                 i_pgrm_index );
284

285
286
287
288
    /* Free the description of this program */
    free( p_pgrm );
}

Stéphane Borel's avatar
   
Stéphane Borel committed
289
290
291
292
293
/*****************************************************************************
 * input_AddArea: add and init an area descriptor
 *****************************************************************************
 * This area descriptor will be referenced in the given stream descriptor
 *****************************************************************************/
gbazin's avatar
   
gbazin committed
294
295
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
296
297
{
    /* Where to add the pgrm */
298
    input_area_t * p_area = malloc( sizeof(input_area_t) );
gbazin's avatar
   
gbazin committed
299
300
    vlc_value_t val;
    int i;
Stéphane Borel's avatar
   
Stéphane Borel committed
301

302
    if( p_area == NULL )
Stéphane Borel's avatar
   
Stéphane Borel committed
303
    {
304
        msg_Err( p_input, "out of memory" );
305
        return NULL;
Stéphane Borel's avatar
   
Stéphane Borel committed
306
    }
gbazin's avatar
   
gbazin committed
307

Stéphane Borel's avatar
   
Stéphane Borel committed
308
    /* Init this entry */
gbazin's avatar
   
gbazin committed
309
310
311
    p_area->i_id = i_area_id;
    p_area->i_part_nb = i_part_nb;
    p_area->i_part= 0;
312
313
314
315
316
317
318
319
320
321
322
    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
323
324
325
326
327
328
    /* 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
329
    var_Change( p_input, "title", VLC_VAR_ADDCHOICE, &val, NULL );
gbazin's avatar
   
gbazin committed
330
331
332
333
334
335
336
337
338
339
340
341
342

    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
343
	var_Change( p_input, "navigation", VLC_VAR_ADDCHOICE, &val, NULL );
gbazin's avatar
   
gbazin committed
344
345
346
347

	for( i = 1; i <= i_part_nb; i++ )
	{
	    val2.i_int = i;
gbazin's avatar
   
gbazin committed
348
349
	    var_Change( p_input, val.psz_string,
                        VLC_VAR_ADDCHOICE, &val2, NULL );
gbazin's avatar
   
gbazin committed
350
351
352
	}
    }

353
    return p_area;
Stéphane Borel's avatar
   
Stéphane Borel committed
354
355
}

356
357
358
359
360
/*****************************************************************************
 * input_SetProgram: changes the current program
 *****************************************************************************/
int input_SetProgram( input_thread_t * p_input, pgrm_descriptor_t * p_new_prg )
{
361
    unsigned int i_es_index;
362
363
364
365
    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
366
    vlc_value_t val;
Johan Bilien's avatar
   
Johan Bilien committed
367

Johan Bilien's avatar
   
Johan Bilien committed
368
    if ( p_input->stream.p_selected_program )
369
    {
Johan Bilien's avatar
   
Johan Bilien committed
370
371
372
        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
373
374
                i_es_index ++ )
        {
Johan Bilien's avatar
   
Johan Bilien committed
375
#define p_es p_input->stream.p_selected_program->pp_es[i_es_index]
376
            if ( p_es->p_decoder_fifo ) /* if the ES was selected */
Johan Bilien's avatar
   
Johan Bilien committed
377
            {
Johan Bilien's avatar
   
Johan Bilien committed
378
                input_UnselectES( p_input , p_es );
Johan Bilien's avatar
   
Johan Bilien committed
379
            }
Johan Bilien's avatar
   
Johan Bilien committed
380
#undef p_es
Johan Bilien's avatar
   
Johan Bilien committed
381
        }
Johan Bilien's avatar
   
Johan Bilien committed
382
383
    }
    /* Get the number of the required audio stream */
384
    if( config_GetInt( p_input, "audio" ) )
Johan Bilien's avatar
   
Johan Bilien committed
385
386
    {
        /* Default is the first one */
387
        i_required_audio_es = config_GetInt( p_input, "audio-channel" );
Johan Bilien's avatar
   
Johan Bilien committed
388
        if( i_required_audio_es < 0 )
Johan Bilien's avatar
   
Johan Bilien committed
389
        {
Johan Bilien's avatar
   
Johan Bilien committed
390
            i_required_audio_es = 1;
Johan Bilien's avatar
   
Johan Bilien committed
391
        }
Johan Bilien's avatar
   
Johan Bilien committed
392
393
394
395
396
    }
    else
    {
        i_required_audio_es = 0;
    }
Johan Bilien's avatar
   
Johan Bilien committed
397

Johan Bilien's avatar
   
Johan Bilien committed
398
    /* Same thing for subtitles */
399
    if( config_GetInt( p_input, "video" ) )
Johan Bilien's avatar
   
Johan Bilien committed
400
401
    {
        /* for spu, default is none */
402
        i_required_spu_es = config_GetInt( p_input, "spu-channel" );
Johan Bilien's avatar
   
Johan Bilien committed
403
        if( i_required_spu_es < 0 )
Johan Bilien's avatar
   
Johan Bilien committed
404
405
406
        {
            i_required_spu_es = 0;
        }
Johan Bilien's avatar
   
Johan Bilien committed
407
408
409
410
411
412
    }
    else
    {
        i_required_spu_es = 0;
    }

413
    for( i_es_index = 0 ; i_es_index < p_new_prg->i_es_number ; i_es_index ++ )
Johan Bilien's avatar
   
Johan Bilien committed
414
    {
Johan Bilien's avatar
   
Johan Bilien committed
415
        switch( p_new_prg->pp_es[i_es_index]->i_cat )
416
417
        {
            case VIDEO_ES:
418
419
                msg_Dbg( p_input, "selecting ES %x",
                         p_new_prg->pp_es[i_es_index]->i_id );
420
421
422
423
424
425
                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 )
                {
426
427
                    msg_Dbg( p_input, "selecting ES %x",
                             p_new_prg->pp_es[i_es_index]->i_id );
428
429
430
431
432
433
434
435
                    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 )
                {
436
437
                    msg_Dbg( p_input, "selecting ES %x",
                             p_new_prg->pp_es[i_es_index]->i_id );
438
439
440
441
                    input_SelectES( p_input, p_new_prg->pp_es[i_es_index] );
                }
            break;
            default :
442
443
                msg_Dbg( p_input, "ES %x has unknown type",
                         p_new_prg->pp_es[i_es_index]->i_id );
444
445
                break;
        }
Johan Bilien's avatar
   
Johan Bilien committed
446

447
    }
Johan Bilien's avatar
   
Johan Bilien committed
448

449
450
451

    p_input->stream.p_selected_program = p_new_prg;

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

456
457
458
    return( 0 );
}

Stéphane Borel's avatar
   
Stéphane Borel committed
459
460
461
462
463
464
465
/*****************************************************************************
 * 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 )
{
466
    unsigned int i_area_index;
gbazin's avatar
   
gbazin committed
467
    vlc_value_t val;
Stéphane Borel's avatar
   
Stéphane Borel committed
468
469
470
471
472
473
474
475
476

    /* 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
477
478
479
    /* If the area wasn't found, do nothing */
    if( i_area_index == p_input->stream.i_area_nb )
    {
480
        msg_Err( p_input, "area does not belong to this input" );
gbazin's avatar
   
gbazin committed
481
482
483
        return;
    }

gbazin's avatar
   
gbazin committed
484
485
486
487
488
    /* 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
489
	var_Change( p_input, "navigation", VLC_VAR_DELCHOICE, &val, NULL );
gbazin's avatar
   
gbazin committed
490
491
492
	var_Destroy( p_input, val.psz_string );
    }

Stéphane Borel's avatar
   
Stéphane Borel committed
493
    /* Remove this area from the stream's list of areas */
494
495
496
    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
497
498
499
500
501
502

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


503
504
505
/*****************************************************************************
 * input_FindES: returns a pointer to an ES described by its ID
 *****************************************************************************/
506
es_descriptor_t * input_FindES( input_thread_t * p_input, uint16_t i_es_id )
507
{
508
    unsigned int i;
509
510
511
512
513
514
515
516
517

    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
518
    return NULL;
519
520
521
522
523
524
525
526
527
528
}

/*****************************************************************************
 * 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,
529
                               pgrm_descriptor_t * p_pgrm, u16 i_es_id,
gbazin's avatar
   
gbazin committed
530
                               int i_category, char const *psz_desc,
531
                               size_t i_data_len )
532
{
533
    es_descriptor_t * p_es;
gbazin's avatar
   
gbazin committed
534
535
    vlc_value_t val, text;
    char *psz_var = NULL;
536

537
    p_es = (es_descriptor_t *)malloc( sizeof(es_descriptor_t) );
Henri Fallon's avatar
   
Henri Fallon committed
538
539
    if( p_es == NULL )
    {
540
        msg_Err( p_input, "out of memory" );
Henri Fallon's avatar
   
Henri Fallon committed
541
        return( NULL);
Henri Fallon's avatar
   
Henri Fallon committed
542
    }
gbazin's avatar
   
gbazin committed
543

544
545
546
547
    INSERT_ELEM( p_input->stream.pp_es,
                 p_input->stream.i_es_number,
                 p_input->stream.i_es_number,
                 p_es );
548

549
    /* Init its values */
550
    p_es->i_id = i_es_id;
gbazin's avatar
   
gbazin committed
551
    p_es->psz_desc = psz_desc ? strdup( psz_desc ) : NULL;
552
553
    p_es->p_pes = NULL;
    p_es->p_decoder_fifo = NULL;
gbazin's avatar
   
gbazin committed
554
    p_es->i_cat = i_category;
555
    p_es->i_demux_fd = 0;
556
557
    p_es->c_packets = 0;
    p_es->c_invalid_packets = 0;
558
    p_es->b_force_decoder = VLC_FALSE;
559
560

    if( i_data_len )
561
    {
562
        p_es->p_demux_data = malloc( i_data_len );
Henri Fallon's avatar
   
Henri Fallon committed
563
564
        if( p_es->p_demux_data == NULL )
        {
565
            msg_Err( p_input, "out of memory" );
Henri Fallon's avatar
   
Henri Fallon committed
566
            return( NULL );
Henri Fallon's avatar
   
Henri Fallon committed
567
        }
568
569
        memset( p_es->p_demux_data, 0, i_data_len );
    }
570
571
572
573
    else
    {
        p_es->p_demux_data = NULL;
    }
574
575
    p_es->p_waveformatex     = NULL;
    p_es->p_bitmapinfoheader = NULL;
576
577
578
579

    /* Add this ES to the program definition if one is given */
    if( p_pgrm )
    {
580
581
582
583
        INSERT_ELEM( p_pgrm->pp_es,
                     p_pgrm->i_es_number,
                     p_pgrm->i_es_number,
                     p_es );
584
        p_es->p_pgrm = p_pgrm;
585
586
587
    }
    else
    {
588
        p_es->p_pgrm = NULL;
589
590
    }

gbazin's avatar
   
gbazin committed
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
    switch( i_category )
    {
    case AUDIO_ES:
        psz_var = "audio-es";
        break;
    case SPU_ES:
        psz_var = "spu-es";
        break;
    case VIDEO_ES:
        psz_var = "video-es";
        break;
    }

    if( psz_var )
    {
        val.i_int = p_es->i_id;
        text.psz_string = (char *)psz_desc;
        var_Change( p_input, psz_var, VLC_VAR_ADDCHOICE, &val, &text );
    }

611
612
613
614
615
616
    return p_es;
}

/*****************************************************************************
 * input_DelES:
 *****************************************************************************/
617
void input_DelES( input_thread_t * p_input, es_descriptor_t * p_es )
618
{
619
    unsigned int            i_index, i_es_index;
620
    pgrm_descriptor_t *     p_pgrm;
gbazin's avatar
   
gbazin committed
621
622
    char *                  psz_var;
    vlc_value_t             val;
623

gbazin's avatar
   
gbazin committed
624
625
626
627
628
629
630
631
632
633
634
    /* 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 )
    {
635
        msg_Err( p_input, "ES does not belong to this input" );
gbazin's avatar
   
gbazin committed
636
637
638
        return;
    }

gbazin's avatar
   
gbazin committed
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
    /* Remove es from its associated variable */
    switch( p_es->i_cat )
    {
    case AUDIO_ES:
        psz_var = "audio-es";
	break;
    case SPU_ES:
        psz_var = "spu-es";
	break;
    case VIDEO_ES:
    default:
        psz_var = "video-es";
	break;
    }
    val.i_int = p_es->i_id;
    var_Change( p_input, psz_var, VLC_VAR_DELCHOICE, &val, NULL );
655
656
657

    /* Kill associated decoder, if any. */
    if( p_es->p_decoder_fifo != NULL )
658
    {
659
        input_EndDecoder( p_input, p_es );
660
661
    }

gbazin's avatar
   
gbazin committed
662
663
664
    /* Remove this ES from the description of the program if it is associated
     * to one */
    p_pgrm = p_es->p_pgrm;
665
666
    if( p_pgrm )
    {
667
        for( i_index = 0; i_index < p_pgrm->i_es_number; i_index++ )
668
        {
669
            if( p_pgrm->pp_es[i_index] == p_es )
670
            {
671
672
673
                REMOVE_ELEM( p_pgrm->pp_es,
                             p_pgrm->i_es_number,
                             i_index );
674
675
676
677
678
                break;
            }
        }
    }

679
680
681
682
683
    /* Free the demux data */
    if( p_es->p_demux_data != NULL )
    {
        free( p_es->p_demux_data );
    }
684
685
686
687
688
689
690
691
    if( p_es->p_waveformatex )
    {
        free( p_es->p_waveformatex );
    }
    if( p_es->p_bitmapinfoheader )
    {
        free( p_es->p_bitmapinfoheader );
    }
692

gbazin's avatar
   
gbazin committed
693
694
695
696
697
698
    /* Free the description string */
    if( p_es->psz_desc != NULL )
    {
        free( p_es->psz_desc );
    }

699
700
701
702
703
704
705
706
    /* 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
707
    /* Remove this ES from the stream's list of ES */
708
709
710
711
    REMOVE_ELEM( p_input->stream.pp_es,
                 p_input->stream.i_es_number,
                 i_es_index );

gbazin's avatar
   
gbazin committed
712
713
    /* Free the ES */
    free( p_es );
714
715
716
717
}

/*****************************************************************************
 * input_SelectES: selects an ES and spawns the associated decoder
718
719
720
 *****************************************************************************
 * Remember we are still supposed to have stream_lock when entering this
 * function ?
721
722
723
 *****************************************************************************/
int input_SelectES( input_thread_t * p_input, es_descriptor_t * p_es )
{
gbazin's avatar
   
gbazin committed
724
725
    vlc_value_t val;

726
727
    if( p_es == NULL )
    {
728
        msg_Err( p_input, "nothing to do in input_SelectES" );
729
730
731
        return -1;
    }

gbazin's avatar
   
gbazin committed
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
    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;
    }

747
    msg_Dbg( p_input, "selecting ES 0x%x", p_es->i_id );
748
749
750

    if( p_es->p_decoder_fifo != NULL )
    {
751
        msg_Err( p_input, "ES 0x%x is already selected", p_es->i_id );
752
        return -1;
753
754
    }

755
756
757
    /* Release the lock, not to block the input thread during
     * the creation of the thread. */
    vlc_mutex_unlock( &p_input->stream.stream_lock );
758
    p_es->p_decoder_fifo = input_RunDecoder( p_input, p_es );
759
    vlc_mutex_lock( &p_input->stream.stream_lock );
gbazin's avatar
   
gbazin committed
760

761
    if( p_es->p_decoder_fifo == NULL )
762
    {
763
        return -1;
764
765
    }

gbazin's avatar
   
gbazin committed
766
767
768
769
    /* Update the es variable without triggering a callback */
    val.i_int = p_es->i_id;
    var_Change( p_input, "audio-es", VLC_VAR_SETVALUE, &val, NULL );

770
    return 0;
771
}
772
773

/*****************************************************************************
774
 * input_UnselectES: removes an ES from the list of selected ES
775
 *****************************************************************************/
776
int input_UnselectES( input_thread_t * p_input, es_descriptor_t * p_es )
777
778
{

779
    unsigned int i_index = 0;
780

781
782
    if( p_es == NULL )
    {
783
        msg_Err( p_input, "nothing to do in input_UnselectES" );
784
785
786
        return -1;
    }

787
    msg_Dbg( p_input, "unselecting ES 0x%x", p_es->i_id );
788
789
790

    if( p_es->p_decoder_fifo == NULL )
    {
791
        msg_Err( p_input, "ES 0x%x is not selected", p_es->i_id );
792
793
794
795
        return( -1 );
    }

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

798
799
    if( ( p_es->p_decoder_fifo == NULL ) &&
        ( p_input->stream.i_selected_es_number > 0 ) )
800
    {
801
        while( ( i_index < p_input->stream.i_selected_es_number - 1 ) &&
802
803
804
805
806
               ( p_input->stream.pp_selected_es[i_index] != p_es ) )
        {
            i_index++;
        }

807
        /* XXX: no need to memmove, we have unsorted data */
808
809
810
        REMOVE_ELEM( p_input->stream.pp_selected_es,
                     p_input->stream.i_selected_es_number,
                     i_index );
811

812
        if( p_input->stream.i_selected_es_number == 0 )
813
        {
814
            msg_Dbg( p_input, "no more selected ES" );
815
            return 1;
816
817
        }
    }
818

819
    return 0;
820
}
gbazin's avatar
   
gbazin committed
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837

/*****************************************************************************
 * 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 );
838
        input_ChangeProgram( p_input, (uint16_t)newval.i_int );
gbazin's avatar
   
gbazin committed
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
        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;
}
gbazin's avatar
   
gbazin committed
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951

static int ESCallback( 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;
    unsigned int i;

    vlc_mutex_lock( &p_input->stream.stream_lock );

    /* Unselect old ES */
    for( i = 0 ; i < p_input->stream.i_es_number ; i++ )
    {
        if( p_input->stream.pp_es[i]->i_id == oldval.i_int &&
            p_input->stream.pp_es[i]->p_decoder_fifo != NULL )
        {
            input_UnselectES( p_input, p_input->stream.pp_es[i] );
        }
    }

    /* Select new ES */
    for( i = 0 ; i < p_input->stream.i_es_number ; i++ )
    {
        if( p_input->stream.pp_es[i]->i_id == newval.i_int &&
            p_input->stream.pp_es[i]->p_decoder_fifo == NULL )
        {
            input_SelectES( p_input, p_input->stream.pp_es[i] );
        }
    }

    vlc_mutex_unlock( &p_input->stream.stream_lock );

    return VLC_SUCCESS;
}