Progressive Decoding Mechanisms in libavif
This article explains how the libavif library handles
the progressive decoding of AVIF images. It covers the core mechanisms
of the library, including its integration with AV1 spatial scalability,
the avifProgressiveState API flags, and how developers can
utilize the avifDecoder structure to incrementally render
images from lower to higher quality.
AV1 Spatial Scalability and Multi-Layer Bitstreams
The primary mechanism enabling progressive decoding in AVIF is AV1’s native support for spatial scalability and multi-layer bitstreams. An AVIF image can be encoded with multiple layers within a single item, where the base layer contains a low-resolution or low-quality version of the image, and subsequent enhancement layers contain the data necessary to reconstruct higher resolutions or finer details.
libavif detects these layers during the container
parsing phase. Instead of treating the file as a single static frame,
the library identifies the presence of these enhancement layers and
prepares the underlying AV1 decoder (such as dav1d or
aom) to decode them sequentially.
The
avifProgressiveState API
To manage progressive rendering, libavif exposes the
avifProgressiveState enumeration through its decoder API.
This state informs the application of the progressive capabilities of
the target file:
AVIF_PROGRESSIVE_STATE_UNAVAILABLE: The image is a standard, single-layer image with no progressive data.AVIF_PROGRESSIVE_STATE_AVAILABLE: The image contains progressive layers, but the decoder has not been configured to decode them progressively, or the sequence has not started.AVIF_PROGRESSIVE_STATE_ACTIVE: The decoder is actively processing a progressive image.
By querying decoder->progressiveState, an application
can dynamically adjust its rendering pipeline based on whether the
incoming image support progressive refinement.
Implementing
Progressive Decoding via avifDecoder
To decode an image progressively using libavif,
developers interact with the avifDecoder structure and its
frame-stepping functions. The workflow operates as follows:
- Enable Progressive Decoding: The developer sets the decoder to allow progressive decoding before parsing the file.
- Determine Layer Count: Once parsed, if
decoder->progressiveStateis active,decoder->imageCountrepresents the total number of progressive layers available rather than individual animation frames. - Sequential Decoding Loop: The application calls
avifDecoderNextImage()in a loop. Each call decodes the next available layer of the image. - Incremental Rendering: After each successful call
to
avifDecoderNextImage(), the buffer pointed to bydecoder->imagecontains the image at the current layer’s quality. The application can immediately draw this buffer to the screen, providing a visual transition from a blurry or blocky preview to the final high-resolution image.
Performance and Overhead
While progressive decoding improves the perceived loading time for
users on slow network connections, it does introduce computational
overhead. libavif must invoke the underlying AV1 decoder
for each layer, which requires additional CPU cycles compared to
decoding only the final, highest-quality layer directly. To optimize
this, libavif relies on efficient memory management within
the codec wrappers to reuse buffers between layer passes whenever
possible.