How libavif Handles AV1 Color Primaries

This article explains how the libavif library decodes, interprets, and manages color primaries specified within an AV1 bitstream. It covers how libavif extracts color metadata using Coding-Independent Code Points (CICP), synchronizes this data between the AV1 payload and the ISOBMFF container, resolves conflicts with ICC profiles, and exposes these properties to developers through its API.

Parsing CICP Values from the AV1 Bitstream

AV1 bitstreams define color properties in the Sequence Header OBU (Sequence Header Open Bitstream Unit) under the color_config syntax element. Rather than saving custom color matrices directly, AV1 utilizes Coding-Independent Code Points (CICP) as defined by the ITU-T H.273 specification.

When decoding an AVIF image, libavif passes the raw bitstream to an underlying AV1 decoder library, such as dav1d or aom. The decoder parses the sequence header and extracts the integer code point representing the Color Primaries (for example, 1 for BT.709, 9 for BT.2020, or 13 for sRGB/AdobeRGB-equivalent primaries). This extracted integer is then handed back to libavif.

Synchronization Between Container and Bitstream

An AVIF file is not just a raw AV1 bitstream; it is packaged inside an ISOBMFF (ISO Base Media File Format) container. This container also contains color metadata stored within the Color Information (colr) box.

To maintain consistency and prevent rendering bugs across different image viewers, libavif enforces strict alignment between the container and the bitstream: * During Encoding: When you pass color primary configurations to the libavif encoder, it writes the corresponding CICP values to both the AV1 sequence header and the ISOBMFF colr box. * During Decoding: libavif reads both sources. If there is a mismatch between the color primaries specified in the container’s colr box and the AV1 bitstream’s sequence header, libavif typically prioritizes the container-level metadata to dictate how the image is presented to the user, though it provides APIs to inspect both.

Interaction with ICC Profiles

AVIF allows images to include an ICC (International Color Consortium) profile payload for advanced color management, alongside the standard CICP color primaries. libavif manages the relationship between these two systems using a clear hierarchy:

  1. ICC Profile Dominance: If an ICC profile is present in the AVIF container, color-managed software should use the ICC profile for rendering, as it offers a highly precise, custom color characterization.
  2. CICP Fallback: Even when an ICC profile is embedded, libavif still requires valid CICP color primaries to be written to both the container and the AV1 bitstream. These serve as a fallback for simpler decoders that do not support full ICC color management. In this scenario, libavif attempts to set the CICP primaries to the closest matching standard color space (such as BT.709 or BT.2020) representing the ICC profile.

Accessing Color Primaries in the libavif API

For developers integrating libavif, the decoded color primaries are exposed directly through the avifImage structure.

Once an image is successfully parsed, the color primaries can be read via the colorPrimaries field (typed as the avifColorPrimaries enum). This enum maps directly to the H.273 CICP values:

// Example of checking color primaries in libavif
if (image->colorPrimaries == AVIF_COLOR_PRIMARIES_BT2020) {
    // Handle BT.2020 wide color gamut rendering
} else if (image->colorPrimaries == AVIF_COLOR_PRIMARIES_BT709) {
    // Handle standard sRGB/BT.709 rendering
}

By cleanly separating bitstream parsing, container validation, and fallback logic, libavif ensures that AV1 color primaries are preserved and accurately translated for rendering engines.