tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

vaapi_decode.c (25724B)


      1 /*
      2 * This file is part of FFmpeg.
      3 *
      4 * FFmpeg is free software; you can redistribute it and/or
      5 * modify it under the terms of the GNU Lesser General Public
      6 * License as published by the Free Software Foundation; either
      7 * version 2.1 of the License, or (at your option) any later version.
      8 *
      9 * FFmpeg is distributed in the hope that it will be useful,
     10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     12 * Lesser General Public License for more details.
     13 *
     14 * You should have received a copy of the GNU Lesser General Public
     15 * License along with FFmpeg; if not, write to the Free Software
     16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
     17 */
     18 
     19 #include "config_components.h"
     20 
     21 #include "libavutil/avassert.h"
     22 #include "libavutil/common.h"
     23 #include "libavutil/mem.h"
     24 #include "libavutil/pixdesc.h"
     25 
     26 #include "avcodec.h"
     27 #include "codec_desc.h"
     28 #include "decode.h"
     29 #include "internal.h"
     30 #include "vaapi_decode.h"
     31 #include "vaapi_hevc.h"
     32 
     33 
     34 int ff_vaapi_decode_make_param_buffer(AVCodecContext *avctx,
     35                                      VAAPIDecodePicture *pic,
     36                                      int type,
     37                                      const void *data,
     38                                      size_t size)
     39 {
     40    VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data;
     41    VAStatus vas;
     42 
     43    av_assert0(pic->nb_param_buffers <= pic->nb_param_buffers_allocated);
     44    if (pic->nb_param_buffers == pic->nb_param_buffers_allocated) {
     45        VABufferID *tmp =
     46            av_realloc_array(pic->param_buffers,
     47                             pic->nb_param_buffers_allocated + 16,
     48                             sizeof(*pic->param_buffers));
     49        if (!tmp)
     50            return AVERROR(ENOMEM);
     51 
     52        pic->param_buffers = tmp;
     53        pic->nb_param_buffers_allocated += 16;
     54    }
     55    av_assert0(pic->nb_param_buffers + 1 <= pic->nb_param_buffers_allocated);
     56 
     57    vas = vaCreateBuffer(ctx->hwctx->display, ctx->va_context,
     58                         type, size, 1, (void*)data,
     59                         &pic->param_buffers[pic->nb_param_buffers]);
     60    if (vas != VA_STATUS_SUCCESS) {
     61        av_log(avctx, AV_LOG_ERROR, "Failed to create parameter "
     62               "buffer (type %d): %d (%s).\n",
     63               type, vas, vaErrorStr(vas));
     64        return AVERROR(EIO);
     65    }
     66 
     67    av_log(avctx, AV_LOG_DEBUG, "Param buffer (type %d, %zu bytes) "
     68           "is %#x.\n", type, size, pic->param_buffers[pic->nb_param_buffers]);
     69 
     70    ++pic->nb_param_buffers;
     71 
     72    return 0;
     73 }
     74 
     75 int ff_vaapi_decode_make_slice_buffer(AVCodecContext *avctx,
     76                                      VAAPIDecodePicture *pic,
     77                                      const void *params_data,
     78                                      int nb_params,
     79                                      size_t params_size,
     80                                      const void *slice_data,
     81                                      size_t slice_size)
     82 {
     83    VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data;
     84    VAStatus vas;
     85    int index;
     86 
     87    av_assert0(pic->nb_slices <= pic->nb_slice_buffers_allocated);
     88    if (pic->nb_slices == pic->nb_slice_buffers_allocated) {
     89        VABufferID *tmp =
     90            av_realloc_array(pic->slice_buffers,
     91                             pic->nb_slice_buffers_allocated ? pic->nb_slice_buffers_allocated * 2 : 64,
     92                             2 * sizeof(*pic->slice_buffers));
     93        if (!tmp)
     94            return AVERROR(ENOMEM);
     95 
     96        pic->slice_buffers = tmp;
     97        pic->nb_slice_buffers_allocated = pic->nb_slice_buffers_allocated ? pic->nb_slice_buffers_allocated * 2 : 64;
     98    }
     99    av_assert0(pic->nb_slices + 1 <= pic->nb_slice_buffers_allocated);
    100 
    101    index = 2 * pic->nb_slices;
    102 
    103    vas = vaCreateBuffer(ctx->hwctx->display, ctx->va_context,
    104                         VASliceParameterBufferType,
    105                         params_size, nb_params, (void*)params_data,
    106                         &pic->slice_buffers[index]);
    107    if (vas != VA_STATUS_SUCCESS) {
    108        av_log(avctx, AV_LOG_ERROR, "Failed to create slice "
    109               "parameter buffer: %d (%s).\n", vas, vaErrorStr(vas));
    110        return AVERROR(EIO);
    111    }
    112 
    113    av_log(avctx, AV_LOG_DEBUG, "Slice %d param buffer (%zu bytes) "
    114           "is %#x.\n", pic->nb_slices, params_size,
    115           pic->slice_buffers[index]);
    116 
    117    vas = vaCreateBuffer(ctx->hwctx->display, ctx->va_context,
    118                         VASliceDataBufferType,
    119                         slice_size, 1, (void*)slice_data,
    120                         &pic->slice_buffers[index + 1]);
    121    if (vas != VA_STATUS_SUCCESS) {
    122        av_log(avctx, AV_LOG_ERROR, "Failed to create slice "
    123               "data buffer (size %zu): %d (%s).\n",
    124               slice_size, vas, vaErrorStr(vas));
    125        vaDestroyBuffer(ctx->hwctx->display,
    126                        pic->slice_buffers[index]);
    127        return AVERROR(EIO);
    128    }
    129 
    130    av_log(avctx, AV_LOG_DEBUG, "Slice %d data buffer (%zu bytes) "
    131           "is %#x.\n", pic->nb_slices, slice_size,
    132           pic->slice_buffers[index + 1]);
    133 
    134    ++pic->nb_slices;
    135    return 0;
    136 }
    137 
    138 static void ff_vaapi_decode_destroy_buffers(AVCodecContext *avctx,
    139                                            VAAPIDecodePicture *pic)
    140 {
    141    VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data;
    142    VAStatus vas;
    143    int i;
    144 
    145    for (i = 0; i < pic->nb_param_buffers; i++) {
    146        vas = vaDestroyBuffer(ctx->hwctx->display,
    147                              pic->param_buffers[i]);
    148        if (vas != VA_STATUS_SUCCESS) {
    149            av_log(avctx, AV_LOG_ERROR, "Failed to destroy "
    150                   "parameter buffer %#x: %d (%s).\n",
    151                   pic->param_buffers[i], vas, vaErrorStr(vas));
    152        }
    153    }
    154 
    155    for (i = 0; i < 2 * pic->nb_slices; i++) {
    156        vas = vaDestroyBuffer(ctx->hwctx->display,
    157                              pic->slice_buffers[i]);
    158        if (vas != VA_STATUS_SUCCESS) {
    159            av_log(avctx, AV_LOG_ERROR, "Failed to destroy slice "
    160                   "slice buffer %#x: %d (%s).\n",
    161                   pic->slice_buffers[i], vas, vaErrorStr(vas));
    162        }
    163    }
    164 }
    165 
    166 int ff_vaapi_decode_issue(AVCodecContext *avctx,
    167                          VAAPIDecodePicture *pic)
    168 {
    169    VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data;
    170    VAStatus vas;
    171    int err;
    172 
    173    if (pic->nb_slices <= 0) {
    174        err = AVERROR(EINVAL);
    175        goto fail;
    176    }
    177 
    178    av_log(avctx, AV_LOG_DEBUG, "Decode to surface %#x.\n",
    179           pic->output_surface);
    180 
    181    vas = vaBeginPicture(ctx->hwctx->display, ctx->va_context,
    182                         pic->output_surface);
    183    if (vas != VA_STATUS_SUCCESS) {
    184        av_log(avctx, AV_LOG_ERROR, "Failed to begin picture decode "
    185               "issue: %d (%s).\n", vas, vaErrorStr(vas));
    186        err = AVERROR(EIO);
    187        goto fail_with_picture;
    188    }
    189 
    190    vas = vaRenderPicture(ctx->hwctx->display, ctx->va_context,
    191                          pic->param_buffers, pic->nb_param_buffers);
    192    if (vas != VA_STATUS_SUCCESS) {
    193        av_log(avctx, AV_LOG_ERROR, "Failed to upload decode "
    194               "parameters: %d (%s).\n", vas, vaErrorStr(vas));
    195        err = AVERROR(EIO);
    196        goto fail_with_picture;
    197    }
    198 
    199    vas = vaRenderPicture(ctx->hwctx->display, ctx->va_context,
    200                          pic->slice_buffers, 2 * pic->nb_slices);
    201    if (vas != VA_STATUS_SUCCESS) {
    202        av_log(avctx, AV_LOG_ERROR, "Failed to upload slices: "
    203               "%d (%s).\n", vas, vaErrorStr(vas));
    204        err = AVERROR(EIO);
    205        goto fail_with_picture;
    206    }
    207 
    208    vas = vaEndPicture(ctx->hwctx->display, ctx->va_context);
    209    if (vas != VA_STATUS_SUCCESS) {
    210        av_log(avctx, AV_LOG_ERROR, "Failed to end picture decode "
    211               "issue: %d (%s).\n", vas, vaErrorStr(vas));
    212        err = AVERROR(EIO);
    213        if (CONFIG_VAAPI_1 || ctx->hwctx->driver_quirks &
    214            AV_VAAPI_DRIVER_QUIRK_RENDER_PARAM_BUFFERS)
    215            goto fail;
    216        else
    217            goto fail_at_end;
    218    }
    219 
    220    if (CONFIG_VAAPI_1 || ctx->hwctx->driver_quirks &
    221        AV_VAAPI_DRIVER_QUIRK_RENDER_PARAM_BUFFERS)
    222        ff_vaapi_decode_destroy_buffers(avctx, pic);
    223 
    224    err = 0;
    225    goto exit;
    226 
    227 fail_with_picture:
    228    vas = vaEndPicture(ctx->hwctx->display, ctx->va_context);
    229    if (vas != VA_STATUS_SUCCESS) {
    230        av_log(avctx, AV_LOG_ERROR, "Failed to end picture decode "
    231               "after error: %d (%s).\n", vas, vaErrorStr(vas));
    232    }
    233 fail:
    234    ff_vaapi_decode_destroy_buffers(avctx, pic);
    235 fail_at_end:
    236 exit:
    237    pic->nb_param_buffers           = 0;
    238    pic->nb_param_buffers_allocated = 0;
    239    av_freep(&pic->param_buffers);
    240    pic->nb_slices                  = 0;
    241    pic->nb_slice_buffers_allocated = 0;
    242    av_freep(&pic->slice_buffers);
    243 
    244    return err;
    245 }
    246 
    247 int ff_vaapi_decode_cancel(AVCodecContext *avctx,
    248                           VAAPIDecodePicture *pic)
    249 {
    250    ff_vaapi_decode_destroy_buffers(avctx, pic);
    251 
    252    pic->nb_param_buffers           = 0;
    253    pic->nb_param_buffers_allocated = 0;
    254    av_freep(&pic->param_buffers);
    255    pic->nb_slices                  = 0;
    256    pic->nb_slice_buffers_allocated = 0;
    257    av_freep(&pic->slice_buffers);
    258 
    259    return 0;
    260 }
    261 
    262 static const struct {
    263    uint32_t fourcc;
    264    enum AVPixelFormat pix_fmt;
    265 } vaapi_format_map[] = {
    266 #define MAP(va, av) { VA_FOURCC_ ## va, AV_PIX_FMT_ ## av }
    267    // 4:0:0
    268    MAP(Y800, GRAY8),
    269    // 4:2:0
    270    MAP(NV12, NV12),
    271    MAP(YV12, YUV420P),
    272    MAP(IYUV, YUV420P),
    273 #ifdef VA_FOURCC_I420
    274    MAP(I420, YUV420P),
    275 #endif
    276    MAP(IMC3, YUV420P),
    277    // 4:1:1
    278    MAP(411P, YUV411P),
    279    // 4:2:2
    280    MAP(422H, YUV422P),
    281 #ifdef VA_FOURCC_YV16
    282    MAP(YV16, YUV422P),
    283 #endif
    284    MAP(YUY2, YUYV422),
    285 #ifdef VA_FOURCC_Y210
    286    MAP(Y210,    Y210),
    287 #endif
    288 #ifdef VA_FOURCC_Y212
    289    MAP(Y212,    Y212),
    290 #endif
    291    // 4:4:0
    292    MAP(422V, YUV440P),
    293    // 4:4:4
    294    MAP(444P, YUV444P),
    295 #ifdef VA_FOURCC_XYUV
    296    MAP(XYUV, VUYX),
    297 #endif
    298 #ifdef VA_FOURCC_Y410
    299    MAP(Y410,    XV30),
    300 #endif
    301 #ifdef VA_FOURCC_Y412
    302    MAP(Y412,    XV36),
    303 #endif
    304    // 4:2:0 10-bit
    305 #ifdef VA_FOURCC_P010
    306    MAP(P010, P010),
    307 #endif
    308 #ifdef VA_FOURCC_P012
    309    MAP(P012, P012),
    310 #endif
    311 #ifdef VA_FOURCC_I010
    312    MAP(I010, YUV420P10),
    313 #endif
    314 #undef MAP
    315 };
    316 
    317 static int vaapi_decode_find_best_format(AVCodecContext *avctx,
    318                                         AVHWDeviceContext *device,
    319                                         VAConfigID config_id,
    320                                         AVHWFramesContext *frames)
    321 {
    322    AVVAAPIDeviceContext *hwctx = device->hwctx;
    323    VAStatus vas;
    324    VASurfaceAttrib *attr;
    325    enum AVPixelFormat source_format, best_format, format;
    326    uint32_t best_fourcc, fourcc;
    327    int i, j, nb_attr;
    328 
    329    source_format = avctx->sw_pix_fmt;
    330    av_assert0(source_format != AV_PIX_FMT_NONE);
    331 
    332    vas = vaQuerySurfaceAttributes(hwctx->display, config_id,
    333                                   NULL, &nb_attr);
    334    if (vas != VA_STATUS_SUCCESS) {
    335        av_log(avctx, AV_LOG_ERROR, "Failed to query surface attributes: "
    336               "%d (%s).\n", vas, vaErrorStr(vas));
    337        return AVERROR(ENOSYS);
    338    }
    339 
    340    attr = av_malloc_array(nb_attr, sizeof(*attr));
    341    if (!attr)
    342        return AVERROR(ENOMEM);
    343 
    344    vas = vaQuerySurfaceAttributes(hwctx->display, config_id,
    345                                   attr, &nb_attr);
    346    if (vas != VA_STATUS_SUCCESS) {
    347        av_log(avctx, AV_LOG_ERROR, "Failed to query surface attributes: "
    348               "%d (%s).\n", vas, vaErrorStr(vas));
    349        av_freep(&attr);
    350        return AVERROR(ENOSYS);
    351    }
    352 
    353    best_format = AV_PIX_FMT_NONE;
    354 
    355    for (i = 0; i < nb_attr; i++) {
    356        if (attr[i].type != VASurfaceAttribPixelFormat)
    357            continue;
    358 
    359        fourcc = attr[i].value.value.i;
    360        for (j = 0; j < FF_ARRAY_ELEMS(vaapi_format_map); j++) {
    361            if (fourcc == vaapi_format_map[j].fourcc)
    362                break;
    363        }
    364        if (j >= FF_ARRAY_ELEMS(vaapi_format_map)) {
    365            av_log(avctx, AV_LOG_DEBUG, "Ignoring unknown format %#x.\n",
    366                   fourcc);
    367            continue;
    368        }
    369        format = vaapi_format_map[j].pix_fmt;
    370        av_log(avctx, AV_LOG_DEBUG, "Considering format %#x -> %s.\n",
    371               fourcc, av_get_pix_fmt_name(format));
    372 
    373        best_format = av_find_best_pix_fmt_of_2(format, best_format,
    374                                                source_format, 0, NULL);
    375        if (format == best_format)
    376            best_fourcc = fourcc;
    377    }
    378 
    379    av_freep(&attr);
    380 
    381    if (best_format == AV_PIX_FMT_NONE) {
    382        av_log(avctx, AV_LOG_ERROR, "No usable formats for decoding!\n");
    383        return AVERROR(EINVAL);
    384    }
    385 
    386    av_log(avctx, AV_LOG_DEBUG, "Picked %s (%#x) as best match for %s.\n",
    387           av_get_pix_fmt_name(best_format), best_fourcc,
    388           av_get_pix_fmt_name(source_format));
    389 
    390    frames->sw_format = best_format;
    391    if (avctx->internal->hwaccel_priv_data) {
    392        VAAPIDecodeContext    *ctx = avctx->internal->hwaccel_priv_data;
    393        AVVAAPIFramesContext *avfc = frames->hwctx;
    394 
    395        ctx->pixel_format_attribute = (VASurfaceAttrib) {
    396            .type          = VASurfaceAttribPixelFormat,
    397            .flags         = VA_SURFACE_ATTRIB_SETTABLE,
    398            .value.type    = VAGenericValueTypeInteger,
    399            .value.value.i = best_fourcc,
    400        };
    401 
    402        avfc->attributes    = &ctx->pixel_format_attribute;
    403        avfc->nb_attributes = 1;
    404    }
    405 
    406    return 0;
    407 }
    408 
    409 static const struct {
    410    enum AVCodecID codec_id;
    411    int codec_profile;
    412    VAProfile va_profile;
    413    VAProfile (*profile_parser)(AVCodecContext *avctx);
    414 } vaapi_profile_map[] = {
    415 #define MAP(c, p, v, ...) { AV_CODEC_ID_ ## c, AV_PROFILE_ ## p, VAProfile ## v, __VA_ARGS__ }
    416    MAP(MPEG2VIDEO,  MPEG2_SIMPLE,    MPEG2Simple ),
    417    MAP(MPEG2VIDEO,  MPEG2_MAIN,      MPEG2Main   ),
    418    MAP(H263,        UNKNOWN,         H263Baseline),
    419    MAP(MPEG4,       MPEG4_SIMPLE,    MPEG4Simple ),
    420    MAP(MPEG4,       MPEG4_ADVANCED_SIMPLE,
    421                               MPEG4AdvancedSimple),
    422    MAP(MPEG4,       MPEG4_MAIN,      MPEG4Main   ),
    423 #if VA_CHECK_VERSION(1, 18, 0)
    424    MAP(H264,        H264_HIGH_10_INTRA,
    425                                      H264High10  ),
    426    MAP(H264,        H264_HIGH_10,    H264High10  ),
    427 #endif
    428    MAP(H264,        H264_CONSTRAINED_BASELINE,
    429                           H264ConstrainedBaseline),
    430    MAP(H264,        H264_MAIN,       H264Main    ),
    431    MAP(H264,        H264_HIGH,       H264High    ),
    432 #if VA_CHECK_VERSION(0, 37, 0)
    433    MAP(HEVC,        HEVC_MAIN,       HEVCMain    ),
    434    MAP(HEVC,        HEVC_MAIN_10,    HEVCMain10  ),
    435    MAP(HEVC,        HEVC_MAIN_STILL_PICTURE,
    436                                      HEVCMain    ),
    437 #endif
    438 #if VA_CHECK_VERSION(1, 2, 0) && CONFIG_HEVC_VAAPI_HWACCEL
    439    MAP(HEVC,        HEVC_REXT,       None,
    440                 ff_vaapi_parse_hevc_rext_scc_profile ),
    441    MAP(HEVC,        HEVC_SCC,        None,
    442                 ff_vaapi_parse_hevc_rext_scc_profile ),
    443 #endif
    444    MAP(MJPEG,       MJPEG_HUFFMAN_BASELINE_DCT,
    445                                      JPEGBaseline),
    446    MAP(WMV3,        VC1_SIMPLE,      VC1Simple   ),
    447    MAP(WMV3,        VC1_MAIN,        VC1Main     ),
    448    MAP(WMV3,        VC1_COMPLEX,     VC1Advanced ),
    449    MAP(WMV3,        VC1_ADVANCED,    VC1Advanced ),
    450    MAP(VC1,         VC1_SIMPLE,      VC1Simple   ),
    451    MAP(VC1,         VC1_MAIN,        VC1Main     ),
    452    MAP(VC1,         VC1_COMPLEX,     VC1Advanced ),
    453    MAP(VC1,         VC1_ADVANCED,    VC1Advanced ),
    454    MAP(VP8,         UNKNOWN,       VP8Version0_3 ),
    455 #if VA_CHECK_VERSION(0, 38, 0)
    456    MAP(VP9,         VP9_0,           VP9Profile0 ),
    457 #endif
    458 #if VA_CHECK_VERSION(0, 39, 0)
    459    MAP(VP9,         VP9_1,           VP9Profile1 ),
    460    MAP(VP9,         VP9_2,           VP9Profile2 ),
    461    MAP(VP9,         VP9_3,           VP9Profile3 ),
    462 #endif
    463 #if VA_CHECK_VERSION(1, 8, 0)
    464    MAP(AV1,         AV1_MAIN,        AV1Profile0),
    465    MAP(AV1,         AV1_HIGH,        AV1Profile1),
    466 #endif
    467 #if VA_CHECK_VERSION(1, 22, 0)
    468    MAP(H266,        VVC_MAIN_10,     VVCMain10),
    469 #endif
    470 
    471 #undef MAP
    472 };
    473 
    474 /*
    475 * Set *va_config and the frames_ref fields from the current codec parameters
    476 * in avctx.
    477 */
    478 static int vaapi_decode_make_config(AVCodecContext *avctx,
    479                                    AVBufferRef *device_ref,
    480                                    VAConfigID *va_config,
    481                                    AVBufferRef *frames_ref)
    482 {
    483    AVVAAPIHWConfig       *hwconfig    = NULL;
    484    AVHWFramesConstraints *constraints = NULL;
    485    VAStatus vas;
    486    int err, i, j;
    487    const AVCodecDescriptor *codec_desc;
    488    VAProfile *profile_list = NULL, matched_va_profile, va_profile;
    489    int profile_count, exact_match, matched_ff_profile, codec_profile;
    490 
    491    AVHWDeviceContext    *device = (AVHWDeviceContext*)device_ref->data;
    492    AVVAAPIDeviceContext *hwctx = device->hwctx;
    493 
    494    codec_desc = avcodec_descriptor_get(avctx->codec_id);
    495    if (!codec_desc) {
    496        err = AVERROR(EINVAL);
    497        goto fail;
    498    }
    499 
    500    profile_count = vaMaxNumProfiles(hwctx->display);
    501    profile_list  = av_malloc_array(profile_count,
    502                                    sizeof(VAProfile));
    503    if (!profile_list) {
    504        err = AVERROR(ENOMEM);
    505        goto fail;
    506    }
    507 
    508    vas = vaQueryConfigProfiles(hwctx->display,
    509                                profile_list, &profile_count);
    510    if (vas != VA_STATUS_SUCCESS) {
    511        av_log(avctx, AV_LOG_ERROR, "Failed to query profiles: "
    512               "%d (%s).\n", vas, vaErrorStr(vas));
    513        err = AVERROR(ENOSYS);
    514        goto fail;
    515    }
    516 
    517    matched_va_profile = VAProfileNone;
    518    exact_match = 0;
    519 
    520    for (i = 0; i < FF_ARRAY_ELEMS(vaapi_profile_map); i++) {
    521        int profile_match = 0;
    522        if (avctx->codec_id != vaapi_profile_map[i].codec_id)
    523            continue;
    524        if (avctx->profile == vaapi_profile_map[i].codec_profile ||
    525            vaapi_profile_map[i].codec_profile == AV_PROFILE_UNKNOWN)
    526            profile_match = 1;
    527 
    528        va_profile = vaapi_profile_map[i].profile_parser ?
    529                     vaapi_profile_map[i].profile_parser(avctx) :
    530                     vaapi_profile_map[i].va_profile;
    531        codec_profile = vaapi_profile_map[i].codec_profile;
    532 
    533        for (j = 0; j < profile_count; j++) {
    534            if (va_profile == profile_list[j]) {
    535                exact_match = profile_match;
    536                break;
    537            }
    538        }
    539        if (j < profile_count) {
    540            matched_va_profile = va_profile;
    541            matched_ff_profile = codec_profile;
    542            if (exact_match)
    543                break;
    544        }
    545    }
    546    av_freep(&profile_list);
    547 
    548    if (matched_va_profile == VAProfileNone) {
    549        av_log(avctx, AV_LOG_ERROR, "No support for codec %s "
    550               "profile %d.\n", codec_desc->name, avctx->profile);
    551        err = AVERROR(ENOSYS);
    552        goto fail;
    553    }
    554    if (!exact_match) {
    555        if (avctx->hwaccel_flags &
    556            AV_HWACCEL_FLAG_ALLOW_PROFILE_MISMATCH) {
    557            av_log(avctx, AV_LOG_VERBOSE, "Codec %s profile %d not "
    558                   "supported for hardware decode.\n",
    559                   codec_desc->name, avctx->profile);
    560            av_log(avctx, AV_LOG_WARNING, "Using possibly-"
    561                   "incompatible profile %d instead.\n",
    562                   matched_ff_profile);
    563        } else {
    564            av_log(avctx, AV_LOG_VERBOSE, "Codec %s profile %d not "
    565                   "supported for hardware decode.\n",
    566                   codec_desc->name, avctx->profile);
    567            err = AVERROR(EINVAL);
    568            goto fail;
    569        }
    570    }
    571 
    572    vas = vaCreateConfig(hwctx->display, matched_va_profile,
    573                         VAEntrypointVLD, NULL, 0,
    574                         va_config);
    575    if (vas != VA_STATUS_SUCCESS) {
    576        av_log(avctx, AV_LOG_ERROR, "Failed to create decode "
    577               "configuration: %d (%s).\n", vas, vaErrorStr(vas));
    578        err = AVERROR(EIO);
    579        goto fail;
    580    }
    581 
    582    hwconfig = av_hwdevice_hwconfig_alloc(device_ref);
    583    if (!hwconfig) {
    584        err = AVERROR(ENOMEM);
    585        goto fail;
    586    }
    587    hwconfig->config_id = *va_config;
    588 
    589    constraints =
    590        av_hwdevice_get_hwframe_constraints(device_ref, hwconfig);
    591    if (!constraints) {
    592        err = AVERROR(ENOMEM);
    593        goto fail;
    594    }
    595 
    596    if (avctx->coded_width  < constraints->min_width  ||
    597        avctx->coded_height < constraints->min_height ||
    598        avctx->coded_width  > constraints->max_width  ||
    599        avctx->coded_height > constraints->max_height) {
    600        av_log(avctx, AV_LOG_ERROR, "Hardware does not support image "
    601               "size %dx%d (constraints: width %d-%d height %d-%d).\n",
    602               avctx->coded_width, avctx->coded_height,
    603               constraints->min_width,  constraints->max_width,
    604               constraints->min_height, constraints->max_height);
    605        err = AVERROR(EINVAL);
    606        goto fail;
    607    }
    608    if (!constraints->valid_sw_formats ||
    609        constraints->valid_sw_formats[0] == AV_PIX_FMT_NONE) {
    610        av_log(avctx, AV_LOG_ERROR, "Hardware does not offer any "
    611               "usable surface formats.\n");
    612        err = AVERROR(EINVAL);
    613        goto fail;
    614    }
    615 
    616    if (frames_ref) {
    617        AVHWFramesContext *frames = (AVHWFramesContext *)frames_ref->data;
    618 
    619        frames->format = AV_PIX_FMT_VAAPI;
    620        frames->width = avctx->coded_width;
    621        frames->height = avctx->coded_height;
    622 
    623        err = vaapi_decode_find_best_format(avctx, device,
    624                                            *va_config, frames);
    625        if (err < 0)
    626            goto fail;
    627 
    628        if (CONFIG_VAAPI_1)
    629            frames->initial_pool_size = 0;
    630        else {
    631            frames->initial_pool_size = 1;
    632            // Add per-codec number of surfaces used for storing reference frames.
    633            switch (avctx->codec_id) {
    634            case AV_CODEC_ID_H264:
    635            case AV_CODEC_ID_H266:
    636            case AV_CODEC_ID_HEVC:
    637            case AV_CODEC_ID_AV1:
    638                frames->initial_pool_size += 16;
    639                break;
    640            case AV_CODEC_ID_VP9:
    641                frames->initial_pool_size += 8;
    642                break;
    643            case AV_CODEC_ID_VP8:
    644                frames->initial_pool_size += 3;
    645                break;
    646            default:
    647                frames->initial_pool_size += 2;
    648            }
    649        }
    650    }
    651 
    652    av_hwframe_constraints_free(&constraints);
    653    av_freep(&hwconfig);
    654 
    655    return 0;
    656 
    657 fail:
    658    av_hwframe_constraints_free(&constraints);
    659    av_freep(&hwconfig);
    660    if (*va_config != VA_INVALID_ID) {
    661        vaDestroyConfig(hwctx->display, *va_config);
    662        *va_config = VA_INVALID_ID;
    663    }
    664    av_freep(&profile_list);
    665    return err;
    666 }
    667 
    668 int ff_vaapi_common_frame_params(AVCodecContext *avctx,
    669                                 AVBufferRef *hw_frames_ctx)
    670 {
    671    AVHWFramesContext *hw_frames = (AVHWFramesContext *)hw_frames_ctx->data;
    672    AVHWDeviceContext *device_ctx = hw_frames->device_ctx;
    673    AVVAAPIDeviceContext *hwctx;
    674    VAConfigID va_config = VA_INVALID_ID;
    675    int err;
    676 
    677    if (device_ctx->type != AV_HWDEVICE_TYPE_VAAPI)
    678        return AVERROR(EINVAL);
    679    hwctx = device_ctx->hwctx;
    680 
    681    err = vaapi_decode_make_config(avctx, hw_frames->device_ref, &va_config,
    682                                   hw_frames_ctx);
    683    if (err)
    684        return err;
    685 
    686    if (va_config != VA_INVALID_ID)
    687        vaDestroyConfig(hwctx->display, va_config);
    688 
    689    return 0;
    690 }
    691 
    692 int ff_vaapi_decode_init(AVCodecContext *avctx)
    693 {
    694    VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data;
    695    VAStatus vas;
    696    int err;
    697 
    698    ctx->va_config  = VA_INVALID_ID;
    699    ctx->va_context = VA_INVALID_ID;
    700 
    701    err = ff_decode_get_hw_frames_ctx(avctx, AV_HWDEVICE_TYPE_VAAPI);
    702    if (err < 0)
    703        goto fail;
    704 
    705    ctx->frames = (AVHWFramesContext*)avctx->hw_frames_ctx->data;
    706    ctx->hwfc   = ctx->frames->hwctx;
    707    ctx->device = ctx->frames->device_ctx;
    708    ctx->hwctx  = ctx->device->hwctx;
    709 
    710    err = vaapi_decode_make_config(avctx, ctx->frames->device_ref,
    711                                   &ctx->va_config, NULL);
    712    if (err)
    713        goto fail;
    714 
    715    vas = vaCreateContext(ctx->hwctx->display, ctx->va_config,
    716                          avctx->coded_width, avctx->coded_height,
    717                          VA_PROGRESSIVE,
    718                          ctx->hwfc->surface_ids,
    719                          ctx->hwfc->nb_surfaces,
    720                          &ctx->va_context);
    721    if (vas != VA_STATUS_SUCCESS) {
    722        av_log(avctx, AV_LOG_ERROR, "Failed to create decode "
    723               "context: %d (%s).\n", vas, vaErrorStr(vas));
    724        err = AVERROR(EIO);
    725        goto fail;
    726    }
    727 
    728    av_log(avctx, AV_LOG_DEBUG, "Decode context initialised: "
    729           "%#x/%#x.\n", ctx->va_config, ctx->va_context);
    730 
    731    return 0;
    732 
    733 fail:
    734    ff_vaapi_decode_uninit(avctx);
    735    return err;
    736 }
    737 
    738 int ff_vaapi_decode_uninit(AVCodecContext *avctx)
    739 {
    740    VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data;
    741    VAStatus vas;
    742 
    743    if (ctx->va_context != VA_INVALID_ID) {
    744        vas = vaDestroyContext(ctx->hwctx->display, ctx->va_context);
    745        if (vas != VA_STATUS_SUCCESS) {
    746            av_log(avctx, AV_LOG_ERROR, "Failed to destroy decode "
    747                   "context %#x: %d (%s).\n",
    748                   ctx->va_context, vas, vaErrorStr(vas));
    749        }
    750    }
    751    if (ctx->va_config != VA_INVALID_ID) {
    752        vas = vaDestroyConfig(ctx->hwctx->display, ctx->va_config);
    753        if (vas != VA_STATUS_SUCCESS) {
    754            av_log(avctx, AV_LOG_ERROR, "Failed to destroy decode "
    755                   "configuration %#x: %d (%s).\n",
    756                   ctx->va_config, vas, vaErrorStr(vas));
    757        }
    758    }
    759 
    760    return 0;
    761 }