blob: d87312d42bf403672e8d330560a8038b816c6f70 [file] [log] [blame]
// 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();
}