Decode AVIF Buffers with Android NDK C++ APIs

The Android Native Development Kit (NDK) provides the AImageDecoder API for reading and decoding modern image formats, including AVIF, directly from memory buffers in native C and C++ code. Starting with Android 12 (API level 31), the platform natively supports the AV1 Image File Format (AVIF) through this interface, allowing developers to decode image bytes into raw pixel buffers without shipping third-party decoding libraries.

The Native Decoding API: AImageDecoder

The primary NDK interface for image decoding is declared in the <android/imagedecoder.h> header and linked via the jnigraphics library. AImageDecoder abstracts the underlying platform codecs and supports AVIF automatically when running on Android 12 (API 31) or higher.

To decode an AVIF image from an existing memory buffer, use the following sequence of C++ APIs:

  1. AImageDecoder_createFromBuffer: Creates a decoder instance by passing a pointer to the AVIF byte buffer and its size in bytes.

    AImageDecoder* decoder = nullptr;
    int result = AImageDecoder_createFromBuffer(avifBuffer, bufferSize, &decoder);
  2. AImageDecoder_getHeaderInfo: Retrieves the image metadata, such as width, height, and color specifications.

    const AImageDecoderHeaderInfo* info = AImageDecoder_getHeaderInfo(decoder);
    int32_t width = AImageDecoderHeaderInfo_getWidth(info);
    int32_t height = AImageDecoderHeaderInfo_getHeight(info);
  3. AImageDecoder_setAndroidBitmapFormat: Specifies the desired output pixel layout. For standard 8-bit AVIF images, ANDROID_BITMAP_FORMAT_RGBA_8888 is typical. For 10-bit or HDR AVIF images, you can configure ANDROID_BITMAP_FORMAT_RGBA_F16 to preserve high dynamic range data.

  4. AImageDecoder_decodeImage: Decodes the compressed AVIF data directly into a pre-allocated pixel buffer.

    size_t stride = AImageDecoder_getMinimumStride(decoder);
    size_t size = stride * height;
    void* pixels = malloc(size);
    
    int decodeResult = AImageDecoder_decodeImage(decoder, pixels, stride, size);
  5. AImageDecoder_delete: Releases the decoder resources once decoding is complete.

    AImageDecoder_delete(decoder);

Handling Backward Compatibility

The native NDK AImageDecoder does not decode AVIF on Android versions prior to API level 31 because the operating system lacked the underlying platform codec. To decode AVIF buffers on Android 11 (API 30) or lower in C++, you must integrate a third-party C/C++ library such as libavif compiled alongside an AV1 decoder such as dav1d.