diff --git a/Limelight/Stream/VideoDecoderRenderer.m b/Limelight/Stream/VideoDecoderRenderer.m index 3d14f05..b38dd81 100644 --- a/Limelight/Stream/VideoDecoderRenderer.m +++ b/Limelight/Stream/VideoDecoderRenderer.m @@ -376,56 +376,71 @@ int DrSubmitDecodeUnit(PDECODE_UNIT decodeUnit); } - (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; + + BOOL hasMetadata = enabled && LiGetHdrMetadata(&hdrMetadata); + BOOL metadataChanged = NO; + + if (hasMetadata && 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 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); + 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); + // 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)]; + NSData* newMdcv = [NSData dataWithBytes:&mdcv length:sizeof(mdcv)]; + if (masteringDisplayColorVolume == nil || ![newMdcv isEqualToData:masteringDisplayColorVolume]) { + masteringDisplayColorVolume = newMdcv; + metadataChanged = YES; } } + else if (masteringDisplayColorVolume != nil) { + masteringDisplayColorVolume = nil; + metadataChanged = YES; + } - // Request an IDR frame to trigger us to re-create the format with the adjusted metadata - LiRequestIdrFrame(); + if (hasMetadata && 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); + + NSData* newCll = [NSData dataWithBytes:&cll length:sizeof(cll)]; + if (contentLightLevelInfo == nil || ![newCll isEqualToData:contentLightLevelInfo]) { + contentLightLevelInfo = newCll; + metadataChanged = YES; + } + } + else if (contentLightLevelInfo != nil) { + contentLightLevelInfo = nil; + metadataChanged = YES; + } + + // If the metadata changed, request an IDR frame to re-create the CMVideoFormatDescription + if (metadataChanged) { + LiRequestIdrFrame(); + } } @end