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:
- 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.
- CICP Fallback: Even when an ICC profile is
embedded,
libavifstill 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,libavifattempts 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.