From 60adcbaf323cfa6b7a2ea408f3c904341a1998c7 Mon Sep 17 00:00:00 2001 From: Frank Barchard Date: Fri, 13 Nov 2015 11:25:56 -0800 Subject: [PATCH] scale with conversion using 2 steps with unittest a prototype function to implement the yuv to rgb with conversion and scale. replace with 1 step function in future version, using same API. R=harryjin@google.com BUG=libyuv:471 Review URL: https://codereview.chromium.org/1421553016 . --- README.chromium | 2 +- include/libyuv/scale_argb.h | 1 - include/libyuv/version.h | 2 +- source/scale_argb.cc | 31 +++++++ unit_test/scale_argb_test.cc | 154 +++++++++++++++++++++++++++++++++++ 5 files changed, 187 insertions(+), 3 deletions(-) diff --git a/README.chromium b/README.chromium index b2bfd5b59..729460b41 100644 --- a/README.chromium +++ b/README.chromium @@ -1,6 +1,6 @@ Name: libyuv URL: http://code.google.com/p/libyuv/ -Version: 1536 +Version: 1537 License: BSD License File: LICENSE diff --git a/include/libyuv/scale_argb.h b/include/libyuv/scale_argb.h index 0c9b36257..b56cf5209 100644 --- a/include/libyuv/scale_argb.h +++ b/include/libyuv/scale_argb.h @@ -35,7 +35,6 @@ int ARGBScaleClip(const uint8* src_argb, int src_stride_argb, int clip_x, int clip_y, int clip_width, int clip_height, enum FilterMode filtering); -// TODO(fbarchard): Implement this. // Scale with YUV conversion to ARGB and clipping. LIBYUV_API int YUVToARGBScaleClip(const uint8* src_y, int src_stride_y, diff --git a/include/libyuv/version.h b/include/libyuv/version.h index 26a9130c9..1970e17ca 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 1536 +#define LIBYUV_VERSION 1537 #endif // INCLUDE_LIBYUV_VERSION_H_ NOLINT diff --git a/source/scale_argb.cc b/source/scale_argb.cc index 40a2d1ab2..132581cce 100644 --- a/source/scale_argb.cc +++ b/source/scale_argb.cc @@ -847,6 +847,37 @@ int ARGBScale(const uint8* src_argb, int src_stride_argb, return 0; } +// Scale with YUV conversion to ARGB and clipping. +LIBYUV_API +int YUVToARGBScaleClip(const uint8* src_y, int src_stride_y, + const uint8* src_u, int src_stride_u, + const uint8* src_v, int src_stride_v, + uint32 src_fourcc, + int src_width, int src_height, + uint8* dst_argb, int dst_stride_argb, + uint32 dst_fourcc, + int dst_width, int dst_height, + int clip_x, int clip_y, int clip_width, int clip_height, + enum FilterMode filtering) { + + uint8* argb_buffer = (uint8*)malloc(src_width * src_height * 4); + int r; + I420ToARGB(src_y, src_stride_y, + src_u, src_stride_u, + src_v, src_stride_v, + argb_buffer, src_width * 4, + src_width, src_height); + + r = ARGBScaleClip(argb_buffer, src_width * 4, + src_width, src_height, + dst_argb, dst_stride_argb, + dst_width, dst_height, + clip_x, clip_y, clip_width, clip_height, + filtering); + free(argb_buffer); + return r; +} + #ifdef __cplusplus } // extern "C" } // namespace libyuv diff --git a/unit_test/scale_argb_test.cc b/unit_test/scale_argb_test.cc index cbf9cb72a..e85eb2a54 100644 --- a/unit_test/scale_argb_test.cc +++ b/unit_test/scale_argb_test.cc @@ -12,8 +12,10 @@ #include #include "libyuv/cpu_id.h" +#include "libyuv/convert.h" #include "libyuv/scale_argb.h" #include "libyuv/row.h" +#include "libyuv/video_common.h" #include "../unit_test/unit_test.h" namespace libyuv { @@ -299,4 +301,156 @@ TEST_SCALETO(ARGBScale, 1280, 720) #undef TEST_SCALETO1 #undef TEST_SCALETO +// Scale with YUV conversion to ARGB and clipping. +LIBYUV_API +int YUVToARGBScaleReference2(const uint8* src_y, int src_stride_y, + const uint8* src_u, int src_stride_u, + const uint8* src_v, int src_stride_v, + uint32 src_fourcc, + int src_width, int src_height, + uint8* dst_argb, int dst_stride_argb, + uint32 dst_fourcc, + int dst_width, int dst_height, + int clip_x, int clip_y, + int clip_width, int clip_height, + enum FilterMode filtering) { + + uint8* argb_buffer = (uint8*)malloc(src_width * src_height * 4); + int r; + I420ToARGB(src_y, src_stride_y, + src_u, src_stride_u, + src_v, src_stride_v, + argb_buffer, src_width * 4, + src_width, src_height); + + r = ARGBScaleClip(argb_buffer, src_width * 4, + src_width, src_height, + dst_argb, dst_stride_argb, + dst_width, dst_height, + clip_x, clip_y, clip_width, clip_height, + filtering); + free(argb_buffer); + return r; +} + +static void FillRamp(uint8* buf, int width, int height, int v, int dx, int dy) { + int rv = v; + for (int y = 0; y < height; ++y) { + for (int x = 0; x < width; ++x) { + *buf++ = v; + v += dx; + if (v < 0 || v > 255) { + dx = -dx; + v += dx; + } + } + v = rv + dy; + if (v < 0 || v > 255) { + dy = -dy; + v += dy; + } + rv = v; + } +} + +// Test scaling with C vs Opt and return maximum pixel difference. 0 = exact. +static int YUVToARGBTestFilter(int src_width, int src_height, + int dst_width, int dst_height, + FilterMode f, int benchmark_iterations, + int disable_cpu_flags, int benchmark_cpu_info) { + int64 src_y_plane_size = Abs(src_width) * Abs(src_height); + int64 src_uv_plane_size = ((Abs(src_width) + 1) / 2) * + ((Abs(src_height) + 1) / 2); + int src_stride_y = Abs(src_width); + int src_stride_uv = (Abs(src_width) + 1) / 2; + + align_buffer_page_end(src_y, src_y_plane_size); + align_buffer_page_end(src_u, src_uv_plane_size); + align_buffer_page_end(src_v, src_uv_plane_size); + + int64 dst_argb_plane_size = (dst_width) * (dst_height) * 4LL; + int dst_stride_argb = (dst_width) * 4; + align_buffer_page_end(dst_argb_c, dst_argb_plane_size); + align_buffer_page_end(dst_argb_opt, dst_argb_plane_size); + if (!dst_argb_c || !dst_argb_opt || !src_y || !src_u || !src_v) { + printf("Skipped. Alloc failed " FILELINESTR(__FILE__, __LINE__) "\n"); + return 0; + } + // Fill YUV image with continuous ramp, which is less sensitive to + // subsampling and filtering differences for test purposes. + FillRamp(src_y, Abs(src_width), Abs(src_height), 128, 1, 1); + FillRamp(src_u, (Abs(src_width) + 1) / 2, (Abs(src_height) + 1) / 2, 3, 1, 1); + FillRamp(src_v, (Abs(src_width) + 1) / 2, (Abs(src_height) + 1) / 2, 4, 1, 1); + memset(dst_argb_c, 2, dst_argb_plane_size); + memset(dst_argb_opt, 3, dst_argb_plane_size); + + YUVToARGBScaleReference2(src_y, src_stride_y, + src_u, src_stride_uv, + src_v, src_stride_uv, + libyuv::FOURCC_I420, + src_width, src_height, + dst_argb_c, dst_stride_argb, + libyuv::FOURCC_I420, + dst_width, dst_height, + 0, 0, dst_width, dst_height, + f); + + for (int i = 0; i < benchmark_iterations; ++i) { + YUVToARGBScaleClip(src_y, src_stride_y, + src_u, src_stride_uv, + src_v, src_stride_uv, + libyuv::FOURCC_I420, + src_width, src_height, + dst_argb_opt, dst_stride_argb, + libyuv::FOURCC_I420, + dst_width, dst_height, + 0, 0, dst_width, dst_height, + f); + } + int max_diff = 0; + for (int i = 0; i < dst_height; ++i) { + for (int j = 0; j < dst_width * 4; ++j) { + int abs_diff = Abs(dst_argb_c[(i * dst_stride_argb) + j] - + dst_argb_opt[(i * dst_stride_argb) + j]); + if (abs_diff > max_diff) { + printf("error %d at %d,%d c %d opt %d", + abs_diff, + j, i, + dst_argb_c[(i * dst_stride_argb) + j], + dst_argb_opt[(i * dst_stride_argb) + j]); + EXPECT_LE(abs_diff, 40); + max_diff = abs_diff; + } + } + } + + free_aligned_buffer_page_end(dst_argb_c); + free_aligned_buffer_page_end(dst_argb_opt); + free_aligned_buffer_page_end(src_y); + free_aligned_buffer_page_end(src_u); + free_aligned_buffer_page_end(src_v); + return max_diff; +} + +TEST_F(LibYUVScaleTest, YUVToRGBScaleUp) { + int diff = YUVToARGBTestFilter(benchmark_width_, benchmark_height_, + benchmark_width_ * 3 / 2, + benchmark_height_ * 3 / 2, + libyuv::kFilterBilinear, + benchmark_iterations_, + disable_cpu_flags_, benchmark_cpu_info_); + EXPECT_LE(diff, 10); +} + +TEST_F(LibYUVScaleTest, YUVToRGBScaleDown) { + int diff = YUVToARGBTestFilter(benchmark_width_ * 3 / 2, + benchmark_height_ * 3 / 2, + benchmark_width_, benchmark_height_, + libyuv::kFilterBilinear, + benchmark_iterations_, + disable_cpu_flags_, benchmark_cpu_info_); + EXPECT_LE(diff, 10); +} + + } // namespace libyuv