diff --git a/source/convert.cc b/source/convert.cc index 842ef094f..9ec71058c 100644 --- a/source/convert.cc +++ b/source/convert.cc @@ -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; } diff --git a/source/convert_from.cc b/source/convert_from.cc index 0507150a9..dc708de5e 100644 --- a/source/convert_from.cc +++ b/source/convert_from.cc @@ -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 diff --git a/source/scale.cc b/source/scale.cc index 893002ba7..0141e1cd6 100644 --- a/source/scale.cc +++ b/source/scale.cc @@ -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 diff --git a/source/scale_common.cc b/source/scale_common.cc index a4a9e3ef6..e7f56d319 100644 --- a/source/scale_common.cc +++ b/source/scale_common.cc @@ -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,