MirVideoMerger
Stitching up to 50 clips into one mp4 with ffmpeg, no Replicate in sight
- output_video_path
- debug_json
- input_video_count
- output_duration_seconds
A multi-segment Kling pipeline doesn't end when the last clip renders. You still have six short clips that need to become one video, with your voiceover on top. MirVideoMerger is the pack's answer - and it's the one node in Auto-Card-Generator that does something local and real with media. It's the local, no-API replacement for the Replicate "zip2mp4" service this kind of workflow would otherwise pay per call. Up to 50 input videos, one output mp4, all on your machine.
How it works
It shells out to ffmpeg. Each video1…video50 input takes a local file path or an http(s) URL (URLs get downloaded to a temp dir first). It concatenates them with the concat filter - normalizing every clip to your target_fps, even dimensions, and yuv420p along the way, which is what makes clips of different sizes actually stitch together instead of crashing. Then it encodes the result with libx264 at your crf and preset, and if you gave it an audio track, muxes that in as AAC.
Two looping flags do the heavy lifting for the classic "voiceover longer than the visuals" problem:
loop_videos- repeats the whole concatenated video to cover a longer audio track. The repeat count is capped bymax_video_repeats(10 default), so a 3-second clip doesn't loop 400 times into a 20-minute nightmare.loop_audio- streams the audio on repeat (-stream_loop -1in ffmpeg) until the video ends, with-shortestcutting it off at the video's length. On by default in spirit - well, off by default, but flip it when your music track is shorter than the footage.
The output lands in your ComfyUI output directory as <prefix>_<timestamp>.mp4 (zip2mp4_local is the default prefix, a nod to the Replicate behavior it replaces).
The inputs that matter
video1 is required; video2–video50 are optional - just leave unused ones empty. target_fps (30 default), crf (18 - visually lossless-ish, 23 is fine if you want smaller files), and preset (medium) are your quality dials. timeout_seconds (600) is per ffmpeg command, and keep_temp_files keeps the intermediate concatenated file around when you're debugging a weird mux. The ffmpeg_path / ffprobe_path inputs exist for when your binaries aren't on PATH.
The real dependency: ffmpeg
This node needs ffmpeg and ffprobe installed and reachable. That's the single most common failure, and it's loud:
RuntimeError: Binary 'ffmpeg' was not found in PATH. Install ffmpeg/ffprobe and restart ComfyUI.
Install it with your package manager (sudo apt install ffmpeg, brew install ffmpeg, or winget on Windows), confirm ffmpeg -version works, restart ComfyUI. Or pass absolute paths into the node. Everything else - the concat, the audio mux, the looping - is handled.
Outputs
output_video_path (where the mp4 went - point a Save or preview node at it), debug_json (effective clip count after looping, encoders used, the temp dir), input_video_count, and output_duration_seconds. All local, all free, no Replicate account required.
Installing it
Ships in the Auto-Card-Generator pack (MIT, no pip dependencies, no model weights). Install via ComfyUI Manager (search "Auto-Card-Generator") or:
cd ComfyUI/custom_nodes
git clone https://github.com/mircudx/Auto-Card-Generator
Restart ComfyUI. The node appears under "Card Creator/Local Video". If a bundled workflow errors on import, use the *_local_safe_compat.json variant, which drops helper nodes local installs usually don't have.
Inputs (62)
| Name | Type | Default | Description |
|---|---|---|---|
| video1 | STRING | — | |
| loop_audio | BOOLEAN | false | — |
| loop_videos | BOOLEAN | false | — |
| output_file_prefix | STRING | zip2mp4_local | — |
| target_fps | INT | 3012–120 | — |
| crf | INT | 180–51 | — |
| preset | COMBO | medium | 9 options: ultrafast, superfast, veryfast, faster, fast, medium, +3 |
| timeout_seconds | INT | 60030–7200 | — |
| max_video_repeats | INT | 101–200 | — |
| keep_temp_files | BOOLEAN | false | — |
| audioopt | STRING | — | |
| ffmpeg_pathopt | STRING | ffmpeg | — |
| ffprobe_pathopt | STRING | ffprobe | — |
| video2opt | STRING | — | |
| video3opt | STRING | — | |
| video4opt | STRING | — | |
| video5opt | STRING | — | |
| video6opt | STRING | — | |
| video7opt | STRING | — | |
| video8opt | STRING | — | |
| video9opt | STRING | — | |
| video10opt | STRING | — | |
| video11opt | STRING | — | |
| video12opt | STRING | — | |
| video13opt | STRING | — | |
| video14opt | STRING | — | |
| video15opt | STRING | — | |
| video16opt | STRING | — | |
| video17opt | STRING | — | |
| video18opt | STRING | — | |
| video19opt | STRING | — | |
| video20opt | STRING | — | |
| video21opt | STRING | — | |
| video22opt | STRING | — | |
| video23opt | STRING | — | |
| video24opt | STRING | — | |
| video25opt | STRING | — | |
| video26opt | STRING | — | |
| video27opt | STRING | — | |
| video28opt | STRING | — | |
| video29opt | STRING | — | |
| video30opt | STRING | — | |
| video31opt | STRING | — | |
| video32opt | STRING | — | |
| video33opt | STRING | — | |
| video34opt | STRING | — | |
| video35opt | STRING | — | |
| video36opt | STRING | — | |
| video37opt | STRING | — | |
| video38opt | STRING | — | |
| video39opt | STRING | — | |
| video40opt | STRING | — | |
| video41opt | STRING | — | |
| video42opt | STRING | — | |
| video43opt | STRING | — | |
| video44opt | STRING | — | |
| video45opt | STRING | — | |
| video46opt | STRING | — | |
| video47opt | STRING | — | |
| video48opt | STRING | — | |
| video49opt | STRING | — | |
| video50opt | STRING | — |
Outputs (4)
| Name | Type | Description |
|---|---|---|
| output_video_path | STRING | — |
| debug_json | STRING | — |
| input_video_count | INT | — |
| output_duration_seconds | FLOAT | — |