/* * 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. Load more
/* * 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;