blob: 74307b45149f95a7072ec02defa2c49c22ca9a45 [file] [log] [blame]
// Copyright 2022 Google LLC. All rights reserved.
// SPDX-License-Identifier: BSD-2-Clause
#include "avif/avif.h"
#include <fstream>
#include <iostream>
#include <string>
#include <tuple>
#include "avifincrtest_helpers.h"
#include "aviftest_helpers.h"
#include "gtest/gtest.h"
using testing::Bool;
using testing::Combine;
using testing::Values;
namespace libavif
{
namespace
{
//------------------------------------------------------------------------------
// Used to pass the data folder path to the GoogleTest suites.
const char * dataPath = nullptr;
// Reads the file with fileName into bytes and returns them.
testutil::avifRWDataCleaner readFile(const char * fileName)
{
std::ifstream file(std::string(dataPath) + fileName, std::ios::binary | std::ios::ate);
testutil::avifRWDataCleaner bytes;
avifRWDataRealloc(&bytes, file.good() ? static_cast<size_t>(file.tellg()) : 0);
file.seekg(0, std::ios::beg);
file.read(reinterpret_cast<char *>(bytes.data), static_cast<std::streamsize>(bytes.size));
return bytes;
}
//------------------------------------------------------------------------------
// Check that non-incremental and incremental decodings of a grid AVIF produce the same pixels.
TEST(IncrementalTest, Decode)
{
const testutil::avifRWDataCleaner encodedAvif = readFile("sofa_grid1x5_420.avif");
ASSERT_NE(encodedAvif.size, 0u);
testutil::avifImagePtr reference(avifImageCreateEmpty(), avifImageDestroy);
ASSERT_NE(reference, nullptr);
testutil::avifDecoderPtr decoder(avifDecoderCreate(), avifDecoderDestroy);
ASSERT_NE(decoder, nullptr);
ASSERT_EQ(avifDecoderReadMemory(decoder.get(), reference.get(), encodedAvif.data, encodedAvif.size), AVIF_RESULT_OK);
// Cell height is hardcoded because there is no API to extract it from an encoded payload.
testutil::decodeIncrementally(encodedAvif, /*isPersistent=*/true, /*giveSizeHint=*/true, /*useNthImageApi=*/false, *reference, /*cellHeight=*/154);
}
//------------------------------------------------------------------------------
class IncrementalTest : public testing::TestWithParam<std::tuple</*width=*/uint32_t,
/*height=*/uint32_t,
/*createAlpha=*/bool,
/*flatCells=*/bool,
/*encodedAvifIsPersistent=*/bool,
/*giveSizeHint=*/bool,
/*useNthImageApi=*/bool>>
{
};
// 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.
TEST_P(IncrementalTest, EncodeDecode)
{
const uint32_t width = std::get<0>(GetParam());
const uint32_t height = std::get<1>(GetParam());
const bool createAlpha = std::get<2>(GetParam());
const bool flatCells = std::get<3>(GetParam());
const bool encodedAvifIsPersistent = std::get<4>(GetParam());
const bool giveSizeHint = std::get<5>(GetParam());
const bool useNthImageApi = std::get<6>(GetParam());
// Load an image. It does not matter that it comes from an AVIF file.
testutil::avifImagePtr image(avifImageCreateEmpty(), avifImageDestroy);
ASSERT_NE(image, nullptr);
const testutil::avifRWDataCleaner imageBytes = readFile("sofa_grid1x5_420.avif");
ASSERT_NE(imageBytes.size, 0u);
testutil::avifDecoderPtr decoder(avifDecoderCreate(), avifDecoderDestroy);
ASSERT_NE(decoder, nullptr);
ASSERT_EQ(avifDecoderReadMemory(decoder.get(), image.get(), imageBytes.data, imageBytes.size), AVIF_RESULT_OK);
// Encode then decode it.
testutil::avifRWDataCleaner encodedAvif;
uint32_t cellWidth, cellHeight;
testutil::encodeRectAsIncremental(*image, width, height, createAlpha, flatCells, &encodedAvif, &cellWidth, &cellHeight);
testutil::decodeNonIncrementallyAndIncrementally(encodedAvif, encodedAvifIsPersistent, giveSizeHint, useNthImageApi, cellHeight);
}
INSTANTIATE_TEST_SUITE_P(WholeImage,
IncrementalTest,
Combine(/*width=*/Values(1024),
/*height=*/Values(770),
/*createAlpha=*/Values(true),
/*flatCells=*/Bool(),
/*encodedAvifIsPersistent=*/Values(true),
/*giveSizeHint=*/Values(true),
/*useNthImageApi=*/Values(false)));
// avifEncoderAddImageInternal() only accepts grids of one unique cell, or grids where width and height are both at least 64.
INSTANTIATE_TEST_SUITE_P(SingleCell,
IncrementalTest,
Combine(/*width=*/Values(1),
/*height=*/Values(1),
/*createAlpha=*/Bool(),
/*flatCells=*/Bool(),
/*encodedAvifIsPersistent=*/Bool(),
/*giveSizeHint=*/Bool(),
/*useNthImageApi=*/Bool()));
// Chroma subsampling requires even dimensions. See ISO 23000-22 section 7.3.11.4.2.
INSTANTIATE_TEST_SUITE_P(SinglePixel,
IncrementalTest,
Combine(/*width=*/Values(64, 66),
/*height=*/Values(64, 66),
/*createAlpha=*/Bool(),
/*flatCells=*/Bool(),
/*encodedAvifIsPersistent=*/Bool(),
/*giveSizeHint=*/Bool(),
/*useNthImageApi=*/Bool()));
//------------------------------------------------------------------------------
} // namespace
} // namespace libavif
int main(int argc, char ** argv)
{
::testing::InitGoogleTest(&argc, argv);
if (argc < 2) {
std::cerr << "The path to the test data folder must be provided as an argument" << std::endl;
return 1;
}
libavif::dataPath = argv[1];
return RUN_ALL_TESTS();
}