Coming from FFmpeg
If you build videos with FFmpeg filtergraphs, this page shows the alpha2 way to do the same things, and where each tool fits.
alpha2 doesn’t replace FFmpeg: the native programs decode and encode with FFmpeg 8. What changes is the middle. Instead of a filtergraph string, you write a project document, a JSON timeline of sources, tracks and clips that a GPU engine renders. The same document previews in a browser and renders on a server, and you can edit it, diff it and check it against a schema.
How the models differ
Section titled “How the models differ”| FFmpeg | alpha2 |
|---|---|
Inputs (-i) |
sources, each with an id. Files are given at export time: --asset <id>=<path>. |
| A filtergraph of labelled streams | tracks of clips on one timeline. Later tracks draw on top. |
Per-input timestamps, -ss, -t, trim |
A clip’s timeline_range (where it plays) and source_range (what part of the source plays), in ticks |
| Output size from the last filter | The project’s settings.width and height. Every source is fitted into it. |
Pixel coordinates (x=W-w-40) |
Normalized positions: 0 to 1 across the canvas |
| Filters on a stream | Effects in a composition graph on a clip |
-filter_complex with sendcmd or expressions over t |
Keyframes on any animatable value |
Side by side
Section titled “Side by side”One project with a crossfade between two photos, a grade on the second, and a line of text, the FFmpeg command beside it:
ffmpeg -loop 1 -t 3 -i coast.jpg -loop 1 -t 3 -i forest.jpg -filter_complex " [0:v]scale=1280:720,setsar=1[a]; [1:v]scale=1280:720,setsar=1,eq=contrast=1.2:saturation=1.3[b]; [a][b]xfade=transition=fade:duration=1:offset=2, drawtext=fontfile=HankenGrotesk.ttf:text='Day two':fontsize=58:fontcolor=white: x=w*0.05:y=h*0.92-th:enable='gte(t,3)'" -r 30 out.mp4{ "schema_version": 1, "id": "from-ffmpeg", "name": "From FFmpeg", "settings": { "width": 1280, "height": 720, "frame_rate": { "num": 30, "den": 1 }, "sample_rate": 48000 }, "sources": [ { "id": "coast", "locator": "asset://coast", "kind": "image" }, { "id": "forest", "locator": "asset://forest", "kind": "image" }, { "id": "caption", "kind": "generated", "generator": { "type": "text", "text": "Day two", "style": { "font_family": "Hanken Grotesk", "font_size": 0.08, "align": "start", "position": { "x": 0.05, "y": 0.92 }, "anchor": { "x": 0, "y": 1 } } } } ], "compositions": [ { "id": "graded", "output": "eq", "nodes": [ { "id": "clip", "op": { "type": "clip" } }, { "id": "eq", "op": { "type": "effect", "input": "clip", "effect": { "id": "alpha2.effect.color-controls", "version": 1, "params": { "contrast": { "mode": "constant", "value": { "type": "float", "value": 1.2 } }, "saturation": { "mode": "constant", "value": { "type": "float", "value": 1.3 } } } } } } ] } ], "timeline": { "tracks": [ { "id": "v1", "name": "Picture", "kind": "video", "clips": [ { "id": "a", "source_id": "coast", "timeline_range": { "start": 0, "end": 360000 }, "source_range": { "start": 0, "end": 360000 } }, { "id": "b", "source_id": "forest", "timeline_range": { "start": 240000, "end": 600000 }, "source_range": { "start": 0, "end": 360000 }, "composition": { "id": "graded" } } ], "transitions": [ { "from_clip": "a", "to_clip": "b", "timeline_range": { "start": 240000, "end": 360000 }, "easing": { "type": "linear" }, "effect": { "id": "alpha2.transition.fade", "version": 1 } } ] }, { "id": "text", "name": "Text", "kind": "video", "clips": [ { "id": "caption-clip", "source_id": "caption", "timeline_range": { "start": 360000, "end": 600000 }, "source_range": { "start": 0, "end": 240000 } } ], "transitions": [] } ] }}alpha2-host export --project graded.json \ --asset coast=coast.jpg --asset forest=forest.jpg \ --font HankenGrotesk.ttf --out out.mp4xfade → a transition
Section titled “xfade → a transition”[a][b]xfade=transition=fade:duration=1:offset=2The two clips overlap on one track from 2 s to 3 s, and a transition in the track’s transitions joins them over that range. effect.id names one of 122 built-in transitions (alpha2.transition.fade, directional-wipe, circle-open and so on), and easing shapes its progress. Unlike offset, the range is explicit on the timeline, and both clips keep their own times.
eq → color-controls
Section titled “eq → color-controls”eq=contrast=1.2:saturation=1.3The graded composition runs the second clip through alpha2.effect.color-controls with contrast 1.2 and saturation 1.3. It also has exposure, temperature and tint. The math is the engine’s own, so the same numbers give a similar look to eq, not the same pixels. levels, lift-gamma-gain, hue-saturation and lut-3d (a .cube file) cover the rest of FFmpeg’s color filters.
drawtext → a text generator
Section titled “drawtext → a text generator”drawtext=fontfile=HankenGrotesk.ttf:text='Day two':fontsize=58:x=w*0.05:y=h*0.92-th:enable='gte(t,3)'Text is a generated source with a text generator, shown by a clip from 3 s to 5 s, which replaces enable. font_size is a fraction of the picture’s shorter side (0.08 × 720 ≈ 58 pixels). position places the text’s anchor point: anchor (0, 1) is its bottom-left corner, so this is x=w*0.05:y=h*0.92-th. Lines are aligned within the text’s wrapping width, max_width (0.9 of the canvas width by default), so align: "start" keeps them at the left. The font comes from --font, as fontfile does. For boxes that size themselves around text, use a layout generator.
overlay and scale → a clip’s visual
Section titled “overlay and scale → a clip’s visual”[1:v]scale=iw*0.32:-1[pip];[0:v][pip]overlay=W-w-50:H-h-50A clip on a higher track draws over the ones below. Its visual.scale scales it from its fitted size, and position places its anchor point. The picture-in-picture recipe has the full project, with rounded corners and a shadow, which take more than one filter in FFmpeg.
scale, pad and crop → fitting the canvas
Section titled “scale, pad and crop → fitting the canvas”Every source is first fitted inside the canvas, centred, keeping its aspect ratio, like scale=...:force_original_aspect_ratio=decrease,pad=.... The bars are the project’s settings.background color (black by default). To fill the frame instead (force_original_aspect_ratio=increase,crop=...), scale the clip up and move it with position: see Vertical video.
alpha2.effect.crop cuts edges off without changing the frame size: top_left and bottom_right are how much to cut from each side, as fractions, with a feather. A clip’s masks cut it to any shape.
Other common filters
Section titled “Other common filters”| FFmpeg | alpha2 |
|---|---|
concat |
Clips one after another on one track |
fade=in, fade=out |
opacity keyframes on a clip, or a transition |
setpts, atempo |
A source_range longer or shorter than the timeline_range: the clip plays faster or slower, with its sound time-stretched or resampled |
reverse |
"time_map": { "type": "reverse" } |
boxblur, gblur |
alpha2.effect.gaussian-blur |
unsharp |
alpha2.effect.unsharp-mask, alpha2.effect.sharpen |
vignette |
alpha2.effect.vignette |
chromakey, colorkey |
alpha2.effect.chroma-key |
lut3d |
alpha2.effect.lut-3d with a .cube effect resource |
amix, volume, pan |
Audio tracks; a clip’s audio.gain and audio.pan |
afade |
A clip’s audio.fade_in and audio.fade_out |
loudnorm |
--loudness-target <LUFS> on export (EBU R128) |
subtitles |
A caption track: see Captions from SRT |
Output options
Section titled “Output options”| FFmpeg | alpha2-host export |
|---|---|
-ss, -to |
--start-ticks, --end-ticks |
-r 30 |
--frame-rate 30/1 |
-c:v libx264, -c:v libvpx-vp9 |
--video-codec h264, --video-codec vp9 |
-crf, -b:v |
--video-quality high (a level) or --video-quality 8000000 (bits per second) |
-c:a, -b:a |
--audio-codec aac, --audio-quality |
-an |
--no-audio |
-f mp4 |
--container mp4, or the output’s extension |
-y |
--overwrite |
The CLI reference lists every flag.
The alpha2 tool
Section titled “The alpha2 tool”The release archives have a second program, alpha2, for single files. It covers the everyday ffprobe and ffmpeg jobs an editing app needs around a project:
| Job | FFmpeg | alpha2 |
|---|---|---|
| Inspect a file | ffprobe clip.mp4 |
alpha2 probe clip.mp4 |
| A poster frame | ffmpeg -ss 2 -i clip.mp4 -frames:v 1 poster.png |
alpha2 thumbnail clip.mp4 poster.png --at 2 |
| A representative frame | ffmpeg -i clip.mp4 -vf thumbnail -frames:v 1 poster.png |
alpha2 thumbnail clip.mp4 poster.png |
| An editing proxy | ffmpeg -i clip.mp4 -vf scale=iw/2:-2 proxy.mp4 |
alpha2 transcode clip.mp4 proxy.mp4 --proxy half |
| Audio to WAV | ffmpeg -i clip.mp4 -ar 48000 audio.wav |
alpha2 export-audio clip.mp4 audio.wav |
| Waveform data | ffmpeg ... astats |
alpha2 waveform clip.mp4 (JSON) |
Without --at, thumbnail picks the sharpest of nine frames spread over the video that is neither black nor white. The commands that decode take --decode-policy tolerant to skip damaged input instead of failing. See CLI reference.
