blob: 51d1c8934b27b2bd608a1462e28f4a593b64c5a6 [file] [log] [blame]
// Copyright 2023 Google LLC
// SPDX-License-Identifier: BSD-2-Clause
#include "avif/avif.h"
#include "aviftest_helpers.h"
#include "avifutil.h"
#include "gtest/gtest.h"
namespace avif {
namespace {
// Used to pass the data folder path to the GoogleTest suites.
const char* data_path = nullptr;
// Tests encode/decode round trips under different matrix coefficients.
TEST(BasicTest, EncodeDecodeMatrixCoefficients) {
for (const auto& file_name :
{"paris_icc_exif_xmp.png", "paris_exif_xmp_icc.jpg"}) {
// Read a ground truth image with default matrix coefficients.
const std::string file_path = std::string(data_path) + file_name;
const ImagePtr ground_truth_image =
testutil::ReadImage(data_path, file_name);
for (auto matrix_coefficient : {
#if defined(AVIF_ENABLE_EXPERIMENTAL_YCGCO_R)
AVIF_MATRIX_COEFFICIENTS_YCGCO_RE, AVIF_MATRIX_COEFFICIENTS_YCGCO_RO,
#endif
AVIF_MATRIX_COEFFICIENTS_IDENTITY, AVIF_MATRIX_COEFFICIENTS_YCGCO
}) {
// Read a ground truth image but ask for certain matrix coefficients.
ImagePtr image(avifImageCreateEmpty());
ASSERT_NE(image, nullptr);
image->matrixCoefficients = (avifMatrixCoefficients)matrix_coefficient;
const avifAppFileFormat file_format = avifReadImage(
file_path.c_str(),
/*requestedFormat=*/AVIF_PIXEL_FORMAT_NONE,
/*requestedDepth=*/0,
/*chromaDownsampling=*/AVIF_CHROMA_DOWNSAMPLING_AUTOMATIC,
/*ignoreColorProfile=*/false, /*ignoreExif=*/false,
/*ignoreXMP=*/false, /*allowChangingCicp=*/true,
/*ignoreGainMap=*/true, AVIF_DEFAULT_IMAGE_SIZE_LIMIT, image.get(),
/*outDepth=*/nullptr, /*sourceTiming=*/nullptr,
/*frameIter=*/nullptr);
#if defined(AVIF_ENABLE_EXPERIMENTAL_YCGCO_R)
if (matrix_coefficient == AVIF_MATRIX_COEFFICIENTS_YCGCO_RO) {
// AVIF_MATRIX_COEFFICIENTS_YCGCO_RO does not work because the input
// depth is not odd.
ASSERT_EQ(file_format, AVIF_APP_FILE_FORMAT_UNKNOWN);
continue;
}
#endif
ASSERT_NE(file_format, AVIF_APP_FILE_FORMAT_UNKNOWN);
// Encode.
EncoderPtr encoder(avifEncoderCreate());
ASSERT_NE(encoder, nullptr);
encoder->speed = AVIF_SPEED_FASTEST;
encoder->quality = AVIF_QUALITY_LOSSLESS;
encoder->qualityAlpha = AVIF_QUALITY_LOSSLESS;
testutil::AvifRwData encoded;
avifResult result =
avifEncoderWrite(encoder.get(), image.get(), &encoded);
ASSERT_EQ(result, AVIF_RESULT_OK) << avifResultToString(result);
// Decode to RAM.
ImagePtr decoded(avifImageCreateEmpty());
ASSERT_NE(decoded, nullptr);
DecoderPtr decoder(avifDecoderCreate());
ASSERT_NE(decoder, nullptr);
result = avifDecoderReadMemory(decoder.get(), decoded.get(), encoded.data,
encoded.size);
ASSERT_EQ(result, AVIF_RESULT_OK) << avifResultToString(result);
// Convert to a temporary PNG and read back, to have default matrix
// coefficients.
const std::string temp_dir = testing::TempDir();
const std::string temp_file = "decoded_default.png";
const std::string tmp_path = temp_dir + temp_file;
ASSERT_TRUE(testutil::WriteImage(decoded.get(), tmp_path.c_str()));
const ImagePtr decoded_default =
testutil::ReadImage(temp_dir.c_str(), temp_file.c_str());
// Verify that the ground truth and decoded images are the same.
const bool are_images_equal =
testutil::AreImagesEqual(*ground_truth_image, *decoded_default);
if (matrix_coefficient == AVIF_MATRIX_COEFFICIENTS_IDENTITY
#if defined(AVIF_ENABLE_EXPERIMENTAL_YCGCO_R)
|| matrix_coefficient == AVIF_MATRIX_COEFFICIENTS_YCGCO_RE
#endif
) {
ASSERT_TRUE(are_images_equal);
} else {
// AVIF_MATRIX_COEFFICIENTS_YCGCO is not lossless because it does not
// expand the input bit range for YCgCo values.
ASSERT_FALSE(are_images_equal);
}
}
}
}
} // namespace
} // namespace avif
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
if (argc != 2) {
std::cerr << "There must be exactly one argument containing the path to "
"the test data folder"
<< std::endl;
return 1;
}
avif::data_path = argv[1];
return RUN_ALL_TESTS();
}