Reuse the test decoder to improve startup performance

This commit is contained in:
Cameron Gutman 2025-12-23 00:32:36 -06:00
commit a6f8901a18
3 changed files with 61 additions and 23 deletions

View file

@ -190,6 +190,9 @@ public:
// If the renderer doesn't provide an explicit test routine,
// we will always assume that any returned AVFrame can be
// rendered successfully.
//
// NB: The test frame passed to this callback may differ in
// dimensions from the actual video stream.
return true;
}

View file

@ -473,7 +473,7 @@ bool FFmpegVideoDecoder::completeInitialization(const AVCodec* decoder, enum AVP
m_VideoFormat = params->videoFormat;
// Don't bother initializing Pacer if we're not actually going to render
if (!testFrame) {
if (!m_TestOnly) {
m_Pacer = new Pacer(m_FrontendRenderer, &m_ActiveWndVideoStats);
if (!m_Pacer->initialize(params->window, params->frameRate,
params->enableFramePacing || (params->enableVsync && (m_FrontendRenderer->getRendererAttributes() & RENDERER_ATTRIBUTE_FORCE_PACING)))) {
@ -662,8 +662,12 @@ bool FFmpegVideoDecoder::completeInitialization(const AVCodec* decoder, enum AVP
}
av_frame_free(&frame);
// Flush the codec to prepare for the real stream
avcodec_flush_buffers(m_VideoDecoderCtx);
}
else {
if (!m_TestOnly) {
if ((params->videoFormat & VIDEO_FORMAT_MASK_H264) &&
!(m_BackendRenderer->getDecoderCapabilities() & CAPABILITY_REFERENCE_FRAME_INVALIDATION_AVC)) {
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
@ -1065,6 +1069,26 @@ IFFmpegRenderer* FFmpegVideoDecoder::createHwAccelRenderer(const AVCodecHWConfig
}
}
bool FFmpegVideoDecoder::isSeparateTestDecoderRequired(const AVCodec* decoder)
{
// We can generally reuse the test decoder for real rendering as long as
// the decoder can handle a change in surface sizes while streaming.
// We know v4l2m2m can't handle this (see comment below), so let's just
// opt-out all non-hwaccel decoders just to be safe.
if (qEnvironmentVariableIntValue("SEPARATE_TEST_DECODER")) {
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
"Using separate test decoder due to environment variable");
return true;
}
else if (getAVCodecCapabilities(decoder) & AV_CODEC_CAP_HARDWARE) {
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
"Using separate test decoder for non-hwaccel decoder");
return true;
}
return false;
}
bool FFmpegVideoDecoder::tryInitializeRenderer(const AVCodec* decoder,
enum AVPixelFormat requiredFormat,
PDECODER_PARAMETERS params,
@ -1073,7 +1097,9 @@ bool FFmpegVideoDecoder::tryInitializeRenderer(const AVCodec* decoder,
std::function<IFFmpegRenderer*()> createRendererFunc)
{
DECODER_PARAMETERS testFrameDecoderParams = *params;
bool separateTestDecoder = isSeparateTestDecoderRequired(decoder);
if (separateTestDecoder) {
// Setup the test decoder parameters using the dimensions for the test frame. These are
// used to populate the AVCodecContext fields of the same names.
//
@ -1084,6 +1110,7 @@ bool FFmpegVideoDecoder::tryInitializeRenderer(const AVCodec* decoder,
// For wave5 (VisionFive), it leads to an invalid pitch error when calling drmModeAddFB2().
testFrameDecoderParams.width = 1280;
testFrameDecoderParams.height = 720;
}
m_HwDecodeCfg = hwConfig;
@ -1116,6 +1143,7 @@ bool FFmpegVideoDecoder::tryInitializeRenderer(const AVCodec* decoder,
return true;
}
if (separateTestDecoder) {
// The test worked, so now let's initialize it for real
reset();
@ -1133,6 +1161,11 @@ bool FFmpegVideoDecoder::tryInitializeRenderer(const AVCodec* decoder,
"Decoder failed to initialize after successful test");
}
}
else {
// The test decoder can be used for real decoding
return true;
}
}
}
else {
// If we failed to initialize the backend entirely, there's no sense in trying

View file

@ -79,6 +79,8 @@ private:
bool initializeRendererInternal(IFFmpegRenderer* renderer, PDECODER_PARAMETERS params);
static bool isSeparateTestDecoderRequired(const AVCodec* decoder);
void reset();
void writeBuffer(PLENTRY entry, int& offset);