Commit 99a1298c authored by fbarchard@google.com's avatar fbarchard@google.com

I444ToI420 etc use ScalePlane on Y to allow mirroring.

BUG=291
TESTED=unittests still pass.
R=tpsiaki@google.com

Review URL: https://webrtc-codereview.appspot.com/4979004

git-svn-id: http://libyuv.googlecode.com/svn/trunk@893 16f28f9a-4ce2-e073-06de-1de4eb20be90
parent a8e4dcb5
......@@ -22,7 +22,43 @@ namespace libyuv {
extern "C" {
#endif
#define SUBSAMPLE(v, a, s) (v < 0) ? (-((-v + a) >> s)) : ((v + a) >> s)
static __inline int Abs(int v) {
return v >= 0 ? v : -v;
}
// Any I4xx To I420 format with mirroring.
static int I4xxToI420(const uint8* src_y, int src_stride_y,
const uint8* src_u, int src_stride_u,
const uint8* src_v, int src_stride_v,
uint8* dst_y, int dst_stride_y,
uint8* dst_u, int dst_stride_u,
uint8* dst_v, int dst_stride_v,
int src_y_width, int src_y_height,
int src_uv_width, int src_uv_height) {
if (src_y_width == 0 || src_y_height == 0 ||
src_uv_width == 0 || src_uv_height == 0) {
return -1;
}
const int dst_y_width = Abs(src_y_width);
const int dst_y_height = Abs(src_y_height);
const int dst_uv_width = SUBSAMPLE(dst_y_width, 1, 1);
const int dst_uv_height = SUBSAMPLE(dst_y_height, 1, 1);
ScalePlane(src_y, src_stride_y, src_y_width, src_y_height,
dst_y, dst_stride_y, dst_y_width, dst_y_height,
kFilterBilinear);
ScalePlane(src_u, src_stride_u, src_uv_width, src_uv_height,
dst_u, dst_stride_u, dst_uv_width, dst_uv_height,
kFilterBilinear);
ScalePlane(src_v, src_stride_v, src_uv_width, src_uv_height,
dst_v, dst_stride_v, dst_uv_width, dst_uv_height,
kFilterBilinear);
return 0;
}
// Copy I420 with optional flipping
// TODO(fbarchard): Use Scale plane which supports mirroring, but ensure
// is does row coalescing.
LIBYUV_API
int I420Copy(const uint8* src_y, int src_stride_y,
const uint8* src_u, int src_stride_u,
......@@ -69,37 +105,15 @@ int I422ToI420(const uint8* src_y, int src_stride_y,
uint8* dst_u, int dst_stride_u,
uint8* dst_v, int dst_stride_v,
int width, int height) {
if (!src_y || !src_u || !src_v ||
!dst_y || !dst_u || !dst_v ||
width <= 0 || height == 0) {
return -1;
}
// Negative height means invert the image.
if (height < 0) {
height = -height;
src_y = src_y + (height - 1) * src_stride_y;
src_u = src_u + (height - 1) * src_stride_u;
src_v = src_v + (height - 1) * src_stride_v;
src_stride_y = -src_stride_y;
src_stride_u = -src_stride_u;
src_stride_v = -src_stride_v;
}
// Copy Y plane
if (dst_y) {
CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
}
// Resample UV planes.
const int halfwidth = (width + 1) >> 1;
const int halfheight = (height + 1) >> 1;
ScalePlane(src_u, src_stride_u, halfwidth, height,
dst_u, dst_stride_u, halfwidth, halfheight,
kFilterBilinear);
ScalePlane(src_v, src_stride_v, halfwidth, height,
dst_v, dst_stride_v, halfwidth, halfheight,
kFilterBilinear);
return 0;
const int src_uv_width = SUBSAMPLE(width, 1, 1);
return I4xxToI420(src_y, src_stride_y,
src_u, src_stride_u,
src_v, src_stride_v,
dst_y, dst_stride_y,
dst_u, dst_stride_u,
dst_v, dst_stride_v,
width, height,
src_uv_width, height);
}
// 444 chroma is 1x width, 1x height
......@@ -112,37 +126,14 @@ int I444ToI420(const uint8* src_y, int src_stride_y,
uint8* dst_u, int dst_stride_u,
uint8* dst_v, int dst_stride_v,
int width, int height) {
if (!src_y || !src_u || !src_v ||
!dst_y || !dst_u || !dst_v ||
width <= 0 || height == 0) {
return -1;
}
// Negative height means invert the image.
if (height < 0) {
height = -height;
src_y = src_y + (height - 1) * src_stride_y;
src_u = src_u + (height - 1) * src_stride_u;
src_v = src_v + (height - 1) * src_stride_v;
src_stride_y = -src_stride_y;
src_stride_u = -src_stride_u;
src_stride_v = -src_stride_v;
}
// Copy Y plane
if (dst_y) {
CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
}
// Resample UV planes.
const int halfwidth = (width + 1) >> 1;
const int halfheight = (height + 1) >> 1;
ScalePlane(src_u, src_stride_u, width, height,
dst_u, dst_stride_u, halfwidth, halfheight,
kFilterBilinear);
ScalePlane(src_v, src_stride_v, width, height,
dst_v, dst_stride_v, halfwidth, halfheight,
kFilterBilinear);
return 0;
return I4xxToI420(src_y, src_stride_y,
src_u, src_stride_u,
src_v, src_stride_v,
dst_y, dst_stride_y,
dst_u, dst_stride_u,
dst_v, dst_stride_v,
width, height,
width, height);
}
// 411 chroma is 1/4 width, 1x height
......@@ -155,38 +146,15 @@ int I411ToI420(const uint8* src_y, int src_stride_y,
uint8* dst_u, int dst_stride_u,
uint8* dst_v, int dst_stride_v,
int width, int height) {
if (!src_y || !src_u || !src_v ||
!dst_y || !dst_u || !dst_v ||
width <= 0 || height == 0) {
return -1;
}
// Negative height means invert the image.
if (height < 0) {
height = -height;
src_y = src_y + (height - 1) * src_stride_y;
src_u = src_u + (height - 1) * src_stride_u;
src_v = src_v + (height - 1) * src_stride_v;
src_stride_y = -src_stride_y;
src_stride_u = -src_stride_u;
src_stride_v = -src_stride_v;
}
// Copy Y plane
if (dst_y) {
CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
}
// Resample UV planes.
const int halfwidth = (width + 1) >> 1;
const int halfheight = (height + 1) >> 1;
const int quarterwidth = (width + 3) >> 2;
ScalePlane(src_u, src_stride_u, quarterwidth, height,
dst_u, dst_stride_u, halfwidth, halfheight,
kFilterNone);
ScalePlane(src_v, src_stride_v, quarterwidth, height,
dst_v, dst_stride_v, halfwidth, halfheight,
kFilterNone);
return 0;
const int src_uv_width = SUBSAMPLE(width, 3, 2);
return I4xxToI420(src_y, src_stride_y,
src_u, src_stride_u,
src_v, src_stride_v,
dst_y, dst_stride_y,
dst_u, dst_stride_u,
dst_v, dst_stride_v,
width, height,
src_uv_width, height);
}
// I400 is greyscale typically used in MJPG
......@@ -232,7 +200,6 @@ static void CopyPlane2(const uint8* src, int src_stride_0, int src_stride_1,
}
#endif
#if defined(HAS_COPYROW_ERMS)
// TODO(fbarchard): Detect Fast String support.
if (TestCpuFlag(kCpuHasERMS)) {
CopyRow = CopyRow_ERMS;
}
......
......@@ -25,6 +25,40 @@ namespace libyuv {
extern "C" {
#endif
#define SUBSAMPLE(v, a, s) (v < 0) ? (-((-v + a) >> s)) : ((v + a) >> s)
static __inline int Abs(int v) {
return v >= 0 ? v : -v;
}
// I420 To any I4xx YUV format with mirroring.
static int I420ToI4xx(const uint8* src_y, int src_stride_y,
const uint8* src_u, int src_stride_u,
const uint8* src_v, int src_stride_v,
uint8* dst_y, int dst_stride_y,
uint8* dst_u, int dst_stride_u,
uint8* dst_v, int dst_stride_v,
int src_y_width, int src_y_height,
int dst_uv_width, int dst_uv_height) {
if (src_y_width == 0 || src_y_height == 0 ||
dst_uv_width <= 0 || dst_uv_height <= 0) {
return -1;
}
const int dst_y_width = Abs(src_y_width);
const int dst_y_height = Abs(src_y_height);
const int src_uv_width = SUBSAMPLE(src_y_width, 1, 1);
const int src_uv_height = SUBSAMPLE(src_y_height, 1, 1);
ScalePlane(src_y, src_stride_y, src_y_width, src_y_height,
dst_y, dst_stride_y, dst_y_width, dst_y_height,
kFilterBilinear);
ScalePlane(src_u, src_stride_u, src_uv_width, src_uv_height,
dst_u, dst_stride_u, dst_uv_width, dst_uv_height,
kFilterBilinear);
ScalePlane(src_v, src_stride_v, src_uv_width, src_uv_height,
dst_v, dst_stride_v, dst_uv_width, dst_uv_height,
kFilterBilinear);
return 0;
}
// 420 chroma is 1/2 width, 1/2 height
// 422 chroma is 1/2 width, 1x height
LIBYUV_API
......@@ -35,38 +69,16 @@ int I420ToI422(const uint8* src_y, int src_stride_y,
uint8* dst_u, int dst_stride_u,
uint8* dst_v, int dst_stride_v,
int width, int height) {
if (!src_y || !src_u || !src_v ||
!dst_y || !dst_u || !dst_v ||
width <= 0 || height == 0) {
return -1;
}
// Negative height means invert the image.
if (height < 0) {
height = -height;
dst_y = dst_y + (height - 1) * dst_stride_y;
dst_u = dst_u + (height - 1) * dst_stride_u;
dst_v = dst_v + (height - 1) * dst_stride_v;
dst_stride_y = -dst_stride_y;
dst_stride_u = -dst_stride_u;
dst_stride_v = -dst_stride_v;
}
// Copy Y plane.
// TODO(fbarchard): Scale Y plane, which will do a copy, but allows mirror.
if (dst_y) {
CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
}
// Resample UV planes.
const int halfwidth = (width + 1) >> 1;
const int halfheight = (height + 1) >> 1;
ScalePlane(src_u, src_stride_u, halfwidth, halfheight,
dst_u, dst_stride_u, halfwidth, height,
kFilterBilinear);
ScalePlane(src_v, src_stride_v, halfwidth, halfheight,
dst_v, dst_stride_v, halfwidth, height,
kFilterBilinear);
return 0;
const int dst_uv_width = (Abs(width) + 1) >> 1;
const int dst_uv_height = Abs(height);
return I420ToI4xx(src_y, src_stride_y,
src_u, src_stride_u,
src_v, src_stride_v,
dst_y, dst_stride_y,
dst_u, dst_stride_u,
dst_v, dst_stride_v,
width, height,
dst_uv_width, dst_uv_height);
}
// 420 chroma is 1/2 width, 1/2 height
......@@ -79,37 +91,16 @@ int I420ToI444(const uint8* src_y, int src_stride_y,
uint8* dst_u, int dst_stride_u,
uint8* dst_v, int dst_stride_v,
int width, int height) {
if (!src_y || !src_u|| !src_v ||
!dst_y || !dst_u || !dst_v ||
width <= 0 || height == 0) {
return -1;
}
// Negative height means invert the image.
if (height < 0) {
height = -height;
dst_y = dst_y + (height - 1) * dst_stride_y;
dst_u = dst_u + (height - 1) * dst_stride_u;
dst_v = dst_v + (height - 1) * dst_stride_v;
dst_stride_y = -dst_stride_y;
dst_stride_u = -dst_stride_u;
dst_stride_v = -dst_stride_v;
}
// Copy Y plane
if (dst_y) {
CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
}
// Resample UV planes.
const int halfwidth = (width + 1) >> 1;
const int halfheight = (height + 1) >> 1;
ScalePlane(src_u, src_stride_u, halfwidth, halfheight,
dst_u, dst_stride_u, width, height,
kFilterBilinear);
ScalePlane(src_v, src_stride_v, halfwidth, halfheight,
dst_v, dst_stride_v, width, height,
kFilterBilinear);
return 0;
const int dst_uv_width = Abs(width);
const int dst_uv_height = Abs(height);
return I420ToI4xx(src_y, src_stride_y,
src_u, src_stride_u,
src_v, src_stride_v,
dst_y, dst_stride_y,
dst_u, dst_stride_u,
dst_v, dst_stride_v,
width, height,
dst_uv_width, dst_uv_height);
}
// 420 chroma is 1/2 width, 1/2 height
......@@ -122,38 +113,16 @@ int I420ToI411(const uint8* src_y, int src_stride_y,
uint8* dst_u, int dst_stride_u,
uint8* dst_v, int dst_stride_v,
int width, int height) {
if (!src_y || !src_u || !src_v ||
!dst_y || !dst_u || !dst_v ||
width <= 0 || height == 0) {
return -1;
}
// Negative height means invert the image.
if (height < 0) {
height = -height;
dst_y = dst_y + (height - 1) * dst_stride_y;
dst_u = dst_u + (height - 1) * dst_stride_u;
dst_v = dst_v + (height - 1) * dst_stride_v;
dst_stride_y = -dst_stride_y;
dst_stride_u = -dst_stride_u;
dst_stride_v = -dst_stride_v;
}
// Copy Y plane
if (dst_y) {
CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
}
// Resample UV planes.
const int halfwidth = (width + 1) >> 1;
const int halfheight = (height + 1) >> 1;
const int quarterwidth = (width + 3) >> 2;
ScalePlane(src_u, src_stride_u, halfwidth, halfheight,
dst_u, dst_stride_u, quarterwidth, height,
kFilterBilinear);
ScalePlane(src_v, src_stride_v, halfwidth, halfheight,
dst_v, dst_stride_v, quarterwidth, height,
kFilterBilinear);
return 0;
const int dst_uv_width = (Abs(width) + 3) >> 2;
const int dst_uv_height = Abs(height);
return I420ToI4xx(src_y, src_stride_y,
src_u, src_stride_u,
src_v, src_stride_v,
dst_y, dst_stride_y,
dst_u, dst_stride_u,
dst_v, dst_stride_v,
width, height,
dst_uv_width, dst_uv_height);
}
// Copy to I400. Source can be I420,422,444,400,NV12,NV21
......
......@@ -30,10 +30,7 @@ static __inline int Abs(int v) {
return v >= 0 ? v : -v;
}
static __inline int Half(int v) {
return v >= 0 ? ((v + 1) >> 1) : -((-v + 1) >> 1);
}
#define SUBSAMPLE(v, a, s) (v < 0) ? (-((-v + a) >> s)) : ((v + a) >> s)
// Scale plane, 1/2
// This is an optimized version for scaling down a plane to 1/2 of
......@@ -763,8 +760,7 @@ static void ScalePlaneSimple(int src_width, int src_height,
}
// Scale a plane.
// This function in turn calls a scaling function suitable for handling
// the desired resolutions.
// This function dispatches to a specialized scaler based on scale factor.
LIBYUV_API
void ScalePlane(const uint8* src, int src_stride,
......@@ -772,6 +768,13 @@ void ScalePlane(const uint8* src, int src_stride,
uint8* dst, int dst_stride,
int dst_width, int dst_height,
FilterMode filtering) {
// Negative height means invert the image.
if (src_height < 0) {
src_height = -src_height;
src = src + (src_height - 1) * src_stride;
src_stride = -src_stride;
}
// Use specialized scales to improve performance for common resolutions.
// For example, all the 1/2 scalings will use ScalePlaneDown2()
if (dst_width == src_width && dst_height == src_height) {
......@@ -841,8 +844,6 @@ void ScalePlane(const uint8* src, int src_stride,
// Scale an I420 image.
// This function in turn calls a scaling function for each plane.
// TODO(fbarchard): Disable UNDER_ALLOCATED_HACK
#define UNDER_ALLOCATED_HACK 1
LIBYUV_API
int I420Scale(const uint8* src_y, int src_stride_y,
......@@ -858,43 +859,10 @@ int I420Scale(const uint8* src_y, int src_stride_y,
!dst_y || !dst_u || !dst_v || dst_width <= 0 || dst_height <= 0) {
return -1;
}
// Negative height means invert the image.
if (src_height < 0) {
src_height = -src_height;
int halfheight = Half(src_height);
src_y = src_y + (src_height - 1) * src_stride_y;
src_u = src_u + (halfheight - 1) * src_stride_u;
src_v = src_v + (halfheight - 1) * src_stride_v;
src_stride_y = -src_stride_y;
src_stride_u = -src_stride_u;
src_stride_v = -src_stride_v;
}
int src_halfwidth = Half(src_width);
int src_halfheight = Half(src_height);
int dst_halfwidth = Half(dst_width);
int dst_halfheight = Half(dst_height);
#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
int src_halfwidth = SUBSAMPLE(src_width, 1, 1);
int src_halfheight = SUBSAMPLE(src_height, 1, 1);
int dst_halfwidth = SUBSAMPLE(dst_width, 1, 1);
int dst_halfheight = SUBSAMPLE(dst_height, 1, 1);
ScalePlane(src_y, src_stride_y, src_width, src_height,
dst_y, dst_stride_y, dst_width, dst_height,
......@@ -917,59 +885,15 @@ int Scale(const uint8* src_y, const uint8* src_u, const uint8* src_v,
int dst_stride_y, int dst_stride_u, int dst_stride_v,
int dst_width, int dst_height,
bool interpolate) {
if (!src_y || !src_u || !src_v || src_width <= 0 || src_height == 0 ||
!dst_y || !dst_u || !dst_v || dst_width <= 0 || dst_height <= 0) {
return -1;
}
// Negative height means invert the image.
if (src_height < 0) {
src_height = -src_height;
int halfheight = Half(src_height);
src_y = src_y + (src_height - 1) * src_stride_y;
src_u = src_u + (halfheight - 1) * src_stride_u;
src_v = src_v + (halfheight - 1) * src_stride_v;
src_stride_y = -src_stride_y;
src_stride_u = -src_stride_u;
src_stride_v = -src_stride_v;
}
int src_halfwidth = Half(src_width);
int src_halfheight = Half(src_height);
int dst_halfwidth = Half(dst_width);
int dst_halfheight = Half(dst_height);
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);
ScalePlane(src_u, src_stride_u, src_halfwidth, src_halfheight,
dst_u, dst_stride_u, dst_halfwidth, dst_halfheight,
filtering);
ScalePlane(src_v, src_stride_v, src_halfwidth, src_halfheight,
dst_v, dst_stride_v, dst_halfwidth, dst_halfheight,
filtering);
return 0;
return I420Scale(src_y, src_stride_y,
src_u, src_stride_u,
src_v, src_stride_v,
src_width, src_height,
dst_y, dst_stride_y,
dst_u, dst_stride_u,
dst_v, dst_stride_v,
dst_width, dst_height,
interpolate ? kFilterBox : kFilterNone);
}
// Deprecated api
......@@ -983,10 +907,10 @@ int ScaleOffset(const uint8* src, int src_width, int src_height,
return -1;
}
dst_yoffset = dst_yoffset & ~1; // chroma requires offset to multiple of 2.
int src_halfwidth = Half(src_width);
int src_halfheight = Half(src_height);
int dst_halfwidth = Half(dst_width);
int dst_halfheight = Half(dst_height);
int src_halfwidth = SUBSAMPLE(src_width, 1, 1);
int src_halfheight = SUBSAMPLE(src_height, 1, 1);
int dst_halfwidth = SUBSAMPLE(dst_width, 1, 1);
int dst_halfheight = SUBSAMPLE(dst_height, 1, 1);
int aheight = dst_height - dst_yoffset * 2; // actual output height
const uint8* src_y = src;
const uint8* src_u = src + src_width * src_height;
......@@ -997,9 +921,15 @@ int ScaleOffset(const uint8* src, int src_width, int src_height,
(dst_yoffset >> 1) * dst_halfwidth;
uint8* dst_v = dst + dst_width * dst_height + dst_halfwidth * dst_halfheight +
(dst_yoffset >> 1) * dst_halfwidth;
return Scale(src_y, src_u, src_v, src_width, src_halfwidth, src_halfwidth,
src_width, src_height, dst_y, dst_u, dst_v, dst_width,
dst_halfwidth, dst_halfwidth, dst_width, aheight, interpolate);
return I420Scale(src_y, src_width,
src_u, src_halfwidth,
src_v, src_halfwidth,
src_width, src_height,
dst_y, dst_width,
dst_u, dst_halfwidth,
dst_v, dst_halfwidth,
dst_width, aheight,
interpolate ? kFilterBox : kFilterNone);
}
#ifdef __cplusplus
......
......@@ -462,7 +462,7 @@ void ScalePlaneVertical(int src_height,
int bpp, FilterMode filtering) {
int dst_widthx4 = dst_width * bpp;
src_argb += (x >> 16) * bpp;
assert(src_height > 0);
assert(src_height != 0);
assert(dst_width > 0);
assert(dst_height > 0);
void (*InterpolateRow)(uint8* dst_argb, const uint8* src_argb,
......
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