libavif Thread Pooling for Animated AVIF

This article provides an overview of how the libavif library manages multi-threading and thread pooling when processing animated AVIF sequences. It explains the relationship between libavif and underlying AV1 codecs, details how to configure thread limits during encoding and decoding, and highlights key performance behaviors during parallel frame processing.

The Role of Underlying AV1 Codecs

To understand thread pooling in libavif, it is essential to recognize that libavif itself does not manage a central thread pool for image processing. Instead, libavif acts as a container parser and multiplexer. It parses the ISOBMFF container format of the AVIF file and delegates the actual heavy lifting of encoding or decoding the AV1 video frames to external codecs, such as:

Consequently, thread pooling and CPU core utilization are handled directly by the worker threads spawned by these underlying codecs.

Configuring Threads in libavif

Developers control the concurrency level of animated sequence processing by configuring the maxThreads property on the encoder or decoder structures:

If maxThreads is set to 1, processing runs strictly on a single thread. If it is set to a value greater than 1, the underlying codec initializes its internal thread pool up to that limit to parallelize operations.

Threading During Animated Decodes

Animated AVIF files consist of a sequence of AV1 keyframes and non-keyframes (inter-frames). When decoding these sequences, libavif feeds the frames sequentially or on-demand to the decoder. The underlying decoder uses two primary types of multi-threading:

  1. Tile-Based Multi-threading: AV1 frames can be divided into independent grid regions called tiles. When tile threading is active, the decoder assigns different tiles of a single frame to different threads in its pool, allowing them to be decoded simultaneously.
  2. Frame-Based Multi-threading: Decoders like dav1d can decode multiple frames in a sequence concurrently if there are no temporal dependencies blocking them. The thread pool manages these dependencies, ensuring that reference frames are sufficiently decoded before dependent frames begin processing.

Threading During Animated Encodes

Encoding animated AVIF sequences is computationally expensive. When maxThreads is set to a high value, the AV1 encoder utilizes its thread pool for several parallel operations:

Thread Oversubscription Warning

Because libavif relies on the active codec’s internal threading mechanisms, each instance of an avifDecoder or avifEncoder maintains its own separate thread pool.

If an application attempts to decode or encode multiple animated AVIF files concurrently on different application threads, each instance will spawn up to its configured maxThreads. This can easily lead to CPU thread oversubscription, high context-switching overhead, and degraded performance. To prevent this, applications processing multiple animations in parallel should lower the maxThreads value per instance relative to the total number of available CPU cores.