decoder.c 82.1 KB
Newer Older
1
/*****************************************************************************
Laurent Aimar's avatar
Laurent Aimar committed
2
 * decoder.c: Functions for the management of decoders
3
 *****************************************************************************
4
 * Copyright (C) 1999-2019 VLC authors, VideoLAN and Videolabs SAS
5
6
 *
 * Authors: Christophe Massiot <massiot@via.ecp.fr>
7
 *          Gildas Bazin <gbazin@videolan.org>
Laurent Aimar's avatar
Laurent Aimar committed
8
 *          Laurent Aimar <fenrir@via.ecp.fr>
9
 *
Jean-Baptiste Kempf's avatar
LGPL    
Jean-Baptiste Kempf committed
10
11
12
 * 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
13
 * (at your option) any later version.
14
 *
15
16
 * 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
17
18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
19
 *
Jean-Baptiste Kempf's avatar
LGPL    
Jean-Baptiste Kempf committed
20
21
22
 * 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.
23
24
25
26
27
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
28
29
30
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
31
#include <assert.h>
32
#include <stdatomic.h>
33

34
#include <vlc_common.h>
zorglub's avatar
zorglub committed
35
36
37
38
39
#include <vlc_block.h>
#include <vlc_vout.h>
#include <vlc_aout.h>
#include <vlc_sout.h>
#include <vlc_codec.h>
40
#include <vlc_spu.h>
Laurent Aimar's avatar
Laurent Aimar committed
41
#include <vlc_meta.h>
42
#include <vlc_dialog.h>
43
#include <vlc_modules.h>
44
#include <vlc_decoder.h>
45
#include <vlc_picture_pool.h>
zorglub's avatar
zorglub committed
46
47
48

#include "audio_output/aout_internal.h"
#include "stream_output/stream_output.h"
49
#include "../clock/clock.h"
50
#include "decoder.h"
51
#include "resource.h"
52
#include "libvlc.h"
53

54
#include "../video_output/vout_internal.h"
Laurent Aimar's avatar
Laurent Aimar committed
55

56
57
58
59
60
61
62
63
64
65
/*
 * Possibles values set in p_owner->reload atomic
 */
enum reload
{
    RELOAD_NO_REQUEST,
    RELOAD_DECODER,     /* Reload the decoder module */
    RELOAD_DECODER_AOUT /* Stop the aout and reload the decoder module */
};

66
struct vlc_input_decoder_t
67
{
68
    decoder_t        dec;
69
    input_resource_t*p_resource;
70
    vlc_clock_t     *p_clock;
71

72
    const struct vlc_input_decoder_callbacks *cbs;
73
74
    void *cbs_userdata;

75
    ssize_t          i_spu_channel;
76
    int64_t          i_spu_order;
77

78
79
    sout_instance_t         *p_sout;
    sout_packetizer_input_t *p_sout_input;
80

81
82
    vlc_thread_t     thread;

83
84
    /* Some decoders require already packetized data (ie. not truncated) */
    decoder_t *p_packetizer;
85
    bool b_packetizer;
86

87
    /* Current format in use by the output */
88
    es_format_t    fmt;
89
    vlc_video_context *vctx;
90

91
    /* */
Thomas Guillem's avatar
Thomas Guillem committed
92
    bool           b_fmt_description;
Laurent Aimar's avatar
Laurent Aimar committed
93
    vlc_meta_t     *p_description;
94
    atomic_int     reload;
95

96
97
    /* fifo */
    block_fifo_t *p_fifo;
98

99
100
    /* Lock for communication with decoder thread */
    vlc_mutex_t lock;
101
102
    vlc_cond_t  wait_request;
    vlc_cond_t  wait_acknowledge;
103
    vlc_cond_t  wait_fifo; /* TODO: merge with wait_acknowledge */
104

105
106
107
    /* pool to use when the decoder doesn't use its own */
    struct picture_pool_t *out_pool;

108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
    /*
     * 3 threads can read/write these output variables, the DecoderThread, the
     * input thread, and the ModuleThread. The ModuleThread is either the
     * DecoderThread for synchronous modules or any thread for asynchronous
     * modules.
     *
     * Asynchronous modules are responsible for serializing/locking every
     * output calls in any thread as long as the decoder_UpdateVideoFormat() or
     * decoder_NewPicture() calls are not concurrent, cf.
     * decoder_UpdateVideoFormat() and decoder_NewPicture() notes.
     *
     * The ModuleThread is the owner of these variables, it should hold
     * the lock when writing them but doesn't have to hold it when using them.
     *
     * The DecoderThread should always hold the lock when reading/using
     * aout/vouts.
     *
     * The input thread can read these variables in order to stop outputs, when
     * both ModuleThread and DecoderThread are stopped (from DecoderDelete()).
     */
128
    audio_output_t *p_aout;
Laurent Aimar's avatar
Laurent Aimar committed
129
130

    vout_thread_t   *p_vout;
131
    bool             vout_started;
132
    enum vlc_vout_order vout_order;
Laurent Aimar's avatar
Laurent Aimar committed
133
134

    /* -- Theses variables need locking on read *and* write -- */
Thomas Guillem's avatar
Thomas Guillem committed
135
    /* Preroll */
Steve Lhomme's avatar
Steve Lhomme committed
136
    vlc_tick_t i_preroll_end;
137
138
139
140

#define PREROLL_NONE    INT64_MIN // vlc_tick_t
#define PREROLL_FORCED  INT64_MAX // vlc_tick_t

141
    /* Pause & Rate */
142
    bool reset_out_state;
Steve Lhomme's avatar
Steve Lhomme committed
143
    vlc_tick_t pause_date;
144
145
    vlc_tick_t delay;
    float request_rate, output_rate;
146
147
    unsigned frames_countdown;
    bool paused;
148

149
150
    bool error;

151
152
153
154
    /* Waiting */
    bool b_waiting;
    bool b_first;
    bool b_has_data;
155

Laurent Aimar's avatar
Laurent Aimar committed
156
    /* Flushing */
157
    bool flushing;
158
    bool b_draining;
159
    atomic_bool drained;
160
    bool b_idle;
161
    bool aborting;
Laurent Aimar's avatar
Laurent Aimar committed
162

163
    /* CC */
164
#define MAX_CC_DECODERS 64 /* The es_out only creates one type of es */
165
166
167
    struct
    {
        bool b_supported;
168
        decoder_cc_desc_t desc;
169
        vlc_input_decoder_t *pp_decoder[MAX_CC_DECODERS];
170
171
        bool b_sout_created;
        sout_packetizer_input_t *p_sout_input;
172
    } cc;
173

174
175
176
    /* Mouse event */
    vlc_mutex_t     mouse_lock;
    vlc_mouse_event mouse_event;
177
    void           *mouse_opaque;
178
179
};

180
181
/* Pictures which are DECODER_BOGUS_VIDEO_DELAY or more in advance probably have
 * a bogus PTS and won't be displayed */
Steve Lhomme's avatar
Steve Lhomme committed
182
#define DECODER_BOGUS_VIDEO_DELAY                ((vlc_tick_t)(DEFAULT_PTS_DELAY * 30))
183
184

/* */
185
#define DECODER_SPU_VOUT_WAIT_DURATION   VLC_TICK_FROM_MS(200)
186
#define BLOCK_FLAG_CORE_PRIVATE_RELOADED (1 << BLOCK_FLAG_CORE_PRIVATE_SHIFT)
187

188
189
#define decoder_Notify(decoder_priv, event, ...) \
    if (decoder_priv->cbs && decoder_priv->cbs->event) \
190
        decoder_priv->cbs->event(decoder_priv, __VA_ARGS__, \
191
192
                                 decoder_priv->cbs_userdata);

193
static inline vlc_input_decoder_t *dec_get_owner( decoder_t *p_dec )
194
{
195
    return container_of( p_dec, vlc_input_decoder_t, dec );
196
197
}

198
199
200
201
202
203
/**
 * Load a decoder module
 */
static int LoadDecoder( decoder_t *p_dec, bool b_packetizer,
                        const es_format_t *restrict p_fmt )
{
204
    decoder_Init( p_dec, p_fmt );
205

206
    p_dec->b_frame_drop_allowed = true;
207
208
209

    /* Find a suitable decoder/packetizer module */
    if( !b_packetizer )
210
    {
Thomas Guillem's avatar
Thomas Guillem committed
211
        static const char caps[ES_CATEGORY_COUNT][16] = {
212
            [VIDEO_ES] = "video decoder",
213
            [AUDIO_ES] = "audio decoder",
214
            [SPU_ES] = "spu decoder",
215
        };
216
217
        p_dec->p_module = module_need_var( p_dec, caps[p_dec->fmt_in.i_cat],
                                           "codec" );
218
    }
219
    else
220
        p_dec->p_module = module_need_var( p_dec, "packetizer", "packetizer" );
221
222
223

    if( !p_dec->p_module )
    {
224
        decoder_Clean( p_dec );
225
226
        return -1;
    }
227
    return 0;
228
229
}

230
static int DecoderThread_Reload( vlc_input_decoder_t *p_owner,
231
232
                                 const es_format_t *restrict p_fmt,
                                 enum reload reload )
233
{
234
    /* Copy p_fmt since it can be destroyed by decoder_Clean */
235
    decoder_t *p_dec = &p_owner->dec;
236
237
238
    es_format_t fmt_in;
    if( es_format_Copy( &fmt_in, p_fmt ) != VLC_SUCCESS )
    {
239
        p_owner->error = true;
240
241
242
243
        return VLC_EGENERIC;
    }

    /* Restart the decoder module */
244
    decoder_Clean( p_dec );
245
    p_owner->error = false;
246
247
248
249
250

    if( reload == RELOAD_DECODER_AOUT )
    {
        assert( p_owner->fmt.i_cat == AUDIO_ES );
        audio_output_t *p_aout = p_owner->p_aout;
251
        // no need to lock, the decoder and ModuleThread are dead
252
253
254
255
256
257
258
259
        p_owner->p_aout = NULL;
        if( p_aout )
        {
            aout_DecDelete( p_aout );
            input_resource_PutAout( p_owner->p_resource, p_aout );
        }
    }

260
    if( LoadDecoder( p_dec, false, &fmt_in ) )
261
    {
262
        p_owner->error = true;
263
264
265
266
267
268
269
        es_format_Clean( &fmt_in );
        return VLC_EGENERIC;
    }
    es_format_Clean( &fmt_in );
    return VLC_SUCCESS;
}

270
static void DecoderUpdateFormatLocked( vlc_input_decoder_t *p_owner )
271
{
272
    decoder_t *p_dec = &p_owner->dec;
273

274
    vlc_mutex_assert( &p_owner->lock );
275

276
277
    es_format_Clean( &p_owner->fmt );
    es_format_Copy( &p_owner->fmt, &p_dec->fmt_out );
278

279
280
    assert( p_owner->fmt.i_cat == p_dec->fmt_in.i_cat );

281
    /* Move p_description */
282
283
284
285
286
287
288
289
    if( p_dec->p_description != NULL )
    {
        if( p_owner->p_description != NULL )
            vlc_meta_Delete( p_owner->p_description );
        p_owner->p_description = p_dec->p_description;
        p_dec->p_description = NULL;
    }

Thomas Guillem's avatar
Thomas Guillem committed
290
    p_owner->b_fmt_description = true;
291
292
}

293
294
295
static void MouseEvent( const vlc_mouse_t *newmouse, void *user_data )
{
    decoder_t *dec = user_data;
296
    vlc_input_decoder_t *owner = dec_get_owner( dec );
297
298
299

    vlc_mutex_lock( &owner->mouse_lock );
    if( owner->mouse_event )
300
        owner->mouse_event( newmouse, owner->mouse_opaque);
301
302
303
    vlc_mutex_unlock( &owner->mouse_lock );
}

304
305
306
/*****************************************************************************
 * Buffers allocation callbacks for the decoders
 *****************************************************************************/
François Cartegnie's avatar
François Cartegnie committed
307
308
309
310
311
312
313
static bool aout_replaygain_changed( const audio_replay_gain_t *a,
                                     const audio_replay_gain_t *b )
{
    for( size_t i=0; i<AUDIO_REPLAY_GAIN_MAX; i++ )
    {
        if( a->pb_gain[i] != b->pb_gain[i] ||
            a->pb_peak[i] != b->pb_peak[i] ||
314
315
            (a->pb_gain[i] && a->pf_gain[i] != b->pf_gain[i]) ||
            (a->pb_peak[i] && a->pf_peak[i] != b->pf_peak[i]) )
François Cartegnie's avatar
François Cartegnie committed
316
317
318
319
320
            return true;
    }
    return false;
}

321
static int ModuleThread_UpdateAudioFormat( decoder_t *p_dec )
322
{
323
    vlc_input_decoder_t *p_owner = dec_get_owner( p_dec );
324

325
326
    if( p_owner->p_aout &&
       ( !AOUT_FMTS_IDENTICAL(&p_dec->fmt_out.audio, &p_owner->fmt.audio) ||
327
328
         p_dec->fmt_out.i_codec != p_dec->fmt_out.audio.i_format ||
         p_dec->fmt_out.i_profile != p_owner->fmt.i_profile ) )
329
    {
330
        audio_output_t *p_aout = p_owner->p_aout;
331

332
333
        /* Parameters changed, restart the aout */
        vlc_mutex_lock( &p_owner->lock );
334
        p_owner->p_aout = NULL; // the DecoderThread should not use the old aout anymore
335
        vlc_mutex_unlock( &p_owner->lock );
336
        aout_DecDelete( p_aout );
337

338
        input_resource_PutAout( p_owner->p_resource, p_aout );
339
    }
340

François Cartegnie's avatar
François Cartegnie committed
341
342
343
344
345
346
347
348
349
350
351
352
    /* Check if only replay gain has changed */
    if( aout_replaygain_changed( &p_dec->fmt_in.audio_replay_gain,
                                 &p_owner->fmt.audio_replay_gain ) )
    {
        p_dec->fmt_out.audio_replay_gain = p_dec->fmt_in.audio_replay_gain;
        if( p_owner->p_aout )
        {
            p_owner->fmt.audio_replay_gain = p_dec->fmt_in.audio_replay_gain;
            var_TriggerCallback( p_owner->p_aout, "audio-replay-gain-mode" );
        }
    }

353
    if( p_owner->p_aout == NULL )
354
    {
355
        p_dec->fmt_out.audio.i_format = p_dec->fmt_out.i_codec;
356

357
358
        audio_sample_format_t format = p_dec->fmt_out.audio;
        aout_FormatPrepare( &format );
359

360
361
        const int i_force_dolby = var_InheritInteger( p_dec, "force-dolby-surround" );
        if( i_force_dolby &&
362
            format.i_physical_channels == (AOUT_CHAN_LEFT|AOUT_CHAN_RIGHT) )
363
        {
364
            if( i_force_dolby == 1 )
365
                format.i_chan_mode |= AOUT_CHANMODE_DOLBYSTEREO;
366
            else /* i_force_dolby == 2 */
367
                format.i_chan_mode &= ~AOUT_CHANMODE_DOLBYSTEREO;
368
        }
369

370
        audio_output_t *p_aout;
Laurent Aimar's avatar
Laurent Aimar committed
371

372
373
        p_aout = input_resource_GetAout( p_owner->p_resource );
        if( p_aout )
Laurent Aimar's avatar
Laurent Aimar committed
374
        {
375
376
            if( aout_DecNew( p_aout, &format, p_dec->fmt_out.i_profile,
                             p_owner->p_clock,
377
                             &p_dec->fmt_out.audio_replay_gain ) )
Laurent Aimar's avatar
Laurent Aimar committed
378
            {
379
380
                input_resource_PutAout( p_owner->p_resource, p_aout );
                p_aout = NULL;
Laurent Aimar's avatar
Laurent Aimar committed
381
382
            }
        }
383

384
385
        vlc_mutex_lock( &p_owner->lock );
        p_owner->p_aout = p_aout;
386

387
        DecoderUpdateFormatLocked( p_owner );
388
        aout_FormatPrepare( &p_owner->fmt.audio );
389
        vlc_mutex_unlock( &p_owner->lock );
390

391
392
        if( p_aout == NULL )
            return -1;
Laurent Aimar's avatar
Laurent Aimar committed
393

394
395
396
397
        p_dec->fmt_out.audio.i_bytes_per_frame =
            p_owner->fmt.audio.i_bytes_per_frame;
        p_dec->fmt_out.audio.i_frame_length =
            p_owner->fmt.audio.i_frame_length;
398
399
400
401

        vlc_fifo_Lock( p_owner->p_fifo );
        p_owner->reset_out_state = true;
        vlc_fifo_Unlock( p_owner->p_fifo );
402
    }
403
    return 0;
Laurent Aimar's avatar
Laurent Aimar committed
404
405
}

406
static int CreateVoutIfNeeded(vlc_input_decoder_t *);
407
408


409
static int ModuleThread_UpdateVideoFormat( decoder_t *p_dec, vlc_video_context *vctx )
410
{
411
    vlc_input_decoder_t *p_owner = dec_get_owner( p_dec );
412

413
    int created_vout = CreateVoutIfNeeded(p_owner);
414
415
    if (created_vout == -1)
        return -1; // error
416
417
418
419
420
421
    if (created_vout == 0)
    {
        // video context didn't change
        if (vctx != NULL && p_owner->vctx == vctx)
            return 0;
    }
422
423
    assert(p_owner->p_vout);

424
425
426
    if (p_owner->vctx)
        vlc_video_context_Release(p_owner->vctx);
    p_owner->vctx = vctx ? vlc_video_context_Hold(vctx) : NULL;
427

428
    // configure the new vout
429

430
431
432
433
434
435
436
437
438
439
440
441
442
    if ( p_owner->out_pool == NULL )
    {
        unsigned dpb_size;
        switch( p_dec->fmt_in.i_codec )
        {
        case VLC_CODEC_HEVC:
        case VLC_CODEC_H264:
        case VLC_CODEC_DIRAC: /* FIXME valid ? */
            dpb_size = 18;
            break;
        case VLC_CODEC_AV1:
            dpb_size = 10;
            break;
443
        case VLC_CODEC_MP4V:
444
445
446
447
448
449
450
451
452
453
        case VLC_CODEC_VP5:
        case VLC_CODEC_VP6:
        case VLC_CODEC_VP6F:
        case VLC_CODEC_VP8:
            dpb_size = 3;
            break;
        default:
            dpb_size = 2;
            break;
        }
454
        picture_pool_t *pool = picture_pool_NewFromFormat( &p_dec->fmt_out.video,
455
                            dpb_size + p_dec->i_extra_picture_buffers + 1 );
456
457

        if( pool == NULL)
458
459
460
461
        {
            msg_Err(p_dec, "Failed to create a pool of %d %4.4s pictures",
                           dpb_size + p_dec->i_extra_picture_buffers + 1,
                           (char*)&p_dec->fmt_out.video.i_chroma);
462
            goto error;
463
        }
464
465
466
467
468

        vlc_mutex_lock( &p_owner->lock );
        p_owner->out_pool = pool;
        vlc_mutex_unlock( &p_owner->lock );

469
    }
470

471
    vout_configuration_t cfg = {
472
        .vout = p_owner->p_vout, .clock = p_owner->p_clock, .fmt = &p_dec->fmt_out.video,
473
474
        .mouse_event = MouseEvent, .mouse_opaque = p_dec,
    };
475
    bool has_started;
476
    vout_thread_t *p_vout =
477
478
        input_resource_RequestVout(p_owner->p_resource, vctx, &cfg, NULL,
                                   &has_started);
479
    if (p_vout != NULL)
480
    {
481
482
483
484
        vlc_mutex_lock( &p_owner->lock );
        p_owner->vout_started = true;
        vlc_mutex_unlock( &p_owner->lock );

485
        if (has_started)
486
487
488
489
490
        {
            vlc_fifo_Lock( p_owner->p_fifo );
            p_owner->reset_out_state = true;
            vlc_fifo_Unlock( p_owner->p_fifo );

491
            decoder_Notify(p_owner, on_vout_started, p_vout, p_owner->vout_order);
492
        }
493
        return 0;
494
    }
495

496
497
498
499
500
501
502
503
504
505
506
507
error:
    /* Clean fmt and vctx to trigger a new vout creation on the next update
     * call */
    vlc_mutex_lock( &p_owner->lock );
    es_format_Clean( &p_owner->fmt );
    vlc_mutex_unlock( &p_owner->lock );

    if (p_owner->vctx != NULL)
    {
        vlc_video_context_Release(p_owner->vctx);
        p_owner->vctx = NULL;
    }
508
    return -1;
509
510
}

511
static int CreateVoutIfNeeded(vlc_input_decoder_t *p_owner)
Sam Hocevar's avatar
   
Sam Hocevar committed
512
{
513
    decoder_t *p_dec = &p_owner->dec;
514
    bool need_vout = false;
515

516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
    if( p_owner->p_vout == NULL )
    {
        msg_Dbg(p_dec, "vout: none found");
        need_vout = true;
    }
    if( p_dec->fmt_out.video.i_width != p_owner->fmt.video.i_width
             || p_dec->fmt_out.video.i_height != p_owner->fmt.video.i_height )
    {
        msg_Dbg(p_dec, "vout change: decoder size");
        need_vout = true;
    }
    if( p_dec->fmt_out.video.i_visible_width != p_owner->fmt.video.i_visible_width
             || p_dec->fmt_out.video.i_visible_height != p_owner->fmt.video.i_visible_height
             || p_dec->fmt_out.video.i_x_offset != p_owner->fmt.video.i_x_offset
             || p_dec->fmt_out.video.i_y_offset != p_owner->fmt.video.i_y_offset )
    {
        msg_Dbg(p_dec, "vout change: visible size");
        need_vout = true;
    }
    if( p_dec->fmt_out.i_codec != p_owner->fmt.video.i_chroma )
    {
        msg_Dbg(p_dec, "vout change: chroma");
        need_vout = true;
    }
    if( (int64_t)p_dec->fmt_out.video.i_sar_num * p_owner->fmt.video.i_sar_den !=
             (int64_t)p_dec->fmt_out.video.i_sar_den * p_owner->fmt.video.i_sar_num )
    {
        msg_Dbg(p_dec, "vout change: SAR");
        need_vout = true;
    }
    if( p_dec->fmt_out.video.orientation != p_owner->fmt.video.orientation )
    {
        msg_Dbg(p_dec, "vout change: orientation");
        need_vout = true;
    }
    if( p_dec->fmt_out.video.multiview_mode != p_owner->fmt.video.multiview_mode )
    {
        msg_Dbg(p_dec, "vout change: multiview");
        need_vout = true;
    }

557
558
    if( !need_vout )
        return 0; // vout unchanged
559

560
    vlc_mutex_lock( &p_owner->lock );
561

562
563
    vout_thread_t *p_vout = p_owner->p_vout;
    p_owner->p_vout = NULL; // the DecoderThread should not use the old vout anymore
564
    p_owner->vout_started = false;
565
    vlc_mutex_unlock( &p_owner->lock );
566

567
    enum vlc_vout_order order;
568
    const vout_configuration_t cfg = { .vout = p_vout, .fmt = NULL };
569
    p_vout = input_resource_RequestVout( p_owner->p_resource, NULL, &cfg, &order, NULL );
570
571
572

    vlc_mutex_lock( &p_owner->lock );
    p_owner->p_vout = p_vout;
573
    p_owner->vout_order = order;
574
575
576

    DecoderUpdateFormatLocked( p_owner );
    p_owner->fmt.video.i_chroma = p_dec->fmt_out.i_codec;
577
578
    picture_pool_t *pool = p_owner->out_pool;
    p_owner->out_pool = NULL;
579
580
    vlc_mutex_unlock( &p_owner->lock );

581
582
     if ( pool != NULL )
         picture_pool_Release( pool );
583

584
585
586
587
588
    if( p_vout == NULL )
    {
        msg_Err( p_dec, "failed to create video output" );
        return -1;
    }
589

590
    return 1; // new vout was created
591
592
}

593
static vlc_decoder_device * ModuleThread_GetDecoderDevice( decoder_t *p_dec )
594
{
595
    vlc_input_decoder_t *p_owner = dec_get_owner( p_dec );
596

597
598
599
600
    /* Requesting a decoder device will automatically enable hw decoding */
    if( !var_InheritBool( p_dec, "hw-dec" ) )
        return NULL;

601
    int created_vout = CreateVoutIfNeeded(p_owner);
602
603
    if (created_vout == -1)
        return NULL;  // error
604
605
606

    assert(p_owner->p_vout);
    vlc_decoder_device *dec_device = vout_GetDevice(p_owner->p_vout);
607
608
    if (created_vout == 1)
        return dec_device; // new vout was created with a decoder device
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626

    bool need_format_update = false;
    if ( memcmp( &p_dec->fmt_out.video.mastering,
                 &p_owner->fmt.video.mastering,
                 sizeof(p_owner->fmt.video.mastering)) )
    {
        msg_Dbg(p_dec, "vout update: mastering data");
        need_format_update = true;
    }
    if ( p_dec->fmt_out.video.lighting.MaxCLL !=
         p_owner->fmt.video.lighting.MaxCLL ||
         p_dec->fmt_out.video.lighting.MaxFALL !=
         p_owner->fmt.video.lighting.MaxFALL )
    {
        msg_Dbg(p_dec, "vout update: lighting data");
        need_format_update = true;
    }

627
    if ( need_format_update )
628
629
630
    {
        /* the format has changed but we don't need a new vout */
        vlc_mutex_lock( &p_owner->lock );
631
        DecoderUpdateFormatLocked( p_owner );
632
633
        vlc_mutex_unlock( &p_owner->lock );
    }
634
    return dec_device;
gbazin's avatar
   
gbazin committed
635
636
}

637
static picture_t *ModuleThread_NewVideoBuffer( decoder_t *p_dec )
gbazin's avatar
   
gbazin committed
638
{
639
    vlc_input_decoder_t *p_owner = dec_get_owner( p_dec );
640
    assert( p_owner->p_vout );
641
    assert( p_owner->out_pool );
642

643
644
645
646
    picture_t *pic = picture_pool_Wait( p_owner->out_pool );
    if (pic)
        picture_Reset( pic );
    return pic;
647
}
648

649
static subpicture_t *ModuleThread_NewSpuBuffer( decoder_t *p_dec,
650
651
                                     const subpicture_updater_t *p_updater )
{
652
    vlc_input_decoder_t *p_owner = dec_get_owner( p_dec );
653
654
655
    vout_thread_t *p_vout = NULL;
    subpicture_t *p_subpic;
    int i_attempts = 30;
656

657
658
    while( i_attempts-- )
    {
659
        if( p_owner->error )
660
            break;
661

662
663
664
        p_vout = input_resource_HoldVout( p_owner->p_resource );
        if( p_vout )
            break;
665

666
        vlc_tick_sleep( DECODER_SPU_VOUT_WAIT_DURATION );
667
    }
668

669
670
671
    if( !p_vout )
    {
        msg_Warn( p_dec, "no vout found, dropping subpicture" );
672
673
        if( p_owner->p_vout )
        {
674
            assert(p_owner->i_spu_channel != VOUT_SPU_CHANNEL_INVALID);
675
            decoder_Notify(p_owner, on_vout_stopped, p_owner->p_vout);
676
677

            vlc_mutex_lock( &p_owner->lock );
678
679
680
            vout_UnregisterSubpictureChannel(p_owner->p_vout,
                                             p_owner->i_spu_channel);
            p_owner->i_spu_channel = VOUT_SPU_CHANNEL_INVALID;
681

682
            vout_Release(p_owner->p_vout);
683
            p_owner->p_vout = NULL; // the DecoderThread should not use the old vout anymore
684
685
            vlc_mutex_unlock( &p_owner->lock );
        }
686
        return NULL;
687
    }
688

689
    if( p_owner->p_vout != p_vout )
690
    {
691
        if (p_owner->p_vout) /* notify the previous vout deletion unlocked */
692
            decoder_Notify(p_owner, on_vout_stopped, p_owner->p_vout);
693

694
695
        vlc_mutex_lock(&p_owner->lock);

696
697
698
699
700
701
        if (p_owner->p_vout)
        {
            /* Unregister the SPU channel of the previous vout */
            assert(p_owner->i_spu_channel != VOUT_SPU_CHANNEL_INVALID);
            vout_UnregisterSubpictureChannel(p_owner->p_vout,
                                             p_owner->i_spu_channel);
702
            vout_Release(p_owner->p_vout);
703
            p_owner->p_vout = NULL; // the DecoderThread should not use the old vout anymore
704
705
        }

706
        enum vlc_vout_order channel_order;
707
        p_owner->i_spu_channel =
708
            vout_RegisterSubpictureChannelInternal(p_vout, p_owner->p_clock,
709
                                                   &channel_order);
710
        p_owner->i_spu_order = 0;
711

712
        if (p_owner->i_spu_channel == VOUT_SPU_CHANNEL_INVALID)
713
        {
714
            /* The new vout doesn't support SPU, aborting... */
715
            vlc_mutex_unlock(&p_owner->lock);
716
717
            vout_Release(p_vout);
            return NULL;
718
        }
719

720
        p_owner->p_vout = p_vout;
721
        p_owner->vout_order = channel_order;
722
        vlc_mutex_unlock(&p_owner->lock);
723
724

        assert(channel_order != VLC_VOUT_ORDER_NONE);
725
        decoder_Notify(p_owner, on_vout_started, p_vout, channel_order);
726
    }
727
    else
728
        vout_Release(p_vout);
729
730
731
732
733
734
735
736
737
738

    p_subpic = subpicture_New( p_updater );
    if( p_subpic )
    {
        p_subpic->i_channel = p_owner->i_spu_channel;
        p_subpic->i_order = p_owner->i_spu_order++;
        p_subpic->b_subtitle = true;
    }

    return p_subpic;
739
}
gbazin's avatar
   
gbazin committed
740

741
static int InputThread_GetInputAttachments( decoder_t *p_dec,
742
743
                                       input_attachment_t ***ppp_attachment,
                                       int *pi_attachment )
744
{
745
    vlc_input_decoder_t *p_owner = dec_get_owner( p_dec );
746
    if (!p_owner->cbs || !p_owner->cbs->get_attachments)
747
        return VLC_ENOOBJ;
748

749
    int ret = p_owner->cbs->get_attachments(p_owner, ppp_attachment,
750
                                            p_owner->cbs_userdata);
751
752
753
754
    if (ret < 0)
        return VLC_EGENERIC;
    *pi_attachment = ret;
    return VLC_SUCCESS;
755
756
}

757
758
static vlc_tick_t ModuleThread_GetDisplayDate( decoder_t *p_dec,
                                       vlc_tick_t system_now, vlc_tick_t i_ts )
759
{
760
    vlc_input_decoder_t *p_owner = dec_get_owner( p_dec );
761
762

    vlc_mutex_lock( &p_owner->lock );
763
    if( p_owner->b_waiting || p_owner->paused )
764
        i_ts = VLC_TICK_INVALID;
765
    float rate = p_owner->output_rate;
766
    vlc_mutex_unlock( &p_owner->lock );
767

768
    if( !p_owner->p_clock || i_ts == VLC_TICK_INVALID )
769
        return i_ts;
770

771
    return vlc_clock_ConvertToSystem( p_owner->p_clock, system_now, i_ts, rate );
772
773
}

774
static float ModuleThread_GetDisplayRate( decoder_t *p_dec )
Laurent Aimar's avatar
Laurent Aimar committed
775
{
776
    vlc_input_decoder_t *p_owner = dec_get_owner( p_dec );
Laurent Aimar's avatar
Laurent Aimar committed
777

778
    if( !p_owner->p_clock )
779
        return 1.f;
780
781
782
783
    vlc_mutex_lock( &p_owner->lock );
    float rate = p_owner->output_rate;
    vlc_mutex_unlock( &p_owner->lock );
    return rate;
784
}
Laurent Aimar's avatar
Laurent Aimar committed
785

786
787
788
789
/*****************************************************************************
 * Public functions
 *****************************************************************************/
block_t *decoder_NewAudioBuffer( decoder_t *dec, int samples )
790
{
791
792
793
    assert( dec->fmt_out.audio.i_frame_length > 0
         && dec->fmt_out.audio.i_bytes_per_frame  > 0 );

794
795
796
797
    size_t length = samples * dec->fmt_out.audio.i_bytes_per_frame
                            / dec->fmt_out.audio.i_frame_length;
    block_t *block = block_Alloc( length );
    if( likely(block != NULL) )
798
    {
799
800
        block->i_nb_samples = samples;
        block->i_pts = block->i_length = 0;
801
    }
802
    return block;
803
804
}

805
static void RequestReload( vlc_input_decoder_t *p_owner )
806
807
808
809
810
811
{
    /* Don't override reload if it's RELOAD_DECODER_AOUT */
    int expected = RELOAD_NO_REQUEST;
    atomic_compare_exchange_strong( &p_owner->reload, &expected, RELOAD_DECODER );
}

812
static void DecoderWaitUnblock( vlc_input_decoder_t *p_owner )
813
{
814
    vlc_mutex_assert( &p_owner->lock );
815

816
    while( p_owner->b_waiting && p_owner->b_has_data )
817
        vlc_cond_wait( &p_owner->wait_request, &p_owner->lock );
818
819
}

Steve Lhomme's avatar
Steve Lhomme committed
820
static inline void DecoderUpdatePreroll( vlc_tick_t *pi_preroll, const block_t *p )
Laurent Aimar's avatar
Laurent Aimar committed
821
{
822
    if( p->i_flags & BLOCK_FLAG_PREROLL )
823
        *pi_preroll = PREROLL_FORCED;
824
825
826
    /* Check if we can use the packet for end of preroll */
    else if( (p->i_flags & BLOCK_FLAG_DISCONTINUITY) &&
             (p->i_buffer == 0 || (p->i_flags & BLOCK_FLAG_CORRUPTED)) )
827
        *pi_preroll = PREROLL_FORCED;
828
    else if( p->i_dts != VLC_TICK_INVALID )
Laurent Aimar's avatar
Laurent Aimar committed
829
        *pi_preroll = __MIN( *pi_preroll, p->i_dts );
830
    else if( p->i_pts != VLC_TICK_INVALID )
Laurent Aimar's avatar
Laurent Aimar committed
831
        *pi_preroll = __MIN( *pi_preroll, p->i_pts );
Laurent Aimar's avatar
Laurent Aimar committed
832
}
833

834
#ifdef ENABLE_SOUT
835
static int DecoderThread_PlaySout( vlc_input_decoder_t *p_owner, block_t *p_sout_block )
836
{
837
    assert( !p_sout_block->p_next );
838

839
    vlc_mutex_lock( &p_owner->lock );
840

841
    if( p_owner->b_waiting )
842
    {
843
        p_owner->b_has_data = true;
flx42's avatar
flx42 committed
844
        vlc_cond_signal( &p_owner->wait_acknowledge );
845
    }
846

847
    DecoderWaitUnblock( p_owner );
848

849
    vlc_mutex_unlock( &p_owner->lock );
850

851
    /* FIXME --VLC_TICK_INVALID inspect stream_output*/
852
853
    return sout_InputSendBuffer( p_owner->p_sout, p_owner->p_sout_input,
                                 p_sout_block );
854
855
}

856
857
/* This function process a block for sout
 */
858
static void DecoderThread_ProcessSout( vlc_input_decoder_t *p_owner, block_t *p_block )
Laurent Aimar's avatar
Laurent Aimar committed
859
{
860
    decoder_t *p_dec = &p_owner->dec;
861
    block_t *p_sout_block;
862
    block_t **pp_block = p_block ? &p_block : NULL;
Laurent Aimar's avatar
Laurent Aimar committed
863

864
    while( ( p_sout_block =
865
                 p_dec->pf_packetize( p_dec, pp_block ) ) )
Laurent Aimar's avatar
Laurent Aimar committed
866
    {
867
        if( p_owner->p_sout_input == NULL )
868
        {
869
            vlc_mutex_lock( &p_owner->lock );
Steve Lhomme's avatar