Use all-intra encoding for some layered images The conditions are: - The total number of layers is 2 - Quality of the first layer is very low (q <= 10)
diff --git a/src/codec_aom.c b/src/codec_aom.c index 75b745d..9faa891 100644 --- a/src/codec_aom.c +++ b/src/codec_aom.c
@@ -49,6 +49,8 @@ #endif #endif +#define TWO_LAYER_ALL_INTRA_QUALITY_THRESHOLD 10 + struct avifCodecInternal { #if defined(AVIF_CODEC_AOM_DECODE) @@ -65,6 +67,7 @@ avifPixelFormatInfo formatInfo; aom_img_fmt_t aomFormat; uint32_t currentLayer; + int qualityFirstLayer; #endif }; @@ -656,6 +659,21 @@ avifAddImageFlags addImageFlags, avifCodecEncodeOutput * output) { + // Save the quality of the first layer because it's useful for further decision making + if (encoder->extraLayerCount > 0 && codec->internal->currentLayer == 0) { + codec->internal->qualityFirstLayer = quality; + } + + // All-intra encoding is beneficial when encoding a two-layer image item and the quality of the first layer is very low. + // Switching to all-intra encoding comes with the following benefits: + // - The first layer will be smaller than the second layer (which is often not the case with inter encoding) + // - Outputs have predictable file sizes: the sum of the first layer (quality <= 10) plus the second layer (quality set by the caller) + // - Because the first layer is very small, layered encoding overhead is also smaller and more stable (about 5-8% for quality 40 and 2-4% for quality 60) + // - Option of choosing tune IQ (which requires AOM_USAGE_ALL_INTRA) + avifBool useAllIntraForLayered = encoder->extraLayerCount == 1 && + codec->internal->qualityFirstLayer <= TWO_LAYER_ALL_INTRA_QUALITY_THRESHOLD; + avifBool useAllIntra = (addImageFlags & AVIF_ADD_IMAGE_FLAG_SINGLE) || useAllIntraForLayered; + // Map encoder speed to AOM usage + CpuUsed: // Speed 0: GoodQuality CpuUsed 0 // Speed 1: GoodQuality CpuUsed 1 @@ -671,7 +689,7 @@ unsigned int aomUsage = AOM_USAGE_GOOD_QUALITY; // Use AOM_USAGE_ALL_INTRA (added in https://crbug.com/aomedia/2959) for still image encoding if available. #if defined(AOM_USAGE_ALL_INTRA) - if (addImageFlags & AVIF_ADD_IMAGE_FLAG_SINGLE) { + if (useAllIntra) { aomUsage = AOM_USAGE_ALL_INTRA; } #endif @@ -680,7 +698,7 @@ aomCpuUsed = AVIF_CLAMP(encoder->speed, 0, 9); if (aomCpuUsed >= 7) { #if defined(AOM_USAGE_ALL_INTRA) && defined(ALL_INTRA_HAS_SPEEDS_7_TO_9) - if (!(addImageFlags & AVIF_ADD_IMAGE_FLAG_SINGLE)) { + if (!useAllIntra) { aomUsage = AOM_USAGE_REALTIME; } #else @@ -826,7 +844,9 @@ // libaom to set still_picture and reduced_still_picture_header to // 1 in AV1 sequence headers. cfg->g_limit = 1; - + } + if (useAllIntra) { +#if !defined(AOM_USAGE_ALL_INTRA) // Use the default settings of the new AOM_USAGE_ALL_INTRA (added in // https://crbug.com/aomedia/2959). // @@ -838,6 +858,7 @@ cfg->kf_mode = AOM_KF_DISABLED; // Tell libaom that all frames will be key frames. cfg->kf_max_dist = 0; +#endif } else { if (encoder->keyframeInterval > 0) { cfg->kf_max_dist = encoder->keyframeInterval;
diff --git a/src/codec_avm.c b/src/codec_avm.c index 937ed54..0be97be 100644 --- a/src/codec_avm.c +++ b/src/codec_avm.c
@@ -14,6 +14,8 @@ #include <stdlib.h> #include <string.h> +#define TWO_LAYER_ALL_INTRA_QUALITY_THRESHOLD 10 + struct avifCodecInternal { avifBool decoderInitialized; @@ -547,7 +549,17 @@ // libavm to set still_picture and reduced_still_picture_header to // 1 in AV2 sequence headers. cfg->g_limit = 1; + } + // All-intra encoding is beneficial when encoding a two-layer image item and the quality of the first layer is very low. + // Switching to all-intra encoding comes with the following benefits: + // - The first layer will be smaller than the second layer (which is often not the case with inter encoding) + // - Outputs have predictable file sizes: the sum of the first layer (quality <= 10) plus the second layer (quality set by the caller) + // - Because the first layer is very small, layered encoding overhead is also smaller and more stable (about 5-8% for quality 40 and 2-4% for quality 60) + avifBool useAllIntraForLayered = encoder->extraLayerCount == 1 && quality <= TWO_LAYER_ALL_INTRA_QUALITY_THRESHOLD; + avifBool useAllIntra = (addImageFlags & AVIF_ADD_IMAGE_FLAG_SINGLE) || useAllIntraForLayered; + + if (useAllIntra) { // Use the default settings of the new AVM_USAGE_ALL_INTRA (added in // https://crbug.com/aomedia/2959). //