mirror of
https://github.com/moonlight-stream/moonlight-qt.git
synced 2026-06-18 14:40:56 +00:00
Attach EDR metadata to Metal layer
This improves the accuracy of HDR streaming and enables HDR->SDR tonemapping.
This commit is contained in:
@@ -9,6 +9,24 @@
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
#import <Metal/Metal.h>
|
||||
|
||||
VTBaseRenderer::VTBaseRenderer(IFFmpegRenderer::RendererType type) :
|
||||
IFFmpegRenderer(type),
|
||||
m_HdrMetadataChanged(false),
|
||||
m_MasteringDisplayColorVolume(nullptr),
|
||||
m_ContentLightLevelInfo(nullptr) {
|
||||
|
||||
}
|
||||
|
||||
VTBaseRenderer::~VTBaseRenderer() {
|
||||
if (m_MasteringDisplayColorVolume != nullptr) {
|
||||
CFRelease(m_MasteringDisplayColorVolume);
|
||||
}
|
||||
|
||||
if (m_ContentLightLevelInfo != nullptr) {
|
||||
CFRelease(m_ContentLightLevelInfo);
|
||||
}
|
||||
}
|
||||
|
||||
bool VTBaseRenderer::checkDecoderCapabilities(id<MTLDevice> device, PDECODER_PARAMETERS params) {
|
||||
if (params->videoFormat & VIDEO_FORMAT_MASK_H264) {
|
||||
if (!VTIsHardwareDecodeSupported(kCMVideoCodecType_H264)) {
|
||||
@@ -76,3 +94,61 @@ bool VTBaseRenderer::checkDecoderCapabilities(id<MTLDevice> device, PDECODER_PAR
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void VTBaseRenderer::setHdrMode(bool enabled) {
|
||||
// Free existing HDR metadata
|
||||
if (m_MasteringDisplayColorVolume != nullptr) {
|
||||
CFRelease(m_MasteringDisplayColorVolume);
|
||||
m_MasteringDisplayColorVolume = nullptr;
|
||||
}
|
||||
if (m_ContentLightLevelInfo != nullptr) {
|
||||
CFRelease(m_ContentLightLevelInfo);
|
||||
m_ContentLightLevelInfo = nullptr;
|
||||
}
|
||||
|
||||
// Store new HDR metadata if available
|
||||
SS_HDR_METADATA hdrMetadata;
|
||||
if (enabled && LiGetHdrMetadata(&hdrMetadata)) {
|
||||
if (hdrMetadata.displayPrimaries[0].x != 0 && hdrMetadata.maxDisplayLuminance != 0) {
|
||||
// This data is all in big-endian
|
||||
struct {
|
||||
vector_ushort2 primaries[3];
|
||||
vector_ushort2 white_point;
|
||||
uint32_t luminance_max;
|
||||
uint32_t luminance_min;
|
||||
} __attribute__((packed, aligned(4))) mdcv;
|
||||
|
||||
// mdcv is in GBR order while SS_HDR_METADATA is in RGB order
|
||||
mdcv.primaries[0].x = __builtin_bswap16(hdrMetadata.displayPrimaries[1].x);
|
||||
mdcv.primaries[0].y = __builtin_bswap16(hdrMetadata.displayPrimaries[1].y);
|
||||
mdcv.primaries[1].x = __builtin_bswap16(hdrMetadata.displayPrimaries[2].x);
|
||||
mdcv.primaries[1].y = __builtin_bswap16(hdrMetadata.displayPrimaries[2].y);
|
||||
mdcv.primaries[2].x = __builtin_bswap16(hdrMetadata.displayPrimaries[0].x);
|
||||
mdcv.primaries[2].y = __builtin_bswap16(hdrMetadata.displayPrimaries[0].y);
|
||||
|
||||
mdcv.white_point.x = __builtin_bswap16(hdrMetadata.whitePoint.x);
|
||||
mdcv.white_point.y = __builtin_bswap16(hdrMetadata.whitePoint.y);
|
||||
|
||||
// These luminance values are in 10000ths of a nit
|
||||
mdcv.luminance_max = __builtin_bswap32((uint32_t)hdrMetadata.maxDisplayLuminance * 10000);
|
||||
mdcv.luminance_min = __builtin_bswap32(hdrMetadata.minDisplayLuminance);
|
||||
|
||||
m_MasteringDisplayColorVolume = CFDataCreate(nullptr, (const UInt8*)&mdcv, sizeof(mdcv));
|
||||
}
|
||||
|
||||
if (hdrMetadata.maxContentLightLevel != 0 && hdrMetadata.maxFrameAverageLightLevel != 0) {
|
||||
// This data is all in big-endian
|
||||
struct {
|
||||
uint16_t max_content_light_level;
|
||||
uint16_t max_frame_average_light_level;
|
||||
} __attribute__((packed, aligned(2))) cll;
|
||||
|
||||
cll.max_content_light_level = __builtin_bswap16(hdrMetadata.maxContentLightLevel);
|
||||
cll.max_frame_average_light_level = __builtin_bswap16(hdrMetadata.maxFrameAverageLightLevel);
|
||||
|
||||
m_ContentLightLevelInfo = CFDataCreate(nullptr, (const UInt8*)&cll, sizeof(cll));
|
||||
}
|
||||
}
|
||||
|
||||
m_HdrMetadataChanged = true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user