2083 lines · 69.4 KB · C
RawDownload
/* * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * FFmpeg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "config.h" #if HAVE_VAAPI_WIN32#   include <windows.h>#define COBJMACROS#   include <initguid.h>#   include <dxgi1_2.h>#   include "compat/w32dlfcn.h"#   include <va/va_win32.h>typedef HRESULT (WINAPI *PFN_CREATE_DXGI_FACTORY)(REFIID riid, void **ppFactory);#endif#if HAVE_VAAPI_X11#   include <va/va_x11.h>#endif#if HAVE_VAAPI_DRM#   include <va/va_drm.h>#endif #if CONFIG_LIBDRM#   include <va/va_drmcommon.h>#   include <xf86drm.h>#   include <drm_fourcc.h>#   ifndef DRM_FORMAT_MOD_INVALID#       define DRM_FORMAT_MOD_INVALID ((1ULL << 56) - 1)#   endif#endif #include <fcntl.h>#if HAVE_UNISTD_H#   include <unistd.h>#endif  #include "avassert.h"#include "buffer.h"#include "common.h"#include "hwcontext.h"#include "hwcontext_drm.h"#include "hwcontext_internal.h"#include "hwcontext_vaapi.h"#include "mem.h"#include "pixdesc.h"#include "pixfmt.h"  typedef struct VAAPIDevicePriv {#if HAVE_VAAPI_X11    Display *x11_display;#endif     int drm_fd;} VAAPIDevicePriv; typedef struct VAAPISurfaceFormat {    enum AVPixelFormat pix_fmt;    VAImageFormat image_format;} VAAPISurfaceFormat; typedef struct VAAPIDeviceContext {    /**     * The public AVVAAPIDeviceContext. See hwcontext_vaapi.h for it.     */    AVVAAPIDeviceContext p;     // Surface formats which can be used with this device.    VAAPISurfaceFormat *formats;    int              nb_formats;} VAAPIDeviceContext; typedef struct VAAPIFramesContext {    /**     * The public AVVAAPIFramesContext. See hwcontext_vaapi.h for it.     */    AVVAAPIFramesContext p;     // Surface attributes set at create time.    VASurfaceAttrib *attributes;    int           nb_attributes;    // RT format of the underlying surface (Intel driver ignores this anyway).    unsigned int rt_format;    // Whether vaDeriveImage works.    int derive_works;    // Caches whether VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2 is unsupported for    // surface imports.    int prime_2_import_unsupported;} VAAPIFramesContext; typedef struct VAAPIMapping {    // Handle to the derived or copied image which is mapped.    VAImage image;    // The mapping flags actually used.    int flags;} VAAPIMapping; typedef struct VAAPIFormat {    unsigned int fourcc;    unsigned int rt_format;    enum AVPixelFormat pix_fmt;    int chroma_planes_swapped;} VAAPIFormatDescriptor; #define MAP(va, rt, av, swap_uv) { \        VA_FOURCC_ ## va, \        VA_RT_FORMAT_ ## rt, \        AV_PIX_FMT_ ## av, \        swap_uv, \    }// The map fourcc <-> pix_fmt isn't bijective because of the annoying U/V// plane swap cases.  The frame handling below tries to hide these.static const VAAPIFormatDescriptor vaapi_format_map[] = {    MAP(NV12, YUV420,  NV12,    0),#ifdef VA_FOURCC_I420    MAP(I420, YUV420,  YUV420P, 0),#endif    MAP(YV12, YUV420,  YUV420P, 1),    MAP(IYUV, YUV420,  YUV420P, 0),    MAP(422H, YUV422,  YUV422P, 0),#ifdef VA_FOURCC_YV16    MAP(YV16, YUV422,  YUV422P, 1),#endif    MAP(UYVY, YUV422,  UYVY422, 0),    MAP(YUY2, YUV422,  YUYV422, 0),#ifdef VA_FOURCC_Y210    MAP(Y210, YUV422_10,  Y210, 0),#endif#ifdef VA_FOURCC_Y212    MAP(Y212, YUV422_12,  Y212, 0),#endif    MAP(411P, YUV411,  YUV411P, 0),    MAP(422V, YUV422,  YUV440P, 0),    MAP(444P, YUV444,  YUV444P, 0),#ifdef VA_FOURCC_XYUV    MAP(XYUV, YUV444,  VUYX,    0),#endif    MAP(Y800, YUV400,  GRAY8,   0),#ifdef VA_FOURCC_P010    MAP(P010, YUV420_10BPP, P010, 0),#endif#ifdef VA_FOURCC_P012    MAP(P012, YUV420_12, P012, 0),#endif    MAP(BGRA, RGB32,   BGRA, 0),    MAP(BGRX, RGB32,   BGR0, 0),    MAP(RGBA, RGB32,   RGBA, 0),    MAP(RGBX, RGB32,   RGB0, 0),#ifdef VA_FOURCC_ABGR    MAP(ABGR, RGB32,   ABGR, 0),    MAP(XBGR, RGB32,   0BGR, 0),#endif    MAP(ARGB, RGB32,   ARGB, 0),    MAP(XRGB, RGB32,   0RGB, 0),#ifdef VA_FOURCC_X2R10G10B10    MAP(X2R10G10B10, RGB32_10, X2RGB10, 0),#endif#ifdef VA_FOURCC_Y410    // libva doesn't include a fourcc for XV30 and the driver only declares    // support for Y410, so we must fudge the mapping here.    MAP(Y410, YUV444_10,  XV30, 0),#endif#ifdef VA_FOURCC_Y412    // libva doesn't include a fourcc for XV36 and the driver only declares    // support for Y412, so we must fudge the mapping here.    MAP(Y412, YUV444_12,  XV36, 0),#endif};#undef MAP static const VAAPIFormatDescriptor *    vaapi_format_from_fourcc(unsigned int fourcc){    int i;    for (i = 0; i < FF_ARRAY_ELEMS(vaapi_format_map); i++)        if (vaapi_format_map[i].fourcc == fourcc)            return &vaapi_format_map[i];    return NULL;} static const VAAPIFormatDescriptor *    vaapi_format_from_pix_fmt(enum AVPixelFormat pix_fmt){    int i;    for (i = 0; i < FF_ARRAY_ELEMS(vaapi_format_map); i++)        if (vaapi_format_map[i].pix_fmt == pix_fmt)            return &vaapi_format_map[i];    return NULL;} static enum AVPixelFormat vaapi_pix_fmt_from_fourcc(unsigned int fourcc){    const VAAPIFormatDescriptor *desc;    desc = vaapi_format_from_fourcc(fourcc);    if (desc)        return desc->pix_fmt;    else        return AV_PIX_FMT_NONE;} static int vaapi_get_image_format(AVHWDeviceContext *hwdev,                                  enum AVPixelFormat pix_fmt,                                  VAImageFormat **image_format){    VAAPIDeviceContext *ctx = hwdev->hwctx;    int i;     for (i = 0; i < ctx->nb_formats; i++) {        if (ctx->formats[i].pix_fmt == pix_fmt) {            if (image_format)                *image_format = &ctx->formats[i].image_format;            return 0;        }    }    return AVERROR(ENOSYS);} static int vaapi_frames_get_constraints(AVHWDeviceContext *hwdev,                                        const void *hwconfig,                                        AVHWFramesConstraints *constraints){    VAAPIDeviceContext *ctx = hwdev->hwctx;    AVVAAPIDeviceContext *hwctx = &ctx->p;    const AVVAAPIHWConfig *config = hwconfig;    VASurfaceAttrib *attr_list = NULL;    VAStatus vas;    enum AVPixelFormat pix_fmt;    unsigned int fourcc;    int err, i, j, attr_count, pix_fmt_count;     if (config &&        !(hwctx->driver_quirks & AV_VAAPI_DRIVER_QUIRK_SURFACE_ATTRIBUTES)) {        attr_count = 0;        vas = vaQuerySurfaceAttributes(hwctx->display, config->config_id,                                       0, &attr_count);        if (vas != VA_STATUS_SUCCESS) {            av_log(hwdev, AV_LOG_ERROR, "Failed to query surface attributes: "                   "%d (%s).\n", vas, vaErrorStr(vas));            err = AVERROR(ENOSYS);            goto fail;        }         attr_list = av_malloc(attr_count * sizeof(*attr_list));        if (!attr_list) {            err = AVERROR(ENOMEM);            goto fail;        }         vas = vaQuerySurfaceAttributes(hwctx->display, config->config_id,                                       attr_list, &attr_count);        if (vas != VA_STATUS_SUCCESS) {            av_log(hwdev, AV_LOG_ERROR, "Failed to query surface attributes: "                   "%d (%s).\n", vas, vaErrorStr(vas));            err = AVERROR(ENOSYS);            goto fail;        }         pix_fmt_count = 0;        for (i = 0; i < attr_count; i++) {            switch (attr_list[i].type) {            case VASurfaceAttribPixelFormat:                fourcc = attr_list[i].value.value.i;                pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc);                if (pix_fmt != AV_PIX_FMT_NONE) {                    ++pix_fmt_count;                } else {                    // Something unsupported - ignore.                }                break;            case VASurfaceAttribMinWidth:                constraints->min_width  = attr_list[i].value.value.i;                break;            case VASurfaceAttribMinHeight:                constraints->min_height = attr_list[i].value.value.i;                break;            case VASurfaceAttribMaxWidth:                constraints->max_width  = attr_list[i].value.value.i;                break;            case VASurfaceAttribMaxHeight:                constraints->max_height = attr_list[i].value.value.i;                break;            }        }        if (pix_fmt_count == 0) {            // Nothing usable found.  Presumably there exists something which            // works, so leave the set null to indicate unknown.            constraints->valid_sw_formats = NULL;        } else {            constraints->valid_sw_formats = av_malloc_array(pix_fmt_count + 1,                                                            sizeof(pix_fmt));            if (!constraints->valid_sw_formats) {                err = AVERROR(ENOMEM);                goto fail;            }             for (i = j = 0; i < attr_count; i++) {                int k;                 if (attr_list[i].type != VASurfaceAttribPixelFormat)                    continue;                fourcc = attr_list[i].value.value.i;                pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc);                 if (pix_fmt == AV_PIX_FMT_NONE)                    continue;                 for (k = 0; k < j; k++) {                    if (constraints->valid_sw_formats[k] == pix_fmt)                        break;                }                 if (k == j)                    constraints->valid_sw_formats[j++] = pix_fmt;            }            constraints->valid_sw_formats[j] = AV_PIX_FMT_NONE;        }    } else {        // No configuration supplied.        // Return the full set of image formats known by the implementation.        constraints->valid_sw_formats = av_malloc_array(ctx->nb_formats + 1,                                                        sizeof(pix_fmt));        if (!constraints->valid_sw_formats) {            err = AVERROR(ENOMEM);            goto fail;        }        for (i = j = 0; i < ctx->nb_formats; i++) {            int k;             for (k = 0; k < j; k++) {                if (constraints->valid_sw_formats[k] == ctx->formats[i].pix_fmt)                    break;            }             if (k == j)                constraints->valid_sw_formats[j++] = ctx->formats[i].pix_fmt;        }         constraints->valid_sw_formats[j] = AV_PIX_FMT_NONE;    }     constraints->valid_hw_formats = av_malloc_array(2, sizeof(pix_fmt));    if (!constraints->valid_hw_formats) {        err = AVERROR(ENOMEM);        goto fail;    }    constraints->valid_hw_formats[0] = AV_PIX_FMT_VAAPI;    constraints->valid_hw_formats[1] = AV_PIX_FMT_NONE;     err = 0;fail:    av_freep(&attr_list);    return err;} static const struct {    const char *friendly_name;    const char *match_string;    unsigned int quirks;} vaapi_driver_quirks_table[] = {#if !VA_CHECK_VERSION(1, 0, 0)    // The i965 driver did not conform before version 2.0.    {        "Intel i965 (Quick Sync)",        "i965",        AV_VAAPI_DRIVER_QUIRK_RENDER_PARAM_BUFFERS,    },#endif    {        "Intel iHD",        "ubit",        AV_VAAPI_DRIVER_QUIRK_ATTRIB_MEMTYPE,    },    {        "VDPAU wrapper",        "Splitted-Desktop Systems VDPAU backend for VA-API",        AV_VAAPI_DRIVER_QUIRK_SURFACE_ATTRIBUTES,    },}; static int vaapi_device_init(AVHWDeviceContext *hwdev){    VAAPIDeviceContext *ctx = hwdev->hwctx;    AVVAAPIDeviceContext *hwctx = &ctx->p;    VAImageFormat *image_list = NULL;    VAStatus vas;    const char *vendor_string;    int err, i, image_count;    enum AVPixelFormat pix_fmt;    unsigned int fourcc;     image_count = vaMaxNumImageFormats(hwctx->display);    if (image_count <= 0) {        err = AVERROR(EIO);        goto fail;    }    image_list = av_malloc(image_count * sizeof(*image_list));    if (!image_list) {        err = AVERROR(ENOMEM);        goto fail;    }    vas = vaQueryImageFormats(hwctx->display, image_list, &image_count);    if (vas != VA_STATUS_SUCCESS) {        err = AVERROR(EIO);        goto fail;    }     ctx->formats  = av_malloc(image_count * sizeof(*ctx->formats));    if (!ctx->formats) {        err = AVERROR(ENOMEM);        goto fail;    }    ctx->nb_formats = 0;    for (i = 0; i < image_count; i++) {        fourcc  = image_list[i].fourcc;        pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc);        if (pix_fmt == AV_PIX_FMT_NONE) {            av_log(hwdev, AV_LOG_DEBUG, "Format %#x -> unknown.\n",                   fourcc);        } else {            av_log(hwdev, AV_LOG_DEBUG, "Format %#x -> %s.\n",                   fourcc, av_get_pix_fmt_name(pix_fmt));            ctx->formats[ctx->nb_formats].pix_fmt      = pix_fmt;            ctx->formats[ctx->nb_formats].image_format = image_list[i];            ++ctx->nb_formats;        }    }     vendor_string = vaQueryVendorString(hwctx->display);    if (vendor_string)        av_log(hwdev, AV_LOG_VERBOSE, "VAAPI driver: %s.\n", vendor_string);     if (hwctx->driver_quirks & AV_VAAPI_DRIVER_QUIRK_USER_SET) {        av_log(hwdev, AV_LOG_VERBOSE, "Using quirks set by user (%#x).\n",               hwctx->driver_quirks);    } else {        // Detect the driver in use and set quirk flags if necessary.        hwctx->driver_quirks = 0;        if (vendor_string) {            for (i = 0; i < FF_ARRAY_ELEMS(vaapi_driver_quirks_table); i++) {                if (strstr(vendor_string,                           vaapi_driver_quirks_table[i].match_string)) {                    av_log(hwdev, AV_LOG_VERBOSE, "Matched driver string "                           "as known nonstandard driver \"%s\", setting "                           "quirks (%#x).\n",                           vaapi_driver_quirks_table[i].friendly_name,                           vaapi_driver_quirks_table[i].quirks);                    hwctx->driver_quirks |=                        vaapi_driver_quirks_table[i].quirks;                    break;                }            }            if (!(i < FF_ARRAY_ELEMS(vaapi_driver_quirks_table))) {                av_log(hwdev, AV_LOG_VERBOSE, "Driver not found in known "                       "nonstandard list, using standard behaviour.\n");            }        } else {            av_log(hwdev, AV_LOG_VERBOSE, "Driver has no vendor string, "                   "assuming standard behaviour.\n");        }    }     av_free(image_list);    return 0;fail:    av_freep(&ctx->formats);    av_free(image_list);    return err;} static void vaapi_device_uninit(AVHWDeviceContext *hwdev){    VAAPIDeviceContext *ctx = hwdev->hwctx;     av_freep(&ctx->formats);} static void vaapi_buffer_free(void *opaque, uint8_t *data){    AVHWFramesContext     *hwfc = opaque;    AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;    VASurfaceID surface_id;    VAStatus vas;     surface_id = (VASurfaceID)(uintptr_t)data; 

Lines 1–500 of 2083.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t