Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ The changes are relative to the previous release, unless the baseline is specifi

* Add the ignoreICC option to avifDecoder
* Support ignoring alpha in avifDecoder::imageContentToDecode
* Support overriding display size in avifEncoder
* avifenc: add --ignore-alpha flag to discard alpha channel on encode
* avifenc: add --display-size flag to override display size of encoded image
* avifgainmaputil: add --ignore-alpha flag to discard alpha channel
* avifgainmaputil: add --ignore-exif and --ignore-xmp flags
* avifdec: add --ignore-exif and --ignore-xmp flags
Expand Down
99 changes: 93 additions & 6 deletions apps/avifenc.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ typedef struct
avifHeaderFormatFlags headerFormat;
uint64_t creationTime;
uint64_t modificationTime;
uint32_t width;
uint32_t height;
Comment thread
wantehchang marked this conversation as resolved.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yuan: Please apply the patch below and review my proposed changes. I moved some code around and edited some comments.

In places where my comment edits may not be easy to see, I also added review comments to describe my edits. In those places my review comments will say "(See patch.)"

Here is my proposed patch:

diff --git a/apps/avifenc.c b/apps/avifenc.c
index b45094e9..d8dad2cc 100644
--- a/apps/avifenc.c
+++ b/apps/avifenc.c
@@ -2230,7 +2230,7 @@ int main(int argc, char * argv[])
         goto cleanup;
     }
     if (avifSettingsUsesDisplaySizeOverride(&settings) && (settings.layers == 1) && (input.filesCount > 1)) {
-        fprintf(stderr, "ERROR: --display-size is not supported with image sequences. Use --layered for multiple still inputs.\n");
+        fprintf(stderr, "ERROR: --display-size is not supported with image sequences. Use --layered for multiple still image inputs.\n");
         goto cleanup;
     }
 
diff --git a/include/avif/avif.h b/include/avif/avif.h
index 231b8550..556359cb 100644
--- a/include/avif/avif.h
+++ b/include/avif/avif.h
@@ -822,10 +822,11 @@ typedef struct avifImage
     // transformFlags. On decode, only honor the values in boxes with the associated transform flag set.
     // These also apply to gainMap->image, if any.
     //
-    // When encoding with avifEncoder.width/height set (see its comment), these values are interpreted
-    // relative to that overridden display size rather than to this avifImage's own width/height.
-    // No special handling is needed during decode: the decoded avifImage is automatically scaled to
-    // the display size, so these values are relative to its width/height as usual.
+    // When encoding with avifEncoder.width/height set (see their comment), these transformations
+    // are interpreted relative to that overridden display size rather than to this avifImage's own
+    // width/height. No special handling is needed during decode: the decoded avifImage is
+    // automatically scaled to the display size, so these transformations are relative to the
+    // decoded avifImage's width/height as usual.
     avifTransformFlags transformFlags;
     avifPixelAspectRatioBox pasp;
     avifCleanApertureBox clap;
@@ -1638,7 +1639,7 @@ typedef struct avifEncoder
     // Overrides the image's display size (the width and height AVIF declares this image is meant
     // to be shown at) independent of the pixel dimensions actually encoded. Any image passed to
     // avifEncoderAddImage()/avifEncoderAddImageGrid() that is encoded smaller than the display size
-    // is upscaled to it on decode.
+    // is upscaled to the display size on decode.
     //
     // Defaults to 0 (disabled). When 0, the display size is the size of the first added image.
     // When set, both width and height must be nonzero, and neither can be smaller than the coded
@@ -1661,9 +1662,9 @@ typedef struct avifEncoder
     // decoder is required to honor; a coded image smaller than it is upscaled by the decoder to
     // match. Separately, an AV1 encoder session declares a maximum frame size once, up front, and
     // every later frame must fit within it; by default that maximum is simply the size of the first
-    // frame encoded. Setting width/height also declares that AV1-level maximum explicitly, in
-    // addition to the ispe box, so that later, larger layers stay within it. This is why it must be
-    // at least as large as every layer's coded size.
+    // frame encoded. Setting width/height also declares that AV1-level maximum frame size
+    // explicitly, in addition to the ispe box, so that later, larger layers stay within it. This is
+    // why it must be at least as large as every layer's coded size.
     uint32_t width;
     uint32_t height;
 } avifEncoder;
diff --git a/src/codec_aom.c b/src/codec_aom.c
index 9f23c620..8edd3f8a 100644
--- a/src/codec_aom.c
+++ b/src/codec_aom.c
@@ -893,14 +893,20 @@ static avifResult aomCodecEncodeImage(avifCodec * codec,
             }
         }
 
-        if ((addImageFlags & AVIF_ADD_IMAGE_FLAG_SINGLE) && (encoder->width == 0) && (encoder->height == 0)) {
+        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
             // 1 in AV1 sequence headers.
-            // Still picture header requires frame size to match
-            // max_frame_width and max_frame_height,
-            // so we can't use it if frame can have a different size.
             cfg->g_limit = 1;
+            // Reduced still picture header requires frame size to match max
+            // frame size, so we can't use reduced still picture header if frame
+            // size is different from max frame size.
+            if (cfg->g_forced_max_frame_width > image->width) {
+                cfg->g_forced_max_frame_width = image->width;
+            }
+            if (cfg->g_forced_max_frame_height > image->height) {
+                cfg->g_forced_max_frame_height = image->height;
+            }
         }
         if (useAllIntra) {
 #if !defined(AOM_USAGE_ALL_INTRA)
@@ -939,7 +945,7 @@ static avifResult aomCodecEncodeImage(avifCodec * codec,
             cfg->g_lag_in_frames = 0;
         }
         if ((encoder->width || encoder->height) && (cfg->g_lag_in_frames > 1)) {
-            // libaom does not allow changing frame dimension if
+            // aom_codec_enc_config_set() does not allow changing frame dimensions if
             // g_lag_in_frames > 1.
             cfg->g_lag_in_frames = 1;
         }
diff --git a/src/codec_avm.c b/src/codec_avm.c
index adf26990..ad829fc8 100644
--- a/src/codec_avm.c
+++ b/src/codec_avm.c
@@ -444,6 +444,11 @@ static avifResult avmCodecEncodeImage(avifCodec * codec,
                                       avifAddImageFlags addImageFlags,
                                       avifCodecEncodeOutput * output)
 {
+    if (encoder->width || encoder->height) {
+        avifDiagnosticsPrintf(codec->diag, "AVM does not support display-size override");
+        return AVIF_RESULT_NOT_IMPLEMENTED;
+    }
+
     struct avm_codec_enc_cfg * cfg = &codec->internal->cfg;
     avifBool quantizerUpdated = AVIF_FALSE;
     const int quantizer = avmQualityToQuantizer(quality, image->depth);
@@ -453,11 +458,6 @@ static avifResult avmCodecEncodeImage(avifCodec * codec,
     // two fields.
     encoderChanges &= ~AVIF_ENCODER_CHANGE_SCALING_MODE;
 
-    if (encoder->width || encoder->height) {
-        avifDiagnosticsPrintf(codec->diag, "AVM does not support display-size override");
-        return AVIF_RESULT_NOT_IMPLEMENTED;
-    }
-
     if (!codec->internal->encoderInitialized) {
         int avmCpuUsed = -1;
         if (encoder->speed != AVIF_SPEED_DEFAULT) {
diff --git a/src/codec_rav1e.c b/src/codec_rav1e.c
index 4b41bfeb..d94553d2 100644
--- a/src/codec_rav1e.c
+++ b/src/codec_rav1e.c
@@ -82,6 +82,12 @@ static avifResult rav1eCodecEncodeImage(avifCodec * codec,
         return AVIF_RESULT_NOT_IMPLEMENTED;
     }
 
+    // rav1e does not support overriding maximum frame width/height in sequence header
+    if (encoder->width || encoder->height) {
+        avifDiagnosticsPrintf(codec->diag, "rav1e does not support display-size override");
+        return AVIF_RESULT_NOT_IMPLEMENTED;
+    }
+
     // rav1e does not support encoding layered image.
     if (encoder->extraLayerCount > 0) {
         return AVIF_RESULT_NOT_IMPLEMENTED;
@@ -90,12 +96,6 @@ static avifResult rav1eCodecEncodeImage(avifCodec * codec,
     // rav1e does not support disabling lagged output. See https://github.com/xiph/rav1e/issues/2267. Ignore this setting.
     (void)disableLaggedOutput;
 
-    // rav1e does not support overriding maximum frame width/height in sequence header
-    if (encoder->width || encoder->height) {
-        avifDiagnosticsPrintf(codec->diag, "rav1e does not support display-size override");
-        return AVIF_RESULT_NOT_IMPLEMENTED;
-    }
-
     avifResult result = AVIF_RESULT_UNKNOWN_ERROR;
 
     RaConfig * rav1eConfig = NULL;
diff --git a/src/codec_svt.c b/src/codec_svt.c
index 70be13fa..71bdac06 100644
--- a/src/codec_svt.c
+++ b/src/codec_svt.c
@@ -75,6 +75,11 @@ static avifResult svtCodecEncodeImage(avifCodec * codec,
         }
     }
 
+    if (encoder->width || encoder->height) {
+        avifDiagnosticsPrintf(codec->diag, "SVT-AV1 does not support display-size override");
+        return AVIF_RESULT_NOT_IMPLEMENTED;
+    }
+
     // SVT-AV1 does not support encoding layered image.
     if (encoder->extraLayerCount > 0) {
         return AVIF_RESULT_NOT_IMPLEMENTED;
@@ -83,11 +88,6 @@ static avifResult svtCodecEncodeImage(avifCodec * codec,
     // SVT-AV1 does not support disabling lagged output. Ignore this setting.
     (void)disableLaggedOutput;
 
-    if (encoder->width || encoder->height) {
-        avifDiagnosticsPrintf(codec->diag, "SVT-AV1 does not support display-size override");
-        return AVIF_RESULT_NOT_IMPLEMENTED;
-    }
-
     avifResult result = AVIF_RESULT_UNKNOWN_ERROR;
     EbColorFormat color_format = EB_YUV420;
     uint8_t * uvPlanes = NULL; // 4:2:0 U and V placeholder for alpha because SVT-AV1 does not support 4:0:0.
diff --git a/src/write.c b/src/write.c
index 59095ac5..3da38e2a 100644
--- a/src/write.c
+++ b/src/write.c
@@ -525,8 +525,6 @@ avifEncoder * avifEncoderCreate(void)
     encoder->maxQuantizer = AVIF_QUANTIZER_WORST_QUALITY;
     encoder->minQuantizerAlpha = AVIF_QUANTIZER_BEST_QUALITY;
     encoder->maxQuantizerAlpha = AVIF_QUANTIZER_WORST_QUALITY;
-    encoder->width = 0;
-    encoder->height = 0;
     encoder->tileRowsLog2 = 0;
     encoder->tileColsLog2 = 0;
     encoder->autoTiling = AVIF_FALSE;
@@ -541,6 +539,8 @@ avifEncoder * avifEncoderCreate(void)
     encoder->creationTime = 0;
     encoder->modificationTime = 0;
     encoder->sampleTransformRecipe = AVIF_SAMPLE_TRANSFORM_NONE;
+    encoder->width = 0;
+    encoder->height = 0;
     return encoder;
 }
 
@@ -574,8 +574,6 @@ static void avifEncoderBackupSettings(avifEncoder * encoder)
     lastEncoder->timescale = encoder->timescale;
     lastEncoder->repetitionCount = encoder->repetitionCount;
     lastEncoder->extraLayerCount = encoder->extraLayerCount;
-    lastEncoder->width = encoder->width;
-    lastEncoder->height = encoder->height;
     lastEncoder->minQuantizer = encoder->minQuantizer;
     lastEncoder->maxQuantizer = encoder->maxQuantizer;
     lastEncoder->minQuantizerAlpha = encoder->minQuantizerAlpha;
@@ -586,6 +584,8 @@ static void avifEncoderBackupSettings(avifEncoder * encoder)
     encoder->data->lastTileColsLog2 = encoder->data->tileColsLog2;
     lastEncoder->scalingMode = encoder->scalingMode;
     lastEncoder->sampleTransformRecipe = encoder->sampleTransformRecipe;
+    lastEncoder->width = encoder->width;
+    lastEncoder->height = encoder->height;
 }
 
 // This function detects changes made on avifEncoder. It returns true on success (i.e., if every
@@ -1598,7 +1598,7 @@ static avifCodecType avifEncoderGetCodecType(const avifEncoder * encoder)
     return avifCodecTypeFromChoice(encoder->codecChoice, AVIF_CODEC_FLAG_CAN_ENCODE);
 }
 
-static avifResult avifEncoderValidateDisplaySizeOverride(avifEncoder * encoder, uint32_t gridCols, uint32_t gridRows, const avifImage * firstCell)
+static avifResult avifEncoderValidateDisplaySizeOverride(const avifEncoder * encoder, uint32_t gridCols, uint32_t gridRows, const avifImage * firstCell)
 {
     if (!avifEncoderUsesDisplaySizeOverride(encoder)) {
         return AVIF_RESULT_OK;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. I have to revert the addition of const to avifEncoderValidateDisplaySizeOverride because this function need to write to the diag struct when it found some unsupported config.


avifBool paspPresent;
uint32_t paspValues[2];
Expand Down Expand Up @@ -242,6 +244,8 @@ static void syntaxLong(void)
printf(" --progressive : Automatically set parameters to encode a simple layered image supporting progressive rendering from a single input frame.\n");
printf(" --layered : Encode a layered AVIF. Each input is encoded as one layer and at most %d layers can be encoded.\n",
AVIF_MAX_AV1_LAYER_COUNT);
printf(" --display-size WxH : Set the size at which the AVIF image is displayed, independent of the encoded pixel dimensions.\n");
printf(" Only supported for layered still images (--layered/--progressive); the last layer must exactly match it.\n");
printf(" -g,--grid MxN : Encode a single-image grid AVIF with M cols & N rows. Either supply MxN identical W/H/D images, or a single\n");
printf(" image that can be evenly split into the MxN grid and follow AVIF grid image restrictions. The grid will adopt\n");
printf(" the color profile of the first image supplied.\n");
Expand Down Expand Up @@ -454,6 +458,35 @@ static avifBool convertCropToClap(uint32_t srcW, uint32_t srcH, uint32_t clapVal
return AVIF_TRUE;
}

static avifBool avifSettingsUsesDisplaySizeOverride(const avifSettings * settings)
{
return (settings->width != 0) || (settings->height != 0);
}

static void avifSettingsGetEffectiveOutputDimensions(const avifSettings * settings, const avifImage * image, uint32_t * width, uint32_t * height)
{
*width = settings->width ? settings->width : image->width;
*height = settings->height ? settings->height : image->height;
}

static avifBool avifSettingsVerifyDisplaySizeBounds(const avifSettings * settings, const avifImage * image, const char * filename)
{
if (!avifSettingsUsesDisplaySizeOverride(settings)) {
return AVIF_TRUE;
}
if ((image->width > settings->width) || (image->height > settings->height)) {
fprintf(stderr,
"ERROR: Input image dimensions [%ux%u] exceed display size [%ux%u]: %s\n",
image->width,
image->height,
settings->width,
settings->height,
filename);
return AVIF_FALSE;
}
return AVIF_TRUE;
}

static avifBool avifInputAddCachedImage(avifInput * input)
{
avifImage * newImage = avifImageCreateEmpty();
Expand Down Expand Up @@ -860,10 +893,11 @@ static avifBool avifEncodeUpdateEncoderSettings(avifEncoder * encoder, const avi
static avifBool avifEncoderVerifyImageCompatibility(const avifImage * refImage,
const avifImage * testImage,
const char * seriesType,
const char * filename)
const char * filename,
avifBool allowDimensionChange)
{
// Verify that this frame's properties matches the first frame's properties
if ((refImage->width != testImage->width) || (refImage->height != testImage->height)) {
if (!allowDimensionChange && ((refImage->width != testImage->width) || (refImage->height != testImage->height))) {
fprintf(stderr,
"ERROR: Image %s dimensions mismatch, [%ux%u] vs [%ux%u]: %s\n",
seriesType,
Expand Down Expand Up @@ -954,7 +988,14 @@ static avifBool avifEncodeRestOfImageSequence(avifEncoder * encoder,
settings->inputFormat)) {
goto cleanup;
}
if (!avifEncoderVerifyImageCompatibility(firstImage, nextImage, "sequence", avifPrettyFilename(nextFile->filename))) {
if (!avifSettingsVerifyDisplaySizeBounds(settings, nextImage, avifPrettyFilename(nextFile->filename))) {
goto cleanup;
}
if (!avifEncoderVerifyImageCompatibility(firstImage,
nextImage,
"sequence",
avifPrettyFilename(nextFile->filename),
/*allowDimensionChange=*/AVIF_FALSE)) {
goto cleanup;
}
if (!avifEncodeUpdateEncoderSettings(encoder, nextSettings)) {
Expand Down Expand Up @@ -1061,14 +1102,21 @@ static avifBool avifEncodeRestOfLayeredImage(avifEncoder * encoder,
settings->inputFormat)) {
goto cleanup;
}
if (!avifSettingsVerifyDisplaySizeBounds(settings, nextImage, avifPrettyFilename(nextFile->filename))) {
goto cleanup;
}
// frameIter is NULL if y4m reached end, so single frame y4m is still supported.
if (input->frameIter) {
fprintf(stderr,
"ERROR: Layered encoding does not support input with multiple frames: %s.\n",
avifPrettyFilename(nextFile->filename));
goto cleanup;
}
if (!avifEncoderVerifyImageCompatibility(firstImage, nextImage, "layer", avifPrettyFilename(nextFile->filename))) {
if (!avifEncoderVerifyImageCompatibility(firstImage,
nextImage,
"layer",
avifPrettyFilename(nextFile->filename),
avifSettingsUsesDisplaySizeOverride(settings))) {
goto cleanup;
}
if (!avifEncodeUpdateEncoderSettings(encoder, nextSettings)) {
Expand Down Expand Up @@ -1129,6 +1177,8 @@ static avifBool avifEncodeImagesFixedQuality(const avifSettings * settings,
encoder->creationTime = settings->creationTime;
encoder->modificationTime = settings->modificationTime;
encoder->extraLayerCount = settings->layers - 1;
encoder->width = settings->width;
encoder->height = settings->height;
if (!avifEncodeUpdateEncoderSettings(encoder, &firstFile->settings)) {
goto cleanup;
}
Expand Down Expand Up @@ -1774,6 +1824,15 @@ int main(int argc, char * argv[])
goto cleanup;
}
settings.layered = AVIF_TRUE;
} else if (!strcmp(arg, "--display-size")) {
uint32_t displaySize[2] = { 0 };
NEXTARG();
if (!parseU32List(displaySize, 2, arg, 'x') || (displaySize[0] == 0) || (displaySize[1] == 0)) {
fprintf(stderr, "ERROR: Invalid display size: %s\n", arg);
goto cleanup;
}
settings.width = displaySize[0];
settings.height = displaySize[1];
} else if (!strcmp(arg, "--scaling-mode") || strpre(arg, "--scaling-mode:")) {
avifOptionSuffixType type = parseOptionSuffix(arg, input.filesCount != 0);
if (type == AVIF_OPTION_SUFFIX_INVALID) {
Expand Down Expand Up @@ -2134,6 +2193,11 @@ int main(int argc, char * argv[])
fprintf(stderr, "WARNING: Trailing options with update suffix has no effect. Place them before the input you intend to apply to.\n");
}

if (avifSettingsUsesDisplaySizeOverride(&settings) && ((settings.width == 0) || (settings.height == 0))) {
fprintf(stderr, "ERROR: --display-size must be specified as WxH.\n");
goto cleanup;
}

// Check layer config
if (settings.progressive) {
assert(!settings.layered);
Expand Down Expand Up @@ -2161,6 +2225,18 @@ int main(int argc, char * argv[])
fprintf(stderr, "Layered grid image unimplemented in avifenc.\n");
goto cleanup;
}
if (avifSettingsUsesDisplaySizeOverride(&settings) && settings.gridDimsPresent) {
fprintf(stderr, "ERROR: --display-size is not supported with --grid.\n");
goto cleanup;
}
if (avifSettingsUsesDisplaySizeOverride(&settings) && (settings.layers == 1)) {
if (input.filesCount > 1) {
fprintf(stderr, "ERROR: --display-size is not supported with image sequences. Use --layered for multiple still image inputs.\n");
} else {
fprintf(stderr, "ERROR: --display-size is only supported with --layered.\n");
}
goto cleanup;
}
Comment thread
wantehchang marked this conversation as resolved.

for (int i = 0; i < input.filesCount; ++i) {
avifInputFile * file = &input.files[i];
Expand Down Expand Up @@ -2381,6 +2457,14 @@ int main(int argc, char * argv[])
goto cleanup;
}

if (!avifSettingsVerifyDisplaySizeBounds(&settings, image, avifPrettyFilename(firstFile->filename))) {
goto cleanup;
}

uint32_t outputImageWidth;
uint32_t outputImageHeight;
avifSettingsGetEffectiveOutputDimensions(&settings, image, &outputImageWidth, &outputImageHeight);

printf("Successfully loaded: %s\n", avifPrettyFilename(firstFile->filename));

// Prepare image timings
Expand Down Expand Up @@ -2433,7 +2517,7 @@ int main(int argc, char * argv[])
image->pasp.vSpacing = settings.paspValues[1];
}
if (cropConversionRequired) {
if (!convertCropToClap(image->width, image->height, settings.clapValues)) {
if (!convertCropToClap(outputImageWidth, outputImageHeight, settings.clapValues)) {
goto cleanup;
}
settings.clapValid = AVIF_TRUE;
Expand All @@ -2453,7 +2537,7 @@ int main(int argc, char * argv[])
avifCropRect cropRect;
avifDiagnostics diag;
avifDiagnosticsClearError(&diag);
if (!avifCropRectFromCleanApertureBox(&cropRect, &image->clap, image->width, image->height, &diag)) {
if (!avifCropRectFromCleanApertureBox(&cropRect, &image->clap, outputImageWidth, outputImageHeight, &diag)) {
fprintf(stderr,
"ERROR: Invalid clap: width:[%d / %d], height:[%d / %d], horizOff:[%d / %d], vertOff:[%d / %d] - %s\n",
(int32_t)image->clap.widthN,
Expand Down Expand Up @@ -2639,6 +2723,9 @@ int main(int argc, char * argv[])
settings.gridDims[0],
settings.gridDims[1],
settings.layers > 1 ? AVIF_PROGRESSIVE_STATE_AVAILABLE : AVIF_PROGRESSIVE_STATE_UNAVAILABLE);
if (avifSettingsUsesDisplaySizeOverride(&settings)) {
printf(" * Display Size : %ux%u\n", settings.width, settings.height);
}

avifEncodedByteSizes byteSizes = { 0, 0, 0 };
if (!avifEncodeImages(&settings, &input, firstFile, image, (const avifImage **)gridCells, &raw, &byteSizes)) {
Expand Down
14 changes: 14 additions & 0 deletions include/avif/avif.h
Original file line number Diff line number Diff line change
Expand Up @@ -821,6 +821,12 @@ typedef struct avifImage
// To encode any of these boxes, set the values in the associated box, then enable the flag in
// transformFlags. On decode, only honor the values in boxes with the associated transform flag set.
// These also apply to gainMap->image, if any.
//
// When encoding with avifEncoder.width/height set (see their comment), these transformations
// are interpreted relative to that size rather than to this intermediate layer's own
// width/height. No special handling is needed during decode: the decoded layer is
// automatically scaled to the configured size, so these transformations are relative to the
// decoded avifImage's width/height as usual.
avifTransformFlags transformFlags;
avifPixelAspectRatioBox pasp;
avifCleanApertureBox clap;
Expand Down Expand Up @@ -1582,6 +1588,7 @@ typedef struct avifEncoder
avifBool autoTiling;

// Up/down scaling of the image to perform before encoding.
// This cannot be used together with encoder->width / encoder->height.
avifScalingMode scalingMode;

// --------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -1628,6 +1635,13 @@ typedef struct avifEncoder

// Version 1.4.0 ends here. Add any new members after this line.
// --------------------------------------------------------------------------------------------

// Only for layered image (extraLayerCount < 0), otherwise must be the default value 0.
// Declares the size of the encoded image beforehand, which shall be exactly the size of the
// last layer. This allows adding smaller images as earlier layers to avoid a wasted scaling
// round trip, or scale ratios that the encoder does not support via scalingMode.
uint32_t width;
uint32_t height;
} avifEncoder;

// Creates an encoder initialized with default settings values.
Expand Down
12 changes: 10 additions & 2 deletions src/codec_aom.c
Original file line number Diff line number Diff line change
Expand Up @@ -871,6 +871,8 @@ static avifResult aomCodecEncodeImage(avifCodec * codec,
cfg->g_input_bit_depth = image->depth;
cfg->g_w = image->width;
cfg->g_h = image->height;
cfg->g_forced_max_frame_width = encoder->width;
cfg->g_forced_max_frame_height = encoder->height;

// Detect the libaom v3.6.0 bug described in
// https://crbug.com/aomedia/2871#c12. See the changes to
Expand Down Expand Up @@ -933,6 +935,11 @@ static avifResult aomCodecEncodeImage(avifCodec * codec,
if (disableLaggedOutput) {
cfg->g_lag_in_frames = 0;
}
if ((encoder->width || encoder->height) && (cfg->g_lag_in_frames > 1)) {
// aom_codec_enc_config_set() does not allow changing frame dimensions if
// g_lag_in_frames > 1.
Comment thread
wantehchang marked this conversation as resolved.
cfg->g_lag_in_frames = 1;
}
if (encoder->maxThreads > 1) {
// libaom fails if cfg->g_threads is greater than 64 threads. See MAX_NUM_THREADS in
// aom/aom_util/aom_thread.h.
Expand Down Expand Up @@ -1082,8 +1089,9 @@ static avifResult aomCodecEncodeImage(avifCodec * codec,
} 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;
cfg->g_w = image->width;
cfg->g_h = image->height;
dimensionsChanged = AVIF_TRUE;
}
if (alpha) {
if (encoderChanges & (AVIF_ENCODER_CHANGE_MIN_QUANTIZER_ALPHA | AVIF_ENCODER_CHANGE_MAX_QUANTIZER_ALPHA)) {
Expand Down
5 changes: 5 additions & 0 deletions src/codec_avm.c
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,11 @@ static avifResult avmCodecEncodeImage(avifCodec * codec,
avifAddImageFlags addImageFlags,
avifCodecEncodeOutput * output)
{
if (encoder->width || encoder->height) {
avifDiagnosticsPrintf(codec->diag, "AVM does not support display-size override");
return AVIF_RESULT_NOT_IMPLEMENTED;
}

struct avm_codec_enc_cfg * cfg = &codec->internal->cfg;
avifBool quantizerUpdated = AVIF_FALSE;
const int quantizer = avmQualityToQuantizer(quality, image->depth);
Expand Down
6 changes: 6 additions & 0 deletions src/codec_rav1e.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,12 @@ static avifResult rav1eCodecEncodeImage(avifCodec * codec,
return AVIF_RESULT_NOT_IMPLEMENTED;
}

// rav1e does not support overriding maximum frame width/height in sequence header
if (encoder->width || encoder->height) {
avifDiagnosticsPrintf(codec->diag, "rav1e does not support display-size override");
return AVIF_RESULT_NOT_IMPLEMENTED;
}

// rav1e does not support encoding layered image.
if (encoder->extraLayerCount > 0) {
return AVIF_RESULT_NOT_IMPLEMENTED;
Expand Down
5 changes: 5 additions & 0 deletions src/codec_svt.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,11 @@ static avifResult svtCodecEncodeImage(avifCodec * codec,
}
}

if (encoder->width || encoder->height) {
avifDiagnosticsPrintf(codec->diag, "SVT-AV1 does not support display-size override");
return AVIF_RESULT_NOT_IMPLEMENTED;
}

// SVT-AV1 does not support encoding layered image.
if (encoder->extraLayerCount > 0) {
return AVIF_RESULT_NOT_IMPLEMENTED;
Expand Down
Loading
Loading