-
Notifications
You must be signed in to change notification settings - Fork 208
CICP
For image formats, the most common way to signal a file format's color profile is using an ICC profile. AVIF supports ICC profiles, but AVIF also offers a simpler alternative, borrowed from the video encoding world. CICP is short for Coding-independent code points, which comes from the title of the publicly available H.273 standard. Even if your AVIF uses an ICC profile, the CICP values in the AVIF still play an important role in how your image is encoded.
For the remainder of this document:
-
YUV will be used interchangeably with (and instead of) YCbCr, despite it technically being only relevant for analog signals. As many other libraries and tooling use the term YUV,
libavif
does as well, despite it dealing entirely with digital signals. -
CP is short for Color Primaries, which defines a specific set of color primaries with a single enumerated value from Table 2 of H.273.
-
TC is short for Transfer Characteristics, which defines a transfer function with a single enumerated value from Table 3 of H.273.
-
MC is short for Matrix Coefficients, which defines a specific set of matrix coefficients as a single enumerated value from Table 4 of H.273. (This is a little trickier than just "matrix coefficients", but we'll get to that.)
-
CICP will refer to a triplet of numbers, each of which is simply an enumerated value from the 3 tables in H.273. They will be presented in the order CP/TC/MC, as this is the order in which they are explained in H.273, and the order the values are stored in an AVIF.
Note: When ffprobe
dumps the CICP values from a video, their ordering is MC/CP/TC (MC is moved to the front), for example:
yuv420p10le(tv, bt2020nc/bt2020/arib-std-b67)
The bt2020nc/bt2020/arib-std-b67
portion here are simply the 3 CICP values, where CP=bt2020(9)
, TF=arib-std-b67(18)
(HLG), and MC=bt2020nc(9)
. This would map to 9/18/9
(in CP/TC/MC order).
Despite MC being the third value in our CICP triplet, it makes sense to explain it first as it still plays a role even when you're using an ICC profile in an AVIF.
While there is no requirement that an image format stores their pixels in RGB(A), this is by far the most common usage and expectation, even if the image format's internals prefers something other than RGB. libavif
(and its tooling) allows people to work entirely in RGB(A), but convert to/from something else to either benefit from additional efficiency with AV1, or avoid conversion to maintain the original pixel values exactly. The MC value exists to provide this choice.
AV1 (as many video codecs) benefits from pixel data whose luma and chroma are separated, so the most common color space for encoding is YUV. For example, most JPEGs are internally stored as YUV, despite most endusers using JPEG entirely for RGB. The conversion between RGB and YUV is straightforward (see H.273), but requires a specific set of coefficients for R, G, and B when building the conversion matrix, which must match when converting back. This is where "Matrix Coefficients" gets its name.
However, there are color spaces other than YUV that might be useful for efficiency reasons, or to preserve the original data better. The MC value in H.273 is effectively overloaded/abused in this capacity, and certain values of MC will avoid the typical YUV conversion in favor of some other formula. As a simple example, setting MC to 0
signals Identity
, which signals that the values in the 3 planes (which are typically YUV) are actually holding the unconverted RGB data (stored in the order GBR). This ensures that there is no loss when converting between RGB and YUV, but AV1 encoding suffers in efficiency. This overloading of the MC value also allows for very specific formulas such as YCgCo (MC=8), by adding another entry and associated math to H.273's Table 4.
To summarize: the MC value simply explains how to convert from RGB pixel data to the "internal" color space handed to the AV1 encoder, which may or may not be YUV.
Once you've successfully used the MC value (explained above) to convert back to RGB, check to see if an ICC profile is present in the AVIF. If so, use it as the source of truth for the color profile of your RGB data and ignore the remaining CICP values. The two remaining values (CP/TC) are overridden by the content in an ICC profile, if present.
Conversely, if encoding an AVIF with an ICC profile, know that the MC value in CICP is still relevant to how the data is converted prior to AV1 encoding, and you still might want to specify MC in your image encoding recipes.
The CP value provides the color primaries used by the resultant RGB data, based on Table 2 of H.273. These primaries are the xy
coordinates on the CIE1931 chromaticity diagram which describe this image's color gamut.
sRGB uses CP=1
(BT.709). HDR10 uses CP=9
(BT.2020). P3 is also common (CP=12
).
Typically, a gamut that is larger ("wider") than BT.709 (used by sRGB) is considered to be a "Wide Color Gamut".
The TC value provides the transfer characteristics (also referred to as "transfer function" or "tone reproduction curve") for this image, based on Table 3 of H.273.
sRGB uses TC=13
(sRGB). HDR10 uses TC=16
(ST.2084, "PQ"). HLG is TC=18
.
In the context of AVIF, PQ (16) and HLG (18) are both considered to be "HDR", but in other file formats (such as formats supporting floating point values exceeding the [0-1] range), HDR can be achieved with simpler transfer functions.
For all three CICP values, the value of 2
in H.273 signals Unspecified
. The wording in H.273 when this occurs:
Unspecified Image characteristics are unknown or are determined by the application.
As it is up to us, AVIF's default CICP is 1/13/6
(MC=5
and MC=6
are functionally identical), as this signals sRGB with BT.601 coefficients. This is what JPEG uses internally, libyuv has a fast path for this specific combination (due to JPEG), and BT.601 coefficients are the default for video tools. libavif
(and associated tools) use this triple as the fallback/default.
The three values CICP provide are effectively independent of another, and any of the most common values could be combined to make something that would "work". However, some triples are much more commonly used, and therefore much more likely to be interpreted correctly and converted with a fast path.
-
1/13/6 - sRGB with BT.601 coefficients. When combined with full range, this is what JPEG uses. If an RGB image with no ICC profile is given to
avifenc
, this is what will be used. Note:MC=5
is functionally identical here, so1/13/5
would behave the same way. -
x/y/0 - (anything) with
MC=Identity
. When combined with no subsampling, full range, and quantizers set to 0, this allows for lossless encoding. Example:1/13/0
would be a way to signal sRGB losslessly. Note that this will typically encode AV1 quite inefficiently and end up with a large AV1 payload (file size). -
9/16/9 - BT.2020 PQ with BT.2020 coefficients. When combined with 10 bits per channel, this is HDR10. MC could technically be another value, but when
CP=9
, typicallyMC=9
is made to match. -
9/18/9 - BT.2020 HLG with BT.2020 coefficients. Some HDR iPhone image sequences are stored with this triple.
-
12/16/x - P3 PQ. Many video production pipelines use P3 PQ as their working profile, and since there is no direct mapping for P3 with MC, many tools just end up using MC=1 or MC=5/6.