Commit ec0cc5bb authored by fbarchard@google.com's avatar fbarchard@google.com

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
parent 99a1298c
Name: libyuv Name: libyuv
URL: http://code.google.com/p/libyuv/ URL: http://code.google.com/p/libyuv/
Version: 892 Version: 894
License: BSD License: BSD
License File: LICENSE License File: LICENSE
......
...@@ -18,12 +18,12 @@ namespace libyuv { ...@@ -18,12 +18,12 @@ namespace libyuv {
extern "C" { extern "C" {
#endif #endif
// Supported filtering // Supported filtering.
enum FilterMode { enum FilterMode {
kFilterNone = 0, // Point sample; Fastest. kFilterNone = 0, // Point sample; Fastest.
kFilterBilinear = 1, // Faster than box, but lower quality scaling down. kFilterLinear = 1, // Filter horizontally only.
kFilterBox = 2, // Highest quality. kFilterBilinear = 2, // Faster than box, but lower quality scaling down.
kFilterLinear = 3 // Faster than bilinear, slower than None. kFilterBox = 3 // Highest quality.
}; };
// Scale a YUV plane. // Scale a YUV plane.
......
...@@ -55,6 +55,10 @@ extern "C" { ...@@ -55,6 +55,10 @@ extern "C" {
#define HAS_SCALEROWDOWN38_MIPS_DSPR2 #define HAS_SCALEROWDOWN38_MIPS_DSPR2
#endif #endif
FilterMode ScaleFilterReduce(int src_width, int src_height,
int dst_width, int dst_height,
FilterMode filtering);
// Scale ARGB vertically with bilinear interpolation. // Scale ARGB vertically with bilinear interpolation.
void ScalePlaneVertical(int src_height, void ScalePlaneVertical(int src_height,
int dst_width, int dst_height, int dst_width, int dst_height,
......
...@@ -11,6 +11,6 @@ ...@@ -11,6 +11,6 @@
#ifndef INCLUDE_LIBYUV_VERSION_H_ // NOLINT #ifndef INCLUDE_LIBYUV_VERSION_H_ // NOLINT
#define INCLUDE_LIBYUV_VERSION_H_ #define INCLUDE_LIBYUV_VERSION_H_
#define LIBYUV_VERSION 892 #define LIBYUV_VERSION 894
#endif // INCLUDE_LIBYUV_VERSION_H_ NOLINT #endif // INCLUDE_LIBYUV_VERSION_H_ NOLINT
...@@ -768,6 +768,11 @@ void ScalePlane(const uint8* src, int src_stride, ...@@ -768,6 +768,11 @@ void ScalePlane(const uint8* src, int src_stride,
uint8* dst, int dst_stride, uint8* dst, int dst_stride,
int dst_width, int dst_height, int dst_width, int dst_height,
FilterMode filtering) { FilterMode filtering) {
// Simplify filtering when possible.
filtering = ScaleFilterReduce(src_width, src_height,
dst_width, dst_height,
filtering);
// Negative height means invert the image. // Negative height means invert the image.
if (src_height < 0) { if (src_height < 0) {
src_height = -src_height; src_height = -src_height;
......
...@@ -572,6 +572,16 @@ static void ScaleARGB(const uint8* src, int src_stride, ...@@ -572,6 +572,16 @@ static void ScaleARGB(const uint8* src, int src_stride,
int dst_width, int dst_height, int dst_width, int dst_height,
int clip_x, int clip_y, int clip_width, int clip_height, int clip_x, int clip_y, int clip_width, int clip_height,
FilterMode filtering) { 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. // Negative src_height means invert the image.
if (src_height < 0) { if (src_height < 0) {
src_height = -src_height; src_height = -src_height;
......
...@@ -460,18 +460,20 @@ void ScalePlaneVertical(int src_height, ...@@ -460,18 +460,20 @@ void ScalePlaneVertical(int src_height,
const uint8* src_argb, uint8* dst_argb, const uint8* src_argb, uint8* dst_argb,
int x, int y, int dy, int x, int y, int dy,
int bpp, FilterMode filtering) { int bpp, FilterMode filtering) {
int dst_widthx4 = dst_width * bpp; // TODO(fbarchard): Allow higher bpp.
src_argb += (x >> 16) * bpp; assert(bpp >= 1 && bpp <= 4);
assert(src_height != 0); assert(src_height != 0);
assert(dst_width > 0); assert(dst_width > 0);
assert(dst_height > 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, void (*InterpolateRow)(uint8* dst_argb, const uint8* src_argb,
ptrdiff_t src_stride, int dst_width, int source_y_fraction) = ptrdiff_t src_stride, int dst_width, int source_y_fraction) =
InterpolateRow_C; InterpolateRow_C;
#if defined(HAS_INTERPOLATEROW_SSE2) #if defined(HAS_INTERPOLATEROW_SSE2)
if (TestCpuFlag(kCpuHasSSE2) && dst_widthx4 >= 16) { if (TestCpuFlag(kCpuHasSSE2) && dst_width_bytes >= 16) {
InterpolateRow = InterpolateRow_Any_SSE2; InterpolateRow = InterpolateRow_Any_SSE2;
if (IS_ALIGNED(dst_widthx4, 16)) { if (IS_ALIGNED(dst_width_bytes, 16)) {
InterpolateRow = InterpolateRow_Unaligned_SSE2; InterpolateRow = InterpolateRow_Unaligned_SSE2;
if (IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride, 16) && if (IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride, 16) &&
IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride, 16)) { IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride, 16)) {
...@@ -481,9 +483,9 @@ void ScalePlaneVertical(int src_height, ...@@ -481,9 +483,9 @@ void ScalePlaneVertical(int src_height,
} }
#endif #endif
#if defined(HAS_INTERPOLATEROW_SSSE3) #if defined(HAS_INTERPOLATEROW_SSSE3)
if (TestCpuFlag(kCpuHasSSSE3) && dst_widthx4 >= 16) { if (TestCpuFlag(kCpuHasSSSE3) && dst_width_bytes >= 16) {
InterpolateRow = InterpolateRow_Any_SSSE3; InterpolateRow = InterpolateRow_Any_SSSE3;
if (IS_ALIGNED(dst_widthx4, 16)) { if (IS_ALIGNED(dst_width_bytes, 16)) {
InterpolateRow = InterpolateRow_Unaligned_SSSE3; InterpolateRow = InterpolateRow_Unaligned_SSSE3;
if (IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride, 16) && if (IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride, 16) &&
IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride, 16)) { IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride, 16)) {
...@@ -493,27 +495,27 @@ void ScalePlaneVertical(int src_height, ...@@ -493,27 +495,27 @@ void ScalePlaneVertical(int src_height,
} }
#endif #endif
#if defined(HAS_INTERPOLATEROW_AVX2) #if defined(HAS_INTERPOLATEROW_AVX2)
if (TestCpuFlag(kCpuHasAVX2) && dst_widthx4 >= 32) { if (TestCpuFlag(kCpuHasAVX2) && dst_width_bytes >= 32) {
InterpolateRow = InterpolateRow_Any_AVX2; InterpolateRow = InterpolateRow_Any_AVX2;
if (IS_ALIGNED(dst_widthx4, 32)) { if (IS_ALIGNED(dst_width_bytes, 32)) {
InterpolateRow = InterpolateRow_AVX2; InterpolateRow = InterpolateRow_AVX2;
} }
} }
#endif #endif
#if defined(HAS_INTERPOLATEROW_NEON) #if defined(HAS_INTERPOLATEROW_NEON)
if (TestCpuFlag(kCpuHasNEON) && dst_widthx4 >= 16) { if (TestCpuFlag(kCpuHasNEON) && dst_width_bytes >= 16) {
InterpolateRow = InterpolateRow_Any_NEON; InterpolateRow = InterpolateRow_Any_NEON;
if (IS_ALIGNED(dst_widthx4, 16)) { if (IS_ALIGNED(dst_width_bytes, 16)) {
InterpolateRow = InterpolateRow_NEON; InterpolateRow = InterpolateRow_NEON;
} }
} }
#endif #endif
#if defined(HAS_INTERPOLATEROWS_MIPS_DSPR2) #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(src_argb, 4) && IS_ALIGNED(src_stride, 4) &&
IS_ALIGNED(dst_argb, 4) && IS_ALIGNED(dst_stride, 4)) { IS_ALIGNED(dst_argb, 4) && IS_ALIGNED(dst_stride, 4)) {
InterpolateRow = InterpolateRow_Any_MIPS_DSPR2; InterpolateRow = InterpolateRow_Any_MIPS_DSPR2;
if (IS_ALIGNED(dst_widthx4, 4)) { if (IS_ALIGNED(dst_width_bytes, 4)) {
InterpolateRow = InterpolateRow_MIPS_DSPR2; InterpolateRow = InterpolateRow_MIPS_DSPR2;
} }
} }
...@@ -526,12 +528,53 @@ void ScalePlaneVertical(int src_height, ...@@ -526,12 +528,53 @@ void ScalePlaneVertical(int src_height,
int yi = y >> 16; int yi = y >> 16;
int yf = filtering ? ((y >> 8) & 255) : 0; int yf = filtering ? ((y >> 8) & 255) : 0;
const uint8* src = src_argb + yi * src_stride; 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; dst_argb += dst_stride;
y += dy; 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 #ifdef __cplusplus
} // extern "C" } // extern "C"
} // namespace libyuv } // namespace libyuv
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment