Nodes/ComfyUi-MpiNodes/Mpi Load Video Upload
ComfyUI Node

Mpi Load Video Upload

Frames, audio and metadata in one ffmpeg pass

By MadPonyInteractive·Created 11 months ago·Updated 2 days ago· 3
Mpi Load Video Upload
    • images
    • audio
    • fps
    • frame_count
    • duration
    • width
    • height
    • has_audio
    • loaded
    video
    block_if_emptytrue
    force_rate0
    string

    Most video loaders in ComfyUI are one of two things. There's the built-in Load Video, which needs the file already sitting in input/ and has no path widget to point anywhere else, and there's VideoHelperSuite's Load Video (Path), which works fine but hands you a parameter wall you set once and then squint at forever.

    Mpi Load Video Upload is the third option: a picker with an upload button (drag-and-drop works), one ffmpeg pass that decodes frames and pulls the audio track, and the source metadata as real outputs. If you want "get this clip in and tell me what it is," this is the leanest thing in the room.

    What the decode actually does

    One ffmpeg -i file -f rawvideo -pix_fmt rgb24 - call, piped to stdout, reshaped into a float tensor in 0–1. No intermediate PNGs, no preview, no second pass. Width, height and frame rate are parsed out of ffmpeg's own stderr stream dump (ffmpeg -i with no output target exits non-zero but prints the stream layout) - deliberately, because the portable ComfyUI build doesn't ship ffprobe. If the frame rate can't be parsed, it falls back to 24.0 silently, which is worth remembering when a clip reports a suspiciously round number.

    Audio is separate but conditional: the file is inspected for an Audio: stream line first, and only then extracted, through a 16-bit PCM WAV temp file, read back into a [1, channels, samples] waveform dict. A video with no soundtrack returns no audio object rather than a silent one pretending to be sound.

    force_rate is the sleeper feature, and the implementation is a measured decision. It uses ffmpeg's fps filter, not the output -r flag, because -r rounds timestamps and overshoots: the source notes a 49-frame 30 fps clip through -r 24 returns 41 frames, which plays 4.6% slow - the exact drift you were trying to remove. fps=24 returns 39 and keeps the duration. Either way it happens inside the pass you were already paying for, with no interpolation model involved.

    Inputs and outputs

    You set video (the picker) and, if you like, force_rate - 0 means keep the source rate. block_if_empty decides what a bad path does. string is the optional injection slot: a filename inside input/ that's tried before the picker, so an app driving a saved workflow can write the file name while the picker stays on None.

    Then the outputs, which is where this node earns its keep - nine of them:

    • images - the frame batch, ready for a sampler.
    • audio - the decoded track, wire it into your save node or an audio encoder.
    • fps - send this to whatever writes the video back. A wrong fps doesn't error, it just plays at the wrong speed.
    • frame_count and duration - good for arithmetic and for gating, e.g. trimming a batch to a model's valid frame grid.
    • width and height - take them from here instead of re-deriving from the tensor.
    • has_audio - false when the clip had no track, so you can skip the audio half of a graph cleanly.
    • loaded - true only when something actually decoded, and never blocked, so it can drive a fallback branch.

    With block_if_empty on (the default) a missing or unreadable file blocks the downstream branch. Turn it off and you get a blank 1×1 image plus silent audio so the run continues.

    Installing it, and the ffmpeg you don't have

    Search ComfyUi-MpiNodes in Custom Nodes Manager and install from there. Otherwise:

    cd ComfyUI/custom_nodes
    git clone https://github.com/MadPonyInteractive/ComfyUi-MpiNodes
    

    There's no requirements.txt - nothing to pip install. What the pack does need is an ffmpeg binary, and it looks for one in this order:

    1. the VHS_FORCE_FFMPEG_PATH environment variable,
    2. the ffmpeg bundled by imageio-ffmpeg (the same one VideoHelperSuite uses),
    3. plain ffmpeg on your PATH.

    If none of those exist, the loader doesn't raise - it quietly reports nothing loaded, which looks like a broken file rather than a missing binary. So if video loads are silently dead, install VideoHelperSuite (it drags imageio-ffmpeg in with it) or point VHS_FORCE_FFMPEG_PATH at a real ffmpeg. The pack's own MpiSaveVideo raises an error naming all three lookups, which is how you confirm the diagnosis.

    Where people get tripped up

    Every frame lands in RAM as float32. There's no cap. A 1080p 30 fps clip at 10 seconds is roughly 7.5 GB of tensor before the model even sees it. For long clips, force_rate down or trim upstream - and don't blame the sampler when it OOMs at decode time.

    Paths are contained. A file must resolve inside input/, output/ or temp/; an absolute path pointing at your Desktop is treated as missing with no message. Copy it into input/ (or upload it through the node) and it works.

    Subfolder files aren't in the drop-down. The picker only lists loose files directly in input/. Type sub/clip.mp4 into string and it resolves fine.

    CategoryMpiNodes/Video

    Inputs (4)

    NameTypeDefaultDescription
    videoCOMBOPick a video, or use the upload button / drag-and-drop; the file is uploaded into ComfyUI's input/ folder. Used when string is empty or does not load; None picks nothing.
    block_if_emptyBOOLEANtrueON: empty/missing path blocks downstream execution. OFF: outputs a blank 1x1 image + silent audio so the graph continues.
    force_rateoptFLOAT00–240Resample the video to this frame rate while decoding. 0 = keep the source rate. ffmpeg drops/duplicates frames inside the pass that already happens, so it costs nothing and needs no interpolation model. fps, frame_count and duration are all reported at the forced rate.
    stringoptSTRINGFile name inside ComfyUI's input/ folder, with its subfolder if it has one (an absolute path must be inside input/, output/ or temp/). Tried first; if it is empty or does not load, the picker is tried. Nothing loads only when both fail (picker on None).

    Outputs (9)

    NameTypeDescription
    imagesIMAGE
    audioAUDIO
    fpsFLOAT
    frame_countINT
    durationFLOAT
    widthINT
    heightINT
    has_audioBOOLEAN
    loadedBOOLEAN