From 1cbdd0e67550ec3a5f2d9c076ba2edd4fbff6bdf Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sat, 29 Jan 2022 00:59:04 -0600 Subject: [PATCH] Display the HDR option if the platform has a decoder that supports it --- app/backend/systemproperties.cpp | 12 +--- app/streaming/session.cpp | 64 ++++++++++++------- app/streaming/session.h | 3 +- app/streaming/video/decoder.h | 1 + app/streaming/video/ffmpeg-renderers/drm.cpp | 9 ++- .../video/ffmpeg-renderers/renderer.h | 1 + app/streaming/video/ffmpeg-renderers/vt.mm | 6 ++ app/streaming/video/ffmpeg.cpp | 5 ++ app/streaming/video/ffmpeg.h | 1 + app/streaming/video/slvid.h | 21 +++--- 10 files changed, 77 insertions(+), 46 deletions(-) diff --git a/app/backend/systemproperties.cpp b/app/backend/systemproperties.cpp index 815588f0..6af5da5d 100644 --- a/app/backend/systemproperties.cpp +++ b/app/backend/systemproperties.cpp @@ -64,16 +64,6 @@ SystemProperties::SystemProperties() hasDiscordIntegration = false; #endif - // TODO: Do something smarter than this. We should be able to query - // this from the decoder (or just try VIDEO_FORMAT_H265_MAIN10 and - // fail if we don't get a hardware accelerated decoder). -#ifdef Q_OS_DARWIN - // HDR is supported by the VideoToolbox renderer - supportsHdr = true; -#else - supportsHdr = false; -#endif - unmappedGamepads = SdlInputHandler::getUnmappedGamepads(); // Populate data that requires talking to SDL. We do it all in one shot @@ -158,7 +148,7 @@ void SystemProperties::querySdlVideoInfoInternal() } } - Session::getDecoderInfo(testWindow, hasHardwareAcceleration, rendererAlwaysFullScreen, maximumResolution); + Session::getDecoderInfo(testWindow, hasHardwareAcceleration, rendererAlwaysFullScreen, supportsHdr, maximumResolution); SDL_DestroyWindow(testWindow); diff --git a/app/streaming/session.cpp b/app/streaming/session.cpp index 23a77b2a..b2eac478 100644 --- a/app/streaming/session.cpp +++ b/app/streaming/session.cpp @@ -308,39 +308,55 @@ int Session::drSubmitDecodeUnit(PDECODE_UNIT du) } void Session::getDecoderInfo(SDL_Window* window, - bool& isHardwareAccelerated, bool& isFullScreenOnly, QSize& maxResolution) + bool& isHardwareAccelerated, bool& isFullScreenOnly, + bool& isHdrSupported, QSize& maxResolution) { IVideoDecoder* decoder; - if (!chooseDecoder(StreamingPreferences::VDS_AUTO, - window, VIDEO_FORMAT_H264, 1920, 1080, 60, - false, false, true, decoder)) { - isHardwareAccelerated = isFullScreenOnly = false; + // Try an HEVC Main10 decoder first to see if we have HDR support + if (chooseDecoder(StreamingPreferences::VDS_FORCE_HARDWARE, + window, VIDEO_FORMAT_H265_MAIN10, 1920, 1080, 60, + false, false, true, decoder)) { + isHardwareAccelerated = decoder->isHardwareAccelerated(); + isFullScreenOnly = decoder->isAlwaysFullScreen(); + isHdrSupported = decoder->isHdrSupported(); + maxResolution = decoder->getDecoderMaxResolution(); + delete decoder; + return; } - isHardwareAccelerated = decoder->isHardwareAccelerated(); - isFullScreenOnly = decoder->isAlwaysFullScreen(); - maxResolution = decoder->getDecoderMaxResolution(); + // HDR can only be supported by a hardware codec that can handle HEVC Main10. + // If we made it this far, we don't have one, so HDR will not be available. + isHdrSupported = false; - delete decoder; + // Try a regular hardware accelerated HEVC decoder now + if (chooseDecoder(StreamingPreferences::VDS_FORCE_HARDWARE, + window, VIDEO_FORMAT_H265, 1920, 1080, 60, + false, false, true, decoder)) { + isHardwareAccelerated = decoder->isHardwareAccelerated(); + isFullScreenOnly = decoder->isAlwaysFullScreen(); + maxResolution = decoder->getDecoderMaxResolution(); + delete decoder; - // If we don't get back a hardware H.264 decoder, see if we have a hardware - // HEVC decoder. This can be the case on the Raspberry Pi with Full KMS - // when not running in X11. Everything since Maxwell in 2014 can encode HEVC, - // so we probably don't need to be concerned about a lack of fast H.264 - // decoding enough to bug the user about it every launch. - if (!isHardwareAccelerated) { - if (chooseDecoder(StreamingPreferences::VDS_FORCE_HARDWARE, - window, VIDEO_FORMAT_H265, 1920, 1080, 60, - false, false, true, decoder)) { - isHardwareAccelerated = decoder->isHardwareAccelerated(); - isFullScreenOnly = decoder->isAlwaysFullScreen(); - maxResolution = decoder->getDecoderMaxResolution(); - - delete decoder; - } + return; } + + // If we still didn't find a hardware decoder, try H.264 now. + // This will fall back to software decoding, so it should always work. + if (chooseDecoder(StreamingPreferences::VDS_AUTO, + window, VIDEO_FORMAT_H264, 1920, 1080, 60, + false, false, true, decoder)) { + isHardwareAccelerated = decoder->isHardwareAccelerated(); + isFullScreenOnly = decoder->isAlwaysFullScreen(); + maxResolution = decoder->getDecoderMaxResolution(); + delete decoder; + + return; + } + + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, + "Failed to find ANY working H.264 or HEVC decoder!"); } bool Session::isHardwareDecodeAvailable(SDL_Window* window, diff --git a/app/streaming/session.h b/app/streaming/session.h index 71d89025..ad0ed1e6 100644 --- a/app/streaming/session.h +++ b/app/streaming/session.h @@ -28,7 +28,8 @@ public: static void getDecoderInfo(SDL_Window* window, - bool& isHardwareAccelerated, bool& isFullScreenOnly, QSize& maxResolution); + bool& isHardwareAccelerated, bool& isFullScreenOnly, + bool& isHdrSupported, QSize& maxResolution); static Session* get() { diff --git a/app/streaming/video/decoder.h b/app/streaming/video/decoder.h index 8cf3d022..650a021f 100644 --- a/app/streaming/video/decoder.h +++ b/app/streaming/video/decoder.h @@ -64,6 +64,7 @@ public: virtual bool initialize(PDECODER_PARAMETERS params) = 0; virtual bool isHardwareAccelerated() = 0; virtual bool isAlwaysFullScreen() = 0; + virtual bool isHdrSupported() = 0; virtual int getDecoderCapabilities() = 0; virtual int getDecoderColorspace() = 0; virtual QSize getDecoderMaxResolution() = 0; diff --git a/app/streaming/video/ffmpeg-renderers/drm.cpp b/app/streaming/video/ffmpeg-renderers/drm.cpp index 8c8feb34..85777764 100644 --- a/app/streaming/video/ffmpeg-renderers/drm.cpp +++ b/app/streaming/video/ffmpeg-renderers/drm.cpp @@ -410,8 +410,15 @@ enum AVPixelFormat DrmRenderer::getPreferredPixelFormat(int) int DrmRenderer::getRendererAttributes() { + int attributes = 0; + // This renderer can only draw in full-screen - return RENDERER_ATTRIBUTE_FULLSCREEN_ONLY; + attributes |= RENDERER_ATTRIBUTE_FULLSCREEN_ONLY; + + // This renderer supports HDR + attributes |= RENDERER_ATTRIBUTE_HDR_SUPPORT; + + return attributes; } void DrmRenderer::setHdrMode(bool enabled) diff --git a/app/streaming/video/ffmpeg-renderers/renderer.h b/app/streaming/video/ffmpeg-renderers/renderer.h index 23f75c7b..ae746b11 100644 --- a/app/streaming/video/ffmpeg-renderers/renderer.h +++ b/app/streaming/video/ffmpeg-renderers/renderer.h @@ -90,6 +90,7 @@ private: #define RENDERER_ATTRIBUTE_FULLSCREEN_ONLY 0x01 #define RENDERER_ATTRIBUTE_1080P_MAX 0x02 +#define RENDERER_ATTRIBUTE_HDR_SUPPORT 0x04 class IFFmpegRenderer : public Overlay::IOverlayRenderer { public: diff --git a/app/streaming/video/ffmpeg-renderers/vt.mm b/app/streaming/video/ffmpeg-renderers/vt.mm index 5223e52f..ca168c54 100644 --- a/app/streaming/video/ffmpeg-renderers/vt.mm +++ b/app/streaming/video/ffmpeg-renderers/vt.mm @@ -505,6 +505,12 @@ public: return COLORSPACE_REC_601; } + int getRendererAttributes() override + { + // AVSampleBufferDisplayLayer supports HDR output + return RENDERER_ATTRIBUTE_HDR_SUPPORT; + } + private: AVBufferRef* m_HwContext; AVSampleBufferDisplayLayer* m_DisplayLayer; diff --git a/app/streaming/video/ffmpeg.cpp b/app/streaming/video/ffmpeg.cpp index 43f319c5..aa91f9cd 100644 --- a/app/streaming/video/ffmpeg.cpp +++ b/app/streaming/video/ffmpeg.cpp @@ -57,6 +57,11 @@ bool FFmpegVideoDecoder::isAlwaysFullScreen() return m_FrontendRenderer->getRendererAttributes() & RENDERER_ATTRIBUTE_FULLSCREEN_ONLY; } +bool FFmpegVideoDecoder::isHdrSupported() +{ + return m_FrontendRenderer->getRendererAttributes() & RENDERER_ATTRIBUTE_HDR_SUPPORT; +} + void FFmpegVideoDecoder::setHdrMode(bool enabled) { m_FrontendRenderer->setHdrMode(enabled); diff --git a/app/streaming/video/ffmpeg.h b/app/streaming/video/ffmpeg.h index 06c66a02..ec89b27c 100644 --- a/app/streaming/video/ffmpeg.h +++ b/app/streaming/video/ffmpeg.h @@ -18,6 +18,7 @@ public: virtual bool initialize(PDECODER_PARAMETERS params) override; virtual bool isHardwareAccelerated() override; virtual bool isAlwaysFullScreen() override; + virtual bool isHdrSupported() override; virtual int getDecoderCapabilities() override; virtual int getDecoderColorspace() override; virtual QSize getDecoderMaxResolution() override; diff --git a/app/streaming/video/slvid.h b/app/streaming/video/slvid.h index b8a420c3..9651e941 100644 --- a/app/streaming/video/slvid.h +++ b/app/streaming/video/slvid.h @@ -9,19 +9,22 @@ class SLVideoDecoder : public IVideoDecoder public: SLVideoDecoder(bool testOnly); virtual ~SLVideoDecoder(); - virtual bool initialize(PDECODER_PARAMETERS params); - virtual bool isHardwareAccelerated(); - virtual bool isAlwaysFullScreen(); - virtual int getDecoderCapabilities(); - virtual int getDecoderColorspace(); - virtual QSize getDecoderMaxResolution(); - virtual int submitDecodeUnit(PDECODE_UNIT du); + virtual bool initialize(PDECODER_PARAMETERS params) override; + virtual bool isHardwareAccelerated() override; + virtual bool isAlwaysFullScreen() override; + virtual int getDecoderCapabilities() override; + virtual int getDecoderColorspace() override; + virtual QSize getDecoderMaxResolution() override; + virtual int submitDecodeUnit(PDECODE_UNIT du) override; // Unused since rendering is done directly from the decode thread - virtual void renderFrameOnMainThread() {} + virtual void renderFrameOnMainThread() override {} // HDR is not supported by SLVideo - virtual void setHdrMode(bool) {} + virtual void setHdrMode(bool) override {} + virtual bool isHdrSupported() override { + return false; + } private: static void slLogCallback(void* context, ESLVideoLog logLevel, const char* message);