| // Copyright 2020 Joe Drago. All rights reserved. | |
| // SPDX-License-Identifier: BSD-2-Clause | |
| #include "avif/avif.h" | |
| #include <inttypes.h> | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| int main(int argc, char * argv[]) | |
| { | |
| if (argc != 2) { | |
| fprintf(stderr, "avif_example_decode_memory [filename.avif]\n"); | |
| return 1; | |
| } | |
| const char * inputFilename = argv[1]; | |
| int returnCode = 1; | |
| avifRGBImage rgb; | |
| memset(&rgb, 0, sizeof(rgb)); | |
| avifDecoder * decoder = avifDecoderCreate(); | |
| if (decoder == NULL) { | |
| fprintf(stderr, "Memory allocation failure\n"); | |
| return 1; | |
| } | |
| // Override decoder defaults here (codecChoice, requestedSource, ignoreExif, ignoreXMP, etc) | |
| // Read entire file into fileBuffer | |
| FILE * f = NULL; | |
| uint8_t * fileBuffer = NULL; | |
| f = fopen(inputFilename, "rb"); | |
| if (!f) { | |
| fprintf(stderr, "Cannot open file for read: %s\n", inputFilename); | |
| goto cleanup; | |
| } | |
| fseek(f, 0, SEEK_END); | |
| long fileSize = ftell(f); | |
| if (fileSize < 0) { | |
| fprintf(stderr, "Truncated file: %s\n", inputFilename); | |
| goto cleanup; | |
| } | |
| fseek(f, 0, SEEK_SET); | |
| fileBuffer = malloc(fileSize); | |
| long bytesRead = (long)fread(fileBuffer, 1, fileSize, f); | |
| if (bytesRead != fileSize) { | |
| fprintf(stderr, "Cannot read file: %s\n", inputFilename); | |
| goto cleanup; | |
| } | |
| avifResult result = avifDecoderSetIOMemory(decoder, fileBuffer, fileSize); | |
| if (result != AVIF_RESULT_OK) { | |
| fprintf(stderr, "Cannot set IO on avifDecoder: %s\n", inputFilename); | |
| goto cleanup; | |
| } | |
| result = avifDecoderParse(decoder); | |
| if (result != AVIF_RESULT_OK) { | |
| fprintf(stderr, "Failed to decode image: %s\n", avifResultToString(result)); | |
| goto cleanup; | |
| } | |
| // Now available: | |
| // * All decoder->image information other than pixel data: | |
| // * width, height, depth | |
| // * transformations (pasp, clap, irot, imir) | |
| // * color profile (icc, CICP) | |
| // * metadata (Exif, XMP) | |
| // * decoder->alphaPresent | |
| // * number of total images in the AVIF (decoder->imageCount) | |
| // * overall image sequence timing (including per-frame timing with avifDecoderNthImageTiming()) | |
| printf("Parsed AVIF: %ux%u (%ubpc)\n", decoder->image->width, decoder->image->height, decoder->image->depth); | |
| while (avifDecoderNextImage(decoder) == AVIF_RESULT_OK) { | |
| // Now available (for this frame): | |
| // * All decoder->image YUV pixel data (yuvFormat, yuvPlanes, yuvRange, yuvChromaSamplePosition, yuvRowBytes) | |
| // * decoder->image alpha data (alphaPlane, alphaRowBytes) | |
| // * this frame's sequence timing | |
| avifRGBImageSetDefaults(&rgb, decoder->image); | |
| // Override YUV(A)->RGB(A) defaults here: | |
| // depth, format, chromaUpsampling, avoidLibYUV, ignoreAlpha, alphaPremultiplied, etc. | |
| // Alternative: set rgb.pixels and rgb.rowBytes yourself, which should match your chosen rgb.format | |
| // Be sure to use uint16_t* instead of uint8_t* for rgb.pixels/rgb.rowBytes if (rgb.depth > 8) | |
| result = avifRGBImageAllocatePixels(&rgb); | |
| if (result != AVIF_RESULT_OK) { | |
| fprintf(stderr, "Allocation of RGB samples failed: %s (%s)\n", inputFilename, avifResultToString(result)); | |
| goto cleanup; | |
| } | |
| result = avifImageYUVToRGB(decoder->image, &rgb); | |
| if (result != AVIF_RESULT_OK) { | |
| fprintf(stderr, "Conversion from YUV failed: %s (%s)\n", inputFilename, avifResultToString(result)); | |
| goto cleanup; | |
| } | |
| // Now available: | |
| // * RGB(A) pixel data (rgb.pixels, rgb.rowBytes) | |
| if (rgb.depth > 8) { | |
| uint16_t * firstPixel = (uint16_t *)rgb.pixels; | |
| printf(" * First pixel: RGBA(%u,%u,%u,%u)\n", firstPixel[0], firstPixel[1], firstPixel[2], firstPixel[3]); | |
| } else { | |
| uint8_t * firstPixel = rgb.pixels; | |
| printf(" * First pixel: RGBA(%u,%u,%u,%u)\n", firstPixel[0], firstPixel[1], firstPixel[2], firstPixel[3]); | |
| } | |
| } | |
| returnCode = 0; | |
| cleanup: | |
| avifRGBImageFreePixels(&rgb); // Only use in conjunction with avifRGBImageAllocatePixels() | |
| avifDecoderDestroy(decoder); | |
| if (f) { | |
| fclose(f); | |
| } | |
| free(fileBuffer); | |
| return returnCode; | |
| } |