-
Notifications
You must be signed in to change notification settings - Fork 195
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
Allow odd clap dimensions and offsets #2426
base: main
Are you sure you want to change the base?
Changes from all commits
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 |
---|---|---|
|
@@ -670,19 +670,8 @@ static avifBool overflowsInt32(int64_t x) | |
return (x < INT32_MIN) || (x > INT32_MAX); | ||
} | ||
|
||
static avifBool avifCropRectIsValid(const avifCropRect * cropRect, uint32_t imageW, uint32_t imageH, avifPixelFormat yuvFormat, avifDiagnostics * diag) | ||
|
||
static avifBool avifCropRectIsValid(const avifCropRect * cropRect, uint32_t imageW, uint32_t imageH, avifDiagnostics * diag) | ||
{ | ||
// ISO/IEC 23000-22:2019/Amd. 2:2021, Section 7.3.6.7: | ||
// The clean aperture property is restricted according to the chroma | ||
// sampling format of the input image (4:4:4, 4:2:2:, 4:2:0, or 4:0:0) as | ||
// follows: | ||
// ... | ||
// - If chroma is subsampled horizontally (i.e., 4:2:2 and 4:2:0), the | ||
// leftmost pixel of the clean aperture shall be even numbers; | ||
// - If chroma is subsampled vertically (i.e., 4:2:0), the topmost line | ||
// of the clean aperture shall be even numbers. | ||
|
||
if ((cropRect->width == 0) || (cropRect->height == 0)) { | ||
avifDiagnosticsPrintf(diag, "[Strict] crop rect width and height must be nonzero"); | ||
return AVIF_FALSE; | ||
|
@@ -692,28 +681,16 @@ static avifBool avifCropRectIsValid(const avifCropRect * cropRect, uint32_t imag | |
avifDiagnosticsPrintf(diag, "[Strict] crop rect is out of the image's bounds"); | ||
return AVIF_FALSE; | ||
} | ||
|
||
if ((yuvFormat == AVIF_PIXEL_FORMAT_YUV420) || (yuvFormat == AVIF_PIXEL_FORMAT_YUV422)) { | ||
if ((cropRect->x % 2) != 0) { | ||
avifDiagnosticsPrintf(diag, "[Strict] crop rect X offset must be even due to this image's YUV subsampling"); | ||
return AVIF_FALSE; | ||
} | ||
} | ||
if (yuvFormat == AVIF_PIXEL_FORMAT_YUV420) { | ||
if ((cropRect->y % 2) != 0) { | ||
avifDiagnosticsPrintf(diag, "[Strict] crop rect Y offset must be even due to this image's YUV subsampling"); | ||
return AVIF_FALSE; | ||
} | ||
} | ||
return AVIF_TRUE; | ||
} | ||
|
||
avifBool avifCropRectConvertCleanApertureBox(avifCropRect * cropRect, | ||
const avifCleanApertureBox * clap, | ||
uint32_t imageW, | ||
uint32_t imageH, | ||
avifPixelFormat yuvFormat, | ||
avifDiagnostics * diag) | ||
avifBool avifCropRectFromCleanApertureBox(avifCropRect * cropRect, | ||
avifBool * upsampleBeforeCropping, | ||
const avifCleanApertureBox * clap, | ||
uint32_t imageW, | ||
uint32_t imageH, | ||
avifPixelFormat yuvFormat, | ||
avifDiagnostics * diag) | ||
{ | ||
avifDiagnosticsClearError(diag); | ||
|
||
|
@@ -722,6 +699,16 @@ avifBool avifCropRectConvertCleanApertureBox(avifCropRect * cropRect, | |
// positive or negative. For cleanApertureWidth and cleanApertureHeight, | ||
// N shall be positive and D shall be strictly positive. | ||
|
||
// ISO/IEC 23000-22:2024, Section 7.3.6.7: | ||
// The clean aperture property is restricted according to the chroma sampling format of the input image | ||
// (4:4:4, 4:2:2, 4:2:0, or 4:0:0) as follows: | ||
// - cleanApertureWidth and cleanApertureHeight shall be integers; | ||
// - If any of the following conditions hold true, the image is first implicitly upsampled to 4:4:4: | ||
// - chroma is subsampled horizontally (i.e., 4:2:2 and 4:2:0) and cleanApertureWidth is odd | ||
// - chroma is subsampled horizontally (i.e., 4:2:2 and 4:2:0) and left-most pixel is on an odd position | ||
// - chroma is subsampled vertically (i.e., 4:2:0) and cleanApertureHeight is odd | ||
// - chroma is subsampled vertically (i.e., 4:2:0) and topmost line is on an odd position | ||
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. For AVIF, the first and third conditions are too strict. They are equivalent to disallowing odd widths for 4:2:2 and 4:2:0 and disallowing odd heights for 4:2:0, but AV1 supports those two cases. In libavif we can consider ignoring the first and third conditions. |
||
|
||
const int32_t widthN = (int32_t)clap->widthN; | ||
const int32_t widthD = (int32_t)clap->widthD; | ||
const int32_t heightN = (int32_t)clap->heightN; | ||
|
@@ -810,7 +797,27 @@ avifBool avifCropRectConvertCleanApertureBox(avifCropRect * cropRect, | |
cropRect->y = (uint32_t)(cropY.n / cropY.d); | ||
cropRect->width = (uint32_t)clapW; | ||
cropRect->height = (uint32_t)clapH; | ||
return avifCropRectIsValid(cropRect, imageW, imageH, yuvFormat, diag); | ||
if (!avifCropRectIsValid(cropRect, imageW, imageH, diag)) { | ||
return AVIF_FALSE; | ||
} | ||
|
||
*upsampleBeforeCropping = ((yuvFormat == AVIF_PIXEL_FORMAT_YUV420 || yuvFormat == AVIF_PIXEL_FORMAT_YUV422) && | ||
(cropRect->width % 2 || cropRect->x % 2)) || | ||
(yuvFormat == AVIF_PIXEL_FORMAT_YUV420 && (cropRect->height % 2 || cropRect->y % 2)); | ||
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. An alternative design is to remove the Note that Another alternative is for libavif to upsample to 4:4:4 and crop automatically when necessary so that libavif users don't need to worry about this. But I am not sure if this is a good idea. 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.
The issue with this new function and with the current
I would lean towards that as a default behavior, and why not add an "ignoreClap" setting in |
||
return AVIF_TRUE; | ||
} | ||
|
||
avifBool avifCropRectConvertCleanApertureBox(avifCropRect * cropRect, | ||
const avifCleanApertureBox * clap, | ||
uint32_t imageW, | ||
uint32_t imageH, | ||
avifPixelFormat yuvFormat, | ||
avifDiagnostics * diag) | ||
{ | ||
// Keep the same pre-deprecation behavior. | ||
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. This does not keep the old behavior exactly. The difference is the first and third conditions at lines 706-710. So to be precise, the comment should say "most of the pre-deprecation behavior". If we ignore the first and third conditions as I suggested in my comment at line 710, then we keep the old behavior exactly. |
||
avifBool upsampleBeforeCropping; | ||
return avifCropRectFromCleanApertureBox(cropRect, &upsampleBeforeCropping, clap, imageW, imageH, yuvFormat, diag) && | ||
!upsampleBeforeCropping; | ||
} | ||
|
||
avifBool avifCleanApertureBoxConvertCropRect(avifCleanApertureBox * clap, | ||
|
@@ -820,9 +827,10 @@ avifBool avifCleanApertureBoxConvertCropRect(avifCleanApertureBox * clap, | |
avifPixelFormat yuvFormat, | ||
avifDiagnostics * diag) | ||
{ | ||
(void)yuvFormat; | ||
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. If we want to preserve the old behavior, we cannot ignore It would be useful to move lines 804-806 to a new function that takes |
||
avifDiagnosticsClearError(diag); | ||
|
||
if (!avifCropRectIsValid(cropRect, imageW, imageH, yuvFormat, diag)) { | ||
if (!avifCropRectIsValid(cropRect, imageW, imageH, diag)) { | ||
return AVIF_FALSE; | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is best to wait until ISO/IEC 23000-22:2024 is formally published. Its status is still Final Draft Internal Standard (FDIS) right now: https://www.iso.org/standard/87576.html