Skip to content

Commit d22bfd2

Browse files
committed
Clean up encoder settings update during encoding
Clean up the changes made in the following two pull requests to support updating encoder settings during encoding: AOMediaCodec#1033 AOMediaCodec#1058 In particular, restore the aomCodecEncodeImage() function in src/codec_aom.c to its original structure, plus a new block of code to handle encoder changes. Rename some functions and data members. Edit some comments and messages. In the avifEncoderChange enum, left-shift the unsigned int constant 1u because if we left-shift the signed int constant 1 by 31 bits, it will be shifted into the sign bit. Other miscellaneous cosmetic changes. AOMediaCodec#761
1 parent 304b91b commit d22bfd2

File tree

10 files changed

+130
-124
lines changed

10 files changed

+130
-124
lines changed

include/avif/avif.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ typedef enum avifResult
151151
AVIF_RESULT_NOT_IMPLEMENTED, // a requested code path is not (yet) implemented
152152
AVIF_RESULT_OUT_OF_MEMORY,
153153
AVIF_RESULT_CANNOT_CHANGE_SETTING, // a setting that can't change is changed during encoding
154-
AVIF_RESULT_INCOMPATIBLE_IMAGE // given image is not compatible with already encoded image
154+
AVIF_RESULT_INCOMPATIBLE_IMAGE // the image is incompatible with already encoded images
155155
} avifResult;
156156

157157
AVIF_API const char * avifResultToString(avifResult result);
@@ -1054,11 +1054,11 @@ typedef struct avifEncoder
10541054
avifCodecChoice codecChoice;
10551055

10561056
// settings (see Notes above)
1057-
int keyframeInterval; // How many frames between automatic forced keyframes; 0 to disable (default).
1058-
uint64_t timescale; // timescale of the media (Hz)
10591057
int maxThreads;
10601058
int speed;
1061-
// changeable encoder settings.
1059+
int keyframeInterval; // How many frames between automatic forced keyframes; 0 to disable (default).
1060+
uint64_t timescale; // timescale of the media (Hz)
1061+
// changeable encoder settings
10621062
int minQuantizer;
10631063
int maxQuantizer;
10641064
int minQuantizerAlpha;

include/avif/internal.h

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -262,14 +262,14 @@ struct avifCodecInternal;
262262

263263
typedef enum avifEncoderChange
264264
{
265-
AVIF_ENCODER_CHANGE_MIN_QUANTIZER = (1 << 0),
266-
AVIF_ENCODER_CHANGE_MAX_QUANTIZER = (1 << 1),
267-
AVIF_ENCODER_CHANGE_MIN_QUANTIZER_ALPHA = (1 << 2),
268-
AVIF_ENCODER_CHANGE_MAX_QUANTIZER_ALPHA = (1 << 3),
269-
AVIF_ENCODER_CHANGE_TILE_ROWS_LOG2 = (1 << 4),
270-
AVIF_ENCODER_CHANGE_TILE_COLS_LOG2 = (1 << 5),
271-
272-
AVIF_ENCODER_CHANGE_CODEC_SPECIFIC = (1 << 31)
265+
AVIF_ENCODER_CHANGE_MIN_QUANTIZER = (1u << 0),
266+
AVIF_ENCODER_CHANGE_MAX_QUANTIZER = (1u << 1),
267+
AVIF_ENCODER_CHANGE_MIN_QUANTIZER_ALPHA = (1u << 2),
268+
AVIF_ENCODER_CHANGE_MAX_QUANTIZER_ALPHA = (1u << 3),
269+
AVIF_ENCODER_CHANGE_TILE_ROWS_LOG2 = (1u << 4),
270+
AVIF_ENCODER_CHANGE_TILE_COLS_LOG2 = (1u << 5),
271+
272+
AVIF_ENCODER_CHANGE_CODEC_SPECIFIC = (1u << 31)
273273
} avifEncoderChange;
274274
typedef uint32_t avifEncoderChanges;
275275

src/avif.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,8 @@ const char * avifResultToString(avifResult result)
9898
case AVIF_RESULT_INVALID_ARGUMENT: return "Invalid argument";
9999
case AVIF_RESULT_NOT_IMPLEMENTED: return "Not implemented";
100100
case AVIF_RESULT_OUT_OF_MEMORY: return "Out of memory";
101-
case AVIF_RESULT_CANNOT_CHANGE_SETTING: return "Can not change some settings during encoding";
102-
case AVIF_RESULT_INCOMPATIBLE_IMAGE: return "This image is incompatible with already encoded image";
101+
case AVIF_RESULT_CANNOT_CHANGE_SETTING: return "Cannot change some setting during encoding";
102+
case AVIF_RESULT_INCOMPATIBLE_IMAGE: return "The image is incompatible with already encoded images";
103103
case AVIF_RESULT_UNKNOWN_ERROR:
104104
default:
105105
break;

src/codec_aom.c

Lines changed: 61 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -532,10 +532,7 @@ static avifResult aomCodecEncodeImage(avifCodec * codec,
532532
avifCodecEncodeOutput * output)
533533
{
534534
struct aom_codec_enc_cfg * cfg = &codec->internal->cfg;
535-
aom_codec_iface_t * encoderInterface = NULL;
536-
unsigned int aomUsage = AOM_USAGE_GOOD_QUALITY;
537-
int aomCpuUsed = -1;
538-
avifBool lossless = AVIF_FALSE;
535+
avifBool quantizerUpdated = AVIF_FALSE;
539536

540537
if (!codec->internal->encoderInitialized) {
541538
// Map encoder speed to AOM usage + CpuUsed:
@@ -550,13 +547,15 @@ static avifResult aomCodecEncodeImage(avifCodec * codec,
550547
// Speed 8: RealTime CpuUsed 8
551548
// Speed 9: RealTime CpuUsed 9
552549
// Speed 10: RealTime CpuUsed 9
550+
unsigned int aomUsage = AOM_USAGE_GOOD_QUALITY;
553551
// Use the new AOM_USAGE_ALL_INTRA (added in https://crbug.com/aomedia/2959) for still
554552
// image encoding if it is available.
555553
#if defined(AOM_USAGE_ALL_INTRA)
556554
if (addImageFlags & AVIF_ADD_IMAGE_FLAG_SINGLE) {
557555
aomUsage = AOM_USAGE_ALL_INTRA;
558556
}
559557
#endif
558+
int aomCpuUsed = -1;
560559
if (encoder->speed != AVIF_SPEED_DEFAULT) {
561560
aomCpuUsed = AVIF_CLAMP(encoder->speed, 0, 9);
562561
if (aomCpuUsed >= 7) {
@@ -600,7 +599,7 @@ static avifResult aomCodecEncodeImage(avifCodec * codec,
600599

601600
avifGetPixelFormatInfo(image->yuvFormat, &codec->internal->formatInfo);
602601

603-
encoderInterface = aom_codec_av1_cx();
602+
aom_codec_iface_t * encoderInterface = aom_codec_av1_cx();
604603
aom_codec_err_t err = aom_codec_enc_config_default(encoderInterface, cfg, aomUsage);
605604
if (err != AOM_CODEC_OK) {
606605
avifDiagnosticsPrintf(codec->diag, "aom_codec_enc_config_default() failed: %s", aom_codec_err_to_string(err));
@@ -665,7 +664,8 @@ static avifResult aomCodecEncodeImage(avifCodec * codec,
665664
cfg->g_profile = seqProfile;
666665
cfg->g_bit_depth = image->depth;
667666
cfg->g_input_bit_depth = image->depth;
668-
667+
cfg->g_w = image->width;
668+
cfg->g_h = image->height;
669669
if (addImageFlags & AVIF_ADD_IMAGE_FLAG_SINGLE) {
670670
// Set the maximum number of frames to encode to 1. This instructs
671671
// libaom to set still_picture and reduced_still_picture_header to
@@ -688,6 +688,15 @@ static avifResult aomCodecEncodeImage(avifCodec * codec,
688688
cfg->g_threads = encoder->maxThreads;
689689
}
690690

691+
if (alpha) {
692+
cfg->rc_min_quantizer = AVIF_CLAMP(encoder->minQuantizerAlpha, 0, 63);
693+
cfg->rc_max_quantizer = AVIF_CLAMP(encoder->maxQuantizerAlpha, 0, 63);
694+
} else {
695+
cfg->rc_min_quantizer = AVIF_CLAMP(encoder->minQuantizer, 0, 63);
696+
cfg->rc_max_quantizer = AVIF_CLAMP(encoder->maxQuantizer, 0, 63);
697+
}
698+
quantizerUpdated = AVIF_TRUE;
699+
691700
codec->internal->monochromeEnabled = AVIF_FALSE;
692701
if (aomVersion > aomVersion_2_0_0) {
693702
// There exists a bug in libaom's chroma_check() function where it will attempt to
@@ -703,103 +712,84 @@ static avifResult aomCodecEncodeImage(avifCodec * codec,
703712
cfg->monochrome = 1;
704713
}
705714
}
706-
}
707-
708-
avifBool dimensionsChanged = AVIF_FALSE;
709-
if (!codec->internal->encoderInitialized) {
710-
cfg->g_w = image->width;
711-
cfg->g_h = image->height;
712-
} else if ((cfg->g_w != image->width) || (cfg->g_h != image->height)) {
713-
// We are not ready for dimension change for now.
714-
return AVIF_RESULT_NOT_IMPLEMENTED;
715-
}
716715

717-
if (!codec->internal->encoderInitialized || encoderChanges) {
718-
int minQuantizer = AVIF_CLAMP(encoder->minQuantizer, 0, 63);
719-
int maxQuantizer = AVIF_CLAMP(encoder->maxQuantizer, 0, 63);
720-
if (alpha) {
721-
minQuantizer = AVIF_CLAMP(encoder->minQuantizerAlpha, 0, 63);
722-
maxQuantizer = AVIF_CLAMP(encoder->maxQuantizerAlpha, 0, 63);
716+
if (!avifProcessAOMOptionsPreInit(codec, alpha, cfg)) {
717+
return AVIF_RESULT_INVALID_CODEC_SPECIFIC_OPTION;
723718
}
724-
lossless = ((minQuantizer == AVIF_QUANTIZER_LOSSLESS) && (maxQuantizer == AVIF_QUANTIZER_LOSSLESS));
725-
cfg->rc_min_quantizer = minQuantizer;
726-
cfg->rc_max_quantizer = maxQuantizer;
727-
}
728719

729-
if (!codec->internal->encoderInitialized) {
730720
aom_codec_flags_t encoderFlags = 0;
731721
if (image->depth > 8) {
732722
encoderFlags |= AOM_CODEC_USE_HIGHBITDEPTH;
733723
}
734-
735-
if (!avifProcessAOMOptionsPreInit(codec, alpha, cfg)) {
736-
return AVIF_RESULT_INVALID_CODEC_SPECIFIC_OPTION;
737-
}
738-
739724
if (aom_codec_enc_init(&codec->internal->encoder, encoderInterface, cfg, encoderFlags) != AOM_CODEC_OK) {
740725
avifDiagnosticsPrintf(codec->diag,
741726
"aom_codec_enc_init() failed: %s: %s",
742727
aom_codec_error(&codec->internal->encoder),
743728
aom_codec_error_detail(&codec->internal->encoder));
744729
return AVIF_RESULT_UNKNOWN_ERROR;
745730
}
731+
codec->internal->encoderInitialized = AVIF_TRUE;
746732

733+
avifBool lossless = ((cfg->rc_min_quantizer == AVIF_QUANTIZER_LOSSLESS) && (cfg->rc_max_quantizer == AVIF_QUANTIZER_LOSSLESS));
734+
if (lossless) {
735+
aom_codec_control(&codec->internal->encoder, AV1E_SET_LOSSLESS, 1);
736+
}
747737
if (encoder->maxThreads > 1) {
748738
aom_codec_control(&codec->internal->encoder, AV1E_SET_ROW_MT, 1);
749739
}
740+
if (encoder->tileRowsLog2 != 0) {
741+
int tileRowsLog2 = AVIF_CLAMP(encoder->tileRowsLog2, 0, 6);
742+
aom_codec_control(&codec->internal->encoder, AV1E_SET_TILE_ROWS, tileRowsLog2);
743+
}
744+
if (encoder->tileColsLog2 != 0) {
745+
int tileColsLog2 = AVIF_CLAMP(encoder->tileColsLog2, 0, 6);
746+
aom_codec_control(&codec->internal->encoder, AV1E_SET_TILE_COLUMNS, tileColsLog2);
747+
}
750748
if (aomCpuUsed != -1) {
751749
if (aom_codec_control(&codec->internal->encoder, AOME_SET_CPUUSED, aomCpuUsed) != AOM_CODEC_OK) {
752750
return AVIF_RESULT_UNKNOWN_ERROR;
753751
}
754752
}
755-
} else if ((encoderChanges & ~AVIF_ENCODER_CHANGE_CODEC_SPECIFIC) || dimensionsChanged) {
756-
// Codec specific options does not change cfg, so no need to update it.
757-
aom_codec_err_t err = aom_codec_enc_config_set(&codec->internal->encoder, cfg);
758-
if (err != AOM_CODEC_OK) {
759-
avifDiagnosticsPrintf(codec->diag,
760-
"aom_codec_enc_config_set() failed: %s: %s",
761-
aom_codec_error(&codec->internal->encoder),
762-
aom_codec_error_detail(&codec->internal->encoder));
763-
return AVIF_RESULT_UNKNOWN_ERROR;
764-
}
765-
}
766-
767-
if (!codec->internal->encoderInitialized || (encoderChanges & AVIF_ENCODER_CHANGE_CODEC_SPECIFIC)) {
768753
if (!avifProcessAOMOptionsPostInit(codec, alpha)) {
769754
return AVIF_RESULT_INVALID_CODEC_SPECIFIC_OPTION;
770755
}
771-
}
772-
773-
avifBool quantizerUpdated = AVIF_FALSE;
774-
if (!codec->internal->encoderInitialized) {
775-
quantizerUpdated = AVIF_TRUE;
776-
if (lossless) {
777-
aom_codec_control(&codec->internal->encoder, AV1E_SET_LOSSLESS, lossless);
778-
}
779-
int tileRowsLog2 = AVIF_CLAMP(encoder->tileRowsLog2, 0, 6);
780-
if (tileRowsLog2 > 0) {
781-
aom_codec_control(&codec->internal->encoder, AV1E_SET_TILE_ROWS, tileRowsLog2);
782-
}
783-
int tileColsLog2 = AVIF_CLAMP(encoder->tileColsLog2, 0, 6);
784-
if (tileColsLog2 > 0) {
785-
aom_codec_control(&codec->internal->encoder, AV1E_SET_TILE_COLUMNS, tileColsLog2);
786-
}
787756
if (!codec->internal->tuningSet) {
788757
if (aom_codec_control(&codec->internal->encoder, AOME_SET_TUNING, AOM_TUNE_SSIM) != AOM_CODEC_OK) {
789758
return AVIF_RESULT_UNKNOWN_ERROR;
790759
}
791760
}
792-
codec->internal->encoderInitialized = AVIF_TRUE;
793-
} else if (encoderChanges) {
761+
} else {
762+
avifBool dimensionsChanged = AVIF_FALSE;
763+
if ((cfg->g_w != image->width) || (cfg->g_h != image->height)) {
764+
// We are not ready for dimension change for now.
765+
return AVIF_RESULT_NOT_IMPLEMENTED;
766+
}
794767
if (alpha) {
795768
if (encoderChanges & (AVIF_ENCODER_CHANGE_MIN_QUANTIZER_ALPHA | AVIF_ENCODER_CHANGE_MAX_QUANTIZER_ALPHA)) {
769+
cfg->rc_min_quantizer = AVIF_CLAMP(encoder->minQuantizerAlpha, 0, 63);
770+
cfg->rc_max_quantizer = AVIF_CLAMP(encoder->maxQuantizerAlpha, 0, 63);
796771
quantizerUpdated = AVIF_TRUE;
797-
aom_codec_control(&codec->internal->encoder, AV1E_SET_LOSSLESS, lossless);
798772
}
799773
} else {
800774
if (encoderChanges & (AVIF_ENCODER_CHANGE_MIN_QUANTIZER | AVIF_ENCODER_CHANGE_MAX_QUANTIZER)) {
775+
cfg->rc_min_quantizer = AVIF_CLAMP(encoder->minQuantizer, 0, 63);
776+
cfg->rc_max_quantizer = AVIF_CLAMP(encoder->maxQuantizer, 0, 63);
801777
quantizerUpdated = AVIF_TRUE;
802-
aom_codec_control(&codec->internal->encoder, AV1E_SET_LOSSLESS, lossless);
778+
}
779+
}
780+
if (quantizerUpdated) {
781+
avifBool lossless =
782+
((cfg->rc_min_quantizer == AVIF_QUANTIZER_LOSSLESS) && (cfg->rc_max_quantizer == AVIF_QUANTIZER_LOSSLESS));
783+
aom_codec_control(&codec->internal->encoder, AV1E_SET_LOSSLESS, lossless);
784+
}
785+
if (quantizerUpdated || dimensionsChanged) {
786+
aom_codec_err_t err = aom_codec_enc_config_set(&codec->internal->encoder, cfg);
787+
if (err != AOM_CODEC_OK) {
788+
avifDiagnosticsPrintf(codec->diag,
789+
"aom_codec_enc_config_set() failed: %s: %s",
790+
aom_codec_error(&codec->internal->encoder),
791+
aom_codec_error_detail(&codec->internal->encoder));
792+
return AVIF_RESULT_UNKNOWN_ERROR;
803793
}
804794
}
805795
if (encoderChanges & AVIF_ENCODER_CHANGE_TILE_ROWS_LOG2) {
@@ -808,10 +798,15 @@ static avifResult aomCodecEncodeImage(avifCodec * codec,
808798
if (encoderChanges & AVIF_ENCODER_CHANGE_TILE_COLS_LOG2) {
809799
aom_codec_control(&codec->internal->encoder, AV1E_SET_TILE_COLUMNS, AVIF_CLAMP(encoder->tileColsLog2, 0, 6));
810800
}
801+
if (encoderChanges & AVIF_ENCODER_CHANGE_CODEC_SPECIFIC) {
802+
if (!avifProcessAOMOptionsPostInit(codec, alpha)) {
803+
return AVIF_RESULT_INVALID_CODEC_SPECIFIC_OPTION;
804+
}
805+
}
811806
}
812807

813808
#if defined(AOM_USAGE_ALL_INTRA)
814-
if (aomUsage == AOM_USAGE_ALL_INTRA && !codec->internal->endUsageSet && !codec->internal->cqLevelSet && quantizerUpdated) {
809+
if (quantizerUpdated && cfg->g_usage == AOM_USAGE_ALL_INTRA && !codec->internal->endUsageSet && !codec->internal->cqLevelSet) {
815810
// The default rc_end_usage in all intra mode is AOM_Q, which requires cq-level to
816811
// function. A libavif user may not know this internal detail and therefore may only
817812
// set the min and max quantizers in the avifEncoder struct. If this is the case, set

src/codec_rav1e.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,16 +53,16 @@ static avifResult rav1eCodecEncodeImage(avifCodec * codec,
5353
avifEncoder * encoder,
5454
const avifImage * image,
5555
avifBool alpha,
56-
avifEncoderChanges updatedConfig,
56+
avifEncoderChanges encoderChanges,
5757
uint32_t addImageFlags,
5858
avifCodecEncodeOutput * output)
5959
{
60-
// rav1e does not support changing config.
61-
if (updatedConfig) {
60+
// rav1e does not support changing encoder settings.
61+
if (encoderChanges) {
6262
return AVIF_RESULT_NOT_IMPLEMENTED;
6363
}
6464

65-
// rav1e does not support changing encoding dimension.
65+
// rav1e does not support changing image dimensions.
6666
if (!codec->internal->rav1eContext) {
6767
codec->internal->encodeWidth = image->width;
6868
codec->internal->encodeHeight = image->height;

src/codec_svt.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,16 +46,16 @@ static avifResult svtCodecEncodeImage(avifCodec * codec,
4646
avifEncoder * encoder,
4747
const avifImage * image,
4848
avifBool alpha,
49-
avifEncoderChanges updatedConfig,
49+
avifEncoderChanges encoderChanges,
5050
uint32_t addImageFlags,
5151
avifCodecEncodeOutput * output)
5252
{
53-
// svt does not support changing config.
54-
if (updatedConfig) {
53+
// SVT-AV1 does not support changing encoder settings.
54+
if (encoderChanges) {
5555
return AVIF_RESULT_NOT_IMPLEMENTED;
5656
}
5757

58-
// svt does not support changing encoding dimension.
58+
// SVT-AV1 does not support changing image dimensions.
5959
if (codec->internal->svt_encoder != NULL) {
6060
if ((codec->internal->svt_config.source_width != image->width) || (codec->internal->svt_config.source_height != image->height)) {
6161
return AVIF_RESULT_NOT_IMPLEMENTED;

0 commit comments

Comments
 (0)