Garionhk/RTX-VSR-Studio

Windows GUI and CLI for upscaling video with NVIDIA RTX Video Super Resolution (no ComfyUI or PyTorch needed). Resumable segments for long films, batch queue, before/after preview, 720p–4K presets that keep aspect ratio, H.264/HEVC/ProRes/DNxHR output, never overwrites.

Python

24

1 commits

updated Oct 5, 2026

See the code

See what people are saying

SourceMessageScoreDate

I made a standalone Windows app for NVIDIA RTX Video Super Resolution, no ComfyUI needed, and it can resume a 2-hour film if it crashes (r/StableDiffusion)

I've been upscaling old footage with RTX Video Super Resolution in ComfyUI, and it works fine for short clips. But for a full-length film it's painful. If it crashes or you cancel at the 90 minute mark, you start again from zero. So I made RTX VSR Studio. It's a normal Windows app that calls…

1

Oct 8, 2026

README

RTX VSR Studio

A standalone Windows GUI for upscaling video with NVIDIA RTX Video Super Resolution. Built for long jobs: a 2-hour feature is processed as a stream of resumable segments, so a crash or a cancel costs minutes, not hours.

Calls NVIDIA's nvidia-vfx (Video Effects SDK) directly. No ComfyUI, no node graph, no PyTorch.

What it does

  • Pick a target resolution — 720p, 1080p, 1440p or 4K — and it works out the pixels. Each preset is a bounding box, so a 1.85:1 or 2.39:1 film keeps its shape instead of being stretched to fill 16:9. Scale factors and exact pixel sizes are still there under Advanced.
  • AI upscaling at any ratio, or clean up at native resolution with the denoise / deblur / high-bitrate modes.
  • Batch queue — add files, set them up, walk away.
  • Before/after preview — render one frame at a chosen timestamp and drag a split to judge quality before committing to a long run.
  • Time range — process 30 seconds to check settings instead of 2 hours.
  • Resumable — kill it, lose power, cancel; rerun the same job and it picks up at the exact frame it reached.
  • Editor-ready output — H.264/HEVC in .mp4, or ProRes / DNxHR in .mov. Everything imports natively into Final Cut Pro and DaVinci Resolve, tagged bt709 so colours do not shift. See docs/OUTPUT_FORMATS.md.
  • Denoise and sharpening around the upscale, as real ffmpeg filter stages.
  • Content presets — Balanced, Anime, Film, Screen capture, Old/DVD, Editing/ProRes — that fill in every setting for you.
  • Simple and Advanced modes, so the everyday case is three controls.
  • Never overwrites. If the output name is taken, the job writes name (2).mp4 beside it instead. Existing renders are safe.
  • Audio and subtitles are copied through untouched.

Requirements

GPUNVIDIA with Tensor Cores — Turing (RTX 20-series) or newer
Driver570.65 or later on Windows
OS64-bit Windows 10 or later
Python3.10+ (only when running from source)
ffmpegon PATH, or ffmpeg.exe/ffprobe.exe in bin/

VRAM is not a constraint: frames are processed one at a time, so usage depends on frame size, not video length. A 1080p→4K job peaks around 1.6 GB, which leaves large headroom on an 8 GB card. A 2-hour film costs the same VRAM as a 2-second clip.

Running it

Double-click run.bat. On first run it creates the venv and installs everything (~1.4 GB, since nvidia-vfx pulls roughly 790 MB of NVIDIA DLLs), then launches the GUI. Afterwards it just launches.

No console window is left behind: the GUI runs under pythonw.exe and the launcher exits immediately. Since there is then nowhere to print, everything the app logs goes to rtxvsr.log beside the app, and an unexpected error raises a dialog rather than vanishing. Passing any argument (such as --self-test) keeps the console attached so you can read the output.

To build the standalone app, run build.bat. It refreshes the icon, stages ffmpeg, runs PyInstaller, then verifies the frozen build with --self-test and prints the report. Output lands in dist\RTX VSR Upscaler\.

build.bat onefile produces a single 869 MB .exe in dist-onefile\ instead. It works identically, but unpacks ~1.7 GB to %TEMP% on every launch, so it takes 12–16 s to open rather than 1–4 s. Convenient to hand to someone; the folder build is better for daily use. Numbers in docs/PACKAGING.md.

Manual equivalents:

py -3.12 -m venv .venv; .\.venv\Scripts\python.exe -m pip install -r requirements.txt
.\.venv\Scripts\python.exe -m rtxvsr.app.main

If anything misbehaves, check rtxvsr.log, then run the diagnostics — they check the SDK, the GPU backend, a real upscale and NVENC, and say which one is broken:

.\run.bat --self-test

To ask the app what it makes of one specific file — useful when a single file fails and others work:

.\run.bat --probe "C:\path\to\video.mp4"

Both flags work on the built .exe too; the windowed build shows the report in a dialog, since it has no console to print to.

"could not be read" when adding a file? The commonest cause by far is adding a video that is still downloading. MP4 stores its index (the moov atom) at the end of the file, so a partially written download has no readable structure at all until it completes. The app now says exactly that instead of reporting a bare failure.

Command line

The CLI drives the same core code as the GUI.

.\.venv\Scripts\python.exe -m rtxvsr.cli input.mp4 output --preset 4K --format prores_422

Useful flags:

FlagMeaning
--probeprint source info and exit
-p, --preset720p, 1080p, 1440p, 4K — aspect ratio preserved
-f, --formath264, hevc, prores_lt, prores_422, prores_hq, dnxhr_hq
-q, --qualityHIGH, ULTRA, DENOISE_HIGH, DEBLUR_MEDIUM, ...
-s, --scalescale factor; or --size WxH / --fit WxH for exact control
--enc-presetNVENC speed/quality, p1 (fastest) to p7 (best)
--start / --endprocess only a time range, in seconds
--cqencoder quality target, lower is better (default 21)
--segment-framesframes per resumable segment (default 2000)
--tonemapconvert HDR/10-bit sources to SDR instead of refusing
--no-resumeignore existing progress and start over
--overwritereplace an existing output instead of writing name (2)

Quality modes

Modes come from the SDK and fall into four groups:

  • Upscale — BICUBIC, LOW, MEDIUM, HIGH, ULTRA. Trained on typical compressed video; removes compression artifacts while upscaling.
  • High-bitrate upscale — HIGHBITRATE_*. For clean sources (ProRes, high-quality H.265) where artifact suppression would only soften real detail.
  • Denoise — DENOISE_*. Native resolution only.
  • Deblur — DEBLUR_*. Native resolution only.

The GUI locks sizing to 1x when a denoise or deblur mode is selected, because the SDK rejects a differing output size for those.

Measured performance

RTX A4000, 1080p→4K:

StageRate
VSR alone, HIGH109 fps
VSR alone, ULTRA80 fps
End to end, HIGH (NVENC-bound)~40 fps

VSR is not the bottleneck — NVENC is. A 2-hour 24 fps film takes roughly 1.2 hours end to end. Full numbers in docs/PHASE0_SPIKE.md.

Limitations

  • 8-bit SDR only. The SDK does not process HDR or 10-bit. Such sources are refused by default; --tonemap converts to SDR bt709 first, which visibly changes the grade. This is deliberately opt-in rather than silent.
  • There is no 4x upscale limit. NVIDIA's sample script documents 1-4x, but the SDK itself has none: 5x, 6x and 21x all run correctly. Ratios above 4x are logged as a note, since beyond that detail is invented rather than recovered. The real cap is a 16384 px output edge.
  • Upscaling is single-pass at any ratio. Chaining passes was measured and is both worse and slower — see docs/MULTIPASS.md.
  • Variable-frame-rate sources are normalised to CFR on decode. That is required for correct A/V sync, but it does alter timing on genuinely VFR content.
  • AV1 encoding needs an Ada or newer GPU. ffmpeg advertises av1_nvenc on every build; the app probes it and hides it when the hardware cannot do it.
  • ProRes and DNxHR encode on the CPU. NVENC cannot produce them, so those formats are slower than H.264/HEVC and produce files 10-15x larger.
  • Free DaVinci Resolve on Windows cannot decode HEVC. That is a Studio-only feature; use H.264 or an editing codec instead.

Output safety

An existing file is never overwritten. Before a job starts, the output name is resolved against the folder: if movie_4K_high.mp4 is taken, the job writes movie_4K_high (2).mp4, then (3), and so on. The GUI shows the name it will actually use, and says which file it is stepping around.

Two details make this safe rather than merely usual:

  • Resume still works. The name is chosen before the working directory is derived from it, and a partial job has not written its output yet — so a killed run and its resume agree on the same name and the same segments. This holds even when the plain name was already taken and the run is working under (2); there is an end-to-end test for exactly that case.
  • The check cannot be raced. Beyond picking a free name, the final mux is run with ffmpeg's -n, so ffmpeg itself refuses to write over anything that appears in the gap between the check and the write.

--overwrite opts out, for scripted use where replacing the previous result is the point. The GUI has no such control on purpose.

Interface

RTX VSR Studio

Built from the RTX VSR Studio design canvas — see docs/UI_REDESIGN.md for what was implemented, what was adapted, and what was deliberately left out.

Layout

rtxvsr/
  core/          engine, GPU-free where possible
    dimensions.py    resolution presets, alignment, the 16K workaround
    integrity.py     channel-collapse detection
    jobspec.py       job description and quality metadata
    naming.py        never-overwrite output naming
    gpu_backend.py   CuPy (default) / torch frame transfer
    vsr_engine.py    nvvfx.VideoSuperRes lifecycle
    formats.py       output codecs and containers
    filters.py       denoise / sharpen ffmpeg stages
    presets.py       content presets
    telemetry.py     GPU utilisation for the footer
    ffmpeg_io.py     probe, raw frame IO, concat, mux
    segments.py      resumable manifest
    pipeline.py      threaded decode -> VSR -> encode
  app/           PySide6 GUI (never imported by core)
    main.py          entry point, logging, --self-test / --probe
    main_window.py   the main window, Simple and Advanced modes
    preview_dialog.py  before/after split preview
    job_model.py     queue job state
    worker.py        background job thread
    queue_view.py    queue cards
    widgets.py       segmented controls, sliders, toggles, tips
    theme.py         design tokens and stylesheet
    resources.py     asset lookup (source and frozen builds)
    tips.py          help text
  cli.py
packaging/
  rtxvsr.spec      PyInstaller spec (folder or onefile via RTXVSR_ONEFILE)
  make_icon.py     regenerates icon.ico from icon.png
docs/            design notes, measurements, screenshots
tests/           unit and end-to-end tests
rtxvsr_gui.py    entry script for the frozen build
run.bat          create venv on first run, then launch
build.bat        build and self-test the standalone app

Generated and ignored by git: .venv/, bin/ (staged ffmpeg), build*/, dist*/, testdata/ and rtxvsr.log.

Tests

.\.venv\Scripts\python.exe -m pytest tests/test_core.py -q
.\.venv\Scripts\python.exe tests\test_resume_e2e.py
.\.venv\Scripts\python.exe tests\test_gui_e2e.py
  • test_core.py is GPU-free: sizing, the 16K workaround, collapse detection, manifest and resume logic. The two end-to-end tests need an NVIDIA GPU and ffmpeg on PATH. They generate their own clips in testdata/, so nothing needs to be checked in.

  • test_resume_e2e.py kills a running job partway and verifies the resumed run produces an exact, complete output.

  • test_gui_e2e.py drives the real GUI with a live Qt event loop: renders a preview, then runs a two-job queue to completion. This one matters more than it looks. Qt worker-thread lifetime bugs kill the process outright with STATUS_STACK_BUFFER_OVERRUN instead of raising, so only a run that finishes and exits 0 proves the threading is sound — constructing widgets and poking them without an event loop does not.

Licensing

This project's own code is Apache-2.0, with portions derived from ComfyUI-NVIDIA-RTX-VSR-Pro — see NOTICE.

nvidia-vfx and the DLLs it installs are NVIDIA proprietary. Review NVIDIA's terms before redistributing a frozen build.

ffmpeg
nvenc
nvidia
prores
pyside6
python
rtx-video-super-resolution
super-resolution
video-upscaling
windows

Garionhk/RTX-VSR-Studio

Windows GUI and CLI for upscaling video with NVIDIA RTX Video Super Resolution (no ComfyUI or PyTorch needed). Resumable segments for long films, batch queue, before/after preview, 720p–4K presets that keep aspect ratio, H.264/HEVC/ProRes/DNxHR output, never overwrites.

Python

24

1 commits

updated Oct 5, 2026

See the code

See what people are saying

SourceMessageScoreDate

I made a standalone Windows app for NVIDIA RTX Video Super Resolution, no ComfyUI needed, and it can resume a 2-hour film if it crashes (r/StableDiffusion)

I've been upscaling old footage with RTX Video Super Resolution in ComfyUI, and it works fine for short clips. But for a full-length film it's painful. If it crashes or you cancel at the 90 minute mark, you start again from zero. So I made RTX VSR Studio. It's a normal Windows app that calls…

1

Oct 8, 2026

README

RTX VSR Studio

A standalone Windows GUI for upscaling video with NVIDIA RTX Video Super Resolution. Built for long jobs: a 2-hour feature is processed as a stream of resumable segments, so a crash or a cancel costs minutes, not hours.

Calls NVIDIA's nvidia-vfx (Video Effects SDK) directly. No ComfyUI, no node graph, no PyTorch.

What it does

  • Pick a target resolution — 720p, 1080p, 1440p or 4K — and it works out the pixels. Each preset is a bounding box, so a 1.85:1 or 2.39:1 film keeps its shape instead of being stretched to fill 16:9. Scale factors and exact pixel sizes are still there under Advanced.
  • AI upscaling at any ratio, or clean up at native resolution with the denoise / deblur / high-bitrate modes.
  • Batch queue — add files, set them up, walk away.
  • Before/after preview — render one frame at a chosen timestamp and drag a split to judge quality before committing to a long run.
  • Time range — process 30 seconds to check settings instead of 2 hours.
  • Resumable — kill it, lose power, cancel; rerun the same job and it picks up at the exact frame it reached.
  • Editor-ready output — H.264/HEVC in .mp4, or ProRes / DNxHR in .mov. Everything imports natively into Final Cut Pro and DaVinci Resolve, tagged bt709 so colours do not shift. See docs/OUTPUT_FORMATS.md.
  • Denoise and sharpening around the upscale, as real ffmpeg filter stages.
  • Content presets — Balanced, Anime, Film, Screen capture, Old/DVD, Editing/ProRes — that fill in every setting for you.
  • Simple and Advanced modes, so the everyday case is three controls.
  • Never overwrites. If the output name is taken, the job writes name (2).mp4 beside it instead. Existing renders are safe.
  • Audio and subtitles are copied through untouched.

Requirements

GPUNVIDIA with Tensor Cores — Turing (RTX 20-series) or newer
Driver570.65 or later on Windows
OS64-bit Windows 10 or later
Python3.10+ (only when running from source)
ffmpegon PATH, or ffmpeg.exe/ffprobe.exe in bin/

VRAM is not a constraint: frames are processed one at a time, so usage depends on frame size, not video length. A 1080p→4K job peaks around 1.6 GB, which leaves large headroom on an 8 GB card. A 2-hour film costs the same VRAM as a 2-second clip.

Running it

Double-click run.bat. On first run it creates the venv and installs everything (~1.4 GB, since nvidia-vfx pulls roughly 790 MB of NVIDIA DLLs), then launches the GUI. Afterwards it just launches.

No console window is left behind: the GUI runs under pythonw.exe and the launcher exits immediately. Since there is then nowhere to print, everything the app logs goes to rtxvsr.log beside the app, and an unexpected error raises a dialog rather than vanishing. Passing any argument (such as --self-test) keeps the console attached so you can read the output.

To build the standalone app, run build.bat. It refreshes the icon, stages ffmpeg, runs PyInstaller, then verifies the frozen build with --self-test and prints the report. Output lands in dist\RTX VSR Upscaler\.

build.bat onefile produces a single 869 MB .exe in dist-onefile\ instead. It works identically, but unpacks ~1.7 GB to %TEMP% on every launch, so it takes 12–16 s to open rather than 1–4 s. Convenient to hand to someone; the folder build is better for daily use. Numbers in docs/PACKAGING.md.

Manual equivalents:

py -3.12 -m venv .venv; .\.venv\Scripts\python.exe -m pip install -r requirements.txt
.\.venv\Scripts\python.exe -m rtxvsr.app.main

If anything misbehaves, check rtxvsr.log, then run the diagnostics — they check the SDK, the GPU backend, a real upscale and NVENC, and say which one is broken:

.\run.bat --self-test

To ask the app what it makes of one specific file — useful when a single file fails and others work:

.\run.bat --probe "C:\path\to\video.mp4"

Both flags work on the built .exe too; the windowed build shows the report in a dialog, since it has no console to print to.

"could not be read" when adding a file? The commonest cause by far is adding a video that is still downloading. MP4 stores its index (the moov atom) at the end of the file, so a partially written download has no readable structure at all until it completes. The app now says exactly that instead of reporting a bare failure.

Command line

The CLI drives the same core code as the GUI.

.\.venv\Scripts\python.exe -m rtxvsr.cli input.mp4 output --preset 4K --format prores_422

Useful flags:

FlagMeaning
--probeprint source info and exit
-p, --preset720p, 1080p, 1440p, 4K — aspect ratio preserved
-f, --formath264, hevc, prores_lt, prores_422, prores_hq, dnxhr_hq
-q, --qualityHIGH, ULTRA, DENOISE_HIGH, DEBLUR_MEDIUM, ...
-s, --scalescale factor; or --size WxH / --fit WxH for exact control
--enc-presetNVENC speed/quality, p1 (fastest) to p7 (best)
--start / --endprocess only a time range, in seconds
--cqencoder quality target, lower is better (default 21)
--segment-framesframes per resumable segment (default 2000)
--tonemapconvert HDR/10-bit sources to SDR instead of refusing
--no-resumeignore existing progress and start over
--overwritereplace an existing output instead of writing name (2)

Quality modes

Modes come from the SDK and fall into four groups:

  • Upscale — BICUBIC, LOW, MEDIUM, HIGH, ULTRA. Trained on typical compressed video; removes compression artifacts while upscaling.
  • High-bitrate upscale — HIGHBITRATE_*. For clean sources (ProRes, high-quality H.265) where artifact suppression would only soften real detail.
  • Denoise — DENOISE_*. Native resolution only.
  • Deblur — DEBLUR_*. Native resolution only.

The GUI locks sizing to 1x when a denoise or deblur mode is selected, because the SDK rejects a differing output size for those.

Measured performance

RTX A4000, 1080p→4K:

StageRate
VSR alone, HIGH109 fps
VSR alone, ULTRA80 fps
End to end, HIGH (NVENC-bound)~40 fps

VSR is not the bottleneck — NVENC is. A 2-hour 24 fps film takes roughly 1.2 hours end to end. Full numbers in docs/PHASE0_SPIKE.md.

Limitations

  • 8-bit SDR only. The SDK does not process HDR or 10-bit. Such sources are refused by default; --tonemap converts to SDR bt709 first, which visibly changes the grade. This is deliberately opt-in rather than silent.
  • There is no 4x upscale limit. NVIDIA's sample script documents 1-4x, but the SDK itself has none: 5x, 6x and 21x all run correctly. Ratios above 4x are logged as a note, since beyond that detail is invented rather than recovered. The real cap is a 16384 px output edge.
  • Upscaling is single-pass at any ratio. Chaining passes was measured and is both worse and slower — see docs/MULTIPASS.md.
  • Variable-frame-rate sources are normalised to CFR on decode. That is required for correct A/V sync, but it does alter timing on genuinely VFR content.
  • AV1 encoding needs an Ada or newer GPU. ffmpeg advertises av1_nvenc on every build; the app probes it and hides it when the hardware cannot do it.
  • ProRes and DNxHR encode on the CPU. NVENC cannot produce them, so those formats are slower than H.264/HEVC and produce files 10-15x larger.
  • Free DaVinci Resolve on Windows cannot decode HEVC. That is a Studio-only feature; use H.264 or an editing codec instead.

Output safety

An existing file is never overwritten. Before a job starts, the output name is resolved against the folder: if movie_4K_high.mp4 is taken, the job writes movie_4K_high (2).mp4, then (3), and so on. The GUI shows the name it will actually use, and says which file it is stepping around.

Two details make this safe rather than merely usual:

  • Resume still works. The name is chosen before the working directory is derived from it, and a partial job has not written its output yet — so a killed run and its resume agree on the same name and the same segments. This holds even when the plain name was already taken and the run is working under (2); there is an end-to-end test for exactly that case.
  • The check cannot be raced. Beyond picking a free name, the final mux is run with ffmpeg's -n, so ffmpeg itself refuses to write over anything that appears in the gap between the check and the write.

--overwrite opts out, for scripted use where replacing the previous result is the point. The GUI has no such control on purpose.

Interface

RTX VSR Studio

Built from the RTX VSR Studio design canvas — see docs/UI_REDESIGN.md for what was implemented, what was adapted, and what was deliberately left out.

Layout

rtxvsr/
  core/          engine, GPU-free where possible
    dimensions.py    resolution presets, alignment, the 16K workaround
    integrity.py     channel-collapse detection
    jobspec.py       job description and quality metadata
    naming.py        never-overwrite output naming
    gpu_backend.py   CuPy (default) / torch frame transfer
    vsr_engine.py    nvvfx.VideoSuperRes lifecycle
    formats.py       output codecs and containers
    filters.py       denoise / sharpen ffmpeg stages
    presets.py       content presets
    telemetry.py     GPU utilisation for the footer
    ffmpeg_io.py     probe, raw frame IO, concat, mux
    segments.py      resumable manifest
    pipeline.py      threaded decode -> VSR -> encode
  app/           PySide6 GUI (never imported by core)
    main.py          entry point, logging, --self-test / --probe
    main_window.py   the main window, Simple and Advanced modes
    preview_dialog.py  before/after split preview
    job_model.py     queue job state
    worker.py        background job thread
    queue_view.py    queue cards
    widgets.py       segmented controls, sliders, toggles, tips
    theme.py         design tokens and stylesheet
    resources.py     asset lookup (source and frozen builds)
    tips.py          help text
  cli.py
packaging/
  rtxvsr.spec      PyInstaller spec (folder or onefile via RTXVSR_ONEFILE)
  make_icon.py     regenerates icon.ico from icon.png
docs/            design notes, measurements, screenshots
tests/           unit and end-to-end tests
rtxvsr_gui.py    entry script for the frozen build
run.bat          create venv on first run, then launch
build.bat        build and self-test the standalone app

Generated and ignored by git: .venv/, bin/ (staged ffmpeg), build*/, dist*/, testdata/ and rtxvsr.log.

Tests

.\.venv\Scripts\python.exe -m pytest tests/test_core.py -q
.\.venv\Scripts\python.exe tests\test_resume_e2e.py
.\.venv\Scripts\python.exe tests\test_gui_e2e.py
  • test_core.py is GPU-free: sizing, the 16K workaround, collapse detection, manifest and resume logic. The two end-to-end tests need an NVIDIA GPU and ffmpeg on PATH. They generate their own clips in testdata/, so nothing needs to be checked in.

  • test_resume_e2e.py kills a running job partway and verifies the resumed run produces an exact, complete output.

  • test_gui_e2e.py drives the real GUI with a live Qt event loop: renders a preview, then runs a two-job queue to completion. This one matters more than it looks. Qt worker-thread lifetime bugs kill the process outright with STATUS_STACK_BUFFER_OVERRUN instead of raising, so only a run that finishes and exits 0 proves the threading is sound — constructing widgets and poking them without an event loop does not.

Licensing

This project's own code is Apache-2.0, with portions derived from ComfyUI-NVIDIA-RTX-VSR-Pro — see NOTICE.

nvidia-vfx and the DLLs it installs are NVIDIA proprietary. Review NVIDIA's terms before redistributing a frozen build.

ffmpeg
nvenc
nvidia
prores
pyside6
python
rtx-video-super-resolution
super-resolution
video-upscaling
windows