Expand description
CLI-compat layer (cli feature): run or translate a strict, documented
subset of ffmpeg command lines in-process.
Two capabilities share one typed intermediate representation:
- Run:
from_cli_args/from_cliparse a command and build a ready-to-startFfmpegContexton the crate’s native pipeline. - Translate:
emit_rust_code_from_args/emit_rust_codeturn the same command into a complete, compile-ready builder program to copy into your codebase.
use ez_ffmpeg::cli::from_cli_args;
from_cli_args(&["-i", "in.mkv", "-c:v", "libx264", "-crf", "23",
"-preset", "fast", "-c:a", "aac", "-y", "out.mp4"])?
.start()?
.wait()?;The layer is optional; enable it in Cargo.toml:
[dependencies.ez-ffmpeg]
version = "*"
features = ["cli"]§The contract: classify everything, approximate nothing
Broad CLI compatibility is a non-goal. The ffmpeg CLI is ~14k lines of option machinery whose semantics move with every release; chasing it wholesale produces the “runs, but subtly different” failures that destroy trust. This layer does the opposite:
- every argv token must classify against the versioned compatibility
manifest, or the ENTIRE command is rejected with a token-anchored,
typed diagnostic (
CliError) — nothing is dropped or guessed; - commands whose exact shape is backed by a semantic golden test (stream identity, codecs, dimensions, durations, playlist topology compared against the real ffmpeg CLI) are verified: they may execute;
- commands that parse and match an ENUMERATED unverified manifest entry
are emit-only: the code generators label their output “unverified
scaffolding” and
from_cli_argsrefuses to run them; - commands that parse but match neither manifest table are rejected
outright (
CliError::UnmatchedShape) — run and emit alike; no silent scaffolding class exists; - execution additionally requires a verified runtime profile of the
linked FFmpeg (currently 7.1 only; 8.1 joins once its version-matched
golden lane passes) — anything else fails with the typed
CliError::UnverifiedRuntimeProfilebefore any I/O.
CLI-initiated pipelines also run with strict AVOption handling: an option
no component consumed fails the run (fftools check_avoptions parity)
instead of the default builder path’s warning.
§The manifest (generated; revision-pinned by an exact-equality test)
Manifest revision 4; dialect: ffmpeg 7.1 command line.
| option | scope | selector | repeat | notes | maps to |
|---|---|---|---|---|---|
-y | global | run | repeatable | flag | mandatory overwrite gate |
-hide_banner | global | no-op | repeatable | accepted, no in-process effect | none (documented no-op) |
-nostdin | global | no-op | repeatable | accepted, no in-process effect | none (documented no-op) |
-stats | global | no-op | repeatable | accepted, no in-process effect | none (documented no-op) |
-nostats | global | no-op | repeatable | accepted, no in-process effect | none (documented no-op) |
-loglevel | global | no-op | repeatable | no in-process effect; value: [repeat+][level+]LEVEL | none (documented no-op) |
-v | global | no-op | repeatable | no in-process effect; value: [repeat+][level+]LEVEL | none (documented no-op) |
-ss | input or output (position-scoped) | container | once | decimal seconds only (10, 2.5) | Input::set_start_time_us / Output::set_start_time_us |
-t | input or output (position-scoped) | container | once | decimal seconds only (10, 2.5) | Input::set_recording_time_us / Output::set_recording_time_us |
-to | input or output (position-scoped) | container | once | decimal seconds only (10, 2.5) | Input::set_stop_time_us / Output::set_stop_time_us |
-f | input or output (position-scoped) | container | once | container/demuxer name ([a-z0-9_]+) | Input::set_format / Output::set_format |
-vn | output | video | repeatable | flag | Output::disable_video |
-an | output | audio | repeatable | flag | Output::disable_audio |
-c:v | output | video | once | codec name or copy ([A-Za-z0-9_-]+) | Output::set_video_codec |
-c:a | output | audio | once | codec name or copy ([A-Za-z0-9_-]+) | Output::set_audio_codec |
-b:v | output | video | once | NNN with optional k/K/m/M suffix | Output::set_video_bitrate |
-b:a | output | audio | once | NNN with optional k/K/m/M suffix | Output::set_audio_bitrate |
-crf | output | video | once | integer 0..=51 | Output::set_video_codec_opt(“crf”, …), libx264 only |
-preset | output | video | once | x264 preset name | Output::set_video_codec_opt(“preset”, …), libx264 only |
-pix_fmt | output | video | once | pixel format name ([a-z0-9_]+) | Output::set_pix_fmt |
-ar | output | audio | once | positive integer | Output::set_audio_sample_rate |
-ac | output | audio | once | positive integer | Output::set_audio_channels |
-frames:v | output | video | once | exactly 1 | Output::set_max_video_frames(1) |
-vf | output | video | once | single scale=… chain only | Output::set_video_filter |
-map | output | stream map | accumulates | basic index maps only (0, 0:v, 0:a:1, 0:1, …) | Output::add_stream_map / add_stream_map_with_copy |
-movflags | output | container | once | exactly +faststart | Output::set_format_opt(“movflags”, “+faststart”) |
-hls_time | output | container | once | decimal seconds > 0 | Output::set_format_opt(“hls_time”, …) |
-hls_playlist_type | output | container | once | exactly vod | Output::set_format_opt(“hls_playlist_type”, “vod”) |
-hls_list_size | output | container | once | exactly 0 | Output::set_format_opt(“hls_list_size”, “0”) |
-hls_segment_filename | output | container | once | non-empty path; --leading values rejected | Output::set_format_opt(“hls_segment_filename”, …) |
Command layout is fixed: exactly one -i input and exactly one output
path, in the canonical [global/input options] -i INPUT [output options] OUTPUT [global options] order — after the output path only GLOBAL options
are accepted (e.g. a trailing -y). The - stdin/stdout pseudo-paths are
excluded — pipe I/O is process wiring, not part of the in-process subset.
Verified shapes (may execute; each is backed by a semantic golden and a compile-pinned emitted example):
| id | shape | container |
|---|---|---|
| V1 | H.264/AAC transcode (crf + preset) | .mp4 |
| V2 | re-encoded clip (input -ss, output -t) | .mp4 |
| V3 | audio extract (-vn, AAC) | .m4a |
| V4 | single-frame thumbnail (input -ss, -an, mjpeg) | .jpg |
| V5 | scaled H.264/AAC transcode (-vf scale) | .mp4 |
| V6 | single-rendition VOD HLS | .m3u8 |
Unverified entries (emit-only: code generation with a scaffolding banner, execution refused):
| id | shape |
|---|---|
| U1 | input-side trim (-ss + -t before -i) |
| U2 | faststart remux (explicit per-media copy) |
| U3 | scale with audio copy |
| U4 | thumbnail recipe shape (-vf + -frames:v) |
| U5 | audio extract via stream copy |
| U6 | PCM / resampled audio extract |
| U7 | partial HLS option set |
| U8 | mapped transcode (basic index maps) |
| U9 | mapped audio copy |
| U10 | cross-scope trim pair (input -t, output -to) |
| U11 | output-side seek transcode |
| U12 | bitrate-driven transcode |
| U13 | pixel-format transcode |
| U14 | explicit input format (e.g. lavfi) |
| U15 | container-defaults remux |
| U16 | video-codec-only transcode |
| U17 | transcode without preset |
| U18 | transcode with audio bitrate |
| U19 | audio+video codec selection only |
| U20 | transcode shape with unpinned values/container |
| U21 | clip shape with unpinned values/container |
| U22 | audio-extract shape with unpinned values/container |
| U23 | thumbnail shape with unpinned values/container |
| U24 | scaled-transcode shape with unpinned values/container |
| U25 | VOD HLS shape with unpinned values/container |
Everything else — including parseable option sets outside both tables — is rejected with a typed diagnostic.
§String form
from_cli / emit_rust_code accept one string and apply POSIX word
splitting ONLY: single/double quotes, backslash escapes,
backslash-newline continuation, plus caret-newline continuation as an
explicitly named cmd.exe compatibility extension. No variables, globs,
tilde, pipes, redirects, comments or command lists — those tokens are
rejected, never emulated (unquoted *, ? and [ included: quote or
escape a literal). Windows cmd.exe quoting is NOT reproduced:
commands relying on CommandLineToArgvW backslash rules must use the
argv form.
Enums§
- CliError
- Error type of the CLI-compat entry points (
from_cli_args,from_cli,emit_rust_code,emit_rust_code_from_args). - CliScope
- Where in the command an option was found (positional scoping: options apply to the next file on the command line).
Functions§
- emit_
rust_ code - Single-string convenience wrapper over
emit_rust_code_from_args, using the same POSIX word-splitting contract asfrom_cli. - emit_
rust_ code_ from_ args - Translates ffmpeg-style argv tokens into a complete Rust program using the ez-ffmpeg builder API.
- from_
cli - Single-string convenience wrapper over
from_cli_args. - from_
cli_ args - Builds a ready-to-start
FfmpegContextfrom ffmpeg-style argv tokens.