fix(encode): trimmed multi-wave ladders die on an empty filter graph - #236
Merged
Conversation
… wave Audio rides with the first wave of a split ladder, so later waves have no audio groups — they map no audio and name none in var_stream_map. The trim filter graph was built and pushed anyway, and from no groups it came out empty, which ffmpeg refuses: [AVFilterGraph] No filters specified in the graph description FFmpeg exited with code 234 So every trimmed encode of more than MAX_HARDWARE_SESSIONS re-encoded rungs failed on its second wave. The graph exists to feed `-map [aoutN]`; a wave that maps no audio has no consumer for it, so none is emitted. The video graph keeps its own select=concatdec_select per wave, so the trim stays sample-accurate.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A trimmed encode of more than three re-encoded rungs fails every time, on its second wave, with:
Why
buildVideoArgsempties the audio groups for every wave after the first — audio rides with wave 1, by design:Everything downstream already respects that. The
-map [aoutN]loop doesn't run, no audio codec options are emitted, and-var_stream_mapgets noa:Nentries —buildVideoArgseven carries a comment explaining that a wave without audio names anagroupthat isn't in the run, and that the merge restores theAUDIOattribute afterwards.The one thing that didn't respect it was the trim filter graph, which was pushed whenever
trimmingwas set. Built from no groups it came out as the empty string, and ffmpeg refuses an empty graph.Why dropping the argument is the fix
The graph exists solely to produce
[aoutN]labels for-map [aoutN]to consume. A wave without audio maps none, so there is no consumer: an empty graph is a parse error, and a populated one would be worse — a-filter_complexoutput that nothing maps is itself an ffmpeg error. The argument is meaningless without the maps it feeds, so the correct amount of it is none.The video side is untouched: each wave's own
select=concatdec_selectstill rides in the video graph, so wave 2's video is cut sample-accurately exactly as before. Audio keeps being written once, by wave 1.The same guard is applied in
buildAudioArgs, where it is unreachable today — the controller requires at least one audio group for an audio job, and audio jobs do not run in waves — but the code is identical and shouldn't rely on a guarantee made in another file.Reproduced
Two real sessions from the same machine, differing in one field:
Both split into two waves (
MAX_HARDWARE_SESSIONS = 3), both have four audio groups. Only the trimmed one hits the empty graph.Why the suite missed it
ladder-waves.spec.tscoversincludeAudio,ffmpeg.service.spec.tscoverstrimSegments, and nothing covered them together — which is the only combination that breaks. The new tests drive the realplanLadderWavesoutput rather than a hand-written wave, and assert on the wave the planner actually produces: no empty argv entry, one filter graph rather than two, no[aoutlabels — plus one test holding the first wave unchanged, so the guard can't quietly swallow the audio graph everywhere.