gRestorer is a GPU-first video pipeline for mosaic detection, restoration, and face swapping:
NVDEC (PyNvVideoCodec) → RGB/RGBP → BGR → Detect → (Track → Clip Restore / Face Swap → Composite) → NVENC → FFmpeg remux
It’s built to be measurable first, optimized second: the CLI prints per-stage timings so you can tune performance and quality surgically.
- Decode frames on GPU using
PyNvVideoCodec(NVDEC) - Convert decoder output RGB/RGBP → BGR (LADA-style and face-swap models expect BGR ordering)
- (Optional) Detect mosaics using a YOLO segmentation model (Ultralytics)
- Restore / transform
none: passthrough baseline (decode + conversion + encode cost)pseudo: draw ROI boxes + fill mosaic regions (visual sanity-check)pseudo_clip: clip-mode pipeline (tracker/compositor validation)basicvsrpp: clip restoration using a BasicVSR++-style model checkpointface_swap: ROI-authoritative face-swap pipeline with backend-specific workers
- Composite restored patches back into the full frame using a LADA-style blend mask (mosaic path)
- Encode on GPU using
PyNvVideoCodec(NVENC) - Remux to MP4 with FFmpeg (optionally copying audio/subtitles from the source)
After pip install -e . you can use either style:
grestorer ...— main pipeline (decode → [detect] → restore / swap → encode → remux)grestorer-add-mosaic ...— synth mosaic generator (for creating SFW test clips)
Module form also works:
python -m gRestorer.cli ...python -m gRestorer.cli.add_mosaic ...
Both commands default to loading ./config.json if present.
gRestorer/
cli/ # CLI entry + pipeline orchestration
core/ # scene/clip tracking logic
detector/ # mosaic detector wrappers (YOLO seg), face detector wrapper
restorer/ # restorers: none, pseudo, pseudo_clip, basicvsrpp, face_swap
utils/ # config + visualization helpers
video/ # NVDEC/NVENC wrappers: decoder.py, encoder.py
synthmosaic/ # mosaic addition functions
pyproject.toml
requirements.txt
requirements.torch-cu128.txt
config.json # optional; loaded by CLI if present
README.md
- Python 3.11+ (3.13 recommended)
- FFmpeg available on PATH (needed for remuxing /
ffprobetroubleshooting) - For GPU decode/encode: NVIDIA driver + NVDEC/NVENC-capable GPU and
PyNvVideoCodecworking
git clone <REPO_URL>
cd gRestorerpy -3.13 -m venv venv
.\venv\Scripts\Activate.ps1
python -m pip install -U pipUltralytics will pull CPU-only torch if torch isn’t installed yet. To avoid the YOLO seg mask failure seen with newer combos, this repo uses a known-good pin:
torch==2.9.1+torchvision==0.24.1ultralytics==8.3.243
CUDA 12.8 wheels example:
pip install -r requirements.torch-cu128.txtVerify:
python -c "import torch; print(torch.__version__); print('cuda?', torch.cuda.is_available()); print('cuda ver', torch.version.cuda)"
python -c "import ultralytics; print('ultralytics', ultralytics.__version__)"For CPU-only or Intel XPU installs, install the appropriate torch build first (per the official PyTorch instructions), then continue below.
pip install -r requirements.txtpip install -e .
python -m gRestorer.cli --helpgrestorer `
--input "D:\Videos\Test\sample.mp4" `
--output "D:\Videos\Test\out_none.mp4" `
--restorer nonegrestorer `
--input "D:\Videos\Test\sample.mp4" `
--output "D:\Videos\Test\out_pseudo.mp4" `
--restorer pseudo `
--det-model "D:\Models\lada\lada_mosaic_detection_model_v4.pt" `
--debuggrestorer `
--input "D:\Videos\Test\sample.mp4" `
--output "D:\Videos\Test\out_pseudo_clip.mp4" `
--restorer pseudo_clip `
--det-model "D:\Models\lada\lada_mosaic_detection_model_v4.pt" `
--debuggrestorer `
--input "D:\Videos\Test\sample.mp4" `
--output "D:\Videos\Test\out_basicvsrpp.mp4" `
--restorer basicvsrpp `
--det-model "D:\Models\lada\lada_mosaic_detection_model_v4.pt" `
--rest-model "D:\Models\lada\lada_mosaic_restoration_model_generic_v1.2.pth" `
--debugFace swap uses the same clip-oriented pipeline shell, but the ROI content is transformed by a face-swap backend instead of a mosaic restoration model.
Minimal example:
grestorer `
--input "D:\Videos\Test\sample.mp4" `
--output "D:\Videos\Test\sample_swap.mp4" `
--restorer face_swap `
--source-face "D:\Faces\source.jpg" `
--swap-model "D:\Models\faceswap\inswapper_128.onnx"Typical HyperSwap / SimSwap runs are usually driven from config.json, because there are more tuning knobs than a one-liner is comfortable with.
Current face swapping is ROI-authoritative:
- Detect face ROIs in the clip
- Stabilize the per-clip target face track
- Optionally refine target landmarks
- Run a backend-specific swap worker on the crop
- Optionally run face enhancement
- Optionally run occlusion preservation
- Return the modified crop to the clip/frame pipeline
- Uses the legacy/native InsightFace paste-back path
- Best current “plug it in and it works” quality
- Good alignment and usually the least tuning pain
- Uses a native worker path
- Follows a FaceFusion-style integration
- Uses whole-face aligned crop inference and native mask/paste-back
- This is the preferred path for HyperSwap; the shared compositor path was not a good fit
- Also uses a native worker path
- Follows a FaceFusion-style integration
- Properly scales and pastes back, but usually benefits more from enhancement than InSwapper or HyperSwap
The framework still contains a shared face compositor path for backends that return aligned backend results, but the currently validated face-swap backends above are all driven through native swap() workers.
That is intentional.
For the currently validated backends:
- InSwapper: native path
- HyperSwap: native path
- SimSwap: native path
So the face_comp_* knobs remain part of the framework surface, but they are not the primary quality controls for the native face-swap paths above.
The face-swap pipeline exposes the following practical controls.
source_face_path— source identity imageswap_model_path— ONNX swap modelswap_backend— explicit backend selection when you do not want backend autodetectswap_input_size— aligned crop size requested by the backend wrapperprovider/swap_provider—cpu,cuda,xpu, orauto
landmark_refiner_enabledlandmark_modellandmark_model_pathlandmark_providerlandmark_score
Practical note:
- Landmark refinement is worth enabling when you want better mask geometry and more stable face coverage on difficult clips.
face_enhancer_enabledface_enhancer_model_pathface_enhancer_providerface_enhancer_blend
Practical note:
- SimSwap often benefits noticeably from the enhancer.
- Start with
face_enhancer_blendaround70-80and adjust from there.
face_occluder_enabledface_occluder_model_pathface_occluder_providerface_occluder_thresholdface_occluder_blurface_occluder_blendface_occluder_invert
Practical note:
- Useful when the target face is partially blocked by a microphone, hand, hair strand, or similar object.
- Start conservative: threshold near
0.5, blur near5.
debug_enableddebug_dirdebug_startdebug_endmaterial_change_mad_threshold
Practical note:
- Use debug frame dumps to inspect crops, target selection, and post-swap changes without committing to a full long encode.
These still exist in the shared face pipeline surface:
face_comp_mask_modeface_comp_geom_expandface_comp_mask_erodeface_comp_mask_dilateface_comp_mask_blurface_comp_blend_modeface_comp_color_transferface_comp_face_scaleface_comp_debug
Practical note:
- These are still useful for backends that genuinely use the shared compositor path.
- For the current native InSwapper / HyperSwap / SimSwap flows, they are not the primary tuning levers.
- Start here if you want the most reliable baseline
- Usually runs fine without enhancer
- Good default for “is the rest of the face-swap pipeline healthy?” testing
- Use the native HyperSwap worker path
- Start without enhancer and without occluder
- Turn on landmark refinement if edge coverage or crop geometry needs help
- Use the native SimSwap worker path
- Expect to use enhancer more often than with InSwapper / HyperSwap
- Start with enhancer enabled and moderate blend
- Do not try to force HyperSwap through the shared compositor path
- Do not assume compositor face-scale/mask shaping is the main quality fix for native paths
- Treat experimental pixel-boost work as separate from the stable native backend paths unless explicitly validated
gRestorer supports SBS (Left/Right) videos, including a seam-safe ROI mode so restored regions don’t create a visible “split seam” down the center line.
In SBS, the left and right views meet at a vertical boundary. If the detector produces an ROI that crosses that boundary, you can get:
- discontinuities at the center seam, or
- a restored patch that “belongs” to only one eye.
To avoid this, gRestorer can enforce seam-safe ROIs:
- ROIs are clipped or adjusted so they do not straddle the SBS seam.
- Optionally, detection can be performed per-eye (det-split) so each half is analyzed independently.
- Keep seam-safe ROI handling enabled for SBS content.
- Keep
restoration.feather_radius = 0(paste-back already uses a blend mask). - If you see occasional ROI jitter near the seam, increase
roi_dilateslightly (+2 px).
grestorer --input Mosaic.ts --output Restored.mp4 --det-model D:\Models\lada\lada_vr_mosaic_detection_model_1.0.pt --sbs --sbs-layout lrHigh-res decode limits (NVDEC): Some SBS sources are 4320×2160 (5K). On some NVIDIA NVDEC generations, the max supported decode dimension is 4096 px per side. In that case PyNvVideoCodec will fail with an error like:
Error code : 801/Resolution not supported on this GPU
gRestorer will fall back to CPU decode so the run can continue, but throughput will be slower.
Some videos exceed the NVDEC decode limits of certain GPUs (common threshold: 4096 px max in width/height). Example: 4320×2160.
Symptoms:
- PyNvVideoCodec error like
Error code : 801/Resolution not supported on this GPU - Decode fails immediately (often on the first batch)
Behavior:
- gRestorer will automatically fall back to CPU decode to keep the pipeline running.
- Expect lower throughput due to CPU decode + GPU upload.
Workarounds:
- Use a GPU/NVDEC generation that supports the input resolution, or
- Downscale to ≤4096 width, or
- Pre-remux/convert problematic containers before processing.
Some players (including certain Quest playback stacks) are picky about the MP4 video sample entry for HEVC:
hev1can cause jerky / broken playback in some playershvc1is often the more compatible tag for MP4+HEVC
gRestorer now remuxes MP4 outputs with the correct tag:
- MP4 + HEVC ⇒
-tag:v hvc1 - MP4 + H.264 ⇒
-tag:v avc1
Quick check:
ffprobe -v error -select_streams v:0 -show_entries stream=codec_name,codec_tag_string,width,height -of default=nw=1 "VIDEO.mp4"How to fix an older file:
ffmpeg -hide_banner -y -i "in.mp4" -c copy -tag:v hvc1 "out.mp4"Transport streams can carry odd timestamp behavior and are more likely to trip up tooling. If you hit weird decode behavior, remux first (no re-encode):
ffmpeg -hide_banner -y -fflags +genpts -i "in.ts" -map 0 -c copy "in.mp4"Generate controlled SFW mosaics (fixed ROIs) for testing:
grestorer-add-mosaic `
--input "D:\Videos\Test\sample.mp4" `
--output "D:\Videos\Mosaic\sample-M3.mp4"ROIs can be specified either via CLI (--roi t,l,b,r, repeatable) or in config.json under synth_mosaic.rois.
config.json is optional; CLI flags override config values.
Unless explicitly specified, gRestorer operates on mosaic restoration.
Use:
"process": "mosaic"for mosaic detection/restoration"process": "face"for face detection / face-swap workflows
If process is omitted, the CLI defaults to mosaic blocks:
mosaic_detectionthen legacydetectionmosaic_restorationthen legacyrestoration
Face workflows must set:
{
"process": "face"
}Use debug_enabled as the runtime master switch. The debug object is only for debug settings/output locations.
Common mosaic knobs:
detection.batch_size,detection.imgsz,detection.conf_threshold,detection.iou_threshold,detection.fp16restoration.max_clip_length,restoration.clip_size,restoration.border_ratio,restoration.pad_mode,restoration.fp16roi_dilate— expand ROI boxes (pixels) before cropping/restoringencoder.*— codec/preset/profile/qp and remux behavior
Common face knobs:
{
"process": "face",
"restorer": "face_swap",
"source_face_path": "D:\Faces\source.jpg",
"swap_model_path": "D:\Models\faceswap\inswapper_128.onnx",
"swap_backend": "auto",
"swap_input_size": 256,
"swap_provider": "cuda",
"landmark_refiner_enabled": false,
"landmark_refiner_model": "2dfan4",
"landmark_refiner_model_path": "",
"landmark_refiner_provider": "auto",
"landmark_refiner_score": 0.5,
"face_enhancer_enabled": false,
"face_enhancer_model_path": "",
"face_enhancer_provider": "auto",
"face_enhancer_blend": 80,
"face_occluder_enabled": false,
"face_occluder_model_path": "",
"face_occluder_provider": "auto",
"face_occluder_threshold": 0.5,
"face_occluder_blur": 5,
"face_occluder_blend": 100,
"face_occluder_invert": false,
"fs_debug_enabled": false,
"fs_debug_dir": "fs_debug",
"fs_debug_start": -1,
"fs_debug_end": -1,
"fs_material_mad": 1.0
}Paste-back uses a blend mask to reduce visible ROI boundaries on the mosaic path. If you still see seams:
- keep
restoration.feather_radiusat0(recommended) - optionally increase
roi_dilateslightly (+2 px)
The pipeline reports:
- per-stage timings (
decode / det / track / restore / encode) - processing time without mux
- total time with mux (FFmpeg remux duration shown separately)
ffprobe -v error -select_streams v:0 -count_frames `
-show_entries stream=nb_read_frames -of default=nk=1:nw=1 "VIDEO.mp4"If you see seg mask indexing errors with newer Ultralytics/Torch combos:
- Pin to
ultralytics==8.3.243 - Install CUDA torch first (
torch==2.9.1,torchvision==0.24.1) usingrequirements.torch-cu128.txt
- Increase
detection.imgsz(e.g., 640 → 1280) - For synth mosaics, use a sufficiently large mosaic block size so artifacts survive scaling
- First validate backend + model + source face with InSwapper
- Then test HyperSwap / SimSwap with enhancer and occluder off
- Use debug frame dumps to inspect target face selection and swap output before adding post-processing
- If SimSwap looks structurally right but soft, enable enhancer before changing anything else
This project draws heavily from:
- lada – for the detection and restoration models and the original pipeline.
- BasicVSR++ – for the underlying video restoration architecture.
- InsightFace / InSwapper – for the InSwapper face-swap path.
- FaceFusion – for practical integration patterns for HyperSwap / SimSwap native worker flows.
Please check the upstream projects for full training code, original implementations, and model weights.