-
Notifications
You must be signed in to change notification settings - Fork 303
Support display size override for layered image #1069
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
d5fc449
f3e8b2e
25eb44b
ae4d145
d78bc6c
43279ab
d313caf
9f5af4d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -44,6 +44,8 @@ typedef struct | |
| avifHeaderFormatFlags headerFormat; | ||
| uint64_t creationTime; | ||
| uint64_t modificationTime; | ||
| uint32_t width; | ||
| uint32_t height; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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:
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. I have to revert the addition of |
||
|
|
||
| avifBool paspPresent; | ||
| uint32_t paspValues[2]; | ||
|
|
@@ -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"); | ||
|
|
@@ -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(); | ||
|
|
@@ -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, | ||
|
|
@@ -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)) { | ||
|
|
@@ -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)) { | ||
|
|
@@ -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; | ||
| } | ||
|
|
@@ -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) { | ||
|
|
@@ -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); | ||
|
|
@@ -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; | ||
| } | ||
|
wantehchang marked this conversation as resolved.
|
||
|
|
||
| for (int i = 0; i < input.filesCount; ++i) { | ||
| avifInputFile * file = &input.files[i]; | ||
|
|
@@ -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 | ||
|
|
@@ -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; | ||
|
|
@@ -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, | ||
|
|
@@ -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)) { | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.