You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

673 lines
24 KiB

/*****************************************************************************
* d3d11va.c: Direct3D11 Video Acceleration decoder
*****************************************************************************
* Copyright © 2009 Geoffroy Couprie
* Copyright © 2009 Laurent Aimar
* Copyright © 2015 Steve Lhomme
* Copyright © 2015 VideoLabs
*
* Authors: Geoffroy Couprie <geal@videolan.org>
* Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
* Steve Lhomme <robux4@gmail.com>
*
* This program 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.
*
* This program 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 this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
/**
* See https://msdn.microsoft.com/en-us/library/windows/desktop/hh162912%28v=vs.85%29.aspx
**/
#include <process.h>
#include <winapifamily.h>
#undef WINAPI_FAMILY
#define WINAPI_FAMILY WINAPI_FAMILY_DESKTOP_APP
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <assert.h>
#include <vlc_common.h>
#include <vlc_picture.h>
#include <vlc_plugin.h>
#include <vlc_charset.h>
#include <vlc_codec.h>
#define COBJMACROS
#include <initguid.h>
#include <d3d11.h>
#include <libavcodec/d3d11va.h>
#include "../../video_chroma/d3d11_fmt.h"
struct d3d11va_pic_context
{
struct d3d11_pic_context ctx;
struct vlc_va_surface_t *va_surface;
};
#define D3D11VA_PICCONTEXT_FROM_PICCTX(pic_ctx) \
container_of((pic_ctx), struct d3d11va_pic_context, ctx.s)
#include "directx_va.h"
static int Open(vlc_va_t *, AVCodecContext *, enum AVPixelFormat hwfmt, const AVPixFmtDescriptor *,
const es_format_t *, vlc_decoder_device *, video_format_t *, vlc_video_context **);
vlc_module_begin()
set_description(N_("Direct3D11 Video Acceleration"))
set_subcategory(SUBCAT_INPUT_VCODEC)
set_va_callback(Open, 110)
vlc_module_end()
typedef struct
{
d3d11_device_t *d3d_dev;
vlc_video_context *vctx;
const d3d_format_t *render_fmt;
/* Video decoder */
D3D11_VIDEO_DECODER_CONFIG cfg;
const directx_va_mode_t *selected_decoder;
ID3D11VideoDevice *d3ddec;
/* avcodec internals */
struct AVD3D11VAContext hw;
/* pool */
va_pool_t *va_pool;
ID3D11VideoDecoderOutputView *hw_surface[MAX_SURFACE_COUNT];
ID3D11ShaderResourceView *renderSrc[MAX_SURFACE_COUNT * DXGI_MAX_SHADER_VIEW];
} vlc_va_sys_t;
/* */
static int D3dCreateDevice(vlc_va_t *);
static int DxGetInputList(vlc_va_t *, input_list_t *);
static int DxSetupOutput(vlc_va_t *, const directx_va_mode_t *, const video_format_t *);
static int DxCreateDecoderSurfaces(vlc_va_t *, int codec_id,
const video_format_t *fmt, size_t surface_count);
static void DxDestroySurfaces(void *);
static void SetupAVCodecContext(void *opaque, AVCodecContext *avctx)
{
vlc_va_sys_t *sys = opaque;
sys->hw.cfg = &sys->cfg;
sys->hw.surface = sys->hw_surface;
sys->hw.context_mutex = sys->d3d_dev->context_mutex;
#ifndef FF_DXVA_WORKAROUND_GONE
sys->hw.workaround = sys->selected_decoder->workaround;
#endif
avctx->hwaccel_context = &sys->hw;
}
static void d3d11va_pic_context_destroy(picture_context_t *ctx)
{
struct d3d11va_pic_context *pic_ctx = D3D11VA_PICCONTEXT_FROM_PICCTX(ctx);
struct vlc_va_surface_t *va_surface = pic_ctx->va_surface;
static_assert(offsetof(struct d3d11va_pic_context, ctx.s) == 0,
"Cast assumption failure");
d3d11_pic_context_destroy(ctx);
va_surface_Release(va_surface);
}
static picture_context_t *d3d11va_pic_context_copy(picture_context_t *ctx)
{
struct d3d11va_pic_context *src_ctx = D3D11VA_PICCONTEXT_FROM_PICCTX(ctx);
struct d3d11va_pic_context *pic_ctx = malloc(sizeof(*pic_ctx));
if (unlikely(pic_ctx==NULL))
return NULL;
*pic_ctx = *src_ctx;
vlc_video_context_Hold(pic_ctx->ctx.s.vctx);
va_surface_AddRef(pic_ctx->va_surface);
for (int i=0;i<DXGI_MAX_SHADER_VIEW; i++)
{
pic_ctx->ctx.picsys.resource[i] = src_ctx->ctx.picsys.resource[i];
pic_ctx->ctx.picsys.renderSrc[i] = src_ctx->ctx.picsys.renderSrc[i];
}
AcquireD3D11PictureSys(&pic_ctx->ctx.picsys);
return &pic_ctx->ctx.s;
}
static struct d3d11va_pic_context *CreatePicContext(ID3D11Resource *p_resource,
UINT slice,
ID3D11ShaderResourceView *renderSrc[DXGI_MAX_SHADER_VIEW],
vlc_video_context *vctx)
{
struct d3d11va_pic_context *pic_ctx = calloc(1, sizeof(*pic_ctx));
if (unlikely(pic_ctx==NULL))
return NULL;
pic_ctx->ctx.s = (picture_context_t) {
d3d11va_pic_context_destroy, d3d11va_pic_context_copy,
vlc_video_context_Hold(vctx),
};
pic_ctx->ctx.picsys.slice_index = slice;
pic_ctx->ctx.picsys.sharedHandle = INVALID_HANDLE_VALUE;
for (int i=0;i<DXGI_MAX_SHADER_VIEW; i++)
{
pic_ctx->ctx.picsys.resource[i] = p_resource;
pic_ctx->ctx.picsys.renderSrc[i] = renderSrc[i];
}
AcquireD3D11PictureSys(&pic_ctx->ctx.picsys);
return pic_ctx;
}
static picture_context_t* NewSurfacePicContext(vlc_va_t *va, vlc_va_surface_t *va_surface)
{
vlc_va_sys_t *sys = va->sys;
ID3D11VideoDecoderOutputView *surface = sys->hw_surface[va_surface_GetIndex(va_surface)];
ID3D11ShaderResourceView *resourceView[DXGI_MAX_SHADER_VIEW];
D3D11_VIDEO_DECODER_OUTPUT_VIEW_DESC viewDesc;
ID3D11VideoDecoderOutputView_GetDesc(surface, &viewDesc);
for (size_t i=0; i<DXGI_MAX_SHADER_VIEW; i++)
resourceView[i] = sys->renderSrc[viewDesc.Texture2D.ArraySlice*DXGI_MAX_SHADER_VIEW + i];
ID3D11Resource *p_resource;
ID3D11VideoDecoderOutputView_GetResource(surface, &p_resource);
struct d3d11va_pic_context *pic_ctx = CreatePicContext(p_resource,
viewDesc.Texture2D.ArraySlice,
resourceView, sys->vctx);
ID3D11Resource_Release(p_resource);
if (unlikely(pic_ctx==NULL))
return NULL;
pic_ctx->va_surface = va_surface;
return &pic_ctx->ctx.s;
}
static int Get(vlc_va_t *va, picture_t *pic, AVCodecContext *ctx, AVFrame *frame)
{
(void) ctx;
vlc_va_sys_t *sys = va->sys;
vlc_va_surface_t *va_surface = va_pool_Get(sys->va_pool);
if (unlikely(va_surface == NULL))
return VLC_ENOENT;
pic->context = NewSurfacePicContext(va, va_surface);
if (unlikely(pic->context == NULL))
{
va_surface_Release(va_surface);
return VLC_ENOMEM;
}
frame->data[3] = (uint8_t*)sys->hw_surface[va_surface_GetIndex(va_surface)];
return VLC_SUCCESS;
}
static void Close(vlc_va_t *va, AVCodecContext* ctx)
{
vlc_va_sys_t *sys = va->sys;
if (sys->vctx)
vlc_video_context_Release(sys->vctx);
if (sys->va_pool)
va_pool_Close(sys->va_pool);
if (ctx)
ctx->hwaccel_context = NULL;
}
static const struct vlc_va_operations ops = { Get, Close, };
static int Open(vlc_va_t *va, AVCodecContext *ctx, enum AVPixelFormat hwfmt, const AVPixFmtDescriptor *desc,
const es_format_t *fmt_in, vlc_decoder_device *dec_device,
video_format_t *fmt_out, vlc_video_context **vtcx_out)
{
int err = VLC_EGENERIC;
ctx->hwaccel_context = NULL;
if ( hwfmt != AV_PIX_FMT_D3D11VA_VLD )
return VLC_EGENERIC;
d3d11_decoder_device_t *devsys = GetD3D11OpaqueDevice( dec_device );
if ( devsys == NULL )
return VLC_EGENERIC;
if (!(ID3D11Device_GetCreationFlags(devsys->d3d_dev.d3ddevice) & D3D11_CREATE_DEVICE_VIDEO_SUPPORT))
{
msg_Err(va, "Missing D3D11_CREATE_DEVICE_VIDEO_SUPPORT");
return VLC_EGENERIC;
}
vlc_va_sys_t *sys = calloc(1, sizeof (*sys));
if (unlikely(sys == NULL))
return VLC_ENOMEM;
va->sys = sys;
sys->render_fmt = NULL;
sys->d3d_dev = &devsys->d3d_dev;
if (sys->d3d_dev->context_mutex == INVALID_HANDLE_VALUE)
msg_Warn(va, "No mutex found to lock the decoder");
struct va_pool_cfg pool_cfg = {
D3dCreateDevice,
DxDestroySurfaces,
DxCreateDecoderSurfaces,
SetupAVCodecContext,
sys,
};
sys->va_pool = va_pool_Create(va, &pool_cfg);
if (sys->va_pool == NULL)
{
err = VLC_EGENERIC;
goto error;
}
video_format_t final_fmt = *fmt_out;
static const directx_sys_t dx_sys = { DxGetInputList, DxSetupOutput };
sys->selected_decoder = directx_va_Setup(va, &dx_sys, ctx, desc, fmt_in, isXboxHardware(sys->d3d_dev),
&final_fmt, &sys->hw.surface_count);
if (sys->selected_decoder == NULL)
{
err = VLC_EGENERIC;
goto error;
}
final_fmt.i_chroma = sys->render_fmt->fourcc;
err = va_pool_SetupDecoder(va, sys->va_pool, ctx, &final_fmt, sys->hw.surface_count);
if (err != VLC_SUCCESS)
goto error;
msg_Info(va, "Using D3D11VA (%ls, vendor %x(%s), device %x, revision %x)",
sys->d3d_dev->adapterDesc.Description,
sys->d3d_dev->adapterDesc.VendorId, DxgiVendorStr(sys->d3d_dev->adapterDesc.VendorId),
sys->d3d_dev->adapterDesc.DeviceId, sys->d3d_dev->adapterDesc.Revision);
sys->vctx = D3D11CreateVideoContext(dec_device, sys->render_fmt->formatTexture, sys->render_fmt->alphaTexture);
if (sys->vctx == NULL)
{
msg_Dbg(va, "no video context");
err = VLC_EGENERIC;
goto error;
}
va->ops = &ops;
*fmt_out = final_fmt;
*vtcx_out = sys->vctx;
return VLC_SUCCESS;
error:
Close(va, ctx);
return err;
}
/**
* It creates a Direct3D device usable for decoding
*/
static int D3dCreateDevice(vlc_va_t *va)
{
vlc_va_sys_t *sys = va->sys;
HRESULT hr;
assert(sys->d3d_dev->d3ddevice && sys->d3d_dev->d3dcontext);
void *d3dvidctx = NULL;
hr = ID3D11DeviceContext_QueryInterface(sys->d3d_dev->d3dcontext, &IID_ID3D11VideoContext, &d3dvidctx);
if (FAILED(hr)) {
msg_Err(va, "Could not Query ID3D11VideoContext Interface. (hr=0x%lX)", hr);
return VLC_EGENERIC;
}
sys->hw.video_context = d3dvidctx;
void *d3dviddev = NULL;
hr = ID3D11Device_QueryInterface(sys->d3d_dev->d3ddevice, &IID_ID3D11VideoDevice, &d3dviddev);
if (FAILED(hr)) {
msg_Err(va, "Could not Query ID3D11VideoDevice Interface. (hr=0x%lX)", hr);
ID3D11VideoContext_Release(sys->hw.video_context);
return VLC_EGENERIC;
}
sys->d3ddec = d3dviddev;
return VLC_SUCCESS;
}
static void ReleaseInputList(input_list_t *p_list)
{
free(p_list->list);
}
static int DxGetInputList(vlc_va_t *va, input_list_t *p_list)
{
vlc_va_sys_t *sys = va->sys;
HRESULT hr;
UINT input_count = ID3D11VideoDevice_GetVideoDecoderProfileCount(sys->d3ddec);
p_list->count = input_count;
p_list->list = calloc(input_count, sizeof(*p_list->list));
if (unlikely(p_list->list == NULL)) {
return VLC_ENOMEM;
}
p_list->pf_release = ReleaseInputList;
for (unsigned i = 0; i < input_count; i++) {
hr = ID3D11VideoDevice_GetVideoDecoderProfile(sys->d3ddec, i, &p_list->list[i]);
if (FAILED(hr))
{
msg_Err(va, "GetVideoDecoderProfile %d failed. (hr=0x%lX)", i, hr);
ReleaseInputList(p_list);
return VLC_EGENERIC;
}
}
return VLC_SUCCESS;
}
static int DxSetupOutput(vlc_va_t *va, const directx_va_mode_t *mode, const video_format_t *fmt)
{
vlc_va_sys_t *sys = va->sys;
HRESULT hr;
#ifndef NDEBUG
BOOL bSupported = false;
for (int format = 0; format < 188; format++) {
hr = ID3D11VideoDevice_CheckVideoDecoderFormat(sys->d3ddec, mode->guid, format, &bSupported);
if (SUCCEEDED(hr) && bSupported)
msg_Dbg(va, "format %s is supported for output", DxgiFormatToStr(format));
}
#endif
if (!directx_va_canUseDecoder(va, sys->d3d_dev->adapterDesc.VendorId, sys->d3d_dev->adapterDesc.DeviceId,
mode->guid, sys->d3d_dev->WDDM.build))
{
msg_Warn(va, "GPU blocklisted for %s codec", mode->name);
return VLC_EGENERIC;
}
const d3d_format_t *processorInput[4];
int idx = 0;
const d3d_format_t *decoder_format;
UINT supportFlags = D3D11_FORMAT_SUPPORT_DECODER_OUTPUT;
// enough sub-sampling+bit depth, with any alpha
decoder_format = FindD3D11Format( va, sys->d3d_dev, 0, DXGI_RGB_FORMAT|DXGI_YUV_FORMAT,
mode->bit_depth, mode->log2_chroma_h+1, mode->log2_chroma_w+1, -1,
DXGI_CHROMA_GPU, supportFlags );
if (decoder_format == NULL)
// other chroma sub-sampling
decoder_format = FindD3D11Format( va, sys->d3d_dev, 0, DXGI_RGB_FORMAT|DXGI_YUV_FORMAT,
mode->bit_depth, 0, 0, 0, DXGI_CHROMA_GPU, supportFlags );
if (decoder_format == NULL && mode->bit_depth > 10)
// 10 bits instead of 8/12/14/16
decoder_format = FindD3D11Format( va, sys->d3d_dev, 0, DXGI_RGB_FORMAT|DXGI_YUV_FORMAT,
10, 0, 0, 0, DXGI_CHROMA_GPU, supportFlags );
if (decoder_format == NULL)
// any bit depth
decoder_format = FindD3D11Format( va, sys->d3d_dev, 0, DXGI_RGB_FORMAT|DXGI_YUV_FORMAT,
0, 0, 0, 0, DXGI_CHROMA_GPU, supportFlags );
if (decoder_format != NULL)
{
msg_Dbg(va, "favor decoder format %s", decoder_format->name);
processorInput[idx++] = decoder_format;
}
if (decoder_format == NULL || decoder_format->formatTexture != DXGI_FORMAT_NV12)
processorInput[idx++] = D3D11_RenderFormat(DXGI_FORMAT_NV12, DXGI_FORMAT_UNKNOWN ,true);
processorInput[idx++] = D3D11_RenderFormat(DXGI_FORMAT_420_OPAQUE, DXGI_FORMAT_UNKNOWN ,true);
processorInput[idx++] = NULL;
/* */
for (idx = 0; processorInput[idx] != NULL; ++idx)
{
BOOL is_supported = false;
hr = ID3D11VideoDevice_CheckVideoDecoderFormat(sys->d3ddec, mode->guid, processorInput[idx]->formatTexture, &is_supported);
if (SUCCEEDED(hr) && is_supported)
msg_Dbg(va, "%s output is supported for decoder %s.", DxgiFormatToStr(processorInput[idx]->formatTexture), mode->name);
else
{
msg_Dbg(va, "Can't get a decoder output format %s for decoder %s.", DxgiFormatToStr(processorInput[idx]->formatTexture), mode->name);
continue;
}
// check if we can create render texture of that format
// check the decoder can output to that format
if ( !D3D11_DeviceSupportsFormat(sys->d3d_dev, processorInput[idx]->formatTexture,
D3D11_FORMAT_SUPPORT_SHADER_LOAD) )
{
#ifndef ID3D11VideoContext_VideoProcessorBlt
msg_Dbg(va, "Format %s needs a processor but is not supported",
DxgiFormatToStr(processorInput[idx]->formatTexture));
#else
if ( !D3D11_DeviceSupportsFormat(sys->d3d_dev, processorInput[idx]->formatTexture,
D3D11_FORMAT_SUPPORT_VIDEO_PROCESSOR_INPUT) )
{
msg_Dbg(va, "Format %s needs a processor but is not available",
DxgiFormatToStr(processorInput[idx]->formatTexture));
continue;
}
#endif
}
D3D11_VIDEO_DECODER_DESC decoderDesc;
ZeroMemory(&decoderDesc, sizeof(decoderDesc));
decoderDesc.Guid = *mode->guid;
decoderDesc.SampleWidth = fmt->i_width;
decoderDesc.SampleHeight = fmt->i_height;
decoderDesc.OutputFormat = processorInput[idx]->formatTexture;
UINT cfg_count = 0;
hr = ID3D11VideoDevice_GetVideoDecoderConfigCount( sys->d3ddec, &decoderDesc, &cfg_count );
if (FAILED(hr))
{
msg_Err( va, "Failed to get configuration for decoder %s. (hr=0x%lX)", mode->name, hr );
continue;
}
if (cfg_count == 0) {
msg_Err( va, "No decoder configuration possible for %s %dx%d",
DxgiFormatToStr(decoderDesc.OutputFormat),
decoderDesc.SampleWidth, decoderDesc.SampleHeight );
continue;
}
msg_Dbg(va, "Using output format %s for decoder %s", DxgiFormatToStr(processorInput[idx]->formatTexture), mode->name);
sys->render_fmt = processorInput[idx];
return VLC_SUCCESS;
}
msg_Dbg(va, "Output format from picture source not supported.");
return VLC_EGENERIC;
}
/**
* It creates a Direct3D11 decoder using the given video format
*/
static int DxCreateDecoderSurfaces(vlc_va_t *va, int codec_id,
const video_format_t *fmt, size_t surface_count)
{
vlc_va_sys_t *sys = va->sys;
HRESULT hr;
d3d11_device_lock(sys->d3d_dev);
void *pv;
hr = ID3D11Device_QueryInterface( sys->d3d_dev->d3ddevice, &IID_ID3D10Multithread, &pv);
if (SUCCEEDED(hr)) {
ID3D10Multithread *pMultithread = pv;
ID3D10Multithread_SetMultithreadProtected(pMultithread, TRUE);
ID3D10Multithread_Release(pMultithread);
}
/* On the Xbox 1/S, any decoding of H264 with one dimension over 2304
* crashes totally the device */
if (codec_id == AV_CODEC_ID_H264 &&
(fmt->i_width > 2304 || fmt->i_height > 2304) &&
isXboxHardware(sys->d3d_dev))
{
msg_Warn(va, "%dx%d resolution not supported by your hardware", fmt->i_width, fmt->i_height);
d3d11_device_unlock(sys->d3d_dev);
return VLC_EGENERIC;
}
D3D11_VIDEO_DECODER_OUTPUT_VIEW_DESC viewDesc;
ZeroMemory(&viewDesc, sizeof(viewDesc));
viewDesc.DecodeProfile = *sys->selected_decoder->guid;
viewDesc.ViewDimension = D3D11_VDOV_DIMENSION_TEXTURE2D;
D3D11_TEXTURE2D_DESC texDesc;
ZeroMemory(&texDesc, sizeof(texDesc));
texDesc.Width = fmt->i_width;
texDesc.Height = fmt->i_height;
texDesc.MipLevels = 1;
texDesc.Format = sys->render_fmt->formatTexture;
texDesc.SampleDesc.Count = 1;
texDesc.MiscFlags = 0;
texDesc.ArraySize = surface_count;
texDesc.Usage = D3D11_USAGE_DEFAULT;
texDesc.BindFlags = D3D11_BIND_DECODER;
texDesc.CPUAccessFlags = 0;
if (D3D11_DeviceSupportsFormat(sys->d3d_dev, texDesc.Format, D3D11_FORMAT_SUPPORT_SHADER_LOAD))
texDesc.BindFlags |= D3D11_BIND_SHADER_RESOURCE;
ID3D11Texture2D *p_texture;
hr = ID3D11Device_CreateTexture2D( sys->d3d_dev->d3ddevice, &texDesc, NULL, &p_texture );
if (FAILED(hr)) {
msg_Err(va, "CreateTexture2D %zu failed. (hr=0x%lX)", surface_count, hr);
d3d11_device_unlock(sys->d3d_dev);
return VLC_EGENERIC;
}
unsigned surface_idx;
for (surface_idx = 0; surface_idx < surface_count; surface_idx++) {
viewDesc.Texture2D.ArraySlice = surface_idx;
hr = ID3D11VideoDevice_CreateVideoDecoderOutputView( sys->d3ddec,
(ID3D11Resource*) p_texture,
&viewDesc,
&sys->hw_surface[surface_idx] );
if (FAILED(hr)) {
msg_Err(va, "CreateVideoDecoderOutputView %d failed. (hr=0x%lX)", surface_idx, hr);
ID3D11Texture2D_Release(p_texture);
d3d11_device_unlock(sys->d3d_dev);
return VLC_EGENERIC;
}
if (texDesc.BindFlags & D3D11_BIND_SHADER_RESOURCE)
{
ID3D11Texture2D *textures[DXGI_MAX_SHADER_VIEW] = {p_texture, p_texture, p_texture};
D3D11_AllocateResourceView(vlc_object_logger(va), sys->d3d_dev->d3ddevice, sys->render_fmt, textures, surface_idx,
&sys->renderSrc[surface_idx * DXGI_MAX_SHADER_VIEW]);
}
}
ID3D11Texture2D_Release(p_texture);
msg_Dbg(va, "ID3D11VideoDecoderOutputView succeed with %zu surfaces (%dx%d)",
surface_count, fmt->i_width, fmt->i_height);
D3D11_VIDEO_DECODER_DESC decoderDesc;
ZeroMemory(&decoderDesc, sizeof(decoderDesc));
decoderDesc.Guid = *sys->selected_decoder->guid;
decoderDesc.SampleWidth = fmt->i_width;
decoderDesc.SampleHeight = fmt->i_height;
decoderDesc.OutputFormat = sys->render_fmt->formatTexture;
UINT cfg_count;
hr = ID3D11VideoDevice_GetVideoDecoderConfigCount( sys->d3ddec, &decoderDesc, &cfg_count );
if (FAILED(hr)) {
msg_Err(va, "GetVideoDecoderConfigCount failed. (hr=0x%lX)", hr);
d3d11_device_unlock(sys->d3d_dev);
return VLC_EGENERIC;
}
/* List all configurations available for the decoder */
D3D11_VIDEO_DECODER_CONFIG cfg_list[cfg_count];
for (unsigned i = 0; i < cfg_count; i++) {
hr = ID3D11VideoDevice_GetVideoDecoderConfig( sys->d3ddec, &decoderDesc, i, &cfg_list[i] );
if (FAILED(hr)) {
msg_Err(va, "GetVideoDecoderConfig failed. (hr=0x%lX)", hr);
d3d11_device_unlock(sys->d3d_dev);
return VLC_EGENERIC;
}
}
msg_Dbg(va, "we got %d decoder configurations", cfg_count);
/* Select the best decoder configuration */
int cfg_score = 0;
for (unsigned i = 0; i < cfg_count; i++) {
const D3D11_VIDEO_DECODER_CONFIG *cfg = &cfg_list[i];
/* */
msg_Dbg(va, "configuration[%d] ConfigBitstreamRaw %d",
i, cfg->ConfigBitstreamRaw);
/* */
int score;
if (cfg->ConfigBitstreamRaw == 1)
score = 1;
else if (codec_id == AV_CODEC_ID_H264 && cfg->ConfigBitstreamRaw == 2)
score = 2;
else
continue;
if (IsEqualGUID(&cfg->guidConfigBitstreamEncryption, &DXVA_NoEncrypt))
score += 16;
if (cfg_score < score) {
sys->cfg = *cfg;
cfg_score = score;
}
}
if (cfg_score <= 0) {
msg_Err(va, "Failed to find a supported decoder configuration");
d3d11_device_unlock(sys->d3d_dev);
return VLC_EGENERIC;
}
/* Create the decoder */
ID3D11VideoDecoder *decoder;
hr = ID3D11VideoDevice_CreateVideoDecoder( sys->d3ddec, &decoderDesc, &sys->cfg, &decoder );
if (FAILED(hr)) {
msg_Err(va, "ID3D11VideoDevice_CreateVideoDecoder failed. (hr=0x%lX)", hr);
sys->hw.decoder = NULL;
d3d11_device_unlock(sys->d3d_dev);
return VLC_EGENERIC;
}
d3d11_device_unlock(sys->d3d_dev);
sys->hw.decoder = decoder;
msg_Dbg(va, "DxCreateDecoderSurfaces succeed");
return VLC_SUCCESS;
}
static void DxDestroySurfaces(void *opaque)
{
vlc_va_sys_t *sys = opaque;
if (sys->hw.decoder)
ID3D11VideoDecoder_Release(sys->hw.decoder);
if (sys->hw_surface[0]) {
for (unsigned i = 0; i < sys->hw.surface_count; i++)
{
for (int j = 0; j < DXGI_MAX_SHADER_VIEW; j++)
{
if (sys->renderSrc[i*DXGI_MAX_SHADER_VIEW + j])
ID3D11ShaderResourceView_Release(sys->renderSrc[i*DXGI_MAX_SHADER_VIEW + j]);
}
ID3D11VideoDecoderOutputView_Release( sys->hw_surface[i] );
}
}
if (sys->d3ddec)
ID3D11VideoDevice_Release(sys->d3ddec);
if (sys->hw.video_context)
ID3D11VideoContext_Release(sys->hw.video_context);
free(sys);
}