From c14ebb1ad7790674bffe8892524ebeb5d88f6d3c Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sun, 11 Jan 2026 14:18:22 -0600 Subject: [PATCH] Adjust buffer count for hwaccel and v4l2m2m decoders - For hwaccel decoders, don't depend on FFmpeg's 4 working surfaces. The decoders might need one or more of them internally. - For V4L2M2M decoders, adjust the buffer counts to match our needs and requirements regarding Pacer-held frames. --- app/streaming/video/ffmpeg.cpp | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/app/streaming/video/ffmpeg.cpp b/app/streaming/video/ffmpeg.cpp index 460f9170..478fbeeb 100644 --- a/app/streaming/video/ffmpeg.cpp +++ b/app/streaming/video/ffmpeg.cpp @@ -545,10 +545,7 @@ bool FFmpegVideoDecoder::completeInitialization(const AVCodec* decoder, enum AVP m_VideoDecoderCtx->pkt_timebase.den = 90000; // Allocate enough extra frames for Pacer to avoid stalling the decoder - // - // NB: Subtract 4 because FFmpeg always allocates 4 working surfaces when - // constructing a hwframes context (see ff_decode_get_hw_frames_ctx()). - m_VideoDecoderCtx->extra_hw_frames = std::max(0, PACER_MAX_OUTSTANDING_FRAMES - 4); + m_VideoDecoderCtx->extra_hw_frames = PACER_MAX_OUTSTANDING_FRAMES; // For non-hwaccel decoders, set the pix_fmt to hint to the decoder which // format should be used. This is necessary for certain decoders like the @@ -568,6 +565,23 @@ bool FFmpegVideoDecoder::completeInitialization(const AVCodec* decoder, enum AVP return false; } + // The V4L2M2M decoders are one of the rare non-hwaccel decoders that allocates + // hardware frames under the hood. We need to adjust the number of buffers it + // allocates to ensure it allocates enough for our use case, but not too many. + // Normal hwaccel decoders will examine the codec/bitstream and the value we + // set in extra_hw_frames to determine how many buffers are required. + if (QString::fromUtf8(decoder->name).endsWith("_v4l2m2m", Qt::CaseInsensitive)) { + // 2 buffers for incoming compressed video data + av_dict_set_int(&options, "num_output_buffers", 2, 0); + + // 4 ref frames + what pacer holds + a working surface for each output + // + // NB: The reason we allocate 4 ref frames and not 16 (H.264 maximum) + // is because V4L2M2M decoders have reference frame invalidation disabled + // for compatibility, so we will never actually need 16 reference frames. + av_dict_set_int(&options, "num_capture_buffers", 4 + PACER_MAX_OUTSTANDING_FRAMES + 2, 0); + } + QString optionVarName = QString("%1_AVOPTIONS").arg(decoder->name).toUpper(); QByteArray optionVarValue = qgetenv(optionVarName.toUtf8()); if (!optionVarValue.isNull()) {