π¬ Compose Video
The single-encode endpoint that makes stacking effects cheap
- frames
- audio
- overlays
- audio_ops
- final_video_path
- filter_complex_script
MF_ComposeVideo is the destination for every MediaForge Compose workflow. It takes an overlay chain (from MF_ComposeOverlayText / MF_ComposeOverlayImage / MF_ComposeWatermark / MF_ComposeBurnSubtitle) and an audio chain (from MF_ComposeVolume / MF_ComposeAudioMix / MF_ComposeAudioFade / MF_ComposeNormalize), compiles both into one FFmpeg filter_complex graph, and encodes once.
This is the reason to use the Compose pipeline at all. Stack ten overlays, four audio ops, and a subtitle burn, and the video still decodes once and encodes once. Compare that to chaining separate single-effect nodes, where every output becomes the next input and every effect is a fresh re-encode. Quality survives re-encodes worse than file size does, so this is both faster and cleaner. For a one-shot single effect, though, the standalone nodes (MF_BurnSubtitle, MF_LoopVideo) are simpler - Compose earns its keep at 2+ effects.
It also replaces the older ComposeStart + ComposeFinalize pair. If you load an old workflow and see missing-node warnings, that's what happened; the readme has a migration walkthrough (copy ComposeStart's source/target settings and ComposeFinalize's encode settings onto this node, delete both, rewire the chain into the new overlays pin).
How it works
The overlay and audio chains arrive as lists of op dicts (MF_COMPOSE_OPS and MF_COMPOSE_AUDIO_OPS). The node resolves them into a compiled filter graph - internal plumbing is the ComposeIR dataclass, but you never touch it. If the compiled graph exceeds ~6000 chars it auto-switches to writing a -filter_complex_script temp file, dodging Windows command-line length limits. It's also dual-input: wire frames + tensor_fps + audio instead of video_path and it works off your tensor pipeline.
The inputs that matter
video_path- the source. Hidden in tensor mode.filename_prefix- output name base;output/<prefix>_NNNNN.mp4with an auto-counter.target_fps/target_width/target_height-0= inherit from source (probed internally, rotation-aware). This is why you usually don't needMF_ProbeMediafirst.codec/crf/preset- the one encode. Smart default picksh264_nvencif your GPU has it, libx264 otherwise; HEVC, AV1, and ProRes are in the dropdown.keep_audio- preserve source audio when noaudio_opschain is wired.
Outputs: final_video_path (STRING) plus filter_complex_script (STRING) - the compiled graph. When a Compose run misbehaves, that second output is your debugging window; it's worth wiring to a text display node while you iterate.
Install
Part of MediaForge:
cd ComfyUI/custom_nodes
git clone https://github.com/leon80148/comfyui_MediaForge.git
# restart ComfyUI
Or ComfyUI Manager β "MediaForge". Pack requirements.txt covers the small deps; system ffmpeg preferred, pip fallback binaries auto-installed.
Common issues
The most common failure is wiring an overlay chain but forgetting to actually connect it to this node's overlays input - your overlay silently doesn't render, and ComposeVideo encodes the source unchanged. Chain order is also meaningful: overlay list order is z-order, audio op order is filter order, so Volume β AudioMix and AudioMix β Volume differ. When something's off, read filter_complex_script before guessing.
Inputs (14)
| Name | Type | Default | Description |
|---|---|---|---|
| video_path | STRING | input/sample.mp4 | β |
| filename_prefix | STRING | MediaForge/composed | β |
| target_fps | FLOAT | 0.00β240 | β |
| target_width | INT | 00β7680 | β |
| target_height | INT | 00β4320 | β |
| codec | COMBO | h264_nvenc | 7 options: libx264, libx265, libsvtav1, prores_ks, h264_nvenc, hevc_nvenc, +1 |
| crf | INT | 180β51 | β |
| preset | COMBO | medium | 9 options: ultrafast, superfast, veryfast, faster, fast, medium, +3 |
| keep_audio | BOOLEAN | true | β |
| framesopt | IMAGE | β | |
| tensor_fpsopt | FLOAT | 30.01β240 | β |
| audioopt | AUDIO | β | |
| overlaysopt | MF_COMPOSE_OPS | β | |
| audio_opsopt | MF_COMPOSE_AUDIO_OPS | β |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| final_video_path | STRING | β |
| filter_complex_script | STRING | β |