fix(session): keyframe recovery when the decoder produces no output
Under infinite GOP the pump only re-requested an IDR when the reassembler's drop count climbed. A lost initial IDR (or a mid-GOP join) delivers complete-but-undecodable delta frames instead — the reassembler never drops, so recovery never fired and the stream froze on the last good frame while libavcodec flooded stderr with missing-reference errors. Reproduced at 4K@144 (large IDRs, higher loss); lower modes hid it. Now a 3-frame no-output streak (~50 ms) forces a fresh IDR, throttled and re-armed across the request→IDR round trip. Verified on glass: 4K@144 recovers and holds. Also quiets libavcodec's raw stderr (it bypassed tracing) to fatal-only, PUNKTFUNK_FFMPEG_LOG restores it. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -175,6 +175,25 @@ pub fn decodable_codecs() -> u8 {
|
||||
bits
|
||||
}
|
||||
|
||||
/// libavcodec logs reference-frame recovery to the process stderr very verbosely
|
||||
/// (`First slice in a frame missing`, `Could not find ref with POC …`, `Error
|
||||
/// constructing the frame RPS`) — normal chatter while the decoder waits for a keyframe
|
||||
/// after loss, but a raw flood in the user's terminal (it bypasses our tracing). Default
|
||||
/// it to fatal-only; `PUNKTFUNK_FFMPEG_LOG=<quiet|error|warning|info|debug>` restores it
|
||||
/// for decode debugging. Process-global; set once per decoder build (idempotent).
|
||||
fn quiet_ffmpeg_log() {
|
||||
use ffmpeg::util::log::Level;
|
||||
let level = match std::env::var("PUNKTFUNK_FFMPEG_LOG").ok().as_deref() {
|
||||
Some("quiet") => Level::Quiet,
|
||||
Some("error") => Level::Error,
|
||||
Some("warning") => Level::Warning,
|
||||
Some("info") => Level::Info,
|
||||
Some("debug" | "trace") => Level::Debug,
|
||||
_ => Level::Fatal,
|
||||
};
|
||||
ffmpeg::util::log::set_level(level);
|
||||
}
|
||||
|
||||
impl Decoder {
|
||||
/// `codec_id` is the codec the host resolved in the Welcome (never assume HEVC).
|
||||
/// `pref` is the Settings "Video decoder" value (`auto`/`vaapi`/`software`).
|
||||
@@ -183,6 +202,7 @@ impl Decoder {
|
||||
/// (VAAPI → software).
|
||||
pub fn new(codec_id: ffmpeg::codec::Id, pref: &str) -> Result<Decoder> {
|
||||
ffmpeg::init().context("ffmpeg init")?;
|
||||
quiet_ffmpeg_log();
|
||||
let choice = std::env::var("PUNKTFUNK_DECODER")
|
||||
.ok()
|
||||
.filter(|v| !v.is_empty())
|
||||
|
||||
Reference in New Issue
Block a user