blob: 88bda67759679ab8e764ba94bbea2a06589c4103 [file] [log] [blame]
// Copyright 2022 Google LLC. All rights reserved.
// SPDX-License-Identifier: BSD-2-Clause
#include "avif/avif.h"
#include <tuple>
#include <vector>
#include "aviftest_helpers.h"
#include "gtest/gtest.h"
using testing::Combine;
using testing::Values;
using testing::ValuesIn;
namespace libavif
{
namespace
{
// Pair of cell count and cell size for a single dimension.
struct Cell
{
int count, size;
};
class GridApiTest
: public testing::TestWithParam<std::tuple</*horizontal=*/Cell, /*vertical=*/Cell, /*bitDepth=*/int, /*yuvFormat=*/avifPixelFormat, /*createAlpha=*/bool, /*expectedSuccess=*/bool>>
{
};
TEST_P(GridApiTest, EncodeDecode)
{
const Cell horizontal = std::get<0>(GetParam());
const Cell vertical = std::get<1>(GetParam());
const int bitDepth = std::get<2>(GetParam());
const avifPixelFormat yuvFormat = std::get<3>(GetParam());
const bool createAlpha = std::get<4>(GetParam());
const bool expectedSuccess = std::get<5>(GetParam());
// Construct a grid.
std::vector<testutil::avifImagePtr> cellImages;
cellImages.reserve(horizontal.count * vertical.count);
for (int i = 0; i < horizontal.count * vertical.count; ++i) {
cellImages.emplace_back(
testutil::createImage(horizontal.size, vertical.size, bitDepth, yuvFormat, createAlpha ? AVIF_PLANES_ALL : AVIF_PLANES_YUV));
ASSERT_NE(cellImages.back(), nullptr);
testutil::fillImageGradient(cellImages.back().get());
}
// Encode the grid image.
testutil::avifEncoderPtr encoder(avifEncoderCreate(), avifEncoderDestroy);
ASSERT_NE(encoder, nullptr);
encoder->speed = AVIF_SPEED_FASTEST;
std::vector<avifImage *> cellImagePtrs(cellImages.size()); // Just here to match libavif API.
for (size_t i = 0; i < cellImages.size(); ++i) {
cellImagePtrs[i] = cellImages[i].get();
}
const avifResult result =
avifEncoderAddImageGrid(encoder.get(), horizontal.count, vertical.count, cellImagePtrs.data(), AVIF_ADD_IMAGE_FLAG_SINGLE);
if (expectedSuccess) {
ASSERT_EQ(result, AVIF_RESULT_OK);
testutil::avifRWDataCleaner encodedAvif;
ASSERT_EQ(avifEncoderFinish(encoder.get(), &encodedAvif), AVIF_RESULT_OK);
// Decode the grid image.
testutil::avifImagePtr image(avifImageCreateEmpty(), avifImageDestroy);
ASSERT_NE(image, nullptr);
testutil::avifDecoderPtr decoder(avifDecoderCreate(), avifDecoderDestroy);
ASSERT_NE(decoder, nullptr);
ASSERT_EQ(avifDecoderReadMemory(decoder.get(), image.get(), encodedAvif.data, encodedAvif.size), AVIF_RESULT_OK);
} else {
ASSERT_TRUE(result == AVIF_RESULT_INVALID_IMAGE_GRID || result == AVIF_RESULT_NO_CONTENT);
}
}
// A cell cannot be smaller than 64px in any dimension if there are several cells.
// A cell cannot have an odd size in any dimension if there are several cells and chroma subsampling.
// Image size must be a multiple of cell size.
constexpr Cell kValidCells[] = { { 1, 64 }, { 1, 66 }, { 2, 64 }, { 3, 68 } };
constexpr Cell kInvalidCells[] = { { 0, 0 }, { 0, 1 }, { 1, 0 }, { 2, 1 }, { 2, 2 }, { 2, 3 }, { 2, 63 } };
constexpr int kBitDepths[] = { 8, 10, 12 };
constexpr avifPixelFormat kPixelFormats[] = { AVIF_PIXEL_FORMAT_YUV444, AVIF_PIXEL_FORMAT_YUV422, AVIF_PIXEL_FORMAT_YUV420, AVIF_PIXEL_FORMAT_YUV400 };
INSTANTIATE_TEST_SUITE_P(Valid,
GridApiTest,
Combine(/*horizontal=*/ValuesIn(kValidCells),
/*vertical=*/ValuesIn(kValidCells),
ValuesIn(kBitDepths),
ValuesIn(kPixelFormats),
/*createAlpha=*/Values(false, true),
/*expectedSuccess=*/Values(true)));
INSTANTIATE_TEST_SUITE_P(InvalidVertically,
GridApiTest,
Combine(/*horizontal=*/ValuesIn(kValidCells),
/*vertical=*/ValuesIn(kInvalidCells),
ValuesIn(kBitDepths),
ValuesIn(kPixelFormats),
/*createAlpha=*/Values(false, true),
/*expectedSuccess=*/Values(false)));
INSTANTIATE_TEST_SUITE_P(InvalidHorizontally,
GridApiTest,
Combine(/*horizontal=*/ValuesIn(kInvalidCells),
/*vertical=*/ValuesIn(kValidCells),
ValuesIn(kBitDepths),
ValuesIn(kPixelFormats),
/*createAlpha=*/Values(false, true),
/*expectedSuccess=*/Values(false)));
INSTANTIATE_TEST_SUITE_P(InvalidBoth,
GridApiTest,
Combine(/*horizontal=*/ValuesIn(kInvalidCells),
/*vertical=*/ValuesIn(kInvalidCells),
ValuesIn(kBitDepths),
ValuesIn(kPixelFormats),
/*createAlpha=*/Values(false, true),
/*expectedSuccess=*/Values(false)));
// Special case depending on the cell count and the chroma subsampling.
INSTANTIATE_TEST_SUITE_P(ValidOddHeight,
GridApiTest,
Combine(/*horizontal=*/Values(Cell { 1, 64 }),
/*vertical=*/Values(Cell { 1, 65 }, Cell { 2, 65 }),
ValuesIn(kBitDepths),
Values(AVIF_PIXEL_FORMAT_YUV444, AVIF_PIXEL_FORMAT_YUV422, AVIF_PIXEL_FORMAT_YUV400),
/*createAlpha=*/Values(false, true),
/*expectedSuccess=*/Values(true)));
INSTANTIATE_TEST_SUITE_P(InvalidOddHeight,
GridApiTest,
Combine(/*horizontal=*/Values(Cell { 1, 64 }),
/*vertical=*/Values(Cell { 2, 65 }),
ValuesIn(kBitDepths),
Values(AVIF_PIXEL_FORMAT_YUV420),
/*createAlpha=*/Values(false, true),
/*expectedSuccess=*/Values(false)));
// Special case depending on the cell count and the cell size.
INSTANTIATE_TEST_SUITE_P(ValidOddDimensions,
GridApiTest,
Combine(/*horizontal=*/Values(Cell { 1, 1 }),
/*vertical=*/Values(Cell { 1, 65 }),
ValuesIn(kBitDepths),
ValuesIn(kPixelFormats),
/*createAlpha=*/Values(false, true),
/*expectedSuccess=*/Values(true)));
INSTANTIATE_TEST_SUITE_P(InvalidOddDimensions,
GridApiTest,
Combine(/*horizontal=*/Values(Cell { 2, 1 }),
/*vertical=*/Values(Cell { 1, 65 }, Cell { 2, 65 }),
ValuesIn(kBitDepths),
ValuesIn(kPixelFormats),
/*createAlpha=*/Values(false, true),
/*expectedSuccess=*/Values(false)));
} // namespace
} // namespace libavif