Skip to content

Commit c67bc45

Browse files
authored
Refactor avifAOMOptionsContainExplicitTuning() (#3060)
1 parent 0dbf30d commit c67bc45

1 file changed

Lines changed: 48 additions & 58 deletions

File tree

src/codec_aom.c

Lines changed: 48 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -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

399423
static 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)
460440
typedef 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

Comments
 (0)