Video Save Plus (Custom Path) π¬
The save node that doesn't throw away your video's audio
- video
- images
- audio
- filepath
ComfyUI's default video output has a hole: it saves the pixels and, depending on which node you grabbed, quietly drops the soundtrack. That used to be fine - most video models were silent. Then MiniMax H3 landed with native stereo audio built in (the first serious open answer to Veo's audio gap), and "where's the sound?" became the most annoying question in the room. VideoSavePlus is the answer. It's a video output node that writes an MP4 with H.264/H.265 plus AAC audio to any folder on any drive, aimed squarely at the new class of models that hand you a VIDEO tensor with audio already attached.
Why v2 exists
This pack is a rewrite, and the changelog is the story. The old node, VideoCombineCustomPath, wrote audio through torchaudio.save, which silently drops the track on newer torchaudio versions - you'd get a pristine silent MP4 and never know. v2 pipes raw float32 PCM and raw RGB frames straight into ffmpeg over pipes: no torchaudio, no temp PNG sequence, and if an audio input can't be processed it raises a clear error instead of quietly succeeding. "Fails loudly" is the right design for a save node, because a silent "successful" render is worse than a red one. One-time cost: old workflows have to be re-wired to the new node name once.
What to plug in
- video (
VIDEO) - the output of native-audio models like MiniMax. Frames, audio, and frame rate are all pulled from it. - images (
IMAGE) - the fallback for classic image-batch workflows;frame_rateonly applies here, since a VIDEO input brings its own. - audio (
AUDIO) - overrides the track inside a VIDEO input, handy for dubbing a silent generation. - filename_prefix - supports subfolders (
scene1/take) and the placeholders%date%,%time%,%seed%,%date:yyyy-MM-dd hh-mm-ss%. A 5-digit counter is always appended. - custom_output_path - any folder on any drive; created if missing, empty falls back to ComfyUI's output dir.
- crf (default 19) - the main quality knob: 17β19 is visually lossless, 0 is lossless, 28 is small.
The output is a single filepath string with the full path of the saved MP4 - wire it to a Text or a "Show Text" node if you want to see it in the UI.
The stuff that makes it a keeper
Beyond the video itself, each run writes a workflow PNG (drag it back onto the canvas to rebuild the graph - the same workflow-in-the-file convention ComfyUI's own SaveImage uses), an optional name.txt with your prompt, and optionally frames as first/last/all in jpg or png. That's the whole training pair in one folder, which is exactly what the Save Training File button is for: it copies the mp4 + png + txt + frames to copy_to_folder under identical names. There are also buttons to reveal the file in your file manager, play it with sound, grab the last frame losslessly, and delete the whole set - and the server endpoints only ever touch files this node saved in the current session, not arbitrary paths.
Install
Via ComfyUI Manager, search for Video Save Plus, or:
cd ComfyUI/custom_nodes
git clone https://github.com/Slartibart23/ComfyUI-CustomVideoSave
Restart ComfyUI and hit Ctrl+F5 in the browser once. The only hard dependency is ffmpeg on your PATH (or pip install imageio-ffmpeg as a fallback - the node checks both); requirements.txt is just pillow, so no torchaudio install to fight.
Gotchas
- h265 is ~40% smaller at the same CRF but many players and browsers refuse it -
h264plays everywhere, andyuv420pis the compatibility-safe pixel format.yuv444plooks sharper on text/edges but is a browser no-go. - Odd frame dimensions get auto-scaled to even numbers for yuv420p - a classic ffmpeg footgun this node just handles for you.
- If ffmpeg is missing, you get a loud error, not a silent file. That's the feature.
Inputs (21)
| Name | Type | Default | Description |
|---|---|---|---|
| filename_prefix | STRING | video | Base filename. May contain subfolders (scene1/take) and placeholders: %date% (2026-08-21), %time% (143012), %seed% (from the seed input), %date:yyyy-MM-dd hh-mm-ss%. A 5-digit counter (_00001) is always appended. |
| custom_output_path | STRING | Any folder on any drive. Created if missing. Empty = ComfyUI's default output folder. | |
| frame_rate | FLOAT | 24.001β120 | Only used for the 'images' input. With a VIDEO input or source_video_path the video's own frame rate is used. |
| video_codec | COMBO | h264 | h264 = plays everywhere (Windows, web, phones). h265 = ~40% smaller at the same quality but not every player/browser supports it. Ignored in passthrough mode. |
| crf | INT | 190β51 | Constant quality. Lower = better and larger. 0 = lossless, 17-19 = visually lossless, 23 = ffmpeg default, 28 = small. Main quality control. Ignored in passthrough mode. |
| preset | COMBO | medium | Encoding speed vs. file size at the SAME quality (CRF). Does not change picture quality. Slower = smaller file, longer encode. Ignored in passthrough mode. |
| pixel_format | COMBO | yuv420p | yuv420p = maximum compatibility (standard). yuv444p = full colour resolution, sharper edges/text, but many players and all browsers refuse to play it. Ignored in passthrough mode. |
| audio_bitrate | INT | 19264β320 | AAC bitrate in kbit/s. 128 = speech, 192 = very good, 256-320 = music/transparent. In passthrough mode only used when 'audio' replaces the original track. |
| save_workflow_png | BOOLEAN | true | Save the first frame as PNG with the complete workflow embedded. Drag & drop into ComfyUI restores the workflow. |
| save_workflow_json | BOOLEAN | false | Also save the workflow as name.json (plain JSON, loadable via Workflow > Open; readable without image tools). |
| png_compression | INT | 40β9 | PNG is ALWAYS lossless. This only trades file size against write time: 0 = fastest/largest, 9 = smallest/slowest. 4 is a good balance. |
| save_frame | COMBO | none | Automatically save frames as images next to the video (name_first Frame / name_last Frame / name_frame_00001). The 'Save Last Frame' button works independently of this. 'all' needs frames (images/VIDEO), not available for passthrough without frames. |
| frame_format | COMBO | jpg | Image format for saved frames. jpg = small, lossy. png = lossless, larger (uses png_compression). |
| frame_quality | INT | 9510β100 | JPEG quality for saved frames (ignored for png). 90-95 = excellent, 100 = near lossless but large. |
| copy_to_folder | STRING | Target folder used by the 'Save Training File' button. Copies mp4 + png + json + txt + frames with identical names. | |
| videoopt | VIDEO | VIDEO output of models/nodes with native audio (e.g. Grok Imagine Video, MiniMax). Frames, audio and frame rate are taken from it and RE-ENCODED with the settings above. A connected 'audio' input overrides its audio track. | |
| imagesopt | IMAGE | Frames as IMAGE batch (used when no VIDEO is connected). In passthrough mode optional: only used for the PNG/frames. | |
| audioopt | AUDIO | Audio track. Overrides the audio contained in a VIDEO input. In passthrough mode it REPLACES the file's own soundtrack (video stream is still copied, not re-encoded). | |
| source_video_pathopt | STRING | PASSTHROUGH: path of a finished MP4 (e.g. the video_path output of Grok Imagine Video). The file is copied 1:1 to the destination - no re-encoding, no quality loss, audio kept - and renamed/numbered like everything else. Codec/CRF/preset/pixel_format are ignored. Leave unconnected to encode video/images as usual. | |
| prompt_textopt | STRING | Saved as name.txt next to the video (training pair). Nothing is written if empty. | |
| seedopt | INT | 00β18446744073709550000 | Only used for the %seed% placeholder in filename_prefix. |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| filepath | STRING | β |