From 26fe1cb22c298d66d864f9e62bf0889ef6a80487 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sat, 25 Nov 2017 12:12:38 -0800 Subject: [PATCH] Separate H.265 video format for SDR and HDR formats --- src/ControlStream.c | 8 ++++---- src/Limelight.h | 16 ++++++++++++---- src/RtspConnection.c | 15 ++++++++++----- src/SdpGenerator.c | 2 +- src/VideoDepacketizer.c | 4 ++-- 5 files changed, 29 insertions(+), 16 deletions(-) diff --git a/src/ControlStream.c b/src/ControlStream.c index f04fda7..c0b70d5 100644 --- a/src/ControlStream.c +++ b/src/ControlStream.c @@ -207,8 +207,8 @@ int getNextFrameInvalidationTuple(PQUEUED_FRAME_INVALIDATION_TUPLE* qfit) { void queueFrameInvalidationTuple(int startFrame, int endFrame) { LC_ASSERT(startFrame <= endFrame); - if ((NegotiatedVideoFormat == VIDEO_FORMAT_H264 && (VideoCallbacks.capabilities & CAPABILITY_REFERENCE_FRAME_INVALIDATION_AVC)) || - ((NegotiatedVideoFormat == VIDEO_FORMAT_H265 && (VideoCallbacks.capabilities & CAPABILITY_REFERENCE_FRAME_INVALIDATION_HEVC)))) { + if (((NegotiatedVideoFormat & VIDEO_FORMAT_MASK_H264) && (VideoCallbacks.capabilities & CAPABILITY_REFERENCE_FRAME_INVALIDATION_AVC)) || + (((NegotiatedVideoFormat & VIDEO_FORMAT_MASK_H265) && (VideoCallbacks.capabilities & CAPABILITY_REFERENCE_FRAME_INVALIDATION_HEVC)))) { PQUEUED_FRAME_INVALIDATION_TUPLE qfit; qfit = malloc(sizeof(*qfit)); if (qfit != NULL) { @@ -500,8 +500,8 @@ static void requestInvalidateReferenceFrames(void) { long long payload[3]; PQUEUED_FRAME_INVALIDATION_TUPLE qfit; - LC_ASSERT((NegotiatedVideoFormat == VIDEO_FORMAT_H264 && (VideoCallbacks.capabilities & CAPABILITY_REFERENCE_FRAME_INVALIDATION_AVC)) || - (NegotiatedVideoFormat == VIDEO_FORMAT_H265 && (VideoCallbacks.capabilities & CAPABILITY_REFERENCE_FRAME_INVALIDATION_HEVC))); + LC_ASSERT(((NegotiatedVideoFormat & VIDEO_FORMAT_MASK_H264) && (VideoCallbacks.capabilities & CAPABILITY_REFERENCE_FRAME_INVALIDATION_AVC)) || + ((NegotiatedVideoFormat & VIDEO_FORMAT_MASK_H265) && (VideoCallbacks.capabilities & CAPABILITY_REFERENCE_FRAME_INVALIDATION_HEVC))); if (!getNextFrameInvalidationTuple(&qfit)) { return; diff --git a/src/Limelight.h b/src/Limelight.h index 8bbe596..31b3ff4 100644 --- a/src/Limelight.h +++ b/src/Limelight.h @@ -119,12 +119,20 @@ typedef struct _DECODE_UNIT { #define AUDIO_CONFIGURATION_51_SURROUND 1 // Passed to DecoderRendererSetup to indicate that the following video stream will be -// in H.264 format -#define VIDEO_FORMAT_H264 1 +// in H.264 High Profile. +#define VIDEO_FORMAT_H264 0x0001 // Passed to DecoderRendererSetup to indicate that the following video stream will be -// in H.265 format -#define VIDEO_FORMAT_H265 2 +// in H.265 Main profile. This will only be passed if supportsHevc is true. +#define VIDEO_FORMAT_H265 0x0100 + +// Passed to DecoderRendererSetup to indicate that the following video stream will be +// in H.265 Main10 (HDR10) profile. This will only be passed if enableHdr is true. +#define VIDEO_FORMAT_H265_MAIN10 0x0200 + +// Masks for clients to use to match video codecs without profile-specific details. +#define VIDEO_FORMAT_MASK_H264 0x00FF +#define VIDEO_FORMAT_MASK_H265 0xFF00 // If set in the renderer capabilities field, this flag will cause audio/video data to // be submitted directly from the receive thread. This should only be specified if the diff --git a/src/RtspConnection.c b/src/RtspConnection.c index 2ff839f..f54d67f 100644 --- a/src/RtspConnection.c +++ b/src/RtspConnection.c @@ -536,12 +536,17 @@ int performRtspHandshake(void) { // format to H264, so we can't just look for the HEVC MIME type. What we'll do instead is // look for the base 64 encoded VPS NALU prefix that is unique to the HEVC bitstream. if (StreamConfig.supportsHevc && strstr(response.payload, "sprop-parameter-sets=AAAAAU")) { - NegotiatedVideoFormat = VIDEO_FORMAT_H265; + if (StreamConfig.enableHdr) { + NegotiatedVideoFormat = VIDEO_FORMAT_H265_MAIN10; + } + else { + NegotiatedVideoFormat = VIDEO_FORMAT_H265; - // Apply bitrate adjustment for SDR HEVC if the client requested one - if (StreamConfig.hevcBitratePercentageMultiplier != 0 && !StreamConfig.enableHdr) { - StreamConfig.bitrate *= StreamConfig.hevcBitratePercentageMultiplier; - StreamConfig.bitrate /= 100; + // Apply bitrate adjustment for SDR HEVC if the client requested one + if (StreamConfig.hevcBitratePercentageMultiplier != 0) { + StreamConfig.bitrate *= StreamConfig.hevcBitratePercentageMultiplier; + StreamConfig.bitrate /= 100; + } } } else { diff --git a/src/SdpGenerator.c b/src/SdpGenerator.c index 8319b69..137ce9b 100644 --- a/src/SdpGenerator.c +++ b/src/SdpGenerator.c @@ -277,7 +277,7 @@ static PSDP_OPTION getAttributesList(char*urlSafeAddr) { } if (AppVersionQuad[0] >= 4) { - if (NegotiatedVideoFormat == VIDEO_FORMAT_H265) { + if (NegotiatedVideoFormat & VIDEO_FORMAT_MASK_H265) { err |= addAttributeString(&optionHead, "x-nv-clientSupportHevc", "1"); err |= addAttributeString(&optionHead, "x-nv-vqos[0].bitStreamFormat", "1"); diff --git a/src/VideoDepacketizer.c b/src/VideoDepacketizer.c index ba045fd..601b335 100644 --- a/src/VideoDepacketizer.c +++ b/src/VideoDepacketizer.c @@ -44,8 +44,8 @@ void initializeVideoDepacketizer(int pktSize) { LC_ASSERT(NegotiatedVideoFormat != 0); strictIdrFrameWait = - !((NegotiatedVideoFormat == VIDEO_FORMAT_H264 && (VideoCallbacks.capabilities & CAPABILITY_REFERENCE_FRAME_INVALIDATION_AVC)) || - ((NegotiatedVideoFormat == VIDEO_FORMAT_H265 && (VideoCallbacks.capabilities & CAPABILITY_REFERENCE_FRAME_INVALIDATION_HEVC)))); + !(((NegotiatedVideoFormat & VIDEO_FORMAT_MASK_H264) && (VideoCallbacks.capabilities & CAPABILITY_REFERENCE_FRAME_INVALIDATION_AVC)) || + (((NegotiatedVideoFormat & VIDEO_FORMAT_MASK_H265) && (VideoCallbacks.capabilities & CAPABILITY_REFERENCE_FRAME_INVALIDATION_HEVC)))); } // Free the NAL chain