Advanced: editable FFmpeg arguments box — show the composed command, allow override, reset to default #736

Open
opened 2026-08-04 22:42:49 +02:00 by timothy · 0 comments
Owner

Requested during #726. Complements #735 (bounded, validated fields for the known tunables); this is the escape hatch for everything we can't reasonably anticipate.

Requested design

  • An FFmpeg arguments box, clearly labelled Advanced and hidden behind an advanced-settings toggle/disclosure — not visible in the normal flow.
  • It shows the currently composed arguments derived from the selected profile options + defaults, so it doubles as a "what is this profile actually doing" view.
  • The user may edit it at will.
  • A reset button nearby to restore the composed default when experimenting goes wrong.

Rationale: useful for debugging (during #726 the only way to try a different pacing value was to rebuild the app and replay command lines by hand on the Docker host), and beyond debugging, for people with specific requirements we couldn't reasonably account for.

The hard part — the composed command is per-ITEM, not static

This is the constraint that shapes the whole feature, so it belongs at the top rather than being discovered in implementation. A real captured production command:

... -ss 00:04:05.3602444 -readrate 1.05 -readrate_initial_burst 8 -i "/data/tvshows/.../S10E02.mkv"
    ... -filter_complex [1:1]aresample=async=1,apad[a];[0:0]setpts=PTS-STARTPTS,fps=23.97603[v];...
    ... -t 00:30:33.4197556 -output_ts_offset 44.0319999s ... /transcode/107/live.m3u8

The seek, input path, duration, -output_ts_offset, the subtitle stream index, and the entire -filter_complex are regenerated for every playout item. So a saved edited string would be frozen against one episode and wrong for the next — and wrong in ways that fail at transcode time, on a live channel.

Approaches worth weighing (pick during design, don't assume):

  1. Structured overrides — the user edits/adds/removes specific option groups, applied to each regenerated command. Survives regeneration; least expressive.
  2. Template with placeholders — show the composed command with {input}, {seek}, {filter_complex} tokens the user must preserve. Expressive; fragile, and breaks silently if a token is deleted.
  3. Session-scoped override for troubleshooting only — an override attached to a troubleshooting-playback run rather than persisted on the profile. Exactly fits the debugging use case, does not fit the "specific ongoing requirements" use case.
  4. Rewrite rules — ordered add/replace/remove operations applied post-composition.

(1) or (4) look most survivable; (3) may be worth shipping first as a smaller, safer slice.

Safety posture — state it explicitly in the UI

An overridden command means the app can no longer guarantee what it normally guarantees:

  • the capability gate (e.g. -readrate_catchup is only emitted when the binary supports it — a hand-written arg is not checked)
  • the ffmpeg.qsv-extra-hw-frames-floor guard (#529: too small a QSV surface pool produces zero segments, not degraded quality)
  • live pacing itself (#726: a bad readrate stalls every client on the channel)

So this is an explicit "you are on your own" mode. The reset button is the safety valve and should be impossible to miss. Consider also surfacing "this profile has a custom argument override" somewhere persistent, so a channel that mysteriously stops working doesn't take an hour to trace back to a forgotten edit.

Out of scope

Not a replacement for #735 — known-dangerous knobs should still become bounded, validated, explained fields. This box is for the long tail, not the head.

Done-when

  • Design decision recorded for how an override survives per-item regeneration (approach chosen + why)
  • Advanced-gated, non-default-visible UI showing the composed arguments
  • Edit + reset-to-default, with reset discoverable
  • Override state visible somewhere persistent (so a stale edit is diagnosable)
  • Explicit in-UI statement that overrides bypass capability gating and the #529 floor
  • Adversarial review passed
  • Docs updated (or explicitly none required, with reason)
Requested during #726. Complements #735 (bounded, validated fields for the *known* tunables); this is the escape hatch for everything we can't reasonably anticipate. ## Requested design - An FFmpeg arguments box, **clearly labelled Advanced** and hidden behind an advanced-settings toggle/disclosure — not visible in the normal flow. - It **shows the currently composed arguments** derived from the selected profile options + defaults, so it doubles as a "what is this profile actually doing" view. - The user may **edit it at will**. - A **reset button** nearby to restore the composed default when experimenting goes wrong. Rationale: useful for debugging (during #726 the only way to try a different pacing value was to rebuild the app and replay command lines by hand on the Docker host), and beyond debugging, for people with specific requirements we couldn't reasonably account for. ## The hard part — the composed command is per-ITEM, not static This is the constraint that shapes the whole feature, so it belongs at the top rather than being discovered in implementation. A real captured production command: ``` ... -ss 00:04:05.3602444 -readrate 1.05 -readrate_initial_burst 8 -i "/data/tvshows/.../S10E02.mkv" ... -filter_complex [1:1]aresample=async=1,apad[a];[0:0]setpts=PTS-STARTPTS,fps=23.97603[v];... ... -t 00:30:33.4197556 -output_ts_offset 44.0319999s ... /transcode/107/live.m3u8 ``` The seek, input path, duration, `-output_ts_offset`, the subtitle stream index, and the entire `-filter_complex` are **regenerated for every playout item**. So a saved edited string would be frozen against one episode and wrong for the next — and wrong in ways that fail at transcode time, on a live channel. Approaches worth weighing (pick during design, don't assume): 1. **Structured overrides** — the user edits/adds/removes specific option groups, applied to each regenerated command. Survives regeneration; least expressive. 2. **Template with placeholders** — show the composed command with `{input}`, `{seek}`, `{filter_complex}` tokens the user must preserve. Expressive; fragile, and breaks silently if a token is deleted. 3. **Session-scoped override for troubleshooting only** — an override attached to a troubleshooting-playback run rather than persisted on the profile. Exactly fits the debugging use case, does **not** fit the "specific ongoing requirements" use case. 4. **Rewrite rules** — ordered add/replace/remove operations applied post-composition. (1) or (4) look most survivable; (3) may be worth shipping first as a smaller, safer slice. ## Safety posture — state it explicitly in the UI An overridden command means the app can no longer guarantee what it normally guarantees: - the **capability gate** (e.g. `-readrate_catchup` is only emitted when the binary supports it — a hand-written arg is not checked) - the **`ffmpeg.qsv-extra-hw-frames-floor` guard** (#529: too small a QSV surface pool produces **zero segments**, not degraded quality) - live pacing itself (#726: a bad readrate stalls every client on the channel) So this is an explicit "you are on your own" mode. The reset button is the safety valve and should be impossible to miss. Consider also surfacing "this profile has a custom argument override" somewhere persistent, so a channel that mysteriously stops working doesn't take an hour to trace back to a forgotten edit. ## Out of scope Not a replacement for #735 — known-dangerous knobs should still become bounded, validated, explained fields. This box is for the long tail, not the head. ## Done-when - [ ] Design decision recorded for how an override survives per-item regeneration (approach chosen + why) - [ ] Advanced-gated, non-default-visible UI showing the composed arguments - [ ] Edit + reset-to-default, with reset discoverable - [ ] Override state visible somewhere persistent (so a stale edit is diagnosable) - [ ] Explicit in-UI statement that overrides bypass capability gating and the #529 floor - [ ] Adversarial review passed - [ ] Docs updated (or explicitly none required, with reason)
timothy added the enhancementpriority: lowfrontend labels 2026-08-04 22:42:49 +02:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: timothy/ersatztv#736