| @@ -0,0 +1,490 @@ |
| 1 | +/* |
| 2 | + * This file is part of Libav. |
| 3 | + * |
| 4 | + * Libav 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 | + * Libav 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 Libav; if not, write to the Free Software |
| 16 | + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
| 17 | + */ |
| 18 | + |
| 19 | +#include <windows.h> |
| 20 | + |
| 21 | +#if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0600 |
| 22 | +#undef _WIN32_WINNT |
| 23 | +#define _WIN32_WINNT 0x0600 |
| 24 | +#endif |
| 25 | +#define COBJMACROS |
| 26 | + |
| 27 | +#include <initguid.h> |
| 28 | +#include <d3d11.h> |
| 29 | +#include <dxgi1_2.h> |
| 30 | + |
| 31 | +#include "avassert.h" |
| 32 | +#include "common.h" |
| 33 | +#include "hwcontext.h" |
| 34 | +#include "hwcontext_d3d11va.h" |
| 35 | +#include "hwcontext_internal.h" |
| 36 | +#include "imgutils.h" |
| 37 | +#include "pixdesc.h" |
| 38 | +#include "pixfmt.h" |
| 39 | + |
| 40 | +typedef HRESULT(WINAPI *PFN_CREATE_DXGI_FACTORY)(REFIID riid, void **ppFactory); |
| 41 | + |
| 42 | +typedef struct D3D11VAFramesContext { |
| 43 | + int nb_surfaces_used; |
| 44 | + |
| 45 | + DXGI_FORMAT format; |
| 46 | + |
| 47 | + ID3D11Texture2D *staging_texture; |
| 48 | +} D3D11VAFramesContext; |
| 49 | + |
| 50 | +static const struct { |
| 51 | + DXGI_FORMAT d3d_format; |
| 52 | + enum AVPixelFormat pix_fmt; |
| 53 | +} supported_formats[] = { |
| 54 | + { DXGI_FORMAT_NV12, AV_PIX_FMT_NV12 }, |
| 55 | + { DXGI_FORMAT_P010, AV_PIX_FMT_P010 }, |
| 56 | +}; |
| 57 | + |
| 58 | +static void d3d11va_default_lock(void *ctx) |
| 59 | +{ |
| 60 | + WaitForSingleObjectEx(ctx, INFINITE, FALSE); |
| 61 | +} |
| 62 | + |
| 63 | +static void d3d11va_default_unlock(void *ctx) |
| 64 | +{ |
| 65 | + ReleaseMutex(ctx); |
| 66 | +} |
| 67 | + |
| 68 | +static void d3d11va_frames_uninit(AVHWFramesContext *ctx) |
| 69 | +{ |
| 70 | + AVD3D11VAFramesContext *frames_hwctx = ctx->hwctx; |
| 71 | + D3D11VAFramesContext *s = ctx->internal->priv; |
| 72 | + |
| 73 | + if (frames_hwctx->texture) |
| 74 | + ID3D11Texture2D_Release(frames_hwctx->texture); |
| 75 | + |
| 76 | + if (s->staging_texture) |
| 77 | + ID3D11Texture2D_Release(s->staging_texture); |
| 78 | +} |
| 79 | + |
| 80 | +static void free_texture(void *opaque, uint8_t *data) |
| 81 | +{ |
| 82 | + ID3D11Texture2D_Release((ID3D11Texture2D *)opaque); |
| 83 | +} |
| 84 | + |
| 85 | +static AVBufferRef *wrap_texture_buf(ID3D11Texture2D *tex, int index) |
| 86 | +{ |
| 87 | + AVBufferRef *buf; |
| 88 | + AVD3D11FrameDescriptor *desc = av_mallocz(sizeof(*desc)); |
| 89 | + if (!desc) { |
| 90 | + ID3D11Texture2D_Release(tex); |
| 91 | + return NULL; |
| 92 | + } |
| 93 | + |
| 94 | + desc->texture = tex; |
| 95 | + desc->index = index; |
| 96 | + |
| 97 | + buf = av_buffer_create((uint8_t *)desc, sizeof(desc), free_texture, tex, 0); |
| 98 | + if (!buf) { |
| 99 | + ID3D11Texture2D_Release(tex); |
| 100 | + av_free(desc); |
| 101 | + return NULL; |
| 102 | + } |
| 103 | + |
| 104 | + return buf; |
| 105 | +} |
| 106 | + |
| 107 | +static AVBufferRef *d3d11va_alloc_single(AVHWFramesContext *ctx) |
| 108 | +{ |
| 109 | + D3D11VAFramesContext *s = ctx->internal->priv; |
| 110 | + AVD3D11VAFramesContext *hwctx = ctx->hwctx; |
| 111 | + AVD3D11VADeviceContext *device_hwctx = ctx->device_ctx->hwctx; |
| 112 | + HRESULT hr; |
| 113 | + ID3D11Texture2D *tex; |
| 114 | + D3D11_TEXTURE2D_DESC texDesc = { |
| 115 | + .Width = ctx->width, |
| 116 | + .Height = ctx->height, |
| 117 | + .MipLevels = 1, |
| 118 | + .Format = s->format, |
| 119 | + .SampleDesc = { .Count = 1 }, |
| 120 | + .ArraySize = 1, |
| 121 | + .Usage = D3D11_USAGE_DEFAULT, |
| 122 | + .BindFlags = hwctx->BindFlags, |
| 123 | + .MiscFlags = hwctx->MiscFlags, |
| 124 | + }; |
| 125 | + |
| 126 | + hr = ID3D11Device_CreateTexture2D(device_hwctx->device, &texDesc, NULL, &tex); |
| 127 | + if (FAILED(hr)) { |
| 128 | + av_log(ctx, AV_LOG_ERROR, "Could not create the texture (%lx)\n", (long)hr); |
| 129 | + return NULL; |
| 130 | + } |
| 131 | + |
| 132 | + return wrap_texture_buf(tex, 0); |
| 133 | +} |
| 134 | + |
| 135 | +static AVBufferRef *d3d11va_pool_alloc(void *opaque, int size) |
| 136 | +{ |
| 137 | + AVHWFramesContext *ctx = (AVHWFramesContext*)opaque; |
| 138 | + D3D11VAFramesContext *s = ctx->internal->priv; |
| 139 | + AVD3D11VAFramesContext *hwctx = ctx->hwctx; |
| 140 | + D3D11_TEXTURE2D_DESC texDesc; |
| 141 | + |
| 142 | + if (!hwctx->texture) |
| 143 | + return d3d11va_alloc_single(ctx); |
| 144 | + |
| 145 | + ID3D11Texture2D_GetDesc(hwctx->texture, &texDesc); |
| 146 | + |
| 147 | + if (s->nb_surfaces_used >= texDesc.ArraySize) { |
| 148 | + av_log(ctx, AV_LOG_ERROR, "Static surface pool size exceeded.\n"); |
| 149 | + return NULL; |
| 150 | + } |
| 151 | + |
| 152 | + ID3D11Texture2D_AddRef(hwctx->texture); |
| 153 | + return wrap_texture_buf(hwctx->texture, s->nb_surfaces_used++); |
| 154 | +} |
| 155 | + |
| 156 | +static int d3d11va_frames_init(AVHWFramesContext *ctx) |
| 157 | +{ |
| 158 | + AVD3D11VAFramesContext *hwctx = ctx->hwctx; |
| 159 | + AVD3D11VADeviceContext *device_hwctx = ctx->device_ctx->hwctx; |
| 160 | + D3D11VAFramesContext *s = ctx->internal->priv; |
| 161 | + |
| 162 | + int i; |
| 163 | + HRESULT hr; |
| 164 | + D3D11_TEXTURE2D_DESC texDesc; |
| 165 | + |
| 166 | + for (i = 0; i < FF_ARRAY_ELEMS(supported_formats); i++) { |
| 167 | + if (ctx->sw_format == supported_formats[i].pix_fmt) { |
| 168 | + s->format = supported_formats[i].d3d_format; |
| 169 | + break; |
| 170 | + } |
| 171 | + } |
| 172 | + if (i == FF_ARRAY_ELEMS(supported_formats)) { |
| 173 | + av_log(ctx, AV_LOG_ERROR, "Unsupported pixel format: %s\n", |
| 174 | + av_get_pix_fmt_name(ctx->sw_format)); |
| 175 | + return AVERROR(EINVAL); |
| 176 | + } |
| 177 | + |
| 178 | + texDesc = (D3D11_TEXTURE2D_DESC){ |
| 179 | + .Width = ctx->width, |
| 180 | + .Height = ctx->height, |
| 181 | + .MipLevels = 1, |
| 182 | + .Format = s->format, |
| 183 | + .SampleDesc = { .Count = 1 }, |
| 184 | + .ArraySize = ctx->initial_pool_size, |
| 185 | + .Usage = D3D11_USAGE_DEFAULT, |
| 186 | + .BindFlags = hwctx->BindFlags, |
| 187 | + .MiscFlags = hwctx->MiscFlags, |
| 188 | + }; |
| 189 | + |
| 190 | + if (hwctx->texture) { |
| 191 | + D3D11_TEXTURE2D_DESC texDesc2; |
| 192 | + ID3D11Texture2D_GetDesc(hwctx->texture, &texDesc2); |
| 193 | + |
| 194 | + if (texDesc.Width != texDesc2.Width || |
| 195 | + texDesc.Height != texDesc2.Height || |
| 196 | + texDesc.Format != texDesc2.Format) { |
| 197 | + av_log(ctx, AV_LOG_ERROR, "User-provided texture has mismatching parameters\n"); |
| 198 | + return AVERROR(EINVAL); |
| 199 | + } |
| 200 | + } else if (texDesc.ArraySize > 0) { |
| 201 | + hr = ID3D11Device_CreateTexture2D(device_hwctx->device, &texDesc, NULL, &hwctx->texture); |
| 202 | + if (FAILED(hr)) { |
| 203 | + av_log(ctx, AV_LOG_ERROR, "Could not create the texture (%lx)\n", (long)hr); |
| 204 | + return AVERROR_UNKNOWN; |
| 205 | + } |
| 206 | + } |
| 207 | + |
| 208 | + texDesc.ArraySize = 1; |
| 209 | + texDesc.Usage = D3D11_USAGE_STAGING; |
| 210 | + texDesc.BindFlags = 0; |
| 211 | + texDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE; |
| 212 | + texDesc.MiscFlags = 0; |
| 213 | + hr = ID3D11Device_CreateTexture2D(device_hwctx->device, &texDesc, NULL, &s->staging_texture); |
| 214 | + if (FAILED(hr)) { |
| 215 | + av_log(ctx, AV_LOG_ERROR, "Could not create the staging texture (%lx)\n", (long)hr); |
| 216 | + return AVERROR_UNKNOWN; |
| 217 | + } |
| 218 | + |
| 219 | + ctx->internal->pool_internal = av_buffer_pool_init2(sizeof(AVD3D11FrameDescriptor), |
| 220 | + ctx, d3d11va_pool_alloc, NULL); |
| 221 | + if (!ctx->internal->pool_internal) |
| 222 | + return AVERROR(ENOMEM); |
| 223 | + |
| 224 | + return 0; |
| 225 | +} |
| 226 | + |
| 227 | +static int d3d11va_get_buffer(AVHWFramesContext *ctx, AVFrame *frame) |
| 228 | +{ |
| 229 | + AVD3D11FrameDescriptor *desc; |
| 230 | + |
| 231 | + frame->buf[0] = av_buffer_pool_get(ctx->pool); |
| 232 | + if (!frame->buf[0]) |
| 233 | + return AVERROR(ENOMEM); |
| 234 | + |
| 235 | + desc = (AVD3D11FrameDescriptor *)frame->buf[0]->data; |
| 236 | + |
| 237 | + frame->data[0] = (uint8_t *)desc->texture; |
| 238 | + frame->data[1] = (uint8_t *)desc->index; |
| 239 | + frame->format = AV_PIX_FMT_D3D11; |
| 240 | + frame->width = ctx->width; |
| 241 | + frame->height = ctx->height; |
| 242 | + |
| 243 | + return 0; |
| 244 | +} |
| 245 | + |
| 246 | +static int d3d11va_transfer_get_formats(AVHWFramesContext *ctx, |
| 247 | + enum AVHWFrameTransferDirection dir, |
| 248 | + enum AVPixelFormat **formats) |
| 249 | +{ |
| 250 | + enum AVPixelFormat *fmts; |
| 251 | + |
| 252 | + fmts = av_malloc_array(2, sizeof(*fmts)); |
| 253 | + if (!fmts) |
| 254 | + return AVERROR(ENOMEM); |
| 255 | + |
| 256 | + fmts[0] = ctx->sw_format; |
| 257 | + fmts[1] = AV_PIX_FMT_NONE; |
| 258 | + |
| 259 | + *formats = fmts; |
| 260 | + |
| 261 | + return 0; |
| 262 | +} |
| 263 | + |
| 264 | +static void fill_texture_ptrs(uint8_t *data[4], int linesize[4], |
| 265 | + AVHWFramesContext *ctx, |
| 266 | + D3D11_TEXTURE2D_DESC *desc, |
| 267 | + D3D11_MAPPED_SUBRESOURCE *map) |
| 268 | +{ |
| 269 | + int i; |
| 270 | + |
| 271 | + for (i = 0; i < 4; i++) |
| 272 | + linesize[i] = map->RowPitch; |
| 273 | + |
| 274 | + av_image_fill_pointers(data, ctx->sw_format, desc->Height, |
| 275 | + (uint8_t*)map->pData, linesize); |
| 276 | +} |
| 277 | + |
| 278 | +static int d3d11va_transfer_data(AVHWFramesContext *ctx, AVFrame *dst, |
| 279 | + const AVFrame *src) |
| 280 | +{ |
| 281 | + AVD3D11VADeviceContext *device_hwctx = ctx->device_ctx->hwctx; |
| 282 | + D3D11VAFramesContext *s = ctx->internal->priv; |
| 283 | + int download = src->format == AV_PIX_FMT_D3D11; |
| 284 | + const AVFrame *frame = download ? src : dst; |
| 285 | + const AVFrame *other = download ? dst : src; |
| 286 | + // (The interface types are compatible.) |
| 287 | + ID3D11Resource *texture = (ID3D11Resource *)(ID3D11Texture2D *)frame->data[0]; |
| 288 | + int index = (intptr_t)frame->data[1]; |
| 289 | + ID3D11Resource *staging = (ID3D11Resource *)s->staging_texture; |
| 290 | + int w = FFMIN(dst->width, src->width); |
| 291 | + int h = FFMIN(dst->height, src->height); |
| 292 | + uint8_t *map_data[4]; |
| 293 | + int map_linesize[4]; |
| 294 | + D3D11_TEXTURE2D_DESC desc; |
| 295 | + D3D11_MAPPED_SUBRESOURCE map; |
| 296 | + HRESULT hr; |
| 297 | + |
| 298 | + if (frame->hw_frames_ctx->data != (uint8_t *)ctx || other->format != ctx->sw_format) |
| 299 | + return AVERROR(EINVAL); |
| 300 | + |
| 301 | + device_hwctx->lock(device_hwctx->lock_ctx); |
| 302 | + |
| 303 | + ID3D11Texture2D_GetDesc(s->staging_texture, &desc); |
| 304 | + |
| 305 | + if (download) { |
| 306 | + ID3D11DeviceContext_CopySubresourceRegion(device_hwctx->device_context, |
| 307 | + staging, 0, 0, 0, 0, |
| 308 | + texture, index, NULL); |
| 309 | + |
| 310 | + hr = ID3D11DeviceContext_Map(device_hwctx->device_context, |
| 311 | + staging, 0, D3D11_MAP_READ, 0, &map); |
| 312 | + if (FAILED(hr)) |
| 313 | + goto map_failed; |
| 314 | + |
| 315 | + fill_texture_ptrs(map_data, map_linesize, ctx, &desc, &map); |
| 316 | + |
| 317 | + av_image_copy(dst->data, dst->linesize, map_data, map_linesize, |
| 318 | + ctx->sw_format, w, h); |
| 319 | + |
| 320 | + ID3D11DeviceContext_Unmap(device_hwctx->device_context, staging, 0); |
| 321 | + } else { |
| 322 | + hr = ID3D11DeviceContext_Map(device_hwctx->device_context, |
| 323 | + staging, 0, D3D11_MAP_WRITE, 0, &map); |
| 324 | + if (FAILED(hr)) |
| 325 | + goto map_failed; |
| 326 | + |
| 327 | + fill_texture_ptrs(map_data, map_linesize, ctx, &desc, &map); |
| 328 | + |
| 329 | + av_image_copy(map_data, map_linesize, src->data, src->linesize, |
| 330 | + ctx->sw_format, w, h); |
| 331 | + |
| 332 | + ID3D11DeviceContext_Unmap(device_hwctx->device_context, staging, 0); |
| 333 | + |
| 334 | + ID3D11DeviceContext_CopySubresourceRegion(device_hwctx->device_context, |
| 335 | + texture, index, 0, 0, 0, |
| 336 | + staging, 0, NULL); |
| 337 | + } |
| 338 | + |
| 339 | + device_hwctx->unlock(device_hwctx->lock_ctx); |
| 340 | + return 0; |
| 341 | + |
| 342 | +map_failed: |
| 343 | + av_log(ctx, AV_LOG_ERROR, "Unable to lock D3D11VA surface (%lx)\n", (long)hr); |
| 344 | + device_hwctx->unlock(device_hwctx->lock_ctx); |
| 345 | + return AVERROR_UNKNOWN; |
| 346 | +} |
| 347 | + |
| 348 | +static int d3d11va_device_init(AVHWDeviceContext *hwdev) |
| 349 | +{ |
| 350 | + AVD3D11VADeviceContext *device_hwctx = hwdev->hwctx; |
| 351 | + HRESULT hr; |
| 352 | + |
| 353 | + if (!device_hwctx->lock) { |
| 354 | + device_hwctx->lock_ctx = CreateMutex(NULL, 0, NULL); |
| 355 | + if (device_hwctx->lock_ctx == INVALID_HANDLE_VALUE) { |
| 356 | + av_log(NULL, AV_LOG_ERROR, "Failed to create a mutex\n"); |
| 357 | + return AVERROR(EINVAL); |
| 358 | + } |
| 359 | + device_hwctx->lock = d3d11va_default_lock; |
| 360 | + device_hwctx->unlock = d3d11va_default_unlock; |
| 361 | + } |
| 362 | + |
| 363 | + if (!device_hwctx->device_context) { |
| 364 | + ID3D11Device_GetImmediateContext(device_hwctx->device, &device_hwctx->device_context); |
| 365 | + if (!device_hwctx->device_context) |
| 366 | + return AVERROR_UNKNOWN; |
| 367 | + } |
| 368 | + |
| 369 | + if (!device_hwctx->video_device) { |
| 370 | + hr = ID3D11DeviceContext_QueryInterface(device_hwctx->device, &IID_ID3D11VideoDevice, |
| 371 | + (void **)&device_hwctx->video_device); |
| 372 | + if (FAILED(hr)) |
| 373 | + return AVERROR_UNKNOWN; |
| 374 | + } |
| 375 | + |
| 376 | + if (!device_hwctx->video_context) { |
| 377 | + hr = ID3D11DeviceContext_QueryInterface(device_hwctx->device_context, &IID_ID3D11VideoContext, |
| 378 | + (void **)&device_hwctx->video_context); |
| 379 | + if (FAILED(hr)) |
| 380 | + return AVERROR_UNKNOWN; |
| 381 | + } |
| 382 | + |
| 383 | + return 0; |
| 384 | +} |
| 385 | + |
| 386 | +static void d3d11va_device_uninit(AVHWDeviceContext *hwdev) |
| 387 | +{ |
| 388 | + AVD3D11VADeviceContext *device_hwctx = hwdev->hwctx; |
| 389 | + |
| 390 | + if (device_hwctx->device) |
| 391 | + ID3D11Device_Release(device_hwctx->device); |
| 392 | + |
| 393 | + if (device_hwctx->device_context) |
| 394 | + ID3D11DeviceContext_Release(device_hwctx->device_context); |
| 395 | + |
| 396 | + if (device_hwctx->video_device) |
| 397 | + ID3D11VideoDevice_Release(device_hwctx->video_device); |
| 398 | + |
| 399 | + if (device_hwctx->video_context) |
| 400 | + ID3D11VideoContext_Release(device_hwctx->video_context); |
| 401 | + |
| 402 | + if (device_hwctx->lock == d3d11va_default_lock) |
| 403 | + CloseHandle(device_hwctx->lock_ctx); |
| 404 | +} |
| 405 | + |
| 406 | +static int d3d11va_device_create(AVHWDeviceContext *ctx, const char *device, |
| 407 | + AVDictionary *opts, int flags) |
| 408 | +{ |
| 409 | + AVD3D11VADeviceContext *device_hwctx = ctx->hwctx; |
| 410 | + HANDLE d3dlib; |
| 411 | + |
| 412 | + HRESULT hr; |
| 413 | + PFN_D3D11_CREATE_DEVICE createD3D; |
| 414 | + IDXGIAdapter *pAdapter = NULL; |
| 415 | + ID3D10Multithread *pMultithread; |
| 416 | + UINT creationFlags = D3D11_CREATE_DEVICE_VIDEO_SUPPORT; |
| 417 | + |
| 418 | + if (device) { |
| 419 | + PFN_CREATE_DXGI_FACTORY mCreateDXGIFactory; |
| 420 | + HMODULE dxgilib = LoadLibrary("dxgi.dll"); |
| 421 | + if (!dxgilib) |
| 422 | + return AVERROR_UNKNOWN; |
| 423 | + |
| 424 | + mCreateDXGIFactory = (PFN_CREATE_DXGI_FACTORY) GetProcAddress(dxgilib, "CreateDXGIFactory"); |
| 425 | + if (mCreateDXGIFactory) { |
| 426 | + IDXGIFactory2 *pDXGIFactory; |
| 427 | + hr = mCreateDXGIFactory(&IID_IDXGIFactory2, (void **)&pDXGIFactory); |
| 428 | + if (SUCCEEDED(hr)) { |
| 429 | + int adapter = atoi(device); |
| 430 | + if (FAILED(IDXGIFactory2_EnumAdapters(pDXGIFactory, adapter, &pAdapter))) |
| 431 | + pAdapter = NULL; |
| 432 | + IDXGIFactory2_Release(pDXGIFactory); |
| 433 | + } |
| 434 | + } |
| 435 | + FreeLibrary(dxgilib); |
| 436 | + } |
| 437 | + |
| 438 | + // We let this "leak" - this is fine, as unloading has no great benefit, and |
| 439 | + // Windows will mark a DLL as loaded forever if its internal refcount overflows |
| 440 | + // from too many LoadLibrary calls. |
| 441 | + d3dlib = LoadLibrary("d3d11.dll"); |
| 442 | + if (!d3dlib) { |
| 443 | + av_log(ctx, AV_LOG_ERROR, "Failed to load D3D11 library\n"); |
| 444 | + return AVERROR_UNKNOWN; |
| 445 | + } |
| 446 | + |
| 447 | + createD3D = (PFN_D3D11_CREATE_DEVICE) GetProcAddress(d3dlib, "D3D11CreateDevice"); |
| 448 | + if (!createD3D) { |
| 449 | + av_log(ctx, AV_LOG_ERROR, "Failed to locate D3D11CreateDevice\n"); |
| 450 | + return AVERROR_UNKNOWN; |
| 451 | + } |
| 452 | + |
| 453 | + hr = createD3D(pAdapter, pAdapter ? D3D_DRIVER_TYPE_UNKNOWN : D3D_DRIVER_TYPE_HARDWARE, NULL, creationFlags, NULL, 0, |
| 454 | + D3D11_SDK_VERSION, &device_hwctx->device, NULL, NULL); |
| 455 | + if (pAdapter) |
| 456 | + IDXGIAdapter_Release(pAdapter); |
| 457 | + if (FAILED(hr)) { |
| 458 | + av_log(ctx, AV_LOG_ERROR, "Failed to create Direct3D device (%lx)\n", (long)hr); |
| 459 | + return AVERROR_UNKNOWN; |
| 460 | + } |
| 461 | + |
| 462 | + hr = ID3D11Device_QueryInterface(device_hwctx->device, &IID_ID3D10Multithread, (void **)&pMultithread); |
| 463 | + if (SUCCEEDED(hr)) { |
| 464 | + ID3D10Multithread_SetMultithreadProtected(pMultithread, TRUE); |
| 465 | + ID3D10Multithread_Release(pMultithread); |
| 466 | + } |
| 467 | + |
| 468 | + return 0; |
| 469 | +} |
| 470 | + |
| 471 | +const HWContextType ff_hwcontext_type_d3d11va = { |
| 472 | + .type = AV_HWDEVICE_TYPE_D3D11VA, |
| 473 | + .name = "D3D11VA", |
| 474 | + |
| 475 | + .device_hwctx_size = sizeof(AVD3D11VADeviceContext), |
| 476 | + .frames_hwctx_size = sizeof(AVD3D11VAFramesContext), |
| 477 | + .frames_priv_size = sizeof(D3D11VAFramesContext), |
| 478 | + |
| 479 | + .device_create = d3d11va_device_create, |
| 480 | + .device_init = d3d11va_device_init, |
| 481 | + .device_uninit = d3d11va_device_uninit, |
| 482 | + .frames_init = d3d11va_frames_init, |
| 483 | + .frames_uninit = d3d11va_frames_uninit, |
| 484 | + .frames_get_buffer = d3d11va_get_buffer, |
| 485 | + .transfer_get_formats = d3d11va_transfer_get_formats, |
| 486 | + .transfer_data_to = d3d11va_transfer_data, |
| 487 | + .transfer_data_from = d3d11va_transfer_data, |
| 488 | + |
| 489 | + .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_D3D11, AV_PIX_FMT_NONE }, |
| 490 | +}; |