Skip to content

Commit

Permalink
Added support for HLG (Hybrid Log-Gamma) and Rec.2020 for Live TV
Browse files Browse the repository at this point in the history
Refactored and simplified some functions to be more easily re-usable.
  • Loading branch information
thexai committed Dec 19, 2019
1 parent 8182d6d commit a13a7d1
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 71 deletions.
64 changes: 36 additions & 28 deletions xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/DXVAHD.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,9 @@ DXGI_COLOR_SPACE_TYPE CProcessorHD::GetDXGIColorSpace(CRenderBuffer* view, bool
// DXGI_COLOR_SPACE_YCBCR_STUDIO_G2084_TOPLEFT_P2020
return DXGI_COLOR_SPACE_YCBCR_STUDIO_G2084_LEFT_P2020;

if (view->color_transfer == AVCOL_TRC_ARIB_STD_B67) // HLG
return DXGI_COLOR_SPACE_YCBCR_STUDIO_GHLG_TOPLEFT_P2020;

if (view->full_range)
return DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P2020;

Expand Down Expand Up @@ -505,18 +508,26 @@ bool CProcessorHD::Render(CRect src, CRect dst, ID3D11Resource* target, CRenderB
if (SUCCEEDED(m_pVideoContext.As(&videoCtx1)))
{
const DXGI_COLOR_SPACE_TYPE source_color = GetDXGIColorSpace(views[2], m_bSupportHDR10);
DXGI_COLOR_SPACE_TYPE target_color;
DXGI_COLOR_SPACE_TYPE target_color = DX::Windowing()->UseLimitedColor()
? DXGI_COLOR_SPACE_RGB_STUDIO_G22_NONE_P709
: DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709;

if (DX::DeviceResources::Get()->Is10BitSwapchain() && CRendererBase::IsStreamHDR10(views[2]))
{
target_color = DX::Windowing()->UseLimitedColor()
? DXGI_COLOR_SPACE_RGB_STUDIO_G2084_NONE_P2020
: DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020;
}
else
if (DX::DeviceResources::Get()->Is10BitSwapchain())
{
target_color = DX::Windowing()->UseLimitedColor() ? DXGI_COLOR_SPACE_RGB_STUDIO_G22_NONE_P709
: DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709;
if ((views[2]->color_transfer == AVCOL_TRC_SMPTE2084 ||
views[2]->color_transfer == AVCOL_TRC_ARIB_STD_B67) &&
views[2]->primaries == AVCOL_PRI_BT2020)
{
target_color = DX::Windowing()->UseLimitedColor()
? DXGI_COLOR_SPACE_RGB_STUDIO_G2084_NONE_P2020
: DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020;
}
else if (views[2]->primaries == AVCOL_PRI_BT2020)
{
target_color = DX::Windowing()->UseLimitedColor()
? DXGI_COLOR_SPACE_RGB_STUDIO_G22_NONE_P2020
: DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P2020;
}
}

videoCtx1->VideoProcessorSetStreamColorSpace1(m_pVideoProcessor.Get(), DEFAULT_STREAM_INDEX,
Expand All @@ -525,26 +536,23 @@ bool CProcessorHD::Render(CRect src, CRect dst, ID3D11Resource* target, CRenderB
// makes target available for processing in shaders
videoCtx1->VideoProcessorSetOutputShaderUsage(m_pVideoProcessor.Get(), 1);

if (m_bSupportHDR10 && (target_color == DXGI_COLOR_SPACE_RGB_STUDIO_G2084_NONE_P2020 ||
target_color == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020))
if (m_bSupportHDR10 && views[2]->color_transfer == AVCOL_TRC_SMPTE2084 &&
views[2]->primaries == AVCOL_PRI_BT2020)
{
if (CRendererBase::IsStreamHDR10(views[2]))
ComPtr<ID3D11VideoContext2> videoCtx2;
if (SUCCEEDED(m_pVideoContext.As(&videoCtx2)))
{
ComPtr<ID3D11VideoContext2> videoCtx2;
if (SUCCEEDED(m_pVideoContext.As(&videoCtx2)))
{
// Passes stream SEI HDR metadata to VideoProcessor (refresh changes during playback)
DXGI_HDR_METADATA_HDR10 hdr10Stream = CRendererBase::GetDXGIHDR10MetaData(views[2]);
videoCtx2->VideoProcessorSetStreamHDRMetaData(
m_pVideoProcessor.Get(), DEFAULT_STREAM_INDEX, DXGI_HDR_METADATA_TYPE_HDR10,
sizeof(hdr10Stream), &hdr10Stream);

// Passes Display HDR parameters (EDID) to VideoProcessor
DXGI_HDR_METADATA_HDR10 hdr10Display = DX::DeviceResources::Get()->GetHdr10Display();
videoCtx2->VideoProcessorSetOutputHDRMetaData(m_pVideoProcessor.Get(),
DXGI_HDR_METADATA_TYPE_HDR10,
sizeof(hdr10Display), &hdr10Display);
}
// Passes stream SEI HDR metadata to VideoProcessor (refresh changes during playback)
DXGI_HDR_METADATA_HDR10 hdr10Stream = CRendererBase::GetDXGIHDR10MetaData(views[2]);
videoCtx2->VideoProcessorSetStreamHDRMetaData(m_pVideoProcessor.Get(), DEFAULT_STREAM_INDEX,
DXGI_HDR_METADATA_TYPE_HDR10,
sizeof(hdr10Stream), &hdr10Stream);

// Passes Display HDR parameters (EDID) to VideoProcessor
DXGI_HDR_METADATA_HDR10 hdr10Display = DX::DeviceResources::Get()->GetHdr10Display();
videoCtx2->VideoProcessorSetOutputHDRMetaData(m_pVideoProcessor.Get(),
DXGI_HDR_METADATA_TYPE_HDR10,
sizeof(hdr10Display), &hdr10Display);
}
}
}
Expand Down
57 changes: 42 additions & 15 deletions xbmc/cores/VideoPlayer/VideoRenderers/windows/RendererBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,8 @@ CRendererBase::~CRendererBase()
{
if (DX::DeviceResources::Get()->IsDisplayHDREnabled())
{
DX::DeviceResources::Get()->ClearHdrMetaData();
CLog::LogF(LOGDEBUG, "Restoring SDR rendering");
DX::DeviceResources::Get()->SetColorSpace1(DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709);
}
}
Flush(false);
Expand Down Expand Up @@ -171,6 +172,8 @@ bool CRendererBase::Configure(const VideoPicture& picture, float fps, unsigned o

m_lastHdr10 = {};
m_isHdrEnabled = false;
m_isHlgEnabled = false;
m_isRec2020Enabled = false;
m_iCntMetaData = 0;

return true;
Expand Down Expand Up @@ -208,7 +211,7 @@ void CRendererBase::Render(CD3DTexture& target, const CRect& sourceRect, const C

if (DX::DeviceResources::Get()->Is10BitSwapchain())
{
if (IsStreamHDR10(buf))
if (buf->color_transfer == AVCOL_TRC_SMPTE2084 && buf->primaries == AVCOL_PRI_BT2020) // HDR10
{
DXGI_HDR_METADATA_HDR10 hdr10 = GetDXGIHDR10MetaData(buf);
if (m_isHdrEnabled)
Expand All @@ -217,7 +220,7 @@ void CRendererBase::Render(CD3DTexture& target, const CRect& sourceRect, const C
if (0 != std::memcmp(&hdr10, &m_lastHdr10, sizeof(hdr10)))
{
// Sets HDR10 metadata only
DX::DeviceResources::Get()->SetHdrMetaData(hdr10, false);
DX::DeviceResources::Get()->SetHdrMetaData(hdr10);
m_lastHdr10 = hdr10;
}
}
Expand All @@ -226,13 +229,38 @@ void CRendererBase::Render(CD3DTexture& target, const CRect& sourceRect, const C
// Sets HDR10 metadata and enables HDR10 color space (switch to HDR rendering)
if (DX::DeviceResources::Get()->IsDisplayHDREnabled())
{
DX::DeviceResources::Get()->SetHdrMetaData(hdr10, true);
DX::DeviceResources::Get()->SetHdrMetaData(hdr10);
CLog::LogF(LOGNOTICE, "Switching to HDR rendering");
DX::DeviceResources::Get()->SetColorSpace1(DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020);
m_isHdrEnabled = true;
m_lastHdr10 = hdr10;
}
}
m_iCntMetaData = 0;
}
else if (buf->color_transfer == AVCOL_TRC_ARIB_STD_B67 && buf->primaries == AVCOL_PRI_BT2020) // HLG
{
if (!m_isHlgEnabled)
{
if (DX::DeviceResources::Get()->IsDisplayHDREnabled())
{
// Switch to HLG rendering (internally converts HLG to HDR10)
CLog::LogF(LOGNOTICE, "Switching to HLG rendering");
DX::DeviceResources::Get()->SetColorSpace1(DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020);
m_isHlgEnabled = true;
}
}
}
else if (buf->primaries == AVCOL_PRI_BT2020)
{
if (m_isRec2020Enabled == false)
{
// Switch to Rec.2020 rendering
CLog::LogF(LOGNOTICE, "Switching to Rec.2020 rendering");
DX::DeviceResources::Get()->SetColorSpace1(DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P2020);
m_isRec2020Enabled = true;
}
}
else
{
if (m_isHdrEnabled)
Expand All @@ -241,11 +269,20 @@ void CRendererBase::Render(CD3DTexture& target, const CRect& sourceRect, const C
if (m_iCntMetaData > 60)
{
// If more than 60 frames are received without HDR10 metadata switch to SDR rendering
DX::DeviceResources::Get()->ClearHdrMetaData();
CLog::LogF(LOGNOTICE, "Switching to SDR rendering");
DX::DeviceResources::Get()->SetColorSpace1(DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709);
m_isHdrEnabled = false;
m_iCntMetaData = 0;
}
}
if (m_isHlgEnabled || m_isRec2020Enabled)
{
// Switch to SDR rendering
CLog::LogF(LOGNOTICE, "Switching to SDR rendering");
DX::DeviceResources::Get()->SetColorSpace1(DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709);
m_isHlgEnabled = false;
m_isRec2020Enabled = false;
}
}
}

Expand Down Expand Up @@ -537,13 +574,3 @@ DXGI_HDR_METADATA_HDR10 CRendererBase::GetDXGIHDR10MetaData(CRenderBuffer* rb)
}
return hdr10;
}

bool CRendererBase::IsStreamHDR10(CRenderBuffer* rb)
{
if ((rb->displayMetadata.has_luminance || rb->hasLightMetadata ||
rb->color_transfer == AVCOL_TRC_SMPTE2084) &&
rb->primaries == AVCOL_PRI_BT2020)
return true;

return false;
}
3 changes: 2 additions & 1 deletion xbmc/cores/VideoPlayer/VideoRenderers/windows/RendererBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,6 @@ class CRendererBase
static DXGI_FORMAT GetDXGIFormat(CVideoBuffer* videoBuffer);
static AVPixelFormat GetAVFormat(DXGI_FORMAT dxgi_format);
static DXGI_HDR_METADATA_HDR10 GetDXGIHDR10MetaData(CRenderBuffer* rb);
static bool IsStreamHDR10(CRenderBuffer* rb);

protected:
explicit CRendererBase(CVideoSettings& videoSettings);
Expand Down Expand Up @@ -173,4 +172,6 @@ class CRendererBase
DXGI_HDR_METADATA_HDR10 m_lastHdr10 = {};
int m_iCntMetaData = 0;
bool m_isHdrEnabled = false;
bool m_isHlgEnabled = false;
bool m_isRec2020Enabled = false;
};
55 changes: 31 additions & 24 deletions xbmc/rendering/dx/DeviceResources.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1198,10 +1198,13 @@ bool DX::DeviceResources::IsDisplayHDREnabled()
return hdrEnabled;
}

void DX::DeviceResources::SetHdrMetaData(DXGI_HDR_METADATA_HDR10& hdr10, bool setColorSpace) const
void DX::DeviceResources::SetHdrMetaData(DXGI_HDR_METADATA_HDR10& hdr10) const
{
ComPtr<IDXGISwapChain4> swapChain4;

if (m_swapChain == nullptr)
return;

if (SUCCEEDED(m_swapChain.As(&swapChain4)))
{
if (SUCCEEDED(swapChain4->SetHDRMetaData(DXGI_HDR_METADATA_TYPE_HDR10, sizeof(hdr10), &hdr10)))
Expand Down Expand Up @@ -1231,37 +1234,41 @@ void DX::DeviceResources::SetHdrMetaData(DXGI_HDR_METADATA_HDR10& hdr10, bool se
{
CLog::LogF(LOGERROR, "DXGI SetHDRMetaData failed");
}

if (setColorSpace)
{
const DXGI_COLOR_SPACE_TYPE cs = DX::Windowing()->UseLimitedColor()
? DXGI_COLOR_SPACE_RGB_STUDIO_G2084_NONE_P2020
: DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020;

if (SUCCEEDED(swapChain4->SetColorSpace1(cs)))
{
CLog::LogF(LOGDEBUG, "DXGI SetColorSpace1 success");
}
else
{
CLog::LogF(LOGERROR, "DXGI SetColorSpace1 failed");
}
}
}
}

void DX::DeviceResources::ClearHdrMetaData() const
void DX::DeviceResources::SetColorSpace1(const DXGI_COLOR_SPACE_TYPE colorSpace) const
{
ComPtr<IDXGISwapChain3> swapChain3;

CLog::LogF(LOGDEBUG, "Restoring SDR rendering");
if (m_swapChain == nullptr)
return;

if (SUCCEEDED(m_swapChain.As(&swapChain3)))
{
const DXGI_COLOR_SPACE_TYPE cs = DX::Windowing()->UseLimitedColor()
? DXGI_COLOR_SPACE_RGB_STUDIO_G22_NONE_P709
: DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709;

swapChain3->SetColorSpace1(cs);
DXGI_COLOR_SPACE_TYPE cs = colorSpace;
if (DX::Windowing()->UseLimitedColor())
{
switch (cs)
{
case DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709:
cs = DXGI_COLOR_SPACE_RGB_STUDIO_G22_NONE_P709;
break;
case DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020:
cs = DXGI_COLOR_SPACE_RGB_STUDIO_G2084_NONE_P2020;
break;
case DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P2020:
cs = DXGI_COLOR_SPACE_RGB_STUDIO_G22_NONE_P2020;
break;
}
}
if (SUCCEEDED(swapChain3->SetColorSpace1(cs)))
{
CLog::LogF(LOGDEBUG, "DXGI SetColorSpace1 success");
}
else
{
CLog::LogF(LOGERROR, "DXGI SetColorSpace1 failed");
}
}
}
6 changes: 3 additions & 3 deletions xbmc/rendering/dx/DeviceResources.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
#include <wrl.h>
#include <wrl/client.h>
#include <concrt.h>
#if !defined(TARGET_WINDOWS_STORE)
#if defined(TARGET_WINDOWS_DESKTOP)
#include <easyhook/easyhook.h>
#endif
#include <dxgi1_6.h>
Expand Down Expand Up @@ -80,8 +80,8 @@ namespace DX
bool SetFullScreen(bool fullscreen, RESOLUTION_INFO& res);

bool IsDisplayHDREnabled();
void SetHdrMetaData(DXGI_HDR_METADATA_HDR10& hdr10, bool setColorSpace) const;
void ClearHdrMetaData() const;
void SetHdrMetaData(DXGI_HDR_METADATA_HDR10& hdr10) const;
void SetColorSpace1(const DXGI_COLOR_SPACE_TYPE colorSpace) const;
bool Is10BitSwapchain() const { return m_Is10bSwapchain; }
DXGI_HDR_METADATA_HDR10 GetHdr10Display() const { return m_displayHDR10; }

Expand Down

0 comments on commit a13a7d1

Please sign in to comment.