BFS H3 Prepare Native Video (Auto Size / Frames)
The frame-count rule that eats your first H3 render
- images
- reference_video_24fps
- guide_contact_sheet
- width
- height
- length
- metadata
- guide_analysis_instruction
- request
- trim_frames
What it does, and why it exists
MiniMax H3 does not generate arbitrary frame counts. It wants 17n+5 - 22, 39, 56, 107, 124 - and it wants width and height in multiples of 32. Your source clip, meanwhile, is whatever the person who filmed it felt like: 30 fps, 1920×1080, nine seconds.
So before you can hand a guide performance to H3, someone has to answer three boring questions. How many frames does my clip become at 24 fps? What resolution can I afford? And how do I show a vision model twelve evenly spaced frames of it so it can describe the performance?
BFS H3 Prepare Native Video answers those. It's the first node in the pack's auto-prompt workflow, and it's the one you'll re-open every time a render comes out the wrong length.
How it works
Feed it a decoded IMAGE batch and it does the arithmetic in prepare_video():
- Frames first.
available = floor(frames × 24 / source_fps), optionally capped bymax_frames. Thenlength = (available - 5, plus 16 if you're padding) // 17 × 17 + 5. A 300-frame, 30 fps clip becomes 240 frames at 24 fps, which rounds down to 226. Under 5 frames it raises; over 3600 it tells you to split into shots. - Size second.
scale = min(output_scale, sqrt(max_megapixels × 1e6 / (w × h))), then width and height floor to multiples of 32. Defaults are scale 1.0 and a 0.4 MP cap, so a 1080p source lands at roughly 838×480 → 832×480, not 512×288. There's no fixed canvas - resolution follows the source. Portrait sources stay portrait. - Reference size third.
reference_scale(0.01–1.0, down only) resizes the actual frames it returns. So it doesn't just shrink a preview: the<Video 1>you hand to H3, and the frames Qwen sees, come back at the reduced size. It resizes rather than letterboxing, so a mild aspect change is possible and the console metadata says so.
Out of that comes reference_video_24fps, plus the integers width, height and length that you wire into the encoder node - and this is the part people skip. Typing numbers is how you get length mismatches.
It also builds the two things the prompt half of the workflow needs. guide_contact_sheet is an IMAGE of up to analysis_frames frames sampled evenly across the clip timeline, each cell labelled Frame 137 | 5.708 s, laid out four to a row. guide_analysis_instruction is a ready-made prompt telling the captioner to analyse only those numbered frames in order, describe positions, clothing, action, camera motion and cuts, and explicitly not invent choreography, audio or identities from the reference pictures. metadata is a JSON blob (source and output size, reference size, frames, duration, padding, trim count) that gets printed to the console and passed on to the prompt builder as ground truth.
The inputs a beginner actually sets
images- from VHS Load Video. If that loader resamples to 24 fps for you, keepsource_fpsat 24; if you're feeding a loader that doesn't, put the real rate in. Get it wrong and every timestamp downstream is shifted - which TARA then can't fix, no matter its strength.max_megapixels(0.4) - your main cost dial. Lower it before you lower steps.max_frames(0 = whole clip) - the honest cap. The tooltip is blunt about why: "Long clips can exhaust VRAM."frame_rounding-pad last framerepeats the final frame to reach the grid, and you trim the decoded output back to the true duration with thetrim_framesinteger downstream (ImageFromBatch).trim tailjust discards the remainder. Padding is the default because losing the last half-second of a performance is worse than an extra frame.analysis_frames(12, up to 32) - more frames, better guide description, more VLM context.request- the whole workflow's user request lives here and gets passed forward. Write the roles explicitly: which picture is the identity, which is the scene.
Outputs, in order: reference_video_24fps, guide_contact_sheet, width, height, length, metadata, guide_analysis_instruction, request, trim_frames.
Install
Manager → search ComfyUI-BFSNodes (registry publisher alisson-anjos), or:
cd ComfyUI/custom_nodes
git clone https://github.com/alisson-anjos/ComfyUI-BFSNodes.git
cd ComfyUI-BFSNodes && pip install -r requirements.txt
Restart ComfyUI. Requirements are light: torch, numpy, Pillow, safetensors, librosa, opencv-python, scenedetect. You'll also want VideoHelperSuite, since the author's example graph loads video with it. Auto-prompt workflow wants BFSNodes 1.115.21+, and the pack updates often.
Where people get burned
CPU RAM, not VRAM. VHS decodes the entire clip before any of these controls run. A long 4K source can eat system memory even though your output budget is 0.4 MP. Trim or cap in the loader, not here.
Padding confused with extending. pad last frame doesn't give you more video - trim_frames exists precisely so the decoded result gets cut back to your source duration. Skip that trim step and your clip ends on a short freeze.
Treating 0.4 MP as a recommendation. It's a default tuned on a 5090. On a 12 GB card, drop output_scale or max_megapixels. And note the two knobs aren't the same: reference_scale shrinks what the model sees of the guide, not the render size.
Inputs (9)
| Name | Type | Default | Description |
|---|---|---|---|
| images | IMAGE | — | |
| source_fps | FLOAT | 24.00 | — |
| output_scale | FLOAT | 1.000.01–4 | — |
| max_megapixels | FLOAT | 0.400.01–16 | — |
| reference_scale | FLOAT | 1.000.01–1 | — |
| max_frames | INT | 00–3600 | 0 = whole loaded clip; rounded down to 17n+5. Long clips can exhaust VRAM. Use VHS trim/cap or split shots. |
| frame_rounding | COMBO | pad last frame | Pad only the last frame to the H3 grid and trim decoded output to source duration; trim tail discards the remainder instead. |
| analysis_frames | INT | 122–32 | — |
| request | STRING | Replace the main performer with <Picture 1>. | — |
Outputs (9)
| Name | Type | Description |
|---|---|---|
| reference_video_24fps | IMAGE | — |
| guide_contact_sheet | IMAGE | — |
| width | INT | — |
| height | INT | — |
| length | INT | — |
| metadata | STRING | — |
| guide_analysis_instruction | STRING | — |
| request | STRING | — |
| trim_frames | INT | — |