Skip to content

5.23.10 - Software decoder drain + prefetcher time base

Choose a tag to compare

@superuser404notfound superuser404notfound released this 27 Jul 11:31

Patch release. Two defects on the software decode path, both found by rrgomes while reading it for #220.

Fixed

A software-decoded title could stop its picture for good and never recover without a seek.

avcodec_send_packet returning AVERROR(EAGAIN) is not a decode error. It means the packet was not consumed, because the decoder's output queue is full and has to be drained before more input is accepted, and that is legal at any point under frame threading. SoftwareVideoDecoder runs with thread_count at the core count and FF_THREAD_FRAME | FF_THREAD_SLICE, so it happens.

It was handled as any other negative result: return before the receive loop. That dropped the packet and left the queue full, so every subsequent send hit the same wall. Video stopped permanently while audio kept playing, until a seek flushed the decoder.

The send now classifies its result. EAGAIN drains the receive loop and resends the same packet, a genuine error drops the packet and logs once per decoder, and the drain runs in either case since a dropped packet does not invalidate frames the decoder already holds.

One failed time-base lookup disarmed the subtitle prefetcher's forward park for the whole session.

The #151 forward prefetcher memoized its own failure. A stream lookup that returned nothing fell back to AVRational(0, 1), that value went into the per-session cache, and the park guard (tb.num > 0) then skipped every subsequent packet on the stream. The side reader ran the rest of the session with no forward park at all, pulling from the origin far ahead of the playhead on a second connection that shares bandwidth with the pump.

The same value also reached SubtitlePacketStore.harvest, where the harvest rate is num/den: at zero, every cue the prefetcher harvested lands at second 0.

Only usable time bases are cached now. An unusable one drops that single packet and retries on the next, and logs once per session.

Notes

Both fixes are covered by tests (Issue220SoftwareDecoderDrainTests, Issue220PrefetchTimeBaseTests). Neither closes #220 itself, which is still open on the memory side.