diff --git a/libyuv_test.gyp b/libyuv_test.gyp index f67a85269..ab8b91bd6 100644 --- a/libyuv_test.gyp +++ b/libyuv_test.gyp @@ -24,7 +24,8 @@ # sources 'unit_test/unit_test.cc', 'unit_test/rotate_test.cc', - ], # source + 'unit_test/scale_test.cc', + ], 'conditions': [ ['OS=="linux"', { 'cflags': [ diff --git a/source/scale.cc b/source/scale.cc index 9cc5e6200..d3b7d3332 100644 --- a/source/scale.cc +++ b/source/scale.cc @@ -1213,7 +1213,7 @@ static void ScaleRowDown4Int_SSE2(const uint8* src_ptr, int src_stride, asm volatile( "pcmpeqb %%xmm7,%%xmm7\n" "psrlw $0x8,%%xmm7\n" - "lea (%4,%4,2),%4\n" + "lea (%4,%4,2),%3\n" "1:" "movdqa (%0),%%xmm0\n" "movdqa 0x10(%0),%%xmm1\n" diff --git a/unit_test/scale_test.cc b/unit_test/scale_test.cc new file mode 100644 index 000000000..e147d78b0 --- /dev/null +++ b/unit_test/scale_test.cc @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2011 The LibYuv project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "libyuv/scale.h" +#include "unit_test.h" +#include +#include + +using namespace libyuv; + +#define align_buffer_16(var, size) \ + uint8 *var; \ + uint8 *var##_mem; \ + var##_mem = reinterpret_cast(calloc(size+15, sizeof(uint8))); \ + var = reinterpret_cast \ + ((reinterpret_cast(var##_mem) + 15) & (~0x0f)); + +#define free_aligned_buffer_16(var) \ + free(var##_mem); \ + var = 0; + +TEST_F(libyuvTest, ScaleDownBy4) { + int b = 128; + int src_width = 1280; + int src_height = 720; + int src_width_uv = (src_width + 1) >> 1; + int src_height_uv = (src_height + 1) >> 1; + + int src_y_plane_size = (src_width + (2 * b)) * (src_height + (2 * b)); + int src_uv_plane_size = (src_width_uv + (2 * b)) * (src_height_uv + (2 * b)); + + int src_stride_y = 2 * b + src_width; + int src_stride_uv = 2 * b + src_width_uv; + + align_buffer_16(src_y, src_y_plane_size) + align_buffer_16(src_u, src_uv_plane_size) + align_buffer_16(src_v, src_uv_plane_size) + + int dst_width = src_width >> 2; + int dst_height = src_height >> 2; + + int dst_width_uv = (dst_width + 1) >> 1; + int dst_height_uv = (dst_height + 1) >> 1; + + int dst_y_plane_size = (dst_width + (2 * b)) * (dst_height + (2 * b)); + int dst_uv_plane_size = (dst_width_uv + (2 * b)) * (dst_height_uv + (2 * b)); + + int dst_stride_y = 2 * b + dst_width; + int dst_stride_uv = 2 * b + dst_width_uv; + + align_buffer_16(dst_y, dst_y_plane_size) + align_buffer_16(dst_u, dst_uv_plane_size) + align_buffer_16(dst_v, dst_uv_plane_size) + + // create an image with random data reoccurring in 4x4 grid. When the image + // is filtered all the values should be the same. + srandom(time(NULL)); + + uint8 block_data[16]; + + int i, j; + + // Pulling 16 random numbers there is an infinitesimally small + // chance that they are all 0. Then the output will be all 0. + // Output buffer is filled with 0, want to make sure that after the + // filtering something went into the output buffer. + // Avoid this by setting one of the values to 128. Also set the + // random data to at least 1 for when point sampling to prevent + // output all being 0. + block_data[0] = 128; + + for (i = 1; i < 16; i++) + block_data[i] = (random() & 0xfe) + 1; + + for (i = b; i < (src_height + b); i += 4) { + for (j = b; j < (src_width + b); j += 4) { + uint8 *ptr = src_y + (i * src_stride_y) + j; + int k, l; + for (k = 0; k < 4; ++k) + for (l = 0; l < 4; ++l) + ptr[k + src_stride_y * l] = block_data[k + 4 * l]; + } + } + + for (i = 1; i < 16; i++) + block_data[i] = (random() & 0xfe) + 1; + + for (i = b; i < (src_height_uv + b); i += 4) { + for (j = b; j < (src_width_uv + b); j += 4) { + uint8 *ptru = src_u + (i * src_stride_uv) + j; + uint8 *ptrv = src_v + (i * src_stride_uv) + j; + int k, l; + for (k = 0; k < 4; ++k) + for (l = 0; l < 4; ++l) { + ptru[k + src_stride_uv * l] = block_data[k + 4 * l]; + ptrv[k + src_stride_uv * l] = block_data[k + 4 * l]; + } + } + } + + int f; + int err = 0; + + // currently three filter modes, defined as FilterMode in scale.h + for (f = 0; f < 3; ++f) { + I420Scale(src_y + (src_stride_y * b) + b, src_stride_y, + src_u + (src_stride_uv * b) + b, src_stride_uv, + src_v + (src_stride_uv * b) + b, src_stride_uv, + src_width, src_height, + dst_y + (dst_stride_y * b) + b, dst_stride_y, + dst_u + (dst_stride_uv * b) + b, dst_stride_uv, + dst_v + (dst_stride_uv * b) + b, dst_stride_uv, + dst_width, dst_height, + static_cast(f)); + + int value = dst_y[(dst_stride_y * b) + b]; + + // catch the case that the output buffer is all 0 + if (value == 0) + ++err; + + for (i = b; i < (dst_height + b); ++i) { + for (j = b; j < (dst_width + b); ++j) { + if (value != dst_y[(i * dst_stride_y) + j]) + ++err; + } + } + + value = dst_u[(dst_stride_uv * b) + b]; + + if (value == 0) + ++err; + + for (i = b; i < (dst_height_uv + b); ++i) { + for (j = b; j < (dst_width_uv + b); ++j) { + if (value != dst_u[(i * dst_stride_uv) + j]) + ++err; + if (value != dst_v[(i * dst_stride_uv) + j]) + ++err; + } + } + } + + free_aligned_buffer_16(src_y) + free_aligned_buffer_16(src_u) + free_aligned_buffer_16(src_v) + free_aligned_buffer_16(dst_y) + free_aligned_buffer_16(dst_u) + free_aligned_buffer_16(dst_v) + + EXPECT_EQ(0, err); +}