From ec0cc5bb2dc308a69f870adfbe019d5e5eea9f9f Mon Sep 17 00:00:00 2001 From: "fbarchard@google.com" Date: Thu, 5 Dec 2013 00:28:12 +0000 Subject: [PATCH] Function to switch filters to a simplier one based on scale factors. BUG=none TEST=untested R=tpsiaki@google.com Review URL: https://webrtc-codereview.appspot.com/4989004 git-svn-id: http://libyuv.googlecode.com/svn/trunk@894 16f28f9a-4ce2-e073-06de-1de4eb20be90 --- README.chromium | 2 +- include/libyuv/scale.h | 8 ++--- include/libyuv/scale_row.h | 4 +++ include/libyuv/version.h | 2 +- source/scale.cc | 5 +++ source/scale_argb.cc | 10 ++++++ source/scale_common.cc | 69 +++++++++++++++++++++++++++++++------- 7 files changed, 81 insertions(+), 19 deletions(-) diff --git a/README.chromium b/README.chromium index 175b15cba..fca38c077 100644 --- a/README.chromium +++ b/README.chromium @@ -1,6 +1,6 @@ Name: libyuv URL: http://code.google.com/p/libyuv/ -Version: 892 +Version: 894 License: BSD License File: LICENSE diff --git a/include/libyuv/scale.h b/include/libyuv/scale.h index 03a4f50ce..3bfddb29d 100644 --- a/include/libyuv/scale.h +++ b/include/libyuv/scale.h @@ -18,12 +18,12 @@ namespace libyuv { extern "C" { #endif -// Supported filtering +// Supported filtering. enum FilterMode { kFilterNone = 0, // Point sample; Fastest. - kFilterBilinear = 1, // Faster than box, but lower quality scaling down. - kFilterBox = 2, // Highest quality. - kFilterLinear = 3 // Faster than bilinear, slower than None. + kFilterLinear = 1, // Filter horizontally only. + kFilterBilinear = 2, // Faster than box, but lower quality scaling down. + kFilterBox = 3 // Highest quality. }; // Scale a YUV plane. diff --git a/include/libyuv/scale_row.h b/include/libyuv/scale_row.h index ab4d0e724..b94bf5c1f 100644 --- a/include/libyuv/scale_row.h +++ b/include/libyuv/scale_row.h @@ -55,6 +55,10 @@ extern "C" { #define HAS_SCALEROWDOWN38_MIPS_DSPR2 #endif +FilterMode ScaleFilterReduce(int src_width, int src_height, + int dst_width, int dst_height, + FilterMode filtering); + // Scale ARGB vertically with bilinear interpolation. void ScalePlaneVertical(int src_height, int dst_width, int dst_height, diff --git a/include/libyuv/version.h b/include/libyuv/version.h index 067914fd5..cc24ca80a 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 892 +#define LIBYUV_VERSION 894 #endif // INCLUDE_LIBYUV_VERSION_H_ NOLINT diff --git a/source/scale.cc b/source/scale.cc index 0141e1cd6..f9ca3bf44 100644 --- a/source/scale.cc +++ b/source/scale.cc @@ -768,6 +768,11 @@ void ScalePlane(const uint8* src, int src_stride, uint8* dst, int dst_stride, int dst_width, int dst_height, FilterMode filtering) { + // Simplify filtering when possible. + filtering = ScaleFilterReduce(src_width, src_height, + dst_width, dst_height, + filtering); + // Negative height means invert the image. if (src_height < 0) { src_height = -src_height; diff --git a/source/scale_argb.cc b/source/scale_argb.cc index 9a718b386..5e4d65208 100644 --- a/source/scale_argb.cc +++ b/source/scale_argb.cc @@ -572,6 +572,16 @@ static void ScaleARGB(const uint8* src, int src_stride, int dst_width, int dst_height, int clip_x, int clip_y, int clip_width, int clip_height, FilterMode filtering) { + // ARGB does not support box filter yet, but allow the user to pass it. + // TODO(fbarchard): Support Box filter. Move row function to common. + if (filtering == kFilterBox) { + filtering = kFilterBilinear; + } + // Simplify filtering when possible. + filtering = ScaleFilterReduce(src_width, src_height, + dst_width, dst_height, + filtering); + // Negative src_height means invert the image. if (src_height < 0) { src_height = -src_height; diff --git a/source/scale_common.cc b/source/scale_common.cc index e7f56d319..f5944f1ec 100644 --- a/source/scale_common.cc +++ b/source/scale_common.cc @@ -460,18 +460,20 @@ void ScalePlaneVertical(int src_height, const uint8* src_argb, uint8* dst_argb, int x, int y, int dy, int bpp, FilterMode filtering) { - int dst_widthx4 = dst_width * bpp; - src_argb += (x >> 16) * bpp; + // TODO(fbarchard): Allow higher bpp. + assert(bpp >= 1 && bpp <= 4); assert(src_height != 0); assert(dst_width > 0); assert(dst_height > 0); + int dst_width_bytes = dst_width * bpp; + src_argb += (x >> 16) * bpp; void (*InterpolateRow)(uint8* dst_argb, const uint8* src_argb, ptrdiff_t src_stride, int dst_width, int source_y_fraction) = InterpolateRow_C; #if defined(HAS_INTERPOLATEROW_SSE2) - if (TestCpuFlag(kCpuHasSSE2) && dst_widthx4 >= 16) { + if (TestCpuFlag(kCpuHasSSE2) && dst_width_bytes >= 16) { InterpolateRow = InterpolateRow_Any_SSE2; - if (IS_ALIGNED(dst_widthx4, 16)) { + if (IS_ALIGNED(dst_width_bytes, 16)) { InterpolateRow = InterpolateRow_Unaligned_SSE2; if (IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride, 16) && IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride, 16)) { @@ -481,9 +483,9 @@ void ScalePlaneVertical(int src_height, } #endif #if defined(HAS_INTERPOLATEROW_SSSE3) - if (TestCpuFlag(kCpuHasSSSE3) && dst_widthx4 >= 16) { + if (TestCpuFlag(kCpuHasSSSE3) && dst_width_bytes >= 16) { InterpolateRow = InterpolateRow_Any_SSSE3; - if (IS_ALIGNED(dst_widthx4, 16)) { + if (IS_ALIGNED(dst_width_bytes, 16)) { InterpolateRow = InterpolateRow_Unaligned_SSSE3; if (IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride, 16) && IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride, 16)) { @@ -493,27 +495,27 @@ void ScalePlaneVertical(int src_height, } #endif #if defined(HAS_INTERPOLATEROW_AVX2) - if (TestCpuFlag(kCpuHasAVX2) && dst_widthx4 >= 32) { + if (TestCpuFlag(kCpuHasAVX2) && dst_width_bytes >= 32) { InterpolateRow = InterpolateRow_Any_AVX2; - if (IS_ALIGNED(dst_widthx4, 32)) { + if (IS_ALIGNED(dst_width_bytes, 32)) { InterpolateRow = InterpolateRow_AVX2; } } #endif #if defined(HAS_INTERPOLATEROW_NEON) - if (TestCpuFlag(kCpuHasNEON) && dst_widthx4 >= 16) { + if (TestCpuFlag(kCpuHasNEON) && dst_width_bytes >= 16) { InterpolateRow = InterpolateRow_Any_NEON; - if (IS_ALIGNED(dst_widthx4, 16)) { + if (IS_ALIGNED(dst_width_bytes, 16)) { InterpolateRow = InterpolateRow_NEON; } } #endif #if defined(HAS_INTERPOLATEROWS_MIPS_DSPR2) - if (TestCpuFlag(kCpuHasMIPS_DSPR2) && dst_widthx4 >= 4 && + if (TestCpuFlag(kCpuHasMIPS_DSPR2) && dst_width_bytes >= 4 && IS_ALIGNED(src_argb, 4) && IS_ALIGNED(src_stride, 4) && IS_ALIGNED(dst_argb, 4) && IS_ALIGNED(dst_stride, 4)) { InterpolateRow = InterpolateRow_Any_MIPS_DSPR2; - if (IS_ALIGNED(dst_widthx4, 4)) { + if (IS_ALIGNED(dst_width_bytes, 4)) { InterpolateRow = InterpolateRow_MIPS_DSPR2; } } @@ -526,12 +528,53 @@ void ScalePlaneVertical(int src_height, int yi = y >> 16; int yf = filtering ? ((y >> 8) & 255) : 0; const uint8* src = src_argb + yi * src_stride; - InterpolateRow(dst_argb, src, src_stride, dst_widthx4, yf); + InterpolateRow(dst_argb, src, src_stride, dst_width_bytes, yf); dst_argb += dst_stride; y += dy; } } +// Scale plane vertically with bilinear interpolation. +FilterMode ScaleFilterReduce(int src_width, int src_height, + int dst_width, int dst_height, + FilterMode filtering) { + if (src_width < 0) { + src_width = -src_width; + } + if (src_height < 0) { + src_height = -src_height; + } + if (filtering == kFilterBox) { + // If scaling both axis to 0.5 or larger, switch from Box to Bilinear. + if (dst_width * 2 >= src_width && dst_height * 2 >= src_height) { + filtering = kFilterBilinear; + } + // If scaling to larger, switch from Box to Bilinear. + if (dst_width >= src_width || dst_height >= src_height) { + filtering = kFilterBilinear; + } + } + if (filtering == kFilterBilinear) { + if (src_height == 1) { + filtering = kFilterLinear; + } + // TODO(fbarchard): Detect any odd scale factor and reduce to Linear. + if (dst_height == src_height || dst_height * 3 == src_height) { + filtering = kFilterLinear; + } + } + if (filtering == kFilterLinear) { + if (src_width == 1) { + filtering = kFilterNone; + } + // TODO(fbarchard): Detect any odd scale factor and reduce to None. + if (dst_width == src_width || dst_width * 3 == src_width) { + filtering = kFilterNone; + } + } + return filtering; +} + #ifdef __cplusplus } // extern "C" } // namespace libyuv