Configuring Dither, Filter, and Range in FFmpeg zscale

The zscale filter in FFmpeg uses the zimg library to perform high-precision video scaling, pixel format conversion, and colorspace modifications. This article provides a direct, practical guide on how to configure the filter (scaling algorithm), dither (quantization error diffusion), and range (color dynamic range) parameters inside FFmpeg's zscale filter to achieve optimal video quality and prevent common artifacts like banding or incorrect contrast.

Understanding the Parameters

When using zscale, multiple parameters are chained together using colons (:) within the filter graph:

  • filter: Sets the resampling algorithm used for scaling image dimensions.
  • dither: Controls the dithering algorithm applied when reducing color bit-depth, preventing color banding.
  • range / rangein: Controls the output and input quantization ranges (limited vs. full range).

Configuring the Scaling filter

The filter parameter dictates which interpolation algorithm calculates pixel values during resizing.

Common Values:

  • bicubic (Default: balanced sharpness and speed)
  • bilinear (Faster, but softer)
  • lanczos (High sharpness, ideal for downscaling)
  • spline16 / spline36 (Smooth, minimizes ringing artifacts)
  • point (Nearest-neighbor, useful for pixel art)

Syntax Example:

zscale=w=1920:h=1080:filter=spline36

Configuring the dither Parameter

Dithering introduces subtle noise to mask quantization errors when lowering bit-depth (for instance, converting 10-bit HDR content down to standard 8-bit SDR).

Available Options:

  • none: Disables dithering (fastest, but may cause visible color banding).
  • ordered: Applies ordered spatial dithering.
  • random: Adds uniform random noise.
  • error_diffusion: Uses Floyd-Steinberg error diffusion (highest quality for color transitions and gradients).

Syntax Example:

zscale=dither=error_diffusion

Configuring the Color range

The range parameter defines the dynamic range (quantization range) for luminance and chrominance values. It prevents crushed shadows or washed-out highlights caused by mismatched full/limited range tags.

Values:

  • input / unspecified: Keeps the detected input range.
  • limited (or tv): Studio range (Y: 16–235, Cb/Cr: 16–240 in 8-bit). Standard for broadcast and standard SDR/HDR video.
  • full (or pc): Full range (0–255 in 8-bit). Common for PC monitors, photography, and JPEG images.

You can set both the expected input range (rangein) and the target output range (range):

Syntax Example:

zscale=rangein=full:range=limited

Combining Filter, Dither, and Range in a Complete Command

To scale a video down to 1080p, apply a Spline36 algorithm, convert from full range to limited range, and apply error diffusion dithering, configure the command as follows:

ffmpeg -i input.mp4 -vf "zscale=w=1920:h=1080:filter=spline36:rangein=full:range=limited:dither=error_diffusion" -c:v libx264 -crf 18 output.mp4

In this pipeline:

  1. w=1920:h=1080 sets the target frame size.
  2. filter=spline36 sharpens the image cleanly with low ringing.
  3. rangein=full:range=limited remaps 0–255 levels down to 16–235 levels correctly.
  4. dither=error_diffusion ensures smooth gradients across areas like skies or shadows where banding typically occurs.