fix: allow for the codec's delay in the decoder_queue limit

Decode() flushes the codec once decoder_queue holds more than 2 x the
keyframe interval while the codec still wants input (#5363). The codec
legitimately holds frames back before returning one: has_b_frames for
reordering, and one per extra thread with frame threading. For an
all-intra stream (keyframe interval 1, so a limit of 2) decoded with a
raised thread_count that delay alone passes the limit, and the codec was
flushed every few frames with a Warning each time.

Add the delay to the limit in DecoderQueueLimit().

refs #5362

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Isaac ConnorandClaude Opus 5.5 committed 2026-10-31 11:14:10 -04:00
1 parent 27411776c8
commit 08673d0629
3 files changed
+44 -1

No files matched your search

+26
View File
@@ -34,6 +34,7 @@ void EnsureConfig() {
class DecoderQueue : public Monitor {
public:
DecoderQueue() : Monitor() {}
using Monitor::DecoderQueueLimit;
// Packets sent to the codec, in decode order, by pts.
std::vector<std::shared_ptr<ZMPacket>> Send(const std::vector<int64_t> &pts) {
@@ -135,3 +136,28 @@ TEST_CASE("Monitor decoder queue: without a pts the oldest entry is used", "[Mon
CHECK(q.Receive(99999) == 3600);
CHECK(q.Queued().empty());
}
TEST_CASE("Monitor decoder queue: the limit allows for the codec's own delay", "[Monitor][decoder]") {
CHECK(DecoderQueue::DecoderQueueLimit(25, nullptr) == 50);
AVCodecContext *context = avcodec_alloc_context3(nullptr);
REQUIRE(context);
CHECK(DecoderQueue::DecoderQueueLimit(25, context) == 50);
context->has_b_frames = 2;
CHECK(DecoderQueue::DecoderQueueLimit(25, context) == 52);
// All-intra stream (keyframe interval 1) decoded with 8 frame threads: the
// codec holds 7 frames before returning one, more than 2 x 1.
context->has_b_frames = 0;
context->thread_count = 8;
context->active_thread_type = FF_THREAD_FRAME;
CHECK(DecoderQueue::DecoderQueueLimit(1, context) == 9);
// Slice threads add no delay
context->active_thread_type = FF_THREAD_SLICE;
CHECK(DecoderQueue::DecoderQueueLimit(1, context) == 2);
avcodec_free_context(&context);
}