From ef888b7dba20bb4988e18b716be8bebc675bf825 Mon Sep 17 00:00:00 2001 From: "fbarchard@google.com" Date: Mon, 6 May 2013 17:48:25 +0000 Subject: [PATCH] ARGBScale accept negative width for scaling to indicate mirror horizontally. BUG=220 TEST=convert util and ARGBScale unittests with set LIBYUV_WIDTH=-1280 Review URL: https://webrtc-codereview.appspot.com/1409005 git-svn-id: http://libyuv.googlecode.com/svn/trunk@685 16f28f9a-4ce2-e073-06de-1de4eb20be90 --- README.chromium | 2 +- include/libyuv/version.h | 2 +- source/scale_argb.cc | 81 +++++++++++++++++++++++++++--------- unit_test/scale_argb_test.cc | 76 +++++++++++++++++---------------- 4 files changed, 103 insertions(+), 58 deletions(-) diff --git a/README.chromium b/README.chromium index b826c3156..8dd8b37cf 100644 --- a/README.chromium +++ b/README.chromium @@ -1,6 +1,6 @@ Name: libyuv URL: http://code.google.com/p/libyuv/ -Version: 684 +Version: 685 License: BSD License File: LICENSE diff --git a/include/libyuv/version.h b/include/libyuv/version.h index eba9810c3..2e4b04a17 100644 --- a/include/libyuv/version.h +++ b/include/libyuv/version.h @@ -11,6 +11,6 @@ #ifndef INCLUDE_LIBYUV_VERSION_H_ // NOLINT #define INCLUDE_LIBYUV_VERSION_H_ -#define LIBYUV_VERSION 684 +#define LIBYUV_VERSION 685 #endif // INCLUDE_LIBYUV_VERSION_H_ NOLINT diff --git a/source/scale_argb.cc b/source/scale_argb.cc index 2103f898f..dd8188c3a 100644 --- a/source/scale_argb.cc +++ b/source/scale_argb.cc @@ -23,6 +23,10 @@ namespace libyuv { extern "C" { #endif +static __inline int Abs(int v) { + return v >= 0 ? v : -v; +} + // ARGB scaling uses bilinear or point, but not box filter. #if !defined(LIBYUV_DISABLE_NEON) && \ (defined(__ARM_NEON__) || defined(LIBYUV_NEON)) @@ -794,7 +798,13 @@ static void ScaleARGBDownEven(int src_width, int src_height, // Adjust to point to center of box. int row_step = src_height / dst_height; int row_stride = row_step * src_stride; - src_argb += ((row_step >> 1) - 1) * src_stride + ((src_step >> 1) - 1) * 4; + src_argb += ((row_step >> 1) - 1) * src_stride + + ((Abs(src_step) >> 1) - 1) * 4; + // Negative src_width means horizontally mirror. + if (src_width < 0) { + src_argb += -src_step * (dst_width - 1) * 4; + } + for (int y = 0; y < dst_height; ++y) { ScaleARGBRowDownEven(src_argb, src_stride, src_step, dst_argb, dst_width); src_argb += row_stride; @@ -810,15 +820,15 @@ static void ScaleARGBBilinearDown(int src_width, int src_height, const uint8* src_argb, uint8* dst_argb) { assert(dst_width > 0); assert(dst_height > 0); - assert(src_width * 4 <= kMaxStride); + assert(Abs(src_width) * 4 <= kMaxStride); SIMD_ALIGNED(uint8 row[kMaxStride + 16]); void (*ScaleARGBFilterRows)(uint8* dst_argb, const uint8* src_argb, ptrdiff_t src_stride, int dst_width, int source_y_fraction) = ARGBInterpolateRow_C; #if defined(HAS_ARGBINTERPOLATEROW_SSE2) - if (TestCpuFlag(kCpuHasSSE2) && src_width >= 4) { + if (TestCpuFlag(kCpuHasSSE2) && Abs(src_width) >= 4) { ScaleARGBFilterRows = ARGBInterpolateRow_Any_SSE2; - if (IS_ALIGNED(src_width, 4)) { + if (IS_ALIGNED(Abs(src_width), 4)) { ScaleARGBFilterRows = ARGBInterpolateRow_Unaligned_SSE2; if (IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride, 16)) { ScaleARGBFilterRows = ARGBInterpolateRow_SSE2; @@ -827,9 +837,9 @@ static void ScaleARGBBilinearDown(int src_width, int src_height, } #endif #if defined(HAS_ARGBINTERPOLATEROW_SSSE3) - if (TestCpuFlag(kCpuHasSSSE3) && src_width >= 4) { + if (TestCpuFlag(kCpuHasSSSE3) && Abs(src_width) >= 4) { ScaleARGBFilterRows = ARGBInterpolateRow_Any_SSSE3; - if (IS_ALIGNED(src_width, 4)) { + if (IS_ALIGNED(Abs(src_width), 4)) { ScaleARGBFilterRows = ARGBInterpolateRow_Unaligned_SSSE3; if (IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride, 16)) { ScaleARGBFilterRows = ARGBInterpolateRow_SSSE3; @@ -838,9 +848,9 @@ static void ScaleARGBBilinearDown(int src_width, int src_height, } #endif #if defined(HAS_ARGBINTERPOLATEROW_NEON) - if (TestCpuFlag(kCpuHasNEON) && src_width >= 4) { + if (TestCpuFlag(kCpuHasNEON) && Abs(src_width) >= 4) { ScaleARGBFilterRows = ARGBInterpolateRow_Any_NEON; - if (IS_ALIGNED(src_width, 4)) { + if (IS_ALIGNED(Abs(src_width), 4)) { ScaleARGBFilterRows = ARGBInterpolateRow_NEON; } } @@ -856,11 +866,17 @@ static void ScaleARGBBilinearDown(int src_width, int src_height, int dy = 0; int x = 0; int y = 0; - if (dst_width <= src_width) { - dx = (src_width << 16) / dst_width; + if (dst_width <= Abs(src_width)) { + dx = (Abs(src_width) << 16) / dst_width; x = (dx >> 1) - 32768; } else if (dst_width > 1) { - dx = ((src_width - 1) << 16) / (dst_width - 1); + dx = ((Abs(src_width) - 1) << 16) / (dst_width - 1); + } + // Negative src_width means horizontally mirror. + if (src_width < 0) { + x += (dst_width - 1) * dx; + dx = -dx; + src_width = -src_width; } if (dst_height <= src_height) { dy = (src_height << 16) / dst_height; @@ -936,11 +952,17 @@ static void ScaleARGBBilinearUp(int src_width, int src_height, int dy = 0; int x = 0; int y = 0; - if (dst_width <= src_width) { - dx = (src_width << 16) / dst_width; + if (dst_width <= Abs(src_width)) { + dx = (Abs(src_width) << 16) / dst_width; x = (dx >> 1) - 32768; } else if (dst_width > 1) { - dx = ((src_width - 1) << 16) / (dst_width - 1); + dx = ((Abs(src_width) - 1) << 16) / (dst_width - 1); + } + // Negative src_width means horizontally mirror. + if (src_width < 0) { + x += (dst_width - 1) * dx; + dx = -dx; + src_width = -src_width; } if (dst_height <= src_height) { dy = (src_height << 16) / dst_height; @@ -1024,10 +1046,29 @@ static void ScaleARGBSimple(int src_width, int src_height, ScaleARGBCols = ScaleARGBCols_SSE2; } #endif - int dx = (src_width << 16) / dst_width; - int dy = (src_height << 16) / dst_height; - int x = (dx >= 65536) ? ((dx >> 1) - 32768) : (dx >> 1); - int y = (dy >= 65536) ? ((dy >> 1) - 32768) : (dy >> 1); + int dx = 0; + int dy = 0; + int x = 0; + int y = 0; + if (dst_width <= Abs(src_width)) { + dx = (Abs(src_width) << 16) / dst_width; + x = (dx >> 1) - 32768; + } else if (dst_width > 1) { + dx = ((Abs(src_width) - 1) << 16) / (dst_width - 1); + } + // Negative src_width means horizontally mirror. + if (src_width < 0) { + x += (dst_width - 1) * dx; + dx = -dx; + src_width = -src_width; + } + if (dst_height <= src_height) { + dy = (src_height << 16) / dst_height; + y = (dy >> 1) - 32768; + } else if (dst_height > 1) { + dy = ((src_height - 1) << 16) / (dst_height - 1); + } + for (int i = 0; i < dst_height; ++i) { ScaleARGBCols(dst_argb, src_argb + (y >> 16) * src_stride, dst_width, x, dx); @@ -1044,7 +1085,7 @@ static void ScaleARGBAnySize(int src_width, int src_height, const uint8* src_argb, uint8* dst_argb, FilterMode filtering) { if (!filtering || - (src_width * 4 > kMaxStride && dst_width * 4 > kMaxStride)) { + (Abs(src_width) * 4 > kMaxStride && dst_width * 4 > kMaxStride)) { ScaleARGBSimple(src_width, src_height, dst_width, dst_height, src_stride, dst_stride, src_argb, dst_argb); return; @@ -1111,7 +1152,7 @@ int ARGBScale(const uint8* src_argb, int src_stride_argb, uint8* dst_argb, int dst_stride_argb, int dst_width, int dst_height, FilterMode filtering) { - if (!src_argb || src_width <= 0 || src_height == 0 || + if (!src_argb || src_width == 0 || src_height == 0 || !dst_argb || dst_width <= 0 || dst_height <= 0) { return -1; } diff --git a/unit_test/scale_argb_test.cc b/unit_test/scale_argb_test.cc index 21b812be1..35e508595 100644 --- a/unit_test/scale_argb_test.cc +++ b/unit_test/scale_argb_test.cc @@ -17,12 +17,16 @@ namespace libyuv { +static __inline int Abs(int v) { + return v >= 0 ? v : -v; +} + static int ARGBTestFilter(int src_width, int src_height, int dst_width, int dst_height, FilterMode f, int benchmark_iterations) { const int b = 128; - int src_argb_plane_size = (src_width + b * 2) * (src_height + b * 2) * 4; - int src_stride_argb = (b * 2 + src_width) * 4; + int src_argb_plane_size = (Abs(src_width) + b * 2) * (Abs(src_height) + b * 2) * 4; + int src_stride_argb = (b * 2 + Abs(src_width)) * 4; align_buffer_64(src_argb, src_argb_plane_size) memset(src_argb, 1, src_argb_plane_size); @@ -33,8 +37,8 @@ static int ARGBTestFilter(int src_width, int src_height, srandom(time(NULL)); int i, j; - for (i = b; i < (src_height + b); ++i) { - for (j = b; j < (src_width + b) * 4; ++j) { + for (i = b; i < (Abs(src_height) + b); ++i) { + for (j = b; j < (Abs(src_width) + b) * 4; ++j) { src_argb[(i * src_stride_argb) + j] = (random() & 0xff); } } @@ -103,8 +107,8 @@ static int ARGBTestFilter(int src_width, int src_height, TEST_F(libyuvTest, ARGBScaleDownBy2_None) { const int src_width = benchmark_width_; const int src_height = benchmark_height_; - const int dst_width = src_width / 2; - const int dst_height = src_height / 2; + const int dst_width = Abs(src_width) / 2; + const int dst_height = Abs(src_height) / 2; int max_diff = ARGBTestFilter(src_width, src_height, dst_width, dst_height, @@ -116,8 +120,8 @@ TEST_F(libyuvTest, ARGBScaleDownBy2_None) { TEST_F(libyuvTest, ARGBScaleDownBy2_Bilinear) { const int src_width = benchmark_width_; const int src_height = benchmark_height_; - const int dst_width = src_width / 2; - const int dst_height = src_height / 2; + const int dst_width = Abs(src_width) / 2; + const int dst_height = Abs(src_height) / 2; int max_diff = ARGBTestFilter(src_width, src_height, dst_width, dst_height, @@ -129,8 +133,8 @@ TEST_F(libyuvTest, ARGBScaleDownBy2_Bilinear) { TEST_F(libyuvTest, ARGBScaleDownBy4_None) { const int src_width = benchmark_width_; const int src_height = benchmark_height_; - const int dst_width = src_width / 4; - const int dst_height = src_height / 4; + const int dst_width = Abs(src_width) / 4; + const int dst_height = Abs(src_height) / 4; int max_diff = ARGBTestFilter(src_width, src_height, dst_width, dst_height, @@ -142,8 +146,8 @@ TEST_F(libyuvTest, ARGBScaleDownBy4_None) { TEST_F(libyuvTest, ARGBScaleDownBy4_Bilinear) { const int src_width = benchmark_width_; const int src_height = benchmark_height_; - const int dst_width = src_width / 4; - const int dst_height = src_height / 4; + const int dst_width = Abs(src_width) / 4; + const int dst_height = Abs(src_height) / 4; int max_diff = ARGBTestFilter(src_width, src_height, dst_width, dst_height, @@ -155,8 +159,8 @@ TEST_F(libyuvTest, ARGBScaleDownBy4_Bilinear) { TEST_F(libyuvTest, ARGBScaleDownBy5_None) { const int src_width = benchmark_width_; const int src_height = benchmark_height_; - const int dst_width = src_width / 5; - const int dst_height = src_height / 5; + const int dst_width = Abs(src_width) / 5; + const int dst_height = Abs(src_height) / 5; int max_diff = ARGBTestFilter(src_width, src_height, dst_width, dst_height, @@ -168,8 +172,8 @@ TEST_F(libyuvTest, ARGBScaleDownBy5_None) { TEST_F(libyuvTest, ARGBScaleDownBy5_Bilinear) { const int src_width = benchmark_width_; const int src_height = benchmark_height_; - const int dst_width = src_width / 5; - const int dst_height = src_height / 5; + const int dst_width = Abs(src_width) / 5; + const int dst_height = Abs(src_height) / 5; int max_diff = ARGBTestFilter(src_width, src_height, dst_width, dst_height, @@ -181,8 +185,8 @@ TEST_F(libyuvTest, ARGBScaleDownBy5_Bilinear) { TEST_F(libyuvTest, ARGBScaleDownBy8_None) { const int src_width = benchmark_width_; const int src_height = benchmark_height_; - const int dst_width = src_width / 8; - const int dst_height = src_height / 8; + const int dst_width = Abs(src_width) / 8; + const int dst_height = Abs(src_height) / 8; int max_diff = ARGBTestFilter(src_width, src_height, dst_width, dst_height, @@ -194,8 +198,8 @@ TEST_F(libyuvTest, ARGBScaleDownBy8_None) { TEST_F(libyuvTest, ARGBScaleDownBy8_Bilinear) { const int src_width = benchmark_width_; const int src_height = benchmark_height_; - const int dst_width = src_width / 8; - const int dst_height = src_height / 8; + const int dst_width = Abs(src_width) / 8; + const int dst_height = Abs(src_height) / 8; int max_diff = ARGBTestFilter(src_width, src_height, dst_width, dst_height, @@ -207,8 +211,8 @@ TEST_F(libyuvTest, ARGBScaleDownBy8_Bilinear) { TEST_F(libyuvTest, ARGBScaleDownBy16_None) { const int src_width = benchmark_width_; const int src_height = benchmark_height_; - const int dst_width = src_width / 16; - const int dst_height = src_height / 16; + const int dst_width = Abs(src_width) / 16; + const int dst_height = Abs(src_height) / 16; int max_diff = ARGBTestFilter(src_width, src_height, dst_width, dst_height, @@ -220,8 +224,8 @@ TEST_F(libyuvTest, ARGBScaleDownBy16_None) { TEST_F(libyuvTest, ARGBScaleDownBy16_Bilinear) { const int src_width = benchmark_width_; const int src_height = benchmark_height_; - const int dst_width = src_width / 16; - const int dst_height = src_height / 16; + const int dst_width = Abs(src_width) / 16; + const int dst_height = Abs(src_height) / 16; int max_diff = ARGBTestFilter(src_width, src_height, dst_width, dst_height, @@ -233,8 +237,8 @@ TEST_F(libyuvTest, ARGBScaleDownBy16_Bilinear) { TEST_F(libyuvTest, ARGBScaleDownBy34_None) { const int src_width = benchmark_width_; const int src_height = benchmark_height_; - const int dst_width = src_width * 3 / 4; - const int dst_height = src_height * 3 / 4; + const int dst_width = Abs(src_width) * 3 / 4; + const int dst_height = Abs(src_height) * 3 / 4; int max_diff = ARGBTestFilter(src_width, src_height, dst_width, dst_height, @@ -246,8 +250,8 @@ TEST_F(libyuvTest, ARGBScaleDownBy34_None) { TEST_F(libyuvTest, ARGBScaleDownBy34_Bilinear) { const int src_width = benchmark_width_; const int src_height = benchmark_height_; - const int dst_width = src_width * 3 / 4; - const int dst_height = src_height * 3 / 4; + const int dst_width = Abs(src_width) * 3 / 4; + const int dst_height = Abs(src_height) * 3 / 4; int max_diff = ARGBTestFilter(src_width, src_height, dst_width, dst_height, @@ -259,8 +263,8 @@ TEST_F(libyuvTest, ARGBScaleDownBy34_Bilinear) { TEST_F(libyuvTest, ARGBScaleDownBy38_None) { int src_width = benchmark_width_; int src_height = benchmark_height_; - int dst_width = src_width * 3 / 8; - int dst_height = src_height * 3 / 8; + int dst_width = Abs(src_width) * 3 / 8; + int dst_height = Abs(src_height) * 3 / 8; int max_diff = ARGBTestFilter(src_width, src_height, dst_width, dst_height, @@ -272,8 +276,8 @@ TEST_F(libyuvTest, ARGBScaleDownBy38_None) { TEST_F(libyuvTest, ARGBScaleDownBy38_Bilinear) { int src_width = benchmark_width_; int src_height = benchmark_height_; - int dst_width = src_width * 3 / 8; - int dst_height = src_height * 3 / 8; + int dst_width = Abs(src_width) * 3 / 8; + int dst_height = Abs(src_height) * 3 / 8; int max_diff = ARGBTestFilter(src_width, src_height, dst_width, dst_height, @@ -364,8 +368,8 @@ TEST_F(libyuvTest, ARGBScaleTo853x480_Bilinear) { TEST_F(libyuvTest, ARGBScaleFrom640x360_None) { int src_width = 640; int src_height = 360; - int dst_width = benchmark_width_; - int dst_height = benchmark_height_; + int dst_width = Abs(benchmark_width_); + int dst_height = Abs(benchmark_height_); int max_diff = ARGBTestFilter(src_width, src_height, dst_width, dst_height, @@ -377,8 +381,8 @@ TEST_F(libyuvTest, ARGBScaleFrom640x360_None) { TEST_F(libyuvTest, ARGBScaleFrom640x360_Bilinear) { int src_width = 640; int src_height = 360; - int dst_width = benchmark_width_; - int dst_height = benchmark_height_; + int dst_width = Abs(benchmark_width_); + int dst_height = Abs(benchmark_height_); int max_diff = ARGBTestFilter(src_width, src_height, dst_width, dst_height,