blob: a04ae36d500850aa26949e9c5159e0e397438b57 [file] [edit]
// Copyright 2022 Google LLC
// SPDX-License-Identifier: BSD-2-Clause
#include <cstring>
#include <vector>
#include "avif/avif.h"
#include "avif/internal.h"
#include "aviftest_helpers.h"
#include "gtest/gtest.h"
namespace avif {
namespace {
// Returns the content of the first box of the given type among the sibling
// boxes contained in container_content, or an empty avifROData if not found.
avifROData FindBox(avifROData container_content, const char type[4]) {
avifROStream stream;
avifROStreamStart(&stream, &container_content,
/*diag=*/nullptr, /*diagContext=*/nullptr);
avifBoxHeader header;
while (avifROStreamReadBoxHeader(&stream, &header)) {
if (!memcmp(header.type, type, 4)) {
return {avifROStreamCurrent(&stream), header.size};
}
if (!avifROStreamSkip(&stream, header.size)) {
break;
}
}
return {nullptr, 0};
}
// One AVIF cell in an AVIF grid.
struct Cell {
int width, height; // In pixels.
};
avifResult EncodeDecodeGrid(const std::vector<std::vector<Cell>>& cell_rows,
avifPixelFormat yuv_format) {
// Construct a grid.
std::vector<ImagePtr> cell_images;
cell_images.reserve(cell_rows.size() * cell_rows.front().size());
for (const std::vector<Cell>& cell_row : cell_rows) {
assert(cell_row.size() == cell_rows.front().size());
for (const Cell& cell : cell_row) {
cell_images.emplace_back(testutil::CreateImage(
cell.width, cell.height, /*depth=*/8, yuv_format, AVIF_PLANES_ALL));
if (!cell_images.back()) {
return AVIF_RESULT_INVALID_ARGUMENT;
}
testutil::FillImageGradient(cell_images.back().get());
}
}
// Encode the grid image (losslessly for easy pixel-by-pixel comparison).
EncoderPtr encoder(avifEncoderCreate());
if (!encoder) {
return AVIF_RESULT_OUT_OF_MEMORY;
}
encoder->speed = AVIF_SPEED_FASTEST;
encoder->quality = AVIF_QUALITY_LOSSLESS;
encoder->qualityAlpha = AVIF_QUALITY_LOSSLESS;
// cell_image_ptrs exists only to match the libavif API.
std::vector<avifImage*> cell_image_ptrs(cell_images.size());
for (size_t i = 0; i < cell_images.size(); ++i) {
cell_image_ptrs[i] = cell_images[i].get();
}
avifResult result = avifEncoderAddImageGrid(
encoder.get(), static_cast<uint32_t>(cell_rows.front().size()),
static_cast<uint32_t>(cell_rows.size()), cell_image_ptrs.data(),
AVIF_ADD_IMAGE_FLAG_SINGLE);
if (result != AVIF_RESULT_OK) {
return result;
}
testutil::AvifRwData encoded_avif;
result = avifEncoderFinish(encoder.get(), &encoded_avif);
if (result != AVIF_RESULT_OK) {
return result;
}
// Decode the grid image.
ImagePtr image(avifImageCreateEmpty());
DecoderPtr decoder(avifDecoderCreate());
if (!image || !decoder) {
return AVIF_RESULT_OUT_OF_MEMORY;
}
result = avifDecoderReadMemory(decoder.get(), image.get(), encoded_avif.data,
encoded_avif.size);
if (result != AVIF_RESULT_OK) {
return result;
}
// Reconstruct the input image by merging all cells into a single avifImage.
ImagePtr grid = testutil::CreateImage(
static_cast<int>(image->width), static_cast<int>(image->height),
/*depth=*/8, yuv_format, AVIF_PLANES_ALL);
const int num_rows = (int)cell_rows.size();
const int num_cols = (int)cell_rows[0].size();
AVIF_CHECKRES(
testutil::MergeGrid(num_cols, num_rows, cell_images, grid.get()));
if ((grid->width != image->width) || (grid->height != image->height) ||
!testutil::AreImagesEqual(*image, *grid)) {
return AVIF_RESULT_UNKNOWN_ERROR;
}
return AVIF_RESULT_OK;
}
TEST(GridApiTest, SingleCell) {
for (avifPixelFormat pixel_format :
{AVIF_PIXEL_FORMAT_YUV444, AVIF_PIXEL_FORMAT_YUV422,
AVIF_PIXEL_FORMAT_YUV420, AVIF_PIXEL_FORMAT_YUV400}) {
// Rules on grids do not apply to a single cell.
EXPECT_EQ(EncodeDecodeGrid({{{1, 1}}}, pixel_format), AVIF_RESULT_OK);
EXPECT_EQ(EncodeDecodeGrid({{{1, 64}}}, pixel_format), AVIF_RESULT_OK);
EXPECT_EQ(EncodeDecodeGrid({{{64, 1}}}, pixel_format), AVIF_RESULT_OK);
EXPECT_EQ(EncodeDecodeGrid({{{64, 64}}}, pixel_format), AVIF_RESULT_OK);
EXPECT_EQ(EncodeDecodeGrid({{{127, 127}}}, pixel_format), AVIF_RESULT_OK);
}
}
TEST(GridApiTest, CellsOfSameDimensions) {
for (avifPixelFormat pixel_format :
{AVIF_PIXEL_FORMAT_YUV444, AVIF_PIXEL_FORMAT_YUV422,
AVIF_PIXEL_FORMAT_YUV420, AVIF_PIXEL_FORMAT_YUV400}) {
// ISO/IEC 23000-22:2019, Section 7.3.11.4.2:
// - the tile_width shall be greater than or equal to 64, and should be a
// multiple of 64
// - the tile_height shall be greater than or equal to 64, and should be a
// multiple of 64
EXPECT_EQ(EncodeDecodeGrid({{{64, 64}, {64, 64}, {64, 64}}}, pixel_format),
AVIF_RESULT_OK);
EXPECT_EQ(EncodeDecodeGrid({{{100, 110}}, //
{{100, 110}}, //
{{100, 110}}},
pixel_format),
AVIF_RESULT_OK);
EXPECT_EQ(EncodeDecodeGrid({{{64, 64}, {64, 64}, {64, 64}},
{{64, 64}, {64, 64}, {64, 64}},
{{64, 64}, {64, 64}, {64, 64}}},
pixel_format),
AVIF_RESULT_OK);
EXPECT_EQ(EncodeDecodeGrid({{{2, 64}, {2, 64}}}, pixel_format),
AVIF_RESULT_INVALID_IMAGE_GRID);
EXPECT_EQ(EncodeDecodeGrid({{{64, 62}, {64, 62}}}, pixel_format),
AVIF_RESULT_INVALID_IMAGE_GRID);
EXPECT_EQ(EncodeDecodeGrid({{{64, 2}}, //
{{64, 2}}},
pixel_format),
AVIF_RESULT_INVALID_IMAGE_GRID);
EXPECT_EQ(EncodeDecodeGrid({{{2, 64}}, //
{{2, 64}}},
pixel_format),
AVIF_RESULT_INVALID_IMAGE_GRID);
}
// ISO/IEC 23000-22:2019, Section 7.3.11.4.2:
// - when the images are in the 4:2:2 chroma sampling format the horizontal
// tile offsets and widths, and the output width, shall be even numbers;
EXPECT_EQ(EncodeDecodeGrid({{{64, 65}, {64, 65}}}, AVIF_PIXEL_FORMAT_YUV422),
AVIF_RESULT_OK);
EXPECT_EQ(EncodeDecodeGrid({{{65, 64}, {65, 64}}}, AVIF_PIXEL_FORMAT_YUV422),
AVIF_RESULT_INVALID_IMAGE_GRID);
// - when the images are in the 4:2:0 chroma sampling format both the
// horizontal and vertical tile offsets and widths, and the output width
// and height, shall be even numbers.
EXPECT_EQ(EncodeDecodeGrid({{{64, 65}, {64, 65}}}, AVIF_PIXEL_FORMAT_YUV420),
AVIF_RESULT_INVALID_IMAGE_GRID);
EXPECT_EQ(EncodeDecodeGrid({{{65, 64}, {65, 64}}}, AVIF_PIXEL_FORMAT_YUV420),
AVIF_RESULT_INVALID_IMAGE_GRID);
}
TEST(GridApiTest, CellsOfDifferentDimensions) {
for (avifPixelFormat pixel_format :
{AVIF_PIXEL_FORMAT_YUV444, AVIF_PIXEL_FORMAT_YUV422,
AVIF_PIXEL_FORMAT_YUV420, AVIF_PIXEL_FORMAT_YUV400}) {
// Right-most cells are narrower.
EXPECT_EQ(
EncodeDecodeGrid({{{100, 100}, {100, 100}, {66, 100}}}, pixel_format),
AVIF_RESULT_OK);
// Bottom-most cells are shorter.
EXPECT_EQ(EncodeDecodeGrid({{{100, 100}, {100, 100}},
{{100, 100}, {100, 100}},
{{100, 66}, {100, 66}}},
pixel_format),
AVIF_RESULT_OK);
// Right-most cells are narrower and bottom-most cells are shorter.
EXPECT_EQ(EncodeDecodeGrid({{{100, 100}, {100, 100}, {66, 100}},
{{100, 100}, {100, 100}, {66, 100}},
{{100, 66}, {100, 66}, {66, 66}}},
pixel_format),
AVIF_RESULT_OK);
// Right-most cells are wider.
EXPECT_EQ(EncodeDecodeGrid({{{100, 100}, {100, 100}, {222, 100}},
{{100, 100}, {100, 100}, {222, 100}},
{{100, 100}, {100, 100}, {222, 100}}},
pixel_format),
AVIF_RESULT_INVALID_IMAGE_GRID);
// Bottom-most cells are taller.
EXPECT_EQ(EncodeDecodeGrid({{{100, 100}, {100, 100}, {100, 100}},
{{100, 100}, {100, 100}, {100, 100}},
{{100, 222}, {100, 222}, {100, 222}}},
pixel_format),
AVIF_RESULT_INVALID_IMAGE_GRID);
// One cell dimension is off.
EXPECT_EQ(EncodeDecodeGrid({{{100, 100}, {100, 100}, {100, 100}},
{{100, 100}, {66 /* here */, 100}, {100, 100}},
{{100, 100}, {100, 100}, {100, 100}}},
pixel_format),
AVIF_RESULT_INVALID_IMAGE_GRID);
EXPECT_EQ(EncodeDecodeGrid({{{100, 100}, {100, 100}, {66, 100}},
{{100, 100}, {100, 100}, {66, 100}},
{{100, 66}, {100, 66}, {66, 100 /* here */}}},
pixel_format),
AVIF_RESULT_INVALID_IMAGE_GRID);
}
// ISO/IEC 23000-22:2019, Section 7.3.11.4.2:
// - when the images are in the 4:2:2 chroma sampling format the horizontal
// tile offsets and widths, and the output width, shall be even numbers;
EXPECT_EQ(EncodeDecodeGrid({{{66, 66}}, //
{{66, 65}}},
AVIF_PIXEL_FORMAT_YUV422),
AVIF_RESULT_OK);
EXPECT_EQ(EncodeDecodeGrid({{{66, 66}, {65, 66}}}, AVIF_PIXEL_FORMAT_YUV422),
AVIF_RESULT_INVALID_IMAGE_GRID);
// - when the images are in the 4:2:0 chroma sampling format both the
// horizontal and vertical tile offsets and widths, and the output width
// and height, shall be even numbers.
EXPECT_EQ(EncodeDecodeGrid({{{66, 66}}, //
{{66, 65}}},
AVIF_PIXEL_FORMAT_YUV420),
AVIF_RESULT_INVALID_IMAGE_GRID);
EXPECT_EQ(EncodeDecodeGrid({{{66, 66}, {65, 66}}}, AVIF_PIXEL_FORMAT_YUV420),
AVIF_RESULT_INVALID_IMAGE_GRID);
}
//------------------------------------------------------------------------------
TEST(GridApiTest, ColorAlphaGridExceeding16BitItemIDs) {
// A color grid and an alpha grid of 128x256 cells each contain 32768 cells,
// so encoding them requires 65538 distinct item IDs (2 grid items + 2 x 32768
// cell items), which does not fit in the 16-bit item ID space (item ID 0 is
// also invalid, see ISO/IEC 14496-12 Section 8.11.1.1). The encoder writes
// the 32-bit item ID variants of the boxes with item ID fields
// ('pitm' version 1, 'iloc' version 2, 'iinf' version 1, 'infe' version 3,
// 'iref' version 1 and 'ipma' version 1) so that such files are valid.
// The cells are 64x64 because it is the smallest size allowed by MIAF.
// Note: Most of the time spent in this test is the encoding of the 65536
// cells. The generated file is not parsed with avifDecoderParse() because
// that would cost minutes with the current quadratic lookups for this many
// items; walking the boxes below is enough to check what was written.
ImagePtr cell = testutil::CreateImage(
/*width=*/64, /*height=*/64, /*depth=*/8, AVIF_PIXEL_FORMAT_YUV400,
AVIF_PLANES_ALL /* the alpha channel is needed */);
ASSERT_NE(cell, nullptr);
// The pixels do not matter but avoid use-of-uninitialized-value errors.
testutil::FillImageGradient(cell.get());
const std::vector<avifImage*> cell_image_ptrs(128 * 256, cell.get());
EncoderPtr encoder(avifEncoderCreate());
ASSERT_NE(encoder, nullptr);
// Worst quality to keep the encoding of the 65536 cells as fast as possible.
encoder->speed = AVIF_SPEED_FASTEST;
encoder->quality = AVIF_QUALITY_WORST;
ASSERT_EQ(avifEncoderAddImageGrid(encoder.get(), /*gridCols=*/128,
/*gridRows=*/256, cell_image_ptrs.data(),
AVIF_ADD_IMAGE_FLAG_SINGLE),
AVIF_RESULT_OK);
testutil::AvifRwData encoded_avif;
ASSERT_EQ(avifEncoderFinish(encoder.get(), &encoded_avif), AVIF_RESULT_OK);
// The color grid item, the color cell items, the alpha grid item, the alpha
// cell items and possibly some metadata items are given sequential item IDs,
// starting with the primary item (the color grid item).
constexpr uint32_t kExpectedItemCount = 65538;
const avifROData file = {encoded_avif.data, encoded_avif.size};
avifROData meta = FindBox(file, "meta");
ASSERT_NE(meta.data, nullptr);
// The 'meta' box is a FullBox: its version and flags come before its child
// boxes.
const avifROData meta_children = {meta.data + 4, meta.size - 4};
// 'pitm' version 1 and a 32-bit primary item ID.
avifROData pitm = FindBox(meta_children, "pitm");
ASSERT_NE(pitm.data, nullptr);
{
avifROStream stream;
avifROStreamStart(&stream, &pitm, /*diag=*/nullptr,
/*diagContext=*/nullptr);
uint8_t version;
uint32_t flags;
ASSERT_TRUE(avifROStreamReadVersionAndFlags(&stream, &version, &flags));
EXPECT_EQ(version, 1);
uint32_t item_id;
ASSERT_TRUE(avifROStreamReadU32(&stream, &item_id));
EXPECT_EQ(item_id, 1);
}
// 'iloc' version 2 and a 32-bit item_count.
avifROData iloc = FindBox(meta_children, "iloc");
ASSERT_NE(iloc.data, nullptr);
{
avifROStream stream;
avifROStreamStart(&stream, &iloc, /*diag=*/nullptr,
/*diagContext=*/nullptr);
uint8_t version;
ASSERT_TRUE(avifROStreamReadVersionAndFlags(&stream, &version, nullptr));
EXPECT_EQ(version, 2);
ASSERT_TRUE(avifROStreamSkip(
&stream,
2)); // offset_size, length_size, base_offset_size and index_size
uint32_t item_count;
ASSERT_TRUE(avifROStreamReadU32(&stream, &item_count));
EXPECT_EQ(item_count, kExpectedItemCount);
}
// 'iinf' version 1, a 32-bit entry_count, and 'infe' entries with version 3.
avifROData iinf = FindBox(meta_children, "iinf");
ASSERT_NE(iinf.data, nullptr);
{
avifROStream stream;
avifROStreamStart(&stream, &iinf, /*diag=*/nullptr,
/*diagContext=*/nullptr);
uint8_t version;
ASSERT_TRUE(avifROStreamReadVersionAndFlags(&stream, &version, nullptr));
EXPECT_EQ(version, 1);
uint32_t entry_count;
ASSERT_TRUE(avifROStreamReadU32(&stream, &entry_count));
EXPECT_EQ(entry_count, kExpectedItemCount);
// The 'infe' child boxes follow the version, flags and entry_count fields.
avifROData iinf_children = {iinf.data + 8, iinf.size - 8};
avifROData infe = FindBox(iinf_children, "infe");
ASSERT_NE(infe.data, nullptr);
avifROStream infe_stream;
avifROStreamStart(&infe_stream, &infe, /*diag=*/nullptr,
/*diagContext=*/nullptr);
ASSERT_TRUE(
avifROStreamReadVersionAndFlags(&infe_stream, &version, nullptr));
EXPECT_EQ(version, 3);
uint32_t item_id;
ASSERT_TRUE(avifROStreamReadU32(&infe_stream, &item_id));
EXPECT_EQ(item_id, 1);
}
// 'iref' version 1 and 32-bit item_ID fields in the 'dimg' references.
avifROData iref = FindBox(meta_children, "iref");
ASSERT_NE(iref.data, nullptr);
{
avifROStream stream;
avifROStreamStart(&stream, &iref, /*diag=*/nullptr,
/*diagContext=*/nullptr);
uint8_t version;
ASSERT_TRUE(avifROStreamReadVersionAndFlags(&stream, &version, nullptr));
EXPECT_EQ(version, 1);
// The SingleItemTypeReferenceBox child boxes follow the version and flags.
avifROData iref_children = {iref.data + 4, iref.size - 4};
avifROData dimg = FindBox(iref_children, "dimg");
ASSERT_NE(dimg.data, nullptr);
avifROStream dimg_stream;
avifROStreamStart(&dimg_stream, &dimg, /*diag=*/nullptr,
/*diagContext=*/nullptr);
uint32_t from_item_id;
ASSERT_TRUE(avifROStreamReadU32(&dimg_stream, &from_item_id));
EXPECT_EQ(from_item_id, 1);
uint16_t reference_count;
ASSERT_TRUE(avifROStreamReadU16(&dimg_stream, &reference_count));
EXPECT_EQ(reference_count, 32768);
}
// 'ipma' version 1 and a 32-bit item_ID field per entry.
const avifROData iprp = FindBox(meta_children, "iprp");
ASSERT_NE(iprp.data, nullptr);
avifROData ipma = FindBox(iprp, "ipma");
ASSERT_NE(ipma.data, nullptr);
{
avifROStream stream;
avifROStreamStart(&stream, &ipma, /*diag=*/nullptr,
/*diagContext=*/nullptr);
uint8_t version;
uint32_t flags;
ASSERT_TRUE(avifROStreamReadVersionAndFlags(&stream, &version, &flags));
EXPECT_EQ(version, 1);
EXPECT_EQ(flags, 0); // The property_index fields are 7-bit wide.
uint32_t entry_count;
ASSERT_TRUE(avifROStreamReadU32(&stream, &entry_count));
EXPECT_EQ(entry_count, kExpectedItemCount);
uint32_t item_id;
ASSERT_TRUE(avifROStreamReadU32(&stream, &item_id));
EXPECT_EQ(item_id, 1);
}
}
TEST(GridApiTest, CellCountExceeding16BitReferenceCount) {
// A 256x256 grid contains 65536 cells, which does not fit in the 16-bit
// reference_count field of a 'dimg' item reference (ISO/IEC 14496-12
// Section 8.11.12), so avifEncoderAddImageGrid() refuses it. Note that the
// maximum is a single 256x256 grid; any other combination of grid
// dimensions is at most 256x255 = 65280 cells.
ImagePtr cell = testutil::CreateImage(
/*width=*/64, /*height=*/64, /*depth=*/8, AVIF_PIXEL_FORMAT_YUV400,
AVIF_PLANES_ALL);
ASSERT_NE(cell, nullptr);
const std::vector<avifImage*> cell_image_ptrs(256 * 256, cell.get());
EncoderPtr encoder(avifEncoderCreate());
ASSERT_NE(encoder, nullptr);
ASSERT_EQ(avifEncoderAddImageGrid(encoder.get(), /*gridCols=*/256,
/*gridRows=*/256, cell_image_ptrs.data(),
AVIF_ADD_IMAGE_FLAG_SINGLE),
AVIF_RESULT_INVALID_IMAGE_GRID);
}
//------------------------------------------------------------------------------
TEST(GridApiTest, SameMatrixCoefficients) {
ImagePtr cell_0 = testutil::CreateImage(
64, 64, /*depth=*/8, AVIF_PIXEL_FORMAT_YUV444, AVIF_PLANES_ALL);
ImagePtr cell_1 = testutil::CreateImage(
1, 64, /*depth=*/8, AVIF_PIXEL_FORMAT_YUV444, AVIF_PLANES_ALL);
ASSERT_NE(cell_0, nullptr);
ASSERT_NE(cell_1, nullptr);
// The pixels do not matter but avoid use-of-uninitialized-value errors.
testutil::FillImageGradient(cell_0.get());
testutil::FillImageGradient(cell_1.get());
// All input cells have the same non-default properties.
cell_0->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_BT601;
cell_1->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_BT601;
EncoderPtr encoder(avifEncoderCreate());
ASSERT_NE(encoder, nullptr);
encoder->speed = AVIF_SPEED_FASTEST;
const avifImage* cell_image_ptrs[2] = {cell_0.get(), cell_1.get()};
ASSERT_EQ(
avifEncoderAddImageGrid(encoder.get(), /*gridCols=*/2, /*gridRows=*/1,
cell_image_ptrs, AVIF_ADD_IMAGE_FLAG_SINGLE),
AVIF_RESULT_OK);
testutil::AvifRwData encoded_avif;
ASSERT_EQ(avifEncoderFinish(encoder.get(), &encoded_avif), AVIF_RESULT_OK);
ASSERT_NE(testutil::Decode(encoded_avif.data, encoded_avif.size), nullptr);
}
TEST(GridApiTest, DifferentMatrixCoefficients) {
ImagePtr cell_0 = testutil::CreateImage(
64, 64, /*depth=*/8, AVIF_PIXEL_FORMAT_YUV444, AVIF_PLANES_ALL);
ImagePtr cell_1 = testutil::CreateImage(
1, 64, /*depth=*/8, AVIF_PIXEL_FORMAT_YUV444, AVIF_PLANES_ALL);
ASSERT_NE(cell_0, nullptr);
ASSERT_NE(cell_1, nullptr);
// The pixels do not matter but avoid use-of-uninitialized-value errors.
testutil::FillImageGradient(cell_0.get());
testutil::FillImageGradient(cell_1.get());
// Some input cells have different properties.
cell_0->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_BT601;
cell_1->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_UNSPECIFIED;
EncoderPtr encoder(avifEncoderCreate());
ASSERT_NE(encoder, nullptr);
encoder->speed = AVIF_SPEED_FASTEST;
// Encoding should fail.
const avifImage* cell_image_ptrs[2] = {cell_0.get(), cell_1.get()};
ASSERT_EQ(
avifEncoderAddImageGrid(encoder.get(), /*gridCols=*/2, /*gridRows=*/1,
cell_image_ptrs, AVIF_ADD_IMAGE_FLAG_SINGLE),
AVIF_RESULT_INVALID_IMAGE_GRID);
}
TEST(GridApiTest, CellsTooManyForDimgReferenceCount) {
// Section 8.11.12.1 of ISO/IEC 14496-12 requires all the references from one
// item to be collected into a single item type reference box, whose
// reference_count field is unsigned int(16) whatever the 'iref' version
// (Section 8.11.12.2). ISO/IEC 23008-12 (HEIF) Section 6.6.1 additionally
// forbids more than one 'dimg' box with the same from_item_ID. A grid item
// therefore cannot have more than 65535 cells, so a 256x256-cell grid is
// rejected upfront instead of silently generating a broken file.
ImagePtr cell = testutil::CreateImage(
/*width=*/64, /*height=*/64, /*depth=*/8, AVIF_PIXEL_FORMAT_YUV400,
AVIF_PLANES_YUV);
ASSERT_NE(cell, nullptr);
testutil::FillImageGradient(cell.get());
const std::vector<avifImage*> cell_image_ptrs(256 * 256, cell.get());
EncoderPtr encoder(avifEncoderCreate());
ASSERT_NE(encoder, nullptr);
encoder->speed = AVIF_SPEED_FASTEST;
ASSERT_EQ(avifEncoderAddImageGrid(encoder.get(), /*gridCols=*/256,
/*gridRows=*/256, cell_image_ptrs.data(),
AVIF_ADD_IMAGE_FLAG_SINGLE),
AVIF_RESULT_INVALID_IMAGE_GRID);
}
} // namespace
} // namespace avif