mirror of
https://chromium.googlesource.com/libyuv/libyuv
synced 2026-10-29 02:17:13 +08:00
Fix center coordinate when dst == 1 and src == 32768 in scale functions
In ScalePlane and ScalePlane_16, when dst_width == src_width and dst_height == 1 with src_height >= 32768, set y to (src_height << 15) - 32768 for bilinear filtering and src_height << 15 for point sampling so the center row is sampled instead of row 0. In ScaleSlope, when dst_width == 1 and Abs(src_width) >= 32768 (or dst_height == 1 and src_height >= 32768), compute the centered *x and *y coordinates directly instead of overwriting dst_width or dst_height, which previously sampled pixel/row 0 (or 0.5) and added (Abs(src_width) - 1) * *dx when horizontally mirroring src_width < 0. Use Abs(src_width) << 15 and src_height << 15 as the non-box step values so ScaleARGB and ScaleUV treat the 32768x downscale as an even scale factor rather than 1x. Save Abs(src_width) in a local variable. In ScaleAddCols1_16_C, shift x >>= 16 before indexing src_ptr[x], matching ScaleAddCols1_C. Bug: b:573815252 Test: libyuv_unittest --gtest_filter=*ScalePlaneOversizeHeight*:*ARGBScaleOversizeWidthTo1* Change-Id: Ic82319dae6291d17b98b056b5d64a4bbf02f7787
This commit is contained in:
parent
0b9e5c922d
commit
dd4ac91d3f
@ -917,6 +917,7 @@ static void ScaleAddCols1_16_C(int dst_width,
|
||||
int boxwidth = MIN1(dx >> 16);
|
||||
int scaleval = 65536 / (boxwidth * boxheight);
|
||||
int i;
|
||||
x >>= 16;
|
||||
for (i = 0; i < dst_width; ++i) {
|
||||
*dst_ptr++ = SumPixels_16(boxwidth, src_ptr + x) * scaleval >> 16;
|
||||
x += boxwidth;
|
||||
@ -2125,11 +2126,9 @@ int ScalePlane(const uint8_t* src,
|
||||
int dy = 0;
|
||||
int y = 0;
|
||||
// Check for 1 pixel and avoid FixedDiv overflow.
|
||||
// TODO(b/573815252): Fix center row calculation when dst_height == 1 and
|
||||
// src_height == 32768.
|
||||
if (dst_height == 1 && src_height >= 32768) {
|
||||
dy = FixedDiv(src_height, src_height);
|
||||
y = CENTERSTART(dy, -32768);
|
||||
dy = 1 << 16;
|
||||
y = filtering ? ((src_height << 15) - 32768) : (src_height << 15);
|
||||
} else if (dst_height <= src_height) {
|
||||
// When scaling down, use the center 2 rows to filter.
|
||||
dy = FixedDiv(src_height, dst_height);
|
||||
@ -2246,11 +2245,9 @@ int ScalePlane_16(const uint16_t* src,
|
||||
int dy = 0;
|
||||
int y = 0;
|
||||
// Check for 1 pixel and avoid FixedDiv overflow.
|
||||
// TODO(b/573815252): Fix center row calculation when dst_height == 1 and
|
||||
// src_height == 32768.
|
||||
if (dst_height == 1 && src_height >= 32768) {
|
||||
dy = FixedDiv(src_height, src_height);
|
||||
y = CENTERSTART(dy, -32768);
|
||||
dy = 1 << 16;
|
||||
y = filtering ? ((src_height << 15) - 32768) : (src_height << 15);
|
||||
} else if (dst_height <= src_height) {
|
||||
// When scaling down, use the center 2 rows to filter.
|
||||
dy = FixedDiv(src_height, dst_height);
|
||||
|
||||
@ -1639,31 +1639,41 @@ void ScaleSlope(int src_width,
|
||||
assert(src_height != 0);
|
||||
assert(dst_width > 0);
|
||||
assert(dst_height > 0);
|
||||
// Check for 1 pixel and avoid FixedDiv overflow.
|
||||
// TODO(b/573815252): Fix center coordinate calculation when dst == 1 and
|
||||
// src == 32768.
|
||||
if (dst_width == 1 && Abs(src_width) >= 32768) {
|
||||
dst_width = Abs(src_width);
|
||||
}
|
||||
if (dst_height == 1 && src_height >= 32768) {
|
||||
dst_height = src_height;
|
||||
}
|
||||
const int abs_src_width = Abs(src_width);
|
||||
if (filtering == kFilterBox) {
|
||||
// Scale step for point sampling duplicates all pixels equally.
|
||||
*dx = FixedDiv(Abs(src_width), dst_width);
|
||||
*dy = FixedDiv(src_height, dst_height);
|
||||
*x = 0;
|
||||
*y = 0;
|
||||
} else if (filtering == kFilterBilinear) {
|
||||
// Scale step for bilinear sampling renders last pixel once for upsample.
|
||||
if (dst_width <= Abs(src_width)) {
|
||||
*dx = FixedDiv(Abs(src_width), dst_width);
|
||||
*x = CENTERSTART(*dx, -32768); // Subtract 0.5 (32768) to center filter.
|
||||
} else if (src_width > 1 && dst_width > 1) {
|
||||
*dx = FixedDiv1(Abs(src_width), dst_width);
|
||||
if (dst_width == 1 && abs_src_width >= 32768) {
|
||||
// Avoid overflowing 32-bit signed int in FixedDiv(32768, 1) and box
|
||||
// filter accumulation in row16.
|
||||
*dx = 1 << 16;
|
||||
*x = abs_src_width << 15;
|
||||
} else {
|
||||
*dx = FixedDiv(abs_src_width, dst_width);
|
||||
*x = 0;
|
||||
}
|
||||
if (dst_height <= src_height) {
|
||||
if (dst_height == 1 && src_height >= 32768) {
|
||||
*dy = 1 << 16;
|
||||
*y = src_height << 15;
|
||||
} else {
|
||||
*dy = FixedDiv(src_height, dst_height);
|
||||
*y = 0;
|
||||
}
|
||||
} else if (filtering == kFilterBilinear) {
|
||||
// Scale step for bilinear sampling renders last pixel once for upsample.
|
||||
if (dst_width == 1 && abs_src_width >= 32768) {
|
||||
*dx = abs_src_width << 15;
|
||||
*x = (abs_src_width << 15) - 32768;
|
||||
} else if (dst_width <= abs_src_width) {
|
||||
*dx = FixedDiv(abs_src_width, dst_width);
|
||||
*x = CENTERSTART(*dx, -32768); // Subtract 0.5 (32768) to center filter.
|
||||
} else if (src_width > 1 && dst_width > 1) {
|
||||
*dx = FixedDiv1(abs_src_width, dst_width);
|
||||
*x = 0;
|
||||
}
|
||||
if (dst_height == 1 && src_height >= 32768) {
|
||||
*dy = src_height << 15;
|
||||
*y = (src_height << 15) - 32768;
|
||||
} else if (dst_height <= src_height) {
|
||||
*dy = FixedDiv(src_height, dst_height);
|
||||
*y = CENTERSTART(*dy, -32768); // Subtract 0.5 (32768) to center filter.
|
||||
} else if (src_height > 1 && dst_height > 1) {
|
||||
@ -1672,21 +1682,39 @@ void ScaleSlope(int src_width,
|
||||
}
|
||||
} else if (filtering == kFilterLinear) {
|
||||
// Scale step for bilinear sampling renders last pixel once for upsample.
|
||||
if (dst_width <= Abs(src_width)) {
|
||||
*dx = FixedDiv(Abs(src_width), dst_width);
|
||||
if (dst_width == 1 && abs_src_width >= 32768) {
|
||||
*dx = abs_src_width << 15;
|
||||
*x = (abs_src_width << 15) - 32768;
|
||||
} else if (dst_width <= abs_src_width) {
|
||||
*dx = FixedDiv(abs_src_width, dst_width);
|
||||
*x = CENTERSTART(*dx, -32768); // Subtract 0.5 (32768) to center filter.
|
||||
} else if (src_width > 1 && dst_width > 1) {
|
||||
*dx = FixedDiv1(Abs(src_width), dst_width);
|
||||
*dx = FixedDiv1(abs_src_width, dst_width);
|
||||
*x = 0;
|
||||
}
|
||||
*dy = FixedDiv(src_height, dst_height);
|
||||
*y = *dy >> 1;
|
||||
if (dst_height == 1 && src_height >= 32768) {
|
||||
*dy = src_height << 15;
|
||||
*y = src_height << 15;
|
||||
} else {
|
||||
*dy = FixedDiv(src_height, dst_height);
|
||||
*y = *dy >> 1;
|
||||
}
|
||||
} else {
|
||||
// Scale step for point sampling duplicates all pixels equally.
|
||||
*dx = FixedDiv(Abs(src_width), dst_width);
|
||||
*dy = FixedDiv(src_height, dst_height);
|
||||
*x = CENTERSTART(*dx, 0);
|
||||
*y = CENTERSTART(*dy, 0);
|
||||
if (dst_width == 1 && abs_src_width >= 32768) {
|
||||
*dx = abs_src_width << 15;
|
||||
*x = abs_src_width << 15;
|
||||
} else {
|
||||
*dx = FixedDiv(abs_src_width, dst_width);
|
||||
*x = CENTERSTART(*dx, 0);
|
||||
}
|
||||
if (dst_height == 1 && src_height >= 32768) {
|
||||
*dy = src_height << 15;
|
||||
*y = src_height << 15;
|
||||
} else {
|
||||
*dy = FixedDiv(src_height, dst_height);
|
||||
*y = CENTERSTART(*dy, 0);
|
||||
}
|
||||
}
|
||||
// Negative src_width means horizontally mirror.
|
||||
if (src_width < 0) {
|
||||
|
||||
@ -653,6 +653,34 @@ TEST_F(LibYUVScaleTest, ARGBScaleDimensionOverflow) {
|
||||
kFilterNone));
|
||||
}
|
||||
|
||||
TEST_F(LibYUVScaleTest, ARGBScaleOversizeWidthTo1) {
|
||||
const int kSrcWidth = 32768;
|
||||
const int kSrcHeight = 2;
|
||||
uint8_t* src = new uint8_t[kSrcWidth * kSrcHeight * 4];
|
||||
memset(src, 0, kSrcWidth * kSrcHeight * 4);
|
||||
for (int y = 0; y < kSrcHeight; ++y) {
|
||||
memset(src + (y * kSrcWidth + 16383) * 4, 100, 4);
|
||||
memset(src + (y * kSrcWidth + 16384) * 4, 200, 4);
|
||||
}
|
||||
uint8_t dst[2 * 4] = {};
|
||||
|
||||
for (int sign : {1, -1}) {
|
||||
for (int dst_h : {1, 2}) {
|
||||
for (FilterMode f :
|
||||
{kFilterNone, kFilterLinear, kFilterBilinear, kFilterBox}) {
|
||||
EXPECT_EQ(0, ARGBScale(src, kSrcWidth * 4, sign * kSrcWidth, kSrcHeight,
|
||||
dst, 4, 1, dst_h, f));
|
||||
if (f == kFilterNone) {
|
||||
EXPECT_EQ(200, dst[0]);
|
||||
} else {
|
||||
EXPECT_NEAR(150, dst[0], 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
delete[] src;
|
||||
}
|
||||
|
||||
#if defined(__LP64__) || defined(_WIN64)
|
||||
TEST_F(LibYUVScaleTest, ARGBScaleLargeImageOver2GB) {
|
||||
const int kSrcWidth = 4;
|
||||
|
||||
@ -811,20 +811,61 @@ TEST_F(LibYUVScaleTest, ScalePlaneOversizeHeight) {
|
||||
const int kSrcHeight = 32768;
|
||||
uint8_t* src = new uint8_t[kSrcWidth * kSrcHeight];
|
||||
memset(src, 0, kSrcWidth * kSrcHeight);
|
||||
memset(src + 16383 * kSrcWidth, 100, kSrcWidth);
|
||||
memset(src + 16384 * kSrcWidth, 200, kSrcWidth);
|
||||
uint8_t dst[4 * 2] = {};
|
||||
|
||||
for (int dst_w : {4, 2}) {
|
||||
for (int dst_w : {4, 2, 1}) {
|
||||
for (int dst_h : {1, 2}) {
|
||||
for (FilterMode f :
|
||||
{kFilterNone, kFilterLinear, kFilterBilinear, kFilterBox}) {
|
||||
EXPECT_EQ(0, ScalePlane(src, kSrcWidth, kSrcWidth, kSrcHeight, dst,
|
||||
dst_w, dst_w, dst_h, f));
|
||||
if (dst_h == 1) {
|
||||
const uint8_t expected =
|
||||
(f == kFilterBilinear || (f == kFilterBox && dst_w >= 2)) ? 150
|
||||
: 200;
|
||||
EXPECT_EQ(expected, dst[0]);
|
||||
}
|
||||
EXPECT_EQ(0, ScalePlane(src, kSrcWidth, kSrcWidth, -kSrcHeight, dst,
|
||||
dst_w, dst_w, dst_h, f));
|
||||
if (dst_h == 1) {
|
||||
const uint8_t expected =
|
||||
(f == kFilterBilinear || (f == kFilterBox && dst_w >= 2)) ? 150
|
||||
: 100;
|
||||
EXPECT_EQ(expected, dst[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
delete[] src;
|
||||
|
||||
uint16_t* src16 = new uint16_t[kSrcWidth * kSrcHeight];
|
||||
memset(src16, 0, kSrcWidth * kSrcHeight * sizeof(uint16_t));
|
||||
for (int x = 0; x < kSrcWidth; ++x) {
|
||||
src16[16383 * kSrcWidth + x] = 1000;
|
||||
src16[16384 * kSrcWidth + x] = 2000;
|
||||
}
|
||||
uint16_t dst16[4] = {};
|
||||
for (int dst_w : {4, 2, 1}) {
|
||||
for (FilterMode f :
|
||||
{kFilterNone, kFilterLinear, kFilterBilinear, kFilterBox}) {
|
||||
EXPECT_EQ(0, ScalePlane_16(src16, kSrcWidth, kSrcWidth, kSrcHeight, dst16,
|
||||
dst_w, dst_w, 1, f));
|
||||
const uint16_t expected =
|
||||
(f == kFilterBilinear || (f == kFilterBox && dst_w >= 2)) ? 1500
|
||||
: 2000;
|
||||
EXPECT_EQ(expected, dst16[0]);
|
||||
}
|
||||
}
|
||||
// Test ScalePlane_16 horizontal 32768 -> 1 box filter (ScaleAddCols1_16_C).
|
||||
for (int y = 0; y < kSrcWidth; ++y) {
|
||||
src16[y * kSrcHeight + 16384] = 3000;
|
||||
}
|
||||
EXPECT_EQ(0, ScalePlane_16(src16, kSrcHeight, kSrcHeight, kSrcWidth, dst16, 1,
|
||||
1, 1, kFilterBox));
|
||||
EXPECT_EQ(3000, dst16[0]);
|
||||
delete[] src16;
|
||||
}
|
||||
|
||||
TEST_F(LibYUVScaleTest, ScalePlaneBoxMaxSrcHeight) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user