libavif
| Language | C (usable from C++) |
|---|---|
| License | BSD-2-Clause |
| Repository | github.com/AOMediaCodec/libavif |
| Documentation | comments in avif.h, examples |
| Depends on | at least one AV1 codec: dav1d or libgav1 (decode), libaom (decode and encode), SVT-AV1 or rav1e (encode); optionally libyuv for faster color conversion |
| Read / write | yes / 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#
# 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:
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#
#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#
#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:
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#
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):
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#
// 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#
- Pick a codec explicitly with
decoder->codecChoice/encoder->codecChoice(AVIF_CODEC_CHOICE_DAV1D,AVIF_CODEC_CHOICE_AOM,AVIF_CODEC_CHOICE_SVT,AVIF_CODEC_CHOICE_RAV1E); the default is the best one compiled in. encoder->quality = AVIF_QUALITY_LOSSLESS(100) withAVIF_PIXEL_FORMAT_YUV444andimage->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_IDENTITYgives lossless output.- Set
encoder->maxThreadsanddecoder->maxThreadsto use more cores. - For untrusted files, limit
decoder->imageSizeLimit(pixels) anddecoder->imageDimensionLimit. avifDecoderReadFile(decoder, image, path)decodes the primary image in one call when you don’t need the frame loop.