FFmpeg Colorspace Filter: High-Precision Conversion

The FFmpeg colorspace filter provides mathematically accurate color conversions between various broadcast and digital standards, including BT.601, BT.709, and BT.2020. Unlike the standard scale filter, which primarily handles resolution and simple color matrix shifts, the colorspace filter processes color primaries, transfer characteristics, and matrix coefficients using internal high-precision 14-bit to 16-bit arithmetic. This guide demonstrates how to configure the colorspace filter to perform high-precision conversions while preventing banding, clipping, and color shifts.

Core Concepts of the colorspace Filter

Accurate color conversion requires defining four distinct properties:

  1. Matrix Coefficients (space): How color differences are derived from RGB (e.g., bt709, bt601, bt2020nc).
  2. Color Primaries (primaries): The chromaticity coordinates of the red, green, and blue reference points (e.g., bt709, bt2020, smpte170m).
  3. Transfer Characteristics (trc): The gamma curve or electro-optical transfer function (e.g., bt709, iec61966-2-1 for sRGB, smpte2084 for PQ).
  4. Range (range): Limited/broadcast range (tv) or full range (pc).

Enabling High-Precision Processing

To maximize mathematical precision and avoid truncation artifacts, follow these rules:

  • Disable Fast Mode: By default, the filter may use approximate calculations. Setting fast=0 forces full-precision calculations.
  • Enable High-Quality Dithering: When reducing bit depth, use dither=fsb (Floyd-Steinberg) to prevent banding.
  • Upsample Bit Depth Before Filtering: If your input is 8-bit, convert it to 10-bit or 16-bit planar format using the format filter before applying colorspace. This gives the filter extra mathematical headroom.

Example: High-Precision BT.601 (SD) to BT.709 (HD)

Standard definition footage typically uses BT.601 colorimetry. When upscaling or remastering to BT.709, an accurate conversion is required to prevent green/red shifts.

ffmpeg -i input_sd.mp4 -vf "
  format=yuv422p10le,
  colorspace=
    iall=bt601-6-625:
    all=bt709:
    fast=0:
    dither=fsb,
  format=yuv420p
" -c:v libx264 -crf 18 output_hd.mp4

Breakdown of the Filtergraph:

  • format=yuv422p10le: Promotes the video to 10-bit 4:2:2 to eliminate rounding errors during processing.
  • iall=bt601-6-625: Explicitly sets the input matrix, transfer curve, and primaries to PAL BT.601 (use smpte170m for NTSC).
  • all=bt709: Targets BT.709 matrix, transfer curve, and primaries.
  • fast=0: Disables approximations.
  • dither=fsb: Applies Floyd-Steinberg dithering during the internal conversion.
  • format=yuv420p: Safely downsamples back to 8-bit 4:2:0 for delivery.

Example: Detailed Parameter Mapping

When the input metadata is incomplete or when converting specific components (e.g., keeping sRGB transfer characteristics but changing primaries), specify properties individually:

ffmpeg -i input.mov -vf "
  format=yuv444p16le,
  colorspace=
    ispace=bt2020nc:
    iprimaries=bt2020:
    itrc=arib-std-b67:
    irange=tv:
    space=bt709:
    primaries=bt709:
    trc=bt709:
    range=tv:
    fast=0:
    dither=fsb,
  format=yuv420p10le
" -c:v libx265 -crf 20 output_sdr.mp4

In this command:

  • ispace, iprimaries, itrc, and irange explicitly define the input as HLG BT.2020 limited range.
  • space, primaries, trc, and range define the output as BT.709 SDR limited range.
  • format=yuv444p16le ensures processing occurs at full 4:4:4 chroma resolution and 16-bit depth.

Metadata Flagging

FFmpeg filters process raw pixel data, but players rely on container and bitstream metadata to read colors correctly. Always mirror your filter settings using encoder flags to ensure accurate playback:

ffmpeg -i input.mp4 -vf "colorspace=all=bt709:fast=0" \
  -c:v libx264 \
  -color_primaries bt709 \
  -color_trc bt709 \
  -colorspace bt709 \
  -color_range tv \
  output.mp4