video.c 38.7 KB
Newer Older
1
2
3
/*****************************************************************************
 * video.c: video decoder using the ffmpeg library
 *****************************************************************************
4
 * Copyright (C) 1999-2001 the VideoLAN team
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 * $Id$
 *
 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
 *          Gildas Bazin <gbazin@videolan.org>
 *
 * 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
dionoea's avatar
dionoea committed
22
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23
24
25
26
27
 *****************************************************************************/

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

32
#include <vlc_common.h>
zorglub's avatar
zorglub committed
33
#include <vlc_codec.h>
34
#include <vlc_codecs.h>                               /* BITMAPINFOHEADER */
35
#include <vlc_avcodec.h>
36
#include <assert.h>
37
38

/* ffmpeg header */
39
40
#ifdef HAVE_LIBAVCODEC_AVCODEC_H
#   include <libavcodec/avcodec.h>
41
42
43
#   ifdef HAVE_AVCODEC_VAAPI
#       include <libavcodec/vaapi.h>
#   endif
44
#elif defined(HAVE_FFMPEG_AVCODEC_H)
45
#   include <ffmpeg/avcodec.h>
46
47
48
49
#else
#   include <avcodec.h>
#endif

50
#include "avcodec.h"
51
#include "vaapi.h"
52
53
54
55
56
57

/*****************************************************************************
 * decoder_sys_t : decoder descriptor
 *****************************************************************************/
struct decoder_sys_t
{
58
    FFMPEG_COMMON_MEMBERS
59
60
61
62
63
64
65
66
67

    /* Video decoder specific part */
    mtime_t input_pts;
    mtime_t input_dts;
    mtime_t i_pts;

    AVFrame          *p_ff_pic;

    /* for frame skipping algo */
68
    bool b_hurry_up;
69
70
    enum AVDiscard i_skip_frame;
    enum AVDiscard i_skip_idct;
71
72
73
74
75
76

    /* how many decoded frames are late */
    int     i_late_frames;
    mtime_t i_late_frames_start;

    /* for direct rendering */
77
    bool b_direct_rendering;
78

79
    bool b_has_b_frames;
80
81

    /* Hack to force display of still pictures */
82
    bool b_first_frame;
83
84
85

    int i_buffer_orig, i_buffer;
    char *p_buffer_orig, *p_buffer;
86

87
88
    /* */
    AVPaletteControl palette;
89
90
91

    /* */
    bool b_flush;
92
93
94

    /* VA API */
    vlc_va_t *p_va;
95
96
97
};

/* FIXME (dummy palette for now) */
hartman's avatar
hartman committed
98
static const AVPaletteControl palette_control;
99
100
101
102

/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
103
static void ffmpeg_InitCodec      ( decoder_t * );
104
static int  ffmpeg_OpenCodec      ( decoder_t * );
105
106
static void ffmpeg_CopyPicture    ( decoder_t *, picture_t *, AVFrame * );
static int  ffmpeg_GetFrameBuf    ( struct AVCodecContext *, AVFrame * );
107
static int  ffmpeg_ReGetFrameBuf( struct AVCodecContext *, AVFrame * );
108
static void ffmpeg_ReleaseFrameBuf( struct AVCodecContext *, AVFrame * );
109
static void ffmpeg_NextPts( decoder_t * );
110

111
#ifdef HAVE_AVCODEC_VAAPI
112
113
static enum PixelFormat ffmpeg_GetFormat( AVCodecContext *,
                                          const enum PixelFormat * );
114
#endif
115

116
117
118
119
120
121
122
123
124
125
126
127
128
129
static uint32_t ffmpeg_CodecTag( vlc_fourcc_t fcc )
{
    uint8_t *p = (uint8_t*)&fcc;
    return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
}

/*****************************************************************************
 * Local Functions
 *****************************************************************************/

/* Returns a new picture buffer */
static inline picture_t *ffmpeg_NewPictBuf( decoder_t *p_dec,
                                            AVCodecContext *p_context )
{
130
    decoder_sys_t *p_sys = p_dec->p_sys;
131
132
133
134
135
136
137
138
139

    p_dec->fmt_out.video.i_width = p_context->width;
    p_dec->fmt_out.video.i_height = p_context->height;

    if( !p_context->width || !p_context->height )
    {
        return NULL; /* invalid display size */
    }

140
    if( !p_sys->p_va && GetVlcChroma( &p_dec->fmt_out.video, p_context->pix_fmt ) )
141
    {
142
143
144
145
        /* we are doomed, but not really, because most codecs set their pix_fmt
         * much later
         * FIXME does it make sense here ? */
        p_dec->fmt_out.video.i_chroma = VLC_CODEC_I420;
146
    }
147
    p_dec->fmt_out.i_codec = p_dec->fmt_out.video.i_chroma;
148
149
150
151
152
153
154
155
156
157
158

    /* If an aspect-ratio was specified in the input format then force it */
    if( p_dec->fmt_in.video.i_aspect )
    {
        p_dec->fmt_out.video.i_aspect = p_dec->fmt_in.video.i_aspect;
    }
    else
    {
        p_dec->fmt_out.video.i_aspect =
            VOUT_ASPECT_FACTOR * ( av_q2d(p_context->sample_aspect_ratio) *
                p_context->width / p_context->height );
159
160
        p_dec->fmt_out.video.i_sar_num = p_context->sample_aspect_ratio.num;
        p_dec->fmt_out.video.i_sar_den = p_context->sample_aspect_ratio.den;
161

162
163
164
165
166
167
168
        if( p_dec->fmt_out.video.i_aspect == 0 )
        {
            p_dec->fmt_out.video.i_aspect =
                VOUT_ASPECT_FACTOR * p_context->width / p_context->height;
        }
    }

Laurent Aimar's avatar
Laurent Aimar committed
169
170
    if( p_dec->fmt_in.video.i_frame_rate > 0 &&
        p_dec->fmt_in.video.i_frame_rate_base > 0 )
171
172
173
174
    {
        p_dec->fmt_out.video.i_frame_rate =
            p_dec->fmt_in.video.i_frame_rate;
        p_dec->fmt_out.video.i_frame_rate_base =
damienf's avatar
damienf committed
175
            p_dec->fmt_in.video.i_frame_rate_base;
176
    }
177
    else if( p_context->time_base.num > 0 && p_context->time_base.den > 0 )
178
179
180
181
    {
        p_dec->fmt_out.video.i_frame_rate = p_context->time_base.den;
        p_dec->fmt_out.video.i_frame_rate_base = p_context->time_base.num;
    }
182

183
    return decoder_NewPicture( p_dec );
184
185
186
187
188
189
190
191
}

/*****************************************************************************
 * InitVideo: initialize the video decoder
 *****************************************************************************
 * the ffmpeg codec will be opened, some memory allocated. The vout is not yet
 * opened (done after the first decoded frame).
 *****************************************************************************/
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
192
int InitVideoDec( decoder_t *p_dec, AVCodecContext *p_context,
193
                      AVCodec *p_codec, int i_codec_id, const char *psz_namecodec )
194
195
196
197
198
{
    decoder_sys_t *p_sys;
    vlc_value_t val;

    /* Allocate the memory needed to store the decoder's structure */
ivoire's avatar
ivoire committed
199
    if( ( p_dec->p_sys = p_sys = calloc( 1, sizeof(decoder_sys_t) ) ) == NULL )
200
        return VLC_ENOMEM;
201

202
203
204
205
    p_sys->p_context = p_context;
    p_sys->p_codec = p_codec;
    p_sys->i_codec_id = i_codec_id;
    p_sys->psz_namecodec = psz_namecodec;
206
    p_sys->p_ff_pic = avcodec_alloc_frame();
207
    p_sys->b_delayed_open = true;
208
    p_sys->p_va = NULL;
209
210

    /* ***** Fill p_context with init values ***** */
211
    p_sys->p_context->codec_tag = ffmpeg_CodecTag( p_dec->fmt_in.i_original_fourcc ?: p_dec->fmt_in.i_codec );
212
213
214
215

    /*  ***** Get configuration of ffmpeg plugin ***** */
    p_sys->p_context->workaround_bugs =
        config_GetInt( p_dec, "ffmpeg-workaround-bugs" );
aballier's avatar
aballier committed
216
#if LIBAVCODEC_VERSION_INT < ((52<<16)+(0<<8)+0)
217
218
    p_sys->p_context->error_resilience =
        config_GetInt( p_dec, "ffmpeg-error-resilience" );
aballier's avatar
aballier committed
219
220
221
222
#else
    p_sys->p_context->error_recognition =
        config_GetInt( p_dec, "ffmpeg-error-resilience" );
#endif
223
224
225
226
227
228
229
230
231
232
233
234
235

    var_Create( p_dec, "grayscale", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
    var_Get( p_dec, "grayscale", &val );
    if( val.b_bool ) p_sys->p_context->flags |= CODEC_FLAG_GRAY;

    var_Create( p_dec, "ffmpeg-vismv", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
    var_Get( p_dec, "ffmpeg-vismv", &val );
    if( val.i_int ) p_sys->p_context->debug_mv = val.i_int;

    var_Create( p_dec, "ffmpeg-lowres", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
    var_Get( p_dec, "ffmpeg-lowres", &val );
    if( val.i_int > 0 && val.i_int <= 2 ) p_sys->p_context->lowres = val.i_int;

236
237
238
239
240
241
242
243
    var_Create( p_dec, "ffmpeg-skiploopfilter",
                VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
    var_Get( p_dec, "ffmpeg-skiploopfilter", &val );
    if( val.i_int > 0 ) p_sys->p_context->skip_loop_filter = AVDISCARD_NONREF;
    if( val.i_int > 1 ) p_sys->p_context->skip_loop_filter = AVDISCARD_BIDIR;
    if( val.i_int > 2 ) p_sys->p_context->skip_loop_filter = AVDISCARD_NONKEY;
    if( val.i_int > 3 ) p_sys->p_context->skip_loop_filter = AVDISCARD_ALL;

244
245
246
    bool b_fast = var_CreateGetBool( p_dec, "ffmpeg-fast" );
    if( b_fast ) p_sys->p_context->flags2 |= CODEC_FLAG2_FAST;

247
248
249
250
251
    /* ***** ffmpeg frame skipping ***** */
    var_Create( p_dec, "ffmpeg-hurry-up", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
    var_Get( p_dec, "ffmpeg-hurry-up", &val );
    p_sys->b_hurry_up = val.b_bool;

252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
    var_Create( p_dec, "ffmpeg-skip-frame", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
    var_Get( p_dec, "ffmpeg-skip-frame", &val );
    switch( val.i_int )
    {
        case -1:
            p_sys->p_context->skip_frame = AVDISCARD_NONE;
            break;
        case 0:
            p_sys->p_context->skip_frame = AVDISCARD_DEFAULT;
            break;
        case 1:
            p_sys->p_context->skip_frame = AVDISCARD_BIDIR;
            break;
        case 2:
            p_sys->p_context->skip_frame = AVDISCARD_NONKEY;
            break;
        case 3:
            p_sys->p_context->skip_frame = AVDISCARD_ALL;
            break;
        default:
            p_sys->p_context->skip_frame = AVDISCARD_NONE;
            break;
    }
275
    p_sys->i_skip_frame = p_sys->p_context->skip_frame;
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299

    var_Create( p_dec, "ffmpeg-skip-idct",  VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
    var_Get( p_dec, "ffmpeg-skip-idct", &val );
    switch( val.i_int )
    {
        case -1:
            p_sys->p_context->skip_idct = AVDISCARD_NONE;
            break;
        case 0:
            p_sys->p_context->skip_idct = AVDISCARD_DEFAULT;
            break;
        case 1:
            p_sys->p_context->skip_idct = AVDISCARD_BIDIR;
            break;
        case 2:
            p_sys->p_context->skip_idct = AVDISCARD_NONKEY;
            break;
        case 3:
            p_sys->p_context->skip_idct = AVDISCARD_ALL;
            break;
        default:
            p_sys->p_context->skip_idct = AVDISCARD_NONE;
            break;
    }
300
    p_sys->i_skip_idct = p_sys->p_context->skip_idct;
301

302
    /* ***** ffmpeg direct rendering ***** */
303
    p_sys->b_direct_rendering = false;
304
305
306
307
308
309
310
    var_Create( p_dec, "ffmpeg-dr", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
    var_Get( p_dec, "ffmpeg-dr", &val );
    if( val.b_bool && (p_sys->p_codec->capabilities & CODEC_CAP_DR1) &&
        /* Apparently direct rendering doesn't work with YUV422P */
        p_sys->p_context->pix_fmt != PIX_FMT_YUV422P &&
        /* H264 uses too many reference frames */
        p_sys->i_codec_id != CODEC_ID_H264 &&
311
312
        /* No idea why ... but this fixes flickering on some TSCC streams */
        p_sys->i_codec_id != CODEC_ID_TSCC &&
313
314
315
316
        !p_sys->p_context->debug_mv )
    {
        /* Some codecs set pix_fmt only after the 1st frame has been decoded,
         * so we need to do another check in ffmpeg_GetFrameBuf() */
317
        p_sys->b_direct_rendering = true;
318
319
320
    }

    /* ffmpeg doesn't properly release old pictures when frames are skipped */
321
    //if( p_sys->b_hurry_up ) p_sys->b_direct_rendering = false;
322
323
324
325
326
327
328
329
330
    if( p_sys->b_direct_rendering )
    {
        msg_Dbg( p_dec, "using direct rendering" );
        p_sys->p_context->flags |= CODEC_FLAG_EMU_EDGE;
    }

    /* Always use our get_buffer wrapper so we can calculate the
     * PTS correctly */
    p_sys->p_context->get_buffer = ffmpeg_GetFrameBuf;
331
    p_sys->p_context->reget_buffer = ffmpeg_ReGetFrameBuf;
332
333
334
    p_sys->p_context->release_buffer = ffmpeg_ReleaseFrameBuf;
    p_sys->p_context->opaque = p_dec;

335
#ifdef HAVE_AVCODEC_VAAPI
336
337
    if( var_CreateGetBool( p_dec, "ffmpeg-hw" ) )
        p_sys->p_context->get_format = ffmpeg_GetFormat;
338
#endif
339

340
341
342
    /* ***** misc init ***** */
    p_sys->input_pts = p_sys->input_dts = 0;
    p_sys->i_pts = 0;
343
344
    p_sys->b_has_b_frames = false;
    p_sys->b_first_frame = true;
345
    p_sys->b_flush = false;
346
347
348
349
    p_sys->i_late_frames = 0;
    p_sys->i_buffer = 0;
    p_sys->i_buffer_orig = 1;
    p_sys->p_buffer_orig = p_sys->p_buffer = malloc( p_sys->i_buffer_orig );
ivoire's avatar
ivoire committed
350
351
    if( !p_sys->p_buffer_orig )
    {
352
        av_free( p_sys->p_ff_pic );
ivoire's avatar
ivoire committed
353
354
355
        free( p_sys );
        return VLC_ENOMEM;
    }
356
357
358

    /* Set output properties */
    p_dec->fmt_out.i_cat = VIDEO_ES;
359
360
    if( GetVlcChroma( &p_dec->fmt_out.video, p_context->pix_fmt ) != VLC_SUCCESS )
    {
361
        /* we are doomed. but not really, because most codecs set their pix_fmt later on */
362
        p_dec->fmt_out.i_codec = VLC_CODEC_I420;
363
364
    }
    p_dec->fmt_out.i_codec = p_dec->fmt_out.video.i_chroma;
365
366

    /* Setup palette */
367
    memset( &p_sys->palette, 0, sizeof(p_sys->palette) );
368
    if( p_dec->fmt_in.video.p_palette )
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
    {
        p_sys->palette.palette_changed = 1;

        for( int i = 0; i < __MIN( AVPALETTE_COUNT, p_dec->fmt_in.video.p_palette->i_entries ); i++ )
        {
            union {
                uint32_t u;
                uint8_t a[4];
            } c;
            c.a[0] = p_dec->fmt_in.video.p_palette->palette[i][0];
            c.a[1] = p_dec->fmt_in.video.p_palette->palette[i][1];
            c.a[2] = p_dec->fmt_in.video.p_palette->palette[i][2];
            c.a[3] = p_dec->fmt_in.video.p_palette->palette[i][3];

            p_sys->palette.palette[i] = c.u;
        }
        p_sys->p_context->palctrl = &p_sys->palette;

        p_dec->fmt_out.video.p_palette = malloc( sizeof(video_palette_t) );
        if( p_dec->fmt_out.video.p_palette )
            *p_dec->fmt_out.video.p_palette = *p_dec->fmt_in.video.p_palette;
    }
391
    else if( p_sys->i_codec_id != CODEC_ID_MSVIDEO1 && p_sys->i_codec_id != CODEC_ID_CINEPAK )
392
393
394
    {
        p_sys->p_context->palctrl = &p_sys->palette;
    }
395

396
397
398
    /* ***** init this codec with special data ***** */
    ffmpeg_InitCodec( p_dec );

399
    /* ***** Open the codec ***** */
400
    if( ffmpeg_OpenCodec( p_dec ) < 0 )
401
402
    {
        msg_Err( p_dec, "cannot open codec (%s)", p_sys->psz_namecodec );
403
        av_free( p_sys->p_ff_pic );
404
        free( p_sys->p_buffer_orig );
405
406
407
408
409
410
411
412
413
414
        free( p_sys );
        return VLC_EGENERIC;
    }

    return VLC_SUCCESS;
}

/*****************************************************************************
 * DecodeVideo: Called to decode one or more frames
 *****************************************************************************/
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
415
picture_t *DecodeVideo( decoder_t *p_dec, block_t **pp_block )
416
417
418
{
    decoder_sys_t *p_sys = p_dec->p_sys;
    int b_drawpicture;
419
    int b_null_size = false;
420
421
    block_t *p_block;

422
423
    if( !pp_block || !*pp_block )
        return NULL;
424

425
    if( !p_sys->p_context->extradata_size && p_dec->fmt_in.i_extra )
426
    {
427
        ffmpeg_InitCodec( p_dec );
428
429
430
431
432
433
        if( p_sys->b_delayed_open )
        {
            if( ffmpeg_OpenCodec( p_dec ) )
                msg_Err( p_dec, "cannot open codec (%s)", p_sys->psz_namecodec );
        }
    }
434

435
    p_block = *pp_block;
436
437
438
439
440
    if( p_sys->b_delayed_open )
    {
        block_Release( p_block );
        return NULL;
    }
441
442
443
444
445
446
447
448
449
450

    if( p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) )
    {
        p_sys->i_buffer = 0;
        p_sys->i_pts = 0; /* To make sure we recover properly */

        p_sys->input_pts = p_sys->input_dts = 0;
        p_sys->i_late_frames = 0;

        block_Release( p_block );
Laurent Aimar's avatar
Laurent Aimar committed
451
452
453

        //if( p_block->i_flags & BLOCK_FLAG_CORRUPTED )
            //avcodec_flush_buffers( p_sys->p_context );
454
455
456
457
458
459
460
461
462
463
464
        return NULL;
    }

    if( p_block->i_flags & BLOCK_FLAG_PREROLL )
    {
        /* Do not care about late frames when prerolling
         * TODO avoid decoding of non reference frame
         * (ie all B except for H264 where it depends only on nal_ref_idc) */
        p_sys->i_late_frames = 0;
    }

465
    if( !p_dec->b_pace_control && (p_sys->i_late_frames > 0) &&
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
466
        (mdate() - p_sys->i_late_frames_start > INT64_C(5000000)) )
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
    {
        if( p_sys->i_pts )
        {
            msg_Err( p_dec, "more than 5 seconds of late video -> "
                     "dropping frame (computer too slow ?)" );
            p_sys->i_pts = 0; /* To make sure we recover properly */
        }
        block_Release( p_block );
        p_sys->i_late_frames--;
        return NULL;
    }

    if( p_block->i_pts > 0 || p_block->i_dts > 0 )
    {
        p_sys->input_pts = p_block->i_pts;
        p_sys->input_dts = p_block->i_dts;

        /* Make sure we don't reuse the same timestamps twice */
        p_block->i_pts = p_block->i_dts = 0;
    }

    /* A good idea could be to decode all I pictures and see for the other */
    if( !p_dec->b_pace_control &&
490
491
        p_sys->b_hurry_up &&
        (p_sys->i_late_frames > 4) )
492
493
    {
        b_drawpicture = 0;
494
        if( p_sys->i_late_frames < 12 )
495
        {
496
497
498
            p_sys->p_context->skip_frame =
                    (p_sys->i_skip_frame <= AVDISCARD_BIDIR) ?
                    AVDISCARD_BIDIR : p_sys->i_skip_frame;
499
500
501
502
503
504
505
506
507
508
509
510
511
        }
        else
        {
            /* picture too late, won't decode
             * but break picture until a new I, and for mpeg4 ...*/
            p_sys->i_late_frames--; /* needed else it will never be decrease */
            block_Release( p_block );
            p_sys->i_buffer = 0;
            return NULL;
        }
    }
    else
    {
512
        if( p_sys->b_hurry_up )
513
            p_sys->p_context->skip_frame = p_sys->i_skip_frame;
Laurent Aimar's avatar
Laurent Aimar committed
514
        if( !(p_block->i_flags & BLOCK_FLAG_PREROLL) )
515
516
517
518
519
520
521
            b_drawpicture = 1;
        else
            b_drawpicture = 0;
    }

    if( p_sys->p_context->width <= 0 || p_sys->p_context->height <= 0 )
    {
522
        if( p_sys->b_hurry_up )
523
            p_sys->p_context->skip_frame = p_sys->i_skip_frame;
524
        b_null_size = true;
525
    }
Laurent Aimar's avatar
Laurent Aimar committed
526
527
    else if( !b_drawpicture )
    {
528
529
530
        /* It creates broken picture
         * FIXME either our parser or ffmpeg is broken */
#if 0
531
532
533
        if( p_sys->b_hurry_up )
            p_sys->p_context->skip_frame = __MAX( p_sys->p_context->skip_frame,
                                                  AVDISCARD_NONREF );
534
#endif
Laurent Aimar's avatar
Laurent Aimar committed
535
    }
536
537
538
539
540
541
542
543
544

    /*
     * Do the actual decoding now
     */

    /* Don't forget that ffmpeg requires a little more bytes
     * that the real frame size */
    if( p_block->i_buffer > 0 )
    {
545
546
        p_sys->b_flush = ( p_block->i_flags & BLOCK_FLAG_END_OF_SEQUENCE ) != 0;

547
548
549
550
551
552
553
554
555
556
557
        p_sys->i_buffer = p_block->i_buffer;
        if( p_sys->i_buffer + FF_INPUT_BUFFER_PADDING_SIZE >
            p_sys->i_buffer_orig )
        {
            free( p_sys->p_buffer_orig );
            p_sys->i_buffer_orig =
                p_block->i_buffer + FF_INPUT_BUFFER_PADDING_SIZE;
            p_sys->p_buffer_orig = malloc( p_sys->i_buffer_orig );
        }
        p_sys->p_buffer = p_sys->p_buffer_orig;
        p_sys->i_buffer = p_block->i_buffer;
ivoire's avatar
ivoire committed
558
559
560
561
562
        if( !p_sys->p_buffer )
        {
            block_Release( p_block );
            return NULL;
        }
563
        vlc_memcpy( p_sys->p_buffer, p_block->p_buffer, p_block->i_buffer );
564
565
566
567
568
569
        memset( p_sys->p_buffer + p_block->i_buffer, 0,
                FF_INPUT_BUFFER_PADDING_SIZE );

        p_block->i_buffer = 0;
    }

570
    while( p_sys->i_buffer > 0 || p_sys->b_flush )
571
572
573
574
575
576
    {
        int i_used, b_gotpicture;
        picture_t *p_pic;

        i_used = avcodec_decode_video( p_sys->p_context, p_sys->p_ff_pic,
                                       &b_gotpicture,
577
578
                                       p_sys->i_buffer <= 0 && p_sys->b_flush ? NULL : (uint8_t*)p_sys->p_buffer, p_sys->i_buffer );

579
        if( b_null_size && p_sys->p_context->width > 0 &&
580
581
            p_sys->p_context->height > 0 &&
            !p_sys->b_flush )
582
583
        {
            /* Reparse it to not drop the I frame */
584
            b_null_size = false;
585
            if( p_sys->b_hurry_up )
586
                p_sys->p_context->skip_frame = p_sys->i_skip_frame;
587
588
            i_used = avcodec_decode_video( p_sys->p_context, p_sys->p_ff_pic,
                                           &b_gotpicture,
589
                                           (uint8_t*)p_sys->p_buffer, p_sys->i_buffer );
590
591
        }

592
593
594
595
596
597
        if( p_sys->b_flush )
            p_sys->b_first_frame = true;

        if( p_sys->i_buffer <= 0 )
            p_sys->b_flush = false;

598
599
        if( i_used < 0 )
        {
Laurent Aimar's avatar
Laurent Aimar committed
600
601
602
            if( b_drawpicture )
                msg_Warn( p_dec, "cannot decode one frame (%d bytes)",
                          p_sys->i_buffer );
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
            block_Release( p_block );
            return NULL;
        }
        else if( i_used > p_sys->i_buffer )
        {
            i_used = p_sys->i_buffer;
        }

        /* Consumed bytes */
        p_sys->i_buffer -= i_used;
        p_sys->p_buffer += i_used;

        /* Nothing to display */
        if( !b_gotpicture )
        {
            if( i_used == 0 ) break;
            continue;
        }

622
623
624
625
        /* Set the PTS */
        if( p_sys->p_ff_pic->pts )
            p_sys->i_pts = p_sys->p_ff_pic->pts;

626
        /* Update frame late count (except when doing preroll) */
627
628
629
        mtime_t i_display_date = 0;
        if( !(p_block->i_flags & BLOCK_FLAG_PREROLL) )
            i_display_date = decoder_GetDisplayDate( p_dec, p_sys->i_pts );
630

631
        if( i_display_date > 0 && i_display_date <= mdate() )
632
633
634
635
636
637
638
639
640
641
        {
            p_sys->i_late_frames++;
            if( p_sys->i_late_frames == 1 )
                p_sys->i_late_frames_start = mdate();
        }
        else
        {
            p_sys->i_late_frames = 0;
        }

642
        if( !b_drawpicture || ( !p_sys->p_va && !p_sys->p_ff_pic->linesize[0] ) )
643
644
        {
            /* Do not display the picture */
Laurent Aimar's avatar
Laurent Aimar committed
645
646
            p_pic = (picture_t *)p_sys->p_ff_pic->opaque;
            if( !b_drawpicture && p_pic )
647
                decoder_DeletePicture( p_dec, p_pic );
648

649
            ffmpeg_NextPts( p_dec );
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
            continue;
        }

        if( !p_sys->p_ff_pic->opaque )
        {
            /* Get a new picture */
            p_pic = ffmpeg_NewPictBuf( p_dec, p_sys->p_context );
            if( !p_pic )
            {
                block_Release( p_block );
                return NULL;
            }

            /* Fill p_picture_t from AVVideoFrame and do chroma conversion
             * if needed */
            ffmpeg_CopyPicture( p_dec, p_pic, p_sys->p_ff_pic );
        }
        else
        {
            p_pic = (picture_t *)p_sys->p_ff_pic->opaque;
        }

672
        /* Sanity check (seems to be needed for some streams) */
673
674
        if( p_sys->p_ff_pic->pict_type == FF_B_TYPE )
        {
675
            p_sys->b_has_b_frames = true;
676
677
        }

678
679
680
681
682
683
684
685
686
687
688
        if( !p_dec->fmt_in.video.i_aspect )
        {
            /* Fetch again the aspect ratio in case it changed */
            p_dec->fmt_out.video.i_aspect =
                VOUT_ASPECT_FACTOR
                    * ( av_q2d(p_sys->p_context->sample_aspect_ratio)
                    * p_sys->p_context->width / p_sys->p_context->height );
            p_dec->fmt_out.video.i_sar_num
                = p_sys->p_context->sample_aspect_ratio.num;
            p_dec->fmt_out.video.i_sar_den
                = p_sys->p_context->sample_aspect_ratio.den;
689

690
691
692
693
694
695
696
            if( p_dec->fmt_out.video.i_aspect == 0 )
            {
                p_dec->fmt_out.video.i_aspect = VOUT_ASPECT_FACTOR
                    * p_sys->p_context->width / p_sys->p_context->height;
            }
        }

697
698
699
700
701
        /* Send decoded frame to vout */
        if( p_sys->i_pts )
        {
            p_pic->date = p_sys->i_pts;

702
            ffmpeg_NextPts( p_dec );
703
704
705
706

            if( p_sys->b_first_frame )
            {
                /* Hack to force display of still pictures */
707
708
                p_sys->b_first_frame = false;
                p_pic->b_force = true;
709
710
711
712
713
714
            }

            p_pic->i_nb_fields = 2 + p_sys->p_ff_pic->repeat_pict;
            p_pic->b_progressive = !p_sys->p_ff_pic->interlaced_frame;
            p_pic->b_top_field_first = p_sys->p_ff_pic->top_field_first;

715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
            p_pic->i_qstride = p_sys->p_ff_pic->qstride;
            int i_mb_h = ( p_pic->format.i_height + 15 ) / 16;
            p_pic->p_q = malloc( p_pic->i_qstride * i_mb_h );
            memcpy( p_pic->p_q, p_sys->p_ff_pic->qscale_table,
                    p_pic->i_qstride * i_mb_h );
            switch( p_sys->p_ff_pic->qscale_type )
            {
                case FF_QSCALE_TYPE_MPEG1:
                    p_pic->i_qtype = QTYPE_MPEG1;
                    break;
                case FF_QSCALE_TYPE_MPEG2:
                    p_pic->i_qtype = QTYPE_MPEG2;
                    break;
                case FF_QSCALE_TYPE_H264:
                    p_pic->i_qtype = QTYPE_H264;
                    break;
            }

733
734
735
736
            return p_pic;
        }
        else
        {
737
            decoder_DeletePicture( p_dec, p_pic );
738
739
740
741
742
743
744
745
746
747
        }
    }

    block_Release( p_block );
    return NULL;
}

/*****************************************************************************
 * EndVideo: decoder destruction
 *****************************************************************************
748
 * This function is called when the thread ends after a successful
749
750
 * initialization.
 *****************************************************************************/
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
751
void EndVideoDec( decoder_t *p_dec )
752
753
754
{
    decoder_sys_t *p_sys = p_dec->p_sys;

755
756
    avcodec_flush_buffers( p_sys->p_context );

757
758
    if( p_sys->p_ff_pic ) av_free( p_sys->p_ff_pic );
    free( p_sys->p_buffer_orig );
759
760
761

    if( p_sys->p_va )
        VaDelete( p_sys->p_va );
762
763
}

764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
/*****************************************************************************
 * ffmpeg_InitCodec: setup codec extra initialization data for ffmpeg
 *****************************************************************************/
static void ffmpeg_InitCodec( decoder_t *p_dec )
{
    decoder_sys_t *p_sys = p_dec->p_sys;
    int i_size = p_dec->fmt_in.i_extra;

    if( !i_size ) return;

    if( p_sys->i_codec_id == CODEC_ID_SVQ3 )
    {
        uint8_t *p;

        p_sys->p_context->extradata_size = i_size + 12;
        p = p_sys->p_context->extradata  =
            malloc( p_sys->p_context->extradata_size );
ivoire's avatar
ivoire committed
781
782
        if( !p )
            return;
783
784
785
786
787
788
789

        memcpy( &p[0],  "SVQ3", 4 );
        memset( &p[4], 0, 8 );
        memcpy( &p[12], p_dec->fmt_in.p_extra, i_size );

        /* Now remove all atoms before the SMI one */
        if( p_sys->p_context->extradata_size > 0x5a &&
790
            strncmp( (char*)&p[0x56], "SMI ", 4 ) )
791
792
793
794
795
796
797
798
799
800
801
        {
            uint8_t *psz = &p[0x52];

            while( psz < &p[p_sys->p_context->extradata_size - 8] )
            {
                int i_size = GetDWBE( psz );
                if( i_size <= 1 )
                {
                    /* FIXME handle 1 as long size */
                    break;
                }
802
                if( !strncmp( (char*)&psz[4], "SMI ", 4 ) )
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
                {
                    memmove( &p[0x52], psz,
                             &p[p_sys->p_context->extradata_size] - psz );
                    break;
                }

                psz += i_size;
            }
        }
    }
    else
    {
        p_sys->p_context->extradata_size = i_size;
        p_sys->p_context->extradata =
            malloc( i_size + FF_INPUT_BUFFER_PADDING_SIZE );
ivoire's avatar
ivoire committed
818
819
820
821
822
823
824
        if( p_sys->p_context->extradata )
        {
            memcpy( p_sys->p_context->extradata,
                    p_dec->fmt_in.p_extra, i_size );
            memset( &((uint8_t*)p_sys->p_context->extradata)[i_size],
                    0, FF_INPUT_BUFFER_PADDING_SIZE );
        }
825
826
827
    }
}

828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
/*****************************************************************************
 * ffmpeg_OpenCodec:
 *****************************************************************************/
static int ffmpeg_OpenCodec( decoder_t *p_dec )
{
    decoder_sys_t *p_sys = p_dec->p_sys;

    if( p_sys->p_context->extradata_size <= 0 )
    {
        if( p_sys->i_codec_id == CODEC_ID_VC1 ||
            p_sys->i_codec_id == CODEC_ID_VORBIS ||
            p_sys->i_codec_id == CODEC_ID_THEORA )
        {
            msg_Warn( p_dec, "waiting for extra data for codec %s",
                      p_sys->psz_namecodec );
            return 1;
        }
    }
    p_sys->p_context->width  = p_dec->fmt_in.video.i_width;
    p_sys->p_context->height = p_dec->fmt_in.video.i_height;
Laurent Aimar's avatar
Laurent Aimar committed
848
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(52, 0, 0)
849
850
851
852
853
    p_sys->p_context->bits_per_sample = p_dec->fmt_in.video.i_bits_per_pixel;
#else
    p_sys->p_context->bits_per_coded_sample = p_dec->fmt_in.video.i_bits_per_pixel;
#endif

854
855
856
857
858
    int ret;
    vlc_avcodec_lock();
    ret = avcodec_open( p_sys->p_context, p_sys->p_codec );
    vlc_avcodec_unlock();
    if( ret < 0 )
859
860
861
862
863
        return VLC_EGENERIC;
    msg_Dbg( p_dec, "ffmpeg codec (%s) started", p_sys->psz_namecodec );

    p_sys->b_delayed_open = false;

864
865
866
867
868
869
870
871
    if( p_sys->p_va )
    {
        char psz_version[128];

        VaVersion( p_sys->p_va, psz_version, sizeof(psz_version) );
        msg_Info( p_dec, "Using VA API version %s for hardware decoding.", psz_version );
    }

872
873
    return VLC_SUCCESS;
}
874
875
876
877
878
879
880
881
882
/*****************************************************************************
 * ffmpeg_CopyPicture: copy a picture from ffmpeg internal buffers to a
 *                     picture_t structure (when not in direct rendering mode).
 *****************************************************************************/
static void ffmpeg_CopyPicture( decoder_t *p_dec,
                                picture_t *p_pic, AVFrame *p_ff_pic )
{
    decoder_sys_t *p_sys = p_dec->p_sys;

883
884
885
886
887
    if( p_sys->p_va )
    {
        VaExtract( p_sys->p_va, p_pic, p_ff_pic );
    }
    else if( TestFfmpegChroma( p_sys->p_context->pix_fmt, -1 ) == VLC_SUCCESS )
888
889
890
891
892
    {
        int i_plane, i_size, i_line;
        uint8_t *p_dst, *p_src;
        int i_src_stride, i_dst_stride;

893
        for( i_plane = 0; i_plane < p_pic->i_planes; i_plane++ )
894
        {
895
896
897
898
899
900
901
902
            p_src  = p_ff_pic->data[i_plane];
            p_dst = p_pic->p[i_plane].p_pixels;
            i_src_stride = p_ff_pic->linesize[i_plane];
            i_dst_stride = p_pic->p[i_plane].i_pitch;

            i_size = __MIN( i_src_stride, i_dst_stride );
            for( i_line = 0; i_line < p_pic->p[i_plane].i_visible_lines;
                 i_line++ )
903
            {
904
905
906
                vlc_memcpy( p_dst, p_src, i_size );
                p_src += i_src_stride;
                p_dst += i_dst_stride;
907
908
909
910
911
            }
        }
    }
    else
    {
912
913
914
        msg_Err( p_dec, "don't know how to convert chroma %i",
                 p_sys->p_context->pix_fmt );
        p_dec->b_error = 1;
915
916
917
918
919
920
921
922
923
    }
}

/*****************************************************************************
 * ffmpeg_GetFrameBuf: callback used by ffmpeg to get a frame buffer.
 *****************************************************************************
 * It is used for direct rendering as well as to get the right PTS for each
 * decoded picture (even in indirect rendering mode).
 *****************************************************************************/
924
925
static void ffmpeg_SetFrameBufferPts( decoder_t *p_dec, AVFrame *p_ff_pic );

926
927
928
929
930
931
932
933
static int ffmpeg_GetFrameBuf( struct AVCodecContext *p_context,
                               AVFrame *p_ff_pic )
{
    decoder_t *p_dec = (decoder_t *)p_context->opaque;
    decoder_sys_t *p_sys = p_dec->p_sys;
    picture_t *p_pic;

    /* Set picture PTS */
934
    ffmpeg_SetFrameBufferPts( p_dec, p_ff_pic );
935

936
    /* */
937
938
939
940
    p_ff_pic->opaque = NULL;

    if( p_sys->p_va )
    {
941
942
#ifdef HAVE_AVCODEC_VAAPI
        /* hwaccel_context is not present in old fffmpeg version */
943
944
945
946
947
948
949
        if( VaSetup( p_sys->p_va,
                     &p_sys->p_context->hwaccel_context, &p_dec->fmt_out.video.i_chroma,
                     p_sys->p_context->width, p_sys->p_context->height ) )
        {
            msg_Err( p_dec, "VaSetup failed" );
            return -1;
        }
950
951
952
#else
        assert(0);
#endif
953
954
955
956
957

        /* */
        p_ff_pic->type = FF_BUFFER_TYPE_USER;
        /* FIXME what is that, should give good value */
        p_ff_pic->age = 256*256*256*64; // FIXME FIXME from ffmpeg
958

959
960
961
962
963
964
965
966
        if( VaGrabSurface( p_sys->p_va, p_ff_pic ) )
        {
            msg_Err( p_dec, "VaGrabSurface failed" );
            return -1;
        }
        return 0;
    }
    else if( !p_sys->b_direct_rendering )
967
    {
968
        /* Not much to do in indirect rendering mode */
969
970
971
972
        return avcodec_default_get_buffer( p_context, p_ff_pic );
    }

    /* Some codecs set pix_fmt only after the 1st frame has been decoded,
973
974
975
976
977
978
     * so we need to check for direct rendering again. */

    int i_width = p_sys->p_context->width;
    int i_height = p_sys->p_context->height;
    avcodec_align_dimensions( p_sys->p_context, &i_width, &i_height );

979
    if( GetVlcChroma( &p_dec->fmt_out.video, p_context->pix_fmt ) != VLC_SUCCESS ||
980
981
        p_sys->p_context->width % 16 || p_sys->p_context->height % 16 ||
        /* We only pad picture up to 16 */
982
983
        PAD(p_sys->p_context->width,16) < i_width || PAD(p_sys->p_context->height,16) < i_height ||
        p_context->pix_fmt == PIX_FMT_PAL8 )
984
985
    {
        msg_Dbg( p_dec, "disabling direct rendering" );
986
        p_sys->b_direct_rendering = false;
987
988
        return avcodec_default_get_buffer( p_context, p_ff_pic );
    }
989
    p_dec->fmt_out.i_codec = p_dec->fmt_out.video.i_chroma;
990
991
992
993
994
995

    /* Get a new picture */
    //p_sys->p_vout->render.b_allow_modify_pics = 0;
    p_pic = ffmpeg_NewPictBuf( p_dec, p_sys->p_context );
    if( !p_pic )
    {
996
        p_sys->b_direct_rendering = false;
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
        return avcodec_default_get_buffer( p_context, p_ff_pic );
    }
    p_sys->p_context->draw_horiz_band = NULL;

    p_ff_pic->opaque = (void*)p_pic;
    p_ff_pic->type = FF_BUFFER_TYPE_USER;
    p_ff_pic->data[0] = p_pic->p[0].p_pixels;
    p_ff_pic->data[1] = p_pic->p[1].p_pixels;
    p_ff_pic->data[2] = p_pic->p[2].p_pixels;
    p_ff_pic->data[3] = NULL; /* alpha channel but I'm not sure */

    p_ff_pic->linesize[0] = p_pic->p[0].i_pitch;
    p_ff_pic->linesize[1] = p_pic->p[1].i_pitch;
    p_ff_pic->linesize[2] = p_pic->p[2].i_pitch;
    p_ff_pic->linesize[3] = 0;

1013
    decoder_LinkPicture( p_dec, p_pic );
1014
1015
1016
1017
1018
1019

    /* FIXME what is that, should give good value */
    p_ff_pic->age = 256*256*256*64; // FIXME FIXME from ffmpeg

    return 0;
}
1020
1021
1022
static int  ffmpeg_ReGetFrameBuf( struct AVCodecContext *p_context, AVFrame *p_ff_pic )
{
    decoder_t *p_dec = (decoder_t *)p_context->opaque;
1023
    int i_ret;
1024

1025
1026
    /* */
    p_ff_pic->pts = AV_NOPTS_VALUE;
1027
1028

    /* We always use default reget function, it works perfectly fine */
1029
1030
1031
1032
1033
1034
1035
1036
    i_ret = avcodec_default_reget_buffer( p_context, p_ff_pic );

    /* Set picture PTS if avcodec_default_reget_buffer didn't set it (through a
     * ffmpeg_GetFrameBuf call) */
    if( !i_ret && p_ff_pic->pts == AV_NOPTS_VALUE )
        ffmpeg_SetFrameBufferPts( p_dec, p_ff_pic );

    return i_ret;
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
}

static void ffmpeg_SetFrameBufferPts( decoder_t *p_dec, AVFrame *p_ff_pic )
{
    decoder_sys_t *p_sys = p_dec->p_sys;

    /* Set picture PTS */
    if( p_sys->input_pts )
    {
        p_ff_pic->pts = p_sys->input_pts;
    }
    else if( p_sys->input_dts )
    {
        /* Some demuxers only set the dts so let's try to find a useful
         * timestamp from this */
        if( !p_sys->p_context->has_b_frames || !p_sys->b_has_b_frames ||
            !p_ff_pic->reference || !p_sys->i_pts )
        {
            p_ff_pic->pts = p_sys->input_dts;
        }
1057
1058
1059
1060
1061
1062
1063
1064
        else
        {
            p_ff_pic->pts = 0;
        }
    }
    else
    {
        p_ff_pic->pts = 0;
1065
1066
1067
1068
1069
1070
1071
    }

    if( p_sys->i_pts ) /* make sure 1st frame has a pts > 0 */
    {
        p_sys->input_pts = p_sys->input_dts = 0;
    }
}
1072
1073
1074
1075
1076

static void ffmpeg_ReleaseFrameBuf( struct AVCodecContext *p_context,
                                    AVFrame *p_ff_pic )
{
    decoder_t *p_dec = (decoder_t *)p_context->opaque;
1077
1078
1079
1080
1081
    decoder_sys_t *p_sys = p_dec->p_sys;

    if( p_sys->p_va )
    {
        VaUngrabSurface( p_sys->p_va, p_ff_pic );
1082

1083
1084
1085
1086
1087
        /* */
        for( int i = 0; i < 4; i++ )
            p_ff_pic->data[i] = NULL;
    }
    else if( !p_ff_pic->opaque )
1088
1089
1090
    {
        avcodec_default_release_buffer( p_context, p_ff_pic );
    }
1091
1092
1093
    else
    {
        picture_t *p_pic = (picture_t*)p_ff_pic->opaque;
1094

1095
        decoder_UnlinkPicture( p_dec, p_pic );
1096

1097
1098
1099
1100
        /* */
        for( int i = 0; i < 4; i++ )
            p_ff_pic->data[i] = NULL;
    }
1101
}
1102

1103
static void ffmpeg_NextPts( decoder_t *p_dec )
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
{
    decoder_sys_t *p_sys = p_dec->p_sys;

    if( p_sys->i_pts <= 0 )
        return;

    /* interpolate the next PTS */
    if( p_dec->fmt_in.video.i_frame_rate > 0 &&
        p_dec->fmt_in.video.i_frame_rate_base > 0 )
    {
        p_sys->i_pts += INT64_C(1000000) *
            (2 + p_sys->p_ff_pic->repeat_pict) *
1116
            p_dec->fmt_in.video.i_frame_rate_base /
1117
1118
1119
1120
            (2 * p_dec->fmt_in.video.i_frame_rate);
    }
    else if( p_sys->p_context->time_base.den > 0 )
    {
1121
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(52,20,0)
Laurent Aimar's avatar
Laurent Aimar committed
1122
        int i_tick = p_sys->p_context->ticks_per_frame;
1123
1124
1125
1126
1127
1128
        if( i_tick <= 0 )
            i_tick = 1;
#else
        int i_tick = 1;
#endif

1129
1130
        p_sys->i_pts += INT64_C(1000000) *
            (2 + p_sys->p_ff_pic->repeat_pict) *
1131
            i_tick * p_sys->p_context->time_base.num /
1132
1133
1134
            (2 * p_sys->p_context->time_base.den);
    }
}
1135

1136
#ifdef HAVE_AVCODEC_VAAPI
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
static enum PixelFormat ffmpeg_GetFormat( AVCodecContext *p_codec,
                                          const enum PixelFormat *pi_fmt )
{
    decoder_t *p_dec = p_codec->opaque;
    decoder_sys_t *p_sys = p_dec->p_sys;

    if( p_sys->p_va )
    {
        VaDelete( p_sys->p_va );
        p_sys->p_va = NULL;
    }

    /* Try too look for a supported hw acceleration */
    for( int i = 0; pi_fmt[i] != PIX_FMT_NONE; i++ )
    {
        static const char *ppsz_name[PIX_FMT_NB] = {
            [PIX_FMT_VDPAU_H264] = "PIX_FMT_VDPAU_H264",
            [PIX_FMT_VAAPI_IDCT] = "PIX_FMT_VAAPI_IDCT",
            [PIX_FMT_VAAPI_VLD] = "PIX_FMT_VAAPI_VLD",
            [PIX_FMT_VAAPI_MOCO] = "PIX_FMT_VAAPI_MOCO",
            [PIX_FMT_YUYV422] = "PIX_FMT_YUYV422",
            [PIX_FMT_YUV420P] = "PIX_FMT_YUV420P",
        };
        msg_Dbg( p_dec, "Available decoder output format %d (%s)", pi_fmt[i], ppsz_name[pi_fmt[i]] ?: "Unknown" );

        /* Only VLD supported */
        if( pi_fmt[i] == PIX_FMT_VAAPI_VLD )
        {
            msg_Dbg( p_dec, "Trying VA API" );
            p_sys->p_va = VaNew( p_sys->i_codec_id );
            if( p_sys->p_va )
            {
                /* FIXME this will disabled direct rendering
                 * even if a new pixel format is renegociated
                 *
                 * FIXME Try to call VaSetup when possible
                 * to detect errors when possible (later is too late) */
                p_sys->b_direct_rendering = false;
                p_sys->p_context->draw_horiz_band = NULL;
                return pi_fmt[i];
            }
            msg_Warn( p_dec, "Failed to open VA API" );
        }
    }

    /* Fallback to default behaviour */
    return avcodec_default_get_format( p_codec, pi_fmt );
}
1185
#endif
1186