From 845e84adb7d4f8438cf6dfc7af3d660ef9f22b74 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sun, 19 Aug 2018 00:59:04 -0700 Subject: [PATCH] Avoid the test frame for DXVA2 and VT APIs to address flickering in full-screen on Win7 --- .../video/ffmpeg-renderers/dxva2.cpp | 7 +++++ app/streaming/video/ffmpeg-renderers/dxva2.h | 1 + .../video/ffmpeg-renderers/renderer.h | 2 ++ app/streaming/video/ffmpeg-renderers/sdl.cpp | 6 ++++ .../video/ffmpeg-renderers/vaapi.cpp | 8 ++++++ app/streaming/video/ffmpeg-renderers/vaapi.h | 1 + .../video/ffmpeg-renderers/vdpau.cpp | 7 +++++ app/streaming/video/ffmpeg-renderers/vdpau.h | 1 + app/streaming/video/ffmpeg-renderers/vt.mm | 6 ++++ app/streaming/video/ffmpeg.cpp | 28 +++++++++++-------- 10 files changed, 56 insertions(+), 11 deletions(-) diff --git a/app/streaming/video/ffmpeg-renderers/dxva2.cpp b/app/streaming/video/ffmpeg-renderers/dxva2.cpp index 386fac98..7e254071 100644 --- a/app/streaming/video/ffmpeg-renderers/dxva2.cpp +++ b/app/streaming/video/ffmpeg-renderers/dxva2.cpp @@ -496,6 +496,13 @@ bool DXVA2Renderer::initialize(SDL_Window* window, int videoFormat, int width, i return true; } +bool DXVA2Renderer::needsTestFrame() +{ + // We validate the DXVA2 profiles are supported + // in initialize() so no test frame is required + return false; +} + void DXVA2Renderer::renderFrameAtVsync(AVFrame *frame) { IDirect3DSurface9* surface = reinterpret_cast(frame->data[3]); diff --git a/app/streaming/video/ffmpeg-renderers/dxva2.h b/app/streaming/video/ffmpeg-renderers/dxva2.h index 6dbbbd4e..b7edceac 100644 --- a/app/streaming/video/ffmpeg-renderers/dxva2.h +++ b/app/streaming/video/ffmpeg-renderers/dxva2.h @@ -22,6 +22,7 @@ public: int maxFps); virtual bool prepareDecoderContext(AVCodecContext* context); virtual void renderFrameAtVsync(AVFrame* frame); + virtual bool needsTestFrame(); private: bool initializeDecoder(); diff --git a/app/streaming/video/ffmpeg-renderers/renderer.h b/app/streaming/video/ffmpeg-renderers/renderer.h index c1ad8699..79acfdf5 100644 --- a/app/streaming/video/ffmpeg-renderers/renderer.h +++ b/app/streaming/video/ffmpeg-renderers/renderer.h @@ -16,6 +16,7 @@ public: int maxFps) = 0; virtual bool prepareDecoderContext(AVCodecContext* context) = 0; virtual void renderFrameAtVsync(AVFrame* frame) = 0; + virtual bool needsTestFrame() = 0; }; class SdlRenderer : public IFFmpegRenderer { @@ -29,6 +30,7 @@ public: int maxFps); virtual bool prepareDecoderContext(AVCodecContext* context); virtual void renderFrameAtVsync(AVFrame* frame); + virtual bool needsTestFrame(); private: SDL_Renderer* m_Renderer; diff --git a/app/streaming/video/ffmpeg-renderers/sdl.cpp b/app/streaming/video/ffmpeg-renderers/sdl.cpp index ac1c786a..92d4ab44 100644 --- a/app/streaming/video/ffmpeg-renderers/sdl.cpp +++ b/app/streaming/video/ffmpeg-renderers/sdl.cpp @@ -30,6 +30,12 @@ bool SdlRenderer::prepareDecoderContext(AVCodecContext*) return true; } +bool SdlRenderer::needsTestFrame() +{ + // This renderer should always work + return false; +} + bool SdlRenderer::initialize(SDL_Window* window, int, int width, diff --git a/app/streaming/video/ffmpeg-renderers/vaapi.cpp b/app/streaming/video/ffmpeg-renderers/vaapi.cpp index 15ee06dd..6b4e8afe 100644 --- a/app/streaming/video/ffmpeg-renderers/vaapi.cpp +++ b/app/streaming/video/ffmpeg-renderers/vaapi.cpp @@ -141,6 +141,14 @@ VAAPIRenderer::prepareDecoderContext(AVCodecContext* context) return true; } +bool +VAAPIRenderer::needsTestFrame() +{ + // We need a test frame to see if this VAAPI driver + // supports the profile used for streaming + return true; +} + void VAAPIRenderer::renderFrameAtVsync(AVFrame* frame) { diff --git a/app/streaming/video/ffmpeg-renderers/vaapi.h b/app/streaming/video/ffmpeg-renderers/vaapi.h index e5543e9e..13122c4c 100644 --- a/app/streaming/video/ffmpeg-renderers/vaapi.h +++ b/app/streaming/video/ffmpeg-renderers/vaapi.h @@ -37,6 +37,7 @@ public: int maxFps); virtual bool prepareDecoderContext(AVCodecContext* context); virtual void renderFrameAtVsync(AVFrame* frame); + virtual bool needsTestFrame(); private: int m_WindowSystem; diff --git a/app/streaming/video/ffmpeg-renderers/vdpau.cpp b/app/streaming/video/ffmpeg-renderers/vdpau.cpp index 7afd4096..996d62c2 100644 --- a/app/streaming/video/ffmpeg-renderers/vdpau.cpp +++ b/app/streaming/video/ffmpeg-renderers/vdpau.cpp @@ -223,6 +223,13 @@ bool VDPAURenderer::prepareDecoderContext(AVCodecContext* context) return true; } +bool VDPAURenderer::needsTestFrame() +{ + // We need a test frame to see if this VDPAU driver + // supports the profile used for streaming + return true; +} + void VDPAURenderer::renderFrameAtVsync(AVFrame* frame) { VdpStatus status; diff --git a/app/streaming/video/ffmpeg-renderers/vdpau.h b/app/streaming/video/ffmpeg-renderers/vdpau.h index 0b8b200c..56ead072 100644 --- a/app/streaming/video/ffmpeg-renderers/vdpau.h +++ b/app/streaming/video/ffmpeg-renderers/vdpau.h @@ -20,6 +20,7 @@ public: int maxFps); virtual bool prepareDecoderContext(AVCodecContext* context); virtual void renderFrameAtVsync(AVFrame* frame); + virtual bool needsTestFrame(); private: uint32_t m_VideoWidth, m_VideoHeight; diff --git a/app/streaming/video/ffmpeg-renderers/vt.mm b/app/streaming/video/ffmpeg-renderers/vt.mm index a7643e17..aa0e55e0 100644 --- a/app/streaming/video/ffmpeg-renderers/vt.mm +++ b/app/streaming/video/ffmpeg-renderers/vt.mm @@ -189,6 +189,12 @@ public: return true; } + virtual bool needsTestFrame() override + { + // We query VT to determine whether the codec is supported + return false; + } + private: void setupDisplayLayer() { diff --git a/app/streaming/video/ffmpeg.cpp b/app/streaming/video/ffmpeg.cpp index ef5cf7b9..3e541ff3 100644 --- a/app/streaming/video/ffmpeg.cpp +++ b/app/streaming/video/ffmpeg.cpp @@ -280,20 +280,26 @@ bool FFmpegVideoDecoder::initialize( } m_HwDecodeCfg = config; - // Submit test frame to ensure this codec really works + // Initialize the hardware codec and submit a test frame if the renderer needs it if (m_Renderer->initialize(window, videoFormat, width, height, maxFps) && - completeInitialization(decoder, window, videoFormat, width, height, maxFps, true)) { - // OK, it worked, so now let's initialize it for real - reset(); - if ((m_Renderer = createAcceleratedRenderer(config)) != nullptr && - m_Renderer->initialize(window, videoFormat, width, height, maxFps) && - completeInitialization(decoder, window, videoFormat, width, height, maxFps, false)) { - return true; + completeInitialization(decoder, window, videoFormat, width, height, maxFps, m_Renderer->needsTestFrame())) { + if (m_Renderer->needsTestFrame()) { + // The test worked, so now let's initialize it for real + reset(); + if ((m_Renderer = createAcceleratedRenderer(config)) != nullptr && + m_Renderer->initialize(window, videoFormat, width, height, maxFps) && + completeInitialization(decoder, window, videoFormat, width, height, maxFps, false)) { + return true; + } + else { + SDL_LogCritical(SDL_LOG_CATEGORY_APPLICATION, + "Decoder failed to initialize after successful test"); + reset(); + } } else { - SDL_LogCritical(SDL_LOG_CATEGORY_APPLICATION, - "Decoder failed to initialize after successful test"); - reset(); + // No test required. Good to go now. + return true; } } else {