Roop Face Swap (Video)
Face swap an entire video — slowly, but it works
- source_image
Swap a face into a video file instead of a still image. That's the whole pitch, and it's the node that usually gets people to install this pack in the first place. Give it a source face and a path to an mp4, and it runs the swap across every frame, preserving the original FPS and frame count, then writes a new video file.
The honest headline: it's slow. The README says it plainly - video swapping works best with shorter clips. Every frame goes through the full detection-and-swap pipeline as its own subprocess against roop, so a 10-second clip at 30fps is 300 separate swaps. A short clip is a great demo. A feature film is a long lunch, or several.
How it works
Same wrapper mechanism as the rest of the pack: the node saves your source tensor and shells out to roop's run.py, this time with video flags:
python run.py -s source.png -t /path/to/video.mp4 -o swapped_video.mp4 \
--keep-fps --keep-frames --execution-provider cuda --frame-processor face_swapper
--keep-fps and --keep-frames do what they say - your output keeps the original frame rate and every frame, so you don't get a weirdly sped-up or decimated result.
The inputs that matter
- source_image - the face to impose on the video.
- target_video_path - the video file, as a string. Absolute path, and the node does not check it exists up front; roop errors out inside the subprocess if it's wrong.
- output_name - filename of the result. It's written to
roop_dir/temp_io, with auto-incrementing (_1,_2…) so you never clobber a previous run. - many_faces - swap every face that appears in the frame.
- roop_dir - your roop checkout. Default
/content/roop; update it or nothing runs.
The catch: nothing comes out of the node
Read that carefully: this node has no output. RETURN_TYPES is empty. It runs, prints progress to the console, and the finished video lands at roop_dir/temp_io/<output_name>. There's no preview node to attach, no tensor to wire anywhere - you have to go find the file. That's a weird experience if you're used to ComfyUI handing you everything as a node connection.
It's also the reason the webhook nodes exist. The natural workflow for this pack is: swap the video on a Colab or remote box, then use RoopSendWebhookFile to push roop_dir/temp_io/<output_name> to your own server or an automation endpoint. On a local machine, just open the folder.
Gotchas worth knowing
- NSFW filter still applies per-frame. If roop decides a frame is unspeakable, that frame gets skipped, and you can end up with a flicker or a missing swap in the middle of your clip. Check the console for
[Warning] Roop did not produce video outputif the file never appears at all. - CUDA is mandatory. The node hard-codes
--execution-provider cuda. CPU-only machines can't run it, and on a shared T4 it will be slow - this is the node where you notice the 128x128 quality ceiling and the per-frame cost at the same time. - First run still downloads the model. roop fetches
inswapper_128.onnxthe first time you run any swap. Let it finish before assuming a hang. - Output quality is 128x128-flavored. Fine for short social clips; don't expect broadcast-grade results.
Install is the same as the rest of the pack: clone glitchinthemetrix16/ComfyUI-Roop into custom_nodes, restart, and make sure roop_dir points at a real roop checkout (Furkan Gözükara's fork per the README).
Inputs (5)
| Name | Type | Default | Description |
|---|---|---|---|
| source_image | IMAGE | — | |
| target_video_path | STRING | /path/to/video.mp4 | — |
| roop_dir | STRING | /content/roop | — |
| output_name | STRING | swapped_video.mp4 | — |
| many_faces | BOOLEAN | false | — |
Outputs (0)
No outputs