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
URL: http://code.google.com/p/libyuv/
Version: 892
Version: 894
License: BSD
License File: LICENSE
......
......@@ -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.
......
......@@ -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,
......
......@@ -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
......@@ -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;
......
......@@ -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;
......
......@@ -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
......
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