Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[VideoPlayer] d3d11va improvements. #9198

Merged
merged 3 commits into from
Feb 24, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion xbmc/cores/VideoPlayer/DVDCodecs/DVDCodecUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,7 @@ static const EFormatMap g_format_map[] = {
, { AV_PIX_FMT_UYVY422, RENDER_FMT_UYVY422 }
, { AV_PIX_FMT_YUYV422, RENDER_FMT_YUYV422 }
, { AV_PIX_FMT_VAAPI_VLD, RENDER_FMT_VAAPI }
, { AV_PIX_FMT_DXVA2_VLD, RENDER_FMT_DXVA }
, { AV_PIX_FMT_D3D11VA_VLD, RENDER_FMT_DXVA }
, { AV_PIX_FMT_NONE , RENDER_FMT_NONE }
};

Expand Down
132 changes: 37 additions & 95 deletions xbmc/cores/VideoPlayer/DVDCodecs/Video/DXVA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ static const dxva2_mode_t dxva2_modes[] = {

/* HEVC / H.265 */
{ "HEVC / H.265 variable-length decoder, main", &D3D11_DECODER_PROFILE_HEVC_VLD_MAIN, AV_CODEC_ID_HEVC },
{ "HEVC / H.265 variable-length decoder, main10", &D3D11_DECODER_PROFILE_HEVC_VLD_MAIN10, 0 },
{ "HEVC / H.265 variable-length decoder, main10", &D3D11_DECODER_PROFILE_HEVC_VLD_MAIN10, AV_CODEC_ID_HEVC },

#ifdef FF_DXVA2_WORKAROUND_INTEL_CLEARVIDEO
/* Intel specific modes (only useful on older GPUs) */
Expand Down Expand Up @@ -209,79 +209,6 @@ static const dxva2_mode_t *dxva2_find_mode(const GUID *guid)
return nullptr;
}

//-----------------------------------------------------------------------------
// DXVA to D3D11 Video API Wrapper
//-----------------------------------------------------------------------------

CDXVADecoderWrapper::CDXVADecoderWrapper(ID3D11VideoContext* pContext, ID3D11VideoDecoder* pDecoder)
: m_refs(1), m_pContext(pContext), m_pDecoder(pDecoder)
{
assert(pContext != nullptr);
assert(pDecoder != nullptr);
m_pContext->AddRef();
m_pDecoder->AddRef();
};

CDXVADecoderWrapper::~CDXVADecoderWrapper()
{
SAFE_RELEASE(m_pContext);
SAFE_RELEASE(m_pDecoder);
};

STDMETHODIMP_(ULONG) CDXVADecoderWrapper::AddRef(void)
{
return AtomicIncrement(&m_refs);
}

STDMETHODIMP_(ULONG) CDXVADecoderWrapper::Release(void)
{
long refs = AtomicDecrement(&m_refs);
assert(refs >= 0);
if (refs == 0) delete this;
return refs;
};

STDMETHODIMP CDXVADecoderWrapper::GetBuffer(UINT BufferType, void **ppBuffer, UINT *pBufferSize)
{
return m_pContext->GetDecoderBuffer(m_pDecoder, (D3D11_VIDEO_DECODER_BUFFER_TYPE)BufferType, pBufferSize, ppBuffer);
};

STDMETHODIMP CDXVADecoderWrapper::ReleaseBuffer(UINT BufferType)
{
return m_pContext->ReleaseDecoderBuffer(m_pDecoder, (D3D11_VIDEO_DECODER_BUFFER_TYPE)BufferType);
};

STDMETHODIMP CDXVADecoderWrapper::BeginFrame(IDirect3DSurface9 *pRenderTarget, void *pvPVPData)
{
return m_pContext->DecoderBeginFrame(m_pDecoder, reinterpret_cast<ID3D11VideoDecoderOutputView*>(pRenderTarget), 0, pvPVPData);
};

STDMETHODIMP CDXVADecoderWrapper::EndFrame(HANDLE *pHandleComplete)
{
return m_pContext->DecoderEndFrame(m_pDecoder);
};

STDMETHODIMP CDXVADecoderWrapper::Execute(const DXVA2_DecodeExecuteParams *pExecuteParams)
{
D3D11_VIDEO_DECODER_BUFFER_DESC buffer[4];
for (size_t i = 0; i < pExecuteParams->NumCompBuffers; i++)
{
ZeroMemory(&buffer[i], sizeof(D3D11_VIDEO_DECODER_BUFFER_DESC));
buffer[i].BufferType = (D3D11_VIDEO_DECODER_BUFFER_TYPE)pExecuteParams->pCompressedBuffers[i].CompressedBufferType;
buffer[i].BufferIndex = pExecuteParams->pCompressedBuffers[i].BufferIndex;
buffer[i].DataOffset = pExecuteParams->pCompressedBuffers[i].DataOffset;
buffer[i].DataSize = pExecuteParams->pCompressedBuffers[i].DataSize;
buffer[i].FirstMBaddress = pExecuteParams->pCompressedBuffers[i].FirstMBaddress;
buffer[i].NumMBsInBuffer = pExecuteParams->pCompressedBuffers[i].NumMBsInBuffer;
buffer[i].Width = pExecuteParams->pCompressedBuffers[i].Width;
buffer[i].Height = pExecuteParams->pCompressedBuffers[i].Height;
buffer[i].Stride = pExecuteParams->pCompressedBuffers[i].Stride;
buffer[i].ReservedBits = pExecuteParams->pCompressedBuffers[i].ReservedBits;
buffer[i].pIV = pExecuteParams->pCompressedBuffers[i].pvPVPState;
}
return m_pContext->SubmitDecoderBuffers(m_pDecoder, pExecuteParams->NumCompBuffers, buffer);
}

//-----------------------------------------------------------------------------
// DXVA Context
//-----------------------------------------------------------------------------
Expand Down Expand Up @@ -401,7 +328,7 @@ void CDXVAContext::QueryCaps()
}
}

bool CDXVAContext::GetInputAndTarget(int codec, GUID &inGuid, DXGI_FORMAT &outFormat)
bool CDXVAContext::GetInputAndTarget(int codec, bool bHighBitdepth, GUID &inGuid, DXGI_FORMAT &outFormat)
{
outFormat = DXGI_FORMAT_UNKNOWN;

Expand All @@ -414,13 +341,26 @@ bool CDXVAContext::GetInputAndTarget(int codec, GUID &inGuid, DXGI_FORMAT &outFo

for (unsigned i = 0; i < m_input_count && outFormat == DXGI_FORMAT_UNKNOWN; i++)
{
if (!IsEqualGUID(m_input_list[i], *mode->guid))
bool supported = IsEqualGUID(m_input_list[i], *mode->guid);
if (codec == AV_CODEC_ID_HEVC)
{
if (bHighBitdepth && !IsEqualGUID(m_input_list[i], D3D11_DECODER_PROFILE_HEVC_VLD_MAIN10))
supported = false;
else if (!bHighBitdepth && IsEqualGUID(m_input_list[i], D3D11_DECODER_PROFILE_HEVC_VLD_MAIN10))
supported = false;
}
if (!supported)
continue;

CLog::Log(LOGDEBUG, "DXVA - trying '%s'", mode->name);
for (unsigned j = 0; render_targets_dxgi[j] != DXGI_FORMAT_UNKNOWN && outFormat == DXGI_FORMAT_UNKNOWN; j++)
{
BOOL supported;
if (bHighBitdepth && render_targets_dxgi[j] != DXGI_FORMAT_P010 && render_targets_dxgi[j] != DXGI_FORMAT_P016)
continue;
if (!bHighBitdepth && (render_targets_dxgi[j] == DXGI_FORMAT_P010 || render_targets_dxgi[j] == DXGI_FORMAT_P016))
continue;

HRESULT res = m_service->CheckVideoDecoderFormat(&m_input_list[i], render_targets_dxgi[j], &supported);
if (FAILED(res))
{
Expand Down Expand Up @@ -533,7 +473,7 @@ bool CDXVAContext::CreateSurfaces(D3D11_VIDEO_DECODER_DESC format, unsigned int
return SUCCEEDED(hr);
}

bool CDXVAContext::CreateDecoder(D3D11_VIDEO_DECODER_DESC *format, const D3D11_VIDEO_DECODER_CONFIG *config, CDXVADecoderWrapper **decoder)
bool CDXVAContext::CreateDecoder(D3D11_VIDEO_DECODER_DESC *format, const D3D11_VIDEO_DECODER_CONFIG *config, ID3D11VideoDecoder **decoder, ID3D11VideoContext **context)
{
CSingleLock lock(m_section);

Expand All @@ -546,8 +486,9 @@ bool CDXVAContext::CreateDecoder(D3D11_VIDEO_DECODER_DESC *format, const D3D11_V
HRESULT res = m_service->CreateVideoDecoder(format, config, &pDecoder);
if (!FAILED(res))
{
*decoder = new CDXVADecoderWrapper(m_vcontext, pDecoder);
SAFE_RELEASE(pDecoder);
*decoder = pDecoder;
*context = m_vcontext;
m_vcontext->AddRef();
return true;
}
}
Expand Down Expand Up @@ -755,15 +696,16 @@ CDecoder::CDecoder()
m_state = DXVA_OPEN;
m_device = nullptr;
m_decoder = nullptr;
m_vcontext = nullptr;
m_refs = 0;
m_shared = 0;
m_surface_context = nullptr;
m_presentPicture = nullptr;
m_dxva_context = nullptr;
memset(&m_format, 0, sizeof(m_format));
m_context = (dxva_context*)calloc(1, sizeof(dxva_context));
m_context->cfg = reinterpret_cast<DXVA2_ConfigPictureDecode*>(calloc(1, sizeof(DXVA2_ConfigPictureDecode)));
m_context->surface = reinterpret_cast<IDirect3DSurface9**>(calloc(32, sizeof(IDirect3DSurface9*)));
m_context = (AVD3D11VAContext*)calloc(1, sizeof(AVD3D11VAContext));
m_context->cfg = reinterpret_cast<D3D11_VIDEO_DECODER_CONFIG*>(calloc(1, sizeof(D3D11_VIDEO_DECODER_CONFIG)));
m_context->surface = reinterpret_cast<ID3D11VideoDecoderOutputView**>(calloc(32, sizeof(ID3D11VideoDecoderOutputView*)));
m_surface_alignment = 16;
g_Windowing.Register(this);
}
Expand All @@ -774,7 +716,7 @@ CDecoder::~CDecoder()
g_Windowing.Unregister(this);
Close();
free(m_context->surface);
free(const_cast<DXVA2_ConfigPictureDecode*>(m_context->cfg)); // yes this is foobar
free(m_context->cfg);
free(m_context);
}

Expand All @@ -792,6 +734,7 @@ void CDecoder::Close()
{
CSingleLock lock(m_section);
SAFE_RELEASE(m_decoder);
SAFE_RELEASE(m_vcontext);
SAFE_RELEASE(m_surface_context);
SAFE_RELEASE(m_presentPicture);
memset(&m_format, 0, sizeof(m_format));
Expand Down Expand Up @@ -896,7 +839,8 @@ bool CDecoder::Open(AVCodecContext *avctx, AVCodecContext* mainctx, enum AVPixel
if (!CDXVAContext::EnsureContext(&m_dxva_context, this))
return false;

if (!m_dxva_context->GetInputAndTarget(avctx->codec_id, m_format.Guid, m_format.OutputFormat))
bool bHighBitdepth = (avctx->codec_id == AV_CODEC_ID_HEVC && (avctx->sw_pix_fmt == AV_PIX_FMT_YUV420P10 || avctx->profile == FF_PROFILE_HEVC_MAIN_10));
if (!m_dxva_context->GetInputAndTarget(avctx->codec_id, bHighBitdepth, m_format.Guid, m_format.OutputFormat))
{
CLog::Log(LOGDEBUG, "DXVA - unable to find an input/output format combination");
return false;
Expand Down Expand Up @@ -941,13 +885,9 @@ bool CDecoder::Open(AVCodecContext *avctx, AVCodecContext* mainctx, enum AVPixel
else
m_surface_alignment = 16;


D3D11_VIDEO_DECODER_CONFIG config = {0};
if (!m_dxva_context->GetConfig(&m_format, config))
if (!m_dxva_context->GetConfig(&m_format, *m_context->cfg))
return false;

memcpy((void *)m_context->cfg, &config, sizeof(DXVA2_ConfigPictureDecode));

m_surface_context = new CSurfaceContext();

if(!OpenDecoder())
Expand Down Expand Up @@ -1082,7 +1022,7 @@ int CDecoder::Check(AVCodecContext* avctx)
data.pPrivateOutputData = &status;
data.PrivateOutputDataSize = avctx->codec_id == AV_CODEC_ID_H264 ? sizeof(DXVA_Status_H264) : sizeof(DXVA_Status_VC1);
HRESULT hr;
if (FAILED(hr = m_dxva_context->GetVideoContext()->DecoderExtension(m_decoder->m_pDecoder, &data)))
if (FAILED(hr = m_dxva_context->GetVideoContext()->DecoderExtension(m_decoder, &data)))
{
CLog::Log(LOGWARNING, "DXVA - failed to get decoder status - 0x%08X", hr);
return VC_ERROR;
Expand All @@ -1104,32 +1044,34 @@ int CDecoder::Check(AVCodecContext* avctx)
bool CDecoder::OpenDecoder()
{
SAFE_RELEASE(m_decoder);
SAFE_RELEASE(m_vcontext);
m_context->decoder = nullptr;
m_context->video_context = nullptr;

m_context->surface_count = m_refs + 1 + 1 + m_shared; // refs + 1 decode + 1 libavcodec safety + processor buffer

CLog::Log(LOGDEBUG, "DXVA - allocating %d surfaces with format %d", m_context->surface_count, m_format.OutputFormat);

if (!m_dxva_context->CreateSurfaces(m_format, m_context->surface_count, m_surface_alignment,
reinterpret_cast<ID3D11VideoDecoderOutputView**>(m_context->surface)))
if (!m_dxva_context->CreateSurfaces(m_format, m_context->surface_count, m_surface_alignment, m_context->surface))
return false;

for(unsigned i = 0; i < m_context->surface_count; i++)
{
m_surface_context->AddSurface(reinterpret_cast<ID3D11VideoDecoderOutputView*>(m_context->surface[i]));
m_surface_context->AddSurface(m_context->surface[i]);
}

if (!m_dxva_context->CreateDecoder(&m_format, reinterpret_cast<D3D11_VIDEO_DECODER_CONFIG*>((DXVA2_ConfigPictureDecode*)m_context->cfg), &m_decoder))
if (!m_dxva_context->CreateDecoder(&m_format, m_context->cfg, &m_decoder, &m_vcontext))
return false;

m_context->decoder = m_decoder;
m_context->video_context = m_vcontext;

return true;
}

bool CDecoder::Supports(enum AVPixelFormat fmt)
{
if(fmt == AV_PIX_FMT_DXVA2_VLD)
if(fmt == AV_PIX_FMT_D3D11VA_VLD)
return true;
return false;
}
Expand Down
42 changes: 7 additions & 35 deletions xbmc/cores/VideoPlayer/DVDCodecs/Video/DXVA.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
#include "DVDResource.h"
#include "guilib/D3DResource.h"
#include "libavcodec/avcodec.h"
#include "libavcodec/dxva2.h"
#include "libavcodec/d3d11va.h"
#include "threads/Event.h"

namespace DXVA {
Expand Down Expand Up @@ -76,44 +76,15 @@ class CRenderPicture
CSurfaceContext *surface_context;
};

//-----------------------------------------------------------------------------
// DXVA to D3D11 Video API Wrapper
//-----------------------------------------------------------------------------
class CDXVADecoderWrapper : public IDirectXVideoDecoder
{
public:
CDXVADecoderWrapper(ID3D11VideoContext* pContext, ID3D11VideoDecoder* pDecoder);
~CDXVADecoderWrapper();
// unused
STDMETHODIMP QueryInterface(REFIID riid, void** ppvObject) { return E_NOTIMPL; };
STDMETHODIMP_(ULONG) AddRef(void);
STDMETHODIMP_(ULONG) Release(void);
// unused
STDMETHODIMP GetVideoDecoderService(IDirectXVideoDecoderService **ppService) { return E_NOTIMPL; };
// unused
STDMETHODIMP GetCreationParameters(GUID *pDeviceGuid, DXVA2_VideoDesc *pVideoDesc, DXVA2_ConfigPictureDecode *pConfig,
IDirect3DSurface9 ***pDecoderRenderTargets, UINT *pNumSurfaces) { return E_NOTIMPL; };
STDMETHODIMP GetBuffer(UINT BufferType, void **ppBuffer, UINT *pBufferSize);
STDMETHODIMP ReleaseBuffer(UINT BufferType);
STDMETHODIMP BeginFrame(IDirect3DSurface9 *pRenderTarget, void *pvPVPData);
STDMETHODIMP EndFrame(HANDLE *pHandleComplete);
STDMETHODIMP Execute(const DXVA2_DecodeExecuteParams *pExecuteParams);

ID3D11VideoDecoder* m_pDecoder;
private:
volatile long m_refs;
ID3D11VideoContext* m_pContext;
};

class CDecoder;
class CDXVAContext
{
public:
static bool EnsureContext(CDXVAContext **ctx, CDecoder *decoder);
bool GetInputAndTarget(int codec, GUID &inGuid, DXGI_FORMAT &outFormat);
bool GetInputAndTarget(int codec, bool bHighBitdepth, GUID &inGuid, DXGI_FORMAT &outFormat);
bool GetConfig(const D3D11_VIDEO_DECODER_DESC *format, D3D11_VIDEO_DECODER_CONFIG &config);
bool CreateSurfaces(D3D11_VIDEO_DECODER_DESC format, unsigned int count, unsigned int alignment, ID3D11VideoDecoderOutputView **surfaces);
bool CreateDecoder(D3D11_VIDEO_DECODER_DESC *format, const D3D11_VIDEO_DECODER_CONFIG *config, CDXVADecoderWrapper **decoder);
bool CreateDecoder(D3D11_VIDEO_DECODER_DESC *format, const D3D11_VIDEO_DECODER_CONFIG *config, ID3D11VideoDecoder **decoder, ID3D11VideoContext **context);
void Release(CDecoder *decoder);
ID3D11VideoContext* GetVideoContext() { return m_vcontext; }
private:
Expand Down Expand Up @@ -146,7 +117,7 @@ class CDecoder
virtual bool GetPicture(AVCodecContext* avctx, AVFrame* frame, DVDVideoPicture* picture);
virtual int Check (AVCodecContext* avctx);
virtual void Close();
virtual const std::string Name() { return "dxva2"; }
virtual const std::string Name() { return "d3d11va"; }
virtual unsigned GetAllowedReferences();
virtual long Release();

Expand All @@ -170,13 +141,14 @@ class CDecoder
virtual void OnLostDevice() { CSingleLock lock(m_section); m_state = DXVA_LOST; m_event.Reset(); }
virtual void OnResetDevice() { CSingleLock lock(m_section); m_state = DXVA_RESET; m_event.Set(); }

CDXVADecoderWrapper* m_decoder;
ID3D11VideoDecoder* m_decoder;
ID3D11VideoContext* m_vcontext;
HANDLE m_device;
D3D11_VIDEO_DECODER_DESC m_format;
int m_refs;
CRenderPicture *m_presentPicture;

struct dxva_context* m_context;
struct AVD3D11VAContext* m_context;

CSurfaceContext* m_surface_context;
CDXVAContext* m_dxva_context;
Expand Down