| // Copyright 2024 Google LLC | |
| // SPDX-License-Identifier: BSD-2-Clause | |
| #include <cstring> | |
| #include <iostream> | |
| #include <string> | |
| #include <vector> | |
| #include "avif/avif.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(AvifPropertyTest, Parse) { | |
| const std::string path = | |
| std::string(data_path) + "circle_custom_properties.avif"; | |
| DecoderPtr decoder(avifDecoderCreate()); | |
| ASSERT_NE(decoder, nullptr); | |
| ASSERT_EQ(avifDecoderSetIOFile(decoder.get(), path.c_str()), AVIF_RESULT_OK); | |
| ASSERT_EQ(avifDecoderParse(decoder.get()), AVIF_RESULT_OK); | |
| ASSERT_EQ(decoder->image->numProperties, 3u); | |
| const avifImageItemProperty& p1234 = decoder->image->properties[0]; | |
| EXPECT_EQ(std::string(p1234.boxtype, p1234.boxtype + 4), "1234"); | |
| EXPECT_EQ(std::vector<uint8_t>(p1234.boxPayload.data, | |
| p1234.boxPayload.data + p1234.boxPayload.size), | |
| std::vector<uint8_t>({/*version*/ 0, /*flags*/ 0, 0, 0, | |
| /*FullBoxPayload*/ 1, 2, 3, 4})); | |
| const avifImageItemProperty& abcd = decoder->image->properties[1]; | |
| EXPECT_EQ(std::string(abcd.boxtype, abcd.boxtype + 4), "abcd"); | |
| EXPECT_EQ(std::string(reinterpret_cast<const char*>(abcd.boxPayload.data)), | |
| "abcd"); | |
| const avifImageItemProperty& uuid = decoder->image->properties[2]; | |
| EXPECT_EQ(std::string(uuid.boxtype, uuid.boxtype + 4), "uuid"); | |
| EXPECT_EQ(std::string(uuid.usertype, uuid.usertype + 16), "extended_type 16"); | |
| EXPECT_EQ(uuid.boxPayload.size, 0); | |
| } | |
| TEST(AvifPropertyTest, Serialise) { | |
| ImagePtr image = testutil::CreateImage(128, 30, 8, AVIF_PIXEL_FORMAT_YUV420, | |
| AVIF_PLANES_ALL); | |
| ASSERT_NE(image, nullptr); | |
| testutil::FillImageGradient(image.get()); | |
| std::vector<uint8_t> abcd_data({0, 0, 0, 1, 'a', 'b', 'c'}); | |
| std::vector<uint8_t> efgh_data({'e', 'h'}); | |
| uint8_t uuid[16] = {0x95, 0x96, 0xf1, 0xad, 0xb8, 0xab, 0x4a, 0xfc, | |
| 0x9e, 0xfc, 0x83, 0x87, 0xac, 0x79, 0x37, 0xda}; | |
| std::vector<uint8_t> uuid_data({'x', 'y', 'z'}); | |
| ASSERT_EQ(avifImageAddOpaqueProperty(image.get(), (uint8_t*)"abcd", | |
| abcd_data.data(), abcd_data.size()), | |
| AVIF_RESULT_OK); | |
| ASSERT_EQ(avifImageAddOpaqueProperty(image.get(), (uint8_t*)"efgh", | |
| efgh_data.data(), efgh_data.size()), | |
| AVIF_RESULT_OK); | |
| // Should not be added | |
| ASSERT_EQ(avifImageAddOpaqueProperty(image.get(), (uint8_t*)"mdat", | |
| efgh_data.data(), efgh_data.size()), | |
| AVIF_RESULT_INVALID_ARGUMENT); | |
| ASSERT_EQ(avifImageAddUUIDProperty(image.get(), uuid, uuid_data.data(), | |
| uuid_data.size()), | |
| AVIF_RESULT_OK); | |
| EncoderPtr encoder(avifEncoderCreate()); | |
| ASSERT_NE(encoder, nullptr); | |
| testutil::AvifRwData encoded; | |
| avifResult result = avifEncoderWrite(encoder.get(), image.get(), &encoded); | |
| ASSERT_EQ(result, AVIF_RESULT_OK) << avifResultToString(result); | |
| DecoderPtr decoder(avifDecoderCreate()); | |
| ASSERT_NE(decoder, nullptr); | |
| ASSERT_EQ(avifDecoderSetIOMemory(decoder.get(), encoded.data, encoded.size), | |
| AVIF_RESULT_OK); | |
| ASSERT_EQ(avifDecoderParse(decoder.get()), AVIF_RESULT_OK); | |
| ASSERT_EQ(decoder->image->numProperties, 3u); | |
| const avifImageItemProperty& abcd = decoder->image->properties[0]; | |
| EXPECT_EQ(std::string(abcd.boxtype, abcd.boxtype + 4), "abcd"); | |
| EXPECT_EQ(std::vector<uint8_t>(abcd.boxPayload.data, | |
| abcd.boxPayload.data + abcd.boxPayload.size), | |
| abcd_data); | |
| const avifImageItemProperty& efgh = decoder->image->properties[1]; | |
| EXPECT_EQ(std::string(efgh.boxtype, efgh.boxtype + 4), "efgh"); | |
| EXPECT_EQ(std::vector<uint8_t>(efgh.boxPayload.data, | |
| efgh.boxPayload.data + efgh.boxPayload.size), | |
| efgh_data); | |
| const avifImageItemProperty& uuidProp = decoder->image->properties[2]; | |
| EXPECT_EQ(std::string(uuidProp.boxtype, uuidProp.boxtype + 4), "uuid"); | |
| EXPECT_EQ(std::vector<uint8_t>(uuidProp.usertype, uuidProp.usertype + 16), | |
| std::vector<uint8_t>(uuid, uuid + 16)); | |
| EXPECT_EQ( | |
| std::vector<uint8_t>(uuidProp.boxPayload.data, | |
| uuidProp.boxPayload.data + uuidProp.boxPayload.size), | |
| uuid_data); | |
| } | |
| TEST(AvifPropertyTest, TooManyUniqueProperties) { | |
| ImagePtr image = testutil::CreateImage(128, 30, 8, AVIF_PIXEL_FORMAT_YUV420, | |
| AVIF_PLANES_ALL); | |
| ASSERT_NE(image, nullptr); | |
| testutil::FillImageGradient(image.get()); | |
| for (uint8_t i = 0; i < 128; ++i) { | |
| ASSERT_EQ(avifImageAddOpaqueProperty(image.get(), (uint8_t*)"abcd", &i, 1), | |
| AVIF_RESULT_OK); | |
| } | |
| EncoderPtr encoder(avifEncoderCreate()); | |
| ASSERT_NE(encoder, nullptr); | |
| testutil::AvifRwData encoded; | |
| ASSERT_EQ(avifEncoderWrite(encoder.get(), image.get(), &encoded), | |
| AVIF_RESULT_INVALID_ARGUMENT); | |
| } | |
| TEST(AvifPropertyTest, ManyTimesTheSameProperty) { | |
| ImagePtr image = testutil::CreateImage(128, 30, 8, AVIF_PIXEL_FORMAT_YUV420, | |
| AVIF_PLANES_ALL); | |
| ASSERT_NE(image, nullptr); | |
| testutil::FillImageGradient(image.get()); | |
| for (uint8_t i = 0; i < 128; ++i) { | |
| const uint8_t sameData = 42; | |
| ASSERT_EQ( | |
| avifImageAddOpaqueProperty(image.get(), (uint8_t*)"abcd", &sameData, 1), | |
| AVIF_RESULT_OK); | |
| } | |
| EncoderPtr encoder(avifEncoderCreate()); | |
| ASSERT_NE(encoder, nullptr); | |
| testutil::AvifRwData encoded; | |
| ASSERT_EQ(avifEncoderWrite(encoder.get(), image.get(), &encoded), | |
| AVIF_RESULT_OK); | |
| } | |
| //------------------------------------------------------------------------------ | |
| } // 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(); | |
| } |