diff --git a/app/streaming/session.cpp b/app/streaming/session.cpp index 4ab101d9..85f8b903 100644 --- a/app/streaming/session.cpp +++ b/app/streaming/session.cpp @@ -143,19 +143,28 @@ void Session::clConnectionStatusUpdate(int connectionStatus) } } -#define CALL_INITIALIZE(dec) (dec)->initialize(vds, window, videoFormat, width, height, frameRate, enableVsync, enableFramePacing) - bool Session::chooseDecoder(StreamingPreferences::VideoDecoderSelection vds, SDL_Window* window, int videoFormat, int width, int height, int frameRate, bool enableVsync, bool enableFramePacing, bool testOnly, IVideoDecoder*& chosenDecoder) { + DECODER_PARAMETERS params; + + params.width = width; + params.height = height; + params.frameRate = frameRate; + params.videoFormat = videoFormat; + params.window = window; + params.enableVsync = enableVsync; + params.enableFramePacing = enableFramePacing; + params.vds = vds; + SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "V-sync %s", enableVsync ? "enabled" : "disabled"); #ifdef HAVE_SLVIDEO chosenDecoder = new SLVideoDecoder(testOnly); - if (CALL_INITIALIZE(chosenDecoder)) { + if (chosenDecoder->initialize(¶ms)) { SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "SLVideo video decoder chosen"); return true; @@ -170,7 +179,7 @@ bool Session::chooseDecoder(StreamingPreferences::VideoDecoderSelection vds, #ifdef HAVE_FFMPEG chosenDecoder = new FFmpegVideoDecoder(testOnly); - if (CALL_INITIALIZE(chosenDecoder)) { + if (chosenDecoder->initialize(¶ms)) { SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "FFmpeg-based video decoder chosen"); return true; diff --git a/app/streaming/video/decoder.h b/app/streaming/video/decoder.h index 139c83e0..81565faf 100644 --- a/app/streaming/video/decoder.h +++ b/app/streaming/video/decoder.h @@ -26,17 +26,22 @@ typedef struct _VIDEO_STATS { uint32_t measurementStartTimestamp; } VIDEO_STATS, *PVIDEO_STATS; +typedef struct _DECODER_PARAMETERS { + SDL_Window* window; + StreamingPreferences::VideoDecoderSelection vds; + + int videoFormat; + int width; + int height; + int frameRate; + bool enableVsync; + bool enableFramePacing; +} DECODER_PARAMETERS, *PDECODER_PARAMETERS; + class IVideoDecoder { public: virtual ~IVideoDecoder() {} - virtual bool initialize(StreamingPreferences::VideoDecoderSelection vds, - SDL_Window* window, - int videoFormat, - int width, - int height, - int frameRate, - bool enableVsync, - bool enableFramePacing) = 0; + virtual bool initialize(PDECODER_PARAMETERS params) = 0; virtual bool isHardwareAccelerated() = 0; virtual int getDecoderCapabilities() = 0; virtual int submitDecodeUnit(PDECODE_UNIT du) = 0; diff --git a/app/streaming/video/ffmpeg-renderers/dxva2.cpp b/app/streaming/video/ffmpeg-renderers/dxva2.cpp index b8e58ec1..875a0ca6 100644 --- a/app/streaming/video/ffmpeg-renderers/dxva2.cpp +++ b/app/streaming/video/ffmpeg-renderers/dxva2.cpp @@ -107,7 +107,7 @@ bool DXVA2Renderer::prepareDecoderContext(AVCodecContext* context) int DXVA2Renderer::ffGetBuffer2(AVCodecContext* context, AVFrame* frame, int) { - DXVA2Renderer* me = (DXVA2Renderer*)((FFmpegVideoDecoder*)context->opaque)->getRenderer(); + DXVA2Renderer* me = (DXVA2Renderer*)((FFmpegVideoDecoder*)context->opaque)->getBackendRenderer(); frame->buf[0] = av_buffer_pool_get(me->m_Pool); if (!frame->buf[0]) { @@ -649,11 +649,11 @@ bool DXVA2Renderer::initializeDevice(SDL_Window* window, bool enableVsync) return true; } -bool DXVA2Renderer::initialize(SDL_Window* window, int videoFormat, int width, int height, int, bool enableVsync) +bool DXVA2Renderer::initialize(PDECODER_PARAMETERS params) { - m_VideoFormat = videoFormat; - m_VideoWidth = width; - m_VideoHeight = height; + m_VideoFormat = params->videoFormat; + m_VideoWidth = params->width; + m_VideoHeight = params->height; RtlZeroMemory(&m_Desc, sizeof(m_Desc)); @@ -682,7 +682,7 @@ bool DXVA2Renderer::initialize(SDL_Window* window, int videoFormat, int width, i m_Desc.SampleFormat.SampleFormat = DXVA2_SampleProgressiveFrame; m_Desc.Format = (D3DFORMAT)MAKEFOURCC('N','V','1','2'); - if (!initializeDevice(window, enableVsync)) { + if (!initializeDevice(params->window, params->enableVsync)) { return false; } diff --git a/app/streaming/video/ffmpeg-renderers/dxva2.h b/app/streaming/video/ffmpeg-renderers/dxva2.h index 8e39bc37..f2cb8020 100644 --- a/app/streaming/video/ffmpeg-renderers/dxva2.h +++ b/app/streaming/video/ffmpeg-renderers/dxva2.h @@ -16,12 +16,7 @@ class DXVA2Renderer : public IFFmpegRenderer public: DXVA2Renderer(); virtual ~DXVA2Renderer(); - virtual bool initialize(SDL_Window* window, - int videoFormat, - int width, - int height, - int maxFps, - bool enableVsync) override; + virtual bool initialize(PDECODER_PARAMETERS params) override; virtual bool prepareDecoderContext(AVCodecContext* context) override; virtual void renderFrame(AVFrame* frame) override; virtual bool needsTestFrame() override; diff --git a/app/streaming/video/ffmpeg-renderers/renderer.h b/app/streaming/video/ffmpeg-renderers/renderer.h index 19b543af..4ceea08f 100644 --- a/app/streaming/video/ffmpeg-renderers/renderer.h +++ b/app/streaming/video/ffmpeg-renderers/renderer.h @@ -2,6 +2,7 @@ #include +#include "streaming/video/decoder.h" #include "streaming/video/overlaymanager.h" extern "C" { @@ -16,12 +17,7 @@ public: PACING_ANY }; - virtual bool initialize(SDL_Window* window, - int videoFormat, - int width, - int height, - int maxFps, - bool enableVsync) = 0; + virtual bool initialize(PDECODER_PARAMETERS params) = 0; virtual bool prepareDecoderContext(AVCodecContext* context) = 0; virtual void renderFrame(AVFrame* frame) = 0; virtual bool needsTestFrame() = 0; diff --git a/app/streaming/video/ffmpeg-renderers/sdlvid.cpp b/app/streaming/video/ffmpeg-renderers/sdlvid.cpp index c80e1280..ee30b863 100644 --- a/app/streaming/video/ffmpeg-renderers/sdlvid.cpp +++ b/app/streaming/video/ffmpeg-renderers/sdlvid.cpp @@ -144,20 +144,15 @@ bool SdlRenderer::isRenderThreadSupported() return true; } -bool SdlRenderer::initialize(SDL_Window* window, - int, - int width, - int height, - int, - bool enableVsync) +bool SdlRenderer::initialize(PDECODER_PARAMETERS params) { Uint32 rendererFlags = SDL_RENDERER_ACCELERATED; - if ((SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN) { + if ((SDL_GetWindowFlags(params->window) & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN) { // In full-screen exclusive mode, we enable V-sync if requested. For other modes, Windows and Mac // have compositors that make rendering tear-free. Linux compositor varies by distro and user // configuration but doesn't seem feasible to detect here. - if (enableVsync) { + if (params->enableVsync) { rendererFlags |= SDL_RENDERER_PRESENTVSYNC; } } @@ -170,7 +165,7 @@ bool SdlRenderer::initialize(SDL_Window* window, SDL_SetHintWithPriority(SDL_HINT_RENDER_DIRECT3D_THREADSAFE, "1", SDL_HINT_OVERRIDE); #endif - m_Renderer = SDL_CreateRenderer(window, -1, rendererFlags); + m_Renderer = SDL_CreateRenderer(params->window, -1, rendererFlags); if (!m_Renderer) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_CreateRenderer() failed: %s", @@ -180,7 +175,7 @@ bool SdlRenderer::initialize(SDL_Window* window, // The window may be smaller than the stream size, so ensure our // logical rendering surface size is equal to the stream size - SDL_RenderSetLogicalSize(m_Renderer, width, height); + SDL_RenderSetLogicalSize(m_Renderer, params->width, params->height); // Draw a black frame until the video stream starts rendering SDL_SetRenderDrawColor(m_Renderer, 0, 0, 0, SDL_ALPHA_OPAQUE); @@ -190,8 +185,8 @@ bool SdlRenderer::initialize(SDL_Window* window, m_Texture = SDL_CreateTexture(m_Renderer, SDL_PIXELFORMAT_YV12, SDL_TEXTUREACCESS_STREAMING, - width, - height); + params->width, + params->height); if (!m_Texture) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_CreateRenderer() failed: %s", @@ -252,6 +247,32 @@ void SdlRenderer::renderOverlay(Overlay::OverlayType type) void SdlRenderer::renderFrame(AVFrame* frame) { + int err; + AVFrame* swFrame = nullptr; + + if (frame->hw_frames_ctx != nullptr) { + // If we are acting as the frontend for a hardware + // accelerated decoder, we'll need to read the frame + // back to render it. + + swFrame = av_frame_alloc(); + if (swFrame == nullptr) { + return; + } + + swFrame->width = frame->width; + swFrame->height = frame->height; + swFrame->format = AV_PIX_FMT_YUV420P; + + err = av_hwframe_transfer_data(swFrame, frame, 0); + if (err != 0) { + av_frame_free(&swFrame); + return; + } + + frame = swFrame; + } + SDL_UpdateYUVTexture(m_Texture, nullptr, frame->data[0], frame->linesize[0], @@ -271,4 +292,8 @@ void SdlRenderer::renderFrame(AVFrame* frame) } SDL_RenderPresent(m_Renderer); + + if (swFrame != nullptr) { + av_frame_free(&swFrame); + } } diff --git a/app/streaming/video/ffmpeg-renderers/sdlvid.h b/app/streaming/video/ffmpeg-renderers/sdlvid.h index baac6977..d36d7e0b 100644 --- a/app/streaming/video/ffmpeg-renderers/sdlvid.h +++ b/app/streaming/video/ffmpeg-renderers/sdlvid.h @@ -8,12 +8,7 @@ class SdlRenderer : public IFFmpegRenderer { public: SdlRenderer(); virtual ~SdlRenderer() override; - virtual bool initialize(SDL_Window* window, - int videoFormat, - int width, - int height, - int maxFps, - bool enableVsync) override; + virtual bool initialize(PDECODER_PARAMETERS params) override; virtual bool prepareDecoderContext(AVCodecContext* context) override; virtual void renderFrame(AVFrame* frame) override; virtual bool needsTestFrame() override; diff --git a/app/streaming/video/ffmpeg-renderers/vaapi.cpp b/app/streaming/video/ffmpeg-renderers/vaapi.cpp index f4c9d06b..d8fd3547 100644 --- a/app/streaming/video/ffmpeg-renderers/vaapi.cpp +++ b/app/streaming/video/ffmpeg-renderers/vaapi.cpp @@ -29,19 +29,19 @@ VAAPIRenderer::~VAAPIRenderer() } bool -VAAPIRenderer::initialize(SDL_Window* window, int, int width, int height, int, bool) +VAAPIRenderer::initialize(PDECODER_PARAMETERS params) { int err; SDL_SysWMinfo info; - m_VideoWidth = width; - m_VideoHeight = height; + m_VideoWidth = params->width; + m_VideoHeight = params->height; - SDL_GetWindowSize(window, &m_DisplayWidth, &m_DisplayHeight); + SDL_GetWindowSize(params->window, &m_DisplayWidth, &m_DisplayHeight); SDL_VERSION(&info.version); - if (!SDL_GetWindowWMInfo(window, &info)) { + if (!SDL_GetWindowWMInfo(params->window, &info)) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_GetWindowWMInfo() failed: %s", SDL_GetError()); diff --git a/app/streaming/video/ffmpeg-renderers/vaapi.h b/app/streaming/video/ffmpeg-renderers/vaapi.h index 91eb98ee..3fd58d87 100644 --- a/app/streaming/video/ffmpeg-renderers/vaapi.h +++ b/app/streaming/video/ffmpeg-renderers/vaapi.h @@ -30,12 +30,7 @@ class VAAPIRenderer : public IFFmpegRenderer public: VAAPIRenderer(); virtual ~VAAPIRenderer(); - virtual bool initialize(SDL_Window* window, - int videoFormat, - int width, - int height, - int maxFps, - bool enableVsync); + virtual bool initialize(PDECODER_PARAMETERS params); virtual bool prepareDecoderContext(AVCodecContext* context); virtual void renderFrame(AVFrame* frame); virtual bool needsTestFrame(); diff --git a/app/streaming/video/ffmpeg-renderers/vdpau.cpp b/app/streaming/video/ffmpeg-renderers/vdpau.cpp index d6765ff8..02802dcf 100644 --- a/app/streaming/video/ffmpeg-renderers/vdpau.cpp +++ b/app/streaming/video/ffmpeg-renderers/vdpau.cpp @@ -54,14 +54,14 @@ VDPAURenderer::~VDPAURenderer() } } -bool VDPAURenderer::initialize(SDL_Window* window, int, int width, int height, int, bool) +bool VDPAURenderer::initialize(PDECODER_PARAMETERS params) { int err; VdpStatus status; SDL_SysWMinfo info; - m_VideoWidth = width; - m_VideoHeight = height; + m_VideoWidth = params->width; + m_VideoHeight = params->height; err = av_hwdevice_ctx_create(&m_HwContext, AV_HWDEVICE_TYPE_VDPAU, @@ -93,11 +93,11 @@ bool VDPAURenderer::initialize(SDL_Window* window, int, int width, int height, i GET_PROC_ADDRESS(VDP_FUNC_ID_VIDEO_SURFACE_GET_PARAMETERS, &m_VdpVideoSurfaceGetParameters); GET_PROC_ADDRESS(VDP_FUNC_ID_GET_INFORMATION_STRING, &m_VdpGetInformationString); - SDL_GetWindowSize(window, (int*)&m_DisplayWidth, (int*)&m_DisplayHeight); + SDL_GetWindowSize(params->window, (int*)&m_DisplayWidth, (int*)&m_DisplayHeight); SDL_VERSION(&info.version); - if (!SDL_GetWindowWMInfo(window, &info)) { + if (!SDL_GetWindowWMInfo(params->window, &info)) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_GetWindowWMInfo() failed: %s", SDL_GetError()); diff --git a/app/streaming/video/ffmpeg-renderers/vdpau.h b/app/streaming/video/ffmpeg-renderers/vdpau.h index 0620a3a8..ffac4b8a 100644 --- a/app/streaming/video/ffmpeg-renderers/vdpau.h +++ b/app/streaming/video/ffmpeg-renderers/vdpau.h @@ -13,12 +13,7 @@ class VDPAURenderer : public IFFmpegRenderer public: VDPAURenderer(); virtual ~VDPAURenderer(); - virtual bool initialize(SDL_Window* window, - int videoFormat, - int width, - int height, - int maxFps, - bool enableVsync); + virtual bool initialize(PDECODER_PARAMETERS params); virtual bool prepareDecoderContext(AVCodecContext* context); virtual void renderFrame(AVFrame* frame); virtual bool needsTestFrame(); diff --git a/app/streaming/video/ffmpeg-renderers/vt.mm b/app/streaming/video/ffmpeg-renderers/vt.mm index 690945c3..ddc1b0eb 100644 --- a/app/streaming/video/ffmpeg-renderers/vt.mm +++ b/app/streaming/video/ffmpeg-renderers/vt.mm @@ -106,16 +106,11 @@ public: CFRelease(sampleBuffer); } - virtual bool initialize(SDL_Window* window, - int videoFormat, - int, - int, - int, - bool) override + virtual bool initialize(PDECODER_PARAMETERS params) override { int err; - if (videoFormat & VIDEO_FORMAT_MASK_H264) { + if (params->videoFormat & VIDEO_FORMAT_MASK_H264) { // Prior to 10.13, we'll just assume everything has // H.264 support and fail open to allow VT decode. #if __MAC_OS_X_VERSION_MAX_ALLOWED >= 101300 @@ -133,7 +128,7 @@ public: "Assuming H.264 HW decode on < macOS 10.13"); } } - else if (videoFormat & VIDEO_FORMAT_MASK_H265) { + else if (params->videoFormat & VIDEO_FORMAT_MASK_H265) { #if __MAC_OS_X_VERSION_MAX_ALLOWED >= 101300 if (__builtin_available(macOS 10.13, *)) { if (!VTIsHardwareDecodeSupported(kCMVideoCodecType_HEVC)) { @@ -156,7 +151,7 @@ public: SDL_VERSION(&info.version); - if (!SDL_GetWindowWMInfo(window, &info)) { + if (!SDL_GetWindowWMInfo(params->window, &info)) { SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "SDL_GetWindowWMInfo() failed: %s", SDL_GetError()); diff --git a/app/streaming/video/ffmpeg.cpp b/app/streaming/video/ffmpeg.cpp index 9f990253..ac95e332 100644 --- a/app/streaming/video/ffmpeg.cpp +++ b/app/streaming/video/ffmpeg.cpp @@ -38,7 +38,7 @@ bool FFmpegVideoDecoder::isHardwareAccelerated() int FFmpegVideoDecoder::getDecoderCapabilities() { - return m_Renderer->getDecoderCapabilities(); + return m_BackendRenderer->getDecoderCapabilities(); } enum AVPixelFormat FFmpegVideoDecoder::ffGetFormat(AVCodecContext* context, @@ -66,7 +66,8 @@ FFmpegVideoDecoder::FFmpegVideoDecoder(bool testOnly) : m_VideoDecoderCtx(nullptr), m_DecodeBuffer(1024 * 1024, 0), m_HwDecodeCfg(nullptr), - m_Renderer(nullptr), + m_BackendRenderer(nullptr), + m_FrontendRenderer(nullptr), m_ConsecutiveFailedDecodes(0), m_Pacer(nullptr), m_LastFrameNumber(0), @@ -95,9 +96,9 @@ FFmpegVideoDecoder::~FFmpegVideoDecoder() av_log_set_level(AV_LOG_INFO); } -IFFmpegRenderer* FFmpegVideoDecoder::getRenderer() +IFFmpegRenderer* FFmpegVideoDecoder::getBackendRenderer() { - return m_Renderer; + return m_BackendRenderer; } void FFmpegVideoDecoder::reset() @@ -116,8 +117,14 @@ void FFmpegVideoDecoder::reset() Session::get()->getOverlayManager().setOverlayRenderer(nullptr); } - delete m_Renderer; - m_Renderer = nullptr; + // If we have a separate frontend renderer, free that first + if (m_FrontendRenderer != m_BackendRenderer) { + delete m_FrontendRenderer; + m_FrontendRenderer = nullptr; + } + + delete m_BackendRenderer; + m_BackendRenderer = nullptr; if (!m_TestOnly) { logVideoStats(m_GlobalVideoStats, "Global video stats"); @@ -128,35 +135,46 @@ void FFmpegVideoDecoder::reset() } } -bool FFmpegVideoDecoder::completeInitialization(AVCodec* decoder, SDL_Window* window, - int videoFormat, int width, int height, - int maxFps, bool enableFramePacing, bool testFrame) +bool FFmpegVideoDecoder::createFrontendRenderer(PDECODER_PARAMETERS params) +{ + m_FrontendRenderer = m_BackendRenderer; + + // Determine whether the frontend renderer prefers frame pacing + auto vsyncConstraint = m_FrontendRenderer->getFramePacingConstraint(); + if (vsyncConstraint == IFFmpegRenderer::PACING_FORCE_OFF && params->enableFramePacing) { + SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, + "Frame pacing is forcefully disabled by the frontend renderer"); + params->enableFramePacing = false; + } + else if (vsyncConstraint == IFFmpegRenderer::PACING_FORCE_ON && !params->enableFramePacing) { + // FIXME: This duplicates logic in Session.cpp + int displayHz = StreamUtils::getDisplayRefreshRate(params->window); + if (displayHz + 5 >= params->frameRate) { + SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, + "Frame pacing is forcefully enabled by the frontend renderer"); + params->enableFramePacing = true; + } + } + + return true; +} + +bool FFmpegVideoDecoder::completeInitialization(AVCodec* decoder, PDECODER_PARAMETERS params, bool testFrame) { // In test-only mode, we should only see test frames SDL_assert(!m_TestOnly || testFrame); - auto vsyncConstraint = m_Renderer->getFramePacingConstraint(); - if (vsyncConstraint == IFFmpegRenderer::PACING_FORCE_OFF && enableFramePacing) { - SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, - "Frame pacing is forcefully disabled by the active renderer"); - enableFramePacing = false; - } - else if (vsyncConstraint == IFFmpegRenderer::PACING_FORCE_ON && !enableFramePacing) { - // FIXME: This duplicates logic in Session.cpp - int displayHz = StreamUtils::getDisplayRefreshRate(window); - if (displayHz + 5 >= maxFps) { - SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, - "Frame pacing is forcefully enabled by the active renderer"); - enableFramePacing = true; - } + // Create the frontend renderer based on the capabilities of the backend renderer + if (!createFrontendRenderer(params)) { + return false; } - m_StreamFps = maxFps; + m_StreamFps = params->frameRate; // Don't bother initializing Pacer if we're not actually going to render if (!testFrame) { - m_Pacer = new Pacer(m_Renderer, &m_ActiveWndVideoStats); - if (!m_Pacer->initialize(window, maxFps, enableFramePacing)) { + m_Pacer = new Pacer(m_FrontendRenderer, &m_ActiveWndVideoStats); + if (!m_Pacer->initialize(params->window, params->frameRate, params->enableFramePacing)) { return false; } } @@ -176,7 +194,7 @@ bool FFmpegVideoDecoder::completeInitialization(AVCodec* decoder, SDL_Window* wi m_VideoDecoderCtx->flags2 |= AV_CODEC_FLAG2_SHOW_ALL; // Enable slice multi-threading for software decoding - if (!m_HwDecodeCfg) { + if (!isHardwareAccelerated()) { m_VideoDecoderCtx->thread_type = FF_THREAD_SLICE; m_VideoDecoderCtx->thread_count = qMin(MAX_SLICES, SDL_GetCPUCount()); } @@ -186,13 +204,13 @@ bool FFmpegVideoDecoder::completeInitialization(AVCodec* decoder, SDL_Window* wi } // Setup decoding parameters - m_VideoDecoderCtx->width = width; - m_VideoDecoderCtx->height = height; + m_VideoDecoderCtx->width = params->width; + m_VideoDecoderCtx->height = params->height; m_VideoDecoderCtx->pix_fmt = AV_PIX_FMT_YUV420P; // FIXME: HDR m_VideoDecoderCtx->get_format = ffGetFormat; - // Allow the renderer to attach data to this decoder - if (!m_Renderer->prepareDecoderContext(m_VideoDecoderCtx)) { + // Allow the backend renderer to attach data to this decoder + if (!m_BackendRenderer->prepareDecoderContext(m_VideoDecoderCtx)) { return false; } @@ -207,7 +225,7 @@ bool FFmpegVideoDecoder::completeInitialization(AVCodec* decoder, SDL_Window* wi if (err < 0) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to open decoder for format: %x", - videoFormat); + params->videoFormat); return false; } @@ -217,7 +235,7 @@ bool FFmpegVideoDecoder::completeInitialization(AVCodec* decoder, SDL_Window* wi // now to see if things will actually work when the video stream // comes in. if (testFrame) { - if (videoFormat & VIDEO_FORMAT_MASK_H264) { + if (params->videoFormat & VIDEO_FORMAT_MASK_H264) { m_Pkt.data = (uint8_t*)k_H264TestFrame; m_Pkt.size = sizeof(k_H264TestFrame); } @@ -236,8 +254,8 @@ bool FFmpegVideoDecoder::completeInitialization(AVCodec* decoder, SDL_Window* wi } } else { - if ((videoFormat & VIDEO_FORMAT_MASK_H264) && - !(m_Renderer->getDecoderCapabilities() & CAPABILITY_REFERENCE_FRAME_INVALIDATION_AVC)) { + if ((params->videoFormat & VIDEO_FORMAT_MASK_H264) && + !(m_BackendRenderer->getDecoderCapabilities() & CAPABILITY_REFERENCE_FRAME_INVALIDATION_AVC)) { SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Using H.264 SPS fixup"); m_NeedsSpsFixup = true; @@ -246,8 +264,8 @@ bool FFmpegVideoDecoder::completeInitialization(AVCodec* decoder, SDL_Window* wi m_NeedsSpsFixup = false; } - // Tell overlay manager to use this renderer - Session::get()->getOverlayManager().setOverlayRenderer(m_Renderer); + // Tell overlay manager to use this frontend renderer + Session::get()->getOverlayManager().setOverlayRenderer(m_FrontendRenderer); } return true; @@ -361,25 +379,17 @@ IFFmpegRenderer* FFmpegVideoDecoder::createAcceleratedRenderer(const AVCodecHWCo } } -bool FFmpegVideoDecoder::initialize( - StreamingPreferences::VideoDecoderSelection vds, - SDL_Window* window, - int videoFormat, - int width, - int height, - int maxFps, - bool enableVsync, - bool enableFramePacing) +bool FFmpegVideoDecoder::initialize(PDECODER_PARAMETERS params) { AVCodec* decoder; // Increase log level until the first frame is decoded av_log_set_level(AV_LOG_DEBUG); - if (videoFormat & VIDEO_FORMAT_MASK_H264) { + if (params->videoFormat & VIDEO_FORMAT_MASK_H264) { decoder = avcodec_find_decoder(AV_CODEC_ID_H264); } - else if (videoFormat & VIDEO_FORMAT_MASK_H265) { + else if (params->videoFormat & VIDEO_FORMAT_MASK_H265) { decoder = avcodec_find_decoder(AV_CODEC_ID_HEVC); } else { @@ -390,20 +400,20 @@ bool FFmpegVideoDecoder::initialize( if (!decoder) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to find decoder for format: %x", - videoFormat); + params->videoFormat); return false; } for (int i = 0;; i++) { const AVCodecHWConfig *config = avcodec_get_hw_config(decoder, i); - if (!config || vds == StreamingPreferences::VDS_FORCE_SOFTWARE) { + if (!config || params->vds == StreamingPreferences::VDS_FORCE_SOFTWARE) { // No matching hardware acceleration support. // This is not an error. m_HwDecodeCfg = nullptr; - m_Renderer = new SdlRenderer(); - if (vds != StreamingPreferences::VDS_FORCE_HARDWARE && - m_Renderer->initialize(window, videoFormat, width, height, maxFps, enableVsync) && - completeInitialization(decoder, window, videoFormat, width, height, maxFps, enableFramePacing, m_TestOnly)) { + m_BackendRenderer = new SdlRenderer(); + if (params->vds != StreamingPreferences::VDS_FORCE_HARDWARE && + m_BackendRenderer->initialize(params) && + completeInitialization(decoder, params, m_TestOnly)) { return true; } else { @@ -412,27 +422,27 @@ bool FFmpegVideoDecoder::initialize( } } - m_Renderer = createAcceleratedRenderer(config); - if (!m_Renderer) { + m_BackendRenderer = createAcceleratedRenderer(config); + if (!m_BackendRenderer) { continue; } m_HwDecodeCfg = config; // Initialize the hardware codec and submit a test frame if the renderer needs it - if (m_Renderer->initialize(window, videoFormat, width, height, maxFps, enableVsync) && - completeInitialization(decoder, window, videoFormat, width, height, maxFps, enableFramePacing, m_TestOnly || m_Renderer->needsTestFrame())) { + if (m_BackendRenderer->initialize(params) && + completeInitialization(decoder, params, m_TestOnly || m_BackendRenderer->needsTestFrame())) { if (m_TestOnly) { // This decoder is only for testing capabilities, so don't bother // creating a usable renderer return true; } - if (m_Renderer->needsTestFrame()) { + if (m_BackendRenderer->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, enableVsync) && - completeInitialization(decoder, window, videoFormat, width, height, maxFps, enableFramePacing, false)) { + if ((m_BackendRenderer = createAcceleratedRenderer(config)) != nullptr && + m_BackendRenderer->initialize(params) && + completeInitialization(decoder, params, false)) { return true; } else { diff --git a/app/streaming/video/ffmpeg.h b/app/streaming/video/ffmpeg.h index 9127a3be..8fc6a8c5 100644 --- a/app/streaming/video/ffmpeg.h +++ b/app/streaming/video/ffmpeg.h @@ -12,25 +12,16 @@ class FFmpegVideoDecoder : public IVideoDecoder { public: FFmpegVideoDecoder(bool testOnly); virtual ~FFmpegVideoDecoder() override; - virtual bool initialize(StreamingPreferences::VideoDecoderSelection vds, - SDL_Window* window, - int videoFormat, - int width, - int height, - int maxFps, - bool enableVsync, - bool enableFramePacing) override; + virtual bool initialize(PDECODER_PARAMETERS params) override; virtual bool isHardwareAccelerated() override; virtual int getDecoderCapabilities() override; virtual int submitDecodeUnit(PDECODE_UNIT du) override; virtual void renderFrameOnMainThread() override; - virtual IFFmpegRenderer* getRenderer(); + virtual IFFmpegRenderer* getBackendRenderer(); private: - bool completeInitialization(AVCodec* decoder, SDL_Window* window, - int videoFormat, int width, int height, - int maxFps, bool enableFramePacing, bool testFrame); + bool completeInitialization(AVCodec* decoder, PDECODER_PARAMETERS params, bool testFrame); void stringifyVideoStats(VIDEO_STATS& stats, char* output); @@ -38,6 +29,8 @@ private: void addVideoStats(VIDEO_STATS& src, VIDEO_STATS& dst); + bool createFrontendRenderer(PDECODER_PARAMETERS params); + IFFmpegRenderer* createAcceleratedRenderer(const AVCodecHWConfig* hwDecodeCfg); void reset(); @@ -52,7 +45,8 @@ private: AVCodecContext* m_VideoDecoderCtx; QByteArray m_DecodeBuffer; const AVCodecHWConfig* m_HwDecodeCfg; - IFFmpegRenderer* m_Renderer; + IFFmpegRenderer* m_BackendRenderer; + IFFmpegRenderer* m_FrontendRenderer; int m_ConsecutiveFailedDecodes; Pacer* m_Pacer; VIDEO_STATS m_ActiveWndVideoStats; diff --git a/app/streaming/video/slvid.cpp b/app/streaming/video/slvid.cpp index 642f49df..f0ce6e2d 100644 --- a/app/streaming/video/slvid.cpp +++ b/app/streaming/video/slvid.cpp @@ -32,17 +32,15 @@ SLVideoDecoder::getDecoderCapabilities() } bool -SLVideoDecoder::initialize(StreamingPreferences::VideoDecoderSelection vds, - SDL_Window*, - int videoFormat, int, int, int frameRate, bool, bool) +SLVideoDecoder::initialize(PDECODER_PARAMETERS params) { // SLVideo only supports hardware decoding - if (vds == StreamingPreferences::VDS_FORCE_SOFTWARE) { + if (params->vds == StreamingPreferences::VDS_FORCE_SOFTWARE) { return false; } // SLVideo only supports H.264 - if (videoFormat != VIDEO_FORMAT_H264) { + if (params->videoFormat != VIDEO_FORMAT_H264) { return false; } @@ -61,7 +59,7 @@ SLVideoDecoder::initialize(StreamingPreferences::VideoDecoderSelection vds, return false; } - SLVideo_SetStreamTargetFramerate(m_VideoStream, frameRate, 1); + SLVideo_SetStreamTargetFramerate(m_VideoStream, params->frameRate, 1); return true; } diff --git a/app/streaming/video/slvid.h b/app/streaming/video/slvid.h index 1af92edf..bbe0467d 100644 --- a/app/streaming/video/slvid.h +++ b/app/streaming/video/slvid.h @@ -9,14 +9,7 @@ class SLVideoDecoder : public IVideoDecoder public: SLVideoDecoder(bool testOnly); virtual ~SLVideoDecoder(); - virtual bool initialize(StreamingPreferences::VideoDecoderSelection vds, - SDL_Window* window, - int videoFormat, - int width, - int height, - int frameRate, - bool enableVsync, - bool enableFramePacing); + virtual bool initialize(PDECODER_PARAMETERS params); virtual bool isHardwareAccelerated(); virtual int getDecoderCapabilities(); virtual int submitDecodeUnit(PDECODE_UNIT du);