| // Copyright 2022 Google LLC | |
| // SPDX-License-Identifier: BSD-2-Clause | |
| #include <iostream> | |
| #include <string> | |
| #include <tuple> | |
| #include "avif/avif.h" | |
| #include "avifincrtest_helpers.h" | |
| #include "aviftest_helpers.h" | |
| #include "gtest/gtest.h" | |
| using testing::Bool; | |
| using testing::Combine; | |
| using testing::Values; | |
| namespace avif { | |
| namespace { | |
| // Used to pass the data folder path to the GoogleTest suites. | |
| const char* data_path = nullptr; | |
| //------------------------------------------------------------------------------ | |
| // Check that non-incremental and incremental decodings of a grid AVIF produce | |
| // the same pixels. | |
| TEST(IncrementalTest, Decode) { | |
| const testutil::AvifRwData encoded_avif = | |
| testutil::ReadFile(std::string(data_path) + "sofa_grid1x5_420.avif"); | |
| ASSERT_NE(encoded_avif.size, 0u); | |
| ImagePtr reference(avifImageCreateEmpty()); | |
| ASSERT_NE(reference, nullptr); | |
| DecoderPtr decoder(avifDecoderCreate()); | |
| ASSERT_NE(decoder, nullptr); | |
| ASSERT_EQ(avifDecoderReadMemory(decoder.get(), reference.get(), | |
| encoded_avif.data, encoded_avif.size), | |
| AVIF_RESULT_OK); | |
| // Cell height is hardcoded because there is no API to extract it from an | |
| // encoded payload. | |
| ASSERT_EQ(testutil::DecodeIncrementally( | |
| encoded_avif, decoder.get(), | |
| /*is_persistent=*/true, /*give_size_hint=*/true, | |
| /*use_nth_image_api=*/false, *reference, | |
| /*cell_height=*/154, | |
| /*enable_fine_incremental_check=*/true), | |
| AVIF_RESULT_OK); | |
| } | |
| //------------------------------------------------------------------------------ | |
| class IncrementalTest | |
| : public testing::TestWithParam<std::tuple< | |
| /*width=*/uint32_t, /*height=*/uint32_t, /*create_alpha=*/bool, | |
| /*flat_cells=*/bool, /*encoded_avif_is_persistent=*/bool, | |
| /*give_size_hint=*/bool, /*use_nth_image_api=*/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 create_alpha = std::get<2>(GetParam()); | |
| const bool flat_cells = std::get<3>(GetParam()); | |
| const bool encoded_avif_is_persistent = std::get<4>(GetParam()); | |
| const bool give_size_hint = std::get<5>(GetParam()); | |
| const bool use_nth_image_api = std::get<6>(GetParam()); | |
| // Load an image. It does not matter that it comes from an AVIF file. | |
| ImagePtr image(avifImageCreateEmpty()); | |
| ASSERT_NE(image, nullptr); | |
| const testutil::AvifRwData image_bytes = | |
| testutil::ReadFile(std::string(data_path) + "sofa_grid1x5_420.avif"); | |
| ASSERT_NE(image_bytes.size, 0u); | |
| DecoderPtr decoder(avifDecoderCreate()); | |
| ASSERT_NE(decoder, nullptr); | |
| ASSERT_EQ(avifDecoderReadMemory(decoder.get(), image.get(), image_bytes.data, | |
| image_bytes.size), | |
| AVIF_RESULT_OK); | |
| // Encode then decode it. | |
| testutil::AvifRwData encoded_avif; | |
| uint32_t cell_width, cell_height; | |
| testutil::EncodeRectAsIncremental(*image, width, height, create_alpha, | |
| flat_cells, &encoded_avif, &cell_width, | |
| &cell_height); | |
| ASSERT_EQ(testutil::DecodeNonIncrementallyAndIncrementally( | |
| encoded_avif, decoder.get(), encoded_avif_is_persistent, | |
| give_size_hint, use_nth_image_api, cell_height, | |
| /*enable_fine_incremental_check=*/true), | |
| AVIF_RESULT_OK); | |
| } | |
| INSTANTIATE_TEST_SUITE_P(WholeImage, IncrementalTest, | |
| Combine(/*width=*/Values(1024), | |
| /*height=*/Values(770), | |
| /*create_alpha=*/Values(true), | |
| /*flat_cells=*/Bool(), | |
| /*encoded_avif_is_persistent=*/Values(true), | |
| /*give_size_hint=*/Values(true), | |
| /*use_nth_image_api=*/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), | |
| /*create_alpha=*/Bool(), | |
| /*flat_cells=*/Bool(), | |
| /*encoded_avif_is_persistent=*/Bool(), | |
| /*give_size_hint=*/Bool(), | |
| /*use_nth_image_api=*/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), | |
| /*create_alpha=*/Bool(), | |
| /*flat_cells=*/Bool(), | |
| /*encoded_avif_is_persistent=*/Bool(), | |
| /*give_size_hint=*/Bool(), | |
| /*use_nth_image_api=*/Bool())); | |
| //------------------------------------------------------------------------------ | |
| // Check that avifDecoderDecodedRowCount() returns 0 unless | |
| // decoder->imageContentToDecode is set to at least | |
| // AVIF_IMAGE_CONTENT_COLOR_AND_ALPHA. | |
| // Regression test for b/481550106. | |
| TEST(IncrementalTest, DecodeGainMapOnly) { | |
| const testutil::AvifRwData encoded_avif = testutil::ReadFile( | |
| std::string(data_path) + "seine_sdr_gainmap_srgb.avif"); | |
| ASSERT_NE(encoded_avif.size, 0u); | |
| ImagePtr reference(avifImageCreateEmpty()); | |
| ASSERT_NE(reference, nullptr); | |
| DecoderPtr decoder(avifDecoderCreate()); | |
| ASSERT_NE(decoder, nullptr); | |
| ASSERT_EQ(avifDecoderReadMemory(decoder.get(), reference.get(), | |
| encoded_avif.data, encoded_avif.size), | |
| AVIF_RESULT_OK); | |
| ASSERT_NE(reference->gainMap, nullptr); | |
| decoder->imageContentToDecode = AVIF_IMAGE_CONTENT_GAIN_MAP; | |
| ASSERT_EQ( | |
| testutil::DecodeIncrementally( | |
| encoded_avif, decoder.get(), /*is_persistent=*/true, | |
| /*give_size_hint=*/true, /*use_nth_image_api=*/false, *reference, | |
| /*cell_height=*/154, /*enable_fine_incremental_check=*/true), | |
| AVIF_RESULT_OK); | |
| } | |
| //------------------------------------------------------------------------------ | |
| } // namespace | |
| } // namespace avif | |
| 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; | |
| } | |
| avif::data_path = argv[1]; | |
| return RUN_ALL_TESTS(); | |
| } |