From 197c1ba21b561184b0db9f1a7cac6ec5b1b52669 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sat, 21 May 2022 00:10:49 -0500 Subject: [PATCH] Add support for the status overlay on Steam Link --- app/streaming/video/slvid.cpp | 78 ++++++++++++++++++++++++++++++++++- app/streaming/video/slvid.h | 8 +++- 2 files changed, 84 insertions(+), 2 deletions(-) diff --git a/app/streaming/video/slvid.cpp b/app/streaming/video/slvid.cpp index 234c420d..1cedc1df 100644 --- a/app/streaming/video/slvid.cpp +++ b/app/streaming/video/slvid.cpp @@ -1,18 +1,30 @@ #include "slvid.h" +#include "streaming/session.h" SLVideoDecoder::SLVideoDecoder(bool) : m_VideoContext(nullptr), - m_VideoStream(nullptr) + m_VideoStream(nullptr), + m_Overlay(nullptr) { SLVideo_SetLogFunction(SLVideoDecoder::slLogCallback, nullptr); } SLVideoDecoder::~SLVideoDecoder() { + Session* session = Session::get(); + if (session != nullptr) { + session->getOverlayManager().setOverlayRenderer(nullptr); + } + if (m_VideoStream != nullptr) { SLVideo_FreeStream(m_VideoStream); } + if (m_Overlay != nullptr) { + SLVideo_HideOverlay(m_Overlay); + SLVideo_FreeOverlay(m_Overlay); + } + if (m_VideoContext != nullptr) { SLVideo_FreeContext(m_VideoContext); } @@ -78,6 +90,14 @@ SLVideoDecoder::initialize(PDECODER_PARAMETERS params) SLVideo_SetStreamVideoTransferMatrix(m_VideoStream, k_ESLVideoTransferMatrix_BT709); SLVideo_SetStreamTargetFramerate(m_VideoStream, params->frameRate, 1); + SDL_GetWindowSize(params->window, &m_ViewportWidth, &m_ViewportHeight); + + // Register ourselves for overlay callbacks + Session* session = Session::get(); + if (session != nullptr) { + session->getOverlayManager().setOverlayRenderer(this); + } + return true; } @@ -126,6 +146,62 @@ SLVideoDecoder::submitDecodeUnit(PDECODE_UNIT du) return DR_OK; } +void SLVideoDecoder::notifyOverlayUpdated(Overlay::OverlayType type) +{ + // SLVideo supports only one visible overlay at a time. Since we don't have + // stats like the FFmpeg-based decoders, we'll just support the status update + // overlay and nothing else. + if (type != Overlay::OverlayStatusUpdate) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, + "Unsupported overlay type: %d", type); + return; + } + + SDL_Surface* newSurface = Session::get()->getOverlayManager().getUpdatedOverlaySurface(type); + if (newSurface == nullptr && Session::get()->getOverlayManager().isOverlayEnabled(type)) { + // There's no updated surface and the overlay is enabled, so just leave the old surface alone. + return; + } + + // Hide and free any existing overlay + if (m_Overlay != nullptr) { + SLVideo_HideOverlay(m_Overlay); + SLVideo_FreeOverlay(m_Overlay); + m_Overlay = nullptr; + } + + if (!Session::get()->getOverlayManager().isOverlayEnabled(type)) { + SDL_FreeSurface(newSurface); + return; + } + + m_Overlay = SLVideo_CreateOverlay(m_VideoContext, newSurface->w, newSurface->h); + if (m_Overlay == nullptr) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, + "SLVideo_CreateOverlay() failed"); + return; + } + + uint32_t* pixels; + int pitch; + SLVideo_GetOverlayPixels(m_Overlay, &pixels, &pitch); + + // Copy surface pixels into the new overlay + SDL_ConvertPixels(newSurface->w, newSurface->h, newSurface->format->format, newSurface->pixels, newSurface->pitch, + SDL_PIXELFORMAT_ARGB8888, pixels, pitch); + + // We're done with the surface now + SDL_FreeSurface(newSurface); + + // Position the status overlay at the bottom left corner + float flWidth = (float)newSurface->w / m_ViewportWidth; + float flHeight = (float)newSurface->h / m_ViewportHeight; + SLVideo_SetOverlayDisplayArea(m_Overlay, 0.0f, 1.0f - flHeight, flWidth, flHeight); + + // Show the overlay + SLVideo_ShowOverlay(m_Overlay); +} + void SLVideoDecoder::slLogCallback(void*, ESLVideoLog logLevel, const char *message) { SDL_LogPriority priority; diff --git a/app/streaming/video/slvid.h b/app/streaming/video/slvid.h index 9651e941..acf226ae 100644 --- a/app/streaming/video/slvid.h +++ b/app/streaming/video/slvid.h @@ -1,10 +1,11 @@ #pragma once #include "decoder.h" +#include "overlaymanager.h" #include -class SLVideoDecoder : public IVideoDecoder +class SLVideoDecoder : public IVideoDecoder, public Overlay::IOverlayRenderer { public: SLVideoDecoder(bool testOnly); @@ -16,6 +17,7 @@ public: virtual int getDecoderColorspace() override; virtual QSize getDecoderMaxResolution() override; virtual int submitDecodeUnit(PDECODE_UNIT du) override; + virtual void notifyOverlayUpdated(Overlay::OverlayType) override; // Unused since rendering is done directly from the decode thread virtual void renderFrameOnMainThread() override {} @@ -31,4 +33,8 @@ private: CSLVideoContext* m_VideoContext; CSLVideoStream* m_VideoStream; + CSLVideoOverlay* m_Overlay; + + int m_ViewportWidth; + int m_ViewportHeight; };