Skip to content

4.2.0 — caller-bounded probe budget

Choose a tag to compare

@superuser404notfound superuser404notfound released this 26 Jun 03:02

Added

Caller-bounded demux probe budget per load() (#68)

A large remote remux with sparse streams (HDMV PGS subtitles, an mjpeg cover attachment) makes avformat_find_stream_info read to the full internal probe budget (50 MB / 60 s) on every open, costing roughly 13-14 s before the first frame over a slow CDN even though the video and audio streams resolve almost immediately. That budget is tuned for local disk, where reading 50 MB is free, and a remote caller had no way to cap it.

Two optional LoadOptions fields now let a caller cap the open-time probe, both defaulting to nil so nothing changes unless set:

public var probesize: Int64?           // bytes  -> AVFormatContext.probesize
public var maxAnalyzeDuration: Int64?  // micros -> AVFormatContext.max_analyze_duration

Example (a Jellyfin client that already knows the track layout from the server's MediaInfo, so it can afford a tighter probe):

try await engine.load(url: remoteRemuxURL, options: LoadOptions(
    httpHeaders: authHeaders,
    probesize: 4 * 1024 * 1024,        // 4 MB instead of 50 MB
    maxAnalyzeDuration: 5 * 1_000_000  // 5 s instead of 60 s
))

The cap is applied to every main-playback open that runs find_stream_info (the routing probe that becomes the session demuxer, the software and audio fallback opens, the audio/title-switch reopens so a switch does not re-incur the cost, and the native HLS fallback open and live reopen), and only to those. The subtitle side-demuxer, the routing probe(url:) API, the Dolby Vision probe, still extraction, and the live companion-audio demuxer all keep the full budget, because a complete probe is load-bearing there (sparse PGS / DVB track detection).

Notes on the trade-off, documented on the fields:

  • An over-tight budget fails open, not closed: find_stream_info still returns success with a logged warning, so a late-resolving track is silently missing rather than throwing a load error. Validate track presence after load if you set this aggressively.
  • maxAnalyzeDuration: 0 is not "no cap": FFmpeg maps it to a container-dependent heuristic (~5-7 s for MPEG-TS, longer elsewhere) that is shorter than the 60 s default. Pass a positive value for an explicit cap, or leave nil to keep the default.

Both fields default to nil, so existing callers are unaffected and the change is source-compatible.

Full changelog: https://github.com/superuser404notfound/AetherEngine/blob/main/CHANGELOG.md