es_out.c 143 KB
Newer Older
1
2
3
/*****************************************************************************
 * es_out.c: Es Out handler for input.
 *****************************************************************************
4
 * Copyright (C) 2003-2019 VLC authors, VideoLAN and Videolabs SAS
5
6
 *
 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
7
 *          Jean-Paul Saman <jpsaman #_at_# m2x dot nl>
8
 *
Jean-Baptiste Kempf's avatar
LGPL    
Jean-Baptiste Kempf committed
9
10
11
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
12
13
14
15
 * (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
Jean-Baptiste Kempf's avatar
LGPL    
Jean-Baptiste Kempf committed
16
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
18
 *
Jean-Baptiste Kempf's avatar
LGPL    
Jean-Baptiste Kempf committed
19
20
21
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22
23
24
25
26
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
27
28
29
30
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

31
#include <stdio.h>
32
33
#include <assert.h>
#include <vlc_common.h>
34

zorglub's avatar
zorglub committed
35
36
#include <vlc_es_out.h>
#include <vlc_block.h>
37
#include <vlc_aout.h>
38
#include <vlc_fourcc.h>
39
#include <vlc_meta.h>
40
#include <vlc_list.h>
41
#include <vlc_decoder.h>
42
#include <vlc_memstream.h>
43
44

#include "input_internal.h"
45
#include "../clock/input_clock.h"
46
#include "../clock/clock.h"
47
48
#include "decoder.h"
#include "es_out.h"
49
#include "event.h"
Thomas Guillem's avatar
Thomas Guillem committed
50
#include "resource.h"
51
#include "info.h"
52
#include "item.h"
53

54
55
#include "../stream_output/stream_output.h"

56
#include <vlc_iso_lang.h>
57
/* FIXME we should find a better way than including that */
58
#include "../text/iso-639_def.h"
59
60
61
62
63
64

/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
typedef struct
{
65
66
67
    /* Program context */
    input_source_t *source;

68
69
70
71
72
73
    /* Program ID */
    int i_id;

    /* Number of es for this pgrm */
    int i_es;

74
    bool b_selected;
75
    bool b_scrambled;
76
77

    /* Clock for this program */
78
79
    input_clock_t    *p_input_clock;
    vlc_clock_main_t *p_main_clock;
80
    enum vlc_clock_master_source active_clock_source;
81

82
83
    vlc_tick_t i_last_pcr;

84
    vlc_meta_t *p_meta;
85
    struct vlc_list node;
86
87
} es_out_pgrm_t;

88
89
90
91
92
93
94
95
96
97

/**
 * Opaque structure representing an ES (Elementary Stream) track.
 *
 * This structure is propagated via the vlc_input_event_es event
 */
struct vlc_es_id_t
{
    int i_id;
    enum es_format_category_e i_cat;
98
99
100
    /* Input source used to create this ES. Equals to p_pgrm->source when not
     * using a default program id. */
    input_source_t *source;
101
102
    bool stable;
    char *str_id;
103
104
};

105
106
struct es_out_id_t
{
107
108
    vlc_es_id_t id;

109
    /* weak reference, used by input_decoder_callbacks and vlc_clock_cbs */
110
111
    es_out_t *out;

112
113
114
    /* ES ID */
    es_out_pgrm_t *p_pgrm;

115
116
117
    /* */
    bool b_scrambled;

118
119
    /* Channel in the track type */
    int         i_channel;
120
121
122
123
124
125

    vlc_atomic_rc_t rc;

    size_t      i_pos; /* position, used to get the title of the track */
    es_format_t fmt; /* input fmt from the demuxer */
    es_format_t fmt_out; /* updated fmt (by the decoder) */
126
127
    char        *psz_language;
    char        *psz_language_code;
128
129
    char        *psz_title;
    bool        b_terminated;
130

131
132
    vlc_input_decoder_t   *p_dec;
    vlc_input_decoder_t   *p_dec_record;
133
    vlc_clock_t *p_clock;
134

135
136
137
    /* Used by vlc_clock_cbs, need to be const during the lifetime of the clock */
    bool master;

138
    vlc_tick_t i_pts_level;
Thomas Guillem's avatar
Thomas Guillem committed
139
140
    vlc_tick_t delay;

141
    /* Fields for Video with CC */
142
143
144
145
146
147
    struct
    {
        vlc_fourcc_t type;
        uint64_t     i_bitmap;    /* channels bitmap */
        es_out_id_t  *pp_es[64]; /* a max of 64 chans for CEA708 */
    } cc;
148
149
150

    /* Field for CC track from a master video */
    es_out_id_t *p_master;
151

152
    struct vlc_list node;
153
154
155

    vlc_mouse_event mouse_event_cb;
    void* mouse_event_userdata;
156
157
};

158
159
160
161
162
163
164
typedef struct
{
    int         i_count;    /* es count */
    es_out_id_t *p_main_es; /* current main es */
    enum es_out_policy_e e_policy;

    /* Parameters used for es selection */
165
    bool        b_autoselect; /* if we want to select an es when no user prefs */
166
    char        *str_ids; /* List of string id generated by EsOutCreateStrId() (delimited by ',') */
167
168
169
170
171
    int         i_demux_id; /* same as previous, demuxer set default value */
    int         i_channel;  /* es number in creation order */
    char        **ppsz_language;
} es_out_es_props_t;

172
typedef struct
173
174
175
{
    input_thread_t *p_input;

176
177
    input_source_t *main_source;

178
179
180
    /* */
    vlc_mutex_t   lock;

181
    /* all programs */
182
    struct vlc_list programs;
183
184
    es_out_pgrm_t *p_pgrm;  /* Master program */

185
    enum vlc_clock_master_source clock_source;
186

187
188
    /* all es */
    int         i_id;
189
    struct vlc_list es;
190
    struct vlc_list es_slaves; /* Dynamically created es on regular es selection */
191
192

    /* mode gestion */
193
    bool  b_active;
194
195
    int         i_mode;

196
    es_out_es_props_t video, audio, sub;
197

Laurent Aimar's avatar
Laurent Aimar committed
198
199
    /* es/group to select */
    int         i_group_id;
200
201

    /* delay */
Steve Lhomme's avatar
Steve Lhomme committed
202
203
    vlc_tick_t i_audio_delay;
    vlc_tick_t i_spu_delay;
204

205
    /* Clock configuration */
Steve Lhomme's avatar
Steve Lhomme committed
206
    vlc_tick_t  i_pts_delay;
Thomas Guillem's avatar
Thomas Guillem committed
207
    vlc_tick_t  i_tracks_pts_delay;
Steve Lhomme's avatar
Steve Lhomme committed
208
    vlc_tick_t  i_pts_jitter;
209
    int         i_cr_average;
Thomas Guillem's avatar
Thomas Guillem committed
210
    float       rate;
211

Laurent Aimar's avatar
Laurent Aimar committed
212
213
    /* */
    bool        b_paused;
Steve Lhomme's avatar
Steve Lhomme committed
214
    vlc_tick_t  i_pause_date;
Laurent Aimar's avatar
Laurent Aimar committed
215

216
    /* Current preroll */
Steve Lhomme's avatar
Steve Lhomme committed
217
    vlc_tick_t  i_preroll_end;
218

219
220
    /* Used for buffering */
    bool        b_buffering;
Steve Lhomme's avatar
Steve Lhomme committed
221
222
223
    vlc_tick_t  i_buffering_extra_initial;
    vlc_tick_t  i_buffering_extra_stream;
    vlc_tick_t  i_buffering_extra_system;
224

225
226
    /* Record */
    sout_instance_t *p_sout_record;
227
228
229

    /* Used only to limit debugging output */
    int         i_prev_stream_level;
230

231
232
    unsigned    cc_decoder;

233
    es_out_t out;
234
} es_out_sys_t;
235

Thomas Guillem's avatar
Thomas Guillem committed
236
static void         EsOutDelLocked( es_out_t *, es_out_id_t * );
237
238
static void         EsOutDel    ( es_out_t *, es_out_id_t * );

239
static void         EsOutTerminate( es_out_t * );
240
static void         EsOutSelect( es_out_t *, es_out_id_t *es, bool b_force );
241
242
static void         EsOutSelectList( es_out_t *, enum es_format_category_e cat,
                                     vlc_es_id_t *const* es_id_list );
243
static void         EsOutUpdateInfo( es_out_t *, es_out_id_t *es, const vlc_meta_t * );
244
static int          EsOutSetRecord(  es_out_t *, bool b_record );
245

246
static bool EsIsSelected( es_out_id_t *es );
247
static void EsOutSelectEs( es_out_t *out, es_out_id_t *es, bool b_force );
Thomas Guillem's avatar
Thomas Guillem committed
248
249
static void EsOutDeleteInfoEs( es_out_t *, es_out_id_t *es );
static void EsOutUnselectEs( es_out_t *out, es_out_id_t *es, bool b_update );
250
static void EsOutDecoderChangeDelay( es_out_t *out, es_out_id_t *p_es );
Steve Lhomme's avatar
Steve Lhomme committed
251
252
static void EsOutDecodersChangePause( es_out_t *out, bool b_paused, vlc_tick_t i_date );
static void EsOutProgramChangePause( es_out_t *out, bool b_paused, vlc_tick_t i_date );
Laurent Aimar's avatar
Laurent Aimar committed
253
static void EsOutProgramsChangeRate( es_out_t *out );
254
static void EsOutDecodersStopBuffering( es_out_t *out, bool b_forced );
255
256
static void EsOutGlobalMeta( es_out_t *p_out, const vlc_meta_t *p_meta );
static void EsOutMeta( es_out_t *p_out, const vlc_meta_t *p_meta, const vlc_meta_t *p_progmeta );
257
static int EsOutEsUpdateFmt(es_out_t *out, es_out_id_t *es, const es_format_t *fmt);
258
static int EsOutControlLocked( es_out_t *out, input_source_t *, int i_query, ... );
259
static int EsOutPrivControlLocked( es_out_t *out, int i_query, ... );
260

261
262
static char *LanguageGetName( const char *psz_code );
static char *LanguageGetCode( const char *psz_lang );
263
static char **LanguageSplit( const char *psz_langs );
264
static int LanguageArrayIndex( char **ppsz_langs, const char *psz_lang );
265

266
static char *EsOutProgramGetMetaName( es_out_pgrm_t *p_pgrm );
267
static char *EsInfoCategoryName( es_out_id_t* es );
268

269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
struct clock_source_mapping
{
    char key[sizeof("monotonic")];
    enum vlc_clock_master_source val;
};

static int clock_source_mapping_cmp(const void *key, const void *val)
{
    const struct clock_source_mapping *entry = val;
    return strcasecmp( key, entry->key );
}

static enum vlc_clock_master_source
clock_source_Inherit(vlc_object_t *obj)
{
    static const struct clock_source_mapping clock_source_list[] =
    {
        { "0", VLC_CLOCK_MASTER_AUDIO }, /* legacy option */
        { "1", VLC_CLOCK_MASTER_MONOTONIC }, /* legacy option */
        { "audio", VLC_CLOCK_MASTER_AUDIO },
289
        { "auto", VLC_CLOCK_MASTER_AUTO },
290
        { "input", VLC_CLOCK_MASTER_INPUT },
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
        { "monotonic", VLC_CLOCK_MASTER_MONOTONIC },
    };

    char *master_source_str = var_InheritString(obj, "clock-master");
    if (master_source_str == NULL)
        goto default_val;

    const struct clock_source_mapping *entry =
        bsearch(master_source_str, clock_source_list, ARRAY_SIZE(clock_source_list),
                sizeof (*clock_source_list), clock_source_mapping_cmp);
    free(master_source_str);
    if (entry == NULL)
        goto default_val;

    return entry->val;

default_val:
308
    return VLC_CLOCK_MASTER_AUTO;
309
310
}

311
static inline int EsOutGetClosedCaptionsChannel( const es_format_t *p_fmt )
312
{
313
314
315
    int i_channel;
    if( p_fmt->i_codec == VLC_CODEC_CEA608 && p_fmt->subs.cc.i_channel < 4 )
        i_channel = p_fmt->subs.cc.i_channel;
316
317
    else if( p_fmt->i_codec == VLC_CODEC_CEA708 && p_fmt->subs.cc.i_channel < 64 )
        i_channel = p_fmt->subs.cc.i_channel;
318
319
320
    else
        i_channel = -1;
    return i_channel;
321
322
}

323
324
325
326
#define foreach_es_then_es_slaves( pos ) \
    for( int fetes_i=0; fetes_i<2; fetes_i++ ) \
        vlc_list_foreach( pos, (!fetes_i ? &p_sys->es : &p_sys->es_slaves), node )

327
static void
328
decoder_on_vout_started(vlc_input_decoder_t *decoder, vout_thread_t *vout,
329
                      enum vlc_vout_order order, void *userdata)
330
{
331
332
333
334
335
    (void) decoder;

    es_out_id_t *id = userdata;
    es_out_t *out = id->out;
    es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
336

337
338
    if (!p_sys->p_input)
        return;
339
340

    struct vlc_input_event_vout event = {
341
        .action = VLC_INPUT_EVENT_VOUT_STARTED,
342
        .vout = vout,
343
        .order = order,
344
        .id = &id->id,
345
346
    };

347
    input_SendEventVout(p_sys->p_input, &event);
348
349
350
}

static void
351
decoder_on_vout_stopped(vlc_input_decoder_t *decoder, vout_thread_t *vout, void *userdata)
352
{
353
    (void) decoder;
354

355
356
357
358
359
360
    es_out_id_t *id = userdata;
    es_out_t *out = id->out;
    es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);

    if (!p_sys->p_input)
        return;
361
362

    struct vlc_input_event_vout event = {
363
        .action = VLC_INPUT_EVENT_VOUT_STOPPED,
364
        .vout = vout,
365
        .order = VLC_VOUT_ORDER_NONE,
366
        .id = &id->id,
367
368
    };

369
    input_SendEventVout(p_sys->p_input, &event);
370
371
372
}

static void
373
decoder_on_thumbnail_ready(vlc_input_decoder_t *decoder, picture_t *pic, void *userdata)
374
{
375
    (void) decoder;
376

377
378
379
380
381
382
    es_out_id_t *id = userdata;
    es_out_t *out = id->out;
    es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);

    if (!p_sys->p_input)
        return;
383
384
385
386
387
388

    struct vlc_input_event event = {
        .type = INPUT_EVENT_THUMBNAIL_READY,
        .thumbnail = pic,
    };

389
    input_SendEvent(p_sys->p_input, &event);
390
391
392
}

static void
393
decoder_on_new_video_stats(vlc_input_decoder_t *decoder, unsigned decoded, unsigned lost,
394
                           unsigned displayed, unsigned late, void *userdata)
395
396
397
{
    (void) decoder;

398
399
400
401
402
    es_out_id_t *id = userdata;
    es_out_t *out = id->out;
    es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);

    if (!p_sys->p_input)
403
404
        return;

405
    struct input_stats *stats = input_priv(p_sys->p_input)->stats;
406
407
408
409
410
411
412
413
414
    if (!stats)
        return;

    atomic_fetch_add_explicit(&stats->decoded_video, decoded,
                              memory_order_relaxed);
    atomic_fetch_add_explicit(&stats->lost_pictures, lost,
                              memory_order_relaxed);
    atomic_fetch_add_explicit(&stats->displayed_pictures, displayed,
                              memory_order_relaxed);
415
416
    atomic_fetch_add_explicit(&stats->late_pictures, late,
                              memory_order_relaxed);
417
418
419
}

static void
420
decoder_on_new_audio_stats(vlc_input_decoder_t *decoder, unsigned decoded, unsigned lost,
421
422
423
424
                           unsigned played, void *userdata)
{
    (void) decoder;

425
426
427
428
429
    es_out_id_t *id = userdata;
    es_out_t *out = id->out;
    es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);

    if (!p_sys->p_input)
430
431
        return;

432
    struct input_stats *stats = input_priv(p_sys->p_input)->stats;
433
434
435
436
437
438
439
440
441
442
443
444
    if (!stats)
        return;

    atomic_fetch_add_explicit(&stats->decoded_audio, decoded,
                              memory_order_relaxed);
    atomic_fetch_add_explicit(&stats->lost_abuffers, lost,
                              memory_order_relaxed);
    atomic_fetch_add_explicit(&stats->played_abuffers, played,
                              memory_order_relaxed);
}

static int
445
decoder_get_attachments(vlc_input_decoder_t *decoder,
446
447
448
449
450
                        input_attachment_t ***ppp_attachment,
                        void *userdata)
{
    (void) decoder;

451
452
453
454
455
    es_out_id_t *id = userdata;
    es_out_t *out = id->out;
    es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);

    if (!p_sys->p_input)
456
457
        return -1;

458
    return input_GetAttachments(p_sys->p_input, ppp_attachment);
459
460
}

461
static const struct vlc_input_decoder_callbacks decoder_cbs = {
462
463
    .on_vout_started = decoder_on_vout_started,
    .on_vout_stopped = decoder_on_vout_stopped,
464
465
466
467
468
    .on_thumbnail_ready = decoder_on_thumbnail_ready,
    .on_new_video_stats = decoder_on_new_video_stats,
    .on_new_audio_stats = decoder_on_new_audio_stats,
    .get_attachments = decoder_get_attachments,
};
469

470
471
472
473
/*****************************************************************************
 * Es category specific structs
 *****************************************************************************/
static es_out_es_props_t * GetPropsByCat( es_out_sys_t *p_sys, int i_cat )
474
475
476
477
478
479
480
481
482
483
484
485
486
{
    switch( i_cat )
    {
    case AUDIO_ES:
        return &p_sys->audio;
    case SPU_ES:
        return &p_sys->sub;
    case VIDEO_ES:
        return &p_sys->video;
    }
    return NULL;
}

487
488
static void EsOutPropsCleanup( es_out_es_props_t *p_props )
{
489
    free( p_props->str_ids );
490
491
492
493
494
495
496
497
498
    if( p_props->ppsz_language )
    {
        for( int i = 0; p_props->ppsz_language[i]; i++ )
            free( p_props->ppsz_language[i] );
        free( p_props->ppsz_language );
    }
}

static void EsOutPropsInit( es_out_es_props_t *p_props,
499
                            bool autoselect,
500
501
502
503
504
505
506
507
508
                            input_thread_t *p_input,
                            enum es_out_policy_e e_default_policy,
                            const char *psz_trackidvar,
                            const char *psz_trackvar,
                            const char *psz_langvar,
                            const char *psz_debug )
{
    p_props->e_policy = e_default_policy;
    p_props->i_count = 0;
509
    p_props->b_autoselect = autoselect;
510
    p_props->str_ids = (psz_trackidvar) ? var_GetNonEmptyString( p_input, psz_trackidvar ) : NULL;
511
512
513
514
    p_props->i_channel = (psz_trackvar) ? var_GetInteger( p_input, psz_trackvar ): -1;
    p_props->i_demux_id = -1;
    p_props->p_main_es = NULL;

515
    if( !input_priv(p_input)->b_preparsing && psz_langvar )
516
517
    {
        char *psz_string = var_GetString( p_input, psz_langvar );
518
        p_props->ppsz_language = LanguageSplit( psz_string );
519
520
521
522
523
524
525
526
527
528
        if( p_props->ppsz_language )
        {
            for( int i = 0; p_props->ppsz_language[i]; i++ )
                msg_Dbg( p_input, "selected %s language[%d] %s",
                         psz_debug, i, p_props->ppsz_language[i] );
        }
        free( psz_string );
    }
}

529
530
static const struct es_out_callbacks es_out_cbs;

531
532
533
/*****************************************************************************
 * input_EsOutNew:
 *****************************************************************************/
534
es_out_t *input_EsOutNew( input_thread_t *p_input, input_source_t *main_source, float rate )
535
{
Rafaël Carré's avatar
Rafaël Carré committed
536
    es_out_sys_t *p_sys = calloc( 1, sizeof( *p_sys ) );
537
538
539
    if( !p_sys )
        return NULL;

540
    p_sys->out.cbs = &es_out_cbs;
541

Thomas Guillem's avatar
Thomas Guillem committed
542
    vlc_mutex_init( &p_sys->lock );
543
    p_sys->p_input = p_input;
544
    p_sys->main_source = main_source;
545

546
    p_sys->b_active = false;
Laurent Aimar's avatar
Laurent Aimar committed
547
    p_sys->i_mode   = ES_OUT_MODE_NONE;
548

549
    vlc_list_init(&p_sys->programs);
550
    vlc_list_init(&p_sys->es);
551
    vlc_list_init(&p_sys->es_slaves);
552
553

    /* */
554
    EsOutPropsInit( &p_sys->video, true, p_input, ES_OUT_ES_POLICY_AUTO,
555
                    "video-track-id", "video-track", NULL, NULL );
556
    EsOutPropsInit( &p_sys->audio, true, p_input, ES_OUT_ES_POLICY_EXCLUSIVE,
557
                    "audio-track-id", "audio-track", "audio-language", "audio" );
558
    EsOutPropsInit( &p_sys->sub,  false, p_input, ES_OUT_ES_POLICY_AUTO,
559
                    "sub-track-id", "sub-track", "sub-language", "sub" );
560

561
562
    p_sys->cc_decoder = var_InheritInteger( p_input, "captions" );

Laurent Aimar's avatar
Laurent Aimar committed
563
    p_sys->i_group_id = var_GetInteger( p_input, "program" );
564

565
    p_sys->clock_source = clock_source_Inherit( VLC_OBJECT(p_input) );
566

567
    p_sys->i_pause_date = -1;
Laurent Aimar's avatar
Laurent Aimar committed
568

Thomas Guillem's avatar
Thomas Guillem committed
569
    p_sys->rate = rate;
570

571
    p_sys->b_buffering = true;
572
    p_sys->i_preroll_end = -1;
573
    p_sys->i_prev_stream_level = -1;
574

575
    return &p_sys->out;
576
577
578
579
580
}

/*****************************************************************************
 *
 *****************************************************************************/
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
static void EsTerminate(es_out_id_t *es)
{
    vlc_list_remove(&es->node);

    es->b_terminated = true;
}

static char *EsGetTitle( es_out_id_t *es )
{
    const es_format_t *fmt = &es->fmt;
    char *title;

    /* Take care of the ES description */
    if( fmt->psz_description && *fmt->psz_description )
    {
        if( es->psz_language && *es->psz_language )
        {
            if( asprintf( &title, "%s - [%s]", fmt->psz_description,
                          es->psz_language ) == -1 )
                title = NULL;
        }
        else
            title = strdup( fmt->psz_description );
    }
    else
    {
        if( es->psz_language && *es->psz_language )
        {
            if( asprintf( &title, "%s %zu - [%s]", _("Track"),
                          es->i_pos, es->psz_language ) == -1 )
                title = NULL;
        }
        else
        {
            if( asprintf( &title, "%s %zu", _("Track"), es->i_pos ) == -1 )
                title = NULL;
        }
    }

    return title;
}

static void EsRelease(es_out_id_t *es)
{
    if (vlc_atomic_rc_dec(&es->rc))
    {
        free(es->psz_title);
        free(es->psz_language);
        free(es->psz_language_code);
        es_format_Clean(&es->fmt);
631
        input_source_Release(es->id.source);
632
        free(es->id.str_id);
633
634
635
636
637
638
639
640
641
        free(es);
    }
}

static void EsHold(es_out_id_t *es)
{
    vlc_atomic_rc_inc(&es->rc);
}

642
643
static void EsOutDelete( es_out_t *out )
{
644
    es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
645

646
    assert(vlc_list_is_empty(&p_sys->es));
647
    assert(vlc_list_is_empty(&p_sys->es_slaves));
648
649
    assert(vlc_list_is_empty(&p_sys->programs));
    assert(p_sys->p_pgrm == NULL);
650
    EsOutPropsCleanup( &p_sys->video );
651
652
    EsOutPropsCleanup( &p_sys->audio );
    EsOutPropsCleanup( &p_sys->sub );
653
654
655
656

    free( p_sys );
}

657
658
659
660
661
662
static void ProgramDelete( es_out_pgrm_t *p_pgrm )
{
    input_clock_Delete( p_pgrm->p_input_clock );
    vlc_clock_main_Delete( p_pgrm->p_main_clock );
    if( p_pgrm->p_meta )
        vlc_meta_Delete( p_pgrm->p_meta );
663
    input_source_Release( p_pgrm->source );
664
665
666
667

    free( p_pgrm );
}

668
669
static void EsOutTerminate( es_out_t *out )
{
670
    es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
671
    es_out_id_t *es;
672
673

    if( p_sys->p_sout_record )
674
        EsOutSetRecord( out, false );
675

676
    foreach_es_then_es_slaves(es)
677
    {
678
        if (es->p_dec != NULL)
679
            vlc_input_decoder_Delete(es->p_dec);
680

681
682
        EsTerminate(es);
        EsRelease(es);
683
684
    }

685
686
    es_out_pgrm_t *p_pgrm;
    vlc_list_foreach(p_pgrm, &p_sys->programs, node)
687
    {
688
        vlc_list_remove(&p_pgrm->node);
689
        input_SendEventProgramDel( p_sys->p_input, p_pgrm->i_id );
690
        ProgramDelete(p_pgrm);
691
    }
Laurent Aimar's avatar
Laurent Aimar committed
692

693
694
    p_sys->p_pgrm = NULL;

695
    input_item_SetEpgOffline( input_priv(p_sys->p_input)->p_item );
696
    input_SendEventMetaEpg( p_sys->p_input );
697
698
}

Steve Lhomme's avatar
Steve Lhomme committed
699
static vlc_tick_t EsOutGetWakeup( es_out_t *out )
700
{
701
    es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
702
703
704
705
706
707
708
709
    input_thread_t *p_input = p_sys->p_input;

    if( !p_sys->p_pgrm )
        return 0;

    /* We do not have a wake up date if the input cannot have its speed
     * controlled or sout is imposing its own or while buffering
     *
710
     * FIXME for !input_CanPaceControl() a wake-up time is still needed
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
711
     * to avoid too heavy buffering */
712
    if( !input_CanPaceControl(p_input) ||
713
        input_priv(p_input)->b_out_pace_control ||
714
715
716
        p_sys->b_buffering )
        return 0;

717
    return input_clock_GetWakeup( p_sys->p_pgrm->p_input_clock );
718
719
}

720
721
static es_out_id_t es_cat[DATA_ES];

722
723
724
725
726
727
728
729
730
731
732
733
static es_out_id_t *EsOutGetSelectedCat( es_out_t *out,
                                         enum es_format_category_e cat )
{
    es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
    es_out_id_t *es;

    foreach_es_then_es_slaves( es )
        if( es->fmt.i_cat == cat && EsIsSelected( es ) )
            return es;
    return NULL;
}

734
735
static bool EsOutDecodersIsEmpty( es_out_t *out )
{
736
    es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
737
    es_out_id_t *es;
738
739
740
741
742
743
744
745

    if( p_sys->b_buffering && p_sys->p_pgrm )
    {
        EsOutDecodersStopBuffering( out, true );
        if( p_sys->b_buffering )
            return true;
    }

746
    foreach_es_then_es_slaves(es)
747
    {
748
        if( es->p_dec && !vlc_input_decoder_IsEmpty( es->p_dec ) )
749
            return false;
750
        if( es->p_dec_record && !vlc_input_decoder_IsEmpty( es->p_dec_record ) )
751
752
753
754
755
            return false;
    }
    return true;
}

Thomas Guillem's avatar
Thomas Guillem committed
756
757
758
759
static void EsOutSetEsDelay(es_out_t *out, es_out_id_t *es, vlc_tick_t delay)
{
    es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);

760
761
    assert(es->fmt.i_cat == AUDIO_ES || es->fmt.i_cat == SPU_ES);

Thomas Guillem's avatar
Thomas Guillem committed
762
763
764
765
766
    es->delay = delay;

    EsOutDecoderChangeDelay(out, es);

    /* Update the clock pts delay only if the extra tracks delay changed */
767
768
    EsOutPrivControlLocked(out, ES_OUT_PRIV_SET_JITTER, p_sys->i_pts_delay,
                           p_sys->i_pts_jitter, p_sys->i_cr_average);
Thomas Guillem's avatar
Thomas Guillem committed
769
770
}

Steve Lhomme's avatar
Steve Lhomme committed
771
static void EsOutSetDelay( es_out_t *out, int i_cat, vlc_tick_t i_delay )
772
{
773
    es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
774
    es_out_id_t *es;
775
776
777
778
779
780

    if( i_cat == AUDIO_ES )
        p_sys->i_audio_delay = i_delay;
    else if( i_cat == SPU_ES )
        p_sys->i_spu_delay = i_delay;

781
    foreach_es_then_es_slaves(es)
782
        EsOutDecoderChangeDelay(out, es);
Thomas Guillem's avatar
Thomas Guillem committed
783
784

    /* Update the clock pts delay only if the extra tracks delay changed */
785
786
    EsOutPrivControlLocked(out, ES_OUT_PRIV_SET_JITTER, p_sys->i_pts_delay,
                           p_sys->i_pts_jitter, p_sys->i_cr_average);
787
788
789
790
}

static int EsOutSetRecord(  es_out_t *out, bool b_record )
{
791
    es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
792
    input_thread_t *p_input = p_sys->p_input;
793
    es_out_id_t *p_es;
794
795
796
797
798

    assert( ( b_record && !p_sys->p_sout_record ) || ( !b_record && p_sys->p_sout_record ) );

    if( b_record )
    {
799
800
        char *psz_path = var_CreateGetNonEmptyString( p_input, "input-record-path" );
        if( !psz_path )
801
802
803
804
805
806
807
808
        {
            if( var_CountChoices( p_input, "video-es" ) )
                psz_path = config_GetUserDir( VLC_VIDEOS_DIR );
            else if( var_CountChoices( p_input, "audio-es" ) )
                psz_path = config_GetUserDir( VLC_MUSIC_DIR );
            else
                psz_path = config_GetUserDir( VLC_DOWNLOAD_DIR );
        }
809
810
811
812
813

        char *psz_sout = NULL;  // TODO conf

        if( !psz_sout && psz_path )
        {
814
815
816
            char *psz_file = input_item_CreateFilename( input_GetItem(p_input),
                                                        psz_path,
                                                        INPUT_RECORD_PREFIX, NULL );
817
818
            if( psz_file )
            {
819
820
821
822
823
824
825
                char* psz_file_esc = config_StringEscape( psz_file );
                if ( psz_file_esc )
                {
                    if( asprintf( &psz_sout, "#record{dst-prefix='%s'}", psz_file_esc ) < 0 )
                        psz_sout = NULL;
                    free( psz_file_esc );
                }
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
                free( psz_file );
            }
        }
        free( psz_path );

        if( !psz_sout )
            return VLC_EGENERIC;

#ifdef ENABLE_SOUT
        p_sys->p_sout_record = sout_NewInstance( p_input, psz_sout );
#endif
        free( psz_sout );

        if( !p_sys->p_sout_record )
            return VLC_EGENERIC;

842
        vlc_list_foreach( p_es, &p_sys->es, node ) /* Only master es */
843
        {
844
            if( !p_es->p_dec )
845
846
                continue;

847
            p_es->p_dec_record =
848
849
850
851
                vlc_input_decoder_New( VLC_OBJECT(p_input), &p_es->fmt, NULL,
                                       input_priv(p_input)->p_resource,
                                       p_sys->p_sout_record, false,
                                       &decoder_cbs, p_es );
852

853
            if( p_es->p_dec_record && p_sys->b_buffering )
854
                vlc_input_decoder_StartWait( p_es->p_dec_record );
855
856
857
858
        }
    }
    else
    {
859
        vlc_list_foreach( p_es, &p_sys->es, node ) /* Only master es */
860
861
862
863
        {
            if( !p_es->p_dec_record )
                continue;

864
            vlc_input_decoder_Delete( p_es->p_dec_record );
865
866
867
868
869
870
871
872
873
874
            p_es->p_dec_record = NULL;
        }
#ifdef ENABLE_SOUT
        sout_DeleteInstance( p_sys->p_sout_record );
#endif
        p_sys->p_sout_record = NULL;
    }

    return VLC_SUCCESS;
}
Steve Lhomme's avatar
Steve Lhomme committed
875
static void EsOutChangePause( es_out_t *out, bool b_paused, vlc_tick_t i_date )
876
{
877
    es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
878
879
880
881
882
883
884
885
886
887
888

    /* XXX the order is important */
    if( b_paused )
    {
        EsOutDecodersChangePause( out, true, i_date );
        EsOutProgramChangePause( out, true, i_date );
    }
    else
    {
        if( p_sys->i_buffering_extra_initial > 0 )
        {
Steve Lhomme's avatar
Steve Lhomme committed
889
890
891
892
            vlc_tick_t i_stream_start;
            vlc_tick_t i_system_start;
            vlc_tick_t i_stream_duration;
            vlc_tick_t i_system_duration;
893
            int i_ret;
894
            i_ret = input_clock_GetState( p_sys->p_pgrm->p_input_clock,
895
896
897
898
899
                                          &i_stream_start, &i_system_start,
                                          &i_stream_duration, &i_system_duration );
            if( !i_ret )
            {
                /* FIXME pcr != exactly what wanted */
Steve Lhomme's avatar
Steve Lhomme committed
900
                const vlc_tick_t i_used = /*(i_stream_duration - input_priv(p_sys->p_input)->i_pts_delay)*/ p_sys->i_buffering_extra_system - p_sys->i_buffering_extra_initial;
901
902
903
904
905
906
907
908
909
910
911
912
                i_date -= i_used;
            }
            p_sys->i_buffering_extra_initial = 0;
            p_sys->i_buffering_extra_stream = 0;
            p_sys->i_buffering_extra_system = 0;
        }
        EsOutProgramChangePause( out, false, i_date );
        EsOutDecodersChangePause( out, false, i_date );

        EsOutProgramsChangeRate( out );
    }
    p_sys->b_paused = b_paused;
913
    p_sys->i_pause_date = i_date;
914
915
}

Thomas Guillem's avatar
Thomas Guillem committed
916
static void EsOutChangeRate( es_out_t *out, float rate )
917
{
918
    es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
919
    es_out_id_t *es;
920

Thomas Guillem's avatar
Thomas Guillem committed
921
    p_sys->rate = rate;
922
    EsOutProgramsChangeRate( out );
923

924
    foreach_es_then_es_slaves(es)
925
        if( es->p_dec != NULL )
926
            vlc_input_decoder_ChangeRate( es->p_dec, rate );
927
928
}

929
static void EsOutChangePosition( es_out_t *out, bool b_flush )
930
{
931
    es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
932
    es_out_id_t *p_es;
933

934
935
    input_SendEventCache( p_sys->p_input, 0.0 );

936
    foreach_es_then_es_slaves(p_es)
937
    {
938
939
        if( p_es->p_dec != NULL )
        {
940
            if( b_flush )
941
                vlc_input_decoder_Flush( p_es->p_dec );
942
943
            if( !p_sys->b_buffering )
            {
944
                vlc_input_decoder_StartWait( p_es->p_dec );
945
                if( p_es->p_dec_record != NULL )
946
                    vlc_input_decoder_StartWait( p_es->p_dec_record );
947
948
            }
        }
949
950
        p_es->i_pts_level = VLC_TICK_INVALID;
    }
951

952
953
    es_out_pgrm_t *pgrm;
    vlc_list_foreach(pgrm, &p_sys->programs, node)
954
    {
955
        input_clock_Reset(pgrm->p_input_clock);
956
        vlc_clock_main_Reset(pgrm->p_main_clock);
957
        pgrm->i_last_pcr = VLC_TICK_INVALID;
958
    }
959
960
961
962
963
964

    p_sys->b_buffering = true;
    p_sys->i_buffering_extra_initial = 0;
    p_sys->i_buffering_extra_stream = 0;
    p_sys->i_buffering_extra_system = 0;
    p_sys->i_preroll_end = -1;
965
    p_sys->i_prev_stream_level = -1;
966
967
}

968
969
970
static void EsOutStopFreeVout( es_out_t *out )
{
    es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
971

Thomas Guillem's avatar
Thomas Guillem committed
972
    /* Clean up vout after user action (in active mode only). */
973
    if( p_sys->b_active )
Thomas Guillem's avatar
Thomas Guillem committed
974
        input_resource_StopFreeVout( input_priv(p_sys->p_input)->p_resource );
975
}
976

977
978
static void EsOutDecodersStopBuffering( es_out_t *out, bool b_forced )
{
979
    es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
980
    es_out_id_t *p_es;
981

Steve Lhomme's avatar
Steve Lhomme committed
982
983
984
985
    vlc_tick_t i_stream_start;
    vlc_tick_t i_system_start;
    vlc_tick_t i_stream_duration;
    vlc_tick_t i_system_duration;
986
    if (input_clock_GetState( p_sys->p_pgrm->p_input_clock,
987
                                  &i_stream_start, &i_system_start,
988
                                  &i_stream_duration, &i_system_duration ))
989
990
        return;

Steve Lhomme's avatar
Steve Lhomme committed
991
    vlc_tick_t i_preroll_duration = 0;
992
993
    if( p_sys->i_preroll_end >= 0 )
        i_preroll_duration = __MAX( p_sys->i_preroll_end - i_stream_start, 0 );
994

Steve Lhomme's avatar
Steve Lhomme committed
995
    const vlc_tick_t i_buffering_duration = p_sys->i_pts_delay +
Thomas Guillem's avatar
Thomas Guillem committed
996
997
                                         p_sys->i_pts_jitter +
                                         p_sys->i_tracks_pts_delay +
Laurent Aimar's avatar
Laurent Aimar committed
998
                                         i_preroll_duration +
999
                                         p_sys->i_buffering_extra_stream - p_sys->i_buffering_extra_initial;
Laurent Aimar's avatar
Laurent Aimar committed
1000
1001

    if( i_stream_duration <= i_buffering_duration && !b_forced )
1002
    {
flx42's avatar
flx42 committed
1003
1004
1005
1006
1007
        double f_level;
        if (i_buffering_duration == 0)
            f_level = 0;
        else
            f_level = __MAX( (double)i_stream_duration / i_buffering_duration, 0 );
1008
1009
        input_SendEventCache( p_sys->p_input, f_level );

1010
1011