PR #23979 opened by cdcxd URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23979 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23979.patch
# Summary of changes Change the eb_receive_packet to drain available packet when possible, not only attempt after eb_send_frame Reason: The current implementation only attempts svt_av1_enc_get_packet after successful ff_encode_get_frame + eb_send_frame . Meaning we can only get 0 or 1 packet after sending a frame. The unharvested packet count will never decrease. It won't catch up burst output packets either. SVT-AV1 releases packets in mini-GOP sized bursts — measured at up to 39 at once with `640x360, lp=1:hierarchical-levels=5:lookahead=120`. So finished packets are withheld from the application until it supplies more input. Can't drain it asap. Changes: I changed it to always try svt_av1_enc_get_packet if possible. In the LOW_DELAY and rtc mode (available since v3.1.0), the function will block, so we can't attempt it. If EB_NoErrorEmptyQueue is returned, it fallthrough to the send frame as before. Otherwise it just returns the packet and wait for next avcodec_receive_packet call # Verification - ffmpeg cli, I built the patched one locally, asked coding agent to draft byte-identical comparison. It did pass, the script provenance is https://code.ffmpeg.org/cdcxd/FFmpeg/src/branch/libsvtav1-drain-first-provenance/verification_provenance/verify.sh <!-- If this PR requires new FATE test samples, attach them to the PR and list their target paths below (relative to the fate-suite root). Attached filenames must match the sample's filename: ```fate-samples # e.g. vorbis/new-sample.ogg ``` --> From 0f43599289701a7254a9846cc0b820a2caa84f50 Mon Sep 17 00:00:00 2001 From: cdong <[email protected]> Date: Sat, 1 Aug 2026 22:50:03 -0700 Subject: [PATCH] avcodec/libsvtav1 : make eb_receive_packet drain available packets before demanding new input --- libavcodec/libsvtav1.c | 51 +++++++++++++++++++++++++++++++++--------- 1 file changed, 41 insertions(+), 10 deletions(-) diff --git a/libavcodec/libsvtav1.c b/libavcodec/libsvtav1.c index 0bcc176243..3fe27c5b7e 100644 --- a/libavcodec/libsvtav1.c +++ b/libavcodec/libsvtav1.c @@ -653,22 +653,53 @@ static int eb_receive_packet(AVCodecContext *avctx, AVPacket *pkt) EbErrorType svt_ret; AVBufferRef *ref; int ret = 0; + int drain_packet_first, have_packet = 0; if (svt_enc->eos_flag == EOS_RECEIVED) return AVERROR_EOF; - ret = ff_encode_get_frame(avctx, frame); - if (ret < 0 && ret != AVERROR_EOF) - return ret; - if (ret == AVERROR_EOF) - frame = NULL; + /* Take any available packet, don't let them accumulate in output fifo. + * + * svt_av1_enc_get_packet() is documented in EbSvtAv1Enc.h to block when + * pic_send_done is set or when the library runs in low delay, so only poll + * ahead of sending when it is guaranteed not to. Low delay gained that + * behaviour in v2.3.0, testing for it on older versions is merely + * conservative. The library's copy_api_from_app() forces low delay for rtc + * without reflecting it in the configuration we hold, hence the separate + * check. + */ + drain_packet_first = svt_enc->eos_flag == EOS_NOT_REACHED && +#if SVT_AV1_CHECK_VERSION(4, 1, 0) + svt_enc->enc_params.pred_structure != LOW_DELAY +#else + /* LOW_DELAY is not exported before v4.1.0 */ + svt_enc->enc_params.pred_structure != 1 +#endif +#if SVT_AV1_CHECK_VERSION(3, 1, 0) + && !svt_enc->enc_params.rtc +#endif + ; - ret = eb_send_frame(avctx, frame); - if (ret < 0) - return ret; - av_frame_unref(svt_enc->frame); + if (drain_packet_first) { + svt_ret = svt_av1_enc_get_packet(svt_enc->svt_handle, &headerPtr, svt_enc->eos_flag); + have_packet = svt_ret != EB_NoErrorEmptyQueue; + } + + if (!have_packet) { + ret = ff_encode_get_frame(avctx, frame); + if (ret < 0 && ret != AVERROR_EOF) + return ret; + if (ret == AVERROR_EOF) + frame = NULL; + + ret = eb_send_frame(avctx, frame); + if (ret < 0) + return ret; + av_frame_unref(svt_enc->frame); + + svt_ret = svt_av1_enc_get_packet(svt_enc->svt_handle, &headerPtr, svt_enc->eos_flag); + } - svt_ret = svt_av1_enc_get_packet(svt_enc->svt_handle, &headerPtr, svt_enc->eos_flag); if (svt_ret == EB_NoErrorEmptyQueue) return AVERROR(EAGAIN); else if (svt_ret != EB_ErrorNone) -- 2.52.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
