All formats

libavif

LanguageC (usable from C++)
LicenseBSD-2-Clause
Repositorygithub.com/AOMediaCodec/libavif
Documentationcomments in avif.h, examples
Depends onat least one AV1 codec: dav1d or libgav1 (decode), libaom (decode and encode), SVT-AV1 or rav1e (encode); optionally libyuv for faster color conversion
Read / writeyes / yes, 8/10/12-bit, alpha, HDR, grids, gain maps, animation, Exif/XMP/ICC

libavif is the reference implementation of the AVIF container, maintained by the Alliance for Open Media. It parses and writes the HEIF boxes, converts between YUV and RGB, and calls an AV1 codec for the pixel data. It ships the command line tools avifenc and avifdec.

The API is small. An avifImage holds YUV planes plus alpha and metadata; you convert it to or from an avifRGBImage (interleaved RGB/RGBA, 8 or 16 bits per channel). avifDecoder reads still and animated files; avifEncoder writes them. Every function returns an avifResult; avifResultToString gives a message.

Installation#

Shell
# Debian / Ubuntu
sudo apt install libavif-dev
# Fedora
sudo dnf install libavif-devel
# macOS
brew install libavif
# Windows (vcpkg): add codecs as features
vcpkg install libavif[aom,dav1d]

With CMake:

cmake
find_package(libavif REQUIRED)
target_link_libraries(myapp PRIVATE avif)

When building from source, pick codecs with options like -DAVIF_CODEC_DAV1D=SYSTEM -DAVIF_CODEC_AOM=SYSTEM (or LOCAL to download and build them).

Basic usage: decode AVIF to RGBA#

C
#include <avif/avif.h>
#include <stdio.h>

int main(void) {
    avifDecoder *decoder = avifDecoderCreate();
    if (!decoder) return 1;

    avifResult r = avifDecoderSetIOFile(decoder, "in.avif");
    if (r == AVIF_RESULT_OK) r = avifDecoderParse(decoder);
    if (r == AVIF_RESULT_OK) r = avifDecoderNextImage(decoder);  // decode the first (or only) image
    if (r != AVIF_RESULT_OK) {
        fprintf(stderr, "decode error: %s\n", avifResultToString(r));
        avifDecoderDestroy(decoder);
        return 1;
    }

    avifImage *image = decoder->image;
    printf("%u x %u, %u-bit, alpha: %s\n", image->width, image->height, image->depth,
           decoder->alphaPresent ? "yes" : "no");

    avifRGBImage rgb;
    avifRGBImageSetDefaults(&rgb, image);
    rgb.format = AVIF_RGB_FORMAT_RGBA;
    rgb.depth = 8;  // 8 or 16 bits per channel
    r = avifRGBImageAllocatePixels(&rgb);
    if (r == AVIF_RESULT_OK) r = avifImageYUVToRGB(image, &rgb);
    if (r == AVIF_RESULT_OK) {
        // rgb.pixels: rgb.height rows of rgb.rowBytes bytes, top row first
        uint8_t *p = rgb.pixels;
        printf("first pixel: %u %u %u %u\n", p[0], p[1], p[2], p[3]);
    }
    avifRGBImageFreePixels(&rgb);
    avifDecoderDestroy(decoder);
    return r == AVIF_RESULT_OK ? 0 : 1;
}

How to encode an RGBA buffer to AVIF#

C
#include <avif/avif.h>
#include <stdio.h>

int save_avif(const char *path, uint8_t *pixels, uint32_t width, uint32_t height) {
    int ok = 0;
    avifRWData out = AVIF_DATA_EMPTY;
    avifImage *image = avifImageCreate(width, height, 8, AVIF_PIXEL_FORMAT_YUV420);
    avifEncoder *encoder = avifEncoderCreate();
    if (!image || !encoder) goto done;

    avifRGBImage rgb;
    avifRGBImageSetDefaults(&rgb, image);
    rgb.format = AVIF_RGB_FORMAT_RGBA;
    rgb.depth = 8;
    rgb.pixels = pixels;
    rgb.rowBytes = width * 4;
    if (avifImageRGBToYUV(image, &rgb) != AVIF_RESULT_OK) goto done;  // also fills alpha

    encoder->quality = 60;       // 0 (worst) .. 100 (lossless), color
    encoder->qualityAlpha = 80;  // alpha plane
    encoder->speed = 6;          // 0 (slowest, smallest) .. 10 (fastest)

    avifResult r = avifEncoderWrite(encoder, image, &out);
    if (r != AVIF_RESULT_OK) {
        fprintf(stderr, "encode error: %s\n", avifResultToString(r));
        goto done;
    }
    FILE *f = fopen(path, "wb");
    if (f) {
        ok = fwrite(out.data, 1, out.size, f) == out.size;
        fclose(f);
    }
done:
    avifRWDataFree(&out);
    if (encoder) avifEncoderDestroy(encoder);
    if (image) avifImageDestroy(image);
    return ok;
}

How to get AVIF width and height without decoding#

avifDecoderParse reads only the container; the size, bit depth and frame count are known before any AV1 data is decoded:

C
avifDecoder *decoder = avifDecoderCreate();
if (avifDecoderSetIOFile(decoder, "in.avif") == AVIF_RESULT_OK &&
    avifDecoderParse(decoder) == AVIF_RESULT_OK) {
    printf("%u x %u, %u-bit, %d frame(s)\n", decoder->image->width,
           decoder->image->height, decoder->image->depth, decoder->imageCount);
}
avifDecoderDestroy(decoder);

How to read the frames of an animated AVIF#

C
avifDecoder *decoder = avifDecoderCreate();
if (avifDecoderSetIOFile(decoder, "anim.avif") == AVIF_RESULT_OK &&
    avifDecoderParse(decoder) == AVIF_RESULT_OK) {
    while (avifDecoderNextImage(decoder) == AVIF_RESULT_OK) {
        printf("frame %d: pts %.3f s, duration %.3f s\n", decoder->imageIndex,
               decoder->imageTiming.pts, decoder->imageTiming.duration);
        // convert decoder->image with avifImageYUVToRGB as above
    }
}
avifDecoderDestroy(decoder);

How to create an animated AVIF#

Add frames with avifEncoderAddImage, then call avifEncoderFinish. Durations are in units of encoder->timescale (ticks per second):

C
avifEncoder *encoder = avifEncoderCreate();
encoder->timescale = 1000;  // durations in milliseconds
encoder->quality = 60;
for (int i = 0; i < frameCount; i++) {
    // frames[i] is an avifImage filled with avifImageRGBToYUV
    if (avifEncoderAddImage(encoder, frames[i], 100, AVIF_ADD_IMAGE_FLAG_NONE) != AVIF_RESULT_OK)
        break;
}
avifRWData out = AVIF_DATA_EMPTY;
if (avifEncoderFinish(encoder, &out) == AVIF_RESULT_OK) {
    // write out.data / out.size to a file
}
avifRWDataFree(&out);
avifEncoderDestroy(encoder);

How to add Exif metadata#

C
// exif: Exif payload, as in a JPEG APP1 segment
avifResult r = avifImageSetMetadataExif(image, exif, exifSize);
// XMP: avifImageSetMetadataXMP(image, xmp, xmpSize)
// ICC profile: avifImageSetProfileICC(image, icc, iccSize)

Call these on the avifImage before encoding. After decoding, the metadata is in image->exif, image->xmp and image->icc (each an avifRWData).

Tips#