#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
#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),
#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
return 0;
}
}
- return AVERROR(EINVAL);
+ return AVERROR(ENOSYS);
}
static int vaapi_frames_get_constraints(AVHWDeviceContext *hwdev,
err = vaapi_get_image_format(hwfc->device_ctx, dst->format, &image_format);
if (err < 0) {
// Requested format is not a valid output format.
- return AVERROR(EINVAL);
+ return err;
}
map = av_malloc(sizeof(*map));
if (dst->format != AV_PIX_FMT_NONE) {
err = vaapi_get_image_format(hwfc->device_ctx, dst->format, NULL);
if (err < 0)
- return AVERROR(ENOSYS);
+ return err;
}
err = vaapi_map_frame(hwfc, dst, src, flags);
#if defined(VA_FOURCC_P010) && defined(DRM_FORMAT_R16)
DRM_MAP(P010, 2, DRM_FORMAT_R16, DRM_FORMAT_RG1616),
#endif
+#if defined(VA_FOURCC_P012) && defined(DRM_FORMAT_R16)
+ DRM_MAP(P012, 2, DRM_FORMAT_R16, DRM_FORMAT_RG1616),
+#endif
DRM_MAP(BGRA, 1, DRM_FORMAT_ARGB8888),
DRM_MAP(BGRX, 1, DRM_FORMAT_XRGB8888),
DRM_MAP(RGBA, 1, DRM_FORMAT_ABGR8888),
#endif
DRM_MAP(ARGB, 1, DRM_FORMAT_BGRA8888),
DRM_MAP(XRGB, 1, DRM_FORMAT_BGRX8888),
+#if defined(VA_FOURCC_XYUV) && defined(DRM_FORMAT_XYUV8888)
+ DRM_MAP(XYUV, 1, DRM_FORMAT_XYUV8888),
+#endif
+#if defined(VA_FOURCC_Y412) && defined(DRM_FORMAT_XVYU2101010)
+ DRM_MAP(Y410, 1, DRM_FORMAT_XVYU2101010),
+#endif
+#if defined(VA_FOURCC_Y412) && defined(DRM_FORMAT_XVYU12_16161616)
+ DRM_MAP(Y412, 1, DRM_FORMAT_XVYU12_16161616),
+#endif
+#if defined(VA_FOURCC_X2R10G10B10) && defined(DRM_FORMAT_XRGB2101010)
+ DRM_MAP(X2R10G10B10, 1, DRM_FORMAT_XRGB2101010),
+#endif
};
#undef DRM_MAP
surface_id = (VASurfaceID)(uintptr_t)src->data[3];
export_flags = VA_EXPORT_SURFACE_SEPARATE_LAYERS;
- if (flags & AV_HWFRAME_MAP_READ)
+ if (flags & AV_HWFRAME_MAP_READ) {
export_flags |= VA_EXPORT_SURFACE_READ_ONLY;
+
+ vas = vaSyncSurface(hwctx->display, surface_id);
+ if (vas != VA_STATUS_SUCCESS) {
+ av_log(hwfc, AV_LOG_ERROR, "Failed to sync surface "
+ "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
+ return AVERROR(EIO);
+ }
+ }
+
if (flags & AV_HWFRAME_MAP_WRITE)
export_flags |= VA_EXPORT_SURFACE_WRITE_ONLY;
goto fail_derived;
}
- av_log(hwfc, AV_LOG_DEBUG, "DRM PRIME fd is %ld.\n",
+ av_log(hwfc, AV_LOG_DEBUG, "DRM PRIME fd is %"PRIdPTR".\n",
mapping->buffer_info.handle);
mapping->drm_desc.nb_objects = 1;
VAAPIDevicePriv *priv;
VADisplay display = NULL;
const AVDictionaryEntry *ent;
- int try_drm, try_x11, try_all;
+ int try_drm, try_x11, try_win32, try_all;
priv = av_mallocz(sizeof(*priv));
if (!priv)
ent = av_dict_get(opts, "connection_type", NULL, 0);
if (ent) {
- try_all = try_drm = try_x11 = 0;
+ try_all = try_drm = try_x11 = try_win32 = 0;
if (!strcmp(ent->value, "drm")) {
try_drm = 1;
} else if (!strcmp(ent->value, "x11")) {
try_x11 = 1;
+ } else if (!strcmp(ent->value, "win32")) {
+ try_win32 = 1;
} else {
av_log(ctx, AV_LOG_ERROR, "Invalid connection type %s.\n",
ent->value);
try_all = 1;
try_drm = HAVE_VAAPI_DRM;
try_x11 = HAVE_VAAPI_X11;
+ try_win32 = HAVE_VAAPI_WIN32;
}
#if HAVE_VAAPI_DRM
char path[64];
int n, max_devices = 8;
#if CONFIG_LIBDRM
+ drmVersion *info;
const AVDictionaryEntry *kernel_driver;
kernel_driver = av_dict_get(opts, "kernel_driver", NULL, 0);
#endif
break;
}
#if CONFIG_LIBDRM
+ info = drmGetVersion(priv->drm_fd);
+ if (!info) {
+ av_log(ctx, AV_LOG_VERBOSE,
+ "Failed to get DRM version for device %d.\n", n);
+ close(priv->drm_fd);
+ priv->drm_fd = -1;
+ continue;
+ }
if (kernel_driver) {
- drmVersion *info;
- info = drmGetVersion(priv->drm_fd);
if (strcmp(kernel_driver->value, info->name)) {
av_log(ctx, AV_LOG_VERBOSE, "Ignoring device %d "
"with non-matching kernel driver (%s).\n",
"with matching kernel driver (%s).\n",
n, info->name);
drmFreeVersion(info);
- } else
-#endif
- {
- av_log(ctx, AV_LOG_VERBOSE, "Trying to use "
- "DRM render node for device %d.\n", n);
+ break;
+ // drmGetVersion() ensures |info->name| is 0-terminated.
+ } else if (!strcmp(info->name, "vgem")) {
+ av_log(ctx, AV_LOG_VERBOSE,
+ "Skipping vgem node for device %d.\n", n);
+ drmFreeVersion(info);
+ close(priv->drm_fd);
+ priv->drm_fd = -1;
+ continue;
}
+ drmFreeVersion(info);
+#endif
+ av_log(ctx, AV_LOG_VERBOSE, "Trying to use "
+ "DRM render node for device %d.\n", n);
break;
}
if (n >= max_devices)
}
#endif
+#if HAVE_VAAPI_WIN32
+ if (!display && try_win32) {
+ // Try to create a display from the specified device, if any.
+ if (!device) {
+ display = vaGetDisplayWin32(NULL);
+ } else {
+ IDXGIFactory2 *pDXGIFactory = NULL;
+ IDXGIAdapter *pAdapter = NULL;
+#if !HAVE_UWP
+ HANDLE dxgi = dlopen("dxgi.dll", 0);
+ if (!dxgi) {
+ av_log(ctx, AV_LOG_ERROR, "Failed to load dxgi.dll\n");
+ return AVERROR_UNKNOWN;
+ }
+ PFN_CREATE_DXGI_FACTORY pfnCreateDXGIFactory =
+ (PFN_CREATE_DXGI_FACTORY)dlsym(dxgi, "CreateDXGIFactory");
+ if (!pfnCreateDXGIFactory) {
+ av_log(ctx, AV_LOG_ERROR, "CreateDXGIFactory load failed\n");
+ dlclose(dxgi);
+ return AVERROR_UNKNOWN;
+ }
+#else
+ // In UWP (which lacks LoadLibrary), CreateDXGIFactory isn't
+ // available, only CreateDXGIFactory1
+ PFN_CREATE_DXGI_FACTORY pfnCreateDXGIFactory =
+ (PFN_CREATE_DXGI_FACTORY)CreateDXGIFactory1;
+#endif
+ if (SUCCEEDED(pfnCreateDXGIFactory(&IID_IDXGIFactory2,
+ (void **)&pDXGIFactory))) {
+ int adapter = atoi(device);
+ if (SUCCEEDED(IDXGIFactory2_EnumAdapters(pDXGIFactory,
+ adapter,
+ &pAdapter))) {
+ DXGI_ADAPTER_DESC desc;
+ if (SUCCEEDED(IDXGIAdapter2_GetDesc(pAdapter, &desc))) {
+ av_log(ctx, AV_LOG_INFO,
+ "Using device %04x:%04x (%ls) - LUID %lu %ld.\n",
+ desc.VendorId, desc.DeviceId, desc.Description,
+ desc.AdapterLuid.LowPart,
+ desc.AdapterLuid.HighPart);
+ display = vaGetDisplayWin32(&desc.AdapterLuid);
+ }
+ IDXGIAdapter_Release(pAdapter);
+ }
+ IDXGIFactory2_Release(pDXGIFactory);
+ }
+#if !HAVE_UWP
+ dlclose(dxgi);
+#endif
+ }
+
+ if (!display) {
+ av_log(ctx, AV_LOG_ERROR, "Cannot open a VA display "
+ "from Win32 display.\n");
+ return AVERROR_UNKNOWN;
+ }
+
+ av_log(ctx, AV_LOG_VERBOSE, "Opened VA display via "
+ "Win32 display.\n");
+ }
+#endif
+
if (!display) {
if (device)
av_log(ctx, AV_LOG_ERROR, "No VA display found for "