diff --git a/app/streaming/video/ffmpeg-renderers/renderer.h b/app/streaming/video/ffmpeg-renderers/renderer.h index 2c13e678..650fcb2e 100644 --- a/app/streaming/video/ffmpeg-renderers/renderer.h +++ b/app/streaming/video/ffmpeg-renderers/renderer.h @@ -62,6 +62,11 @@ public: } } + virtual bool isPixelFormatSupported(int videoFormat, enum AVPixelFormat pixelFormat) { + // By default, we only support the preferred pixel format + return getPreferredPixelFormat(videoFormat) == pixelFormat; + } + // IOverlayRenderer virtual void notifyOverlayUpdated(Overlay::OverlayType) override { // Nothing diff --git a/app/streaming/video/ffmpeg-renderers/sdlvid.cpp b/app/streaming/video/ffmpeg-renderers/sdlvid.cpp index a9cd0901..2c39a5b4 100644 --- a/app/streaming/video/ffmpeg-renderers/sdlvid.cpp +++ b/app/streaming/video/ffmpeg-renderers/sdlvid.cpp @@ -127,6 +127,21 @@ bool SdlRenderer::isRenderThreadSupported() return true; } +bool SdlRenderer::isPixelFormatSupported(int, AVPixelFormat pixelFormat) +{ + // Remember to keep this in sync with SdlRenderer::renderFrame()! + switch (pixelFormat) + { + case AV_PIX_FMT_YUV420P: + case AV_PIX_FMT_NV12: + case AV_PIX_FMT_NV21: + return true; + + default: + return false; + } +} + bool SdlRenderer::initialize(PDECODER_PARAMETERS params) { Uint32 rendererFlags = SDL_RENDERER_ACCELERATED; @@ -271,6 +286,7 @@ void SdlRenderer::renderFrame(AVFrame* frame) if (m_Texture == nullptr) { Uint32 sdlFormat; + // Remember to keep this in sync with SdlRenderer::isPixelFormatSupported()! switch (frame->format) { case AV_PIX_FMT_YUV420P: diff --git a/app/streaming/video/ffmpeg-renderers/sdlvid.h b/app/streaming/video/ffmpeg-renderers/sdlvid.h index 5c7b2e7f..e0eefd4b 100644 --- a/app/streaming/video/ffmpeg-renderers/sdlvid.h +++ b/app/streaming/video/ffmpeg-renderers/sdlvid.h @@ -13,6 +13,7 @@ public: virtual void renderFrame(AVFrame* frame) override; virtual void notifyOverlayUpdated(Overlay::OverlayType) override; virtual bool isRenderThreadSupported() override; + virtual bool isPixelFormatSupported(int videoFormat, enum AVPixelFormat pixelFormat) override; private: void renderOverlay(Overlay::OverlayType type); diff --git a/app/streaming/video/ffmpeg.cpp b/app/streaming/video/ffmpeg.cpp index be65908d..6ffc8ebc 100644 --- a/app/streaming/video/ffmpeg.cpp +++ b/app/streaming/video/ffmpeg.cpp @@ -73,7 +73,7 @@ enum AVPixelFormat FFmpegVideoDecoder::ffGetFormat(AVCodecContext* context, const enum AVPixelFormat *p; for (p = pixFmts; *p != -1; p++) { - // Only match our hardware decoding codec or SW pixel + // Only match our hardware decoding codec or preferred SW pixel // format (if not using hardware decoding). It's crucial // to override the default get_format() which will try // to gracefully fall back to software decode and break us. @@ -84,6 +84,15 @@ enum AVPixelFormat FFmpegVideoDecoder::ffGetFormat(AVCodecContext* context, } } + // Failed to match the preferred pixel formats. Try non-preferred options for non-hwaccel decoders. + if (decoder->m_HwDecodeCfg == nullptr) { + for (p = pixFmts; *p != -1; p++) { + if (decoder->m_FrontendRenderer->isPixelFormatSupported(decoder->m_VideoFormat, *p)) { + return *p; + } + } + } + return AV_PIX_FMT_NONE; } @@ -97,6 +106,7 @@ FFmpegVideoDecoder::FFmpegVideoDecoder(bool testOnly) m_Pacer(nullptr), m_LastFrameNumber(0), m_StreamFps(0), + m_VideoFormat(0), m_NeedsSpsFixup(false), m_TestOnly(testOnly) { @@ -206,6 +216,7 @@ bool FFmpegVideoDecoder::completeInitialization(AVCodec* decoder, PDECODER_PARAM } m_StreamFps = params->frameRate; + m_VideoFormat = params->videoFormat; // Don't bother initializing Pacer if we're not actually going to render if (!testFrame) { diff --git a/app/streaming/video/ffmpeg.h b/app/streaming/video/ffmpeg.h index 655ff25c..3e186e12 100644 --- a/app/streaming/video/ffmpeg.h +++ b/app/streaming/video/ffmpeg.h @@ -63,6 +63,7 @@ private: int m_LastFrameNumber; int m_StreamFps; + int m_VideoFormat; bool m_NeedsSpsFixup; bool m_TestOnly;