| // Copyright 2022 Google LLC. All rights reserved. |
| // SPDX-License-Identifier: BSD-2-Clause |
| |
| #include "avif/avif.h" |
| #include "avifincrtest_helpers.h" |
| |
| #include <stdint.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| |
| //------------------------------------------------------------------------------ |
| |
| // Reads the file at path into bytes or returns false. |
| static avifBool readFile(const char * path, avifRWData * bytes) |
| { |
| FILE * file; |
| avifRWDataFree(bytes); |
| file = fopen(path, "rb"); |
| if (!file) { |
| return AVIF_FALSE; |
| } |
| if (fseek(file, 0, SEEK_END)) { |
| fclose(file); |
| return AVIF_FALSE; |
| } |
| avifRWDataRealloc(bytes, ftell(file)); |
| rewind(file); |
| if (fread(bytes->data, bytes->size, 1, file) != 1) { |
| avifRWDataFree(bytes); |
| fclose(file); |
| return AVIF_FALSE; |
| } |
| fclose(file); |
| return AVIF_TRUE; |
| } |
| |
| //------------------------------------------------------------------------------ |
| |
| // Encodes then decodes a window of width*height pixels at the middle of the image. |
| // Check that non-incremental and incremental decodings produce the same pixels. |
| static avifBool encodeDecodeNonIncrementallyAndIncrementally(const avifImage * image, |
| uint32_t width, |
| uint32_t height, |
| avifBool createAlphaIfNone, |
| avifBool flatCells, |
| avifBool encodedAvifIsPersistent, |
| avifBool giveSizeHint, |
| avifBool useNthImageApi) |
| { |
| avifBool success = AVIF_FALSE; |
| avifRWData encodedAvif = { 0 }; |
| uint32_t cellWidth, cellHeight; |
| if (!encodeRectAsIncremental(image, width, height, createAlphaIfNone, flatCells, &encodedAvif, &cellWidth, &cellHeight)) { |
| goto cleanup; |
| } |
| if (!decodeNonIncrementallyAndIncrementally(&encodedAvif, encodedAvifIsPersistent, giveSizeHint, useNthImageApi, cellHeight)) { |
| goto cleanup; |
| } |
| success = AVIF_TRUE; |
| cleanup: |
| avifRWDataFree(&encodedAvif); |
| return success; |
| } |
| |
| //------------------------------------------------------------------------------ |
| |
| int main(int argc, char * argv[]) |
| { |
| int exitCode = EXIT_FAILURE; |
| avifRWData encodedAvif = { NULL, 0 }; |
| |
| if (argc != 2) { |
| printf("ERROR: bad arguments\n"); |
| printf("Usage: avifincrtest <AVIF>\n"); |
| goto cleanup; |
| } |
| const char * const avifFilePath = argv[1]; |
| |
| if (!readFile(avifFilePath, &encodedAvif)) { |
| printf("ERROR: cannot read AVIF: %s\n", avifFilePath); |
| goto cleanup; |
| } |
| |
| // First test: decode the input image incrementally and compare it with a non-incrementally decoded reference. |
| avifImage * reference = avifImageCreateEmpty(); |
| if (!reference || !decodeNonIncrementally(&encodedAvif, reference)) { |
| goto cleanup; |
| } |
| // Cell height is hardcoded because there is no API to extract it from an encoded payload. |
| if (!decodeIncrementally(&encodedAvif, |
| /*isPersistent=*/AVIF_TRUE, |
| /*giveSizeHint=*/AVIF_TRUE, |
| /*useNthImageApi=*/AVIF_FALSE, |
| reference, |
| /*cellHeight=*/154)) { |
| goto cleanup; |
| } |
| |
| // Second test: encode a bunch of different dimension combinations and decode them incrementally and non-incrementally. |
| // Chroma subsampling requires even dimensions. See ISO 23000-22 section 7.3.11.4.2. |
| const uint32_t widths[] = { 1, 64, 66 }; |
| const uint32_t heights[] = { 1, 64, 66 }; |
| for (uint32_t w = 0; w < sizeof(widths) / sizeof(widths[0]); ++w) { |
| for (uint32_t h = 0; h < sizeof(heights) / sizeof(heights[0]); ++h) { |
| // avifEncoderAddImageInternal() only accepts grids of one unique cell, or grids where width and height are both at least 64. |
| if ((widths[w] >= 64) != (heights[h] >= 64)) { |
| continue; |
| } |
| |
| for (avifBool createAlpha = AVIF_FALSE; createAlpha <= AVIF_TRUE; ++createAlpha) { |
| for (avifBool flatCells = AVIF_FALSE; flatCells <= AVIF_TRUE; ++flatCells) { |
| for (avifBool encodedAvifIsPersistent = AVIF_FALSE; encodedAvifIsPersistent <= AVIF_TRUE; ++encodedAvifIsPersistent) { |
| for (avifBool giveSizeHint = AVIF_FALSE; giveSizeHint <= AVIF_TRUE; ++giveSizeHint) { |
| for (avifBool useNthImageApi = AVIF_FALSE; useNthImageApi <= AVIF_TRUE; ++useNthImageApi) { |
| if (!encodeDecodeNonIncrementallyAndIncrementally(reference, |
| widths[w], |
| heights[h], |
| createAlpha, |
| flatCells, |
| encodedAvifIsPersistent, |
| giveSizeHint, |
| useNthImageApi)) { |
| goto cleanup; |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| // Third test: full image. |
| for (avifBool flatCells = AVIF_FALSE; flatCells <= AVIF_TRUE; ++flatCells) { |
| if (!encodeDecodeNonIncrementallyAndIncrementally(reference, |
| reference->width, |
| reference->height, |
| /*createAlphaIfNone=*/AVIF_TRUE, |
| flatCells, |
| /*encodedAvifIsPersistent=*/AVIF_TRUE, |
| /*giveSizeHint=*/AVIF_TRUE, |
| /*useNthImageApi=*/AVIF_FALSE)) { |
| goto cleanup; |
| } |
| } |
| |
| exitCode = EXIT_SUCCESS; |
| cleanup: |
| avifRWDataFree(&encodedAvif); |
| return exitCode; |
| } |