diff --git a/app/streaming/video/ffmpeg.cpp b/app/streaming/video/ffmpeg.cpp index 77ae925a..4c1fe9d6 100644 --- a/app/streaming/video/ffmpeg.cpp +++ b/app/streaming/video/ffmpeg.cpp @@ -177,8 +177,9 @@ 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) { + // Failed to match the preferred pixel formats. Try non-preferred pixel format options + // for non-hwaccel decoders if we didn't have a required pixel format to use. + if (decoder->m_HwDecodeCfg == nullptr && decoder->m_RequiredPixelFormat == AV_PIX_FMT_NONE) { for (p = pixFmts; *p != -1; p++) { if (decoder->m_FrontendRenderer->isPixelFormatSupported(decoder->m_VideoFormat, *p) && decoder->m_BackendRenderer->prepareDecoderContextInGetFormat(context, *p)) { @@ -193,6 +194,7 @@ enum AVPixelFormat FFmpegVideoDecoder::ffGetFormat(AVCodecContext* context, FFmpegVideoDecoder::FFmpegVideoDecoder(bool testOnly) : m_Pkt(av_packet_alloc()), m_VideoDecoderCtx(nullptr), + m_RequiredPixelFormat(AV_PIX_FMT_NONE), m_DecodeBuffer(1024 * 1024, 0), m_HwDecodeCfg(nullptr), m_BackendRenderer(nullptr), @@ -356,7 +358,7 @@ bool FFmpegVideoDecoder::createFrontendRenderer(PDECODER_PARAMETERS params, bool return true; } -bool FFmpegVideoDecoder::completeInitialization(const AVCodec* decoder, PDECODER_PARAMETERS params, bool testFrame, bool useAlternateFrontend) +bool FFmpegVideoDecoder::completeInitialization(const AVCodec* decoder, enum AVPixelFormat requiredFormat, PDECODER_PARAMETERS params, bool testFrame, bool useAlternateFrontend) { // In test-only mode, we should only see test frames SDL_assert(!m_TestOnly || testFrame); @@ -366,6 +368,7 @@ bool FFmpegVideoDecoder::completeInitialization(const AVCodec* decoder, PDECODER return false; } + m_RequiredPixelFormat = requiredFormat; m_StreamFps = params->frameRate; m_VideoFormat = params->videoFormat; @@ -414,7 +417,7 @@ bool FFmpegVideoDecoder::completeInitialization(const AVCodec* decoder, PDECODER // Setup decoding parameters m_VideoDecoderCtx->width = params->width; m_VideoDecoderCtx->height = params->height; - m_VideoDecoderCtx->pix_fmt = m_FrontendRenderer->getPreferredPixelFormat(params->videoFormat); + m_VideoDecoderCtx->pix_fmt = requiredFormat != AV_PIX_FMT_NONE ? requiredFormat : m_FrontendRenderer->getPreferredPixelFormat(params->videoFormat); m_VideoDecoderCtx->get_format = ffGetFormat; AVDictionary* options = nullptr; @@ -821,6 +824,7 @@ IFFmpegRenderer* FFmpegVideoDecoder::createHwAccelRenderer(const AVCodecHWConfig } bool FFmpegVideoDecoder::tryInitializeRenderer(const AVCodec* decoder, + enum AVPixelFormat requiredFormat, PDECODER_PARAMETERS params, const AVCodecHWConfig* hwConfig, std::function createRendererFunc) @@ -850,7 +854,10 @@ bool FFmpegVideoDecoder::tryInitializeRenderer(const AVCodec* decoder, SDL_assert(m_BackendRenderer == nullptr); if ((m_BackendRenderer = createRendererFunc()) != nullptr && m_BackendRenderer->initialize((m_TestOnly || m_BackendRenderer->needsTestFrame()) ? &testFrameDecoderParams : params) && - completeInitialization(decoder, (m_TestOnly || m_BackendRenderer->needsTestFrame()) ? &testFrameDecoderParams : params, m_TestOnly || m_BackendRenderer->needsTestFrame(), i == 0 /* EGL/DRM */)) { + completeInitialization(decoder, requiredFormat, + (m_TestOnly || m_BackendRenderer->needsTestFrame()) ? &testFrameDecoderParams : params, + m_TestOnly || m_BackendRenderer->needsTestFrame(), + i == 0 /* EGL/DRM */)) { if (m_TestOnly) { // This decoder is only for testing capabilities, so don't bother // creating a usable renderer @@ -862,7 +869,7 @@ bool FFmpegVideoDecoder::tryInitializeRenderer(const AVCodec* decoder, reset(); if ((m_BackendRenderer = createRendererFunc()) != nullptr && m_BackendRenderer->initialize(params) && - completeInitialization(decoder, params, false, i == 0 /* EGL/DRM */)) { + completeInitialization(decoder, requiredFormat, params, false, i == 0 /* EGL/DRM */)) { return true; } else { @@ -891,7 +898,10 @@ bool FFmpegVideoDecoder::tryInitializeRenderer(const AVCodec* decoder, { \ RENDERER_TYPE renderer; \ if (renderer.getPreferredPixelFormat(params->videoFormat) == decoder->pix_fmts[i]) { \ - if (tryInitializeRenderer(decoder, params, nullptr, \ + SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, \ + "Trying " #RENDERER_TYPE " for codec %s due to preferred pixel format: 0x%x", \ + decoder->name, decoder->pix_fmts[i]); \ + if (tryInitializeRenderer(decoder, decoder->pix_fmts[i], params, nullptr, \ []() -> IFFmpegRenderer* { return new RENDERER_TYPE(); })) { \ SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, \ "Chose " #RENDERER_TYPE " for codec %s due to preferred pixel format: 0x%x", \ @@ -906,7 +916,10 @@ bool FFmpegVideoDecoder::tryInitializeRenderer(const AVCodec* decoder, RENDERER_TYPE renderer; \ if (decoder->pix_fmts[i] != renderer.getPreferredPixelFormat(params->videoFormat) && \ renderer.isPixelFormatSupported(params->videoFormat, decoder->pix_fmts[i])) { \ - if (tryInitializeRenderer(decoder, params, nullptr, \ + SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, \ + "Trying " #RENDERER_TYPE " for codec %s due to compatible pixel format: 0x%x", \ + decoder->name, decoder->pix_fmts[i]); \ + if (tryInitializeRenderer(decoder, decoder->pix_fmts[i], params, nullptr, \ []() -> IFFmpegRenderer* { return new RENDERER_TYPE(); })) { \ SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, \ "Chose " #RENDERER_TYPE " for codec %s due to compatible pixel format: 0x%x", \ @@ -945,7 +958,7 @@ bool FFmpegVideoDecoder::tryInitializeRendererForUnknownDecoder(const AVCodec* d } // Initialize the hardware codec and submit a test frame if the renderer needs it - if (tryInitializeRenderer(decoder, params, config, + if (tryInitializeRenderer(decoder, AV_PIX_FMT_NONE, params, config, [config]() -> IFFmpegRenderer* { return createHwAccelRenderer(config, 0); })) { return true; } @@ -956,13 +969,13 @@ bool FFmpegVideoDecoder::tryInitializeRendererForUnknownDecoder(const AVCodec* d // Supported output pixel formats are unknown. We'll just try DRM/SDL and hope it can cope. #if defined(HAVE_DRM) && defined(GL_IS_SLOW) - if (tryInitializeRenderer(decoder, params, nullptr, + if (tryInitializeRenderer(decoder, AV_PIX_FMT_NONE, params, nullptr, []() -> IFFmpegRenderer* { return new DrmRenderer(); })) { return true; } #endif - if (tryInitializeRenderer(decoder, params, nullptr, + if (tryInitializeRenderer(decoder, AV_PIX_FMT_NONE, params, nullptr, []() -> IFFmpegRenderer* { return new SdlRenderer(); })) { return true; } @@ -1018,6 +1031,10 @@ bool FFmpegVideoDecoder::tryInitializeRendererForUnknownDecoder(const AVCodec* d } #endif + SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, + "No renderer can handle output from decoder: %s", + decoder->name); + // If we made it here, we couldn't find anything return false; } @@ -1122,7 +1139,7 @@ bool FFmpegVideoDecoder::initialize(PDECODER_PARAMETERS params) } // Initialize the hardware codec and submit a test frame if the renderer needs it - if (tryInitializeRenderer(decoder, params, config, + if (tryInitializeRenderer(decoder, AV_PIX_FMT_NONE, params, config, [config]() -> IFFmpegRenderer* { return createHwAccelRenderer(config, 0); })) { return true; } @@ -1180,7 +1197,7 @@ bool FFmpegVideoDecoder::initialize(PDECODER_PARAMETERS params) } // Initialize the hardware codec and submit a test frame if the renderer needs it - if (tryInitializeRenderer(decoder, params, config, + if (tryInitializeRenderer(decoder, AV_PIX_FMT_NONE, params, config, [config]() -> IFFmpegRenderer* { return createHwAccelRenderer(config, 1); })) { return true; } diff --git a/app/streaming/video/ffmpeg.h b/app/streaming/video/ffmpeg.h index 03f5b281..2de89762 100644 --- a/app/streaming/video/ffmpeg.h +++ b/app/streaming/video/ffmpeg.h @@ -30,7 +30,11 @@ public: virtual IFFmpegRenderer* getBackendRenderer(); private: - bool completeInitialization(const AVCodec* decoder, PDECODER_PARAMETERS params, bool testFrame, bool useAlternateFrontend); + bool completeInitialization(const AVCodec* decoder, + enum AVPixelFormat requiredFormat, + PDECODER_PARAMETERS params, + bool testFrame, + bool useAlternateFrontend); void stringifyVideoStats(VIDEO_STATS& stats, char* output, int length); @@ -45,6 +49,7 @@ private: bool tryHwAccel); bool tryInitializeRenderer(const AVCodec* decoder, + enum AVPixelFormat requiredFormat, PDECODER_PARAMETERS params, const AVCodecHWConfig* hwConfig, std::function createRendererFunc); @@ -65,6 +70,7 @@ private: AVPacket* m_Pkt; AVCodecContext* m_VideoDecoderCtx; + enum AVPixelFormat m_RequiredPixelFormat; QByteArray m_DecodeBuffer; const AVCodecHWConfig* m_HwDecodeCfg; IFFmpegRenderer* m_BackendRenderer;