| 115 | constexpr uint64_t kDuration = 1; |
| 116 | |
| 117 | void EncodeAnimation(const char* key, const char* value_before_first_frame, |
| 118 | const char* value_after_first_frame, |
| 119 | const char* value_before_second_frame, |
| 120 | std::vector<uint8_t>& encoded_bitstream) { |
| 121 | // Generate an animation with two different frames. |
| 122 | const ImagePtr first_frame = |
| 123 | testutil::ReadImage(data_path, "paris_exif_xmp_icc.jpg"); |
| 124 | ASSERT_NE(first_frame, nullptr); |
| 125 | // Speed up the test. |
| 126 | first_frame->width = 64; |
| 127 | first_frame->height = 64; |
| 128 | const ImagePtr second_frame(avifImageCreateEmpty()); |
| 129 | ASSERT_NE(second_frame, nullptr); |
| 130 | ASSERT_EQ( |
| 131 | avifImageCopy(second_frame.get(), first_frame.get(), AVIF_PLANES_ALL), |
| 132 | AVIF_RESULT_OK); |
| 133 | testutil::FillImageGradient(first_frame.get()); |
| 134 | |
| 135 | EncoderPtr encoder(avifEncoderCreate()); |
| 136 | ASSERT_NE(encoder, nullptr); |
| 137 | encoder->codecChoice = AVIF_CODEC_CHOICE_AOM; |
| 138 | encoder->creationTime = encoder->modificationTime = 1; // Deterministic. |
| 139 | const avifAddImageFlag flag = AVIF_ADD_IMAGE_FLAG_FORCE_KEYFRAME; |
| 140 | |
| 141 | // First frame. |
| 142 | ASSERT_EQ(avifEncoderSetCodecSpecificOption(encoder.get(), key, |
| 143 | value_before_first_frame), |
| 144 | AVIF_RESULT_OK); |
| 145 | ASSERT_EQ( |
| 146 | avifEncoderAddImage(encoder.get(), first_frame.get(), kDuration, flag), |
| 147 | AVIF_RESULT_OK); |
| 148 | ASSERT_EQ(avifEncoderSetCodecSpecificOption(encoder.get(), key, |
| 149 | value_after_first_frame), |
| 150 | AVIF_RESULT_OK); |
| 151 | |
| 152 | // Second frame. |
| 153 | ASSERT_EQ(avifEncoderSetCodecSpecificOption(encoder.get(), key, |
| 154 | value_before_second_frame), |
| 155 | AVIF_RESULT_OK); |
| 156 | ASSERT_EQ( |
| 157 | avifEncoderAddImage(encoder.get(), second_frame.get(), kDuration, flag), |
| 158 | AVIF_RESULT_OK); |
| 159 | |
| 160 | testutil::AvifRwData encoded; |
| 161 | ASSERT_EQ(avifEncoderFinish(encoder.get(), &encoded), AVIF_RESULT_OK); |
| 162 | |
| 163 | // Make sure it decodes fine, even if unrelated to the current test. |
| 164 | DecoderPtr decoder(avifDecoderCreate()); |
| 165 | ASSERT_NE(decoder, nullptr); |
| 166 | ASSERT_EQ(avifDecoderSetIOMemory(decoder.get(), encoded.data, encoded.size), |
| 167 | AVIF_RESULT_OK); |
| 168 | ASSERT_EQ(avifDecoderParse(decoder.get()), AVIF_RESULT_OK); |
| 169 | ASSERT_EQ(avifDecoderNextImage(decoder.get()), AVIF_RESULT_OK); |
| 170 | ASSERT_GT(testutil::GetPsnr(*first_frame, *decoder->image), 32.0); |
| 171 | ASSERT_EQ(avifDecoderNextImage(decoder.get()), AVIF_RESULT_OK); |
| 172 | ASSERT_GT(testutil::GetPsnr(*second_frame, *decoder->image), 32.0); |
| 173 | |
| 174 | encoded_bitstream = std::vector(encoded.data, encoded.data + encoded.size); |
no test coverage detected