This is an automated email from the git hooks/post-receive script.
git pushed a commit to branch master
in repository legacy-imlib2.
View the commit online.
commit 42ec80f0700f794ec0bff13d841fb29939515a59
Author: Chema Gonzalez <che...@meta.com>
AuthorDate: Sun Jun 1 19:40:50 2025 -0700
Y4M loader: fix support for odd dimensions
Y4M adds an extra line for chromas when a file has an odd dimension. For
example, a 9x9 4:2:0 file has 81 pixels for luma, and 25 pixels for each
of the chromas (5 values for each of the 5 subsampled rows). Older code
was only reading 16 pixels (4x4), which caused the Cb chroma to be shifted,
and not enough pixels to be read.
Added a 9x9 y4m example, where the last column has a different chroma.
---
src/modules/loaders/loader_y4m.c | 118 +++++++++++++++----------------------
test/images/img-9x9.full_range.y4m | Bin 0 -> 189 bytes
2 files changed, 46 insertions(+), 72 deletions(-)
diff --git a/src/modules/loaders/loader_y4m.c b/src/modules/loaders/loader_y4m.c
index 2250054..9e7bd78 100644
--- a/src/modules/loaders/loader_y4m.c
+++ b/src/modules/loaders/loader_y4m.c
@@ -317,7 +317,7 @@ y4m_parse_init(Y4mParse *res, const void *buffer, ptrdiff_t size)
Y4M_PARSE_API enum Y4mParseStatus
y4m_parse_frame(Y4mParse *res)
{
- ptrdiff_t npixels, sdiv, voff;
+ ptrdiff_t ypixels, cpixels, cstride_pixels, voff;
const uint8_t *p = res->p, *end = res->end;
Y4M_PARSE_ASSERT(p <= end);
@@ -337,54 +337,57 @@ y4m_parse_frame(Y4mParse *res)
++p; /* skip '\n' */
res->frame_data = p;
- npixels = res->w * res->h;
+ ypixels = res->w * res->h;
switch (res->colour_space)
{
case Y4M_PARSE_CS_420JPEG:
case Y4M_PARSE_CS_420MPEG2:
case Y4M_PARSE_CS_420PALDV:
case Y4M_PARSE_CS_420:
- res->frame_data_len = npixels * 3 / 2;
- sdiv = 2;
- voff = (npixels * 5) / 4;
+ cpixels = ((res->w + 1) / 2) * ((res->h + 1) / 2);
+ res->frame_data_len = ypixels + 2 * cpixels;
+ cstride_pixels = ((res->w + 1) / 2);
break;
case Y4M_PARSE_CS_420P10:
- res->frame_data_len = npixels * 3;
- sdiv = 2;
- voff = (npixels * 5) / 4;
+ cpixels = ((res->w + 1) / 2) * ((res->h + 1) / 2);
+ res->frame_data_len = 2 * (ypixels + 2 * cpixels);
+ cstride_pixels = ((res->w + 1) / 2);
break;
case Y4M_PARSE_CS_422:
- res->frame_data_len = npixels * 2;
- sdiv = 2;
- voff = (npixels * 3) / 2;
+ cpixels = ((res->w + 1) / 2) * res->h;
+ res->frame_data_len = ypixels + 2 * cpixels;
+ cstride_pixels = ((res->w + 1) / 2);
break;
case Y4M_PARSE_CS_422P10:
- res->frame_data_len = npixels * 2 * 2;
- sdiv = 2;
- voff = (npixels * 3) / 2;
+ cpixels = ((res->w + 1) / 2) * res->h;
+ res->frame_data_len = 2 * (ypixels + 2 * cpixels);
+ cstride_pixels = ((res->w + 1) / 2);
break;
case Y4M_PARSE_CS_444:
- res->frame_data_len = npixels * 3;
- sdiv = 1;
- voff = npixels * 2;
+ cpixels = ypixels;
+ res->frame_data_len = ypixels + 2 * cpixels;
+ cstride_pixels = res->w;
break;
case Y4M_PARSE_CS_444P10:
- res->frame_data_len = npixels * 3 * 2;
- sdiv = 1;
- voff = npixels * 2;
+ cpixels = ypixels;
+ res->frame_data_len = 2 * (ypixels + 2 * cpixels);
+ cstride_pixels = res->w;
break;
case Y4M_PARSE_CS_MONO10:
- res->frame_data_len = npixels * 2;
- sdiv = voff = 0; // silence bogus compiler warning
+ cpixels = 0;
+ res->frame_data_len = ypixels * 2;
+ cstride_pixels = 0; // silence bogus compiler warning
break;
case Y4M_PARSE_CS_MONO:
- res->frame_data_len = npixels;
- sdiv = voff = 0; // silence bogus compiler warning
+ cpixels = 0;
+ res->frame_data_len = ypixels;
+ cstride_pixels = 0; // silence bogus compiler warning
break;
default:
return Y4M_PARSE_UNSUPPORTED;
break;
}
+ voff = ypixels + cpixels;
if (end - p < res->frame_data_len)
{
return Y4M_PARSE_CORRUPTED;
@@ -402,15 +405,15 @@ y4m_parse_frame(Y4mParse *res)
{
if (res->depth == 10)
{
- res->u = p + npixels * 2;
+ res->u = p + ypixels * 2;
res->v = p + voff * 2;
}
else
{
- res->u = p + npixels;
+ res->u = p + ypixels;
res->v = p + voff;
}
- res->u_stride = res->v_stride = res->w / sdiv;
+ res->u_stride = res->v_stride = cstride_pixels;
}
res->p = p + res->frame_data_len; /* advance to next potential frame */
@@ -555,69 +558,40 @@ _load(ImlibImage *im, int load_data)
/* convert y4m (10-bit YUV) to 8-bit YUV (same subsampling) */
/* 1. allocate a small buffer to convert image data to 8-bit */
- size_t buf_size = 0;
+ int ypixels = y4m.w * y4m.h;
+ int cpixels = 0;
+ int cstride_pixels = 0;
if (y4m.colour_space == Y4M_PARSE_CS_420P10)
{
- buf_size = (y4m.w * y4m.h * 3) >> 1;
+ cpixels = ((y4m.w + 1) / 2) * ((y4m.h + 1) / 2);
+ cstride_pixels = ((y4m.w + 1) / 2);
}
else if (y4m.colour_space == Y4M_PARSE_CS_422P10)
{
- buf_size = (y4m.w * y4m.h * 2);
+ cpixels = ((y4m.w + 1) / 2) * y4m.h;
+ cstride_pixels = ((y4m.w + 1) / 2);
}
else if (y4m.colour_space == Y4M_PARSE_CS_444P10)
{
- buf_size = (y4m.w * y4m.h * 3);
+ cpixels = ypixels;
+ cstride_pixels = y4m.w;
}
else if (y4m.colour_space == Y4M_PARSE_CS_MONO10)
{
- buf_size = y4m.w * y4m.h;
+ cpixels = 0;
+ cstride_pixels = 0;
}
+ size_t buf_size = ypixels + 2 * cpixels;
uint8_t *buf = calloc((buf_size), sizeof(uint8_t));
if (!buf)
return LOAD_OOM;
uint8_t *buf_y = buf;
- int npixels = y4m.w * y4m.h;
- uint8_t *buf_u = buf + npixels;
- int voff = 0;
- if (y4m.colour_space == Y4M_PARSE_CS_420P10)
- {
- voff = (npixels * 5) / 4;
- }
- else if (y4m.colour_space == Y4M_PARSE_CS_422P10)
- {
- voff = (npixels * 3) / 2;
- }
- else if (y4m.colour_space == Y4M_PARSE_CS_444P10)
- {
- voff = npixels * 2;
- }
- else if (y4m.colour_space == Y4M_PARSE_CS_MONO10)
- {
- voff = 0;
- }
- uint8_t *buf_v = buf + voff;
+ uint8_t *buf_u = buf + ypixels;
+ uint8_t *buf_v = buf + ypixels + cpixels;
int buf_stride_y = y4m.w;
- ptrdiff_t buf_stride_u;
- ptrdiff_t buf_stride_v;
- int sdiv = 0;
- if (y4m.colour_space == Y4M_PARSE_CS_420P10)
- {
- sdiv = 2;
- }
- else if (y4m.colour_space == Y4M_PARSE_CS_422P10)
- {
- sdiv = 2;
- }
- else if (y4m.colour_space == Y4M_PARSE_CS_444P10)
- {
- sdiv = 1;
- }
- else if (y4m.colour_space == Y4M_PARSE_CS_MONO10)
- {
- sdiv = 1;
- }
- buf_stride_u = buf_stride_v = y4m.w / sdiv;
+ ptrdiff_t buf_stride_u = cstride_pixels;
+ ptrdiff_t buf_stride_v = cstride_pixels;
/* 2. run the color conversion */
if (y4m.colour_space == Y4M_PARSE_CS_420P10)
diff --git a/test/images/img-9x9.full_range.y4m b/test/images/img-9x9.full_range.y4m
new file mode 100644
index 0000000..c93bab1
Binary files /dev/null and b/test/images/img-9x9.full_range.y4m differ
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.