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:
https://github.com/AOMediaCodec/libavif/pull/1033
https://github.com/AOMediaCodec/libavif/pull/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.
https://github.com/AOMediaCodec/libavif/pull/761
diff --git a/include/avif/avif.h b/include/avif/avif.h
index 08555cb..6a1ea87 100644
--- a/include/avif/avif.h
+++ b/include/avif/avif.h
@@ -151,7 +151,7 @@
AVIF_RESULT_NOT_IMPLEMENTED, // a requested code path is not (yet) implemented
AVIF_RESULT_OUT_OF_MEMORY,
AVIF_RESULT_CANNOT_CHANGE_SETTING, // a setting that can't change is changed during encoding
- AVIF_RESULT_INCOMPATIBLE_IMAGE // given image is not compatible with already encoded image
+ AVIF_RESULT_INCOMPATIBLE_IMAGE // the image is incompatible with already encoded images
} avifResult;
AVIF_API const char * avifResultToString(avifResult result);
@@ -1054,11 +1054,11 @@
avifCodecChoice codecChoice;
// settings (see Notes above)
- int keyframeInterval; // How many frames between automatic forced keyframes; 0 to disable (default).
- uint64_t timescale; // timescale of the media (Hz)
int maxThreads;
int speed;
- // changeable encoder settings.
+ int keyframeInterval; // How many frames between automatic forced keyframes; 0 to disable (default).
+ uint64_t timescale; // timescale of the media (Hz)
+ // changeable encoder settings
int minQuantizer;
int maxQuantizer;
int minQuantizerAlpha;
diff --git a/include/avif/internal.h b/include/avif/internal.h
index c3a2749..b854698 100644
--- a/include/avif/internal.h
+++ b/include/avif/internal.h
@@ -262,14 +262,14 @@
typedef enum avifEncoderChange
{
- AVIF_ENCODER_CHANGE_MIN_QUANTIZER = (1 << 0),
- AVIF_ENCODER_CHANGE_MAX_QUANTIZER = (1 << 1),
- AVIF_ENCODER_CHANGE_MIN_QUANTIZER_ALPHA = (1 << 2),
- AVIF_ENCODER_CHANGE_MAX_QUANTIZER_ALPHA = (1 << 3),
- AVIF_ENCODER_CHANGE_TILE_ROWS_LOG2 = (1 << 4),
- AVIF_ENCODER_CHANGE_TILE_COLS_LOG2 = (1 << 5),
+ AVIF_ENCODER_CHANGE_MIN_QUANTIZER = (1u << 0),
+ AVIF_ENCODER_CHANGE_MAX_QUANTIZER = (1u << 1),
+ AVIF_ENCODER_CHANGE_MIN_QUANTIZER_ALPHA = (1u << 2),
+ AVIF_ENCODER_CHANGE_MAX_QUANTIZER_ALPHA = (1u << 3),
+ AVIF_ENCODER_CHANGE_TILE_ROWS_LOG2 = (1u << 4),
+ AVIF_ENCODER_CHANGE_TILE_COLS_LOG2 = (1u << 5),
- AVIF_ENCODER_CHANGE_CODEC_SPECIFIC = (1 << 31)
+ AVIF_ENCODER_CHANGE_CODEC_SPECIFIC = (1u << 31)
} avifEncoderChange;
typedef uint32_t avifEncoderChanges;
diff --git a/src/avif.c b/src/avif.c
index 5381b44..d6e4afb 100644
--- a/src/avif.c
+++ b/src/avif.c
@@ -98,8 +98,8 @@
case AVIF_RESULT_INVALID_ARGUMENT: return "Invalid argument";
case AVIF_RESULT_NOT_IMPLEMENTED: return "Not implemented";
case AVIF_RESULT_OUT_OF_MEMORY: return "Out of memory";
- case AVIF_RESULT_CANNOT_CHANGE_SETTING: return "Can not change some settings during encoding";
- case AVIF_RESULT_INCOMPATIBLE_IMAGE: return "This image is incompatible with already encoded image";
+ case AVIF_RESULT_CANNOT_CHANGE_SETTING: return "Cannot change some setting during encoding";
+ case AVIF_RESULT_INCOMPATIBLE_IMAGE: return "The image is incompatible with already encoded images";
case AVIF_RESULT_UNKNOWN_ERROR:
default:
break;
diff --git a/src/codec_aom.c b/src/codec_aom.c
index 4d9c801..f91b38f 100644
--- a/src/codec_aom.c
+++ b/src/codec_aom.c
@@ -532,10 +532,7 @@
avifCodecEncodeOutput * output)
{
struct aom_codec_enc_cfg * cfg = &codec->internal->cfg;
- aom_codec_iface_t * encoderInterface = NULL;
- unsigned int aomUsage = AOM_USAGE_GOOD_QUALITY;
- int aomCpuUsed = -1;
- avifBool lossless = AVIF_FALSE;
+ avifBool quantizerUpdated = AVIF_FALSE;
if (!codec->internal->encoderInitialized) {
// Map encoder speed to AOM usage + CpuUsed:
@@ -550,6 +547,7 @@
// Speed 8: RealTime CpuUsed 8
// Speed 9: RealTime CpuUsed 9
// Speed 10: RealTime CpuUsed 9
+ unsigned int aomUsage = AOM_USAGE_GOOD_QUALITY;
// Use the new AOM_USAGE_ALL_INTRA (added in https://crbug.com/aomedia/2959) for still
// image encoding if it is available.
#if defined(AOM_USAGE_ALL_INTRA)
@@ -557,6 +555,7 @@
aomUsage = AOM_USAGE_ALL_INTRA;
}
#endif
+ int aomCpuUsed = -1;
if (encoder->speed != AVIF_SPEED_DEFAULT) {
aomCpuUsed = AVIF_CLAMP(encoder->speed, 0, 9);
if (aomCpuUsed >= 7) {
@@ -600,7 +599,7 @@
avifGetPixelFormatInfo(image->yuvFormat, &codec->internal->formatInfo);
- encoderInterface = aom_codec_av1_cx();
+ aom_codec_iface_t * encoderInterface = aom_codec_av1_cx();
aom_codec_err_t err = aom_codec_enc_config_default(encoderInterface, cfg, aomUsage);
if (err != AOM_CODEC_OK) {
avifDiagnosticsPrintf(codec->diag, "aom_codec_enc_config_default() failed: %s", aom_codec_err_to_string(err));
@@ -665,7 +664,8 @@
cfg->g_profile = seqProfile;
cfg->g_bit_depth = image->depth;
cfg->g_input_bit_depth = image->depth;
-
+ cfg->g_w = image->width;
+ cfg->g_h = image->height;
if (addImageFlags & AVIF_ADD_IMAGE_FLAG_SINGLE) {
// Set the maximum number of frames to encode to 1. This instructs
// libaom to set still_picture and reduced_still_picture_header to
@@ -688,6 +688,15 @@
cfg->g_threads = encoder->maxThreads;
}
+ if (alpha) {
+ cfg->rc_min_quantizer = AVIF_CLAMP(encoder->minQuantizerAlpha, 0, 63);
+ cfg->rc_max_quantizer = AVIF_CLAMP(encoder->maxQuantizerAlpha, 0, 63);
+ } else {
+ cfg->rc_min_quantizer = AVIF_CLAMP(encoder->minQuantizer, 0, 63);
+ cfg->rc_max_quantizer = AVIF_CLAMP(encoder->maxQuantizer, 0, 63);
+ }
+ quantizerUpdated = AVIF_TRUE;
+
codec->internal->monochromeEnabled = AVIF_FALSE;
if (aomVersion > aomVersion_2_0_0) {
// There exists a bug in libaom's chroma_check() function where it will attempt to
@@ -703,39 +712,15 @@
cfg->monochrome = 1;
}
}
- }
-
- avifBool dimensionsChanged = AVIF_FALSE;
- if (!codec->internal->encoderInitialized) {
- cfg->g_w = image->width;
- cfg->g_h = image->height;
- } else if ((cfg->g_w != image->width) || (cfg->g_h != image->height)) {
- // We are not ready for dimension change for now.
- return AVIF_RESULT_NOT_IMPLEMENTED;
- }
-
- if (!codec->internal->encoderInitialized || encoderChanges) {
- int minQuantizer = AVIF_CLAMP(encoder->minQuantizer, 0, 63);
- int maxQuantizer = AVIF_CLAMP(encoder->maxQuantizer, 0, 63);
- if (alpha) {
- minQuantizer = AVIF_CLAMP(encoder->minQuantizerAlpha, 0, 63);
- maxQuantizer = AVIF_CLAMP(encoder->maxQuantizerAlpha, 0, 63);
- }
- lossless = ((minQuantizer == AVIF_QUANTIZER_LOSSLESS) && (maxQuantizer == AVIF_QUANTIZER_LOSSLESS));
- cfg->rc_min_quantizer = minQuantizer;
- cfg->rc_max_quantizer = maxQuantizer;
- }
-
- if (!codec->internal->encoderInitialized) {
- aom_codec_flags_t encoderFlags = 0;
- if (image->depth > 8) {
- encoderFlags |= AOM_CODEC_USE_HIGHBITDEPTH;
- }
if (!avifProcessAOMOptionsPreInit(codec, alpha, cfg)) {
return AVIF_RESULT_INVALID_CODEC_SPECIFIC_OPTION;
}
+ aom_codec_flags_t encoderFlags = 0;
+ if (image->depth > 8) {
+ encoderFlags |= AOM_CODEC_USE_HIGHBITDEPTH;
+ }
if (aom_codec_enc_init(&codec->internal->encoder, encoderInterface, cfg, encoderFlags) != AOM_CODEC_OK) {
avifDiagnosticsPrintf(codec->diag,
"aom_codec_enc_init() failed: %s: %s",
@@ -743,63 +728,68 @@
aom_codec_error_detail(&codec->internal->encoder));
return AVIF_RESULT_UNKNOWN_ERROR;
}
+ codec->internal->encoderInitialized = AVIF_TRUE;
+ avifBool lossless = ((cfg->rc_min_quantizer == AVIF_QUANTIZER_LOSSLESS) && (cfg->rc_max_quantizer == AVIF_QUANTIZER_LOSSLESS));
+ if (lossless) {
+ aom_codec_control(&codec->internal->encoder, AV1E_SET_LOSSLESS, 1);
+ }
if (encoder->maxThreads > 1) {
aom_codec_control(&codec->internal->encoder, AV1E_SET_ROW_MT, 1);
}
+ if (encoder->tileRowsLog2 != 0) {
+ int tileRowsLog2 = AVIF_CLAMP(encoder->tileRowsLog2, 0, 6);
+ aom_codec_control(&codec->internal->encoder, AV1E_SET_TILE_ROWS, tileRowsLog2);
+ }
+ if (encoder->tileColsLog2 != 0) {
+ int tileColsLog2 = AVIF_CLAMP(encoder->tileColsLog2, 0, 6);
+ aom_codec_control(&codec->internal->encoder, AV1E_SET_TILE_COLUMNS, tileColsLog2);
+ }
if (aomCpuUsed != -1) {
if (aom_codec_control(&codec->internal->encoder, AOME_SET_CPUUSED, aomCpuUsed) != AOM_CODEC_OK) {
return AVIF_RESULT_UNKNOWN_ERROR;
}
}
- } else if ((encoderChanges & ~AVIF_ENCODER_CHANGE_CODEC_SPECIFIC) || dimensionsChanged) {
- // Codec specific options does not change cfg, so no need to update it.
- aom_codec_err_t err = aom_codec_enc_config_set(&codec->internal->encoder, cfg);
- if (err != AOM_CODEC_OK) {
- avifDiagnosticsPrintf(codec->diag,
- "aom_codec_enc_config_set() failed: %s: %s",
- aom_codec_error(&codec->internal->encoder),
- aom_codec_error_detail(&codec->internal->encoder));
- return AVIF_RESULT_UNKNOWN_ERROR;
- }
- }
-
- if (!codec->internal->encoderInitialized || (encoderChanges & AVIF_ENCODER_CHANGE_CODEC_SPECIFIC)) {
if (!avifProcessAOMOptionsPostInit(codec, alpha)) {
return AVIF_RESULT_INVALID_CODEC_SPECIFIC_OPTION;
}
- }
-
- avifBool quantizerUpdated = AVIF_FALSE;
- if (!codec->internal->encoderInitialized) {
- quantizerUpdated = AVIF_TRUE;
- if (lossless) {
- aom_codec_control(&codec->internal->encoder, AV1E_SET_LOSSLESS, lossless);
- }
- int tileRowsLog2 = AVIF_CLAMP(encoder->tileRowsLog2, 0, 6);
- if (tileRowsLog2 > 0) {
- aom_codec_control(&codec->internal->encoder, AV1E_SET_TILE_ROWS, tileRowsLog2);
- }
- int tileColsLog2 = AVIF_CLAMP(encoder->tileColsLog2, 0, 6);
- if (tileColsLog2 > 0) {
- aom_codec_control(&codec->internal->encoder, AV1E_SET_TILE_COLUMNS, tileColsLog2);
- }
if (!codec->internal->tuningSet) {
if (aom_codec_control(&codec->internal->encoder, AOME_SET_TUNING, AOM_TUNE_SSIM) != AOM_CODEC_OK) {
return AVIF_RESULT_UNKNOWN_ERROR;
}
}
- codec->internal->encoderInitialized = AVIF_TRUE;
- } else if (encoderChanges) {
+ } else {
+ avifBool dimensionsChanged = AVIF_FALSE;
+ if ((cfg->g_w != image->width) || (cfg->g_h != image->height)) {
+ // We are not ready for dimension change for now.
+ return AVIF_RESULT_NOT_IMPLEMENTED;
+ }
if (alpha) {
if (encoderChanges & (AVIF_ENCODER_CHANGE_MIN_QUANTIZER_ALPHA | AVIF_ENCODER_CHANGE_MAX_QUANTIZER_ALPHA)) {
+ cfg->rc_min_quantizer = AVIF_CLAMP(encoder->minQuantizerAlpha, 0, 63);
+ cfg->rc_max_quantizer = AVIF_CLAMP(encoder->maxQuantizerAlpha, 0, 63);
quantizerUpdated = AVIF_TRUE;
- aom_codec_control(&codec->internal->encoder, AV1E_SET_LOSSLESS, lossless);
}
} else {
if (encoderChanges & (AVIF_ENCODER_CHANGE_MIN_QUANTIZER | AVIF_ENCODER_CHANGE_MAX_QUANTIZER)) {
+ cfg->rc_min_quantizer = AVIF_CLAMP(encoder->minQuantizer, 0, 63);
+ cfg->rc_max_quantizer = AVIF_CLAMP(encoder->maxQuantizer, 0, 63);
quantizerUpdated = AVIF_TRUE;
- aom_codec_control(&codec->internal->encoder, AV1E_SET_LOSSLESS, lossless);
+ }
+ }
+ if (quantizerUpdated) {
+ avifBool lossless =
+ ((cfg->rc_min_quantizer == AVIF_QUANTIZER_LOSSLESS) && (cfg->rc_max_quantizer == AVIF_QUANTIZER_LOSSLESS));
+ aom_codec_control(&codec->internal->encoder, AV1E_SET_LOSSLESS, lossless);
+ }
+ if (quantizerUpdated || dimensionsChanged) {
+ aom_codec_err_t err = aom_codec_enc_config_set(&codec->internal->encoder, cfg);
+ if (err != AOM_CODEC_OK) {
+ avifDiagnosticsPrintf(codec->diag,
+ "aom_codec_enc_config_set() failed: %s: %s",
+ aom_codec_error(&codec->internal->encoder),
+ aom_codec_error_detail(&codec->internal->encoder));
+ return AVIF_RESULT_UNKNOWN_ERROR;
}
}
if (encoderChanges & AVIF_ENCODER_CHANGE_TILE_ROWS_LOG2) {
@@ -808,10 +798,15 @@
if (encoderChanges & AVIF_ENCODER_CHANGE_TILE_COLS_LOG2) {
aom_codec_control(&codec->internal->encoder, AV1E_SET_TILE_COLUMNS, AVIF_CLAMP(encoder->tileColsLog2, 0, 6));
}
+ if (encoderChanges & AVIF_ENCODER_CHANGE_CODEC_SPECIFIC) {
+ if (!avifProcessAOMOptionsPostInit(codec, alpha)) {
+ return AVIF_RESULT_INVALID_CODEC_SPECIFIC_OPTION;
+ }
+ }
}
#if defined(AOM_USAGE_ALL_INTRA)
- if (aomUsage == AOM_USAGE_ALL_INTRA && !codec->internal->endUsageSet && !codec->internal->cqLevelSet && quantizerUpdated) {
+ if (quantizerUpdated && cfg->g_usage == AOM_USAGE_ALL_INTRA && !codec->internal->endUsageSet && !codec->internal->cqLevelSet) {
// The default rc_end_usage in all intra mode is AOM_Q, which requires cq-level to
// function. A libavif user may not know this internal detail and therefore may only
// set the min and max quantizers in the avifEncoder struct. If this is the case, set
diff --git a/src/codec_rav1e.c b/src/codec_rav1e.c
index ee68268..8e6dbff 100644
--- a/src/codec_rav1e.c
+++ b/src/codec_rav1e.c
@@ -53,16 +53,16 @@
avifEncoder * encoder,
const avifImage * image,
avifBool alpha,
- avifEncoderChanges updatedConfig,
+ avifEncoderChanges encoderChanges,
uint32_t addImageFlags,
avifCodecEncodeOutput * output)
{
- // rav1e does not support changing config.
- if (updatedConfig) {
+ // rav1e does not support changing encoder settings.
+ if (encoderChanges) {
return AVIF_RESULT_NOT_IMPLEMENTED;
}
- // rav1e does not support changing encoding dimension.
+ // rav1e does not support changing image dimensions.
if (!codec->internal->rav1eContext) {
codec->internal->encodeWidth = image->width;
codec->internal->encodeHeight = image->height;
diff --git a/src/codec_svt.c b/src/codec_svt.c
index f6a4c18..3b49881 100644
--- a/src/codec_svt.c
+++ b/src/codec_svt.c
@@ -46,16 +46,16 @@
avifEncoder * encoder,
const avifImage * image,
avifBool alpha,
- avifEncoderChanges updatedConfig,
+ avifEncoderChanges encoderChanges,
uint32_t addImageFlags,
avifCodecEncodeOutput * output)
{
- // svt does not support changing config.
- if (updatedConfig) {
+ // SVT-AV1 does not support changing encoder settings.
+ if (encoderChanges) {
return AVIF_RESULT_NOT_IMPLEMENTED;
}
- // svt does not support changing encoding dimension.
+ // SVT-AV1 does not support changing image dimensions.
if (codec->internal->svt_encoder != NULL) {
if ((codec->internal->svt_config.source_width != image->width) || (codec->internal->svt_config.source_height != image->height)) {
return AVIF_RESULT_NOT_IMPLEMENTED;
diff --git a/src/write.c b/src/write.c
index 5cfcff9..45f002f 100644
--- a/src/write.c
+++ b/src/write.c
@@ -294,15 +294,15 @@
avifEncoder * encoder = (avifEncoder *)avifAlloc(sizeof(avifEncoder));
memset(encoder, 0, sizeof(avifEncoder));
encoder->maxThreads = 1;
+ encoder->speed = AVIF_SPEED_DEFAULT;
+ encoder->keyframeInterval = 0;
+ encoder->timescale = 1;
encoder->minQuantizer = AVIF_QUANTIZER_LOSSLESS;
encoder->maxQuantizer = AVIF_QUANTIZER_LOSSLESS;
encoder->minQuantizerAlpha = AVIF_QUANTIZER_LOSSLESS;
encoder->maxQuantizerAlpha = AVIF_QUANTIZER_LOSSLESS;
encoder->tileRowsLog2 = 0;
encoder->tileColsLog2 = 0;
- encoder->speed = AVIF_SPEED_DEFAULT;
- encoder->keyframeInterval = 0;
- encoder->timescale = 1;
encoder->data = avifEncoderDataCreate();
encoder->csOptions = avifCodecSpecificOptionsCreate();
return encoder;
@@ -320,59 +320,61 @@
avifCodecSpecificOptionsSet(encoder->csOptions, key, value);
}
-static void avifBackupSettings(avifEncoder * encoder)
+static void avifEncoderBackupSettings(avifEncoder * encoder)
{
avifEncoder * lastEncoder = &encoder->data->lastEncoder;
- // lastEncoder->data is used to mark that lastEncoder is initialized.
+ // lastEncoder->data is only used to mark that lastEncoder is initialized. lastEncoder->data
+ // must not be dereferenced.
lastEncoder->data = encoder->data;
lastEncoder->codecChoice = encoder->codecChoice;
+ lastEncoder->maxThreads = encoder->maxThreads;
+ lastEncoder->speed = encoder->speed;
lastEncoder->keyframeInterval = encoder->keyframeInterval;
lastEncoder->timescale = encoder->timescale;
- lastEncoder->maxThreads = encoder->maxThreads;
lastEncoder->minQuantizer = encoder->minQuantizer;
lastEncoder->maxQuantizer = encoder->maxQuantizer;
lastEncoder->minQuantizerAlpha = encoder->minQuantizerAlpha;
lastEncoder->maxQuantizerAlpha = encoder->maxQuantizerAlpha;
lastEncoder->tileRowsLog2 = encoder->tileRowsLog2;
lastEncoder->tileColsLog2 = encoder->tileColsLog2;
- lastEncoder->speed = encoder->speed;
}
-// This function detect changes made on avifEncoder.
-// It reports if the change is valid, i.e. if any setting that can't change was changed.
-// It also reports detected changes in updatedConfig.
-static avifBool avifEncoderSettingsChanged(const avifEncoder * encoder, avifEncoderChanges * encoderChanges)
+// This function detects changes made on avifEncoder. It returns true on success (i.e., if every
+// change is valid), or false on failure (i.e., if any setting that can't change was changed). It
+// reports detected changes in encoderChanges.
+static avifBool avifEncoderDetectChanges(const avifEncoder * encoder, avifEncoderChanges * encoderChanges)
{
const avifEncoder * lastEncoder = &encoder->data->lastEncoder;
+ *encoderChanges = 0;
if (!lastEncoder->data) {
+ // lastEncoder is not initialized.
return AVIF_TRUE;
}
- if ((lastEncoder->codecChoice != encoder->codecChoice) || (lastEncoder->keyframeInterval != encoder->keyframeInterval) ||
- (lastEncoder->timescale != encoder->timescale) || (lastEncoder->maxThreads != encoder->maxThreads) ||
- (lastEncoder->speed != encoder->speed)) {
+ if ((lastEncoder->codecChoice != encoder->codecChoice) || (lastEncoder->maxThreads != encoder->maxThreads) ||
+ (lastEncoder->speed != encoder->speed) || (lastEncoder->keyframeInterval != encoder->keyframeInterval) ||
+ (lastEncoder->timescale != encoder->timescale)) {
return AVIF_FALSE;
}
- *encoderChanges = 0;
- if ((lastEncoder->minQuantizer != encoder->minQuantizer)) {
+ if (lastEncoder->minQuantizer != encoder->minQuantizer) {
*encoderChanges |= AVIF_ENCODER_CHANGE_MIN_QUANTIZER;
}
- if ((lastEncoder->maxQuantizer != encoder->maxQuantizer)) {
+ if (lastEncoder->maxQuantizer != encoder->maxQuantizer) {
*encoderChanges |= AVIF_ENCODER_CHANGE_MAX_QUANTIZER;
}
- if ((lastEncoder->minQuantizerAlpha != encoder->minQuantizerAlpha)) {
+ if (lastEncoder->minQuantizerAlpha != encoder->minQuantizerAlpha) {
*encoderChanges |= AVIF_ENCODER_CHANGE_MIN_QUANTIZER_ALPHA;
}
- if ((lastEncoder->maxQuantizerAlpha != encoder->maxQuantizerAlpha)) {
+ if (lastEncoder->maxQuantizerAlpha != encoder->maxQuantizerAlpha) {
*encoderChanges |= AVIF_ENCODER_CHANGE_MAX_QUANTIZER_ALPHA;
}
- if ((lastEncoder->tileRowsLog2 != encoder->tileRowsLog2)) {
+ if (lastEncoder->tileRowsLog2 != encoder->tileRowsLog2) {
*encoderChanges |= AVIF_ENCODER_CHANGE_TILE_ROWS_LOG2;
}
- if ((lastEncoder->tileColsLog2 != encoder->tileColsLog2)) {
+ if (lastEncoder->tileColsLog2 != encoder->tileColsLog2) {
*encoderChanges |= AVIF_ENCODER_CHANGE_TILE_COLS_LOG2;
}
if (encoder->csOptions->count > 0) {
@@ -669,11 +671,11 @@
return AVIF_RESULT_NO_CODEC_AVAILABLE;
}
- avifEncoderChanges encoderChanges = 0;
- if (!avifEncoderSettingsChanged(encoder, &encoderChanges)) {
+ avifEncoderChanges encoderChanges;
+ if (!avifEncoderDetectChanges(encoder, &encoderChanges)) {
return AVIF_RESULT_CANNOT_CHANGE_SETTING;
}
- avifBackupSettings(encoder);
+ avifEncoderBackupSettings(encoder);
// -----------------------------------------------------------------------
// Validate images
@@ -876,7 +878,8 @@
// Another frame in an image sequence
const avifImage * imageMetadata = encoder->data->imageMetadata;
- // If the first image had an alpha plane (even if fully opaque), all subsequent images must have alpha as well.
+ // If the first image in the sequence had an alpha plane (even if fully opaque), all
+ // subsequent images must have alpha as well.
if ((imageMetadata->depth != firstCell->depth) || (imageMetadata->yuvFormat != firstCell->yuvFormat) ||
(imageMetadata->yuvRange != firstCell->yuvRange) || (imageMetadata->colorPrimaries != firstCell->colorPrimaries) ||
(imageMetadata->transferCharacteristics != firstCell->transferCharacteristics) ||
diff --git a/tests/gtest/avifchangesettingtest.cc b/tests/gtest/avifchangesettingtest.cc
index 13d3b36..871a06c 100644
--- a/tests/gtest/avifchangesettingtest.cc
+++ b/tests/gtest/avifchangesettingtest.cc
@@ -88,7 +88,7 @@
ASSERT_EQ(avifDecoderParse(decoder.get()), AVIF_RESULT_OK);
ASSERT_EQ(avifDecoderNextImage(decoder.get()), AVIF_RESULT_OK);
ASSERT_EQ(avifDecoderNextImage(decoder.get()), AVIF_RESULT_WAITING_ON_IO);
- ((testutil::AvifIOLimitedReader*)io)->clamp =
+ reinterpret_cast<testutil::AvifIOLimitedReader*>(io)->clamp =
testutil::AvifIOLimitedReader::kNoClamp;
ASSERT_EQ(avifDecoderNextImage(decoder.get()), AVIF_RESULT_OK);
ASSERT_EQ(avifDecoderNextImage(decoder.get()),
diff --git a/tests/gtest/aviftest_helpers.cc b/tests/gtest/aviftest_helpers.cc
index d981a50..a8f7f7f 100644
--- a/tests/gtest/aviftest_helpers.cc
+++ b/tests/gtest/aviftest_helpers.cc
@@ -5,6 +5,7 @@
#include <algorithm>
#include <cassert>
+#include <cstdint>
#include "avif/avif.h"
@@ -214,36 +215,39 @@
return true;
}
-static avifResult avifIOLimitedReaderRead(struct avifIO* io, uint32_t readFlags,
+static avifResult avifIOLimitedReaderRead(avifIO* io, uint32_t readFlags,
uint64_t offset, size_t size,
avifROData* out) {
auto reader = reinterpret_cast<AvifIOLimitedReader*>(io);
+ if (offset > UINT64_MAX - size) {
+ return AVIF_RESULT_IO_ERROR;
+ }
if (offset + size > reader->clamp) {
return AVIF_RESULT_WAITING_ON_IO;
}
- return reader->underlayIO->read(reader->underlayIO, readFlags, offset, size,
+ return reader->underlyingIO->read(reader->underlyingIO, readFlags, offset, size,
out);
}
-static void avifIOLimitedReaderDestroy(struct avifIO* io) {
+static void avifIOLimitedReaderDestroy(avifIO* io) {
auto reader = reinterpret_cast<AvifIOLimitedReader*>(io);
- reader->underlayIO->destroy(reader->underlayIO);
+ reader->underlyingIO->destroy(reader->underlyingIO);
delete reader;
}
-avifIO* AvifIOCreateLimitedReader(avifIO* underlayIO, uint64_t clamp) {
+avifIO* AvifIOCreateLimitedReader(avifIO* underlyingIO, uint64_t clamp) {
return reinterpret_cast<avifIO*>(
new AvifIOLimitedReader{{
avifIOLimitedReaderDestroy,
avifIOLimitedReaderRead,
nullptr,
- underlayIO->sizeHint,
- underlayIO->persistent,
+ underlyingIO->sizeHint,
+ underlyingIO->persistent,
nullptr,
},
- underlayIO,
+ underlyingIO,
clamp});
}
diff --git a/tests/gtest/aviftest_helpers.h b/tests/gtest/aviftest_helpers.h
index ccca8a9..510e6b3 100644
--- a/tests/gtest/aviftest_helpers.h
+++ b/tests/gtest/aviftest_helpers.h
@@ -66,13 +66,15 @@
static constexpr uint64_t kNoClamp = std::numeric_limits<uint64_t>::max();
avifIO io;
- avifIO* underlayIO;
+ avifIO* underlyingIO;
uint64_t clamp;
};
-avifIO* AvifIOCreateLimitedReader(avifIO* underlayIO, uint64_t clamp);
+avifIO* AvifIOCreateLimitedReader(avifIO* underlyingIO, uint64_t clamp);
} // namespace testutil
} // namespace libavif
+//------------------------------------------------------------------------------
+
#endif // LIBAVIF_TESTS_AVIFTEST_HELPERS_H_