Hi,

On Mon, Dec 19, 2016 at 1:04 PM, Anton Khirnov <an...@khirnov.net> wrote:
> Quoting Steve Lhomme (2016-12-16 11:05:40)
>> From: Steve Lhomme <rob...@gmail.com>
>>
>> ---
>>  libavutil/Makefile             |   3 +
>>  libavutil/hwcontext.c          |   3 +
>>  libavutil/hwcontext.h          |   1 +
>>  libavutil/hwcontext_d3d11va.c  | 456 
>> +++++++++++++++++++++++++++++++++++++++++
>>  libavutil/hwcontext_d3d11va.h  |  81 ++++++++
>>  libavutil/hwcontext_internal.h |   1 +
>>  libavutil/version.h            |   2 +-
>>  7 files changed, 546 insertions(+), 1 deletion(-)
>>  create mode 100644 libavutil/hwcontext_d3d11va.c
>>  create mode 100644 libavutil/hwcontext_d3d11va.h
>>
>> diff --git a/libavutil/Makefile b/libavutil/Makefile
>> index f34c799..962dcf2 100644
>> --- a/libavutil/Makefile
>> +++ b/libavutil/Makefile
>> @@ -26,6 +26,7 @@ HEADERS = adler32.h                                        
>>              \
>>            hmac.h                                                        \
>>            hwcontext.h                                                   \
>>            hwcontext_cuda.h                                              \
>> +          hwcontext_d3d11va.h                                           \
>>            hwcontext_dxva2.h                                             \
>>            hwcontext_qsv.h                                               \
>>            hwcontext_vaapi.h                                             \
>> @@ -111,6 +112,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
>> @@ -120,6 +122,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..db5ec03
>> --- /dev/null
>> +++ b/libavutil/hwcontext_d3d11va.c
>> @@ -0,0 +1,456 @@
>> +/*
>> + * 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;
>> +} 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;
>> +
>> +    if (frames_hwctx->decoder_to_release)
>> +        ID3D11VideoDecoder_Release(frames_hwctx->decoder_to_release);
>> +
>> +    av_freep(&s->surfaces_internal);
>> +
>> +    if (frames_hwctx->staging_texture)
>> +        ID3D11Texture2D_Release(frames_hwctx->staging_texture);
>> +
>> +    if (s->d3d11_context) {
>> +        ID3D11DeviceContext_Release(s->d3d11_context);
>> +        s->d3d11_context = NULL;
>> +    }
>> +
>> +    if (frames_hwctx->dev_ctx_mutex != INVALID_HANDLE_VALUE)
>> +        ReleaseMutex(frames_hwctx->dev_ctx_mutex);
>> +}
>> +
>> +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;
>> +    ID3D11Texture2D *p_texture;
>> +    D3D11_VIDEO_DECODER_OUTPUT_VIEW_DESC viewDesc;
>> +    D3D11_VIDEO_DECODER_DESC decoderDesc;
>> +    D3D11_VIDEO_DECODER_CONFIG decoderConfig;
>> +    ID3D11Device *d3d11_device;
>> +
>> +    if (ctx->initial_pool_size <= 0)
>> +        return 0;
>
> Shouldn't this fail?

What do you mean ? Like assert ?
This code is copied from the dxva2 version.

>> +
>> +    hr = ID3D11VideoContext_QueryInterface(device_hwctx->video_context, 
>> &IID_ID3D11DeviceContext,
>> +                                           (void **)&s->d3d11_context);
>
> This function is called conditionally, but the context is then accessed
> unconditionally in transfer_data. Seems to be it would be better to
> create it once in device_init(). Or do you need a separate one for each
> frame pool?
>
> Same for other objects below.

It's tied to the frame context so it's better if there's one per pool.
Given the context is sensitive to thread reusing it's better if
different decoding sessions don't share the same object.

>> +    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);
>> +
>> +    ZeroMemory(&texDesc, sizeof(texDesc));
>
> Isn't this just memset(.., 0, ..)?

I'll use the = {0} init in a future version.

>> +    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;
>> +
>> +    frames_hwctx->dev_ctx_mutex = CreateMutex(NULL, 0, NULL);
>> +    if (frames_hwctx->dev_ctx_mutex == INVALID_HANDLE_VALUE) {
>> +        av_log(ctx, AV_LOG_ERROR, "Failed to get a mutex for the D3D11VA 
>> decoder\n");
>> +        return AVERROR(EINVAL);
>> +    }
>> +
>> +    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->decoder_to_release, 
>> &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;
>> +    }
>> +
>> +    ZeroMemory(&viewDesc, sizeof(viewDesc));
>> +    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, 
>> &frames_hwctx->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;
>> +    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(frames_hwctx->staging_texture, &dstDesc);
>> +
>> +    WaitForSingleObjectEx(frames_hwctx->dev_ctx_mutex, INFINITE, FALSE);
>> +
>> +    ID3D11DeviceContext_CopySubresourceRegion(s->d3d11_context, 
>> (ID3D11Resource*)frames_hwctx->staging_texture,
>> +                                              0, 0, 0, 0,
>> +                                              (ID3D11Resource*)pTexture, 
>> surfaceDesc.Texture2D.ArraySlice,
>> +                                              NULL);
>> +    ID3D11Resource_Release(pTexture);
>> +
>> +    hr = ID3D11DeviceContext_Map(s->d3d11_context, 
>> (ID3D11Resource*)frames_hwctx->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(frames_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*)frames_hwctx->staging_texture, 0);
>> +    ReleaseMutex(frames_hwctx->dev_ctx_mutex);
>> +
>> +    return 0;
>> +}
>> +
>> +static void d3d11va_device_free(AVHWDeviceContext *ctx)
>> +{
>> +    AVD3D11VADeviceContext *device_hwctx = ctx->hwctx;
>> +    D3D11VADevicePriv       *priv = ctx->user_opaque;
>
> nit: broken vertical alignment
>
>> +
>> +    if (device_hwctx->video_device)
>> +        ID3D11Device_Release(device_hwctx->video_device);
>> +
>> +    if (device_hwctx->video_context)
>> +        ID3D11VideoContext_Release(device_hwctx->video_context);
>> +
>> +    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;
>> +    ID3D11Device           *d3d11_device;
>> +    ID3D11DeviceContext    *d3d11_context;
>> +    ID3D10Multithread      *pMultithread;
>> +    D3D11VADevicePriv      *priv;
>> +
>> +    HRESULT hr;
>> +    PFN_D3D11_CREATE_DEVICE createD3D;
>> +    IDXGIAdapter *pAdapter = NULL;
>> +    UINT creationFlags = D3D11_CREATE_DEVICE_VIDEO_SUPPORT;
>> +    /* if the DirectX SDK is installed creationFlags |= 
>> D3D11_CREATE_DEVICE_DEBUG; */
>> +
>> +    if (device) {
>> +        HMODULE dxgilib = LoadLibrary("dxgi.dll");
>> +        if (dxgilib) {
>
> In what circumstances will this library be missing? I think if the
> caller requests a specific device and this function is unable to
> deliver, it should fail, not return some random otehr device.

I think there's no Windows with D3D11 and without DXGI. But what about
Wine ? I likely has DXGI as it predates D3D11. I'll see how to return
an error rather than assuming things are fine.

>> +            PFN_CREATE_DXGI_FACTORY mCreateDXGIFactory;
>> +            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);
>> +                    if (FAILED(IDXGIFactory2_EnumAdapters(pDXGIFactory, 
>> adapter, &pAdapter)))
>> +                        pAdapter = NULL;
>
> If I'm reading the docs correctly, the adapter also needs to be
> released.

Indeed.

>> +                    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 (FAILED(hr)) {
>> +        av_log(ctx, AV_LOG_ERROR, "Failed to create Direct3D device %lx\n", 
>> hr);
>> +        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;
>> +    }
>> +
>> +    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..8ccb1e7
>> --- /dev/null
>> +++ b/libavutil/hwcontext_d3d11va.h
>> @@ -0,0 +1,81 @@
>> +/*
>> + * 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;
>> +} 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;
>> +
>> +    /**
>> +     * Certain drivers require the decoder to be destroyed before the 
>> surfaces.
>> +     * To allow internally managed pools to work properly in such cases, 
>> this
>> +     * field is provided.
>> +     *
>> +     * The decoder must be created before the surface pool.
>> +     *
>> +     * If it is non-NULL, libavutil will call ID3D11VideoDecoder_Release() 
>> on
>> +     * it just before the internal surface pool is freed.
>> +     */
>> +    ID3D11VideoDecoder  *decoder_to_release;
>
> This seems to be used for a completely different purpose than the field
> with same name in the dxva2 context -- you extract some information from
> it. That should certainly be documented, as this field is optional in
> DXVA2 and mandatory here. Also, wouldn't it be better for the caller to
> pass the decode profile directly without doing it in such a roundabout
> way?

You're right all I need it for is the decoderDesc.Guid. I don't know
if it should be the job of the hwcontext to release it though. I don't
know if the same requirements apply as on DXVA2 to release it before
the surfaces. That seems dubious as all the objects are refcounted
internally anyway. The copy was just copy pasted. I can just move it
and provide the GUID for now and if there are issues later it can be
fixed.

>> +
>> +    /**
>> +     * Internal texture to get access to the decoded pixels from the CPU as 
>> the
>> +     * decoder texture needs D3D11_BIND_DECODER which forbdis CPU access.
>> +     */
>> +    ID3D11Texture2D     *staging_texture;
>> +
>> +    /**
>> +     * Internal Mutex to avoid accessing the ID3D11DeviceContext from 
>> multiple
>> +     * threads simultaneously.
>> +     */
>> +    HANDLE               dev_ctx_mutex;
>
> I'm a bit confused by your use of "internal". If it's internal to
> hwcontext, then it should be in the private context, not here.

It's internal in the sense that it's created by the HW context who
owns it. It's also used by libavcodec though so it must be "exported".
I'll see if I can move it in AVD3D11VADeviceContext which would be
more logical.

>> +} 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..6afaf8e 100644
>> --- a/libavutil/version.h
>> +++ b/libavutil/version.h
>> @@ -55,7 +55,7 @@
>>
>>  #define LIBAVUTIL_VERSION_MAJOR 55
>>  #define LIBAVUTIL_VERSION_MINOR 29
>> -#define LIBAVUTIL_VERSION_MICRO  0
>> +#define LIBAVUTIL_VERSION_MICRO  1
>
> This is an API change, so it should be a minor bump. And an APIchanges
> entry is in order.

ok

> --
> Anton Khirnov
> _______________________________________________
> libav-devel mailing list
> libav-devel@libav.org
> https://lists.libav.org/mailman/listinfo/libav-devel
_______________________________________________
libav-devel mailing list
libav-devel@libav.org
https://lists.libav.org/mailman/listinfo/libav-devel

Reply via email to