Source code
Revision control
Copy as Markdown
Other Tools
/*↩
* 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"↩
↩
#include <windows.h>↩
↩
#define COBJMACROS↩
↩
#include <initguid.h>↩
#include <d3d11.h>↩
#include <dxgi1_2.h>↩
↩
#if HAVE_DXGIDEBUG_H↩
#include <dxgidebug.h>↩
#endif↩
↩
#include "avassert.h"↩
#include "common.h"↩
#include "hwcontext.h"↩
#include "hwcontext_d3d11va.h"↩
#include "hwcontext_internal.h"↩
#include "imgutils.h"↩
#include "pixdesc.h"↩
#include "pixfmt.h"↩
#include "thread.h"↩
#include "compat/w32dlfcn.h"↩
↩
typedef HRESULT(WINAPI *PFN_CREATE_DXGI_FACTORY)(REFIID riid, void **ppFactory);↩
↩
static AVOnce functions_loaded = AV_ONCE_INIT;↩
↩
static PFN_CREATE_DXGI_FACTORY mCreateDXGIFactory;↩
static PFN_D3D11_CREATE_DEVICE mD3D11CreateDevice;↩
↩
static av_cold void load_functions(void)↩
{↩
#if !HAVE_UWP↩
// We let these "leak" - this is fine, as unloading has no great benefit, and↩
// Windows will mark a DLL as loaded forever if its internal refcount overflows↩
// from too many LoadLibrary calls.↩
HANDLE d3dlib, dxgilib;↩
↩
d3dlib = dlopen("d3d11.dll", 0);↩
dxgilib = dlopen("dxgi.dll", 0);↩
if (!d3dlib || !dxgilib)↩
return;↩
↩
mD3D11CreateDevice = (PFN_D3D11_CREATE_DEVICE) GetProcAddress(d3dlib, "D3D11CreateDevice");↩
mCreateDXGIFactory = (PFN_CREATE_DXGI_FACTORY) GetProcAddress(dxgilib, "CreateDXGIFactory1");↩
if (!mCreateDXGIFactory)↩
mCreateDXGIFactory = (PFN_CREATE_DXGI_FACTORY) GetProcAddress(dxgilib, "CreateDXGIFactory");↩
#else↩
// In UWP (which lacks LoadLibrary), CreateDXGIFactory isn't available,↩
// only CreateDXGIFactory1↩
mD3D11CreateDevice = (PFN_D3D11_CREATE_DEVICE) D3D11CreateDevice;↩
mCreateDXGIFactory = (PFN_CREATE_DXGI_FACTORY) CreateDXGIFactory1;↩
#endif↩
}↩
↩
typedef struct D3D11VAFramesContext {↩
/**↩
* The public AVD3D11VAFramesContext. See hwcontext_d3d11va.h for it.↩
*/↩
AVD3D11VAFramesContext p;↩
↩
int nb_surfaces;↩
int nb_surfaces_used;↩
↩
DXGI_FORMAT format;↩
↩
ID3D11Texture2D *staging_texture;↩
} D3D11VAFramesContext;↩
↩
static const struct {↩
DXGI_FORMAT d3d_format;↩
enum AVPixelFormat pix_fmt;↩
} supported_formats[] = {↩
{ DXGI_FORMAT_NV12, AV_PIX_FMT_NV12 },↩
{ DXGI_FORMAT_P010, AV_PIX_FMT_P010 },↩
{ DXGI_FORMAT_B8G8R8A8_UNORM, AV_PIX_FMT_BGRA },↩
{ DXGI_FORMAT_R10G10B10A2_UNORM, AV_PIX_FMT_X2BGR10 },↩
{ DXGI_FORMAT_R16G16B16A16_FLOAT, AV_PIX_FMT_RGBAF16 },↩
{ DXGI_FORMAT_AYUV, AV_PIX_FMT_VUYX },↩
{ DXGI_FORMAT_YUY2, AV_PIX_FMT_YUYV422 },↩
{ DXGI_FORMAT_Y210, AV_PIX_FMT_Y210 },↩
{ DXGI_FORMAT_Y410, AV_PIX_FMT_XV30 },↩
{ DXGI_FORMAT_P016, AV_PIX_FMT_P012 },↩
{ DXGI_FORMAT_Y216, AV_PIX_FMT_Y212 },↩
{ DXGI_FORMAT_Y416, AV_PIX_FMT_XV36 },↩
// Special opaque formats. The pix_fmt is merely a place holder, as the↩
// opaque format cannot be accessed directly.↩
{ DXGI_FORMAT_420_OPAQUE, AV_PIX_FMT_YUV420P },↩
};↩
↩
static void d3d11va_default_lock(void *ctx)↩
{↩
WaitForSingleObjectEx(ctx, INFINITE, FALSE);↩
}↩
↩
static void d3d11va_default_unlock(void *ctx)↩
{↩
ReleaseMutex(ctx);↩
}↩
↩
static void d3d11va_frames_uninit(AVHWFramesContext *ctx)↩
{↩
D3D11VAFramesContext *s = ctx->hwctx;↩
AVD3D11VAFramesContext *frames_hwctx = &s->p;↩
↩
if (frames_hwctx->texture)↩
ID3D11Texture2D_Release(frames_hwctx->texture);↩
frames_hwctx->texture = NULL;↩
↩
if (s->staging_texture)↩
ID3D11Texture2D_Release(s->staging_texture);↩
s->staging_texture = NULL;↩
↩
av_freep(&frames_hwctx->texture_infos);↩
}↩
↩
static int d3d11va_frames_get_constraints(AVHWDeviceContext *ctx,↩
const void *hwconfig,↩
AVHWFramesConstraints *constraints)↩
{↩
AVD3D11VADeviceContext *device_hwctx = ctx->hwctx;↩
int nb_sw_formats = 0;↩
HRESULT hr;↩
int i;↩
↩
constraints->valid_sw_formats = av_malloc_array(FF_ARRAY_ELEMS(supported_formats) + 1,↩
sizeof(*constraints->valid_sw_formats));↩
if (!constraints->valid_sw_formats)↩
return AVERROR(ENOMEM);↩
↩
for (i = 0; i < FF_ARRAY_ELEMS(supported_formats); i++) {↩
UINT format_support = 0;↩
hr = ID3D11Device_CheckFormatSupport(device_hwctx->device, supported_formats[i].d3d_format, &format_support);↩
if (SUCCEEDED(hr) && (format_support & D3D11_FORMAT_SUPPORT_TEXTURE2D))↩
constraints->valid_sw_formats[nb_sw_formats++] = supported_formats[i].pix_fmt;↩
}↩
constraints->valid_sw_formats[nb_sw_formats] = AV_PIX_FMT_NONE;↩
↩
constraints->valid_hw_formats = av_malloc_array(2, sizeof(*constraints->valid_hw_formats));↩
if (!constraints->valid_hw_formats)↩
return AVERROR(ENOMEM);↩
↩
constraints->valid_hw_formats[0] = AV_PIX_FMT_D3D11;↩
constraints->valid_hw_formats[1] = AV_PIX_FMT_NONE;↩
↩
return 0;↩
}↩
↩
static void free_texture(void *opaque, uint8_t *data)↩
{↩
ID3D11Texture2D_Release((ID3D11Texture2D *)opaque);↩
av_free(data);↩
}↩
↩
static AVBufferRef *wrap_texture_buf(AVHWFramesContext *ctx, ID3D11Texture2D *tex, int index)↩
{↩
AVBufferRef *buf;↩
AVD3D11FrameDescriptor *desc = av_mallocz(sizeof(*desc));↩
D3D11VAFramesContext *s = ctx->hwctx;↩
AVD3D11VAFramesContext *frames_hwctx = &s->p;↩
if (!desc) {↩
ID3D11Texture2D_Release(tex);↩
return NULL;↩
}↩
↩
if (s->nb_surfaces <= s->nb_surfaces_used) {↩
frames_hwctx->texture_infos = av_realloc_f(frames_hwctx->texture_infos,↩
s->nb_surfaces_used + 1,↩
sizeof(*frames_hwctx->texture_infos));↩
if (!frames_hwctx->texture_infos) {↩
ID3D11Texture2D_Release(tex);↩
av_free(desc);↩
return NULL;↩
}↩
s->nb_surfaces = s->nb_surfaces_used + 1;↩
}↩
↩
frames_hwctx->texture_infos[s->nb_surfaces_used].texture = tex;↩
frames_hwctx->texture_infos[s->nb_surfaces_used].index = index;↩
s->nb_surfaces_used++;↩
↩
desc->texture = tex;↩
desc->index = index;↩
↩
buf = av_buffer_create((uint8_t *)desc, sizeof(*desc), free_texture, tex, 0);↩
if (!buf) {↩
ID3D11Texture2D_Release(tex);↩
av_free(desc);↩
return NULL;↩
}↩
↩
return buf;↩
}↩
↩
static AVBufferRef *d3d11va_alloc_single(AVHWFramesContext *ctx)↩
{↩
D3D11VAFramesContext *s = ctx->hwctx;↩
AVD3D11VAFramesContext *hwctx = &s->p;↩
AVD3D11VADeviceContext *device_hwctx = ctx->device_ctx->hwctx;↩
HRESULT hr;↩
ID3D11Texture2D *tex;↩
D3D11_TEXTURE2D_DESC texDesc = {↩
.Width = ctx->width,↩
.Height = ctx->height,↩
.MipLevels = 1,↩
.Format = s->format,↩
.SampleDesc = { .Count = 1 },↩
.ArraySize = 1,↩
.Usage = D3D11_USAGE_DEFAULT,↩
.BindFlags = hwctx->BindFlags,↩
.MiscFlags = hwctx->MiscFlags,↩
};↩
↩
hr = ID3D11Device_CreateTexture2D(device_hwctx->device, &texDesc, NULL, &tex);↩
if (FAILED(hr)) {↩
av_log(ctx, AV_LOG_ERROR, "Could not create the texture (%lx)\n", (long)hr);↩
return NULL;↩
}↩
↩
return wrap_texture_buf(ctx, tex, 0);↩
}↩
↩
static AVBufferRef *d3d11va_pool_alloc(void *opaque, size_t size)↩
{↩
AVHWFramesContext *ctx = (AVHWFramesContext*)opaque;↩
D3D11VAFramesContext *s = ctx->hwctx;↩
AVD3D11VAFramesContext *hwctx = &s->p;↩
D3D11_TEXTURE2D_DESC texDesc;↩
↩
if (!hwctx->texture) {↩
return d3d11va_alloc_single(ctx);↩
}↩
↩
ID3D11Texture2D_GetDesc(hwctx->texture, &texDesc);↩
↩
if (s->nb_surfaces_used >= texDesc.ArraySize) {↩
av_log(ctx, AV_LOG_ERROR, "Static surface pool size exceeded.\n");↩
return NULL;↩
}↩
↩
ID3D11Texture2D_AddRef(hwctx->texture);↩
return wrap_texture_buf(ctx, hwctx->texture, s->nb_surfaces_used);↩
}↩
↩
static int d3d11va_frames_init(AVHWFramesContext *ctx)↩
{↩
AVD3D11VADeviceContext *device_hwctx = ctx->device_ctx->hwctx;↩
D3D11VAFramesContext *s = ctx->hwctx;↩
AVD3D11VAFramesContext *hwctx = &s->p;↩
↩
int i;↩
HRESULT hr;↩
D3D11_TEXTURE2D_DESC texDesc;↩
↩
for (i = 0; i < FF_ARRAY_ELEMS(supported_formats); i++) {↩
if (ctx->sw_format == supported_formats[i].pix_fmt) {↩
s->format = supported_formats[i].d3d_format;↩
break;↩
}↩
}↩
if (i == FF_ARRAY_ELEMS(supported_formats)) {↩
av_log(ctx, AV_LOG_ERROR, "Unsupported pixel format: %s\n",↩
av_get_pix_fmt_name(ctx->sw_format));↩
return AVERROR(EINVAL);↩
}↩
↩
texDesc = (D3D11_TEXTURE2D_DESC){↩
.Width = ctx->width,↩
.Height = ctx->height,↩
.MipLevels = 1,↩
.Format = s->format,↩
.SampleDesc = { .Count = 1 },↩
.ArraySize = ctx->initial_pool_size,↩
.Usage = D3D11_USAGE_DEFAULT,↩
.BindFlags = hwctx->BindFlags,↩
.MiscFlags = hwctx->MiscFlags,↩
};↩
↩
if (hwctx->texture) {↩
D3D11_TEXTURE2D_DESC texDesc2;↩
ID3D11Texture2D_GetDesc(hwctx->texture, &texDesc2);↩
↩
if (texDesc.Width != texDesc2.Width ||↩
texDesc.Height != texDesc2.Height ||↩
texDesc.Format != texDesc2.Format) {↩
av_log(ctx, AV_LOG_ERROR, "User-provided texture has mismatching parameters\n");↩
return AVERROR(EINVAL);↩
}↩
↩
ctx->initial_pool_size = texDesc2.ArraySize;↩
hwctx->BindFlags = texDesc2.BindFlags;↩
hwctx->MiscFlags = texDesc2.MiscFlags;↩
} else if (!(texDesc.BindFlags & D3D11_BIND_RENDER_TARGET) && texDesc.ArraySize > 0) {↩
hr = ID3D11Device_CreateTexture2D(device_hwctx->device, &texDesc, NULL, &hwctx->texture);↩
if (FAILED(hr)) {↩
av_log(ctx, AV_LOG_ERROR, "Could not create the texture (%lx)\n", (long)hr);↩
return AVERROR_UNKNOWN;↩
}↩
}↩
↩
hwctx->texture_infos = av_realloc_f(NULL, ctx->initial_pool_size, sizeof(*hwctx->texture_infos));↩
if (!hwctx->texture_infos)↩
return AVERROR(ENOMEM);↩
s->nb_surfaces = ctx->initial_pool_size;↩
↩
ffhwframesctx(ctx)->pool_internal =↩
av_buffer_pool_init2(sizeof(AVD3D11FrameDescriptor),↩
ctx, d3d11va_pool_alloc, NULL);↩
if (!ffhwframesctx(ctx)->pool_internal)↩
return AVERROR(ENOMEM);↩
↩
return 0;↩
}↩
↩
static int d3d11va_get_buffer(AVHWFramesContext *ctx, AVFrame *frame)↩
{↩
AVD3D11FrameDescriptor *desc;↩
↩
frame->buf[0] = av_buffer_pool_get(ctx->pool);↩
if (!frame->buf[0])↩
return AVERROR(ENOMEM);↩
↩
desc = (AVD3D11FrameDescriptor *)frame->buf[0]->data;↩
↩
frame->data[0] = (uint8_t *)desc->texture;↩
frame->data[1] = (uint8_t *)desc->index;↩
frame->format = AV_PIX_FMT_D3D11;↩
frame->width = ctx->width;↩
frame->height = ctx->height;↩
↩
return 0;↩
}↩
↩
static int d3d11va_transfer_get_formats(AVHWFramesContext *ctx,↩
enum AVHWFrameTransferDirection dir,↩
enum AVPixelFormat **formats)↩
{↩
D3D11VAFramesContext *s = ctx->hwctx;↩
enum AVPixelFormat *fmts;↩
↩
fmts = av_malloc_array(2, sizeof(*fmts));↩
if (!fmts)↩
return AVERROR(ENOMEM);↩
↩
fmts[0] = ctx->sw_format;↩
fmts[1] = AV_PIX_FMT_NONE;↩
↩
// Don't signal support for opaque formats. Actual access would fail.↩
if (s->format == DXGI_FORMAT_420_OPAQUE)↩
fmts[0] = AV_PIX_FMT_NONE;↩
↩
*formats = fmts;↩
↩
return 0;↩
}↩
↩
static int d3d11va_create_staging_texture(AVHWFramesContext *ctx, DXGI_FORMAT format)↩
{↩
AVD3D11VADeviceContext *device_hwctx = ctx->device_ctx->hwctx;↩
D3D11VAFramesContext *s = ctx->hwctx;↩
HRESULT hr;↩
D3D11_TEXTURE2D_DESC texDesc = {↩
.Width = ctx->width,↩
.Height = ctx->height,↩
.MipLevels = 1,↩
.Format = format,↩
.SampleDesc = { .Count = 1 },↩
.ArraySize = 1,↩
.Usage = D3D11_USAGE_STAGING,↩
.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE,↩
};↩
↩
hr = ID3D11Device_CreateTexture2D(device_hwctx->device, &texDesc, NULL, &s->staging_texture);↩
if (FAILED(hr)) {↩
av_log(ctx, AV_LOG_ERROR, "Could not create the staging texture (%lx)\n", (long)hr);↩
return AVERROR_UNKNOWN;↩
}↩
↩
return 0;↩
}↩
↩
static void fill_texture_ptrs(uint8_t *data[4], int linesize[4],↩
AVHWFramesContext *ctx,↩
D3D11_TEXTURE2D_DESC *desc,↩
D3D11_MAPPED_SUBRESOURCE *map)↩
{↩
int i;↩
↩
for (i = 0; i < 4; i++)↩
linesize[i] = map->RowPitch;↩
↩
av_image_fill_pointers(data, ctx->sw_format, desc->Height,↩
(uint8_t*)map->pData, linesize);↩
}↩
↩
static int d3d11va_transfer_data(AVHWFramesContext *ctx, AVFrame *dst,↩
const AVFrame *src)↩
{↩
AVD3D11VADeviceContext *device_hwctx = ctx->device_ctx->hwctx;↩
D3D11VAFramesContext *s = ctx->hwctx;↩
int download = src->format == AV_PIX_FMT_D3D11;↩
const AVFrame *frame = download ? src : dst;↩
const AVFrame *other = download ? dst : src;↩
// (The interface types are compatible.)↩
ID3D11Resource *texture = (ID3D11Resource *)(ID3D11Texture2D *)frame->data[0];↩
int index = (intptr_t)frame->data[1];↩
ID3D11Resource *staging;↩
int w = FFMIN(dst->width, src->width);↩
int h = FFMIN(dst->height, src->height);↩
uint8_t *map_data[4];↩
int map_linesize[4];↩
D3D11_TEXTURE2D_DESC desc;↩
D3D11_MAPPED_SUBRESOURCE map;↩
HRESULT hr;↩
int res;↩
↩
if (frame->hw_frames_ctx->data != (uint8_t *)ctx || other->format != ctx->sw_format)↩
return AVERROR(EINVAL);↩
↩
device_hwctx->lock(device_hwctx->lock_ctx);↩
↩
if (!s->staging_texture) {↩
ID3D11Texture2D_GetDesc((ID3D11Texture2D *)texture, &desc);↩
res = d3d11va_create_staging_texture(ctx, desc.Format);↩
if (res < 0)↩
return res;↩
}↩
↩
staging = (ID3D11Resource *)s->staging_texture;↩
↩
ID3D11Texture2D_GetDesc(s->staging_texture, &desc);↩
↩
if (download) {↩
ID3D11DeviceContext_CopySubresourceRegion(device_hwctx->device_context,↩
staging, 0, 0, 0, 0,↩
texture, index, NULL);↩
↩
hr = ID3D11DeviceContext_Map(device_hwctx->device_context,↩
staging, 0, D3D11_MAP_READ, 0, &map);↩
if (FAILED(hr))↩
goto map_failed;↩
↩
fill_texture_ptrs(map_data, map_linesize, ctx, &desc, &map);↩
↩
av_image_copy2(dst->data, dst->linesize, map_data, map_linesize,↩
ctx->sw_format, w, h);↩
↩
ID3D11DeviceContext_Unmap(device_hwctx->device_context, staging, 0);↩
} else {↩
hr = ID3D11DeviceContext_Map(device_hwctx->device_context,↩
staging, 0, D3D11_MAP_WRITE, 0, &map);↩
if (FAILED(hr))↩
goto map_failed;↩
↩
fill_texture_ptrs(map_data, map_linesize, ctx, &desc, &map);↩
↩
av_image_copy2(map_data, map_linesize, src->data, src->linesize,↩
ctx->sw_format, w, h);↩
↩
ID3D11DeviceContext_Unmap(device_hwctx->device_context, staging, 0);↩
↩
ID3D11DeviceContext_CopySubresourceRegion(device_hwctx->device_context,↩
texture, index, 0, 0, 0,↩
staging, 0, NULL);↩
}↩
↩
device_hwctx->unlock(device_hwctx->lock_ctx);↩
return 0;↩
↩
map_failed:↩
av_log(ctx, AV_LOG_ERROR, "Unable to lock D3D11VA surface (%lx)\n", (long)hr);↩
device_hwctx->unlock(device_hwctx->lock_ctx);↩
return AVERROR_UNKNOWN;↩
}↩
↩
static int d3d11va_device_init(AVHWDeviceContext *hwdev)↩
{↩
AVD3D11VADeviceContext *device_hwctx = hwdev->hwctx;↩
HRESULT hr;↩
↩
if (!device_hwctx->lock) {↩
device_hwctx->lock_ctx = CreateMutex(NULL, 0, NULL);↩
if (device_hwctx->lock_ctx == INVALID_HANDLE_VALUE) {↩
av_log(NULL, AV_LOG_ERROR, "Failed to create a mutex\n");↩
return AVERROR(EINVAL);↩
}↩
device_hwctx->lock = d3d11va_default_lock;↩
device_hwctx->unlock = d3d11va_default_unlock;↩
}↩
↩
if (!device_hwctx->device_context) {↩
ID3D11Device_GetImmediateContext(device_hwctx->device, &device_hwctx->device_context);↩
if (!device_hwctx->device_context)↩
return AVERROR_UNKNOWN;↩
}↩
↩
if (!device_hwctx->video_device) {↩
hr = ID3D11DeviceContext_QueryInterface(device_hwctx->device, &IID_ID3D11VideoDevice,↩
(void **)&device_hwctx->video_device);↩
if (FAILED(hr))↩
return AVERROR_UNKNOWN;↩
}↩
↩
if (!device_hwctx->video_context) {↩
hr = ID3D11DeviceContext_QueryInterface(device_hwctx->device_context, &IID_ID3D11VideoContext,↩
(void **)&device_hwctx->video_context);↩
if (FAILED(hr))↩
return AVERROR_UNKNOWN;↩
}↩
↩
return 0;↩
}↩
↩
static void d3d11va_device_uninit(AVHWDeviceContext *hwdev)↩
{↩
AVD3D11VADeviceContext *device_hwctx = hwdev->hwctx;↩
↩
if (device_hwctx->device) {↩
ID3D11Device_Release(device_hwctx->device);↩
device_hwctx->device = NULL;↩
}↩
↩
if (device_hwctx->device_context) {↩
ID3D11DeviceContext_Release(device_hwctx->device_context);↩
device_hwctx->device_context = NULL;↩
}↩
↩
if (device_hwctx->video_device) {↩
ID3D11VideoDevice_Release(device_hwctx->video_device);↩
device_hwctx->video_device = NULL;↩
}↩
↩
if (device_hwctx->video_context) {↩
ID3D11VideoContext_Release(device_hwctx->video_context);↩
device_hwctx->video_context = NULL;↩
}↩
↩
if (device_hwctx->lock == d3d11va_default_lock) {↩
CloseHandle(device_hwctx->lock_ctx);↩
device_hwctx->lock_ctx = INVALID_HANDLE_VALUE;↩
device_hwctx->lock = NULL;↩
}↩
}↩
↩
static int d3d11va_device_find_adapter_by_vendor_id(AVHWDeviceContext *ctx, uint32_t flags, const char *vendor_id)↩
{↩
HRESULT hr;↩
IDXGIAdapter *adapter = NULL;↩
IDXGIFactory2 *factory;↩
int adapter_id = 0;↩
long int id = strtol(vendor_id, NULL, 0);↩
↩
hr = mCreateDXGIFactory(&IID_IDXGIFactory2, (void **)&factory);↩
if (FAILED(hr)) {↩
av_log(ctx, AV_LOG_ERROR, "CreateDXGIFactory returned error\n");↩
return -1;↩
}↩
↩
while (IDXGIFactory2_EnumAdapters(factory, adapter_id++, &adapter) != DXGI_ERROR_NOT_FOUND) {↩
ID3D11Device* device = NULL;↩
DXGI_ADAPTER_DESC adapter_desc;↩
↩
hr = mD3D11CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, NULL, flags, NULL, 0, D3D11_SDK_VERSION, &device, NULL, NULL);↩
if (FAILED(hr)) {↩
av_log(ctx, AV_LOG_DEBUG, "D3D11CreateDevice returned error, try next adapter\n");↩
IDXGIAdapter_Release(adapter);↩
continue;↩
}↩
↩
hr = IDXGIAdapter2_GetDesc(adapter, &adapter_desc);↩
ID3D11Device_Release(device);↩
IDXGIAdapter_Release(adapter);↩
if (FAILED(hr)) {↩
av_log(ctx, AV_LOG_DEBUG, "IDXGIAdapter2_GetDesc returned error, try next adapter\n");↩
continue;↩
} else if (adapter_desc.VendorId == id) {↩
IDXGIFactory2_Release(factory);↩
return adapter_id - 1;↩
}↩
}↩
↩
IDXGIFactory2_Release(factory);↩
return -1;↩
}↩
↩
static int d3d11va_device_create(AVHWDeviceContext *ctx, const char *device,↩
AVDictionary *opts, int flags)↩
{↩
AVD3D11VADeviceContext *device_hwctx = ctx->hwctx;↩
↩
HRESULT hr;↩
IDXGIAdapter *pAdapter = NULL;↩
ID3D10Multithread *pMultithread;↩
UINT creationFlags = D3D11_CREATE_DEVICE_VIDEO_SUPPORT;↩
int is_debug = !!av_dict_get(opts, "debug", NULL, 0);↩
int ret;↩
int adapter = -1;↩
↩
if (is_debug) {↩
creationFlags |= D3D11_CREATE_DEVICE_DEBUG;↩
av_log(ctx, AV_LOG_INFO, "Enabling d3d11 debugging.\n");↩
}↩
↩
if ((ret = ff_thread_once(&functions_loaded, load_functions)) != 0)↩
return AVERROR_UNKNOWN;↩
if (!mD3D11CreateDevice || !mCreateDXGIFactory) {↩
av_log(ctx, AV_LOG_ERROR, "Failed to load D3D11 library or its functions\n");↩
return AVERROR_UNKNOWN;↩
}↩
↩
if (device) {↩
adapter = atoi(device);↩
} else {↩
AVDictionaryEntry *e = av_dict_get(opts, "vendor_id", NULL, 0);↩
if (e && e->value) {↩
adapter = d3d11va_device_find_adapter_by_vendor_id(ctx, creationFlags, e->value);↩
if (adapter < 0) {↩
av_log(ctx, AV_LOG_ERROR, "Failed to find d3d11va adapter by "↩
"vendor id %s\n", e->value);↩
return AVERROR_UNKNOWN;↩
}↩
}↩
}↩
↩
if (adapter >= 0) {↩
IDXGIFactory2 *pDXGIFactory;↩
↩
av_log(ctx, AV_LOG_VERBOSE, "Selecting d3d11va adapter %d\n", adapter);↩
hr = mCreateDXGIFactory(&IID_IDXGIFactory2, (void **)&pDXGIFactory);↩
if (SUCCEEDED(hr)) {↩
if (FAILED(IDXGIFactory2_EnumAdapters(pDXGIFactory, adapter, &pAdapter)))↩
pAdapter = NULL;↩
IDXGIFactory2_Release(pDXGIFactory);↩
}↩
}↩
↩
if (pAdapter) {↩
DXGI_ADAPTER_DESC desc;↩
hr = IDXGIAdapter2_GetDesc(pAdapter, &desc);↩
if (!FAILED(hr)) {↩
av_log(ctx, AV_LOG_INFO, "Using device %04x:%04x (%ls).\n",↩
desc.VendorId, desc.DeviceId, desc.Description);↩
}↩
}↩
↩
hr = mD3D11CreateDevice(pAdapter, pAdapter ? D3D_DRIVER_TYPE_UNKNOWN : D3D_DRIVER_TYPE_HARDWARE, NULL, creationFlags, NULL, 0,↩
D3D11_SDK_VERSION, &device_hwctx->device, NULL, NULL);↩
if (pAdapter)↩
IDXGIAdapter_Release(pAdapter);↩
if (FAILED(hr)) {↩
av_log(ctx, AV_LOG_ERROR, "Failed to create Direct3D device (%lx)\n", (long)hr);↩
return AVERROR_UNKNOWN;↩
}↩
↩
hr = ID3D11Device_QueryInterface(device_hwctx->device, &IID_ID3D10Multithread, (void **)&pMultithread);↩
if (SUCCEEDED(hr)) {↩
ID3D10Multithread_SetMultithreadProtected(pMultithread, TRUE);↩
ID3D10Multithread_Release(pMultithread);↩
}↩
↩
#if !HAVE_UWP && HAVE_DXGIDEBUG_H↩
if (is_debug) {↩
HANDLE dxgidebug_dll = LoadLibrary("dxgidebug.dll");↩
if (dxgidebug_dll) {↩
HRESULT (WINAPI * pf_DXGIGetDebugInterface)(const GUID *riid, void **ppDebug)↩
= (void *)GetProcAddress(dxgidebug_dll, "DXGIGetDebugInterface");↩
if (pf_DXGIGetDebugInterface) {↩
IDXGIDebug *dxgi_debug = NULL;↩
hr = pf_DXGIGetDebugInterface(&IID_IDXGIDebug, (void**)&dxgi_debug);↩
if (SUCCEEDED(hr) && dxgi_debug) {↩
IDXGIDebug_ReportLiveObjects(dxgi_debug, DXGI_DEBUG_ALL, DXGI_DEBUG_RLO_ALL);↩
av_log(ctx, AV_LOG_INFO, "Enabled dxgi debugging.\n");↩
} else {↩
av_log(ctx, AV_LOG_WARNING, "Failed enabling dxgi debugging.\n");↩
}↩
} else {↩
av_log(ctx, AV_LOG_WARNING, "Failed getting dxgi debug interface.\n");↩
}↩
} else {↩
av_log(ctx, AV_LOG_WARNING, "Failed loading dxgi debug library.\n");↩
}↩
}↩
#endif↩
↩
return 0;↩
}↩
↩
const HWContextType ff_hwcontext_type_d3d11va = {↩
.type = AV_HWDEVICE_TYPE_D3D11VA,↩
.name = "D3D11VA",↩
↩
.device_hwctx_size = sizeof(AVD3D11VADeviceContext),↩
.frames_hwctx_size = sizeof(D3D11VAFramesContext),↩
↩
.device_create = d3d11va_device_create,↩
.device_init = d3d11va_device_init,↩
.device_uninit = d3d11va_device_uninit,↩
.frames_get_constraints = d3d11va_frames_get_constraints,↩
.frames_init = d3d11va_frames_init,↩
.frames_uninit = d3d11va_frames_uninit,↩
.frames_get_buffer = d3d11va_get_buffer,↩
.transfer_get_formats = d3d11va_transfer_get_formats,↩
.transfer_data_to = d3d11va_transfer_data,↩
.transfer_data_from = d3d11va_transfer_data,↩
↩
.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_D3D11, AV_PIX_FMT_NONE },↩
};↩