blob: 9d555d691da16a2818755942ee523e47ced642e9 [file] [edit]
// Copyright 2024 Google LLC
// SPDX-License-Identifier: BSD-2-Clause
#include <algorithm>
#include <iostream>
#include <string>
#include "avif/avif.h"
#include "avifincrtest_helpers.h"
#include "aviftest_helpers.h"
#include "gtest/gtest.h"
namespace avif {
namespace {
// Used to pass the data folder path to the GoogleTest suites.
const char* data_path = nullptr;
//------------------------------------------------------------------------------
TEST(DimgTest, IrefRepetition) {
testutil::AvifRwData avif = testutil::ReadFile(
std::string(data_path) + "sofa_grid1x5_420_dimg_repeat.avif");
ASSERT_NE(avif.size, 0u);
ImagePtr reference(avifImageCreateEmpty());
ASSERT_NE(reference, nullptr);
DecoderPtr decoder(avifDecoderCreate());
ASSERT_NE(decoder, nullptr);
ASSERT_EQ(avifDecoderReadMemory(decoder.get(), reference.get(), avif.data,
avif.size),
AVIF_RESULT_INVALID_IMAGE_GRID);
}
// Item 10 is a cell of both the color grid and the alpha grid. Sharing a cell
// between two derived items is allowed, so this file now reaches the tile
// consistency check and is refused there: the av1C of a color tile cannot match
// the av1C of the alpha tiles it stands among.
TEST(DimgTest, ItemShared) {
testutil::AvifRwData avif =
testutil::ReadFile(std::string(data_path) +
"color_grid_alpha_grid_tile_shared_in_dimg.avif");
ASSERT_NE(avif.size, 0u);
ImagePtr reference(avifImageCreateEmpty());
ASSERT_NE(reference, nullptr);
DecoderPtr decoder(avifDecoderCreate());
ASSERT_NE(decoder, nullptr);
ASSERT_EQ(avifDecoderReadMemory(decoder.get(), reference.get(), avif.data,
avif.size),
AVIF_RESULT_BMFF_PARSE_FAILED);
}
//------------------------------------------------------------------------------
// The color grid and the alpha grid are built from the same four cells, so each
// of the items 2 to 5 is an input of two derived items. The ordered 'dimg' list
// can express that, and the tiles stay consistent because both grids use the
// same ones.
TEST(DimgTest, TilesSharedBetweenGrids) {
testutil::AvifRwData avif = testutil::ReadFile(
std::string(data_path) + "color_grid_alpha_grid_shared_tiles.avif");
ASSERT_NE(avif.size, 0u);
ImagePtr decoded(avifImageCreateEmpty());
ASSERT_NE(decoded, nullptr);
DecoderPtr decoder(avifDecoderCreate());
ASSERT_NE(decoder, nullptr);
ASSERT_EQ(
avifDecoderReadMemory(decoder.get(), decoded.get(), avif.data, avif.size),
AVIF_RESULT_OK);
ASSERT_NE(decoded->alphaPlane, nullptr);
}
//------------------------------------------------------------------------------
// One item is the alpha auxiliary of both tiles of a color grid. The synthetic
// alpha grid then holds that item in both cells, which the ordered dimg input
// list can express. Every cell carries the same alpha, so the two halves of the
// alpha plane match each other while they differ in the file this one is
// derived from.
TEST(DimgTest, AlphaItemSharedBetweenTiles) {
testutil::AvifRwData avif = testutil::ReadFile(
std::string(data_path) + "color_grid_alpha_item_shared_in_auxl.avif");
ASSERT_NE(avif.size, 0u);
ImagePtr decoded(avifImageCreateEmpty());
ASSERT_NE(decoded, nullptr);
DecoderPtr decoder(avifDecoderCreate());
ASSERT_NE(decoder, nullptr);
ASSERT_EQ(
avifDecoderReadMemory(decoder.get(), decoded.get(), avif.data, avif.size),
AVIF_RESULT_OK);
ASSERT_NE(decoded->alphaPlane, nullptr);
// The grid is two cells tall, so a row in the second cell repeats a row of
// the first one. The cell height is the tile height, not half the output
// height.
testutil::AvifRwData reference = testutil::ReadFile(
std::string(data_path) + "color_grid_alpha_nogrid.avif");
ASSERT_NE(reference.size, 0u);
ImagePtr referenceDecoded(avifImageCreateEmpty());
ASSERT_NE(referenceDecoded, nullptr);
DecoderPtr referenceDecoder(avifDecoderCreate());
ASSERT_NE(referenceDecoder, nullptr);
ASSERT_EQ(
avifDecoderReadMemory(referenceDecoder.get(), referenceDecoded.get(),
reference.data, reference.size),
AVIF_RESULT_OK);
ASSERT_NE(referenceDecoded->alphaPlane, nullptr);
ASSERT_EQ(decoded->width, referenceDecoded->width);
ASSERT_EQ(decoded->height, referenceDecoded->height);
// The first cell is unchanged, and the second one now repeats it instead of
// carrying the alpha of the item that no longer claims that tile.
const uint32_t width = decoded->width;
EXPECT_EQ(memcmp(decoded->alphaPlane, referenceDecoded->alphaPlane, width),
0);
const uint8_t* lastRow =
decoded->alphaPlane +
(size_t)decoded->alphaRowBytes * (decoded->height - 1);
const uint8_t* referenceLastRow =
referenceDecoded->alphaPlane +
(size_t)referenceDecoded->alphaRowBytes * (referenceDecoded->height - 1);
EXPECT_NE(memcmp(lastRow, referenceLastRow, width), 0);
}
//------------------------------------------------------------------------------
TEST(DimgTest, ItemOutOfOrder) {
testutil::AvifRwData avif =
testutil::ReadFile(std::string(data_path) + "sofa_grid1x5_420.avif");
ASSERT_NE(avif.size, 0u);
ImagePtr decoded(avifImageCreateEmpty());
ASSERT_NE(decoded, nullptr);
DecoderPtr decoder(avifDecoderCreate());
ASSERT_NE(decoder, nullptr);
ASSERT_EQ(
avifDecoderReadMemory(decoder.get(), decoded.get(), avif.data, avif.size),
AVIF_RESULT_OK);
testutil::AvifRwData avif_reversed_dimg_order = testutil::ReadFile(
std::string(data_path) + "sofa_grid1x5_420_reversed_dimg_order.avif");
ImagePtr decoded_reversed_dimg_order(avifImageCreateEmpty());
ASSERT_NE(decoded_reversed_dimg_order, nullptr);
ASSERT_EQ(avifDecoderReadMemory(decoder.get(), decoded.get(),
avif_reversed_dimg_order.data,
avif_reversed_dimg_order.size),
AVIF_RESULT_OK);
EXPECT_FALSE(
testutil::AreImagesEqual(*decoded, *decoded_reversed_dimg_order));
// Verify that it works incrementally.
// enable_fine_incremental_check is false because the tiles are out-of-order.
ASSERT_EQ(testutil::DecodeIncrementally(
avif_reversed_dimg_order, decoder.get(), /*is_persistent=*/true,
/*give_size_hint=*/true,
/*use_nth_image_api=*/false, *decoded_reversed_dimg_order,
/*cell_height=*/154, /*enable_fine_incremental_check=*/false),
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();
}