@@ -385,15 +385,39 @@ static avifBool avifKeyEqualsName(const char * key, const char * name, avifBool
385385 (!strncmp (key , shortPrefix , shortPrefixLen ) && !strcmp (key + shortPrefixLen , name ));
386386}
387387
388- static avifBool avifAOMOptionsContainExplicitTuning (const avifCodec * codec , avifBool alpha )
388+ #if !defined(AOM_HAVE_TUNE_IQ )
389+ // Define the tune IQ value here if libaom doesn't define it. The enum value is guaranteed to never change
390+ // in libaom, so this definition won't ever get out of sync.
391+ #define AOM_TUNE_IQ 10
392+ #endif
393+ // Tune IQ string -> enum mapping
394+ static const struct aomOptionEnumList tuneIqEnum [] = { { "iq" , AOM_TUNE_IQ }, { NULL , 0 } };
395+
396+ // Returns true if codec-specific options for AOM contain a tune metric setting. Returns false otherwise.
397+ // Sets *useTuneIq to true if codec-specific options for AOM contain AOM_TUNE_IQ. Otherwise sets *useTuneIq to false.
398+ static avifBool avifAOMOptionsContainExplicitTuning (const avifCodec * codec , avifBool alpha , avifBool * useTuneIq )
389399{
400+ * useTuneIq = AVIF_FALSE ;
401+ avifBool isAnyTuneDefined = AVIF_FALSE ;
402+
403+ // If there are multiple "tune" options specified, honor the last one.
404+ // For consistent behavior, handle both cases where tune was either specified as a string (e.g. tune=iq),
405+ // or as an enum value (e.g. tune=10).
390406 for (uint32_t i = 0 ; i < codec -> csOptions -> count ; ++ i ) {
391407 const avifCodecSpecificOption * entry = & codec -> csOptions -> entries [i ];
392408 if (avifKeyEqualsName (entry -> key , "tune" , alpha )) {
393- return AVIF_TRUE ;
409+ isAnyTuneDefined = AVIF_TRUE ;
410+
411+ int val ;
412+ if (aomOptionParseEnum (entry -> value , tuneIqEnum , & val )) {
413+ assert (val == AOM_TUNE_IQ );
414+ * useTuneIq = AVIF_TRUE ;
415+ } else {
416+ * useTuneIq = AVIF_FALSE ;
417+ }
394418 }
395419 }
396- return AVIF_FALSE ;
420+ return isAnyTuneDefined ;
397421}
398422
399423static avifBool avifProcessAOMOptionsPreInit (avifCodec * codec , avifBool alpha , struct aom_codec_enc_cfg * cfg )
@@ -412,50 +436,6 @@ static avifBool avifProcessAOMOptionsPreInit(avifCodec * codec, avifBool alpha,
412436 return AVIF_TRUE ;
413437}
414438
415- static avifBool avifImageUsesTuneIq (const avifCodec * codec , avifBool alpha )
416- {
417- #if !defined(AOM_HAVE_TUNE_IQ )
418- // Define the tune IQ value here if libaom doesn't define it. The enum value is guaranteed to never change
419- // in libaom, so this definition won't ever get out of sync.
420- #define AOM_TUNE_IQ 10
421- #endif
422-
423- avifBool useTuneIq = AVIF_FALSE ;
424- avifBool isAnyTuneDefined = AVIF_FALSE ;
425-
426- // Tune IQ string -> enum mapping
427- static const struct aomOptionEnumList tuneIqEnum [] = { { "iq" , AOM_TUNE_IQ }, // Image Quality (IQ) mode
428- { NULL , 0 } };
429-
430- for (uint32_t i = 0 ; i < codec -> csOptions -> count ; ++ i ) {
431- const avifCodecSpecificOption * entry = & codec -> csOptions -> entries [i ];
432- int val ;
433- // If there are multiple "tune" options specified, honor the last one.
434- // For consistent behavior, handle both cases where tune IQ was either specified as a string (tune=iq),
435- // or as an enum value (tune=10).
436- if (avifKeyEqualsName (entry -> key , "tune" , alpha )) {
437- isAnyTuneDefined = AVIF_TRUE ;
438-
439- if (aomOptionParseEnum (entry -> value , tuneIqEnum , & val )) {
440- assert (val == AOM_TUNE_IQ );
441- useTuneIq = AVIF_TRUE ;
442- } else {
443- useTuneIq = AVIF_FALSE ;
444- }
445- }
446- }
447-
448- if (isAnyTuneDefined ) {
449- return useTuneIq ;
450- }
451-
452- // Handle the case where the encoder was called with avifEncoderSetCodecSpecificOption("tune", "iq")
453- // for a previous frame and not called (or called with NULL) for this frame, because the tune
454- // option persists across frames in libaom.
455- // In this case, return what the previous frame used.
456- return codec -> internal -> previousFrameUsedTuneIq ;
457- }
458-
459439#if !defined(HAVE_AOM_CODEC_SET_OPTION )
460440typedef enum
461441{
@@ -747,10 +727,21 @@ static avifResult aomCodecEncodeImage(avifCodec * codec,
747727 avifBool useLibavifDefaultTuneMetric = AVIF_FALSE ; // If true, override libaom's default tune option.
748728 aom_tune_metric libavifDefaultTuneMetric = AOM_TUNE_PSNR ; // Meaningless unless useLibavifDefaultTuneMetric.
749729
750- // libavif only needs to set the default tune metric for the first frame,
751- // because libaom will persist that setting until explicitly changed.
752- if (!codec -> internal -> encoderInitialized ) {
753- if (quality != AVIF_QUALITY_LOSSLESS && !avifAOMOptionsContainExplicitTuning (codec , alpha )) {
730+ // True if libavif knows that tune=iq is used, either by default by libavif, or explicitly set by the user.
731+ // False otherwise (including if libaom uses tune=iq by default, which is not the case as of v3.13.1 and earlier versions).
732+ avifBool useTuneIq ;
733+
734+ if (avifAOMOptionsContainExplicitTuning (codec , alpha , & useTuneIq )) {
735+ // avifAOMOptionsContainExplicitTuning() has set useTuneIq.
736+ } else if (!codec -> internal -> encoderInitialized ) {
737+ // libavif only needs to set the default tune metric for the first frame,
738+ // because libaom will persist that setting until explicitly changed.
739+
740+ if (quality == AVIF_QUALITY_LOSSLESS ) {
741+ // AOM_TUNE_IQ is not libaom's default tune option as of v3.13.1.
742+ // Even if it was, it does not matter for lossless.
743+ useTuneIq = AVIF_FALSE ;
744+ } else {
754745 useLibavifDefaultTuneMetric = AVIF_TRUE ;
755746 if (alpha ) {
756747 // Minimize ringing for alpha.
@@ -772,20 +763,19 @@ static avifResult aomCodecEncodeImage(avifCodec * codec,
772763 }
773764#endif
774765 }
766+ useTuneIq = (libavifDefaultTuneMetric == AOM_TUNE_IQ );
775767 }
768+ } else {
769+ // The tune option persists across frames in libaom until explicitly set to another value.
770+ useTuneIq = codec -> internal -> previousFrameUsedTuneIq ;
776771 }
772+ // Remember the current tune option for the next frame.
773+ codec -> internal -> previousFrameUsedTuneIq = useTuneIq ;
777774
778775 struct aom_codec_enc_cfg * cfg = & codec -> internal -> cfg ;
779776 avifBool quantizerUpdated = AVIF_FALSE ;
780- // True if libavif knows that tune=iq is used, either by default by libavif, or explicitly set by the user.
781- // False otherwise (including if libaom uses tune=iq by default, which is not the case as of v3.13.1 and earlier versions).
782- const avifBool useTuneIq = useLibavifDefaultTuneMetric ? libavifDefaultTuneMetric == AOM_TUNE_IQ : avifImageUsesTuneIq (codec , alpha );
783777 const int quantizer = aomQualityToQuantizer (quality , useTuneIq );
784778
785- // libavif needs to know whether the current frame uses tune=iq for the next frame, as libaom persists
786- // tuning modes across frames
787- codec -> internal -> previousFrameUsedTuneIq = useTuneIq ;
788-
789779 // For encoder->scalingMode.horizontal and encoder->scalingMode.vertical to take effect in AOM
790780 // encoder, config should be applied for each frame, so we don't care about changes on these
791781 // two fields.
0 commit comments