diff --git a/Limelight/Stream/Connection.m b/Limelight/Stream/Connection.m index c49822f..a53f30f 100644 --- a/Limelight/Stream/Connection.m +++ b/Limelight/Stream/Connection.m @@ -309,6 +309,7 @@ void ClConnectionStatusUpdate(int status) void ClSetHdrMode(bool enabled) { + [renderer setHdrMode:enabled]; [_callbacks setHdrMode:enabled]; } diff --git a/Limelight/Stream/VideoDecoderRenderer.h b/Limelight/Stream/VideoDecoderRenderer.h index 768db53..bbcc3c1 100644 --- a/Limelight/Stream/VideoDecoderRenderer.h +++ b/Limelight/Stream/VideoDecoderRenderer.h @@ -17,6 +17,7 @@ - (void)setupWithVideoFormat:(int)videoFormat frameRate:(int)frameRate; - (void)start; - (void)stop; +- (void)setHdrMode:(BOOL)enabled; - (int)submitDecodeBuffer:(unsigned char *)data length:(int)length bufferType:(int)bufferType frameType:(int)frameType pts:(unsigned int)pts; diff --git a/Limelight/Stream/VideoDecoderRenderer.m b/Limelight/Stream/VideoDecoderRenderer.m index a74c509..3d14f05 100644 --- a/Limelight/Stream/VideoDecoderRenderer.m +++ b/Limelight/Stream/VideoDecoderRenderer.m @@ -22,6 +22,8 @@ int frameRate; NSData *spsData, *ppsData, *vpsData; + NSData *masteringDisplayColorVolume; + NSData *contentLightLevelInfo; CMVideoFormatDescriptionRef formatDesc; CADisplayLink* _displayLink; @@ -242,6 +244,16 @@ int DrSubmitDecodeUnit(PDECODE_UNIT decodeUnit); const size_t parameterSetSizes[] = { [vpsData length], [spsData length], [ppsData length] }; Log(LOG_I, @"Constructing new HEVC format description"); + + NSMutableDictionary* videoFormatParams = [[NSMutableDictionary alloc] init]; + + if (contentLightLevelInfo) { + [videoFormatParams setObject:contentLightLevelInfo forKey:(__bridge NSString*)kCMFormatDescriptionExtension_ContentLightLevelInfo]; + } + + if (masteringDisplayColorVolume) { + [videoFormatParams setObject:masteringDisplayColorVolume forKey:(__bridge NSString*)kCMFormatDescriptionExtension_MasteringDisplayColorVolume]; + } if (@available(iOS 11.0, *)) { status = CMVideoFormatDescriptionCreateFromHEVCParameterSets(kCFAllocatorDefault, @@ -249,7 +261,7 @@ int DrSubmitDecodeUnit(PDECODE_UNIT decodeUnit); parameterSetPointers, parameterSetSizes, NAL_LENGTH_PREFIX_SIZE, - nil, + (__bridge CFDictionaryRef)videoFormatParams, &formatDesc); } else { // This means Moonlight-common-c decided to give us an HEVC stream @@ -363,4 +375,57 @@ int DrSubmitDecodeUnit(PDECODE_UNIT decodeUnit); return DR_OK; } +- (void)setHdrMode:(BOOL)enabled { + // Free old metadata + masteringDisplayColorVolume = nil; + contentLightLevelInfo = nil; + + // Update metadata from host if provided + 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); + + masteringDisplayColorVolume = [NSData dataWithBytes:&mdcv length: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); + + contentLightLevelInfo = [NSData dataWithBytes:&cll length:sizeof(cll)]; + } + } + + // Request an IDR frame to trigger us to re-create the format with the adjusted metadata + LiRequestIdrFrame(); +} + @end diff --git a/moonlight-common/moonlight-common-c b/moonlight-common/moonlight-common-c index 5c7a5ce..07beb0f 160000 --- a/moonlight-common/moonlight-common-c +++ b/moonlight-common/moonlight-common-c @@ -1 +1 @@ -Subproject commit 5c7a5ce129dab792530da91c42f17867a685524e +Subproject commit 07beb0f0a520106c49fda7664369b29e6938ea6e