vedit

vedit is a compact postfix language that compiles linear video edits into one FFmpeg -filter_complex graph.

Build and run

make
make test
./vedit -n example.edit output.mp4  # compile and print only
./vedit example.edit output.mp4     # print, then execute FFmpeg

Quoted strings may contain positional substitutions. Given video "$1" in a programme, run:

./vedit edit.txt output.mp4 "some input file.mp4"

Arguments after the output path are exposed as $1, $2, and so on. Substitutions may occur inside larger strings, such as video "clips/$1.mp4". Values are never interpreted by a shell.

ffprobe and ffmpeg must be available on PATH for normal CLI use.

The command printed by -n is self-contained, including subtitle cue clipping and concat-list creation. Those steps appear as private helper invocations using the absolute path of the current vedit executable, so keep that executable available when running a saved command later.

Language

Sources and literals push values:

video "picture.mov"
audio "dialogue.wav"
combined "clip.mp4"
subtitles "captions.srt"
duration 250ms
duration 01:23.500
scalar 0.7
index 0
burn-style "font=sans-serif; size=42; color=#FFFFFF"

Paths are quoted and may contain spaces or #. Outside quotes, # begins a comment. There is one instruction per line.

Stack operations are dup, drop, swap, over, and rot. Media operations are:

get-video  get-audio  get-subtitles split length
slice      take       concat delay
mux        attach-subtitles video-to-combined burn-subtitles
volume     mix        silence
speed      fade-in    fade-out

The language also provides compile-time Boolean logic, typed scalar/duration arithmetic and comparisons, structured if/else/end, and bounded begin/while/repeat loops. Loops are fully unrolled while constructing the FFmpeg graph and are limited to 10,000 iterations.

The separate typecheck pass records each instruction's consumed and produced types without modifying the parsed instruction array. COMBINED values retain ordered collections of every video, audio, and subtitle track in their source. Indexed operations select, take, drop, append, replace, and reorder those tracks. Compilation requires exactly one final media value.

Source durations come from ffprobe JSON. Stream-specific durations are preferred, with format.duration as fallback. Results are cached by path. Known durations propagate through the graph and are used by length and to calculate fade-out start times.

See LANGUAGE.md for all value types, operations, signatures, and stack semantics.