Skip to content

Commit 2a4a06f

Browse files
juliobbvwantehchang
authored andcommitted
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)
1 parent b63a913 commit 2a4a06f

2 files changed

Lines changed: 36 additions & 3 deletions

File tree

src/codec_aom.c

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@
4949
#endif
5050
#endif
5151

52+
#define TWO_LAYER_ALL_INTRA_QUALITY_THRESHOLD 10
53+
5254
struct avifCodecInternal
5355
{
5456
#if defined(AVIF_CODEC_AOM_DECODE)
@@ -65,6 +67,7 @@ struct avifCodecInternal
6567
avifPixelFormatInfo formatInfo;
6668
aom_img_fmt_t aomFormat;
6769
uint32_t currentLayer;
70+
int qualityFirstLayer;
6871
#endif
6972
};
7073

@@ -656,6 +659,21 @@ static avifResult aomCodecEncodeImage(avifCodec * codec,
656659
avifAddImageFlags addImageFlags,
657660
avifCodecEncodeOutput * output)
658661
{
662+
// Save the quality of the first layer because it's useful for further decision making
663+
if (encoder->extraLayerCount > 0 && codec->internal->currentLayer == 0) {
664+
codec->internal->qualityFirstLayer = quality;
665+
}
666+
667+
// All-intra encoding is beneficial when encoding a two-layer image item and the quality of the first layer is very low.
668+
// Switching to all-intra encoding comes with the following benefits:
669+
// - The first layer will be smaller than the second layer (which is often not the case with inter encoding)
670+
// - Outputs have predictable file sizes: the sum of the first layer (quality <= 10) plus the second layer (quality set by the caller)
671+
// - 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)
672+
// - Option of choosing tune IQ (which requires AOM_USAGE_ALL_INTRA)
673+
avifBool useAllIntraForLayered = encoder->extraLayerCount == 1 &&
674+
codec->internal->qualityFirstLayer <= TWO_LAYER_ALL_INTRA_QUALITY_THRESHOLD;
675+
avifBool useAllIntra = (addImageFlags & AVIF_ADD_IMAGE_FLAG_SINGLE) || useAllIntraForLayered;
676+
659677
// Map encoder speed to AOM usage + CpuUsed:
660678
// Speed 0: GoodQuality CpuUsed 0
661679
// Speed 1: GoodQuality CpuUsed 1
@@ -671,7 +689,7 @@ static avifResult aomCodecEncodeImage(avifCodec * codec,
671689
unsigned int aomUsage = AOM_USAGE_GOOD_QUALITY;
672690
// Use AOM_USAGE_ALL_INTRA (added in https://crbug.com/aomedia/2959) for still image encoding if available.
673691
#if defined(AOM_USAGE_ALL_INTRA)
674-
if (addImageFlags & AVIF_ADD_IMAGE_FLAG_SINGLE) {
692+
if (useAllIntra) {
675693
aomUsage = AOM_USAGE_ALL_INTRA;
676694
}
677695
#endif
@@ -680,7 +698,7 @@ static avifResult aomCodecEncodeImage(avifCodec * codec,
680698
aomCpuUsed = AVIF_CLAMP(encoder->speed, 0, 9);
681699
if (aomCpuUsed >= 7) {
682700
#if defined(AOM_USAGE_ALL_INTRA) && defined(ALL_INTRA_HAS_SPEEDS_7_TO_9)
683-
if (!(addImageFlags & AVIF_ADD_IMAGE_FLAG_SINGLE)) {
701+
if (!useAllIntra) {
684702
aomUsage = AOM_USAGE_REALTIME;
685703
}
686704
#else
@@ -826,7 +844,9 @@ static avifResult aomCodecEncodeImage(avifCodec * codec,
826844
// libaom to set still_picture and reduced_still_picture_header to
827845
// 1 in AV1 sequence headers.
828846
cfg->g_limit = 1;
829-
847+
}
848+
if (useAllIntra) {
849+
#if !defined(AOM_USAGE_ALL_INTRA)
830850
// Use the default settings of the new AOM_USAGE_ALL_INTRA (added in
831851
// https://crbug.com/aomedia/2959).
832852
//
@@ -838,6 +858,7 @@ static avifResult aomCodecEncodeImage(avifCodec * codec,
838858
cfg->kf_mode = AOM_KF_DISABLED;
839859
// Tell libaom that all frames will be key frames.
840860
cfg->kf_max_dist = 0;
861+
#endif
841862
} else {
842863
if (encoder->keyframeInterval > 0) {
843864
cfg->kf_max_dist = encoder->keyframeInterval;

src/codec_avm.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
#include <stdlib.h>
1515
#include <string.h>
1616

17+
#define TWO_LAYER_ALL_INTRA_QUALITY_THRESHOLD 10
18+
1719
struct avifCodecInternal
1820
{
1921
avifBool decoderInitialized;
@@ -547,7 +549,17 @@ static avifResult avmCodecEncodeImage(avifCodec * codec,
547549
// libavm to set still_picture and reduced_still_picture_header to
548550
// 1 in AV2 sequence headers.
549551
cfg->g_limit = 1;
552+
}
553+
554+
// All-intra encoding is beneficial when encoding a two-layer image item and the quality of the first layer is very low.
555+
// Switching to all-intra encoding comes with the following benefits:
556+
// - The first layer will be smaller than the second layer (which is often not the case with inter encoding)
557+
// - Outputs have predictable file sizes: the sum of the first layer (quality <= 10) plus the second layer (quality set by the caller)
558+
// - 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)
559+
avifBool useAllIntraForLayered = encoder->extraLayerCount == 1 && quality <= TWO_LAYER_ALL_INTRA_QUALITY_THRESHOLD;
560+
avifBool useAllIntra = (addImageFlags & AVIF_ADD_IMAGE_FLAG_SINGLE) || useAllIntraForLayered;
550561

562+
if (useAllIntra) {
551563
// Use the default settings of the new AVM_USAGE_ALL_INTRA (added in
552564
// https://crbug.com/aomedia/2959).
553565
//

0 commit comments

Comments
 (0)