Use Tune IQ for layered image inter-frame encoding

Additionally, for avifenc's --progressive: scale the first layer by a
half for further file size savings.

Note: Tune IQ for inter-frame encoding is expected to be available in
libaom v3.14.0.
diff --git a/apps/avifenc.c b/apps/avifenc.c
index b81194b..1c056fe 100644
--- a/apps/avifenc.c
+++ b/apps/avifenc.c
@@ -993,6 +993,10 @@
             // reversed lerp, so that last layer reaches exact targetQuality
             encoder->quality = targetQuality - (targetQuality - PROGRESSIVE_START_QUALITY) *
                                                    (encoder->extraLayerCount - layerIndex) / encoder->extraLayerCount;
+            // We scaled the first layer by a half (numerator: 1, denominator: 2).
+            // Don't perform any scaling for the second layer (numerator: 1, denominator: 1).
+            const avifScalingMode scalingMode = { { 1, 1 }, { 1, 1 } };
+            encoder->scalingMode = scalingMode;
         } else {
             const avifInputFile * nextFile = avifInputGetFile(input, layerIndex);
             // main() function should set number of layers to number of input,
@@ -1160,8 +1164,11 @@
         // we should not reach here.
         assert(encoder->quality >= PROGRESSIVE_WORST_QUALITY);
         // Encode the base layer with a very low quality to ensure a small encoded size.
-        encoder->quality = 2;
+        encoder->quality = 10;
         // Low alpha quality resulted in weird artifact, so we don't do it.
+        // For further size savings, scale the first layer by a half (numerator: 1, denominator: 2).
+        const avifScalingMode scalingMode = { { 1, 2 }, { 1, 2 } };
+        encoder->scalingMode = scalingMode;
     }
 
     if (settings->layers > 1) {
diff --git a/src/codec_aom.c b/src/codec_aom.c
index 10e1bcb..b31509d 100644
--- a/src/codec_aom.c
+++ b/src/codec_aom.c
@@ -664,16 +664,25 @@
         codec->internal->qualityFirstLayer = quality;
     }
 
-    // Determine whether the encoder should be configured to use intra frames only, either by setting aomUsage to AOM_USAGE_ALL_INTRA,
-    // or by manually configuring the encoder so all frames will be key frames (if AOM_USAGE_ALL_INTRA isn't available).
+    // Determine whether the encoder should be configured to use intra frames only, either by setting aomUsage to
+    // AOM_USAGE_ALL_INTRA, or by manually configuring the encoder so all frames will be key frames (if AOM_USAGE_ALL_INTRA isn't
+    // available).
 
-    // 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:
+    // For libaom versions older than 3.14.0, 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 &&
+    // - 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)
+    // Note: libaom 3.14.0 introduces a mechanism to completely control each layer's QP, and extends tune IQ to inter-frame
+    // encoding modes (AOM_USAGE_GOOD_QUALITY and AOM_USAGE_REALTIME), so there's no need to use all-intra encoding for layered.
+
+    // aom_codec.h says: aom_codec_version() == (major<<16 | minor<<8 | patch)
+    // TODO(wtc): Update constant with the libaom version that contains the layered-encoding improvements
+    static const int aomVersion_3_14_0 = INT_MAX;
+    const int aomVersion = aom_codec_version();
+    avifBool useAllIntraForLayered = aomVersion < aomVersion_3_14_0 && encoder->extraLayerCount == 1 &&
                                      codec->internal->qualityFirstLayer <= TWO_LAYER_ALL_INTRA_QUALITY_THRESHOLD;
     // Also use all-intra encoding when encoding still images.
     avifBool useAllIntra = (addImageFlags & AVIF_ADD_IMAGE_FLAG_SINGLE) || useAllIntraForLayered;
@@ -711,9 +720,7 @@
         }
     }
 
-    // aom_codec.h says: aom_codec_version() == (major<<16 | minor<<8 | patch)
     static const int aomVersion_2_0_0 = (2 << 16);
-    const int aomVersion = aom_codec_version();
     if (aomVersion <= aomVersion_2_0_0) {
         // Issue with v1.0.0-errata1-avif: https://github.com/AOMediaCodec/libavif/issues/56
         // Issue with v2.0.0: https://aomedia-review.googlesource.com/q/I26a39791f820b4d4e1d63ff7141f594c3c7181f5
@@ -750,13 +757,18 @@
                 // AOM_TUNE_IQ has been tuned for the YCbCr family of color spaces, and is favored for
                 // its low perceptual distortion. AOM_TUNE_IQ partially generalizes to, and benefits
                 // from other "YUV-like" spaces (e.g. YCgCo and ICtCp) including monochrome (luma only).
-                // AOM_TUNE_IQ sets --deltaq-mode=6 which can only be used in all intra mode.
+                //
                 // AOM_TUNE_IQ was introduced in libaom v3.12.0 but it has significantly different bit
                 // allocation characteristics compared to v3.13.0. AOM_TUNE_IQ is used by default
                 // starting with v3.13.0 for fewer behavior changes in libavif.
+                //
+                // Starting with libaom v3.14.0, AOM_TUNE_IQ supports all-intra, good-quality and
+                // realtime modes (for single and layered images). Prior to v3.14.0, AOM_TUNE_IQ is only
+                // supported in all-intra mode.
                 static const int aomVersion_3_13_0 = (3 << 16) | (13 << 8);
-                if (image->matrixCoefficients != AVIF_MATRIX_COEFFICIENTS_IDENTITY && aomUsage == AOM_USAGE_ALL_INTRA &&
-                    aomVersion >= aomVersion_3_13_0) {
+                if (image->matrixCoefficients != AVIF_MATRIX_COEFFICIENTS_IDENTITY &&
+                    ((aomUsage == AOM_USAGE_ALL_INTRA && aomVersion >= aomVersion_3_13_0) ||
+                     (encoder->extraLayerCount > 0 && aomVersion >= aomVersion_3_14_0))) {
                     libavifDefaultTuneMetric = AOM_TUNE_IQ;
                 }
 #endif
@@ -904,6 +916,14 @@
             // For layered image, disable lagged encoding to always get output
             // frame for each input frame.
             cfg->g_lag_in_frames = 0;
+
+            if (aomVersion >= aomVersion_3_14_0) {
+                // Disable QP offsets, so CQ level = frame QP for every frame.
+                // This feature requires libaom 3.14.0 or later.
+                if (cfg->rc_end_usage == AOM_Q) {
+                    cfg->use_fixed_qp_offsets = 2;
+                }
+            }
         }
         if (disableLaggedOutput) {
             cfg->g_lag_in_frames = 0;