# How helpers/grade.py Handles HDR Content in the Video-Use Pipeline

> Learn how helpers/grade.py processes SDR video after HDR content is tonemapped to Rec.709 by render.py and ffmpeg, ensuring efficient video-use pipeline operations. Unlock HDR compatibility insights.

- Repository: [Browser Use/video-use](https://github.com/browser-use/video-use)
- Tags: internals
- Published: 2026-06-30

---

**helpers/grade.py does not process HDR content directly; instead, it operates exclusively on SDR video after the upstream render.py module converts HDR sources to Rec.709 using ffmpeg's zscale tonemapping.**

The [`helpers/grade.py`](https://github.com/browser-use/video-use/blob/main/helpers/grade.py) module in the video-use repository provides automated color grading for video clips, but its architecture deliberately delegates HDR processing to other components. Understanding this separation of concerns is essential for developers working with mixed SDR and HDR source material in the browser-use video pipeline.

## The Scope of helpers/grade.py: SDR-Only Color Grading

The [`grade.py`](https://github.com/browser-use/video-use/blob/main/grade.py) module focuses solely on **SDR color correction** using ffmpeg's `eq` filter. It implements two distinct grading modes:

- **Preset mode** – Applies predefined filter chains (e.g., `warm_cinematic`) via `get_preset()`
- **Auto mode** – Analyzes clip statistics and generates subtle corrections via `auto_grade_for_clip()`

Neither mode contains HDR detection logic or tone-mapping capabilities. The module assumes all input video has already been normalized to standard dynamic range before processing begins.

## The Auto-Grading Workflow

When using automatic grading, [`helpers/grade.py`](https://github.com/browser-use/video-use/blob/main/helpers/grade.py) executes a three-stage analysis pipeline that remains agnostic to HDR metadata:

1. **Frame Sampling** – The `_sample_frame_stats` function invokes ffmpeg `signalstats` to extract Y (luma) and saturation values from sampled frames, normalizing them to a 0-1 range regardless of source bit-depth.

2. **Statistical Analysis** – The code maps contrast adjustments to `y_range`, gamma corrections to `y_mean`, and saturation tweaks to `sat_mean`, capping all changes at **±8%** to prevent dramatic alterations.

3. **Filter Application** – The `apply_grade` function constructs an ffmpeg command with `-vf <filter>`; if no adjustments are needed, it copies the stream directly using `-c copy`.

This workflow operates on raw pixel values without interpreting HDR transfer functions like PQ (SMPTE 2084) or HLG (ARIB STD-B67).

## HDR Handling in helpers/render.py

HDR detection and conversion occur upstream in [`helpers/render.py`](https://github.com/browser-use/video-use/blob/main/helpers/render.py), which ensures [`grade.py`](https://github.com/browser-use/video-use/blob/main/grade.py) receives only SDR content. The render module implements HDR handling through two specific mechanisms:

- **HDR Detection** – The `is_hdr_source` function queries ffprobe for `color_transfer` metadata, identifying HDR sources by checking for `"smpte2084"` (PQ) or `"arib-std-b67"` (HLG) values.

- **Tone-Mapping Chain** – When HDR is detected, [`render.py`](https://github.com/browser-use/video-use/blob/main/render.py) prepends the `TONEMAP_CHAIN` to the filter graph before calling any grade.py functions. This chain uses ffmpeg's zscale filter to convert HDR to Rec.709 SDR.

Only after this conversion does the pipeline invoke `auto_grade_for_clip` or `apply_grade` for final color touches.

## Practical Code Examples

The following examples demonstrate how HDR handling remains transparent to grade.py operations:

```python

# Apply a preset grade (HDR-agnostic)

from helpers.grade import get_preset, apply_grade
from pathlib import Path

preset_filter = get_preset("warm_cinematic")
apply_grade(Path("input.mp4"), Path("output.mp4"), preset_filter)

```

```python

# Auto-grade a clip (operates on assumed SDR)

from helpers.grade import auto_grade_for_clip

filter_str, stats = auto_grade_for_clip(Path("hdr_source.mp4"))

# Note: Without render.py preprocessing, this analyzes HDR values as SDR

```

```python

# Full pipeline with HDR conversion

# Run via render.py which handles HDR detection automatically:

# python helpers/render.py edl.json -o final.mp4

# render.py detects HDR, applies TONEMAP_CHAIN, then grades

```

## Summary

- **helpers/grade.py** performs color grading exclusively on SDR content using ffmpeg's `eq` filter for brightness, contrast, and saturation adjustments.
- **Auto-grade analysis** samples frames via `signalstats`, normalizes values to 0-1, and applies corrections capped at ±8%.
- **HDR detection** occurs in [`helpers/render.py`](https://github.com/browser-use/video-use/blob/main/helpers/render.py) via `is_hdr_source`, which checks ffprobe's `color_transfer` for SMPTE 2084 or ARIB STD-B67.
- **Tone-mapping** happens upstream through [`render.py`](https://github.com/browser-use/video-use/blob/main/render.py)'s `TONEMAP_CHAIN`, converting HDR to Rec.709 before grade.py processes the video.

## Frequently Asked Questions

### Does helpers/grade.py support native HDR grading?

No. The module intentionally excludes HDR logic and imports no tone-mapping libraries. It processes only SDR streams using standard ffmpeg `eq` filters, leaving HDR handling to the preprocessing stage in [`helpers/render.py`](https://github.com/browser-use/video-use/blob/main/helpers/render.py).

### How does the pipeline prevent HDR content from reaching grade.py unconverted?

The [`render.py`](https://github.com/browser-use/video-use/blob/main/render.py) module acts as a gatekeeper. Its `is_hdr_source` function parses ffprobe output to detect HDR transfer characteristics. When found, it automatically inserts a zscale-based tonemapping chain that converts the source to Rec.709 SDR before invoking any grade.py functions.

### What would happen if grade.py processed HDR video directly without conversion?

Without the `TONEMAP_CHAIN` preprocessing step, `auto_grade_for_clip` would treat PQ-encoded luma values (up to 10,000 nits) or HLG values as standard SDR data (0-1 range). This would cause the statistical analysis to miscalculate corrections, likely producing clipped highlights or incorrect gamma adjustments since the `eq` filter lacks HDR-aware scaling.

### Where are the HDR tone-mapping parameters configured in the codebase?

The HDR conversion parameters reside in [`helpers/render.py`](https://github.com/browser-use/video-use/blob/main/helpers/render.py) within the `TONEMAP_CHAIN` constant and the `is_hdr_source` function. These components define the zscale filter settings and the specific color_transfer strings (`"smpte2084"` and `"arib-std-b67"`) that trigger HDR-to-SDR conversion before grading begins.