mirror of
https://github.com/moonlight-stream/moonlight-common-c.git
synced 2025-07-02 15:56:02 +00:00
Add Sunshine protocol extension for passing HDR metadata
This commit is contained in:
parent
c9a5cea93e
commit
79b5ef0e1e
@ -50,6 +50,7 @@ static bool stopping;
|
|||||||
static bool disconnectPending;
|
static bool disconnectPending;
|
||||||
static bool encryptedControlStream;
|
static bool encryptedControlStream;
|
||||||
static bool hdrEnabled;
|
static bool hdrEnabled;
|
||||||
|
static SS_HDR_METADATA hdrMetadata;
|
||||||
|
|
||||||
static int intervalGoodFrameCount;
|
static int intervalGoodFrameCount;
|
||||||
static int intervalTotalFrameCount;
|
static int intervalTotalFrameCount;
|
||||||
@ -275,6 +276,7 @@ int initializeControlStream(void) {
|
|||||||
encryptionCtx = PltCreateCryptoContext();
|
encryptionCtx = PltCreateCryptoContext();
|
||||||
decryptionCtx = PltCreateCryptoContext();
|
decryptionCtx = PltCreateCryptoContext();
|
||||||
hdrEnabled = false;
|
hdrEnabled = false;
|
||||||
|
memset(&hdrMetadata, 0, sizeof(hdrMetadata));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -813,9 +815,24 @@ static void controlReceiveThreadFunc(void* context) {
|
|||||||
|
|
||||||
BbInitializeWrappedBuffer(&bb, (char*)ctlHdr, sizeof(*ctlHdr), packetLength - sizeof(*ctlHdr), BYTE_ORDER_LITTLE);
|
BbInitializeWrappedBuffer(&bb, (char*)ctlHdr, sizeof(*ctlHdr), packetLength - sizeof(*ctlHdr), BYTE_ORDER_LITTLE);
|
||||||
|
|
||||||
// FIXME: There are 7 additional bytes that appear to always be all zeros. What do they mean?
|
|
||||||
// Is there some way that GFE tells us the HDR mastering metadata (NV_HDR_COLOR_DATA) set by the game?
|
|
||||||
BbGet8(&bb, &enableByte);
|
BbGet8(&bb, &enableByte);
|
||||||
|
if (IS_SUNSHINE()) {
|
||||||
|
// Zero the metadata buffer to properly handle older servers if we have to add new fields
|
||||||
|
memset(&hdrMetadata, 0, sizeof(hdrMetadata));
|
||||||
|
|
||||||
|
// Sunshine sends HDR metadata in this message too
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
BbGet16(&bb, &hdrMetadata.displayPrimaries[i].x);
|
||||||
|
BbGet16(&bb, &hdrMetadata.displayPrimaries[i].y);
|
||||||
|
}
|
||||||
|
BbGet16(&bb, &hdrMetadata.whitePoint.x);
|
||||||
|
BbGet16(&bb, &hdrMetadata.whitePoint.y);
|
||||||
|
BbGet16(&bb, &hdrMetadata.maxDisplayLuminance);
|
||||||
|
BbGet16(&bb, &hdrMetadata.minDisplayLuminance);
|
||||||
|
BbGet16(&bb, &hdrMetadata.maxContentLightLevel);
|
||||||
|
BbGet16(&bb, &hdrMetadata.maxFrameAverageLightLevel);
|
||||||
|
BbGet16(&bb, &hdrMetadata.maxFullFrameLuminance);
|
||||||
|
}
|
||||||
|
|
||||||
hdrEnabled = (enableByte != 0);
|
hdrEnabled = (enableByte != 0);
|
||||||
ListenerCallbacks.setHdrMode(hdrEnabled);
|
ListenerCallbacks.setHdrMode(hdrEnabled);
|
||||||
@ -1447,3 +1464,12 @@ int startControlStream(void) {
|
|||||||
bool LiGetCurrentHostDisplayHdrMode(void) {
|
bool LiGetCurrentHostDisplayHdrMode(void) {
|
||||||
return hdrEnabled;
|
return hdrEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool LiGetHdrMetadata(PSS_HDR_METADATA metadata) {
|
||||||
|
if (!IS_SUNSHINE() || !hdrEnabled) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
*metadata = hdrMetadata;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
@ -705,6 +705,34 @@ void LiCompleteVideoFrame(VIDEO_FRAME_HANDLE handle, int drStatus);
|
|||||||
// See ConnListenerSetHdrMode() for more details.
|
// See ConnListenerSetHdrMode() for more details.
|
||||||
bool LiGetCurrentHostDisplayHdrMode(void);
|
bool LiGetCurrentHostDisplayHdrMode(void);
|
||||||
|
|
||||||
|
typedef struct _SS_HDR_METADATA {
|
||||||
|
// RGB order
|
||||||
|
struct {
|
||||||
|
uint16_t x; // Normalized to 50,000
|
||||||
|
uint16_t y; // Normalized to 50,000
|
||||||
|
} displayPrimaries[3];
|
||||||
|
|
||||||
|
struct {
|
||||||
|
uint16_t x; // Normalized to 50,000
|
||||||
|
uint16_t y; // Normalized to 50,000
|
||||||
|
} whitePoint;
|
||||||
|
|
||||||
|
uint16_t maxDisplayLuminance; // Nits
|
||||||
|
uint16_t minDisplayLuminance; // 1/10000th of a nit
|
||||||
|
|
||||||
|
// These are content-specific values which may not be available for all hosts.
|
||||||
|
uint16_t maxContentLightLevel; // Nits
|
||||||
|
uint16_t maxFrameAverageLightLevel; // Nits
|
||||||
|
|
||||||
|
// These are display-specific values which may not be available for all hosts.
|
||||||
|
uint16_t maxFullFrameLuminance; // Nits
|
||||||
|
} SS_HDR_METADATA, *PSS_HDR_METADATA;
|
||||||
|
|
||||||
|
// This function populates the provided mastering metadata struct with the HDR metadata
|
||||||
|
// from the host PC's monitor and content (if available). It is only valid to call this
|
||||||
|
// function when HDR mode is active on the host. This is a Sunshine protocol extension.
|
||||||
|
bool LiGetHdrMetadata(PSS_HDR_METADATA metadata);
|
||||||
|
|
||||||
// This function requests an IDR frame from the host. Typically this is done using DR_NEED_IDR, but clients
|
// This function requests an IDR frame from the host. Typically this is done using DR_NEED_IDR, but clients
|
||||||
// processing frames asynchronously may need to reset their decoder state even after returning DR_OK for
|
// processing frames asynchronously may need to reset their decoder state even after returning DR_OK for
|
||||||
// the prior frame. Rather than wait for a new frame and return DR_NEED_IDR for that one, they can just
|
// the prior frame. Rather than wait for a new frame and return DR_NEED_IDR for that one, they can just
|
||||||
|
Loading…
x
Reference in New Issue
Block a user