tor-browser

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

hwcontext_vaapi.c (71054B)


      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.h"
     20 
     21 #if HAVE_VAAPI_WIN32
     22 #   include <windows.h>
     23 #define COBJMACROS
     24 #   include <initguid.h>
     25 #   include <dxgi1_2.h>
     26 #   include "compat/w32dlfcn.h"
     27 #   include <va/va_win32.h>
     28 typedef HRESULT (WINAPI *PFN_CREATE_DXGI_FACTORY)(REFIID riid, void **ppFactory);
     29 #endif
     30 #if HAVE_VAAPI_X11
     31 #   include <va/va_x11.h>
     32 #endif
     33 #if HAVE_VAAPI_DRM
     34 #   include <va/va_drm.h>
     35 #endif
     36 
     37 #if CONFIG_LIBDRM
     38 #   include <va/va_drmcommon.h>
     39 #   include <xf86drm.h>
     40 #   include <libdrm/drm_fourcc.h>
     41 #   ifndef DRM_FORMAT_MOD_INVALID
     42 #       define DRM_FORMAT_MOD_INVALID ((1ULL << 56) - 1)
     43 #   endif
     44 #endif
     45 
     46 #include <fcntl.h>
     47 #if HAVE_UNISTD_H
     48 #   include <unistd.h>
     49 #endif
     50 
     51 
     52 #include "avassert.h"
     53 #include "buffer.h"
     54 #include "common.h"
     55 #include "hwcontext.h"
     56 #include "hwcontext_drm.h"
     57 #include "hwcontext_internal.h"
     58 #include "hwcontext_vaapi.h"
     59 #include "mem.h"
     60 #include "pixdesc.h"
     61 #include "pixfmt.h"
     62 
     63 
     64 typedef struct VAAPIDevicePriv {
     65 #if HAVE_VAAPI_X11
     66    Display *x11_display;
     67 #endif
     68 
     69    int drm_fd;
     70 } VAAPIDevicePriv;
     71 
     72 typedef struct VAAPISurfaceFormat {
     73    enum AVPixelFormat pix_fmt;
     74    VAImageFormat image_format;
     75 } VAAPISurfaceFormat;
     76 
     77 typedef struct VAAPIDeviceContext {
     78    /**
     79     * The public AVVAAPIDeviceContext. See hwcontext_vaapi.h for it.
     80     */
     81    AVVAAPIDeviceContext p;
     82 
     83    // Surface formats which can be used with this device.
     84    VAAPISurfaceFormat *formats;
     85    int              nb_formats;
     86 } VAAPIDeviceContext;
     87 
     88 typedef struct VAAPIFramesContext {
     89    /**
     90     * The public AVVAAPIFramesContext. See hwcontext_vaapi.h for it.
     91     */
     92    AVVAAPIFramesContext p;
     93 
     94    // Surface attributes set at create time.
     95    VASurfaceAttrib *attributes;
     96    int           nb_attributes;
     97    // RT format of the underlying surface (Intel driver ignores this anyway).
     98    unsigned int rt_format;
     99    // Whether vaDeriveImage works.
    100    int derive_works;
    101    // Caches whether VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2 is unsupported for
    102    // surface imports.
    103    int prime_2_import_unsupported;
    104 } VAAPIFramesContext;
    105 
    106 typedef struct VAAPIMapping {
    107    // Handle to the derived or copied image which is mapped.
    108    VAImage image;
    109    // The mapping flags actually used.
    110    int flags;
    111 } VAAPIMapping;
    112 
    113 typedef struct VAAPIFormat {
    114    unsigned int fourcc;
    115    unsigned int rt_format;
    116    enum AVPixelFormat pix_fmt;
    117    int chroma_planes_swapped;
    118 } VAAPIFormatDescriptor;
    119 
    120 #define MAP(va, rt, av, swap_uv) { \
    121        VA_FOURCC_ ## va, \
    122        VA_RT_FORMAT_ ## rt, \
    123        AV_PIX_FMT_ ## av, \
    124        swap_uv, \
    125    }
    126 // The map fourcc <-> pix_fmt isn't bijective because of the annoying U/V
    127 // plane swap cases.  The frame handling below tries to hide these.
    128 static const VAAPIFormatDescriptor vaapi_format_map[] = {
    129    MAP(NV12, YUV420,  NV12,    0),
    130 #ifdef VA_FOURCC_I420
    131    MAP(I420, YUV420,  YUV420P, 0),
    132 #endif
    133    MAP(YV12, YUV420,  YUV420P, 1),
    134    MAP(IYUV, YUV420,  YUV420P, 0),
    135    MAP(422H, YUV422,  YUV422P, 0),
    136 #ifdef VA_FOURCC_YV16
    137    MAP(YV16, YUV422,  YUV422P, 1),
    138 #endif
    139    MAP(UYVY, YUV422,  UYVY422, 0),
    140    MAP(YUY2, YUV422,  YUYV422, 0),
    141 #ifdef VA_FOURCC_Y210
    142    MAP(Y210, YUV422_10,  Y210, 0),
    143 #endif
    144 #ifdef VA_FOURCC_Y212
    145    MAP(Y212, YUV422_12,  Y212, 0),
    146 #endif
    147    MAP(411P, YUV411,  YUV411P, 0),
    148    MAP(422V, YUV422,  YUV440P, 0),
    149    MAP(444P, YUV444,  YUV444P, 0),
    150 #ifdef VA_FOURCC_XYUV
    151    MAP(XYUV, YUV444,  VUYX,    0),
    152 #endif
    153    MAP(Y800, YUV400,  GRAY8,   0),
    154 #ifdef VA_FOURCC_P010
    155    MAP(P010, YUV420_10BPP, P010, 0),
    156 #endif
    157 #ifdef VA_FOURCC_P012
    158    MAP(P012, YUV420_12, P012, 0),
    159 #endif
    160    MAP(BGRA, RGB32,   BGRA, 0),
    161    MAP(BGRX, RGB32,   BGR0, 0),
    162    MAP(RGBA, RGB32,   RGBA, 0),
    163    MAP(RGBX, RGB32,   RGB0, 0),
    164 #ifdef VA_FOURCC_ABGR
    165    MAP(ABGR, RGB32,   ABGR, 0),
    166    MAP(XBGR, RGB32,   0BGR, 0),
    167 #endif
    168    MAP(ARGB, RGB32,   ARGB, 0),
    169    MAP(XRGB, RGB32,   0RGB, 0),
    170 #ifdef VA_FOURCC_X2R10G10B10
    171    MAP(X2R10G10B10, RGB32_10, X2RGB10, 0),
    172 #endif
    173 #ifdef VA_FOURCC_Y410
    174    // libva doesn't include a fourcc for XV30 and the driver only declares
    175    // support for Y410, so we must fudge the mapping here.
    176    MAP(Y410, YUV444_10,  XV30, 0),
    177 #endif
    178 #ifdef VA_FOURCC_Y412
    179    // libva doesn't include a fourcc for XV36 and the driver only declares
    180    // support for Y412, so we must fudge the mapping here.
    181    MAP(Y412, YUV444_12,  XV36, 0),
    182 #endif
    183 };
    184 #undef MAP
    185 
    186 static const VAAPIFormatDescriptor *
    187    vaapi_format_from_fourcc(unsigned int fourcc)
    188 {
    189    int i;
    190    for (i = 0; i < FF_ARRAY_ELEMS(vaapi_format_map); i++)
    191        if (vaapi_format_map[i].fourcc == fourcc)
    192            return &vaapi_format_map[i];
    193    return NULL;
    194 }
    195 
    196 static const VAAPIFormatDescriptor *
    197    vaapi_format_from_pix_fmt(enum AVPixelFormat pix_fmt)
    198 {
    199    int i;
    200    for (i = 0; i < FF_ARRAY_ELEMS(vaapi_format_map); i++)
    201        if (vaapi_format_map[i].pix_fmt == pix_fmt)
    202            return &vaapi_format_map[i];
    203    return NULL;
    204 }
    205 
    206 static enum AVPixelFormat vaapi_pix_fmt_from_fourcc(unsigned int fourcc)
    207 {
    208    const VAAPIFormatDescriptor *desc;
    209    desc = vaapi_format_from_fourcc(fourcc);
    210    if (desc)
    211        return desc->pix_fmt;
    212    else
    213        return AV_PIX_FMT_NONE;
    214 }
    215 
    216 static int vaapi_get_image_format(AVHWDeviceContext *hwdev,
    217                                  enum AVPixelFormat pix_fmt,
    218                                  VAImageFormat **image_format)
    219 {
    220    VAAPIDeviceContext *ctx = hwdev->hwctx;
    221    int i;
    222 
    223    for (i = 0; i < ctx->nb_formats; i++) {
    224        if (ctx->formats[i].pix_fmt == pix_fmt) {
    225            if (image_format)
    226                *image_format = &ctx->formats[i].image_format;
    227            return 0;
    228        }
    229    }
    230    return AVERROR(ENOSYS);
    231 }
    232 
    233 static int vaapi_frames_get_constraints(AVHWDeviceContext *hwdev,
    234                                        const void *hwconfig,
    235                                        AVHWFramesConstraints *constraints)
    236 {
    237    VAAPIDeviceContext *ctx = hwdev->hwctx;
    238    AVVAAPIDeviceContext *hwctx = &ctx->p;
    239    const AVVAAPIHWConfig *config = hwconfig;
    240    VASurfaceAttrib *attr_list = NULL;
    241    VAStatus vas;
    242    enum AVPixelFormat pix_fmt;
    243    unsigned int fourcc;
    244    int err, i, j, attr_count, pix_fmt_count;
    245 
    246    if (config &&
    247        !(hwctx->driver_quirks & AV_VAAPI_DRIVER_QUIRK_SURFACE_ATTRIBUTES)) {
    248        attr_count = 0;
    249        vas = vaQuerySurfaceAttributes(hwctx->display, config->config_id,
    250                                       0, &attr_count);
    251        if (vas != VA_STATUS_SUCCESS) {
    252            av_log(hwdev, AV_LOG_ERROR, "Failed to query surface attributes: "
    253                   "%d (%s).\n", vas, vaErrorStr(vas));
    254            err = AVERROR(ENOSYS);
    255            goto fail;
    256        }
    257 
    258        attr_list = av_malloc(attr_count * sizeof(*attr_list));
    259        if (!attr_list) {
    260            err = AVERROR(ENOMEM);
    261            goto fail;
    262        }
    263 
    264        vas = vaQuerySurfaceAttributes(hwctx->display, config->config_id,
    265                                       attr_list, &attr_count);
    266        if (vas != VA_STATUS_SUCCESS) {
    267            av_log(hwdev, AV_LOG_ERROR, "Failed to query surface attributes: "
    268                   "%d (%s).\n", vas, vaErrorStr(vas));
    269            err = AVERROR(ENOSYS);
    270            goto fail;
    271        }
    272 
    273        pix_fmt_count = 0;
    274        for (i = 0; i < attr_count; i++) {
    275            switch (attr_list[i].type) {
    276            case VASurfaceAttribPixelFormat:
    277                fourcc = attr_list[i].value.value.i;
    278                pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc);
    279                if (pix_fmt != AV_PIX_FMT_NONE) {
    280                    ++pix_fmt_count;
    281                } else {
    282                    // Something unsupported - ignore.
    283                }
    284                break;
    285            case VASurfaceAttribMinWidth:
    286                constraints->min_width  = attr_list[i].value.value.i;
    287                break;
    288            case VASurfaceAttribMinHeight:
    289                constraints->min_height = attr_list[i].value.value.i;
    290                break;
    291            case VASurfaceAttribMaxWidth:
    292                constraints->max_width  = attr_list[i].value.value.i;
    293                break;
    294            case VASurfaceAttribMaxHeight:
    295                constraints->max_height = attr_list[i].value.value.i;
    296                break;
    297            }
    298        }
    299        if (pix_fmt_count == 0) {
    300            // Nothing usable found.  Presumably there exists something which
    301            // works, so leave the set null to indicate unknown.
    302            constraints->valid_sw_formats = NULL;
    303        } else {
    304            constraints->valid_sw_formats = av_malloc_array(pix_fmt_count + 1,
    305                                                            sizeof(pix_fmt));
    306            if (!constraints->valid_sw_formats) {
    307                err = AVERROR(ENOMEM);
    308                goto fail;
    309            }
    310 
    311            for (i = j = 0; i < attr_count; i++) {
    312                int k;
    313 
    314                if (attr_list[i].type != VASurfaceAttribPixelFormat)
    315                    continue;
    316                fourcc = attr_list[i].value.value.i;
    317                pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc);
    318 
    319                if (pix_fmt == AV_PIX_FMT_NONE)
    320                    continue;
    321 
    322                for (k = 0; k < j; k++) {
    323                    if (constraints->valid_sw_formats[k] == pix_fmt)
    324                        break;
    325                }
    326 
    327                if (k == j)
    328                    constraints->valid_sw_formats[j++] = pix_fmt;
    329            }
    330            constraints->valid_sw_formats[j] = AV_PIX_FMT_NONE;
    331        }
    332    } else {
    333        // No configuration supplied.
    334        // Return the full set of image formats known by the implementation.
    335        constraints->valid_sw_formats = av_malloc_array(ctx->nb_formats + 1,
    336                                                        sizeof(pix_fmt));
    337        if (!constraints->valid_sw_formats) {
    338            err = AVERROR(ENOMEM);
    339            goto fail;
    340        }
    341        for (i = j = 0; i < ctx->nb_formats; i++) {
    342            int k;
    343 
    344            for (k = 0; k < j; k++) {
    345                if (constraints->valid_sw_formats[k] == ctx->formats[i].pix_fmt)
    346                    break;
    347            }
    348 
    349            if (k == j)
    350                constraints->valid_sw_formats[j++] = ctx->formats[i].pix_fmt;
    351        }
    352 
    353        constraints->valid_sw_formats[j] = AV_PIX_FMT_NONE;
    354    }
    355 
    356    constraints->valid_hw_formats = av_malloc_array(2, sizeof(pix_fmt));
    357    if (!constraints->valid_hw_formats) {
    358        err = AVERROR(ENOMEM);
    359        goto fail;
    360    }
    361    constraints->valid_hw_formats[0] = AV_PIX_FMT_VAAPI;
    362    constraints->valid_hw_formats[1] = AV_PIX_FMT_NONE;
    363 
    364    err = 0;
    365 fail:
    366    av_freep(&attr_list);
    367    return err;
    368 }
    369 
    370 static const struct {
    371    const char *friendly_name;
    372    const char *match_string;
    373    unsigned int quirks;
    374 } vaapi_driver_quirks_table[] = {
    375 #if !VA_CHECK_VERSION(1, 0, 0)
    376    // The i965 driver did not conform before version 2.0.
    377    {
    378        "Intel i965 (Quick Sync)",
    379        "i965",
    380        AV_VAAPI_DRIVER_QUIRK_RENDER_PARAM_BUFFERS,
    381    },
    382 #endif
    383    {
    384        "Intel iHD",
    385        "ubit",
    386        AV_VAAPI_DRIVER_QUIRK_ATTRIB_MEMTYPE,
    387    },
    388    {
    389        "VDPAU wrapper",
    390        "Splitted-Desktop Systems VDPAU backend for VA-API",
    391        AV_VAAPI_DRIVER_QUIRK_SURFACE_ATTRIBUTES,
    392    },
    393 };
    394 
    395 static int vaapi_device_init(AVHWDeviceContext *hwdev)
    396 {
    397    VAAPIDeviceContext *ctx = hwdev->hwctx;
    398    AVVAAPIDeviceContext *hwctx = &ctx->p;
    399    VAImageFormat *image_list = NULL;
    400    VAStatus vas;
    401    const char *vendor_string;
    402    int err, i, image_count;
    403    enum AVPixelFormat pix_fmt;
    404    unsigned int fourcc;
    405 
    406    image_count = vaMaxNumImageFormats(hwctx->display);
    407    if (image_count <= 0) {
    408        err = AVERROR(EIO);
    409        goto fail;
    410    }
    411    image_list = av_malloc(image_count * sizeof(*image_list));
    412    if (!image_list) {
    413        err = AVERROR(ENOMEM);
    414        goto fail;
    415    }
    416    vas = vaQueryImageFormats(hwctx->display, image_list, &image_count);
    417    if (vas != VA_STATUS_SUCCESS) {
    418        err = AVERROR(EIO);
    419        goto fail;
    420    }
    421 
    422    ctx->formats  = av_malloc(image_count * sizeof(*ctx->formats));
    423    if (!ctx->formats) {
    424        err = AVERROR(ENOMEM);
    425        goto fail;
    426    }
    427    ctx->nb_formats = 0;
    428    for (i = 0; i < image_count; i++) {
    429        fourcc  = image_list[i].fourcc;
    430        pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc);
    431        if (pix_fmt == AV_PIX_FMT_NONE) {
    432            av_log(hwdev, AV_LOG_DEBUG, "Format %#x -> unknown.\n",
    433                   fourcc);
    434        } else {
    435            av_log(hwdev, AV_LOG_DEBUG, "Format %#x -> %s.\n",
    436                   fourcc, av_get_pix_fmt_name(pix_fmt));
    437            ctx->formats[ctx->nb_formats].pix_fmt      = pix_fmt;
    438            ctx->formats[ctx->nb_formats].image_format = image_list[i];
    439            ++ctx->nb_formats;
    440        }
    441    }
    442 
    443    vendor_string = vaQueryVendorString(hwctx->display);
    444    if (vendor_string)
    445        av_log(hwdev, AV_LOG_VERBOSE, "VAAPI driver: %s.\n", vendor_string);
    446 
    447    if (hwctx->driver_quirks & AV_VAAPI_DRIVER_QUIRK_USER_SET) {
    448        av_log(hwdev, AV_LOG_VERBOSE, "Using quirks set by user (%#x).\n",
    449               hwctx->driver_quirks);
    450    } else {
    451        // Detect the driver in use and set quirk flags if necessary.
    452        hwctx->driver_quirks = 0;
    453        if (vendor_string) {
    454            for (i = 0; i < FF_ARRAY_ELEMS(vaapi_driver_quirks_table); i++) {
    455                if (strstr(vendor_string,
    456                           vaapi_driver_quirks_table[i].match_string)) {
    457                    av_log(hwdev, AV_LOG_VERBOSE, "Matched driver string "
    458                           "as known nonstandard driver \"%s\", setting "
    459                           "quirks (%#x).\n",
    460                           vaapi_driver_quirks_table[i].friendly_name,
    461                           vaapi_driver_quirks_table[i].quirks);
    462                    hwctx->driver_quirks |=
    463                        vaapi_driver_quirks_table[i].quirks;
    464                    break;
    465                }
    466            }
    467            if (!(i < FF_ARRAY_ELEMS(vaapi_driver_quirks_table))) {
    468                av_log(hwdev, AV_LOG_VERBOSE, "Driver not found in known "
    469                       "nonstandard list, using standard behaviour.\n");
    470            }
    471        } else {
    472            av_log(hwdev, AV_LOG_VERBOSE, "Driver has no vendor string, "
    473                   "assuming standard behaviour.\n");
    474        }
    475    }
    476 
    477    av_free(image_list);
    478    return 0;
    479 fail:
    480    av_freep(&ctx->formats);
    481    av_free(image_list);
    482    return err;
    483 }
    484 
    485 static void vaapi_device_uninit(AVHWDeviceContext *hwdev)
    486 {
    487    VAAPIDeviceContext *ctx = hwdev->hwctx;
    488 
    489    av_freep(&ctx->formats);
    490 }
    491 
    492 static void vaapi_buffer_free(void *opaque, uint8_t *data)
    493 {
    494    AVHWFramesContext     *hwfc = opaque;
    495    AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
    496    VASurfaceID surface_id;
    497    VAStatus vas;
    498 
    499    surface_id = (VASurfaceID)(uintptr_t)data;
    500 
    501    vas = vaDestroySurfaces(hwctx->display, &surface_id, 1);
    502    if (vas != VA_STATUS_SUCCESS) {
    503        av_log(hwfc, AV_LOG_ERROR, "Failed to destroy surface %#x: "
    504               "%d (%s).\n", surface_id, vas, vaErrorStr(vas));
    505    }
    506 }
    507 
    508 static AVBufferRef *vaapi_pool_alloc(void *opaque, size_t size)
    509 {
    510    AVHWFramesContext     *hwfc = opaque;
    511    VAAPIFramesContext     *ctx = hwfc->hwctx;
    512    AVVAAPIFramesContext  *avfc = &ctx->p;
    513    AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
    514    VASurfaceID surface_id;
    515    VAStatus vas;
    516    AVBufferRef *ref;
    517 
    518    if (hwfc->initial_pool_size > 0 &&
    519        avfc->nb_surfaces >= hwfc->initial_pool_size)
    520        return NULL;
    521 
    522    vas = vaCreateSurfaces(hwctx->display, ctx->rt_format,
    523                           hwfc->width, hwfc->height,
    524                           &surface_id, 1,
    525                           ctx->attributes, ctx->nb_attributes);
    526    if (vas != VA_STATUS_SUCCESS) {
    527        av_log(hwfc, AV_LOG_ERROR, "Failed to create surface: "
    528               "%d (%s).\n", vas, vaErrorStr(vas));
    529        return NULL;
    530    }
    531    av_log(hwfc, AV_LOG_DEBUG, "Created surface %#x.\n", surface_id);
    532 
    533    ref = av_buffer_create((uint8_t*)(uintptr_t)surface_id,
    534                           sizeof(surface_id), &vaapi_buffer_free,
    535                           hwfc, AV_BUFFER_FLAG_READONLY);
    536    if (!ref) {
    537        vaDestroySurfaces(hwctx->display, &surface_id, 1);
    538        return NULL;
    539    }
    540 
    541    if (hwfc->initial_pool_size > 0) {
    542        // This is a fixed-size pool, so we must still be in the initial
    543        // allocation sequence.
    544        av_assert0(avfc->nb_surfaces < hwfc->initial_pool_size);
    545        avfc->surface_ids[avfc->nb_surfaces] = surface_id;
    546        ++avfc->nb_surfaces;
    547    }
    548 
    549    return ref;
    550 }
    551 
    552 static int vaapi_frames_init(AVHWFramesContext *hwfc)
    553 {
    554    VAAPIFramesContext     *ctx = hwfc->hwctx;
    555    AVVAAPIFramesContext  *avfc = &ctx->p;
    556    AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
    557    const VAAPIFormatDescriptor *desc;
    558    VAImageFormat *expected_format;
    559    AVBufferRef *test_surface = NULL;
    560    VASurfaceID test_surface_id;
    561    VAImage test_image;
    562    VAStatus vas;
    563    int err, i;
    564 
    565    desc = vaapi_format_from_pix_fmt(hwfc->sw_format);
    566    if (!desc) {
    567        av_log(hwfc, AV_LOG_ERROR, "Unsupported format: %s.\n",
    568               av_get_pix_fmt_name(hwfc->sw_format));
    569        return AVERROR(EINVAL);
    570    }
    571 
    572    if (!hwfc->pool) {
    573        if (!(hwctx->driver_quirks & AV_VAAPI_DRIVER_QUIRK_SURFACE_ATTRIBUTES)) {
    574            int need_memory_type = !(hwctx->driver_quirks & AV_VAAPI_DRIVER_QUIRK_ATTRIB_MEMTYPE);
    575            int need_pixel_format = 1;
    576            for (i = 0; i < avfc->nb_attributes; i++) {
    577                if (avfc->attributes[i].type == VASurfaceAttribMemoryType)
    578                    need_memory_type  = 0;
    579                if (avfc->attributes[i].type == VASurfaceAttribPixelFormat)
    580                    need_pixel_format = 0;
    581            }
    582            ctx->nb_attributes =
    583                avfc->nb_attributes + need_memory_type + need_pixel_format;
    584 
    585            ctx->attributes = av_malloc(ctx->nb_attributes *
    586                                        sizeof(*ctx->attributes));
    587            if (!ctx->attributes) {
    588                err = AVERROR(ENOMEM);
    589                goto fail;
    590            }
    591 
    592            for (i = 0; i < avfc->nb_attributes; i++)
    593                ctx->attributes[i] = avfc->attributes[i];
    594            if (need_memory_type) {
    595                ctx->attributes[i++] = (VASurfaceAttrib) {
    596                    .type          = VASurfaceAttribMemoryType,
    597                    .flags         = VA_SURFACE_ATTRIB_SETTABLE,
    598                    .value.type    = VAGenericValueTypeInteger,
    599                    .value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_VA,
    600                };
    601            }
    602            if (need_pixel_format) {
    603                ctx->attributes[i++] = (VASurfaceAttrib) {
    604                    .type          = VASurfaceAttribPixelFormat,
    605                    .flags         = VA_SURFACE_ATTRIB_SETTABLE,
    606                    .value.type    = VAGenericValueTypeInteger,
    607                    .value.value.i = desc->fourcc,
    608                };
    609            }
    610            av_assert0(i == ctx->nb_attributes);
    611        } else {
    612            ctx->attributes = NULL;
    613            ctx->nb_attributes = 0;
    614        }
    615 
    616        ctx->rt_format = desc->rt_format;
    617 
    618        if (hwfc->initial_pool_size > 0) {
    619            // This pool will be usable as a render target, so we need to store
    620            // all of the surface IDs somewhere that vaCreateContext() calls
    621            // will be able to access them.
    622            avfc->nb_surfaces = 0;
    623            avfc->surface_ids = av_malloc(hwfc->initial_pool_size *
    624                                          sizeof(*avfc->surface_ids));
    625            if (!avfc->surface_ids) {
    626                err = AVERROR(ENOMEM);
    627                goto fail;
    628            }
    629        } else {
    630            // This pool allows dynamic sizing, and will not be usable as a
    631            // render target.
    632            avfc->nb_surfaces = 0;
    633            avfc->surface_ids = NULL;
    634        }
    635 
    636        ffhwframesctx(hwfc)->pool_internal =
    637            av_buffer_pool_init2(sizeof(VASurfaceID), hwfc,
    638                                 &vaapi_pool_alloc, NULL);
    639        if (!ffhwframesctx(hwfc)->pool_internal) {
    640            av_log(hwfc, AV_LOG_ERROR, "Failed to create VAAPI surface pool.\n");
    641            err = AVERROR(ENOMEM);
    642            goto fail;
    643        }
    644    }
    645 
    646    // Allocate a single surface to test whether vaDeriveImage() is going
    647    // to work for the specific configuration.
    648    if (hwfc->pool) {
    649        test_surface = av_buffer_pool_get(hwfc->pool);
    650        if (!test_surface) {
    651            av_log(hwfc, AV_LOG_ERROR, "Unable to allocate a surface from "
    652                   "user-configured buffer pool.\n");
    653            err = AVERROR(ENOMEM);
    654            goto fail;
    655        }
    656    } else {
    657        test_surface = av_buffer_pool_get(ffhwframesctx(hwfc)->pool_internal);
    658        if (!test_surface) {
    659            av_log(hwfc, AV_LOG_ERROR, "Unable to allocate a surface from "
    660                   "internal buffer pool.\n");
    661            err = AVERROR(ENOMEM);
    662            goto fail;
    663        }
    664    }
    665    test_surface_id = (VASurfaceID)(uintptr_t)test_surface->data;
    666 
    667    ctx->derive_works = 0;
    668 
    669    err = vaapi_get_image_format(hwfc->device_ctx,
    670                                 hwfc->sw_format, &expected_format);
    671    if (err == 0) {
    672        vas = vaDeriveImage(hwctx->display, test_surface_id, &test_image);
    673        if (vas == VA_STATUS_SUCCESS) {
    674            if (expected_format->fourcc == test_image.format.fourcc) {
    675                av_log(hwfc, AV_LOG_DEBUG, "Direct mapping possible.\n");
    676                ctx->derive_works = 1;
    677            } else {
    678                av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: "
    679                       "derived image format %08x does not match "
    680                       "expected format %08x.\n",
    681                       expected_format->fourcc, test_image.format.fourcc);
    682            }
    683            vaDestroyImage(hwctx->display, test_image.image_id);
    684        } else {
    685            av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: "
    686                   "deriving image does not work: "
    687                   "%d (%s).\n", vas, vaErrorStr(vas));
    688        }
    689    } else {
    690        av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: "
    691               "image format is not supported.\n");
    692    }
    693 
    694    av_buffer_unref(&test_surface);
    695    return 0;
    696 
    697 fail:
    698    av_buffer_unref(&test_surface);
    699    av_freep(&avfc->surface_ids);
    700    av_freep(&ctx->attributes);
    701    return err;
    702 }
    703 
    704 static void vaapi_frames_uninit(AVHWFramesContext *hwfc)
    705 {
    706    VAAPIFramesContext    *ctx = hwfc->hwctx;
    707    AVVAAPIFramesContext *avfc = &ctx->p;
    708 
    709    av_freep(&avfc->surface_ids);
    710    av_freep(&ctx->attributes);
    711 }
    712 
    713 static int vaapi_get_buffer(AVHWFramesContext *hwfc, AVFrame *frame)
    714 {
    715    frame->buf[0] = av_buffer_pool_get(hwfc->pool);
    716    if (!frame->buf[0])
    717        return AVERROR(ENOMEM);
    718 
    719    frame->data[3] = frame->buf[0]->data;
    720    frame->format  = AV_PIX_FMT_VAAPI;
    721    frame->width   = hwfc->width;
    722    frame->height  = hwfc->height;
    723 
    724    return 0;
    725 }
    726 
    727 static int vaapi_transfer_get_formats(AVHWFramesContext *hwfc,
    728                                      enum AVHWFrameTransferDirection dir,
    729                                      enum AVPixelFormat **formats)
    730 {
    731    VAAPIDeviceContext *ctx = hwfc->device_ctx->hwctx;
    732    enum AVPixelFormat *pix_fmts;
    733    int i, k, sw_format_available;
    734 
    735    sw_format_available = 0;
    736    for (i = 0; i < ctx->nb_formats; i++) {
    737        if (ctx->formats[i].pix_fmt == hwfc->sw_format)
    738            sw_format_available = 1;
    739    }
    740 
    741    pix_fmts = av_malloc((ctx->nb_formats + 1) * sizeof(*pix_fmts));
    742    if (!pix_fmts)
    743        return AVERROR(ENOMEM);
    744 
    745    if (sw_format_available) {
    746        pix_fmts[0] = hwfc->sw_format;
    747        k = 1;
    748    } else {
    749        k = 0;
    750    }
    751    for (i = 0; i < ctx->nb_formats; i++) {
    752        if (ctx->formats[i].pix_fmt == hwfc->sw_format)
    753            continue;
    754        av_assert0(k < ctx->nb_formats);
    755        pix_fmts[k++] = ctx->formats[i].pix_fmt;
    756    }
    757    pix_fmts[k] = AV_PIX_FMT_NONE;
    758 
    759    *formats = pix_fmts;
    760    return 0;
    761 }
    762 
    763 static void vaapi_unmap_frame(AVHWFramesContext *hwfc,
    764                              HWMapDescriptor *hwmap)
    765 {
    766    AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
    767    VAAPIMapping           *map = hwmap->priv;
    768    VASurfaceID surface_id;
    769    VAStatus vas;
    770 
    771    surface_id = (VASurfaceID)(uintptr_t)hwmap->source->data[3];
    772    av_log(hwfc, AV_LOG_DEBUG, "Unmap surface %#x.\n", surface_id);
    773 
    774    vas = vaUnmapBuffer(hwctx->display, map->image.buf);
    775    if (vas != VA_STATUS_SUCCESS) {
    776        av_log(hwfc, AV_LOG_ERROR, "Failed to unmap image from surface "
    777               "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
    778    }
    779 
    780    if ((map->flags & AV_HWFRAME_MAP_WRITE) &&
    781        !(map->flags & AV_HWFRAME_MAP_DIRECT)) {
    782        vas = vaPutImage(hwctx->display, surface_id, map->image.image_id,
    783                         0, 0, hwfc->width, hwfc->height,
    784                         0, 0, hwfc->width, hwfc->height);
    785        if (vas != VA_STATUS_SUCCESS) {
    786            av_log(hwfc, AV_LOG_ERROR, "Failed to write image to surface "
    787                   "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
    788        }
    789    }
    790 
    791    vas = vaDestroyImage(hwctx->display, map->image.image_id);
    792    if (vas != VA_STATUS_SUCCESS) {
    793        av_log(hwfc, AV_LOG_ERROR, "Failed to destroy image from surface "
    794               "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
    795    }
    796 
    797    av_free(map);
    798 }
    799 
    800 static int vaapi_map_frame(AVHWFramesContext *hwfc,
    801                           AVFrame *dst, const AVFrame *src, int flags)
    802 {
    803    AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
    804    VAAPIFramesContext *ctx = hwfc->hwctx;
    805    VASurfaceID surface_id;
    806    const VAAPIFormatDescriptor *desc;
    807    VAImageFormat *image_format;
    808    VAAPIMapping *map;
    809    VAStatus vas;
    810    void *address = NULL;
    811    int err, i;
    812 #if VA_CHECK_VERSION(1, 21, 0)
    813    uint32_t vaflags = 0;
    814 #endif
    815 
    816    surface_id = (VASurfaceID)(uintptr_t)src->data[3];
    817    av_log(hwfc, AV_LOG_DEBUG, "Map surface %#x.\n", surface_id);
    818 
    819    if (!ctx->derive_works && (flags & AV_HWFRAME_MAP_DIRECT)) {
    820        // Requested direct mapping but it is not possible.
    821        return AVERROR(EINVAL);
    822    }
    823    if (dst->format == AV_PIX_FMT_NONE)
    824        dst->format = hwfc->sw_format;
    825    if (dst->format != hwfc->sw_format && (flags & AV_HWFRAME_MAP_DIRECT)) {
    826        // Requested direct mapping but the formats do not match.
    827        return AVERROR(EINVAL);
    828    }
    829 
    830    err = vaapi_get_image_format(hwfc->device_ctx, dst->format, &image_format);
    831    if (err < 0) {
    832        // Requested format is not a valid output format.
    833        return err;
    834    }
    835 
    836    map = av_malloc(sizeof(*map));
    837    if (!map)
    838        return AVERROR(ENOMEM);
    839    map->flags = flags;
    840    map->image.image_id = VA_INVALID_ID;
    841 
    842    vas = vaSyncSurface(hwctx->display, surface_id);
    843    if (vas != VA_STATUS_SUCCESS) {
    844        av_log(hwfc, AV_LOG_ERROR, "Failed to sync surface "
    845               "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
    846        err = AVERROR(EIO);
    847        goto fail;
    848    }
    849 
    850    // The memory which we map using derive need not be connected to the CPU
    851    // in a way conducive to fast access.  On Gen7-Gen9 Intel graphics, the
    852    // memory is mappable but not cached, so normal memcpy()-like access is
    853    // very slow to read it (but writing is ok).  It is possible to read much
    854    // faster with a copy routine which is aware of the limitation, but we
    855    // assume for now that the user is not aware of that and would therefore
    856    // prefer not to be given direct-mapped memory if they request read access.
    857    if (ctx->derive_works && dst->format == hwfc->sw_format &&
    858        ((flags & AV_HWFRAME_MAP_DIRECT) || !(flags & AV_HWFRAME_MAP_READ))) {
    859        vas = vaDeriveImage(hwctx->display, surface_id, &map->image);
    860        if (vas != VA_STATUS_SUCCESS) {
    861            av_log(hwfc, AV_LOG_ERROR, "Failed to derive image from "
    862                   "surface %#x: %d (%s).\n",
    863                   surface_id, vas, vaErrorStr(vas));
    864            err = AVERROR(EIO);
    865            goto fail;
    866        }
    867        if (map->image.format.fourcc != image_format->fourcc) {
    868            av_log(hwfc, AV_LOG_ERROR, "Derive image of surface %#x "
    869                   "is in wrong format: expected %#08x, got %#08x.\n",
    870                   surface_id, image_format->fourcc, map->image.format.fourcc);
    871            err = AVERROR(EIO);
    872            goto fail;
    873        }
    874        map->flags |= AV_HWFRAME_MAP_DIRECT;
    875    } else {
    876        vas = vaCreateImage(hwctx->display, image_format,
    877                            hwfc->width, hwfc->height, &map->image);
    878        if (vas != VA_STATUS_SUCCESS) {
    879            av_log(hwfc, AV_LOG_ERROR, "Failed to create image for "
    880                   "surface %#x: %d (%s).\n",
    881                   surface_id, vas, vaErrorStr(vas));
    882            err = AVERROR(EIO);
    883            goto fail;
    884        }
    885        if (!(flags & AV_HWFRAME_MAP_OVERWRITE)) {
    886            vas = vaGetImage(hwctx->display, surface_id, 0, 0,
    887                             hwfc->width, hwfc->height, map->image.image_id);
    888            if (vas != VA_STATUS_SUCCESS) {
    889                av_log(hwfc, AV_LOG_ERROR, "Failed to read image from "
    890                       "surface %#x: %d (%s).\n",
    891                       surface_id, vas, vaErrorStr(vas));
    892                err = AVERROR(EIO);
    893                goto fail;
    894            }
    895        }
    896    }
    897 
    898 #if VA_CHECK_VERSION(1, 21, 0)
    899    if (flags & AV_HWFRAME_MAP_READ)
    900        vaflags |= VA_MAPBUFFER_FLAG_READ;
    901    if (flags & AV_HWFRAME_MAP_WRITE)
    902        vaflags |= VA_MAPBUFFER_FLAG_WRITE;
    903    // On drivers not implementing vaMapBuffer2 libva calls vaMapBuffer instead.
    904    vas = vaMapBuffer2(hwctx->display, map->image.buf, &address, vaflags);
    905 #else
    906    vas = vaMapBuffer(hwctx->display, map->image.buf, &address);
    907 #endif
    908    if (vas != VA_STATUS_SUCCESS) {
    909        av_log(hwfc, AV_LOG_ERROR, "Failed to map image from surface "
    910               "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
    911        err = AVERROR(EIO);
    912        goto fail;
    913    }
    914 
    915    err = ff_hwframe_map_create(src->hw_frames_ctx,
    916                                dst, src, &vaapi_unmap_frame, map);
    917    if (err < 0)
    918        goto fail;
    919 
    920    dst->width  = src->width;
    921    dst->height = src->height;
    922 
    923    for (i = 0; i < map->image.num_planes; i++) {
    924        dst->data[i] = (uint8_t*)address + map->image.offsets[i];
    925        dst->linesize[i] = map->image.pitches[i];
    926    }
    927 
    928    desc = vaapi_format_from_fourcc(map->image.format.fourcc);
    929    if (desc && desc->chroma_planes_swapped) {
    930        // Chroma planes are YVU rather than YUV, so swap them.
    931        FFSWAP(uint8_t*, dst->data[1], dst->data[2]);
    932    }
    933 
    934    return 0;
    935 
    936 fail:
    937    if (map) {
    938        if (address)
    939            vaUnmapBuffer(hwctx->display, map->image.buf);
    940        if (map->image.image_id != VA_INVALID_ID)
    941            vaDestroyImage(hwctx->display, map->image.image_id);
    942        av_free(map);
    943    }
    944    return err;
    945 }
    946 
    947 static int vaapi_transfer_data_from(AVHWFramesContext *hwfc,
    948                                    AVFrame *dst, const AVFrame *src)
    949 {
    950    AVFrame *map;
    951    int err;
    952 
    953    if (dst->width > hwfc->width || dst->height > hwfc->height)
    954        return AVERROR(EINVAL);
    955 
    956    map = av_frame_alloc();
    957    if (!map)
    958        return AVERROR(ENOMEM);
    959    map->format = dst->format;
    960 
    961    err = vaapi_map_frame(hwfc, map, src, AV_HWFRAME_MAP_READ);
    962    if (err)
    963        goto fail;
    964 
    965    map->width  = dst->width;
    966    map->height = dst->height;
    967 
    968    err = av_frame_copy(dst, map);
    969    if (err)
    970        goto fail;
    971 
    972    err = 0;
    973 fail:
    974    av_frame_free(&map);
    975    return err;
    976 }
    977 
    978 static int vaapi_transfer_data_to(AVHWFramesContext *hwfc,
    979                                  AVFrame *dst, const AVFrame *src)
    980 {
    981    AVFrame *map;
    982    int err;
    983 
    984    if (src->width > hwfc->width || src->height > hwfc->height)
    985        return AVERROR(EINVAL);
    986 
    987    map = av_frame_alloc();
    988    if (!map)
    989        return AVERROR(ENOMEM);
    990    map->format = src->format;
    991 
    992    err = vaapi_map_frame(hwfc, map, dst, AV_HWFRAME_MAP_WRITE | AV_HWFRAME_MAP_OVERWRITE);
    993    if (err)
    994        goto fail;
    995 
    996    map->width  = src->width;
    997    map->height = src->height;
    998 
    999    err = av_frame_copy(map, src);
   1000    if (err)
   1001        goto fail;
   1002 
   1003    err = 0;
   1004 fail:
   1005    av_frame_free(&map);
   1006    return err;
   1007 }
   1008 
   1009 static int vaapi_map_to_memory(AVHWFramesContext *hwfc, AVFrame *dst,
   1010                               const AVFrame *src, int flags)
   1011 {
   1012    int err;
   1013 
   1014    if (dst->format != AV_PIX_FMT_NONE) {
   1015        err = vaapi_get_image_format(hwfc->device_ctx, dst->format, NULL);
   1016        if (err < 0)
   1017            return err;
   1018    }
   1019 
   1020    err = vaapi_map_frame(hwfc, dst, src, flags);
   1021    if (err)
   1022        return err;
   1023 
   1024    err = av_frame_copy_props(dst, src);
   1025    if (err)
   1026        return err;
   1027 
   1028    return 0;
   1029 }
   1030 
   1031 #if CONFIG_LIBDRM
   1032 
   1033 #define DRM_MAP(va, layers, ...) { \
   1034        VA_FOURCC_ ## va, \
   1035        layers, \
   1036        { __VA_ARGS__ } \
   1037    }
   1038 static const struct {
   1039    uint32_t va_fourcc;
   1040    int   nb_layer_formats;
   1041    uint32_t layer_formats[AV_DRM_MAX_PLANES];
   1042 } vaapi_drm_format_map[] = {
   1043 #ifdef DRM_FORMAT_R8
   1044    DRM_MAP(NV12, 2, DRM_FORMAT_R8,  DRM_FORMAT_RG88),
   1045    DRM_MAP(NV12, 2, DRM_FORMAT_R8,  DRM_FORMAT_GR88),
   1046 #endif
   1047    DRM_MAP(NV12, 1, DRM_FORMAT_NV12),
   1048 #if defined(VA_FOURCC_P010) && defined(DRM_FORMAT_R16)
   1049    DRM_MAP(P010, 2, DRM_FORMAT_R16, DRM_FORMAT_RG1616),
   1050 #endif
   1051 #if defined(VA_FOURCC_P012) && defined(DRM_FORMAT_R16)
   1052    DRM_MAP(P012, 2, DRM_FORMAT_R16, DRM_FORMAT_RG1616),
   1053 #endif
   1054    DRM_MAP(BGRA, 1, DRM_FORMAT_ARGB8888),
   1055    DRM_MAP(BGRX, 1, DRM_FORMAT_XRGB8888),
   1056    DRM_MAP(RGBA, 1, DRM_FORMAT_ABGR8888),
   1057    DRM_MAP(RGBX, 1, DRM_FORMAT_XBGR8888),
   1058 #ifdef VA_FOURCC_ABGR
   1059    DRM_MAP(ABGR, 1, DRM_FORMAT_RGBA8888),
   1060    DRM_MAP(XBGR, 1, DRM_FORMAT_RGBX8888),
   1061 #endif
   1062    DRM_MAP(ARGB, 1, DRM_FORMAT_BGRA8888),
   1063    DRM_MAP(XRGB, 1, DRM_FORMAT_BGRX8888),
   1064 #if defined(VA_FOURCC_XYUV) && defined(DRM_FORMAT_XYUV8888)
   1065    DRM_MAP(XYUV, 1, DRM_FORMAT_XYUV8888),
   1066 #endif
   1067 #if defined(VA_FOURCC_Y412) && defined(DRM_FORMAT_XVYU2101010)
   1068    DRM_MAP(Y410, 1, DRM_FORMAT_XVYU2101010),
   1069 #endif
   1070 #if defined(VA_FOURCC_Y412) && defined(DRM_FORMAT_XVYU12_16161616)
   1071    DRM_MAP(Y412, 1, DRM_FORMAT_XVYU12_16161616),
   1072 #endif
   1073 #if defined(VA_FOURCC_X2R10G10B10) && defined(DRM_FORMAT_XRGB2101010)
   1074    DRM_MAP(X2R10G10B10, 1, DRM_FORMAT_XRGB2101010),
   1075 #endif
   1076 };
   1077 #undef DRM_MAP
   1078 
   1079 static void vaapi_unmap_from_drm(AVHWFramesContext *dst_fc,
   1080                                 HWMapDescriptor *hwmap)
   1081 {
   1082    AVVAAPIDeviceContext *dst_dev = dst_fc->device_ctx->hwctx;
   1083 
   1084    VASurfaceID surface_id = (VASurfaceID)(uintptr_t)hwmap->priv;
   1085 
   1086    av_log(dst_fc, AV_LOG_DEBUG, "Destroy surface %#x.\n", surface_id);
   1087 
   1088    vaDestroySurfaces(dst_dev->display, &surface_id, 1);
   1089 }
   1090 
   1091 static int vaapi_map_from_drm(AVHWFramesContext *src_fc, AVFrame *dst,
   1092                              const AVFrame *src, int flags)
   1093 {
   1094 #if VA_CHECK_VERSION(1, 1, 0)
   1095    VAAPIFramesContext    *src_vafc = src_fc->hwctx;
   1096    int use_prime2;
   1097 #else
   1098    int k;
   1099 #endif
   1100    AVHWFramesContext      *dst_fc =
   1101        (AVHWFramesContext*)dst->hw_frames_ctx->data;
   1102    AVVAAPIDeviceContext  *dst_dev = dst_fc->device_ctx->hwctx;
   1103    const AVDRMFrameDescriptor *desc;
   1104    const VAAPIFormatDescriptor *format_desc;
   1105    VASurfaceID surface_id;
   1106    VAStatus vas = VA_STATUS_SUCCESS;
   1107    uint32_t va_fourcc;
   1108    int err, i, j;
   1109 
   1110 #if !VA_CHECK_VERSION(1, 1, 0)
   1111    unsigned long buffer_handle;
   1112    VASurfaceAttribExternalBuffers buffer_desc;
   1113    VASurfaceAttrib attrs[2] = {
   1114        {
   1115            .type  = VASurfaceAttribMemoryType,
   1116            .flags = VA_SURFACE_ATTRIB_SETTABLE,
   1117            .value.type    = VAGenericValueTypeInteger,
   1118            .value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME,
   1119        },
   1120        {
   1121            .type  = VASurfaceAttribExternalBufferDescriptor,
   1122            .flags = VA_SURFACE_ATTRIB_SETTABLE,
   1123            .value.type    = VAGenericValueTypePointer,
   1124            .value.value.p = &buffer_desc,
   1125        }
   1126    };
   1127 #endif
   1128 
   1129    desc = (AVDRMFrameDescriptor*)src->data[0];
   1130 
   1131    if (desc->nb_objects != 1) {
   1132        av_log(dst_fc, AV_LOG_ERROR, "VAAPI can only map frames "
   1133               "made from a single DRM object.\n");
   1134        return AVERROR(EINVAL);
   1135    }
   1136 
   1137    va_fourcc = 0;
   1138    for (i = 0; i < FF_ARRAY_ELEMS(vaapi_drm_format_map); i++) {
   1139        if (desc->nb_layers != vaapi_drm_format_map[i].nb_layer_formats)
   1140            continue;
   1141        for (j = 0; j < desc->nb_layers; j++) {
   1142            if (desc->layers[j].format !=
   1143                vaapi_drm_format_map[i].layer_formats[j])
   1144                break;
   1145        }
   1146        if (j != desc->nb_layers)
   1147            continue;
   1148        va_fourcc = vaapi_drm_format_map[i].va_fourcc;
   1149        break;
   1150    }
   1151    if (!va_fourcc) {
   1152        av_log(dst_fc, AV_LOG_ERROR, "DRM format not supported "
   1153               "by VAAPI.\n");
   1154        return AVERROR(EINVAL);
   1155    }
   1156 
   1157    av_log(dst_fc, AV_LOG_DEBUG, "Map DRM object %d to VAAPI as "
   1158           "%08x.\n", desc->objects[0].fd, va_fourcc);
   1159 
   1160    format_desc = vaapi_format_from_fourcc(va_fourcc);
   1161    av_assert0(format_desc);
   1162 
   1163 #if VA_CHECK_VERSION(1, 1, 0)
   1164    use_prime2 = !src_vafc->prime_2_import_unsupported &&
   1165                 desc->objects[0].format_modifier != DRM_FORMAT_MOD_INVALID;
   1166    if (use_prime2) {
   1167        VADRMPRIMESurfaceDescriptor prime_desc;
   1168        VASurfaceAttrib prime_attrs[2] = {
   1169            {
   1170                .type  = VASurfaceAttribMemoryType,
   1171                .flags = VA_SURFACE_ATTRIB_SETTABLE,
   1172                .value.type    = VAGenericValueTypeInteger,
   1173                .value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2,
   1174            },
   1175            {
   1176                .type  = VASurfaceAttribExternalBufferDescriptor,
   1177                .flags = VA_SURFACE_ATTRIB_SETTABLE,
   1178                .value.type    = VAGenericValueTypePointer,
   1179                .value.value.p = &prime_desc,
   1180            }
   1181        };
   1182        prime_desc.fourcc = va_fourcc;
   1183        prime_desc.width = src_fc->width;
   1184        prime_desc.height = src_fc->height;
   1185        prime_desc.num_objects = desc->nb_objects;
   1186        for (i = 0; i < desc->nb_objects; ++i) {
   1187            prime_desc.objects[i].fd = desc->objects[i].fd;
   1188            prime_desc.objects[i].size = desc->objects[i].size;
   1189            prime_desc.objects[i].drm_format_modifier =
   1190                    desc->objects[i].format_modifier;
   1191        }
   1192 
   1193        prime_desc.num_layers = desc->nb_layers;
   1194        for (i = 0; i < desc->nb_layers; ++i) {
   1195            prime_desc.layers[i].drm_format = desc->layers[i].format;
   1196            prime_desc.layers[i].num_planes = desc->layers[i].nb_planes;
   1197            for (j = 0; j < desc->layers[i].nb_planes; ++j) {
   1198                prime_desc.layers[i].object_index[j] =
   1199                        desc->layers[i].planes[j].object_index;
   1200                prime_desc.layers[i].offset[j] = desc->layers[i].planes[j].offset;
   1201                prime_desc.layers[i].pitch[j] = desc->layers[i].planes[j].pitch;
   1202            }
   1203 
   1204            if (format_desc->chroma_planes_swapped &&
   1205                desc->layers[i].nb_planes == 3) {
   1206                FFSWAP(uint32_t, prime_desc.layers[i].pitch[1],
   1207                    prime_desc.layers[i].pitch[2]);
   1208                FFSWAP(uint32_t, prime_desc.layers[i].offset[1],
   1209                    prime_desc.layers[i].offset[2]);
   1210            }
   1211        }
   1212 
   1213        /*
   1214         * We can query for PRIME_2 support with vaQuerySurfaceAttributes, but that
   1215         * that needs the config_id which we don't have here . Both Intel and
   1216         * Gallium seem to do the correct error checks, so lets just try the
   1217         * PRIME_2 import first.
   1218         */
   1219        vas = vaCreateSurfaces(dst_dev->display, format_desc->rt_format,
   1220                               src->width, src->height, &surface_id, 1,
   1221                               prime_attrs, FF_ARRAY_ELEMS(prime_attrs));
   1222        if (vas != VA_STATUS_SUCCESS)
   1223            src_vafc->prime_2_import_unsupported = 1;
   1224    }
   1225 
   1226    if (!use_prime2 || vas != VA_STATUS_SUCCESS) {
   1227        int k;
   1228        uintptr_t buffer_handle;
   1229        VASurfaceAttribExternalBuffers buffer_desc;
   1230        VASurfaceAttrib buffer_attrs[2] = {
   1231            {
   1232                .type  = VASurfaceAttribMemoryType,
   1233                .flags = VA_SURFACE_ATTRIB_SETTABLE,
   1234                .value.type    = VAGenericValueTypeInteger,
   1235                .value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME,
   1236            },
   1237            {
   1238                .type  = VASurfaceAttribExternalBufferDescriptor,
   1239                .flags = VA_SURFACE_ATTRIB_SETTABLE,
   1240                .value.type    = VAGenericValueTypePointer,
   1241                .value.value.p = &buffer_desc,
   1242            }
   1243        };
   1244 
   1245        buffer_handle = desc->objects[0].fd;
   1246        buffer_desc.pixel_format = va_fourcc;
   1247        buffer_desc.width        = src_fc->width;
   1248        buffer_desc.height       = src_fc->height;
   1249        buffer_desc.data_size    = desc->objects[0].size;
   1250        buffer_desc.buffers      = &buffer_handle;
   1251        buffer_desc.num_buffers  = 1;
   1252        buffer_desc.flags        = 0;
   1253 
   1254        k = 0;
   1255        for (i = 0; i < desc->nb_layers; i++) {
   1256            for (j = 0; j < desc->layers[i].nb_planes; j++) {
   1257                buffer_desc.pitches[k] = desc->layers[i].planes[j].pitch;
   1258                buffer_desc.offsets[k] = desc->layers[i].planes[j].offset;
   1259                ++k;
   1260            }
   1261        }
   1262        buffer_desc.num_planes = k;
   1263 
   1264        if (format_desc->chroma_planes_swapped &&
   1265            buffer_desc.num_planes == 3) {
   1266            FFSWAP(uint32_t, buffer_desc.pitches[1], buffer_desc.pitches[2]);
   1267            FFSWAP(uint32_t, buffer_desc.offsets[1], buffer_desc.offsets[2]);
   1268        }
   1269 
   1270        vas = vaCreateSurfaces(dst_dev->display, format_desc->rt_format,
   1271                               src->width, src->height,
   1272                               &surface_id, 1,
   1273                               buffer_attrs, FF_ARRAY_ELEMS(buffer_attrs));
   1274    }
   1275 #else
   1276    buffer_handle = desc->objects[0].fd;
   1277    buffer_desc.pixel_format = va_fourcc;
   1278    buffer_desc.width        = src_fc->width;
   1279    buffer_desc.height       = src_fc->height;
   1280    buffer_desc.data_size    = desc->objects[0].size;
   1281    buffer_desc.buffers      = &buffer_handle;
   1282    buffer_desc.num_buffers  = 1;
   1283    buffer_desc.flags        = 0;
   1284 
   1285    k = 0;
   1286    for (i = 0; i < desc->nb_layers; i++) {
   1287        for (j = 0; j < desc->layers[i].nb_planes; j++) {
   1288            buffer_desc.pitches[k] = desc->layers[i].planes[j].pitch;
   1289            buffer_desc.offsets[k] = desc->layers[i].planes[j].offset;
   1290            ++k;
   1291        }
   1292    }
   1293    buffer_desc.num_planes = k;
   1294 
   1295    if (format_desc->chroma_planes_swapped &&
   1296        buffer_desc.num_planes == 3) {
   1297        FFSWAP(uint32_t, buffer_desc.pitches[1], buffer_desc.pitches[2]);
   1298        FFSWAP(uint32_t, buffer_desc.offsets[1], buffer_desc.offsets[2]);
   1299    }
   1300 
   1301    vas = vaCreateSurfaces(dst_dev->display, format_desc->rt_format,
   1302                           src->width, src->height,
   1303                           &surface_id, 1,
   1304                           attrs, FF_ARRAY_ELEMS(attrs));
   1305 #endif
   1306    if (vas != VA_STATUS_SUCCESS) {
   1307        av_log(dst_fc, AV_LOG_ERROR, "Failed to create surface from DRM "
   1308               "object: %d (%s).\n", vas, vaErrorStr(vas));
   1309        return AVERROR(EIO);
   1310    }
   1311    av_log(dst_fc, AV_LOG_DEBUG, "Create surface %#x.\n", surface_id);
   1312 
   1313    err = ff_hwframe_map_create(dst->hw_frames_ctx, dst, src,
   1314                                &vaapi_unmap_from_drm,
   1315                                (void*)(uintptr_t)surface_id);
   1316    if (err < 0)
   1317        return err;
   1318 
   1319    dst->width   = src->width;
   1320    dst->height  = src->height;
   1321    dst->data[3] = (uint8_t*)(uintptr_t)surface_id;
   1322 
   1323    av_log(dst_fc, AV_LOG_DEBUG, "Mapped DRM object %d to "
   1324           "surface %#x.\n", desc->objects[0].fd, surface_id);
   1325 
   1326    return 0;
   1327 }
   1328 
   1329 #if VA_CHECK_VERSION(1, 1, 0)
   1330 static void vaapi_unmap_to_drm_esh(AVHWFramesContext *hwfc,
   1331                                   HWMapDescriptor *hwmap)
   1332 {
   1333    AVDRMFrameDescriptor *drm_desc = hwmap->priv;
   1334    int i;
   1335 
   1336    for (i = 0; i < drm_desc->nb_objects; i++)
   1337        close(drm_desc->objects[i].fd);
   1338 
   1339    av_freep(&drm_desc);
   1340 }
   1341 
   1342 static int vaapi_map_to_drm_esh(AVHWFramesContext *hwfc, AVFrame *dst,
   1343                                const AVFrame *src, int flags)
   1344 {
   1345    AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
   1346    VASurfaceID surface_id;
   1347    VAStatus vas;
   1348    VADRMPRIMESurfaceDescriptor va_desc;
   1349    AVDRMFrameDescriptor *drm_desc = NULL;
   1350    uint32_t export_flags;
   1351    int err, i, j;
   1352 
   1353    surface_id = (VASurfaceID)(uintptr_t)src->data[3];
   1354 
   1355    export_flags = VA_EXPORT_SURFACE_SEPARATE_LAYERS;
   1356    if (flags & AV_HWFRAME_MAP_READ) {
   1357        export_flags |= VA_EXPORT_SURFACE_READ_ONLY;
   1358 
   1359        vas = vaSyncSurface(hwctx->display, surface_id);
   1360        if (vas != VA_STATUS_SUCCESS) {
   1361            av_log(hwfc, AV_LOG_ERROR, "Failed to sync surface "
   1362                   "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
   1363            return AVERROR(EIO);
   1364        }
   1365    }
   1366 
   1367    if (flags & AV_HWFRAME_MAP_WRITE)
   1368        export_flags |= VA_EXPORT_SURFACE_WRITE_ONLY;
   1369 
   1370    vas = vaExportSurfaceHandle(hwctx->display, surface_id,
   1371                                VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2,
   1372                                export_flags, &va_desc);
   1373    if (vas != VA_STATUS_SUCCESS) {
   1374        if (vas == VA_STATUS_ERROR_UNIMPLEMENTED)
   1375            return AVERROR(ENOSYS);
   1376        av_log(hwfc, AV_LOG_ERROR, "Failed to export surface %#x: "
   1377               "%d (%s).\n", surface_id, vas, vaErrorStr(vas));
   1378        return AVERROR(EIO);
   1379    }
   1380 
   1381    drm_desc = av_mallocz(sizeof(*drm_desc));
   1382    if (!drm_desc) {
   1383        err = AVERROR(ENOMEM);
   1384        goto fail;
   1385    }
   1386 
   1387    // By some bizarre coincidence, these structures are very similar...
   1388    drm_desc->nb_objects = va_desc.num_objects;
   1389    for (i = 0; i < va_desc.num_objects; i++) {
   1390        drm_desc->objects[i].fd   = va_desc.objects[i].fd;
   1391        drm_desc->objects[i].size = va_desc.objects[i].size;
   1392        drm_desc->objects[i].format_modifier =
   1393            va_desc.objects[i].drm_format_modifier;
   1394    }
   1395    drm_desc->nb_layers = va_desc.num_layers;
   1396    for (i = 0; i < va_desc.num_layers; i++) {
   1397        drm_desc->layers[i].format    = va_desc.layers[i].drm_format;
   1398        drm_desc->layers[i].nb_planes = va_desc.layers[i].num_planes;
   1399        for (j = 0; j < va_desc.layers[i].num_planes; j++) {
   1400            drm_desc->layers[i].planes[j].object_index =
   1401                va_desc.layers[i].object_index[j];
   1402            drm_desc->layers[i].planes[j].offset =
   1403                va_desc.layers[i].offset[j];
   1404            drm_desc->layers[i].planes[j].pitch =
   1405                va_desc.layers[i].pitch[j];
   1406        }
   1407    }
   1408 
   1409    err = ff_hwframe_map_create(src->hw_frames_ctx, dst, src,
   1410                                &vaapi_unmap_to_drm_esh, drm_desc);
   1411    if (err < 0)
   1412        goto fail;
   1413 
   1414    dst->width   = src->width;
   1415    dst->height  = src->height;
   1416    dst->data[0] = (uint8_t*)drm_desc;
   1417 
   1418    return 0;
   1419 
   1420 fail:
   1421    for (i = 0; i < va_desc.num_objects; i++)
   1422        close(va_desc.objects[i].fd);
   1423    av_freep(&drm_desc);
   1424    return err;
   1425 }
   1426 #endif
   1427 
   1428 #if VA_CHECK_VERSION(0, 36, 0)
   1429 typedef struct VAAPIDRMImageBufferMapping {
   1430    VAImage      image;
   1431    VABufferInfo buffer_info;
   1432 
   1433    AVDRMFrameDescriptor drm_desc;
   1434 } VAAPIDRMImageBufferMapping;
   1435 
   1436 static void vaapi_unmap_to_drm_abh(AVHWFramesContext *hwfc,
   1437                                  HWMapDescriptor *hwmap)
   1438 {
   1439    AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
   1440    VAAPIDRMImageBufferMapping *mapping = hwmap->priv;
   1441    VASurfaceID surface_id;
   1442    VAStatus vas;
   1443 
   1444    surface_id = (VASurfaceID)(uintptr_t)hwmap->source->data[3];
   1445    av_log(hwfc, AV_LOG_DEBUG, "Unmap VAAPI surface %#x from DRM.\n",
   1446           surface_id);
   1447 
   1448    // DRM PRIME file descriptors are closed by vaReleaseBufferHandle(),
   1449    // so we shouldn't close them separately.
   1450 
   1451    vas = vaReleaseBufferHandle(hwctx->display, mapping->image.buf);
   1452    if (vas != VA_STATUS_SUCCESS) {
   1453        av_log(hwfc, AV_LOG_ERROR, "Failed to release buffer "
   1454               "handle of image %#x (derived from surface %#x): "
   1455               "%d (%s).\n", mapping->image.buf, surface_id,
   1456               vas, vaErrorStr(vas));
   1457    }
   1458 
   1459    vas = vaDestroyImage(hwctx->display, mapping->image.image_id);
   1460    if (vas != VA_STATUS_SUCCESS) {
   1461        av_log(hwfc, AV_LOG_ERROR, "Failed to destroy image "
   1462               "derived from surface %#x: %d (%s).\n",
   1463               surface_id, vas, vaErrorStr(vas));
   1464    }
   1465 
   1466    av_free(mapping);
   1467 }
   1468 
   1469 static int vaapi_map_to_drm_abh(AVHWFramesContext *hwfc, AVFrame *dst,
   1470                                const AVFrame *src, int flags)
   1471 {
   1472    AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
   1473    VAAPIDRMImageBufferMapping *mapping = NULL;
   1474    VASurfaceID surface_id;
   1475    VAStatus vas;
   1476    int err, i, p;
   1477 
   1478    surface_id = (VASurfaceID)(uintptr_t)src->data[3];
   1479    av_log(hwfc, AV_LOG_DEBUG, "Map VAAPI surface %#x to DRM.\n",
   1480           surface_id);
   1481 
   1482    mapping = av_mallocz(sizeof(*mapping));
   1483    if (!mapping)
   1484        return AVERROR(ENOMEM);
   1485 
   1486    vas = vaDeriveImage(hwctx->display, surface_id,
   1487                        &mapping->image);
   1488    if (vas != VA_STATUS_SUCCESS) {
   1489        av_log(hwfc, AV_LOG_ERROR, "Failed to derive image from "
   1490               "surface %#x: %d (%s).\n",
   1491               surface_id, vas, vaErrorStr(vas));
   1492        err = AVERROR(EIO);
   1493        goto fail;
   1494    }
   1495 
   1496    for (i = 0; i < FF_ARRAY_ELEMS(vaapi_drm_format_map); i++) {
   1497        if (vaapi_drm_format_map[i].va_fourcc ==
   1498            mapping->image.format.fourcc)
   1499            break;
   1500    }
   1501    if (i >= FF_ARRAY_ELEMS(vaapi_drm_format_map)) {
   1502        av_log(hwfc, AV_LOG_ERROR, "No matching DRM format for "
   1503               "VAAPI format %#x.\n", mapping->image.format.fourcc);
   1504        err = AVERROR(EINVAL);
   1505        goto fail_derived;
   1506    }
   1507 
   1508    mapping->buffer_info.mem_type =
   1509        VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME;
   1510 
   1511    mapping->drm_desc.nb_layers =
   1512        vaapi_drm_format_map[i].nb_layer_formats;
   1513    if (mapping->drm_desc.nb_layers > 1) {
   1514        if (mapping->drm_desc.nb_layers != mapping->image.num_planes) {
   1515            av_log(hwfc, AV_LOG_ERROR, "Image properties do not match "
   1516                   "expected format: got %d planes, but expected %d.\n",
   1517                   mapping->image.num_planes, mapping->drm_desc.nb_layers);
   1518            err = AVERROR(EINVAL);
   1519            goto fail_derived;
   1520        }
   1521 
   1522        for(p = 0; p < mapping->drm_desc.nb_layers; p++) {
   1523            mapping->drm_desc.layers[p] = (AVDRMLayerDescriptor) {
   1524                .format    = vaapi_drm_format_map[i].layer_formats[p],
   1525                .nb_planes = 1,
   1526                .planes[0] = {
   1527                    .object_index = 0,
   1528                    .offset       = mapping->image.offsets[p],
   1529                    .pitch        = mapping->image.pitches[p],
   1530                },
   1531            };
   1532        }
   1533    } else {
   1534        mapping->drm_desc.layers[0].format =
   1535            vaapi_drm_format_map[i].layer_formats[0];
   1536        mapping->drm_desc.layers[0].nb_planes = mapping->image.num_planes;
   1537        for (p = 0; p < mapping->image.num_planes; p++) {
   1538            mapping->drm_desc.layers[0].planes[p] = (AVDRMPlaneDescriptor) {
   1539                .object_index = 0,
   1540                .offset       = mapping->image.offsets[p],
   1541                .pitch        = mapping->image.pitches[p],
   1542            };
   1543        }
   1544    }
   1545 
   1546    vas = vaAcquireBufferHandle(hwctx->display, mapping->image.buf,
   1547                                &mapping->buffer_info);
   1548    if (vas != VA_STATUS_SUCCESS) {
   1549        av_log(hwfc, AV_LOG_ERROR, "Failed to get buffer "
   1550               "handle from image %#x (derived from surface %#x): "
   1551               "%d (%s).\n", mapping->image.buf, surface_id,
   1552               vas, vaErrorStr(vas));
   1553        err = AVERROR(EIO);
   1554        goto fail_derived;
   1555    }
   1556 
   1557    av_log(hwfc, AV_LOG_DEBUG, "DRM PRIME fd is %"PRIdPTR".\n",
   1558           mapping->buffer_info.handle);
   1559 
   1560    mapping->drm_desc.nb_objects = 1;
   1561    mapping->drm_desc.objects[0] = (AVDRMObjectDescriptor) {
   1562        .fd   = mapping->buffer_info.handle,
   1563        .size = mapping->image.data_size,
   1564        // There is no way to get the format modifier with this API.
   1565        .format_modifier = DRM_FORMAT_MOD_INVALID,
   1566    };
   1567 
   1568    err = ff_hwframe_map_create(src->hw_frames_ctx,
   1569                                dst, src, &vaapi_unmap_to_drm_abh,
   1570                                mapping);
   1571    if (err < 0)
   1572        goto fail_mapped;
   1573 
   1574    dst->data[0] = (uint8_t*)&mapping->drm_desc;
   1575    dst->width   = src->width;
   1576    dst->height  = src->height;
   1577 
   1578    return 0;
   1579 
   1580 fail_mapped:
   1581    vaReleaseBufferHandle(hwctx->display, mapping->image.buf);
   1582 fail_derived:
   1583    vaDestroyImage(hwctx->display, mapping->image.image_id);
   1584 fail:
   1585    av_freep(&mapping);
   1586    return err;
   1587 }
   1588 #endif
   1589 
   1590 static int vaapi_map_to_drm(AVHWFramesContext *hwfc, AVFrame *dst,
   1591                            const AVFrame *src, int flags)
   1592 {
   1593 #if VA_CHECK_VERSION(1, 1, 0)
   1594    int err;
   1595    err = vaapi_map_to_drm_esh(hwfc, dst, src, flags);
   1596    if (err != AVERROR(ENOSYS))
   1597        return err;
   1598 #endif
   1599 #if VA_CHECK_VERSION(0, 36, 0)
   1600    return vaapi_map_to_drm_abh(hwfc, dst, src, flags);
   1601 #endif
   1602    return AVERROR(ENOSYS);
   1603 }
   1604 
   1605 #endif /* CONFIG_LIBDRM */
   1606 
   1607 static int vaapi_map_to(AVHWFramesContext *hwfc, AVFrame *dst,
   1608                        const AVFrame *src, int flags)
   1609 {
   1610    switch (src->format) {
   1611 #if CONFIG_LIBDRM
   1612    case AV_PIX_FMT_DRM_PRIME:
   1613        return vaapi_map_from_drm(hwfc, dst, src, flags);
   1614 #endif
   1615    default:
   1616        return AVERROR(ENOSYS);
   1617    }
   1618 }
   1619 
   1620 static int vaapi_map_from(AVHWFramesContext *hwfc, AVFrame *dst,
   1621                          const AVFrame *src, int flags)
   1622 {
   1623    switch (dst->format) {
   1624 #if CONFIG_LIBDRM
   1625    case AV_PIX_FMT_DRM_PRIME:
   1626        return vaapi_map_to_drm(hwfc, dst, src, flags);
   1627 #endif
   1628    default:
   1629        return vaapi_map_to_memory(hwfc, dst, src, flags);
   1630    }
   1631 }
   1632 
   1633 static void vaapi_device_free(AVHWDeviceContext *ctx)
   1634 {
   1635    AVVAAPIDeviceContext *hwctx = ctx->hwctx;
   1636    VAAPIDevicePriv      *priv  = ctx->user_opaque;
   1637 
   1638    if (hwctx->display)
   1639        vaTerminate(hwctx->display);
   1640 
   1641 #if HAVE_VAAPI_X11
   1642    if (priv->x11_display)
   1643        XCloseDisplay(priv->x11_display);
   1644 #endif
   1645 
   1646    if (priv->drm_fd >= 0)
   1647        close(priv->drm_fd);
   1648 
   1649    av_freep(&priv);
   1650 }
   1651 
   1652 #if CONFIG_VAAPI_1
   1653 static void vaapi_device_log_error(void *context, const char *message)
   1654 {
   1655    AVHWDeviceContext *ctx = context;
   1656 
   1657    av_log(ctx, AV_LOG_ERROR, "libva: %s", message);
   1658 }
   1659 
   1660 static void vaapi_device_log_info(void *context, const char *message)
   1661 {
   1662    AVHWDeviceContext *ctx = context;
   1663 
   1664    av_log(ctx, AV_LOG_VERBOSE, "libva: %s", message);
   1665 }
   1666 #endif
   1667 
   1668 static int vaapi_device_connect(AVHWDeviceContext *ctx,
   1669                                VADisplay display)
   1670 {
   1671    AVVAAPIDeviceContext *hwctx = ctx->hwctx;
   1672    int major, minor;
   1673    VAStatus vas;
   1674 
   1675 #if CONFIG_VAAPI_1
   1676    vaSetErrorCallback(display, &vaapi_device_log_error, ctx);
   1677    vaSetInfoCallback (display, &vaapi_device_log_info,  ctx);
   1678 #endif
   1679 
   1680    hwctx->display = display;
   1681 
   1682    vas = vaInitialize(display, &major, &minor);
   1683    if (vas != VA_STATUS_SUCCESS) {
   1684        av_log(ctx, AV_LOG_ERROR, "Failed to initialise VAAPI "
   1685               "connection: %d (%s).\n", vas, vaErrorStr(vas));
   1686        return AVERROR(EIO);
   1687    }
   1688    av_log(ctx, AV_LOG_VERBOSE, "Initialised VAAPI connection: "
   1689           "version %d.%d\n", major, minor);
   1690 
   1691    return 0;
   1692 }
   1693 
   1694 static int vaapi_device_create(AVHWDeviceContext *ctx, const char *device,
   1695                               AVDictionary *opts, int flags)
   1696 {
   1697    VAAPIDevicePriv *priv;
   1698    VADisplay display = NULL;
   1699    const AVDictionaryEntry *ent;
   1700    int try_drm, try_x11, try_win32, try_all;
   1701 
   1702    priv = av_mallocz(sizeof(*priv));
   1703    if (!priv)
   1704        return AVERROR(ENOMEM);
   1705 
   1706    priv->drm_fd = -1;
   1707 
   1708    ctx->user_opaque = priv;
   1709    ctx->free        = vaapi_device_free;
   1710 
   1711    ent = av_dict_get(opts, "connection_type", NULL, 0);
   1712    if (ent) {
   1713        try_all = try_drm = try_x11 = try_win32 = 0;
   1714        if (!strcmp(ent->value, "drm")) {
   1715            try_drm = 1;
   1716        } else if (!strcmp(ent->value, "x11")) {
   1717            try_x11 = 1;
   1718        } else if (!strcmp(ent->value, "win32")) {
   1719            try_win32 = 1;
   1720        } else {
   1721            av_log(ctx, AV_LOG_ERROR, "Invalid connection type %s.\n",
   1722                   ent->value);
   1723            return AVERROR(EINVAL);
   1724        }
   1725    } else {
   1726        try_all = 1;
   1727        try_drm = HAVE_VAAPI_DRM;
   1728        try_x11 = HAVE_VAAPI_X11;
   1729        try_win32 = HAVE_VAAPI_WIN32;
   1730    }
   1731 
   1732 #if HAVE_VAAPI_DRM
   1733    while (!display && try_drm) {
   1734        // If the device is specified, try to open it as a DRM device node.
   1735        // If not, look for a usable render node, possibly restricted to those
   1736        // using a specified kernel driver.
   1737        int loglevel = try_all ? AV_LOG_VERBOSE : AV_LOG_ERROR;
   1738        if (device) {
   1739            priv->drm_fd = open(device, O_RDWR);
   1740            if (priv->drm_fd < 0) {
   1741                av_log(ctx, loglevel, "Failed to open %s as "
   1742                       "DRM device node.\n", device);
   1743                break;
   1744            }
   1745        } else {
   1746            char path[64];
   1747            int n, max_devices = 8;
   1748 #if CONFIG_LIBDRM
   1749            drmVersion *info;
   1750            const AVDictionaryEntry *kernel_driver;
   1751            const AVDictionaryEntry *vendor_id;
   1752            kernel_driver = av_dict_get(opts, "kernel_driver", NULL, 0);
   1753            vendor_id = av_dict_get(opts, "vendor_id", NULL, 0);
   1754 #endif
   1755            for (n = 0; n < max_devices; n++) {
   1756                snprintf(path, sizeof(path),
   1757                         "/dev/dri/renderD%d", 128 + n);
   1758                priv->drm_fd = open(path, O_RDWR);
   1759                if (priv->drm_fd < 0) {
   1760                    if (errno == ENOENT) {
   1761                        if (n != max_devices - 1) {
   1762                            av_log(ctx, AV_LOG_VERBOSE,
   1763                                   "No render device %s, try next device for "
   1764                                   "DRM render node.\n", path);
   1765                            continue;
   1766                        }
   1767 
   1768                        av_log(ctx, AV_LOG_VERBOSE, "No available render device "
   1769                               "for DRM render node.\n");
   1770                    } else
   1771                        av_log(ctx, AV_LOG_VERBOSE, "Cannot open "
   1772                               "DRM render node for device %d.\n", n);
   1773                    break;
   1774                }
   1775 #if CONFIG_LIBDRM
   1776                info = drmGetVersion(priv->drm_fd);
   1777                if (!info) {
   1778                    av_log(ctx, AV_LOG_VERBOSE,
   1779                           "Failed to get DRM version for device %d.\n", n);
   1780                    close(priv->drm_fd);
   1781                    priv->drm_fd = -1;
   1782                    continue;
   1783                }
   1784                if (kernel_driver) {
   1785                    if (strcmp(kernel_driver->value, info->name)) {
   1786                        av_log(ctx, AV_LOG_VERBOSE, "Ignoring device %d "
   1787                               "with non-matching kernel driver (%s).\n",
   1788                               n, info->name);
   1789                        drmFreeVersion(info);
   1790                        close(priv->drm_fd);
   1791                        priv->drm_fd = -1;
   1792                        continue;
   1793                    }
   1794                    av_log(ctx, AV_LOG_VERBOSE, "Trying to use "
   1795                           "DRM render node for device %d, "
   1796                           "with matching kernel driver (%s).\n",
   1797                           n, info->name);
   1798                    drmFreeVersion(info);
   1799                    break;
   1800                // drmGetVersion() ensures |info->name| is 0-terminated.
   1801                } else if (!strcmp(info->name, "vgem")) {
   1802                    av_log(ctx, AV_LOG_VERBOSE,
   1803                           "Skipping vgem node for device %d.\n", n);
   1804                    drmFreeVersion(info);
   1805                    close(priv->drm_fd);
   1806                    priv->drm_fd = -1;
   1807                    continue;
   1808                } else if (vendor_id) {
   1809                    drmDevicePtr device;
   1810                    char drm_vendor[8];
   1811                    if (drmGetDevice(priv->drm_fd, &device)) {
   1812                        av_log(ctx, AV_LOG_VERBOSE,
   1813                               "Failed to get DRM device info for device %d.\n", n);
   1814                        close(priv->drm_fd);
   1815                        priv->drm_fd = -1;
   1816                        continue;
   1817                    }
   1818 
   1819                    snprintf(drm_vendor, sizeof(drm_vendor), "0x%x", device->deviceinfo.pci->vendor_id);
   1820                    if (strcmp(vendor_id->value, drm_vendor)) {
   1821                        av_log(ctx, AV_LOG_VERBOSE, "Ignoring device %d "
   1822                               "with non-matching vendor id (%s).\n",
   1823                               n, vendor_id->value);
   1824                        drmFreeDevice(&device);
   1825                        close(priv->drm_fd);
   1826                        priv->drm_fd = -1;
   1827                        continue;
   1828                    }
   1829                    av_log(ctx, AV_LOG_VERBOSE, "Trying to use "
   1830                           "DRM render node for device %d, "
   1831                           "with matching vendor id (%s).\n",
   1832                           n, vendor_id->value);
   1833                    drmFreeDevice(&device);
   1834                    break;
   1835                }
   1836                drmFreeVersion(info);
   1837 #endif
   1838                av_log(ctx, AV_LOG_VERBOSE, "Trying to use "
   1839                       "DRM render node for device %d.\n", n);
   1840                break;
   1841            }
   1842            if (n >= max_devices)
   1843                break;
   1844        }
   1845 
   1846        display = vaGetDisplayDRM(priv->drm_fd);
   1847        if (!display) {
   1848            av_log(ctx, AV_LOG_VERBOSE, "Cannot open a VA display "
   1849                   "from DRM device %s.\n", device);
   1850            return AVERROR_EXTERNAL;
   1851        }
   1852        break;
   1853    }
   1854 #endif
   1855 
   1856 #if HAVE_VAAPI_X11
   1857    if (!display && try_x11) {
   1858        // Try to open the device as an X11 display.
   1859        priv->x11_display = XOpenDisplay(device);
   1860        if (!priv->x11_display) {
   1861            av_log(ctx, AV_LOG_VERBOSE, "Cannot open X11 display "
   1862                   "%s.\n", XDisplayName(device));
   1863        } else {
   1864            display = vaGetDisplay(priv->x11_display);
   1865            if (!display) {
   1866                av_log(ctx, AV_LOG_ERROR, "Cannot open a VA display "
   1867                       "from X11 display %s.\n", XDisplayName(device));
   1868                return AVERROR_UNKNOWN;
   1869            }
   1870 
   1871            av_log(ctx, AV_LOG_VERBOSE, "Opened VA display via "
   1872                   "X11 display %s.\n", XDisplayName(device));
   1873        }
   1874    }
   1875 #endif
   1876 
   1877 #if HAVE_VAAPI_WIN32
   1878    if (!display && try_win32) {
   1879        // Try to create a display from the specified device, if any.
   1880        if (!device) {
   1881            display = vaGetDisplayWin32(NULL);
   1882        } else {
   1883            IDXGIFactory2 *pDXGIFactory = NULL;
   1884            IDXGIAdapter *pAdapter = NULL;
   1885 #if !HAVE_UWP
   1886            HANDLE dxgi = dlopen("dxgi.dll", 0);
   1887            if (!dxgi) {
   1888                av_log(ctx, AV_LOG_ERROR, "Failed to load dxgi.dll\n");
   1889                return AVERROR_UNKNOWN;
   1890            }
   1891            PFN_CREATE_DXGI_FACTORY pfnCreateDXGIFactory =
   1892                (PFN_CREATE_DXGI_FACTORY)dlsym(dxgi, "CreateDXGIFactory");
   1893            if (!pfnCreateDXGIFactory) {
   1894                av_log(ctx, AV_LOG_ERROR, "CreateDXGIFactory load failed\n");
   1895                dlclose(dxgi);
   1896                return AVERROR_UNKNOWN;
   1897            }
   1898 #else
   1899            // In UWP (which lacks LoadLibrary), CreateDXGIFactory isn't
   1900            // available, only CreateDXGIFactory1
   1901            PFN_CREATE_DXGI_FACTORY pfnCreateDXGIFactory =
   1902                (PFN_CREATE_DXGI_FACTORY)CreateDXGIFactory1;
   1903 #endif
   1904            if (SUCCEEDED(pfnCreateDXGIFactory(&IID_IDXGIFactory2,
   1905                                              (void **)&pDXGIFactory))) {
   1906                int adapter = atoi(device);
   1907                if (SUCCEEDED(IDXGIFactory2_EnumAdapters(pDXGIFactory,
   1908                                                         adapter,
   1909                                                         &pAdapter))) {
   1910                    DXGI_ADAPTER_DESC desc;
   1911                    if (SUCCEEDED(IDXGIAdapter2_GetDesc(pAdapter, &desc))) {
   1912                        av_log(ctx, AV_LOG_INFO,
   1913                              "Using device %04x:%04x (%ls) - LUID %lu %ld.\n",
   1914                              desc.VendorId, desc.DeviceId, desc.Description,
   1915                              desc.AdapterLuid.LowPart,
   1916                              desc.AdapterLuid.HighPart);
   1917                        display = vaGetDisplayWin32(&desc.AdapterLuid);
   1918                    }
   1919                    IDXGIAdapter_Release(pAdapter);
   1920                }
   1921                IDXGIFactory2_Release(pDXGIFactory);
   1922            }
   1923 #if !HAVE_UWP
   1924            dlclose(dxgi);
   1925 #endif
   1926        }
   1927 
   1928        if (!display) {
   1929            av_log(ctx, AV_LOG_ERROR, "Cannot open a VA display "
   1930                    "from Win32 display.\n");
   1931            return AVERROR_UNKNOWN;
   1932        }
   1933 
   1934        av_log(ctx, AV_LOG_VERBOSE, "Opened VA display via "
   1935                "Win32 display.\n");
   1936    }
   1937 #endif
   1938 
   1939    if (!display) {
   1940        if (device)
   1941            av_log(ctx, AV_LOG_ERROR, "No VA display found for "
   1942                   "device %s.\n", device);
   1943        else
   1944            av_log(ctx, AV_LOG_ERROR, "No VA display found for "
   1945                   "any default device.\n");
   1946        return AVERROR(EINVAL);
   1947    }
   1948 
   1949    ent = av_dict_get(opts, "driver", NULL, 0);
   1950    if (ent) {
   1951 #if VA_CHECK_VERSION(0, 38, 0)
   1952        VAStatus vas;
   1953        vas = vaSetDriverName(display, ent->value);
   1954        if (vas != VA_STATUS_SUCCESS) {
   1955            av_log(ctx, AV_LOG_ERROR, "Failed to set driver name to "
   1956                   "%s: %d (%s).\n", ent->value, vas, vaErrorStr(vas));
   1957            vaTerminate(display);
   1958            return AVERROR_EXTERNAL;
   1959        }
   1960 #else
   1961        av_log(ctx, AV_LOG_WARNING, "Driver name setting is not "
   1962               "supported with this VAAPI version.\n");
   1963 #endif
   1964    }
   1965 
   1966    return vaapi_device_connect(ctx, display);
   1967 }
   1968 
   1969 static int vaapi_device_derive(AVHWDeviceContext *ctx,
   1970                               AVHWDeviceContext *src_ctx,
   1971                               AVDictionary *opts, int flags)
   1972 {
   1973 #if HAVE_VAAPI_DRM
   1974    if (src_ctx->type == AV_HWDEVICE_TYPE_DRM) {
   1975        AVDRMDeviceContext *src_hwctx = src_ctx->hwctx;
   1976        VADisplay *display;
   1977        VAAPIDevicePriv *priv;
   1978        int fd;
   1979 
   1980        if (src_hwctx->fd < 0) {
   1981            av_log(ctx, AV_LOG_ERROR, "DRM instance requires an associated "
   1982                   "device to derive a VA display from.\n");
   1983            return AVERROR(EINVAL);
   1984        }
   1985 
   1986 #if CONFIG_LIBDRM
   1987        {
   1988            int node_type = drmGetNodeTypeFromFd(src_hwctx->fd);
   1989            char *render_node;
   1990            if (node_type < 0) {
   1991                av_log(ctx, AV_LOG_ERROR, "DRM instance fd does not appear "
   1992                       "to refer to a DRM device.\n");
   1993                return AVERROR(EINVAL);
   1994            }
   1995            if (node_type == DRM_NODE_RENDER) {
   1996                fd = src_hwctx->fd;
   1997            } else {
   1998                render_node = drmGetRenderDeviceNameFromFd(src_hwctx->fd);
   1999                if (!render_node) {
   2000                    av_log(ctx, AV_LOG_VERBOSE, "Using non-render node "
   2001                           "because the device does not have an "
   2002                           "associated render node.\n");
   2003                    fd = src_hwctx->fd;
   2004                } else {
   2005                    fd = open(render_node, O_RDWR);
   2006                    if (fd < 0) {
   2007                        av_log(ctx, AV_LOG_VERBOSE, "Using non-render node "
   2008                               "because the associated render node "
   2009                               "could not be opened.\n");
   2010                        fd = src_hwctx->fd;
   2011                    } else {
   2012                        av_log(ctx, AV_LOG_VERBOSE, "Using render node %s "
   2013                               "in place of non-render DRM device.\n",
   2014                               render_node);
   2015                    }
   2016                    free(render_node);
   2017                }
   2018            }
   2019        }
   2020 #else
   2021        fd = src_hwctx->fd;
   2022 #endif
   2023 
   2024        priv = av_mallocz(sizeof(*priv));
   2025        if (!priv) {
   2026            if (fd != src_hwctx->fd) {
   2027                // The fd was opened in this function.
   2028                close(fd);
   2029            }
   2030            return AVERROR(ENOMEM);
   2031        }
   2032 
   2033        if (fd == src_hwctx->fd) {
   2034            // The fd is inherited from the source context and we are holding
   2035            // a reference to that, we don't want to close it from here.
   2036            priv->drm_fd = -1;
   2037        } else {
   2038            priv->drm_fd = fd;
   2039        }
   2040 
   2041        ctx->user_opaque = priv;
   2042        ctx->free        = &vaapi_device_free;
   2043 
   2044        display = vaGetDisplayDRM(fd);
   2045        if (!display) {
   2046            av_log(ctx, AV_LOG_ERROR, "Failed to open a VA display from "
   2047                   "DRM device.\n");
   2048            return AVERROR(EIO);
   2049        }
   2050 
   2051        return vaapi_device_connect(ctx, display);
   2052    }
   2053 #endif
   2054    return AVERROR(ENOSYS);
   2055 }
   2056 
   2057 const HWContextType ff_hwcontext_type_vaapi = {
   2058    .type                   = AV_HWDEVICE_TYPE_VAAPI,
   2059    .name                   = "VAAPI",
   2060 
   2061    .device_hwctx_size      = sizeof(VAAPIDeviceContext),
   2062    .device_hwconfig_size   = sizeof(AVVAAPIHWConfig),
   2063    .frames_hwctx_size      = sizeof(VAAPIFramesContext),
   2064 
   2065    .device_create          = &vaapi_device_create,
   2066    .device_derive          = &vaapi_device_derive,
   2067    .device_init            = &vaapi_device_init,
   2068    .device_uninit          = &vaapi_device_uninit,
   2069    .frames_get_constraints = &vaapi_frames_get_constraints,
   2070    .frames_init            = &vaapi_frames_init,
   2071    .frames_uninit          = &vaapi_frames_uninit,
   2072    .frames_get_buffer      = &vaapi_get_buffer,
   2073    .transfer_get_formats   = &vaapi_transfer_get_formats,
   2074    .transfer_data_to       = &vaapi_transfer_data_to,
   2075    .transfer_data_from     = &vaapi_transfer_data_from,
   2076    .map_to                 = &vaapi_map_to,
   2077    .map_from               = &vaapi_map_from,
   2078 
   2079    .pix_fmts = (const enum AVPixelFormat[]) {
   2080        AV_PIX_FMT_VAAPI,
   2081        AV_PIX_FMT_NONE
   2082    },
   2083 };