On Mon, Jan 9, 2017 at 11:51 AM, wm4 <[email protected]> wrote:
> On Tue, 3 Jan 2017 17:34:59 +0100
> Steve Lhomme <[email protected]> wrote:
>
>> From: Steve Lhomme <[email protected]>
>>
>> ---
>> doc/APIchanges | 3 +
>> libavutil/Makefile | 3 +
>> libavutil/hwcontext.c | 3 +
>> libavutil/hwcontext.h | 1 +
>> libavutil/hwcontext_d3d11va.c | 460
>> +++++++++++++++++++++++++++++++++++++++++
>> libavutil/hwcontext_d3d11va.h | 70 +++++++
>> libavutil/hwcontext_internal.h | 1 +
>> libavutil/version.h | 2 +-
>> 8 files changed, 542 insertions(+), 1 deletion(-)
>> create mode 100644 libavutil/hwcontext_d3d11va.c
>> create mode 100644 libavutil/hwcontext_d3d11va.h
>>
>> diff --git a/doc/APIchanges b/doc/APIchanges
>> index 7633c99..29d5113 100644
>> --- a/doc/APIchanges
>> +++ b/doc/APIchanges
>> @@ -13,6 +13,9 @@ libavutil: 2015-08-28
>>
>> API changes, most recent first:
>>
>> +2017-xx-xx - xxxxxxx - lavu 55.30.0 - hwcontext.h
>> + Add AV_HWDEVICE_TYPE_D3D11VA to decode using Direct3D11.
>> +
>> 2016-xx-xx - xxxxxxx - lavc 57.29.0 - avcodec.h
>> Add AV_PKT_DATA_SPHERICAL packet side data to export AVSphericalMapping
>> information from containers.
>> diff --git a/libavutil/Makefile b/libavutil/Makefile
>> index 60e180c..6fb24db 100644
>> --- a/libavutil/Makefile
>> +++ b/libavutil/Makefile
>> @@ -27,6 +27,7 @@ HEADERS = adler32.h
>> \
>> hmac.h \
>> hwcontext.h \
>> hwcontext_cuda.h \
>> + hwcontext_d3d11va.h \
>> hwcontext_dxva2.h \
>> hwcontext_qsv.h \
>> hwcontext_vaapi.h \
>> @@ -112,6 +113,7 @@ OBJS = adler32.o
>> \
>> xtea.o \
>>
>> OBJS-$(CONFIG_CUDA) += hwcontext_cuda.o
>> +OBJS-$(CONFIG_D3D11VA) += hwcontext_d3d11va.o
>> OBJS-$(CONFIG_DXVA2) += hwcontext_dxva2.o
>> OBJS-$(CONFIG_LIBMFX) += hwcontext_qsv.o
>> OBJS-$(CONFIG_LZO) += lzo.o
>> @@ -121,6 +123,7 @@ OBJS-$(CONFIG_VDPAU) +=
>> hwcontext_vdpau.o
>> OBJS += $(COMPAT_OBJS:%=../compat/%)
>>
>> SKIPHEADERS-$(CONFIG_CUDA) += hwcontext_cuda.h
>> +SKIPHEADERS-$(CONFIG_D3D11VA) += hwcontext_d3d11va.h
>> SKIPHEADERS-$(CONFIG_DXVA2) += hwcontext_dxva2.h
>> SKIPHEADERS-$(CONFIG_LIBMFX) += hwcontext_qsv.h
>> SKIPHEADERS-$(CONFIG_VAAPI) += hwcontext_vaapi.h
>> diff --git a/libavutil/hwcontext.c b/libavutil/hwcontext.c
>> index 83f733e..ae27c51 100644
>> --- a/libavutil/hwcontext.c
>> +++ b/libavutil/hwcontext.c
>> @@ -32,6 +32,9 @@ static const HWContextType *hw_table[] = {
>> #if CONFIG_CUDA
>> &ff_hwcontext_type_cuda,
>> #endif
>> +#if CONFIG_D3D11VA
>> + &ff_hwcontext_type_d3d11va,
>> +#endif
>> #if CONFIG_DXVA2
>> &ff_hwcontext_type_dxva2,
>> #endif
>> diff --git a/libavutil/hwcontext.h b/libavutil/hwcontext.h
>> index 037ca64..d64b2da 100644
>> --- a/libavutil/hwcontext.h
>> +++ b/libavutil/hwcontext.h
>> @@ -30,6 +30,7 @@ enum AVHWDeviceType {
>> AV_HWDEVICE_TYPE_VAAPI,
>> AV_HWDEVICE_TYPE_DXVA2,
>> AV_HWDEVICE_TYPE_QSV,
>> + AV_HWDEVICE_TYPE_D3D11VA,
>> };
>>
>> typedef struct AVHWDeviceInternal AVHWDeviceInternal;
>> diff --git a/libavutil/hwcontext_d3d11va.c b/libavutil/hwcontext_d3d11va.c
>> new file mode 100644
>> index 0000000..a23a475
>> --- /dev/null
>> +++ b/libavutil/hwcontext_d3d11va.c
>> @@ -0,0 +1,460 @@
>> +/*
>> + * This file is part of Libav.
>> + *
>> + * Libav 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.
>> + *
>> + * Libav 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 Libav; if not, write to the Free Software
>> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
>> USA
>> + */
>> +
>> +#include <windows.h>
>> +
>> +#if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0600
>> +#undef _WIN32_WINNT
>> +#define _WIN32_WINNT 0x0600
>> +#endif
>> +#define COBJMACROS
>> +
>> +#include <initguid.h>
>> +#include <d3d11.h>
>> +#include <dxgi1_2.h>
>> +
>> +#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"
>> +
>> +typedef HRESULT(WINAPI *PFN_CREATE_DXGI_FACTORY)(REFIID riid, void
>> **ppFactory);
>> +
>> +typedef struct D3D11VAFramesContext {
>> + ID3D11VideoDecoderOutputView **surfaces_internal;
>> + int nb_surfaces_used;
>> +
>> + ID3D11DeviceContext *d3d11_context;
>> +
>> + DXGI_FORMAT format;
>> +
>> + ID3D11Texture2D *staging_texture;
>> +} D3D11VAFramesContext;
>> +
>> +typedef struct D3D11VADevicePriv {
>> + HMODULE d3dlib;
>> +} D3D11VADevicePriv;
>> +
>> +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 },
>> +};
>> +
>> +static void d3d11va_frames_uninit(AVHWFramesContext *ctx)
>> +{
>> + AVD3D11VAFramesContext *frames_hwctx = ctx->hwctx;
>> + D3D11VAFramesContext *s = ctx->internal->priv;
>> +
>> + av_freep(&s->surfaces_internal);
>> +
>> + if (frames_hwctx->video_decoder)
>> + ID3D11VideoDecoder_Release(frames_hwctx->video_decoder);
>> +
>> + if (s->staging_texture)
>> + ID3D11Texture2D_Release(s->staging_texture);
>> +
>> + if (s->d3d11_context) {
>> + ID3D11DeviceContext_Release(s->d3d11_context);
>> + s->d3d11_context = NULL;
>> + }
>> +}
>> +
>> +static void free_surface(void *opaque, uint8_t *data)
>> +{
>> +
>> ID3D11VideoDecoderOutputView_Release((ID3D11VideoDecoderOutputView*)data);
>> +}
>> +
>> +static AVBufferRef *d3d11va_pool_alloc(void *opaque, int size)
>> +{
>> + AVHWFramesContext *ctx = (AVHWFramesContext*)opaque;
>> + D3D11VAFramesContext *s = ctx->internal->priv;
>> + AVD3D11VAFramesContext *hwctx = ctx->hwctx;
>> +
>> + if (s->nb_surfaces_used < hwctx->nb_surfaces) {
>> + s->nb_surfaces_used++;
>> + return
>> av_buffer_create((uint8_t*)s->surfaces_internal[s->nb_surfaces_used - 1],
>> + sizeof(*hwctx->surfaces), free_surface, 0,
>> 0);
>> + }
>> +
>> + return NULL;
>> +}
>> +
>> +static int d3d11va_init_pool(AVHWFramesContext *ctx)
>> +{
>> + AVD3D11VAFramesContext *frames_hwctx = ctx->hwctx;
>> + AVD3D11VADeviceContext *device_hwctx = ctx->device_ctx->hwctx;
>> + D3D11VAFramesContext *s = ctx->internal->priv;
>> +
>> + int i;
>> + HRESULT hr;
>> + D3D11_TEXTURE2D_DESC texDesc = {0};
>> + ID3D11Texture2D *p_texture;
>> + D3D11_VIDEO_DECODER_OUTPUT_VIEW_DESC viewDesc = {0};
>> + D3D11_VIDEO_DECODER_DESC decoderDesc;
>> + D3D11_VIDEO_DECODER_CONFIG decoderConfig;
>> + ID3D11Device *d3d11_device;
>> +
>> + if (ctx->initial_pool_size <= 0)
>> + return 0;
>> +
>> + hr = ID3D11VideoContext_QueryInterface(device_hwctx->video_context,
>> &IID_ID3D11DeviceContext,
>> + (void **)&s->d3d11_context);
>> + if (FAILED(hr)) {
>> + av_log(ctx, AV_LOG_ERROR, "Failed to get the device context %lx\n",
>> hr);
>> + return AVERROR_UNKNOWN;
>> + }
>> +
>> + 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);
>> + }
>> +
>> + s->surfaces_internal = av_mallocz_array(ctx->initial_pool_size,
>> + sizeof(*s->surfaces_internal));
>> + if (!s->surfaces_internal)
>> + return AVERROR(ENOMEM);
>> +
>> + texDesc.Width = ctx->width;
>> + texDesc.Height = ctx->height;
>> + texDesc.MipLevels = 1;
>> + texDesc.Format = s->format;
>> + texDesc.SampleDesc.Count = 1;
>> + texDesc.ArraySize = ctx->initial_pool_size;
>> + texDesc.Usage = D3D11_USAGE_DEFAULT;
>> + texDesc.BindFlags = D3D11_BIND_DECODER;
>> +
>> + hr = ID3D11VideoDevice_QueryInterface(device_hwctx->video_device,
>> &IID_ID3D11Device, (void **)&d3d11_device);
>> + if (FAILED(hr)) {
>> + av_log(ctx, AV_LOG_ERROR, "Failed to get the device %lx\n", hr);
>> + return AVERROR_UNKNOWN;
>> + }
>> +
>> + hr = ID3D11Device_CreateTexture2D(d3d11_device, &texDesc, NULL,
>> &p_texture);
>> + if (FAILED(hr)) {
>> + av_log(ctx, AV_LOG_ERROR, "Could not create the texture %lx\n", hr);
>> + ID3D11Device_Release(d3d11_device);
>> + return AVERROR_UNKNOWN;
>> + }
>> +
>> + hr =
>> ID3D11VideoDecoder_GetCreationParameters(frames_hwctx->video_decoder,
>> &decoderDesc, &decoderConfig);
>> + if (FAILED(hr)) {
>> + av_log(ctx, AV_LOG_ERROR, "Could not get the decoder config %lx\n",
>> hr);
>> + ID3D11Texture2D_Release(p_texture);
>> + ID3D11Device_Release(d3d11_device);
>> + return AVERROR_UNKNOWN;
>> + }
>> +
>> + viewDesc.DecodeProfile = decoderDesc.Guid;
>> + viewDesc.ViewDimension = D3D11_VDOV_DIMENSION_TEXTURE2D;
>> + for (i=0; i<ctx->initial_pool_size; i++)
>> + {
>> + hr =
>> ID3D11VideoDevice_CreateVideoDecoderOutputView(device_hwctx->video_device,
>> +
>> (ID3D11Resource*) p_texture,
>> + &viewDesc,
>> +
>> (ID3D11VideoDecoderOutputView**) &s->surfaces_internal[i]);
>> + if (FAILED(hr)) {
>> + av_log(ctx, AV_LOG_ERROR, "Could not create the decoder output
>> %d\n", i);
>> + while (--i >= 0) {
>> +
>> ID3D11VideoDecoderOutputView_Release(s->surfaces_internal[i]);
>> + s->surfaces_internal[i] = NULL;
>> + }
>> + ID3D11Texture2D_Release(p_texture);
>> + ID3D11Device_Release(d3d11_device);
>> + return AVERROR_UNKNOWN;
>> + }
>> + }
>> + ID3D11Texture2D_Release(p_texture);
>> +
>> + texDesc.ArraySize = 1;
>> + texDesc.Usage = D3D11_USAGE_STAGING;
>> + texDesc.BindFlags = 0;
>> + texDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
>> + hr = ID3D11Device_CreateTexture2D(d3d11_device, &texDesc, NULL,
>> &s->staging_texture);
>> + ID3D11Device_Release(d3d11_device);
>> + if (FAILED(hr)) {
>> + av_log(ctx, AV_LOG_ERROR, "Could not create the staging texture
>> %lx\n", hr);
>> + return AVERROR_UNKNOWN;
>> + }
>> +
>> + ctx->internal->pool_internal =
>> av_buffer_pool_init2(sizeof(*s->surfaces_internal),
>> + ctx,
>> d3d11va_pool_alloc, NULL);
>> + if (!ctx->internal->pool_internal)
>> + return AVERROR(ENOMEM);
>> +
>> + frames_hwctx->surfaces = s->surfaces_internal;
>> + frames_hwctx->nb_surfaces = ctx->initial_pool_size;
>> +
>> + return 0;
>> +}
>> +
>> +static int d3d11va_frames_init(AVHWFramesContext *ctx)
>> +{
>> + int ret;
>> +
>> + /* init the frame pool if the caller didn't provide one */
>> + if (!ctx->pool) {
>> + ret = d3d11va_init_pool(ctx);
>> + if (ret < 0) {
>> + av_log(ctx, AV_LOG_ERROR, "Error creating an internal frame
>> pool\n");
>> + return ret;
>> + }
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static int d3d11va_get_buffer(AVHWFramesContext *ctx, AVFrame *frame)
>> +{
>> + frame->buf[0] = av_buffer_pool_get(ctx->pool);
>> + if (!frame->buf[0])
>> + return AVERROR(ENOMEM);
>> +
>> + frame->data[3] = frame->buf[0]->data;
>> + frame->format = AV_PIX_FMT_D3D11VA_VLD;
>> + frame->width = ctx->width;
>> + frame->height = ctx->height;
>> +
>> + return 0;
>> +}
>> +
>> +static int d3d11va_transfer_get_formats(AVHWFramesContext *ctx,
>> + enum AVHWFrameTransferDirection dir,
>> + enum AVPixelFormat **formats)
>> +{
>> + 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;
>> +
>> + *formats = fmts;
>> +
>> + return 0;
>> +}
>> +
>> +static int d3d11va_transfer_data(AVHWFramesContext *ctx, AVFrame *dst,
>> + const AVFrame *src)
>> +{
>> + ID3D11VideoDecoderOutputView *surface;
>> + D3D11_VIDEO_DECODER_OUTPUT_VIEW_DESC surfaceDesc;
>> + D3D11_TEXTURE2D_DESC dstDesc;
>> + D3D11_MAPPED_SUBRESOURCE LockedRect;
>> + ID3D11Resource *pTexture;
>> + HRESULT hr;
>> + AVD3D11VAFramesContext *frames_hwctx = ctx->hwctx;
>> + AVD3D11VADeviceContext *device_hwctx = ctx->device_ctx->hwctx;
>> + D3D11VAFramesContext *s = ctx->internal->priv;
>> +
>> + uint8_t *surf_data[4] = { NULL };
>> + int surf_linesize[4] = { 0 };
>> + int i;
>> +
>> + int download = !!src->hw_frames_ctx;
>> +
>> + surface = (ID3D11VideoDecoderOutputView*)(download ? src->data[3] :
>> dst->data[3]);
>> +
>> + ID3D11VideoDecoderOutputView_GetDesc(surface, &surfaceDesc);
>> + ID3D11VideoDecoderOutputView_GetResource(surface, &pTexture);
>> + ID3D11Texture2D_GetDesc(s->staging_texture, &dstDesc);
>> +
>> + WaitForSingleObjectEx(device_hwctx->dev_ctx_mutex, INFINITE, FALSE);
>> +
>> + ID3D11DeviceContext_CopySubresourceRegion(s->d3d11_context,
>> (ID3D11Resource*)s->staging_texture,
>> + 0, 0, 0, 0,
>> + (ID3D11Resource*)pTexture,
>> surfaceDesc.Texture2D.ArraySlice,
>> + NULL);
>> + ID3D11Resource_Release(pTexture);
>> +
>> + hr = ID3D11DeviceContext_Map(s->d3d11_context,
>> (ID3D11Resource*)s->staging_texture,
>> + 0, download ? D3D11_MAP_READ :
>> D3D11_MAP_WRITE, 0, &LockedRect);
>> + if (FAILED(hr)) {
>> + av_log(ctx, AV_LOG_ERROR, "Unable to lock D3D11VA surface %lx\n",
>> hr);
>> + ReleaseMutex(device_hwctx->dev_ctx_mutex);
>> + return AVERROR_UNKNOWN;
>> + }
>> +
>> + for (i = 0; download ? dst->data[i] : src->data[i]; i++)
>> + surf_linesize[i] = LockedRect.RowPitch;
>> +
>> + av_image_fill_pointers(surf_data, ctx->sw_format, dstDesc.Height,
>> + (uint8_t*)LockedRect.pData, surf_linesize);
>> +
>> + if (download) {
>> + av_image_copy(dst->data, dst->linesize, surf_data, surf_linesize,
>> + ctx->sw_format, src->width, src->height);
>> + } else {
>> + av_image_copy(surf_data, surf_linesize, src->data, src->linesize,
>> + ctx->sw_format, src->width, src->height);
>> + }
>> +
>> + ID3D11DeviceContext_Unmap(s->d3d11_context,
>> (ID3D11Resource*)s->staging_texture, 0);
>> + ReleaseMutex(device_hwctx->dev_ctx_mutex);
>> +
>> + return 0;
>> +}
>> +
>> +static void d3d11va_device_free(AVHWDeviceContext *ctx)
>> +{
>> + AVD3D11VADeviceContext *device_hwctx = ctx->hwctx;
>> + D3D11VADevicePriv *priv = ctx->user_opaque;
>> +
>> + if (device_hwctx->video_device)
>> + ID3D11Device_Release(device_hwctx->video_device);
>> +
>> + if (device_hwctx->video_context)
>> + ID3D11VideoContext_Release(device_hwctx->video_context);
>> +
>> + if (device_hwctx->dev_ctx_mutex != INVALID_HANDLE_VALUE)
>> + ReleaseMutex(device_hwctx->dev_ctx_mutex);
>> +
>> + if (priv->d3dlib)
>> + FreeLibrary(priv->d3dlib);
>> +
>> + av_freep(&ctx->user_opaque);
>> +}
>> +
>> +static int d3d11va_device_create(AVHWDeviceContext *ctx, const char *device,
>> + AVDictionary *opts, int flags)
>> +{
>> + AVD3D11VADeviceContext *device_hwctx = ctx->hwctx;
>> + D3D11VADevicePriv *priv;
>> +
>> + HRESULT hr;
>> + PFN_D3D11_CREATE_DEVICE createD3D;
>> + IDXGIAdapter *pAdapter = NULL;
>> + ID3D10Multithread *pMultithread;
>> + ID3D11Device *d3d11_device;
>> + ID3D11DeviceContext *d3d11_context;
>> + UINT creationFlags = D3D11_CREATE_DEVICE_VIDEO_SUPPORT;
>> + /* if the DirectX SDK is installed creationFlags |=
>> D3D11_CREATE_DEVICE_DEBUG; */
>> +
>> + if (device) {
>> + PFN_CREATE_DXGI_FACTORY mCreateDXGIFactory;
>> + HMODULE dxgilib = LoadLibrary("dxgi.dll");
>> + if (!dxgilib)
>> + return AVERROR_UNKNOWN;
>> +
>> + mCreateDXGIFactory = (PFN_CREATE_DXGI_FACTORY)
>> GetProcAddress(dxgilib, "CreateDXGIFactory");
>> + if (mCreateDXGIFactory) {
>> + IDXGIFactory2 *pDXGIFactory;
>> + hr = mCreateDXGIFactory(&IID_IDXGIFactory2, (void
>> **)&pDXGIFactory);
>> + if (SUCCEEDED(hr)) {
>> + int adapter = atoi(device);
>
> Still not liking the atoi() call... (because undefined behavior if
> device is not actually a number)
If the user/caller gives bogus data it's fair to give bogus results.
It's not going to crash though. Also this is the same as DXVA2 so if
it needs to be changed it needs to be changed there too. Should the
patchset be delayed until the behaviour is changed in DXVA2 ?
>> + if (FAILED(IDXGIFactory2_EnumAdapters(pDXGIFactory,
>> adapter, &pAdapter)))
>> + pAdapter = NULL;
>> + IDXGIFactory2_Release(pDXGIFactory);
>> + }
>> + }
>> + FreeLibrary(dxgilib);
>> + }
>> +
>> + priv = av_mallocz(sizeof(*priv));
>> + if (!priv)
>> + return AVERROR(ENOMEM);
>> +
>> + ctx->user_opaque = priv;
>> + ctx->free = d3d11va_device_free;
>> +
>> + priv->d3dlib = LoadLibrary("d3d11.dll");
>> + if (!priv->d3dlib) {
>> + av_log(ctx, AV_LOG_ERROR, "Failed to load D3D11 library\n");
>> + return AVERROR_UNKNOWN;
>> + }
>> +
>> + createD3D = (PFN_D3D11_CREATE_DEVICE) GetProcAddress(priv->d3dlib,
>> "D3D11CreateDevice");
>> + if (!createD3D) {
>> + av_log(ctx, AV_LOG_ERROR, "Failed to locate D3D11CreateDevice\n");
>> + return AVERROR_UNKNOWN;
>> + }
>> +
>> + hr = createD3D(pAdapter, pAdapter ? D3D_DRIVER_TYPE_UNKNOWN :
>> D3D_DRIVER_TYPE_HARDWARE, NULL, creationFlags, NULL, 0,
>> + D3D11_SDK_VERSION, &d3d11_device, NULL, &d3d11_context);
>> + if (pAdapter)
>> + IDXGIAdapter_Release(pAdapter);
>> + if (FAILED(hr)) {
>> + av_log(ctx, AV_LOG_ERROR, "Failed to create Direct3D device %lx\n",
>> hr);
>
> Just spotted this, but is HRESULT always the C type "long"?
It's always 32 bits.
>> + return AVERROR_UNKNOWN;
>> + }
>> +
>> + hr = ID3D11Device_QueryInterface(d3d11_device, &IID_ID3D10Multithread,
>> (void **)&pMultithread);
>> + if (SUCCEEDED(hr)) {
>> + ID3D10Multithread_SetMultithreadProtected(pMultithread, TRUE);
>> + ID3D10Multithread_Release(pMultithread);
>> + }
>> +
>> + hr = ID3D11DeviceContext_QueryInterface(d3d11_context,
>> &IID_ID3D11VideoContext,
>> + (void
>> **)&device_hwctx->video_context);
>> + ID3D11DeviceContext_Release(d3d11_context);
>> + if (FAILED(hr)) {
>> + av_log(ctx, AV_LOG_ERROR, "Failed to get the Video Context %lx\n",
>> hr);
>> + ID3D11Device_Release(d3d11_device);
>> + return AVERROR_UNKNOWN;
>> + }
>> +
>> + hr = ID3D11Device_QueryInterface(d3d11_device, &IID_ID3D11VideoDevice,
>> + (void **)&device_hwctx->video_device);
>> + ID3D11Device_Release(d3d11_device);
>> + if (FAILED(hr)) {
>> + av_log(NULL, AV_LOG_ERROR, "Failed to get the Video Device %lx\n",
>> hr);
>> + return AVERROR_UNKNOWN;
>> + }
>> +
>> + device_hwctx->dev_ctx_mutex = CreateMutex(NULL, 0, NULL);
>> + if (device_hwctx->dev_ctx_mutex == INVALID_HANDLE_VALUE) {
>> + av_log(NULL, AV_LOG_ERROR, "Failed to get a mutex for the D3D11VA
>> decoder\n");
>> + return AVERROR(EINVAL);
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +const HWContextType ff_hwcontext_type_d3d11va = {
>> + .type = AV_HWDEVICE_TYPE_D3D11VA,
>> + .name = "D3D11VA",
>> +
>> + .device_hwctx_size = sizeof(AVD3D11VADeviceContext),
>> + .frames_hwctx_size = sizeof(AVD3D11VAFramesContext),
>> + .frames_priv_size = sizeof(D3D11VAFramesContext),
>> +
>> + .device_create = d3d11va_device_create,
>> + .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_D3D11VA_VLD, AV_PIX_FMT_NONE },
>> +};
>> diff --git a/libavutil/hwcontext_d3d11va.h b/libavutil/hwcontext_d3d11va.h
>> new file mode 100644
>> index 0000000..1a649d8
>> --- /dev/null
>> +++ b/libavutil/hwcontext_d3d11va.h
>> @@ -0,0 +1,70 @@
>> +/*
>> + * This file is part of Libav.
>> + *
>> + * Libav 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.
>> + *
>> + * Libav 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 Libav; if not, write to the Free Software
>> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
>> USA
>> + */
>> +
>> +
>> +#ifndef AVUTIL_HWCONTEXT_D3D11VA_H
>> +#define AVUTIL_HWCONTEXT_D3D11VA_H
>> +
>> +/**
>> + * @file
>> + * An API-specific header for AV_HWDEVICE_TYPE_D3D11VA.
>> + *
>> + * Only fixed-size pools are supported.
>> + *
>> + * For user-allocated pools, AVHWFramesContext.pool must return AVBufferRefs
>> + * with the data pointer set to a pointer to ID3D11VideoDecoderOutputView.
>> + */
>> +
>> +#include <d3d11.h>
>> +
>> +/**
>> + * This struct is allocated as AVHWDeviceContext.hwctx
>> + */
>> +typedef struct AVD3D11VADeviceContext {
>> + ID3D11VideoDevice *video_device;
>> + ID3D11VideoContext *video_context;
>> +
>> + /**
>> + * Mutex owned by this context to avoid accessing the video_context from
>> + * multiple threads simultaneously.
>> + */
>> + HANDLE dev_ctx_mutex;
>
> Doesn't say much about those field's lifetime. If you use automatic
> device creation, I assume freeing the device context frees these
> interfaces and the mutex.
>
> But what if the user supplied these?
It's owned by the context which is allocated internally. It must not
be set by the caller. There is indeed an issue if an external code
continues to use the HANDLE after it has been released by the
hwcontext code.
> Is it possible to prevent it from releasing the mutex?
Maybe it should be created/released by the libavutil caller. We will
just need to check somewhere that we have an valid handle.
>> +} AVD3D11VADeviceContext;
>> +
>> +/**
>> + * This struct is allocated as AVHWFramesContext.hwctx
>> + */
>> +typedef struct AVD3D11VAFramesContext {
>> + /**
>> + * The surface pool. When an external pool is not provided by the
>> caller,
>> + * this will be managed (allocated and filled on init, freed on uninit)
>> by
>> + * libavutil.
>> + * When it is provided the allocation/deallocation is up to the caller.
>> + */
>> + ID3D11VideoDecoderOutputView **surfaces;
>> + int nb_surfaces;
>> +
>> + /**
>> + * Video decoder created by the caller. It must be set before
>> + * av_hwframe_ctx_init() is called. When decoding is done it will be
>> + * released.
>> + */
>> + ID3D11VideoDecoder *video_decoder;
>
> "When decoding is done" isn't very precise. I assume that if the frames
> context has no more references to it (including ones via AVFrame), it
> decreases the refcount of video_decoder.
Yes, it means the COM object is released, so the refcounter is
decreased. Whatever the caller did it may still hold references after
that or it will be released for good.
>> +} AVD3D11VAFramesContext;
>> +
>> +#endif /* AVUTIL_HWCONTEXT_D3D11VA_H */
>> diff --git a/libavutil/hwcontext_internal.h b/libavutil/hwcontext_internal.h
>> index 11e3a68..9083ce6 100644
>> --- a/libavutil/hwcontext_internal.h
>> +++ b/libavutil/hwcontext_internal.h
>> @@ -140,6 +140,7 @@ int ff_hwframe_map_create(AVBufferRef *hwframe_ref,
>>
>>
>> extern const HWContextType ff_hwcontext_type_cuda;
>> +extern const HWContextType ff_hwcontext_type_d3d11va;
>> extern const HWContextType ff_hwcontext_type_dxva2;
>> extern const HWContextType ff_hwcontext_type_qsv;
>> extern const HWContextType ff_hwcontext_type_vaapi;
>> diff --git a/libavutil/version.h b/libavutil/version.h
>> index f110231..e9940f2 100644
>> --- a/libavutil/version.h
>> +++ b/libavutil/version.h
>> @@ -54,7 +54,7 @@
>> */
>>
>> #define LIBAVUTIL_VERSION_MAJOR 55
>> -#define LIBAVUTIL_VERSION_MINOR 29
>> +#define LIBAVUTIL_VERSION_MINOR 30
>> #define LIBAVUTIL_VERSION_MICRO 0
>>
>> #define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \
>
> _______________________________________________
> libav-devel mailing list
> [email protected]
> https://lists.libav.org/mailman/listinfo/libav-devel
_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel