Open HDR to SDR Converter
FFmpeg · libplacebo/Vulkan · HandBrakeCLI

Convert HDR video to SDR, simple enough for Grandma. No command line, no guesswork.

A desktop tone-mapping tool for people who care which curve they're using — standard FFmpeg, true BT.2390 on the GPU, or HandBrakeCLI, with the exact command always visible. 10-bit and 12-bit output included, free.

Open HDR to SDR Converter app window, showing Files, Source analysis, Progress and Controls on the left, and Conversion settings on the right.
Backends

Three ways to tone-map, pick per file

Same source video, three genuinely different pipelines. Nothing is hidden behind an "auto" button — the backend and curve you choose are the exact ones that run.

CPU · Standard

Standard FFmpeg

The classic tonemap filter. Fast, works everywhere FFmpeg does, no GPU required.

  • Hable, Reinhard, Mobius curves
  • Pro mode adds Linear, Gamma, Clip, and a direct "None" pass
GPU · Vulkan

libplacebo / BT.2390

Runs the real ITU-R BT.2390 EETF on the GPU via libplacebo, the same curve reference HDR-to-SDR grades are built around.

  • BT.2390 by default
  • Pro mode unlocks BT.2446A, ST2094-10, ST2094-40 (HDR10+), and Auto
Experimental

HandBrakeCLI

An alternate encode path through HandBrakeCLI for cases where its own pipeline behaves better on a given source.

  • Same resolution/encoder controls
  • Own progress parsing, shown live in Activity
Controls

Everything a real conversion needs to get right

Built around the parts of a tone-mapping job that actually go wrong on real footage: the wrong curve, the wrong encoder, or a process that steals the whole machine while it runs.

Resolution presets

Source (no scaling), 4K, 1440p, 1080p, 720p, 480p, or a custom width/height.

Encoder choice

x264/x265 on CPU, or hardware encode via NVIDIA NVENC, AMD AMF, or Apple VideoToolbox, in H.264 or H.265.

10-bit & 12-bit output

Free, no license required. 10-bit works with any H.265 encoder (CPU or hardware); 12-bit is available via libx265 on CPU — the app only shows encoders that actually support the bit depth you picked.

Pro mode

Opens the full CRF/CQ range (0–51), a brightness offset control, and the extra tone-map curves — kept out of the way until you ask for them.

Hardware-accelerated decode

CUDA / DXVA2 / VideoToolbox decode for the FFmpeg backend, so the GPU is doing the reading as well as the tone-mapping.

Process priority

Efficiency, Balanced, or Performance — maps straight to OS process niceness, so a long batch doesn't have to lock up the rest of your machine.

Activity & Capabilities

A collapsible live log streams the actual FFmpeg/HandBrake output and progress; a Capabilities panel reports what's detected on your system — FFmpeg, Vulkan, HandBrakeCLI — before you hit convert.

One-click setup on Windows

Missing FFmpeg or HandBrakeCLI is installed via winget from inside the app, with install output streamed into Activity.

Download

Get the app

A Windows build if you just want to run it, or the source if you're on macOS/Linux or want to read the code first.

Windows

Windows (.exe)

Single-file build, no Python required. FFmpeg is still needed separately — or install it in-app via winget.

Always the newest release · Windows 10/11

Source

Source code

Requires Python 3.10+ and pip install -r requirements.txt. Runs on Windows, macOS, and Linux.

MIT licensed · main branch

Documentation

Install & usage guide

The app is a single PySide6 script. No installer, no background service — you run it, it shells out to FFmpeg (and optionally HandBrakeCLI) directly.

Requirements

What needs to be on the machine before you launch it.

ComponentNeeded for
Python 3.10+Running the app itself
PySide6The Qt-based UI
FFmpegStandard and GPU tone-mapping backends
Vulkan-capable GPU + driversThe libplacebo/BT.2390 backend specifically
HandBrakeCLI (optional)The experimental HandBrake backend
psutil (optional)Nicer process-priority handling

Install & run

Three commands, then you're looking at the window.

# 1. Get the script and its Python dependencies
pip install PySide6 psutil

# 2. Make sure FFmpeg is on your PATH
ffmpeg -version

# 3. Launch
python hdr_to_sdr_gui_qt.py
Windows: if FFmpeg or HandBrakeCLI aren't found, open the Capabilities panel and use "Install missing (winget)" instead of installing them by hand.

Basic workflow

From HDR source file to SDR output.

  1. Pick the source file. Any HDR container FFmpeg can read.
  2. Choose a backend and curve. BT.2390 on GPU is the sane default; switch to Standard FFmpeg if you don't have a Vulkan-capable GPU.
  3. Set resolution and encoder. Leave resolution on "Source" to keep the original frame size, or pick a preset to downscale during the same pass.
  4. Adjust quality, or enable Pro mode for full CRF/CQ range and a brightness offset.
  5. Convert, and watch progress and the live FFmpeg/HandBrake output in Activity.

Choosing a curve

All of these are real, documented FFmpeg/libplacebo tone-mapping options — nothing here is invented.

CurveBackendWhen to reach for it
BT.2390GPUDefault choice — the reference EETF most HDR-to-SDR grades target
HableCPUFilmic rolloff, no GPU needed
Reinhard / MobiusCPUSofter highlight rolloff alternatives to Hable
BT.2446AGPU · ProBroadcast-oriented alternative to BT.2390
ST2094-10 / ST2094-40GPU · ProDynamic tone-mapping; ST2094-40 uses HDR10+ metadata when present
Linear / Gamma / Clip / NoneCPU · ProDiagnostic or manual-grading passes, not general use

Troubleshooting

The Capabilities panel is the first stop — it reports exactly what was detected before you file this as a bug.

  • BT.2390 (GPU) option greyed out — no Vulkan-capable device was detected; use a Standard FFmpeg curve instead.
  • HandBrakeCLI backend missing — it's optional and only appears once HandBrakeCLI is found on your PATH.
  • Conversion feels like it's stealing the machine — drop Process priority to Efficiency.