@@ -112,6 +112,126 @@ TEST(AomSharpnessTest, GenerateDifferentBitstreams) {
112112 }
113113}
114114
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 );
175+ }
176+
177+ TEST (AomTuneMetricTest, TuneOptionHasSameBehaviorAsOtherCodecSpecificOptions) {
178+ if (avifCodecName (AVIF_CODEC_CHOICE_AOM, AVIF_CODEC_FLAG_CAN_ENCODE) ==
179+ nullptr ) {
180+ GTEST_SKIP () << " Codec unavailable, skip test." ;
181+ }
182+ std::vector<uint8_t > a, b;
183+
184+ EncodeAnimation (" tune" , nullptr , nullptr , nullptr , a);
185+ EncodeAnimation (" tune" , nullptr , nullptr , nullptr , b);
186+ // Make sure the comparison works as intended for identical input.
187+ EXPECT_EQ (a, b);
188+
189+ EncodeAnimation (" tune" , " psnr" , nullptr , nullptr , a);
190+ EncodeAnimation (" tune" , nullptr , nullptr , nullptr , b);
191+ // AOM_TUNE_PSNR is not the default.
192+ EXPECT_NE (a, b);
193+
194+ EncodeAnimation (" tune" , nullptr , nullptr , nullptr , a);
195+ EncodeAnimation (" tune" , nullptr , nullptr , " psnr" , b);
196+ // The second frame differs.
197+ EXPECT_NE (a, b);
198+
199+ EncodeAnimation (" tune" , nullptr , " ssim" , " psnr" , a);
200+ EncodeAnimation (" tune" , nullptr , nullptr , " psnr" , b);
201+ // The option is overwritten successfully.
202+ EXPECT_EQ (a, b);
203+
204+ EncodeAnimation (" tune" , nullptr , nullptr , nullptr , a);
205+ EncodeAnimation (" tune" , nullptr , " psnr" , nullptr , b);
206+ // The pending key is successfully deleted.
207+ EXPECT_EQ (a, b);
208+
209+ EncodeAnimation (" tune" , " psnr" , " psnr" , " psnr" , a);
210+ EncodeAnimation (" tune" , " psnr" , nullptr , nullptr , b);
211+ // avifEncoderSetCodecSpecificOption(NULL) only deletes the *pending* key.
212+ EXPECT_EQ (a, b);
213+ }
214+
215+ TEST (AomTuneMetricTest, TuneIqOnlySupportsAllIntra) {
216+ if (avifCodecName (AVIF_CODEC_CHOICE_AOM, AVIF_CODEC_FLAG_CAN_ENCODE) ==
217+ nullptr ) {
218+ GTEST_SKIP () << " Codec unavailable, skip test." ;
219+ }
220+
221+ const ImagePtr image =
222+ testutil::ReadImage (data_path, " paris_exif_xmp_icc.jpg" );
223+ ASSERT_NE (image, nullptr );
224+
225+ EncoderPtr encoder (avifEncoderCreate ());
226+ ASSERT_NE (encoder, nullptr );
227+ encoder->codecChoice = AVIF_CODEC_CHOICE_AOM;
228+ ASSERT_EQ (avifEncoderSetCodecSpecificOption (encoder.get (), " tune" , " iq" ),
229+ AVIF_RESULT_OK);
230+ ASSERT_EQ (avifEncoderAddImage (encoder.get (), image.get (), kDuration ,
231+ AVIF_ADD_IMAGE_FLAG_NONE),
232+ AVIF_RESULT_INVALID_CODEC_SPECIFIC_OPTION);
233+ }
234+
115235// ------------------------------------------------------------------------------
116236
117237} // namespace
0 commit comments