es_out.c 26.6 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.22 2004/01/30 14:25:39 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
#include "codecs.h"
35
#include "iso_lang.h"
36
37
38
39

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

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

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

54
55
    int         i_es;
    es_out_id_t **es;
56

57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
    /* 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;
74
75
76
77
78
79
80
};

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 );

81
static char *LanguageGetName( const char *psz_code );
82

zorglub's avatar
zorglub committed
83
84
85
86
87
88
/**
 * Create a new es_out structure
 *
 * \param p_input The related input thread
 * \return the new es_out_t
 */
89
90
es_out_t *input_EsOutNew( input_thread_t *p_input )
{
91
92
93
    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;
94
95
96
97
98

    out->pf_add     = EsOutAdd;
    out->pf_send    = EsOutSend;
    out->pf_del     = EsOutDel;
    out->pf_control = EsOutControl;
99
100
101
    out->p_sys      = p_sys;

    p_sys->p_input = p_input;
102
    p_sys->b_pcr_set = VLC_FALSE;
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124

    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;
125
126
127
128

    return out;
}

zorglub's avatar
zorglub committed
129
130
131
132
133
134
/**
 * Deletes an es_out structure
 *
 * \param out  the es_out structure to destroy
 * \return nothing
 */
135
136
137
138
139
void input_EsOutDelete( es_out_t *out )
{
    es_out_sys_t *p_sys = out->p_sys;
    int i;

140
    for( i = 0; i < p_sys->i_es; i++ )
141
    {
142
        free( p_sys->es[i] );
143
    }
144
    if( p_sys->es )
145
    {
146
        free( p_sys->es );
147
148
149
150
    }
    free( p_sys );
    free( out );
}
zorglub's avatar
zorglub committed
151
152
153
154
155
156
157
158

/**
 * Add a program
 *
 * \param out the es_out
 * \param i_group ...
 * \return a program descriptor for the new program
 */
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
static pgrm_descriptor_t *EsOutAddProgram( es_out_t *out, int i_group )
{
    input_thread_t    *p_input = out->p_sys->p_input;
    pgrm_descriptor_t *p_prgm;
    es_descriptor_t   *p_pmt;

    /* FIXME we should use a object variable but a lot of place in src/input
     * have to be changed */
    int               i_select = config_GetInt( p_input, "program" );

    /* create it */
    p_prgm = input_AddProgram( p_input, i_group, 0 );

    /* 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
zorglub's avatar
zorglub committed
174
     * es to be the PMT, how that is stupid, nevertheless it is needed for
175
176
177
178
179
180
181
182
183
184
185
186
187
     * the old ts demuxer */
    p_pmt = input_AddES( p_input, p_prgm, 0, UNKNOWN_ES, NULL, 0 );
    p_pmt->i_fourcc = VLC_FOURCC( 'n', 'u', 'l', 'l' );

    /* Select i_select or the first by default */
    if( p_input->stream.p_selected_program == NULL &&
        ( i_select <= 0 || i_select == i_group ) )
    {
        p_input->stream.p_selected_program = p_prgm;
    }

    return p_prgm;
}
188

zorglub's avatar
zorglub committed
189
190
/**
 * Select an ES given the current mode
191
 * XXX: you need to take a the lock before (stream.stream_lock)
zorglub's avatar
zorglub committed
192
193
194
195
196
197
 *
 * \param out The es_out structure
 * \param es es_out_id structure
 * \param b_force ...
 * \return nothing
 */
198
199
200
201
202
203
204
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;

205
206
    if( !p_sys->b_active ||
        ( !b_force && es->p_es->fmt.i_priority < 0 ) )
207
208
209
210
211
212
    {
        return;
    }

    if( p_sys->i_mode == ES_OUT_MODE_ALL || b_force )
    {
213
214
215
216
        if( !es->p_es->p_dec )
        {
            input_SelectES( p_input, es->p_es );
        }
217
218
219
220
221
    }
    else if( p_sys->i_mode == ES_OUT_MODE_AUTO )
    {
        int i_wanted  = -1;

222
223
224
225
226
227
        if( es->p_es->p_pgrm != NULL &&
            es->p_es->p_pgrm != p_input->stream.p_selected_program )
        {
            return;
        }

228
229
        if( i_cat == AUDIO_ES )
        {
gbazin's avatar
   
gbazin committed
230
231
232
            if( p_sys->p_es_audio &&
                p_sys->p_es_audio->p_es->fmt.i_priority >=
                    es->p_es->fmt.i_priority )
233
234
235
            {
                return;
            }
gbazin's avatar
   
gbazin committed
236
237
            i_wanted  = p_sys->i_audio_last >= 0 ?
                            p_sys->i_audio_last : es->i_channel;
238
239
240
        }
        else if( i_cat == SPU_ES )
        {
gbazin's avatar
   
gbazin committed
241
242
243
            if( p_sys->p_es_sub &&
                p_sys->p_es_sub->p_es->fmt.i_priority >=
                    es->p_es->fmt.i_priority )
244
245
246
247
248
249
250
251
252
253
            {
                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
254
        if( i_wanted == es->i_channel && es->p_es->p_dec == NULL )
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
        {
            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;
        }
    }
}

zorglub's avatar
zorglub committed
288
289
290
291
292
293
294
/**
 * Add an es_out
 *
 * \param out the es_out to add
 * \param fmt the es_format of the es_out
 * \return an es_out id
 */
295
296
297
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
298
    playlist_t        *p_playlist = NULL;
299
    input_thread_t    *p_input = p_sys->p_input;
300
    es_out_id_t       *es = malloc( sizeof( es_out_id_t ) );
301
    pgrm_descriptor_t *p_prgm = NULL;
zorglub's avatar
zorglub committed
302
    char              psz_cat[sizeof( _("Stream ") ) + 10];
303
    input_info_category_t *p_cat;
304
    char              *psz_description;
305
306
307
308
309
310
311
312
313

    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 )
        {
314
315
            /* Create it */
            p_prgm = EsOutAddProgram( out, fmt->i_group );
316
317
        }
    }
318
319
320
321
    if( fmt->i_id < 0 )
    {
        fmt->i_id = out->p_sys->i_id - 1;
    }
322

323
    psz_description = LanguageGetName( fmt->psz_language );
324
    es->p_es = input_AddES( p_input,
325
                            p_prgm,
326
                            fmt->i_id + 1,
327
                            fmt->i_cat,
328
                            psz_description, 0 );
329
    es->p_es->i_stream_id = fmt->i_id;
330
    es->p_es->i_fourcc = fmt->i_codec;
331
    free( psz_description );
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350

    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 );
            }
351
352
353
            es->p_es->p_waveformatex = p_wf;

            es->i_channel = p_sys->i_audio;
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
            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 );
            }
377
378
379
            es->p_es->p_bitmapinfoheader = p_bih;

            es->i_channel = p_sys->i_video;
380
381
382
383
384
385
386
387
            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 )
            {
388
                p_sub->psz_header = malloc( fmt->i_extra  + 1 );
389
                memcpy( p_sub->psz_header, fmt->p_extra , fmt->i_extra );
390
391
                /* just to be sure */
                ((uint8_t*)fmt->p_extra)[fmt->i_extra] = '\0';
392
393
            }
            /* FIXME beuuuuuurk */
394
395
396
            es->p_es->p_demux_data = p_sub;

            es->i_channel = p_sys->i_sub;
397
398
            break;
        }
399

400
        default:
401
            es->i_channel = 0;
402
403
404
            break;
    }

405
    sprintf( psz_cat, _("Stream %d"), out->p_sys->i_id - 1 );
zorglub's avatar
zorglub committed
406
407
408
409
    /* 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 ) ) )
410
411
412
413
414
    {
        /* Add information */
        switch( fmt->i_cat )
        {
            case AUDIO_ES:
gbazin's avatar
   
gbazin committed
415
416
                if( fmt->psz_description )
                {
Sam Hocevar's avatar
Sam Hocevar committed
417
                    input_AddInfo( p_cat, _("Description"), "%s",
gbazin's avatar
   
gbazin committed
418
                                   fmt->psz_description );
zorglub's avatar
zorglub committed
419
420
421
                    playlist_AddInfo( p_playlist, -1, psz_cat,
                                     _("Description"), "%s",
                                     fmt->psz_description );
gbazin's avatar
   
gbazin committed
422
                }
423
424
                input_AddInfo( p_cat, _("Codec"), "%.4s",
                               (char*)&fmt->i_codec );
zorglub's avatar
zorglub committed
425
426
427
                playlist_AddInfo( p_playlist, -1, psz_cat,
                                  _("Codec"),"%.4s",(char*)&fmt->i_codec );

428
                input_AddInfo( p_cat, _("Type"), _("Audio") );
zorglub's avatar
zorglub committed
429
430
431
                playlist_AddInfo( p_playlist, -1, psz_cat,
                                 _("Type"), _("Audio") );

432
433
434
435
                if( fmt->audio.i_channels > 0 )
                {
                    input_AddInfo( p_cat, _("Channels"), "%d",
                                   fmt->audio.i_channels );
zorglub's avatar
zorglub committed
436
437
                    playlist_AddInfo( p_playlist, -1, psz_cat,
                                      _("Channels"), "%d",                                                            fmt->audio.i_channels );
438
                }
gbazin's avatar
   
gbazin committed
439
440
                if( fmt->psz_language )
                {
Sam Hocevar's avatar
Sam Hocevar committed
441
                    input_AddInfo( p_cat, _("Language"), "%s",
gbazin's avatar
   
gbazin committed
442
                                   fmt->psz_language );
zorglub's avatar
zorglub committed
443
444
445
                    playlist_AddInfo( p_playlist, -1, psz_cat,
                                     _("Language"), "%s",
                                     fmt->psz_language );
gbazin's avatar
   
gbazin committed
446
                }
447
448
                if( fmt->audio.i_rate > 0 )
                {
zorglub's avatar
zorglub committed
449
                    input_AddInfo( p_cat, _("Sample rate"), _("%d Hz"),
450
                                   fmt->audio.i_rate );
zorglub's avatar
zorglub committed
451
452
453
                    playlist_AddInfo( p_playlist, -1, psz_cat,
                                     _("Sample rate"), _("%d Hz"),
                                      fmt->audio.i_rate );
454
455
456
                }
                if( fmt->i_bitrate > 0 )
                {
zorglub's avatar
zorglub committed
457
                    input_AddInfo( p_cat, _("Bitrate"), _("%d bps"),
458
                                   fmt->i_bitrate );
zorglub's avatar
zorglub committed
459
460
461
                    playlist_AddInfo( p_playlist, -1, psz_cat,
                                    _("Bitrate"), _("%d bps"),
                                     fmt->i_bitrate );
462
463
464
                }
                if( fmt->audio.i_bitspersample )
                {
Sam Hocevar's avatar
Sam Hocevar committed
465
                    input_AddInfo( p_cat, _("Bits per sample"), "%d",
466
                                   fmt->audio.i_bitspersample );
zorglub's avatar
zorglub committed
467
468
469
                    playlist_AddInfo( p_playlist, -1, psz_cat,
                                     _("Bits per sample"), "%d",
                                     fmt->audio.i_bitspersample );
470
471
472
                }
                break;
            case VIDEO_ES:
gbazin's avatar
   
gbazin committed
473
474
                if( fmt->psz_description )
                {
Sam Hocevar's avatar
Sam Hocevar committed
475
                    input_AddInfo( p_cat, _("Description"), "%s",
gbazin's avatar
   
gbazin committed
476
                                   fmt->psz_description );
zorglub's avatar
zorglub committed
477
478
479
                    playlist_AddInfo( p_playlist, -1, psz_cat,
                                     _("Description"), "%s",
                                     fmt->psz_description );
gbazin's avatar
   
gbazin committed
480
                }
481
                input_AddInfo( p_cat, _("Type"), _("Video") );
zorglub's avatar
zorglub committed
482
483
484
                playlist_AddInfo( p_playlist, -1, psz_cat,
                                _("Type"), _("Video") );

485
486
                input_AddInfo( p_cat, _("Codec"), "%.4s",
                               (char*)&fmt->i_codec );
zorglub's avatar
zorglub committed
487
488
489
490
                playlist_AddInfo( p_playlist, -1, psz_cat,
                                 _("Codec"), "%.4s",
                                 (char*)&fmt->i_codec );

491
492
493
494
                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
495
496
497
                    playlist_AddInfo( p_playlist, -1, psz_cat,
                                    _("Resolution"), "%dx%d",
                                    fmt->video.i_width, fmt->video.i_height );
498
499
500
501
                }
                if( fmt->video.i_visible_width > 0 &&
                    fmt->video.i_visible_height > 0 )
                {
Sam Hocevar's avatar
Sam Hocevar committed
502
                    input_AddInfo( p_cat, _("Display resolution"), "%dx%d",
503
504
                                   fmt->video.i_visible_width,
                                   fmt->video.i_visible_height);
zorglub's avatar
zorglub committed
505
506
507
508
                     playlist_AddInfo( p_playlist, -1, psz_cat,
                                       _("Display resolution"), "%dx%d",
                                       fmt->video.i_visible_width,
                                       fmt->video.i_visible_height);
509
510
511
512
                }
                break;
            case SPU_ES:
                input_AddInfo( p_cat, _("Type"), _("Subtitle") );
zorglub's avatar
zorglub committed
513
514
                playlist_AddInfo( p_playlist, -1, psz_cat,
                                   _("Type"), _("Subtitle") );
515
516
                input_AddInfo( p_cat, _("Codec"), "%.4s",
                               (char*)&fmt->i_codec );
zorglub's avatar
zorglub committed
517
518
519
                playlist_AddInfo( p_playlist, -1, psz_cat,
                                 _("Codec"), "%.4s",
                                 (char*)&fmt->i_codec );
520
521
522
523
524
                break;
            default:

                break;
        }
zorglub's avatar
zorglub committed
525
        if( p_playlist ) vlc_object_release( p_playlist );
526
527
    }

528
529
530
    /* Apply mode
     * XXX change that when we do group too */
    if( 1 )
531
    {
532
        EsOutSelect( out, es, VLC_FALSE );
533
    }
534
535
536
537
538
539
540
541

    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 )
542
    {
543
544
545
546
547
548
549
550
551
        case AUDIO_ES:
            p_sys->i_audio++;
            break;
        case SPU_ES:
            p_sys->i_sub++;
            break;
        case VIDEO_ES:
            p_sys->i_video++;
            break;
552
    }
553
554

    return es;
555
556
}

zorglub's avatar
zorglub committed
557
558
559
560
561
562
563
/**
 * Send a block for the given es_out
 *
 * \param out the es_out to send from
 * \param es the es_out_id
 * \param p_block the data block to send
 */
564
static int EsOutSend( es_out_t *out, es_out_id_t *es, block_t *p_block )
565
{
566
567
    es_out_sys_t *p_sys = out->p_sys;

568
    if( p_sys->b_pcr_set )
569
    {
570
571
572
573
574
575
576
        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;
        }
577

578
        if( p_block->i_dts > 0 && p_pgrm )
579
        {
gbazin's avatar
   
gbazin committed
580
            p_block->i_dts =
581
                input_ClockGetTS( p_input, p_pgrm, p_block->i_dts * 9 / 100 );
582
        }
583
        if( p_block->i_pts > 0 && p_pgrm )
584
        {
gbazin's avatar
   
gbazin committed
585
            p_block->i_pts =
586
                input_ClockGetTS( p_input, p_pgrm, p_block->i_pts * 9 / 100 );
587
588
        }
    }
gbazin's avatar
   
gbazin committed
589

590
    vlc_mutex_lock( &out->p_sys->p_input->stream.stream_lock );
gbazin's avatar
   
gbazin committed
591
592
593
    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) )
594
    {
595
        input_DecodeBlock( es->p_es->p_dec, p_block );
596
597
598
    }
    else
    {
599
        block_Release( p_block );
600
    }
601
    vlc_mutex_unlock( &out->p_sys->p_input->stream.stream_lock );
gbazin's avatar
   
gbazin committed
602

603
604
605
606
607
608
    return VLC_SUCCESS;
}

/*****************************************************************************
 * EsOutDel:
 *****************************************************************************/
609
static void EsOutDel( es_out_t *out, es_out_id_t *es )
610
611
612
{
    es_out_sys_t *p_sys = out->p_sys;

613
614
615
616
617
618
619
620
621
622
623
624
625
626
    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;
    }
627

628
    /* We don't try to reselect */
629
    vlc_mutex_lock( &p_sys->p_input->stream.stream_lock );
630
    if( es->p_es->p_dec )
631
    {
632
        input_UnselectES( p_sys->p_input, es->p_es );
633
    }
634
635

    if( es->p_es->p_waveformatex )
636
    {
637
638
        free( es->p_es->p_waveformatex );
        es->p_es->p_waveformatex = NULL;
639
    }
640
    if( es->p_es->p_bitmapinfoheader )
641
    {
642
643
        free( es->p_es->p_bitmapinfoheader );
        es->p_es->p_bitmapinfoheader = NULL;
644
    }
645
646
    input_DelES( p_sys->p_input, es->p_es );

gbazin's avatar
   
gbazin committed
647
648
649
650
    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;

651
652
    vlc_mutex_unlock( &p_sys->p_input->stream.stream_lock );

653
    free( es );
654
655
}

zorglub's avatar
zorglub committed
656
657
658
659
660
661
662
663
/**
 * Control query handler
 *
 * \param out the es_out to control
 * \param i_query A es_out query as defined in include/ninput.h
 * \param args a variable list of arguments for the query
 * \return VLC_SUCCESS or an error code
 */
664
665
666
667
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;
668
669
670
671
    int         i, *pi;

    es_out_id_t *es;

672
673
    switch( i_query )
    {
674
        case ES_OUT_SET_ES_STATE:
675
            vlc_mutex_lock( &p_sys->p_input->stream.stream_lock );
676
            es = (es_out_id_t*) va_arg( args, es_out_id_t * );
677
            b = (vlc_bool_t) va_arg( args, vlc_bool_t );
678
            if( b && es->p_es->p_dec == NULL )
679
            {
680
                input_SelectES( p_sys->p_input, es->p_es );
681
                vlc_mutex_unlock( &p_sys->p_input->stream.stream_lock );
682
                return es->p_es->p_dec ? VLC_SUCCESS : VLC_EGENERIC;
683
            }
684
            else if( !b && es->p_es->p_dec )
685
            {
686
                input_UnselectES( p_sys->p_input, es->p_es );
687
688
689
                vlc_mutex_unlock( &p_sys->p_input->stream.stream_lock );
                return VLC_SUCCESS;
            }
Laurent Aimar's avatar
Laurent Aimar committed
690
691
692
            vlc_mutex_unlock( &p_sys->p_input->stream.stream_lock );
            return VLC_SUCCESS;

693
694
        case ES_OUT_GET_ES_STATE:
            es = (es_out_id_t*) va_arg( args, es_out_id_t * );
695
696
            pb = (vlc_bool_t*) va_arg( args, vlc_bool_t * );

697
698
699
700
            *pb = es->p_es->p_dec ? VLC_TRUE : VLC_FALSE;
            return VLC_SUCCESS;

        case ES_OUT_SET_ACTIVE:
701
        {
702
703
            b = (vlc_bool_t) va_arg( args, vlc_bool_t );
            p_sys->b_active = b;
704
705
706
707
708
709
710

            if( b )
            {
                vlc_value_t val;
                val.b_bool = VLC_TRUE;
                var_Set( p_sys->p_input, "intf-change", val );
            }
711
            return VLC_SUCCESS;
712
        }
713
714
715
716
717
718
719
720

        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
721
722
            if( i == ES_OUT_MODE_NONE || i == ES_OUT_MODE_ALL ||
                i == ES_OUT_MODE_AUTO )
723
            {
724
725
                vlc_value_t val;

726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
                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 );
742
743
744
745

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

746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
                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 );
            }
775
776
            return VLC_SUCCESS;

777
        case ES_OUT_SET_PCR:
778
        case ES_OUT_SET_GROUP_PCR:
779
780
        {
            pgrm_descriptor_t *p_prgm = NULL;
781
            int64_t           i_pcr;
782

783
784
785
786
787
788
789
790
            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 );
791
792
793
794
795
                if( p_prgm == NULL )
                {
                    /* we create the requested program */
                    p_prgm = EsOutAddProgram( out, i_group );
                }
796
            }
797
798
799
            i_pcr   = (int64_t)va_arg( args, int64_t );

            /* search program */
800
            if( p_prgm )
801
            {
802
                input_ClockManageRef( p_sys->p_input, p_prgm, i_pcr * 9 / 100);
803
804
805
806
807
808
            }
            p_sys->b_pcr_set = VLC_TRUE;
            return VLC_SUCCESS;
        }

        case ES_OUT_RESET_PCR:
809
            for( i = 0; i < p_sys->p_input->stream.i_pgrm_number; i++ )
810
            {
811
                p_sys->p_input->stream.pp_programs[i]->i_synchro_state = SYNCHRO_REINIT;
812
813
814
815
            }
            p_sys->b_pcr_set = VLC_TRUE;
            return VLC_SUCCESS;

816
817
818
819
820
        default:
            msg_Err( p_sys->p_input, "unknown query in es_out_Control" );
            return VLC_EGENERIC;
    }
}
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
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

/****************************************************************************
 * LanguageGetName: try to expend iso639 into plain name
 ****************************************************************************/
static char *LanguageGetName( const char *psz_code )
{
    const iso639_lang_t *pl;

    if( psz_code == NULL )
    {
        return strdup( "" );
    }

    if( strlen( psz_code ) == 2 )
    {
        pl = GetLang_1( psz_code );
    }
    else if( strlen( psz_code ) == 3 )
    {
        pl = GetLang_2B( psz_code );
        if( !strcmp( pl->psz_iso639_1, "??" ) )
        {
            pl = GetLang_2T( psz_code );
        }
    }
    else
    {
        return strdup( psz_code );
    }

    if( !strcmp( pl->psz_iso639_1, "??" ) )
    {
       return strdup( psz_code );
    }
    else
    {
        if( *pl->psz_native_name )
        {
            return strdup( pl->psz_native_name );
        }
        return strdup( pl->psz_eng_name );
    }
}