Save Last Frame (FFMPEGA)
How you actually get more than 5 seconds out of Wan
- images
- last_frame
- frame_path
- slot_name
- frame_count
Every i2v model in this ecosystem has the same wall: it generates a fixed window of frames, and then it stops. Wan 2.2's default is 81 frames - about five seconds at 16fps. The oldest trick for going longer is last-frame-to-first-frame chaining, and it's still the standard approach: generate clip one, take its final frame, feed it to the next generation as the starting image, repeat. Save Last Frame is the node that makes the handoff boring instead of fiddly.
What it does
It writes the trailing frame(s) of a generation into a named slot on disk - output/ffmpega_last_frame/<slot>/ - with fixed zero-padded filenames (lastframe_00.png, _01.png, ...). The pairing with Load Last Frame is an explicit contract based on slot name and filename order, not an "newest file in the output folder wins" race, which is the failure you'd otherwise hit the moment you queue three chains in a day.
Use different slot names to keep chains apart - drone_a, drone_b. Slot names get sanitized down to letters, digits, - and _.
The inputs that matter
images first, always. Connect the IMAGE batch straight off your sampler and the tensor is written directly to PNG, with no h264 round-trip. Fall back to video_path only when you have no tensor, because decoding the frame back out of an encoded file bakes in compression artifacts and yuv420p chroma subsampling - and those compound across a chain of generations, which is exactly the drift people complain about in long AI videos.
Then:
frame_count- how many trailing frames to save. 1 is the normal choice for i2v chaining; a few more if your next stage wants context frames.offset_from_end- skip N frames at the very end. This is the one people discover late. The literal final frame is often the worst one: motion blur on a moving shot, and i2v tails tend to soften. Try 1–3 if your continuation starts out mushy.keep_history- off by default, which overwrites and keeps the slot at exactlyframe_countfiles with fixed names so loading is unambiguous. On, it appends numbered files and builds an archive of every run.
Outputs
last_frame is the saved frame(s), oldest first - and it's the exact tensor that was written, not a re-read, so wiring it straight into your next generation avoids both the filesystem trip and PNG's 8-bit quantization. That's the thing to use for chaining inside a single workflow. frame_path, slot_name (sanitized - connect it to Load Last Frame's slot_name to force ordering), and frame_count round it out.
One warning the author puts in the node description, and it's worth quoting because it saves an afternoon: within a single workflow, use last_frame rather than adding a Load Last Frame node. Two unconnected nodes have no guaranteed execution order, and ComfyUI decides node caching before execution starts - so the load side would read the previous run's frame.
Install
ComfyUI Manager → search ComfyUI-FFMPEGA → Install, or:
cd ComfyUI/custom_nodes
git clone https://github.com/AEmotionStudio/ComfyUI-FFMPEGA.git
pip install -r ComfyUI-FFMPEGA/requirements.txt
Restart. No models to download - just FFMPEG on PATH, which is the pack's baseline requirement. The node shows a thumbnail strip of the slot's current contents as soon as you drop it on the canvas, so you can see what you're about to continue from without queueing anything.
Where people get burned
Chains degrade, and this node doesn't stop that. Every continuation is a generation away from the original, so identity drift and softening accumulate. The community workaround is to stop chaining sequentially and instead generate several clips from the same source image and use their frames as keyframes, so nothing is more than one step from the original. SVI-style extension LoRAs are the other live answer - they run on plain Wan 2.2 and recycle error across windows rather than starting each one fresh. Save Last Frame is the plumbing either way; it isn't a fix for the drift.
A missed save looks like a broken graph. If the run errored before the sampler finished, or you saved from a video whose tail you didn't expect, you'll load a stale or empty slot. frame_count on the Load side returns 0 when the slot is empty - check that before you blame your prompt.
Inputs (7)
| Name | Type | Default | Description |
|---|---|---|---|
| slot_name | STRING | default | Named slot to write into (output/ffmpega_last_frame/<slot>/). Load Last Frame reads the same slot. Use different names to keep several continuation chains apart, e.g. 'drone_a'. Only letters, digits, - and _ are kept. |
| frame_count | INT | 11–64 | How many trailing frames to save. 1 is the usual choice for i2v chaining; a few more is useful for workflows that want several context frames. |
| offset_from_end | INT | 00–4096 | Skip this many frames at the very end. The literal final frame is often the worst one — motion blur on a moving shot, and i2v tails tend to soften. Try 1-3 if the saved frame looks mushy. |
| keep_history | BOOLEAN | false | Overwrite (default) keeps the slot at exactly frame_count files with fixed names, so loading is unambiguous. Keep history appends numbered files instead, building an archive of every run. |
| imagesopt | IMAGE | Connect for lossless chaining — the tensor is written straight to PNG with no h264 round-trip. Takes priority over video_path when both are set. | |
| video_pathopt | STRING | Fallback source: path to a video file whose tail gets decoded with ffmpeg. Works with any video, but inherits the file's compression artifacts. | |
| filename_prefixopt | STRING | lastframe | Base filename inside the slot directory. Files are written as <prefix>_00.png, _01.png, ... |
Outputs (4)
| Name | Type | Description |
|---|---|---|
| last_frame | IMAGE | The saved frame(s), in chronological order. Wire this straight into the next generation for single-run chaining — it is the exact tensor that was written, so it avoids both the filesystem round-trip and PNG 8-bit quantisation. |
| frame_path | STRING | Absolute path of the newest saved frame. |
| slot_name | STRING | The sanitized slot name. Connect it to Load Last Frame's slot_name to force this node to run first when both live in one graph. |
| frame_count | INT | How many frames were actually written (may be fewer than requested). |