Extract Frames from Animated AVIF with libavif
This article provides a quick guide on how to extract specific frames
from an animated AVIF file using the official libavif
library. You will learn how to achieve this both through the command
line using the avifdec utility and programmatically using
the libavif C API.
Method 1: Using the avifdec Command-Line Tool
The easiest way to extract a single frame from an animated AVIF is by
using the avifdec command-line tool, which is compiled
alongside libavif.
To extract a specific frame, use the --frame (or
-f) option followed by the zero-based index of the frame
you want to export.
avifdec --frame 5 input.avif output_frame_5.pngIn this example, --frame 5 extracts the sixth frame of
the animation (since indexing starts at 0) and saves it as a PNG file.
You can output to other supported formats like PNG, JPEG, or Y4M
depending on how your avifdec binary was compiled.
Method 2: Using the libavif C API
If you are developing an application, you can use the libavif C
library to programmatically decode and extract specific frames. The key
function for this process is avifDecoderNthImage().
Here is the step-by-step workflow to extract a specific frame:
- Initialize the Decoder: Create and initialize the decoder structure.
- Parse the File: Read the AVIF container to retrieve metadata and track information without decoding the entire pixel payload yet.
- Request the Specific Frame: Use
avifDecoderNthImage()to jump directly to and decode your target frame index.
Below is a simplified C code example demonstrating this process:
#include "avif/avif.h"
#include <stdio.h>
int main() {
const char * sourceFile = "input.avif";
uint32_t targetFrameIndex = 3; // Extract the 4th frame
avifDecoder * decoder = avifDecoderCreate();
// Open and parse the file
avifResult result = avifDecoderSetFile(decoder, sourceFile);
if (result != AVIF_RESULT_OK) {
fprintf(stderr, "Failed to open AVIF: %s\n", avifResultToString(result));
avifDecoderDestroy(decoder);
return 1;
}
result = avifDecoderParse(decoder);
if (result != AVIF_RESULT_OK) {
fprintf(stderr, "Failed to parse AVIF: %s\n", avifResultToString(result));
avifDecoderDestroy(decoder);
return 1;
}
// Verify the requested frame index exists
if (targetFrameIndex >= (uint32_t)decoder->imageCount) {
fprintf(stderr, "Frame index %u is out of bounds. Total frames: %d\n", targetFrameIndex, decoder->imageCount);
avifDecoderDestroy(decoder);
return 1;
}
// Decode the specific frame
result = avifDecoderNthImage(decoder, targetFrameIndex);
if (result != AVIF_RESULT_OK) {
fprintf(stderr, "Failed to decode frame %u: %s\n", targetFrameIndex, avifResultToString(result));
avifDecoderDestroy(decoder);
return 1;
}
// The decoded frame is now available in decoder->image
printf("Successfully decoded frame %u. Width: %u, Height: %u\n",
targetFrameIndex, decoder->image->width, decoder->image->height);
// Clean up
avifDecoderDestroy(decoder);
return 0;
}By utilizing avifDecoderNthImage(), the decoder
efficiently seeks to the specified frame, handling any keyframe
dependencies internally to construct the final image.