| // Copyright 2024 Google LLC |
| // SPDX-License-Identifier: BSD-2-Clause |
| |
| #include <array> |
| #include <string> |
| |
| #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(KeyframeTest, Decode) { |
| if (!testutil::Av1DecoderAvailable()) { |
| GTEST_SKIP() << "AV1 Codec unavailable, skip test."; |
| } |
| |
| std::array<ImagePtr, 5> images; |
| for (ImagePtr& image : images) { |
| // Use 12-bit 4:2:2 studio range for extra coverage. |
| image = testutil::CreateImage(64, 64, 12, AVIF_PIXEL_FORMAT_YUV422, |
| AVIF_PLANES_ALL, AVIF_RANGE_LIMITED); |
| ASSERT_NE(image, nullptr); |
| } |
| |
| // Alpha is always full range. |
| constexpr uint32_t kColor[4] = {3760, 3840, 3840, 4095}; |
| testutil::FillImagePlain(images[0].get(), kColor); |
| constexpr uint32_t kSomeColor[4] = {3760, 256, 256, 4095}; |
| testutil::FillImagePlain(images[1].get(), kSomeColor); |
| constexpr uint32_t kTranslucentColor[4] = {256, 256, 256, 2002}; |
| testutil::FillImagePlain(images[2].get(), kTranslucentColor); |
| testutil::FillImageGradient(images[3].get()); |
| testutil::FillImageGradient(images[4].get()); |
| |
| // The file read below was generated with the following: |
| |
| // EncoderPtr e(avifEncoderCreate()); e->timescale = 1; |
| // avifEncoderAddImage(e.get(), images[1].get(), 1, AVIF_ADD_IMAGE_FLAG_NONE); |
| // avifEncoderAddImage(e.get(), images[1].get(), 1, AVIF_ADD_IMAGE_FLAG_NONE); |
| // avifEncoderAddImage(e.get(), images[1].get(), 1, |
| // AVIF_ADD_IMAGE_FLAG_FORCE_KEYFRAME); |
| // avifEncoderAddImage(e.get(), images[1].get(), 1, AVIF_ADD_IMAGE_FLAG_NONE); |
| // avifEncoderAddImage(e.get(), images[1].get(), 1, AVIF_ADD_IMAGE_FLAG_NONE); |
| // testutil::AvifRwData encoded; avifEncoderFinish(e.get(), &encoded); |
| |
| // Reading a file makes sure the encoder does not pick different keyframes in |
| // the future. |
| |
| DecoderPtr decoder(avifDecoderCreate()); |
| ASSERT_NE(decoder, nullptr); |
| const std::string file_name = "colors-animated-12bpc-keyframes-0-2-3.avif"; |
| ASSERT_EQ( |
| avifDecoderSetIOFile(decoder.get(), (data_path + file_name).c_str()), |
| AVIF_RESULT_OK); |
| ASSERT_EQ(avifDecoderParse(decoder.get()), AVIF_RESULT_OK); |
| |
| // The first frame is always a keyframe. |
| EXPECT_TRUE(avifDecoderIsKeyframe(decoder.get(), 0)); |
| EXPECT_EQ(avifDecoderNearestKeyframe(decoder.get(), 0), 0); |
| |
| // The encoder may choose to use a keyframe here, even without FORCE_KEYFRAME. |
| // It seems not to. |
| EXPECT_FALSE(avifDecoderIsKeyframe(decoder.get(), 1)); |
| EXPECT_EQ(avifDecoderNearestKeyframe(decoder.get(), 1), 0); |
| |
| EXPECT_TRUE(avifDecoderIsKeyframe(decoder.get(), 2)); |
| EXPECT_EQ(avifDecoderNearestKeyframe(decoder.get(), 2), 2); |
| |
| // The encoder seems to prefer a keyframe here |
| // (gradient too different from plain color). |
| EXPECT_TRUE(avifDecoderIsKeyframe(decoder.get(), 3)); |
| EXPECT_EQ(avifDecoderNearestKeyframe(decoder.get(), 3), 3); |
| |
| // This is the same frame as the previous one. It should not be a keyframe. |
| EXPECT_FALSE(avifDecoderIsKeyframe(decoder.get(), 4)); |
| EXPECT_EQ(avifDecoderNearestKeyframe(decoder.get(), 4), 3); |
| |
| // Check it decodes properly. |
| for (const ImagePtr& image : images) { |
| ASSERT_EQ(avifDecoderNextImage(decoder.get()), AVIF_RESULT_OK); |
| EXPECT_GT(testutil::GetPsnr(*image, *decoder->image), 20.0); |
| } |
| } |
| |
| } // 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(); |
| } |