es_out.c 24.9 KB
Newer Older
1
2
3
/*****************************************************************************
 * es_out.c: Es Out handler for input.
 *****************************************************************************
zorglub's avatar
zorglub committed
4
 * Copyright (C) 2003-2004 VideoLAN
5
 * $Id: es_out.c,v 1.19 2004/01/19 18:15:29 fenrir Exp $
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
 *
 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
 *
 * 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.
 *
 * 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
 *****************************************************************************/
#include <stdlib.h>

#include <vlc/vlc.h>
#include <vlc/input.h>
#include <vlc/decoder.h>

zorglub's avatar
zorglub committed
33
#include "vlc_playlist.h"
34
35
36
37
38
#include "codecs.h"

/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
39
40
41
42
43
44
struct es_out_id_t
{
    int             i_channel;
    es_descriptor_t *p_es;
};

45
46
47
struct es_out_sys_t
{
    input_thread_t *p_input;
48
    vlc_bool_t      b_pcr_set;
49

50
    /* all es */
51
52
    int         i_id;

53
54
    int         i_es;
    es_out_id_t **es;
55

56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
    /* mode gestion */
    vlc_bool_t  b_active;
    int         i_mode;

    /* es count */
    int         i_audio;
    int         i_video;
    int         i_sub;

    /* es to select */
    int         i_audio_last;
    int         i_sub_last;

    /* current main es */
    es_out_id_t *p_es_audio;
    es_out_id_t *p_es_video;
    es_out_id_t *p_es_sub;
73
74
75
76
77
78
79
80
81
82
83
84
85
};

static es_out_id_t *EsOutAdd    ( es_out_t *, es_format_t * );
static int          EsOutSend   ( es_out_t *, es_out_id_t *, block_t * );
static void         EsOutDel    ( es_out_t *, es_out_id_t * );
static int          EsOutControl( es_out_t *, int i_query, va_list );


/*****************************************************************************
 * input_EsOutNew:
 *****************************************************************************/
es_out_t *input_EsOutNew( input_thread_t *p_input )
{
86
87
88
    es_out_t     *out = malloc( sizeof( es_out_t ) );
    es_out_sys_t *p_sys = malloc( sizeof( es_out_sys_t ) );
    vlc_value_t  val;
89
90
91
92
93

    out->pf_add     = EsOutAdd;
    out->pf_send    = EsOutSend;
    out->pf_del     = EsOutDel;
    out->pf_control = EsOutControl;
94
95
96
    out->p_sys      = p_sys;

    p_sys->p_input = p_input;
97
    p_sys->b_pcr_set = VLC_FALSE;
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119

    p_sys->b_active = VLC_FALSE;
    p_sys->i_mode   = ES_OUT_MODE_AUTO;

    p_sys->i_id    = 1;

    p_sys->i_es    = 0;
    p_sys->es      = NULL;

    p_sys->i_audio = 0;
    p_sys->i_video = 0;
    p_sys->i_sub   = 0;

    var_Get( p_input, "audio-channel", &val );
    p_sys->i_audio_last = val.i_int;

    var_Get( p_input, "spu-channel", &val );
    p_sys->i_sub_last = val.i_int;

    p_sys->p_es_audio = NULL;
    p_sys->p_es_video = NULL;
    p_sys->p_es_sub   = NULL;
120
121
122
123
124
125
126
127
128
129
130
131

    return out;
}

/*****************************************************************************
 * input_EsOutDelete:
 *****************************************************************************/
void input_EsOutDelete( es_out_t *out )
{
    es_out_sys_t *p_sys = out->p_sys;
    int i;

132
    for( i = 0; i < p_sys->i_es; i++ )
133
    {
134
        free( p_sys->es[i] );
135
    }
136
    if( p_sys->es )
137
    {
138
        free( p_sys->es );
139
140
141
142
143
    }
    free( p_sys );
    free( out );
}

144
145
146
147
148
149
150
151
152
153
154
/*****************************************************************************
 * EsOutSelect: Select an ES given the current mode
 * XXX: you need to take a the lock before (stream.stream_lock)
 *****************************************************************************/
static void EsOutSelect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_force )
{
    es_out_sys_t      *p_sys = out->p_sys;
    input_thread_t    *p_input = p_sys->p_input;

    int i_cat = es->p_es->i_cat;

155
156
    if( !p_sys->b_active ||
        ( !b_force && es->p_es->fmt.i_priority < 0 ) )
157
158
159
160
161
162
    {
        return;
    }

    if( p_sys->i_mode == ES_OUT_MODE_ALL || b_force )
    {
163
164
165
166
        if( !es->p_es->p_dec )
        {
            input_SelectES( p_input, es->p_es );
        }
167
168
169
170
171
    }
    else if( p_sys->i_mode == ES_OUT_MODE_AUTO )
    {
        int i_wanted  = -1;

172
173
174
175
176
177
        if( es->p_es->p_pgrm != NULL &&
            es->p_es->p_pgrm != p_input->stream.p_selected_program )
        {
            return;
        }

178
179
        if( i_cat == AUDIO_ES )
        {
gbazin's avatar
   
gbazin committed
180
181
182
            if( p_sys->p_es_audio &&
                p_sys->p_es_audio->p_es->fmt.i_priority >=
                    es->p_es->fmt.i_priority )
183
184
185
            {
                return;
            }
gbazin's avatar
   
gbazin committed
186
187
            i_wanted  = p_sys->i_audio_last >= 0 ?
                            p_sys->i_audio_last : es->i_channel;
188
189
190
        }
        else if( i_cat == SPU_ES )
        {
gbazin's avatar
   
gbazin committed
191
192
193
            if( p_sys->p_es_sub &&
                p_sys->p_es_sub->p_es->fmt.i_priority >=
                    es->p_es->fmt.i_priority )
194
195
196
197
198
199
200
201
202
203
            {
                return;
            }
            i_wanted  = p_sys->i_sub_last;
        }
        else if( i_cat == VIDEO_ES )
        {
            i_wanted  = es->i_channel;
        }

Laurent Aimar's avatar
Laurent Aimar committed
204
        if( i_wanted == es->i_channel && es->p_es->p_dec == NULL )
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
        {
            input_SelectES( p_input, es->p_es );
        }
    }

    /* FIXME TODO handle priority here */
    if( es->p_es->p_dec )
    {
        if( i_cat == AUDIO_ES )
        {
            if( p_sys->i_mode == ES_OUT_MODE_AUTO &&
                p_sys->p_es_audio && p_sys->p_es_audio->p_es->p_dec )
            {
                input_UnselectES( p_input, p_sys->p_es_audio->p_es );
            }
            p_sys->p_es_audio = es;
        }
        else if( i_cat == SPU_ES )
        {
            if( p_sys->i_mode == ES_OUT_MODE_AUTO &&
                p_sys->p_es_sub && p_sys->p_es_sub->p_es->p_dec )
            {
                input_UnselectES( p_input, p_sys->p_es_sub->p_es );
            }
            p_sys->p_es_sub = es;
        }
        else if( i_cat == VIDEO_ES )
        {
            p_sys->p_es_video = es;
        }
    }
}

238
239
240
241
242
243
/*****************************************************************************
 * EsOutAdd:
 *****************************************************************************/
static es_out_id_t *EsOutAdd( es_out_t *out, es_format_t *fmt )
{
    es_out_sys_t      *p_sys = out->p_sys;
zorglub's avatar
zorglub committed
244
    playlist_t        *p_playlist = NULL;
245
    input_thread_t    *p_input = p_sys->p_input;
246
    es_out_id_t       *es = malloc( sizeof( es_out_id_t ) );
247
    pgrm_descriptor_t *p_prgm = NULL;
248
    char              psz_cat[sizeof( "Stream " ) + 10];
249
250
251
252
253
254
255
256
257
258
    input_info_category_t *p_cat;

    vlc_mutex_lock( &p_input->stream.stream_lock );
    if( fmt->i_group >= 0 )
    {
        /* search program */
        p_prgm = input_FindProgram( p_input, fmt->i_group );

        if( p_prgm == NULL )
        {
259
            es_descriptor_t *p_pmt;
260
261
262
            /* create it */
            p_prgm = input_AddProgram( p_input, fmt->i_group, 0 );

263
264
265
266
            /* XXX welcome to kludge, add a dummy es, if you want to understand
             * why have a look at input_SetProgram. Basicaly, it assume the first
             * es to be the PMT, how that is stupide, nevertheless it is needed for
             * the old ts demuxer */
267
268
            p_pmt = input_AddES( p_input, p_prgm, 0, UNKNOWN_ES, NULL, 0 );
            p_pmt->i_fourcc = VLC_FOURCC( 'n', 'u', 'l', 'l' );
269

270
271
272
273
274
275
276
            /* Select the first by default */
            if( p_input->stream.p_selected_program == NULL )
            {
                p_input->stream.p_selected_program = p_prgm;
            }
        }
    }
277
278
279
280
    if( fmt->i_id < 0 )
    {
        fmt->i_id = out->p_sys->i_id - 1;
    }
281

282
    es->p_es = input_AddES( p_input,
283
                            p_prgm,
284
                            fmt->i_id + 1,
285
                            fmt->i_cat,
Laurent Aimar's avatar
Laurent Aimar committed
286
                            fmt->psz_language, 0 );
287
    es->p_es->i_stream_id = fmt->i_id;
288
    es->p_es->i_fourcc = fmt->i_codec;
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307

    switch( fmt->i_cat )
    {
        case AUDIO_ES:
        {
            WAVEFORMATEX *p_wf =
                malloc( sizeof( WAVEFORMATEX ) + fmt->i_extra);

            p_wf->wFormatTag        = WAVE_FORMAT_UNKNOWN;
            p_wf->nChannels         = fmt->audio.i_channels;
            p_wf->nSamplesPerSec    = fmt->audio.i_rate;
            p_wf->nAvgBytesPerSec   = fmt->i_bitrate / 8;
            p_wf->nBlockAlign       = fmt->audio.i_blockalign;
            p_wf->wBitsPerSample    = fmt->audio.i_bitspersample;
            p_wf->cbSize            = fmt->i_extra;
            if( fmt->i_extra > 0 )
            {
                memcpy( &p_wf[1], fmt->p_extra, fmt->i_extra );
            }
308
309
310
            es->p_es->p_waveformatex = p_wf;

            es->i_channel = p_sys->i_audio;
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
            break;
        }
        case VIDEO_ES:
        {
            BITMAPINFOHEADER *p_bih = malloc( sizeof( BITMAPINFOHEADER ) +
                                              fmt->i_extra );
            p_bih->biSize           = sizeof(BITMAPINFOHEADER) + fmt->i_extra;
            p_bih->biWidth          = fmt->video.i_width;
            p_bih->biHeight         = fmt->video.i_height;
            p_bih->biPlanes         = 1;
            p_bih->biBitCount       = 24;
            p_bih->biCompression    = fmt->i_codec;
            p_bih->biSizeImage      = fmt->video.i_width *
                                          fmt->video.i_height;
            p_bih->biXPelsPerMeter  = 0;
            p_bih->biYPelsPerMeter  = 0;
            p_bih->biClrUsed        = 0;
            p_bih->biClrImportant   = 0;

            if( fmt->i_extra > 0 )
            {
                memcpy( &p_bih[1], fmt->p_extra, fmt->i_extra );
            }
334
335
336
            es->p_es->p_bitmapinfoheader = p_bih;

            es->i_channel = p_sys->i_video;
337
338
339
340
341
342
343
344
            break;
        }
        case SPU_ES:
        {
            subtitle_data_t *p_sub = malloc( sizeof( subtitle_data_t ) );
            memset( p_sub, 0, sizeof( subtitle_data_t ) );
            if( fmt->i_extra > 0 )
            {
345
                p_sub->psz_header = malloc( fmt->i_extra  + 1 );
346
                memcpy( p_sub->psz_header, fmt->p_extra , fmt->i_extra );
347
348
                /* just to be sure */
                ((uint8_t*)fmt->p_extra)[fmt->i_extra] = '\0';
349
350
            }
            /* FIXME beuuuuuurk */
351
352
353
            es->p_es->p_demux_data = p_sub;

            es->i_channel = p_sys->i_sub;
354
355
            break;
        }
356

357
        default:
358
            es->i_channel = 0;
359
360
361
            break;
    }

362
    sprintf( psz_cat, _("Stream %d"), out->p_sys->i_id - 1 );
zorglub's avatar
zorglub committed
363
364
365
366
    /* Get a category and the playlist */
    if( ( p_cat = input_InfoCategory( p_input, psz_cat ) ) &&
        ( p_playlist = (playlist_t *)vlc_object_find( p_input,
                       VLC_OBJECT_PLAYLIST, FIND_ANYWHERE ) ) )
367
368
369
370
371
    {
        /* Add information */
        switch( fmt->i_cat )
        {
            case AUDIO_ES:
gbazin's avatar
   
gbazin committed
372
373
                if( fmt->psz_description )
                {
Sam Hocevar's avatar
Sam Hocevar committed
374
                    input_AddInfo( p_cat, _("Description"), "%s",
gbazin's avatar
   
gbazin committed
375
                                   fmt->psz_description );
zorglub's avatar
zorglub committed
376
377
378
                    playlist_AddInfo( p_playlist, -1, psz_cat,
                                     _("Description"), "%s",
                                     fmt->psz_description );
gbazin's avatar
   
gbazin committed
379
                }
380
381
                input_AddInfo( p_cat, _("Codec"), "%.4s",
                               (char*)&fmt->i_codec );
zorglub's avatar
zorglub committed
382
383
384
                playlist_AddInfo( p_playlist, -1, psz_cat,
                                  _("Codec"),"%.4s",(char*)&fmt->i_codec );

385
                input_AddInfo( p_cat, _("Type"), _("Audio") );
zorglub's avatar
zorglub committed
386
387
388
                playlist_AddInfo( p_playlist, -1, psz_cat,
                                 _("Type"), _("Audio") );

389
390
391
392
                if( fmt->audio.i_channels > 0 )
                {
                    input_AddInfo( p_cat, _("Channels"), "%d",
                                   fmt->audio.i_channels );
zorglub's avatar
zorglub committed
393
394
                    playlist_AddInfo( p_playlist, -1, psz_cat,
                                      _("Channels"), "%d",                                                            fmt->audio.i_channels );
395
                }
gbazin's avatar
   
gbazin committed
396
397
                if( fmt->psz_language )
                {
Sam Hocevar's avatar
Sam Hocevar committed
398
                    input_AddInfo( p_cat, _("Language"), "%s",
gbazin's avatar
   
gbazin committed
399
                                   fmt->psz_language );
zorglub's avatar
zorglub committed
400
401
402
                    playlist_AddInfo( p_playlist, -1, psz_cat,
                                     _("Language"), "%s",
                                     fmt->psz_language );
gbazin's avatar
   
gbazin committed
403
                }
404
405
                if( fmt->audio.i_rate > 0 )
                {
zorglub's avatar
zorglub committed
406
                    input_AddInfo( p_cat, _("Sample rate"), _("%d Hz"),
407
                                   fmt->audio.i_rate );
zorglub's avatar
zorglub committed
408
409
410
                    playlist_AddInfo( p_playlist, -1, psz_cat,
                                     _("Sample rate"), _("%d Hz"),
                                      fmt->audio.i_rate );
411
412
413
                }
                if( fmt->i_bitrate > 0 )
                {
zorglub's avatar
zorglub committed
414
                    input_AddInfo( p_cat, _("Bitrate"), _("%d bps"),
415
                                   fmt->i_bitrate );
zorglub's avatar
zorglub committed
416
417
418
                    playlist_AddInfo( p_playlist, -1, psz_cat,
                                    _("Bitrate"), _("%d bps"),
                                     fmt->i_bitrate );
419
420
421
                }
                if( fmt->audio.i_bitspersample )
                {
Sam Hocevar's avatar
Sam Hocevar committed
422
                    input_AddInfo( p_cat, _("Bits per sample"), "%d",
423
                                   fmt->audio.i_bitspersample );
zorglub's avatar
zorglub committed
424
425
426
                    playlist_AddInfo( p_playlist, -1, psz_cat,
                                     _("Bits per sample"), "%d",
                                     fmt->audio.i_bitspersample );
427
428
429
                }
                break;
            case VIDEO_ES:
gbazin's avatar
   
gbazin committed
430
431
                if( fmt->psz_description )
                {
Sam Hocevar's avatar
Sam Hocevar committed
432
                    input_AddInfo( p_cat, _("Description"), "%s",
gbazin's avatar
   
gbazin committed
433
                                   fmt->psz_description );
zorglub's avatar
zorglub committed
434
435
436
                    playlist_AddInfo( p_playlist, -1, psz_cat,
                                     _("Description"), "%s",
                                     fmt->psz_description );
gbazin's avatar
   
gbazin committed
437
                }
438
                input_AddInfo( p_cat, _("Type"), _("Video") );
zorglub's avatar
zorglub committed
439
440
441
                playlist_AddInfo( p_playlist, -1, psz_cat,
                                _("Type"), _("Video") );

442
443
                input_AddInfo( p_cat, _("Codec"), "%.4s",
                               (char*)&fmt->i_codec );
zorglub's avatar
zorglub committed
444
445
446
447
                playlist_AddInfo( p_playlist, -1, psz_cat,
                                 _("Codec"), "%.4s",
                                 (char*)&fmt->i_codec );

448
449
450
451
                if( fmt->video.i_width > 0 && fmt->video.i_height > 0 )
                {
                    input_AddInfo( p_cat, _("Resolution"), "%dx%d",
                                   fmt->video.i_width, fmt->video.i_height );
zorglub's avatar
zorglub committed
452
453
454
                    playlist_AddInfo( p_playlist, -1, psz_cat,
                                    _("Resolution"), "%dx%d",
                                    fmt->video.i_width, fmt->video.i_height );
455
456
457
458
                }
                if( fmt->video.i_visible_width > 0 &&
                    fmt->video.i_visible_height > 0 )
                {
Sam Hocevar's avatar
Sam Hocevar committed
459
                    input_AddInfo( p_cat, _("Display resolution"), "%dx%d",
460
461
                                   fmt->video.i_visible_width,
                                   fmt->video.i_visible_height);
zorglub's avatar
zorglub committed
462
463
464
465
                     playlist_AddInfo( p_playlist, -1, psz_cat,
                                       _("Display resolution"), "%dx%d",
                                       fmt->video.i_visible_width,
                                       fmt->video.i_visible_height);
466
467
468
469
                }
                break;
            case SPU_ES:
                input_AddInfo( p_cat, _("Type"), _("Subtitle") );
zorglub's avatar
zorglub committed
470
471
                playlist_AddInfo( p_playlist, -1, psz_cat,
                                   _("Type"), _("Subtitle") );
472
473
                input_AddInfo( p_cat, _("Codec"), "%.4s",
                               (char*)&fmt->i_codec );
zorglub's avatar
zorglub committed
474
475
476
                playlist_AddInfo( p_playlist, -1, psz_cat,
                                 _("Codec"), "%.4s",
                                 (char*)&fmt->i_codec );
477
478
479
480
481
                break;
            default:

                break;
        }
zorglub's avatar
zorglub committed
482
        if( p_playlist ) vlc_object_release( p_playlist );
483
484
    }

485
486
487
    /* Apply mode
     * XXX change that when we do group too */
    if( 1 )
488
    {
489
        EsOutSelect( out, es, VLC_FALSE );
490
    }
491
492
493
494
495
496
497
498

    vlc_mutex_unlock( &p_input->stream.stream_lock );

    es->p_es->fmt = *fmt;

    TAB_APPEND( out->p_sys->i_es, out->p_sys->es, es );
    p_sys->i_id++;  /* always incremented */
    switch( fmt->i_cat )
499
    {
500
501
502
503
504
505
506
507
508
        case AUDIO_ES:
            p_sys->i_audio++;
            break;
        case SPU_ES:
            p_sys->i_sub++;
            break;
        case VIDEO_ES:
            p_sys->i_video++;
            break;
509
    }
510
511

    return es;
512
513
514
}

/*****************************************************************************
515
 * EsOutSend:
516
 *****************************************************************************/
517
static int EsOutSend( es_out_t *out, es_out_id_t *es, block_t *p_block )
518
{
519
520
    es_out_sys_t *p_sys = out->p_sys;

521
    if( p_sys->b_pcr_set )
522
    {
523
524
525
526
527
528
529
        pgrm_descriptor_t *p_pgrm = es->p_es->p_pgrm;
        input_thread_t    *p_input = p_sys->p_input;

        if( p_pgrm == NULL )
        {
            p_pgrm = p_sys->p_input->stream.p_selected_program;
        }
530

531
        if( p_block->i_dts > 0 && p_pgrm )
532
        {
gbazin's avatar
   
gbazin committed
533
            p_block->i_dts =
534
                input_ClockGetTS( p_input, p_pgrm, p_block->i_dts * 9 / 100 );
535
        }
536
        if( p_block->i_pts > 0 && p_pgrm )
537
        {
gbazin's avatar
   
gbazin committed
538
            p_block->i_pts =
539
                input_ClockGetTS( p_input, p_pgrm, p_block->i_pts * 9 / 100 );
540
541
        }
    }
gbazin's avatar
   
gbazin committed
542

543
    vlc_mutex_lock( &out->p_sys->p_input->stream.stream_lock );
gbazin's avatar
   
gbazin committed
544
545
546
    p_block->i_rate = out->p_sys->p_input->stream.control.i_rate;
    if( es->p_es->p_dec &&
        (es->p_es->i_cat!=AUDIO_ES || !p_sys->p_input->stream.control.b_mute) )
547
    {
548
        input_DecodeBlock( es->p_es->p_dec, p_block );
549
550
551
    }
    else
    {
552
        block_Release( p_block );
553
    }
554
    vlc_mutex_unlock( &out->p_sys->p_input->stream.stream_lock );
gbazin's avatar
   
gbazin committed
555

556
557
558
559
560
561
    return VLC_SUCCESS;
}

/*****************************************************************************
 * EsOutDel:
 *****************************************************************************/
562
static void EsOutDel( es_out_t *out, es_out_id_t *es )
563
564
565
{
    es_out_sys_t *p_sys = out->p_sys;

566
567
568
569
570
571
572
573
574
575
576
577
578
579
    TAB_REMOVE( p_sys->i_es, p_sys->es, es );

    switch( es->p_es->i_cat )
    {
        case AUDIO_ES:
            p_sys->i_audio--;
            break;
        case SPU_ES:
            p_sys->i_sub--;
            break;
        case VIDEO_ES:
            p_sys->i_video--;
            break;
    }
580

581
    /* We don't try to reselect */
582
    vlc_mutex_lock( &p_sys->p_input->stream.stream_lock );
583
    if( es->p_es->p_dec )
584
    {
585
        input_UnselectES( p_sys->p_input, es->p_es );
586
    }
587
588

    if( es->p_es->p_waveformatex )
589
    {
590
591
        free( es->p_es->p_waveformatex );
        es->p_es->p_waveformatex = NULL;
592
    }
593
    if( es->p_es->p_bitmapinfoheader )
594
    {
595
596
        free( es->p_es->p_bitmapinfoheader );
        es->p_es->p_bitmapinfoheader = NULL;
597
    }
598
599
    input_DelES( p_sys->p_input, es->p_es );

gbazin's avatar
   
gbazin committed
600
601
602
603
    if( p_sys->p_es_audio == es ) p_sys->p_es_audio = NULL;
    if( p_sys->p_es_video == es ) p_sys->p_es_video = NULL;
    if( p_sys->p_es_sub   == es ) p_sys->p_es_sub   = NULL;

604
605
    vlc_mutex_unlock( &p_sys->p_input->stream.stream_lock );

606
    free( es );
607
608
609
610
611
612
613
614
615
}

/*****************************************************************************
 * EsOutControl:
 *****************************************************************************/
static int EsOutControl( es_out_t *out, int i_query, va_list args )
{
    es_out_sys_t *p_sys = out->p_sys;
    vlc_bool_t  b, *pb;
616
617
618
619
    int         i, *pi;

    es_out_id_t *es;

620
621
    switch( i_query )
    {
622
        case ES_OUT_SET_ES_STATE:
623
            vlc_mutex_lock( &p_sys->p_input->stream.stream_lock );
624
            es = (es_out_id_t*) va_arg( args, es_out_id_t * );
625
            b = (vlc_bool_t) va_arg( args, vlc_bool_t );
626
            if( b && es->p_es->p_dec == NULL )
627
            {
628
                input_SelectES( p_sys->p_input, es->p_es );
629
                vlc_mutex_unlock( &p_sys->p_input->stream.stream_lock );
630
                return es->p_es->p_dec ? VLC_SUCCESS : VLC_EGENERIC;
631
            }
632
            else if( !b && es->p_es->p_dec )
633
            {
634
                input_UnselectES( p_sys->p_input, es->p_es );
635
636
637
                vlc_mutex_unlock( &p_sys->p_input->stream.stream_lock );
                return VLC_SUCCESS;
            }
Laurent Aimar's avatar
Laurent Aimar committed
638
639
640
            vlc_mutex_unlock( &p_sys->p_input->stream.stream_lock );
            return VLC_SUCCESS;

641
642
        case ES_OUT_GET_ES_STATE:
            es = (es_out_id_t*) va_arg( args, es_out_id_t * );
643
644
            pb = (vlc_bool_t*) va_arg( args, vlc_bool_t * );

645
646
647
648
            *pb = es->p_es->p_dec ? VLC_TRUE : VLC_FALSE;
            return VLC_SUCCESS;

        case ES_OUT_SET_ACTIVE:
649
        {
650
651
            b = (vlc_bool_t) va_arg( args, vlc_bool_t );
            p_sys->b_active = b;
652
653
654
655
656
657
658

            if( b )
            {
                vlc_value_t val;
                val.b_bool = VLC_TRUE;
                var_Set( p_sys->p_input, "intf-change", val );
            }
659
            return VLC_SUCCESS;
660
        }
661
662
663
664
665
666
667
668

        case ES_OUT_GET_ACTIVE:
            pb = (vlc_bool_t*) va_arg( args, vlc_bool_t * );
            *pb = p_sys->b_active;
            return VLC_SUCCESS;

        case ES_OUT_SET_MODE:
            i = (int) va_arg( args, int );
gbazin's avatar
   
gbazin committed
669
670
            if( i == ES_OUT_MODE_NONE || i == ES_OUT_MODE_ALL ||
                i == ES_OUT_MODE_AUTO )
671
            {
672
673
                vlc_value_t val;

674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
                p_sys->i_mode = i;

                /* Reapply policy mode */
                vlc_mutex_lock( &p_sys->p_input->stream.stream_lock );
                for( i = 0; i < p_sys->i_es; i++ )
                {
                    if( p_sys->es[i]->p_es->p_dec )
                    {
                        input_UnselectES( p_sys->p_input, p_sys->es[i]->p_es );
                    }
                }
                for( i = 0; i < p_sys->i_es; i++ )
                {
                    EsOutSelect( out, p_sys->es[i], VLC_FALSE );
                }
                vlc_mutex_unlock( &p_sys->p_input->stream.stream_lock );
690
691
692
693

                val.b_bool = VLC_TRUE;
                var_Set( p_sys->p_input, "intf-change", val );

694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
                return VLC_SUCCESS;
            }
            return VLC_EGENERIC;

        case ES_OUT_GET_MODE:
            pi = (int*) va_arg( args, int* );
            *pi = p_sys->i_mode;
            return VLC_SUCCESS;

        case ES_OUT_SET_ES:
            es = (es_out_id_t*) va_arg( args, es_out_id_t * );
            if( es == NULL )
            {
                for( i = 0; i < p_sys->i_es; i++ )
                {
                    vlc_mutex_lock( &p_sys->p_input->stream.stream_lock );
                    if( p_sys->es[i]->p_es->p_dec )
                    {
                        input_UnselectES( p_sys->p_input, p_sys->es[i]->p_es );
                    }
                    vlc_mutex_unlock( &p_sys->p_input->stream.stream_lock );
                }
            }
            else
            {
                vlc_mutex_lock( &p_sys->p_input->stream.stream_lock );
                EsOutSelect( out, es, VLC_TRUE );
                vlc_mutex_unlock( &p_sys->p_input->stream.stream_lock );
            }
723
724
            return VLC_SUCCESS;

725
        case ES_OUT_SET_PCR:
726
        case ES_OUT_SET_GROUP_PCR:
727
728
        {
            pgrm_descriptor_t *p_prgm = NULL;
729
            int64_t           i_pcr;
730

731
732
733
734
735
736
737
738
739
            if( i_query == ES_OUT_SET_PCR )
            {
                p_prgm = p_sys->p_input->stream.p_selected_program;
            }
            else
            {
                int i_group = (int)va_arg( args, int );
                p_prgm = input_FindProgram( p_sys->p_input, i_group );
            }
740
741
742
            i_pcr   = (int64_t)va_arg( args, int64_t );

            /* search program */
743
            if( p_prgm )
744
            {
745
                input_ClockManageRef( p_sys->p_input, p_prgm, i_pcr * 9 / 100);
746
747
748
749
750
751
            }
            p_sys->b_pcr_set = VLC_TRUE;
            return VLC_SUCCESS;
        }

        case ES_OUT_RESET_PCR:
752
            for( i = 0; i < p_sys->p_input->stream.i_pgrm_number; i++ )
753
            {
754
                p_sys->p_input->stream.pp_programs[i]->i_synchro_state = SYNCHRO_REINIT;
755
756
757
758
            }
            p_sys->b_pcr_set = VLC_TRUE;
            return VLC_SUCCESS;

759
760
761
762
763
        default:
            msg_Err( p_sys->p_input, "unknown query in es_out_Control" );
            return VLC_EGENERIC;
    }
}