diff --git a/README.chromium b/README.chromium index cfdf86468..578446ba4 100644 --- a/README.chromium +++ b/README.chromium @@ -1,6 +1,6 @@ Name: libyuv URL: http://code.google.com/p/libyuv/ -Version: 289 +Version: 290 License: BSD License File: LICENSE diff --git a/include/libyuv/version.h b/include/libyuv/version.h index edf8f70b8..abf00a12c 100644 --- a/include/libyuv/version.h +++ b/include/libyuv/version.h @@ -11,7 +11,7 @@ #ifndef INCLUDE_LIBYUV_VERSION_H_ #define INCLUDE_LIBYUV_VERSION_H_ -#define LIBYUV_VERSION 289 +#define LIBYUV_VERSION 290 #endif // INCLUDE_LIBYUV_VERSION_H_ diff --git a/source/scale.cc b/source/scale.cc index e57e6590a..5dfd05c23 100644 --- a/source/scale.cc +++ b/source/scale.cc @@ -3361,6 +3361,8 @@ void ScalePlane(const uint8* src, int src_stride, // Scale an I420 image. // This function in turn calls a scaling function for each plane. +#define UNDER_ALLOCATED_HACK 1 + int I420Scale(const uint8* src_y, int src_stride_y, const uint8* src_u, int src_stride_u, const uint8* src_v, int src_stride_v, @@ -3390,6 +3392,28 @@ int I420Scale(const uint8* src_y, int src_stride_y, int dst_halfwidth = (dst_width + 1) >> 1; int dst_halfheight = (dst_height + 1) >> 1; +#ifdef UNDER_ALLOCATED_HACK + // If caller passed width / 2 for stride, adjust halfwidth to match. + if ((src_width & 1) && src_stride_u && src_halfwidth > abs(src_stride_u)) { + src_halfwidth = src_width >> 1; + } + if ((dst_width & 1) && dst_stride_u && dst_halfwidth > abs(dst_stride_u)) { + dst_halfwidth = dst_width >> 1; + } + // If caller used height / 2 when computing src_v, it will point into what + // should be the src_u plane. Detect this and reduce halfheight to match. + int uv_src_plane_size = src_halfwidth * src_halfheight; + if ((src_height & 1) && + (src_v > src_u) && (src_v < (src_u + uv_src_plane_size))) { + src_halfheight = src_height >> 1; + } + int uv_dst_plane_size = dst_halfwidth * dst_halfheight; + if ((dst_height & 1) && + (dst_v > dst_u) && (dst_v < (dst_u + uv_dst_plane_size))) { + dst_halfheight = dst_height >> 1; + } +#endif + ScalePlane(src_y, src_stride_y, src_width, src_height, dst_y, dst_stride_y, dst_width, dst_height, filtering); @@ -3431,6 +3455,28 @@ int Scale(const uint8* src_y, const uint8* src_u, const uint8* src_v, int dst_halfheight = (dst_height + 1) >> 1; FilterMode filtering = interpolate ? kFilterBox : kFilterNone; +#ifdef UNDER_ALLOCATED_HACK + // If caller passed width / 2 for stride, adjust halfwidth to match. + if ((src_width & 1) && src_stride_u && src_halfwidth > abs(src_stride_u)) { + src_halfwidth = src_width >> 1; + } + if ((dst_width & 1) && dst_stride_u && dst_halfwidth > abs(dst_stride_u)) { + dst_halfwidth = dst_width >> 1; + } + // If caller used height / 2 when computing src_v, it will point into what + // should be the src_u plane. Detect this and reduce halfheight to match. + int uv_src_plane_size = src_halfwidth * src_halfheight; + if ((src_height & 1) && + (src_v > src_u) && (src_v < (src_u + uv_src_plane_size))) { + src_halfheight = src_height >> 1; + } + int uv_dst_plane_size = dst_halfwidth * dst_halfheight; + if ((dst_height & 1) && + (dst_v > dst_u) && (dst_v < (dst_u + uv_dst_plane_size))) { + dst_halfheight = dst_height >> 1; + } +#endif + ScalePlane(src_y, src_stride_y, src_width, src_height, dst_y, dst_stride_y, dst_width, dst_height, filtering); diff --git a/unit_test/scale_argb_test.cc b/unit_test/scale_argb_test.cc index 08103ca87..29e1c4cb9 100644 --- a/unit_test/scale_argb_test.cc +++ b/unit_test/scale_argb_test.cc @@ -18,17 +18,17 @@ namespace libyuv { static int ARGBTestFilter(int src_width, int src_height, - int dst_width, int dst_height, - FilterMode f) { + int dst_width, int dst_height, + FilterMode f) { const int b = 128; - int src_argb_plane_size = (src_width + (2 * b)) * (src_height + (2 * b)) * 4; - int src_stride_argb = (2 * b + src_width) * 4; + int src_argb_plane_size = (src_width + b * 2) * (src_height + b * 2) * 4; + int src_stride_argb = (b * 2 + src_width) * 4; align_buffer_16(src_argb, src_argb_plane_size) memset(src_argb, 1, src_argb_plane_size); - int dst_argb_plane_size = (dst_width + (2 * b)) * (dst_height + (2 * b)) * 4; - int dst_stride_argb = (2 * b + dst_width) * 4; + int dst_argb_plane_size = (dst_width + b * 2) * (dst_height + b * 2) * 4; + int dst_stride_argb = (b * 2 + dst_width) * 4; srandom(time(NULL)); @@ -213,4 +213,18 @@ TEST_F(libyuvTest, ARGBScaleTo1366) { } } +TEST_F(libyuvTest, ARGBScaleTo853) { + int src_width = 1280; + int src_height = 720; + int dst_width = 853; + int dst_height = 480; + + for (int f = 0; f < 2; ++f) { + int err = ARGBTestFilter(src_width, src_height, + dst_width, dst_height, + static_cast(f)); + EXPECT_GE(1, err); + } +} + } // namespace libyuv diff --git a/unit_test/scale_test.cc b/unit_test/scale_test.cc index 4701c1e1a..0f9c98101 100644 --- a/unit_test/scale_test.cc +++ b/unit_test/scale_test.cc @@ -19,29 +19,29 @@ namespace libyuv { static int TestFilter(int src_width, int src_height, int dst_width, int dst_height, - FilterMode f) { - const int b = 128; - int src_width_uv = (src_width + 1) >> 1; - int src_height_uv = (src_height + 1) >> 1; + FilterMode f, int rounding) { + const int b = 128 * rounding; + int src_width_uv = (src_width + rounding) >> 1; + int src_height_uv = (src_height + rounding) >> 1; - int src_y_plane_size = (src_width + (2 * b)) * (src_height + (2 * b)); - int src_uv_plane_size = (src_width_uv + (2 * b)) * (src_height_uv + (2 * b)); + int src_y_plane_size = (src_width + b * 2) * (src_height + b * 2); + int src_uv_plane_size = (src_width_uv + b * 2) * (src_height_uv + b * 2); - int src_stride_y = 2 * b + src_width; - int src_stride_uv = 2 * b + src_width_uv; + int src_stride_y = b * 2 + src_width; + int src_stride_uv = b * 2 + src_width_uv; - align_buffer_16(src_y, src_y_plane_size) - align_buffer_16(src_u, src_uv_plane_size) - align_buffer_16(src_v, src_uv_plane_size) + align_buffer_page_end(src_y, src_y_plane_size) + align_buffer_page_end(src_u, src_uv_plane_size) + align_buffer_page_end(src_v, src_uv_plane_size) - int dst_width_uv = (dst_width + 1) >> 1; - int dst_height_uv = (dst_height + 1) >> 1; + int dst_width_uv = (dst_width + rounding) >> 1; + int dst_height_uv = (dst_height + rounding) >> 1; - int dst_y_plane_size = (dst_width + (2 * b)) * (dst_height + (2 * b)); - int dst_uv_plane_size = (dst_width_uv + (2 * b)) * (dst_height_uv + (2 * b)); + int dst_y_plane_size = (dst_width + b * 2) * (dst_height + b * 2); + int dst_uv_plane_size = (dst_width_uv + b * 2) * (dst_height_uv + b * 2); - int dst_stride_y = 2 * b + dst_width; - int dst_stride_uv = 2 * b + dst_width_uv; + int dst_stride_y = b * 2 + dst_width; + int dst_stride_uv = b * 2 + dst_width_uv; srandom(time(NULL)); @@ -60,12 +60,12 @@ static int TestFilter(int src_width, int src_height, } const int runs = 1000; - align_buffer_16(dst_y_c, dst_y_plane_size) - align_buffer_16(dst_u_c, dst_uv_plane_size) - align_buffer_16(dst_v_c, dst_uv_plane_size) - align_buffer_16(dst_y_opt, dst_y_plane_size) - align_buffer_16(dst_u_opt, dst_uv_plane_size) - align_buffer_16(dst_v_opt, dst_uv_plane_size) + align_buffer_page_end(dst_y_c, dst_y_plane_size) + align_buffer_page_end(dst_u_c, dst_uv_plane_size) + align_buffer_page_end(dst_v_c, dst_uv_plane_size) + align_buffer_page_end(dst_y_opt, dst_y_plane_size) + align_buffer_page_end(dst_u_opt, dst_uv_plane_size) + align_buffer_page_end(dst_v_opt, dst_uv_plane_size) // Warm up both versions for consistent benchmarks. MaskCpuFlags(0); // Disable all CPU optimization. @@ -149,16 +149,16 @@ static int TestFilter(int src_width, int src_height, } } - free_aligned_buffer_16(dst_y_c) - free_aligned_buffer_16(dst_u_c) - free_aligned_buffer_16(dst_v_c) - free_aligned_buffer_16(dst_y_opt) - free_aligned_buffer_16(dst_u_opt) - free_aligned_buffer_16(dst_v_opt) + free_aligned_buffer_page_end(dst_y_c) + free_aligned_buffer_page_end(dst_u_c) + free_aligned_buffer_page_end(dst_v_c) + free_aligned_buffer_page_end(dst_y_opt) + free_aligned_buffer_page_end(dst_u_opt) + free_aligned_buffer_page_end(dst_v_opt) - free_aligned_buffer_16(src_y) - free_aligned_buffer_16(src_u) - free_aligned_buffer_16(src_v) + free_aligned_buffer_page_end(src_y) + free_aligned_buffer_page_end(src_u) + free_aligned_buffer_page_end(src_v) return max_diff; } @@ -172,7 +172,7 @@ TEST_F(libyuvTest, ScaleDownBy2) { for (int f = 0; f < 3; ++f) { int err = TestFilter(src_width, src_height, dst_width, dst_height, - static_cast(f)); + static_cast(f), 1); EXPECT_GE(1, err); } } @@ -186,7 +186,7 @@ TEST_F(libyuvTest, ScaleDownBy4) { for (int f = 0; f < 3; ++f) { int err = TestFilter(src_width, src_height, dst_width, dst_height, - static_cast(f)); + static_cast(f), 1); EXPECT_GE(2, err); // This is the only scale factor with error of 2. } } @@ -200,7 +200,7 @@ TEST_F(libyuvTest, ScaleDownBy5) { for (int f = 0; f < 3; ++f) { int err = TestFilter(src_width, src_height, dst_width, dst_height, - static_cast(f)); + static_cast(f), 1); EXPECT_GE(1, err); } } @@ -214,7 +214,7 @@ TEST_F(libyuvTest, ScaleDownBy8) { for (int f = 0; f < 3; ++f) { int err = TestFilter(src_width, src_height, dst_width, dst_height, - static_cast(f)); + static_cast(f), 1); EXPECT_GE(1, err); } } @@ -228,7 +228,7 @@ TEST_F(libyuvTest, ScaleDownBy16) { for (int f = 0; f < 3; ++f) { int err = TestFilter(src_width, src_height, dst_width, dst_height, - static_cast(f)); + static_cast(f), 1); EXPECT_GE(1, err); } } @@ -242,7 +242,7 @@ TEST_F(libyuvTest, ScaleDownBy34) { for (int f = 0; f < 3; ++f) { int err = TestFilter(src_width, src_height, dst_width, dst_height, - static_cast(f)); + static_cast(f), 1); EXPECT_GE(1, err); } } @@ -256,7 +256,7 @@ TEST_F(libyuvTest, ScaleDownBy38) { for (int f = 0; f < 3; ++f) { int err = TestFilter(src_width, src_height, dst_width, dst_height, - static_cast(f)); + static_cast(f), 1); EXPECT_GE(1, err); } } @@ -270,7 +270,35 @@ TEST_F(libyuvTest, ScaleTo1366) { for (int f = 0; f < 3; ++f) { int err = TestFilter(src_width, src_height, dst_width, dst_height, - static_cast(f)); + static_cast(f), 1); + EXPECT_GE(1, err); + } +} + +TEST_F(libyuvTest, ScaleTo853) { + int src_width = 1280; + int src_height = 720; + int dst_width = 853; + int dst_height = 480; + + for (int f = 0; f < 3; ++f) { + int err = TestFilter(src_width, src_height, + dst_width, dst_height, + static_cast(f), 1); + EXPECT_GE(1, err); + } +} + +TEST_F(libyuvTest, ScaleTo853Wrong) { + int src_width = 1280; + int src_height = 720; + int dst_width = 853; + int dst_height = 480; + + for (int f = 0; f < 3; ++f) { + int err = TestFilter(src_width, src_height, + dst_width, dst_height, + static_cast(f), 0); EXPECT_GE(1, err); } } diff --git a/unit_test/unit_test.h b/unit_test/unit_test.h index 8d6eb1ff5..1d072e44a 100644 --- a/unit_test/unit_test.h +++ b/unit_test/unit_test.h @@ -29,7 +29,7 @@ uint8* var; \ uint8* var##_mem; \ var##_mem = reinterpret_cast(malloc(((size) + 4095) & ~4095)); \ - var = var##_mem + (-(size) & 4095) + var = var##_mem + (-(size) & 4095); #define free_aligned_buffer_page_end(var) \ free(var##_mem); \