Commit 196e2e72 authored by Frank Barchard's avatar Frank Barchard Committed by Commit Bot

Revert "Allow negative height when ConvertToI420/ARGB is called with NV12/NV21"

This reverts commit a8aa921c.

Reason for revert: breaks a webrtc unittest on Windows.

https://bugs.chromium.org/p/webrtc/issues/detail?id=9263&can=2&start=0&num=100&q=&colspec=ID%20Pri%20M%20ReleaseBlock%20Component%20Status%20Owner%20Summary&groupby=&sort=

Original change's description:
> Allow negative height when ConvertToI420/ARGB is called with NV12/NV21
> 
> ConvertToI420 and ConvertToARGB support the use of a negative height
> parameter to flip the image vertically. When converting from NV12 or
> NV21 this parameter was misinterpreted, resulting in invalid output.
> This CL introduces the use of abs_src_height to correctly calculate
> the location of the source UV plane.
> 
> The sign of crop_height is not used, to reduce confusion ConvertToI420
> and ConvertToARGB no longer accept negative crop height.
> 
> Unit tests for Android420ToI420 are updated to fix miscalculation of
> src_stride_uv, fix incorrect pixel strides, and to test inversion.
> New unit tests are included to test inversion for ConvertToARGB,
> ConvertToI420, Android420ToARGB, and Android420ToABGR.
> For consistency the test NV12Crop is renamed ConvertToI420_NV12_Crop.
> 
> Bug: libyuv:446
> Test: out/Release/libyuv_unittest --gtest_filter=*.ConvertTo*:*.Android420To*
> Change-Id: Idc98e62671cb30272cfa7e24fafbc8b73712f7c6
> Reviewed-on: https://chromium-review.googlesource.com/994074
> Commit-Queue: Frank Barchard <fbarchard@chromium.org>
> Reviewed-by: Frank Barchard <fbarchard@chromium.org>

TBR=fbarchard@chromium.org,robert@bares.me

# Not skipping CQ checks because original CL landed > 1 day ago.

Bug: libyuv:446, chromium:9263, libyuv:801
Change-Id: I7c55b3fcb477f9754c249b9c2c54b24da2c29283
Reviewed-on: https://chromium-review.googlesource.com/1081267Reviewed-by: 's avatarFrank Barchard <fbarchard@chromium.org>
Reviewed-by: 's avatarWeiyong Yao <braveyao@chromium.org>
Commit-Queue: Frank Barchard <fbarchard@chromium.org>
parent a7fb978e
# Names should be added to this file like so:
# Name or Organization <email address>
Robert Bares <robert@bares.me>
Google Inc.
......@@ -46,7 +46,7 @@ int ConvertToARGB(const uint8_t* sample,
const uint8_t* src;
const uint8_t* src_uv;
int abs_src_height = (src_height < 0) ? -src_height : src_height;
int inv_crop_height;
int inv_crop_height = (crop_height < 0) ? -crop_height : crop_height;
int r = 0;
// One pass rotation is available for some formats. For the rest, convert
......@@ -59,16 +59,18 @@ int ConvertToARGB(const uint8_t* sample,
uint8_t* dest_argb = dst_argb;
int dest_dst_stride_argb = dst_stride_argb;
uint8_t* rotate_buffer = NULL;
int abs_crop_height = (crop_height < 0) ? -crop_height : crop_height;
if (dst_argb == NULL || sample == NULL || src_width <= 0 || crop_width <= 0 ||
src_height == 0 || crop_height <= 0) {
src_height == 0 || crop_height == 0) {
return -1;
}
inv_crop_height = (src_height < 0) ? -crop_height : crop_height;
if (src_height < 0) {
inv_crop_height = -inv_crop_height;
}
if (need_buf) {
int argb_size = crop_width * 4 * crop_height;
int argb_size = crop_width * 4 * abs_crop_height;
rotate_buffer = (uint8_t*)malloc(argb_size); /* NOLINT */
if (!rotate_buffer) {
return 1; // Out of memory runtime error.
......@@ -145,13 +147,13 @@ int ConvertToARGB(const uint8_t* sample,
// Biplanar formats
case FOURCC_NV12:
src = sample + (src_width * crop_y + crop_x);
src_uv = sample + aligned_src_width * (abs_src_height + crop_y / 2) + crop_x;
src_uv = sample + aligned_src_width * (src_height + crop_y / 2) + crop_x;
r = NV12ToARGB(src, src_width, src_uv, aligned_src_width, dst_argb,
dst_stride_argb, crop_width, inv_crop_height);
break;
case FOURCC_NV21:
src = sample + (src_width * crop_y + crop_x);
src_uv = sample + aligned_src_width * (abs_src_height + crop_y / 2) + crop_x;
src_uv = sample + aligned_src_width * (src_height + crop_y / 2) + crop_x;
// Call NV12 but with u and v parameters swapped.
r = NV21ToARGB(src, src_width, src_uv, aligned_src_width, dst_argb,
dst_stride_argb, crop_width, inv_crop_height);
......@@ -250,7 +252,7 @@ int ConvertToARGB(const uint8_t* sample,
if (need_buf) {
if (!r) {
r = ARGBRotate(dst_argb, dst_stride_argb, dest_argb, dest_dst_stride_argb,
crop_width, crop_height, rotation);
crop_width, abs_crop_height, rotation);
}
free(rotate_buffer);
} else if (rotation) {
......
......@@ -46,6 +46,8 @@ int ConvertToI420(const uint8_t* sample,
const uint8_t* src;
const uint8_t* src_uv;
const int abs_src_height = (src_height < 0) ? -src_height : src_height;
// TODO(nisse): Why allow crop_height < 0?
const int abs_crop_height = (crop_height < 0) ? -crop_height : crop_height;
int r = 0;
LIBYUV_BOOL need_buf =
(rotation && format != FOURCC_I420 && format != FOURCC_NV12 &&
......@@ -58,23 +60,22 @@ int ConvertToI420(const uint8_t* sample,
int tmp_u_stride = dst_stride_u;
int tmp_v_stride = dst_stride_v;
uint8_t* rotate_buffer = NULL;
int inv_crop_height;
const int inv_crop_height =
(src_height < 0) ? -abs_crop_height : abs_crop_height;
if (!dst_y || !dst_u || !dst_v || !sample || src_width <= 0 ||
crop_width <= 0 || src_height == 0 || crop_height <= 0) {
crop_width <= 0 || src_height == 0 || crop_height == 0) {
return -1;
}
inv_crop_height = (src_height < 0) ? -crop_height : crop_height;
// One pass rotation is available for some formats. For the rest, convert
// to I420 (with optional vertical flipping) into a temporary I420 buffer,
// and then rotate the I420 to the final destination buffer.
// For in-place conversion, if destination dst_y is same as source sample,
// also enable temporary buffer.
if (need_buf) {
int y_size = crop_width * crop_height;
int uv_size = ((crop_width + 1) / 2) * ((crop_height + 1) / 2);
int y_size = crop_width * abs_crop_height;
int uv_size = ((crop_width + 1) / 2) * ((abs_crop_height + 1) / 2);
rotate_buffer = (uint8_t*)malloc(y_size + uv_size * 2); /* NOLINT */
if (!rotate_buffer) {
return 1; // Out of memory runtime error.
......@@ -162,7 +163,7 @@ int ConvertToI420(const uint8_t* sample,
// Biplanar formats
case FOURCC_NV12:
src = sample + (src_width * crop_y + crop_x);
src_uv = sample + (src_width * abs_src_height) +
src_uv = sample + (src_width * src_height) +
((crop_y / 2) * aligned_src_width) + ((crop_x / 2) * 2);
r = NV12ToI420Rotate(src, src_width, src_uv, aligned_src_width, dst_y,
dst_stride_y, dst_u, dst_stride_u, dst_v,
......@@ -170,7 +171,7 @@ int ConvertToI420(const uint8_t* sample,
break;
case FOURCC_NV21:
src = sample + (src_width * crop_y + crop_x);
src_uv = sample + (src_width * abs_src_height) +
src_uv = sample + (src_width * src_height) +
((crop_y / 2) * aligned_src_width) + ((crop_x / 2) * 2);
// Call NV12 but with dst_u and dst_v parameters swapped.
r = NV12ToI420Rotate(src, src_width, src_uv, aligned_src_width, dst_y,
......@@ -260,7 +261,7 @@ int ConvertToI420(const uint8_t* sample,
if (!r) {
r = I420Rotate(dst_y, dst_stride_y, dst_u, dst_stride_u, dst_v,
dst_stride_v, tmp_y, tmp_y_stride, tmp_u, tmp_u_stride,
tmp_v, tmp_v_stride, crop_width, crop_height,
tmp_v, tmp_v_stride, crop_width, abs_crop_height,
rotation);
}
free(rotate_buffer);
......
......@@ -156,34 +156,31 @@ TESTPLANARTOP(H010, uint16_t, 2, 2, 2, H010, uint16_t, 2, 2, 2)
TESTPLANARTOP(H010, uint16_t, 2, 2, 2, H420, uint8_t, 1, 2, 2)
TESTPLANARTOP(H420, uint8_t, 1, 2, 2, H010, uint16_t, 2, 2, 2)
// Test Android 420 to I420.
// Test Android 420 to I420
#define TESTAPLANARTOPI(SRC_FMT_PLANAR, PIXEL_STRIDE, SRC_SUBSAMP_X, \
SRC_SUBSAMP_Y, FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, \
W1280, N, NEG, OFF, PN, OFF_U, OFF_V, BASELINE) \
W1280, N, NEG, OFF, PN, OFF_U, OFF_V) \
TEST_F(LibYUVConvertTest, SRC_FMT_PLANAR##To##FMT_PLANAR##_##PN##N) { \
const int kWidth = ((W1280) > 0) ? (W1280) : 1; \
const int kHeight = benchmark_height_; \
const int kStrideUVSrc = SUBSAMPLE(kWidth, SRC_SUBSAMP_X); \
const int kStrideUVDst = SUBSAMPLE(kWidth, SUBSAMP_X); \
const int kSizeUVSrc = \
kStrideUVSrc * SUBSAMPLE(kHeight, SRC_SUBSAMP_Y); \
const int kSizeUVDst = \
kStrideUVDst * SUBSAMPLE(kHeight, SUBSAMP_Y); \
align_buffer_page_end(src_y, kWidth * kHeight + OFF); \
const int kSizeUV = \
SUBSAMPLE(kWidth, SRC_SUBSAMP_X) * SUBSAMPLE(kHeight, SRC_SUBSAMP_Y); \
align_buffer_page_end(src_y, kWidth* kHeight + OFF); \
align_buffer_page_end(src_uv, \
kSizeUVSrc*((PIXEL_STRIDE == 3) ? 3 : 2) + OFF); \
align_buffer_page_end(dst_y_c, kWidth * kHeight); \
align_buffer_page_end(dst_u_c, kSizeUVDst); \
align_buffer_page_end(dst_v_c, kSizeUVDst); \
align_buffer_page_end(dst_y_baseline, kWidth * kHeight); \
align_buffer_page_end(dst_u_baseline, kSizeUVDst); \
align_buffer_page_end(dst_v_baseline, kSizeUVDst); \
align_buffer_page_end(dst_y_opt, kWidth * kHeight); \
align_buffer_page_end(dst_u_opt, kSizeUVDst); \
align_buffer_page_end(dst_v_opt, kSizeUVDst); \
kSizeUV*((PIXEL_STRIDE == 3) ? 3 : 2) + OFF); \
align_buffer_page_end(dst_y_c, kWidth* kHeight); \
align_buffer_page_end(dst_u_c, SUBSAMPLE(kWidth, SUBSAMP_X) * \
SUBSAMPLE(kHeight, SUBSAMP_Y)); \
align_buffer_page_end(dst_v_c, SUBSAMPLE(kWidth, SUBSAMP_X) * \
SUBSAMPLE(kHeight, SUBSAMP_Y)); \
align_buffer_page_end(dst_y_opt, kWidth* kHeight); \
align_buffer_page_end(dst_u_opt, SUBSAMPLE(kWidth, SUBSAMP_X) * \
SUBSAMPLE(kHeight, SUBSAMP_Y)); \
align_buffer_page_end(dst_v_opt, SUBSAMPLE(kWidth, SUBSAMP_X) * \
SUBSAMPLE(kHeight, SUBSAMP_Y)); \
uint8_t* src_u = src_uv + OFF_U; \
uint8_t* src_v = src_uv + (PIXEL_STRIDE == 1 ? kSizeUVSrc : OFF_V); \
int src_stride_uv = kStrideUVSrc * PIXEL_STRIDE; \
uint8_t* src_v = src_uv + (PIXEL_STRIDE == 1 ? kSizeUV : OFF_V); \
int src_stride_uv = SUBSAMPLE(kWidth, SUBSAMP_X) * PIXEL_STRIDE; \
for (int i = 0; i < kHeight; ++i) \
for (int j = 0; j < kWidth; ++j) \
src_y[i * kWidth + j + OFF] = (fastrand() & 0xff); \
......@@ -195,68 +192,31 @@ TESTPLANARTOP(H420, uint8_t, 1, 2, 2, H010, uint16_t, 2, 2, 2)
(fastrand() & 0xff); \
} \
} \
memset(dst_y_c, 1, kWidth * kHeight); \
memset(dst_u_c, 2, kSizeUVDst); \
memset(dst_v_c, 3, kSizeUVDst); \
memset(dst_y_baseline, 51, kWidth * kHeight); \
memset(dst_u_baseline, 52, kSizeUVDst); \
memset(dst_v_baseline, 53, kSizeUVDst); \
memset(dst_y_opt, 101, kWidth * kHeight); \
memset(dst_u_opt, 102, kSizeUVDst); \
memset(dst_v_opt, 103, kSizeUVDst); \
memset(dst_y_c, 1, kWidth* kHeight); \
memset(dst_u_c, 2, \
SUBSAMPLE(kWidth, SUBSAMP_X) * SUBSAMPLE(kHeight, SUBSAMP_Y)); \
memset(dst_v_c, 3, \
SUBSAMPLE(kWidth, SUBSAMP_X) * SUBSAMPLE(kHeight, SUBSAMP_Y)); \
memset(dst_y_opt, 101, kWidth* kHeight); \
memset(dst_u_opt, 102, \
SUBSAMPLE(kWidth, SUBSAMP_X) * SUBSAMPLE(kHeight, SUBSAMP_Y)); \
memset(dst_v_opt, 103, \
SUBSAMPLE(kWidth, SUBSAMP_X) * SUBSAMPLE(kHeight, SUBSAMP_Y)); \
MaskCpuFlags(disable_cpu_flags_); \
SRC_FMT_PLANAR##To##FMT_PLANAR( \
src_y + OFF, kWidth, src_u + OFF, src_stride_uv, \
src_v + OFF, src_stride_uv, PIXEL_STRIDE, dst_y_c, \
kWidth, dst_u_c, kStrideUVDst, dst_v_c, \
kStrideUVDst, kWidth, NEG kHeight); \
BASELINE(src_y + OFF, kWidth, src_uv + OFF, src_stride_uv, \
dst_y_baseline, kWidth, dst_u_baseline, \
kStrideUVDst, dst_v_baseline, \
kStrideUVDst, kWidth, NEG kHeight); \
src_y + OFF, kWidth, src_u + OFF, SUBSAMPLE(kWidth, SRC_SUBSAMP_X), \
src_v + OFF, SUBSAMPLE(kWidth, SRC_SUBSAMP_X), PIXEL_STRIDE, dst_y_c, \
kWidth, dst_u_c, SUBSAMPLE(kWidth, SUBSAMP_X), dst_v_c, \
SUBSAMPLE(kWidth, SUBSAMP_X), kWidth, NEG kHeight); \
MaskCpuFlags(benchmark_cpu_info_); \
for (int i = 0; i < benchmark_iterations_; ++i) { \
SRC_FMT_PLANAR##To##FMT_PLANAR( \
src_y + OFF, kWidth, src_u + OFF, src_stride_uv, \
src_v + OFF, src_stride_uv, PIXEL_STRIDE, \
dst_y_opt, kWidth, dst_u_opt, kStrideUVDst, \
dst_v_opt, kStrideUVDst, kWidth, NEG kHeight); \
src_y + OFF, kWidth, src_u + OFF, SUBSAMPLE(kWidth, SRC_SUBSAMP_X), \
src_v + OFF, SUBSAMPLE(kWidth, SRC_SUBSAMP_X), PIXEL_STRIDE, \
dst_y_opt, kWidth, dst_u_opt, SUBSAMPLE(kWidth, SUBSAMP_X), \
dst_v_opt, SUBSAMPLE(kWidth, SUBSAMP_X), kWidth, NEG kHeight); \
} \
int max_diff = 0; \
for (int i = 0; i < kHeight; ++i) { \
for (int j = 0; j < kWidth; ++j) { \
int abs_diff = abs(static_cast<int>(dst_y_c[i * kWidth + j]) - \
static_cast<int>(dst_y_baseline[i * kWidth + j])); \
if (abs_diff > max_diff) { \
max_diff = abs_diff; \
} \
} \
} \
EXPECT_EQ(0, max_diff); \
for (int i = 0; i < SUBSAMPLE(kHeight, SUBSAMP_Y); ++i) { \
for (int j = 0; j < SUBSAMPLE(kWidth, SUBSAMP_X); ++j) { \
int abs_diff = abs( \
static_cast<int>(dst_u_c[i * SUBSAMPLE(kWidth, SUBSAMP_X) + j]) - \
static_cast<int>( \
dst_u_baseline[i * SUBSAMPLE(kWidth, SUBSAMP_X) + j])); \
if (abs_diff > max_diff) { \
max_diff = abs_diff; \
} \
} \
} \
EXPECT_EQ(0, max_diff); \
for (int i = 0; i < SUBSAMPLE(kHeight, SUBSAMP_Y); ++i) { \
for (int j = 0; j < SUBSAMPLE(kWidth, SUBSAMP_X); ++j) { \
int abs_diff = abs( \
static_cast<int>(dst_v_c[i * SUBSAMPLE(kWidth, SUBSAMP_X) + j]) - \
static_cast<int>( \
dst_v_baseline[i * SUBSAMPLE(kWidth, SUBSAMP_X) + j])); \
if (abs_diff > max_diff) { \
max_diff = abs_diff; \
} \
} \
} \
EXPECT_EQ(0, max_diff); \
for (int i = 0; i < kHeight; ++i) { \
for (int j = 0; j < kWidth; ++j) { \
int abs_diff = abs(static_cast<int>(dst_y_c[i * kWidth + j]) - \
......@@ -294,9 +254,6 @@ TESTPLANARTOP(H420, uint8_t, 1, 2, 2, H010, uint16_t, 2, 2, 2)
free_aligned_buffer_page_end(dst_y_c); \
free_aligned_buffer_page_end(dst_u_c); \
free_aligned_buffer_page_end(dst_v_c); \
free_aligned_buffer_page_end(dst_y_baseline); \
free_aligned_buffer_page_end(dst_u_baseline); \
free_aligned_buffer_page_end(dst_v_baseline); \
free_aligned_buffer_page_end(dst_y_opt); \
free_aligned_buffer_page_end(dst_u_opt); \
free_aligned_buffer_page_end(dst_v_opt); \
......@@ -306,33 +263,23 @@ TESTPLANARTOP(H420, uint8_t, 1, 2, 2, H010, uint16_t, 2, 2, 2)
#define TESTAPLANARTOP(SRC_FMT_PLANAR, PN, PIXEL_STRIDE, OFF_U, OFF_V, \
SRC_SUBSAMP_X, SRC_SUBSAMP_Y, FMT_PLANAR, SUBSAMP_X, \
SUBSAMP_Y, BASELINE) \
SUBSAMP_Y) \
TESTAPLANARTOPI(SRC_FMT_PLANAR, PIXEL_STRIDE, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, \
FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, benchmark_width_ - 4, \
_Any, +, 0, PN, OFF_U, OFF_V, BASELINE) \
_Any, +, 0, PN, OFF_U, OFF_V) \
TESTAPLANARTOPI(SRC_FMT_PLANAR, PIXEL_STRIDE, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, \
FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, benchmark_width_, \
_Unaligned, +, 1, PN, OFF_U, OFF_V, BASELINE) \
_Unaligned, +, 1, PN, OFF_U, OFF_V) \
TESTAPLANARTOPI(SRC_FMT_PLANAR, PIXEL_STRIDE, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, \
FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, benchmark_width_, _Invert, \
-, 0, PN, OFF_U, OFF_V, BASELINE) \
-, 0, PN, OFF_U, OFF_V) \
TESTAPLANARTOPI(SRC_FMT_PLANAR, PIXEL_STRIDE, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, \
FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, benchmark_width_, _Opt, +, \
0, PN, OFF_U, OFF_V, BASELINE)
0, PN, OFF_U, OFF_V)
// I420ToI420 matching the NV12ToI420 signature, requires kSizeUVSrc in scope.
#define I420TOI420_I(src_y, src_stride_y, src_uv, src_stride_uv, \
dst_y, dst_stride_y, dst_u, dst_stride_u, \
dst_v, dst_stride_v, width, height) \
I420ToI420(src_y, src_stride_y, src_uv, src_stride_uv, \
src_uv + kSizeUVSrc, src_stride_uv, dst_y, dst_stride_y, \
dst_u, dst_stride_u, dst_v, dst_stride_v, width, height)
TESTAPLANARTOP(Android420, I420, 1, 0, 0, 2, 2, I420, 2, 2, I420TOI420_I)
TESTAPLANARTOP(Android420, NV12, 2, 0, 1, 2, 2, I420, 2, 2, NV12ToI420)
TESTAPLANARTOP(Android420, NV21, 2, 1, 0, 2, 2, I420, 2, 2, NV21ToI420)
#undef I420TOI420_I
TESTAPLANARTOP(Android420, I420, 1, 0, 0, 2, 2, I420, 2, 2)
TESTAPLANARTOP(Android420, NV12, 2, 0, 1, 2, 2, I420, 2, 2)
TESTAPLANARTOP(Android420, NV21, 2, 1, 0, 2, 2, I420, 2, 2)
#define TESTPLANARTOBPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, \
FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, W1280, N, NEG, OFF) \
......@@ -1477,216 +1424,85 @@ TEST_F(LibYUVConvertTest, MJPGToARGB) {
#endif // HAVE_JPEG
#define TESTTOI420(FMT, NEG, N) \
TEST_F(LibYUVConvertTest, ConvertToI420_##FMT##N) { \
const int SUBSAMP_X = 2; \
const int SUBSAMP_Y = 2; \
const int kWidth = benchmark_width_; \
const int kHeight = benchmark_height_; \
const int crop_y = \
((benchmark_height_ - (benchmark_height_ * 360 / 480)) / 2 + 1) & ~1; \
const int kDestWidth = benchmark_width_; \
const int kDestHeight = benchmark_height_ - crop_y * 2; \
const int kStrideUV = SUBSAMPLE(kWidth, SUBSAMP_X); \
const int sample_size = \
kWidth * kHeight + kStrideUV * SUBSAMPLE(kHeight, SUBSAMP_Y) * 2; \
align_buffer_page_end(src_y, sample_size); \
uint8_t* src_uv = src_y + kWidth * kHeight; \
\
align_buffer_page_end(dst_y, kDestWidth * kDestHeight); \
align_buffer_page_end(dst_u, SUBSAMPLE(kDestWidth, SUBSAMP_X) * \
SUBSAMPLE(kDestHeight, SUBSAMP_Y)); \
align_buffer_page_end(dst_v, SUBSAMPLE(kDestWidth, SUBSAMP_X) * \
SUBSAMPLE(kDestHeight, SUBSAMP_Y)); \
\
align_buffer_page_end(dst_y_2, kDestWidth * kDestHeight); \
align_buffer_page_end(dst_u_2, SUBSAMPLE(kDestWidth, SUBSAMP_X) * \
SUBSAMPLE(kDestHeight, SUBSAMP_Y)); \
align_buffer_page_end(dst_v_2, SUBSAMPLE(kDestWidth, SUBSAMP_X) * \
SUBSAMPLE(kDestHeight, SUBSAMP_Y)); \
\
for (int i = 0; i < kHeight * kWidth; ++i) { \
src_y[i] = (fastrand() & 0xff); \
} \
for (int i = 0; i < (SUBSAMPLE(kHeight, SUBSAMP_Y) * kStrideUV) * 2; ++i) { \
src_uv[i] = (fastrand() & 0xff); \
} \
memset(dst_y, 1, kDestWidth * kDestHeight); \
memset(dst_u, 2, \
SUBSAMPLE(kDestWidth, SUBSAMP_X) * SUBSAMPLE(kDestHeight, SUBSAMP_Y)); \
memset(dst_v, 3, \
SUBSAMPLE(kDestWidth, SUBSAMP_X) * SUBSAMPLE(kDestHeight, SUBSAMP_Y)); \
memset(dst_y_2, 1, kDestWidth * kDestHeight); \
memset(dst_u_2, 2, \
SUBSAMPLE(kDestWidth, SUBSAMP_X) * SUBSAMPLE(kDestHeight, SUBSAMP_Y)); \
memset(dst_v_2, 3, \
SUBSAMPLE(kDestWidth, SUBSAMP_X) * SUBSAMPLE(kDestHeight, SUBSAMP_Y)); \
\
ConvertToI420(src_y, sample_size, dst_y_2, kDestWidth, dst_u_2, \
SUBSAMPLE(kDestWidth, SUBSAMP_X), dst_v_2, \
SUBSAMPLE(kDestWidth, SUBSAMP_X), 0, crop_y, kWidth, NEG kHeight, \
kDestWidth, kDestHeight, libyuv::kRotate0, libyuv::FOURCC_##FMT); \
\
FMT##ToI420(src_y + crop_y * kWidth, kWidth, \
src_uv + (crop_y / 2) * kStrideUV * 2, kStrideUV * 2, dst_y, \
kDestWidth, dst_u, SUBSAMPLE(kDestWidth, SUBSAMP_X), dst_v, \
SUBSAMPLE(kDestWidth, SUBSAMP_X), kDestWidth, NEG kDestHeight); \
\
for (int i = 0; i < kDestHeight; ++i) { \
for (int j = 0; j < kDestWidth; ++j) { \
EXPECT_EQ(dst_y[i * kWidth + j], dst_y_2[i * kWidth + j]); \
} \
} \
for (int i = 0; i < SUBSAMPLE(kDestHeight, SUBSAMP_Y); ++i) { \
for (int j = 0; j < SUBSAMPLE(kDestWidth, SUBSAMP_X); ++j) { \
EXPECT_EQ(dst_u[i * SUBSAMPLE(kDestWidth, SUBSAMP_X) + j], \
dst_u_2[i * SUBSAMPLE(kDestWidth, SUBSAMP_X) + j]); \
} \
} \
for (int i = 0; i < SUBSAMPLE(kDestHeight, SUBSAMP_Y); ++i) { \
for (int j = 0; j < SUBSAMPLE(kDestWidth, SUBSAMP_X); ++j) { \
EXPECT_EQ(dst_v[i * SUBSAMPLE(kDestWidth, SUBSAMP_X) + j], \
dst_v_2[i * SUBSAMPLE(kDestWidth, SUBSAMP_X) + j]); \
} \
} \
free_aligned_buffer_page_end(dst_y); \
free_aligned_buffer_page_end(dst_u); \
free_aligned_buffer_page_end(dst_v); \
free_aligned_buffer_page_end(dst_y_2); \
free_aligned_buffer_page_end(dst_u_2); \
free_aligned_buffer_page_end(dst_v_2); \
free_aligned_buffer_page_end(src_y); \
}
TESTTOI420(NV12, +, _Crop)
TESTTOI420(NV12, -, _Crop_Invert)
TESTTOI420(NV21, +, _Crop)
TESTTOI420(NV21, -, _Crop_Invert)
#define TESTTOARGB(FMT, NEG, N) \
TEST_F(LibYUVConvertTest, ConvertToARGB_##FMT##N) { \
const int SUBSAMP_X = 2; \
const int SUBSAMP_Y = 2; \
const int kWidth = benchmark_width_; \
const int kHeight = benchmark_height_; \
const int crop_y = \
((benchmark_height_ - (benchmark_height_ * 360 / 480)) / 2 + 1) & ~1; \
const int kDestWidth = benchmark_width_; \
const int kDestHeight = benchmark_height_ - crop_y * 2; \
const int kStrideUV = SUBSAMPLE(kWidth, SUBSAMP_X); \
const int kSizeUV = kStrideUV * SUBSAMPLE(kHeight, SUBSAMP_Y); \
const int sample_size = kWidth * kHeight + kSizeUV * 2; \
align_buffer_page_end(src_y, sample_size); \
uint8_t* src_uv = src_y + kWidth * kHeight; \
\
align_buffer_page_end(dst_argb, kWidth * 4 * kHeight); \
align_buffer_page_end(dst_argb_2, kWidth * 4 * kHeight); \
\
for (int i = 0; i < kHeight * kWidth; ++i) { \
src_y[i] = (fastrand() & 0xff); \
} \
for (int i = 0; i < kSizeUV * 2; ++i) { \
src_uv[i] = (fastrand() & 0xff); \
} \
memset(dst_argb, 1, kDestWidth * 4 * kDestHeight); \
memset(dst_argb_2, 1, kDestWidth * 4 * kDestHeight); \
\
ConvertToARGB(src_y, sample_size, dst_argb_2, kDestWidth * 4, 0, crop_y, \
kWidth, NEG kHeight, kDestWidth, kDestHeight, \
libyuv::kRotate0, libyuv::FOURCC_##FMT); \
\
FMT##ToARGB(src_y + crop_y * kWidth, kWidth, \
src_uv + (crop_y / 2) * kStrideUV * 2, kStrideUV * 2, \
dst_argb, kDestWidth * 4, kDestWidth, NEG kDestHeight); \
\
for (int i = 0; i < kDestHeight; ++i) { \
for (int j = 0; j < kDestWidth * 4; ++j) { \
EXPECT_EQ(dst_argb[i * kWidth + j], dst_argb_2[i * kWidth + j]); \
} \
} \
free_aligned_buffer_page_end(dst_argb); \
free_aligned_buffer_page_end(dst_argb_2); \
free_aligned_buffer_page_end(src_y); \
}
TESTTOARGB(NV12, +, _Crop)
TESTTOARGB(NV12, -, _Crop_Invert)
TESTTOARGB(NV21, +, _Crop)
TESTTOARGB(NV21, -, _Crop_Invert)
#define TESTANDROID420TOBI(FMT_A, PIXEL_STRIDE, OFF_U, OFF_V, FMT_B, BASELINE, \
NEG, N) \
TEST_F(LibYUVConvertTest, Android420To##FMT_B##_##FMT_A##N) { \
const int SUBSAMP_X = 2; \
const int SUBSAMP_Y = 2; \
const int kWidth = benchmark_width_; \
const int kHeight = benchmark_height_; \
const int kDestWidth = benchmark_width_; \
const int kDestHeight = benchmark_height_; \
const int kStrideUV = SUBSAMPLE(kWidth, SUBSAMP_X); \
const int kSizeUV = kStrideUV * SUBSAMPLE(kHeight, SUBSAMP_Y); \
const int sample_size = kWidth * kHeight + kSizeUV * 2; \
align_buffer_page_end(src_y, sample_size); \
uint8_t* src_uv = src_y + kWidth * kHeight; \
uint8_t* src_u = src_uv + OFF_U; \
uint8_t* src_v = src_uv + (PIXEL_STRIDE == 1 ? kSizeUV : OFF_V); \
int src_stride_uv = kStrideUV * PIXEL_STRIDE; \
align_buffer_page_end(dst_argb, kWidth * 4 * kHeight); \
align_buffer_page_end(dst_argb_2, kWidth * 4 * kHeight); \
\
for (int i = 0; i < kHeight * kWidth; ++i) { \
src_y[i] = (fastrand() & 0xff); \
} \
for (int i = 0; i < kSizeUV * 2; ++i) { \
src_uv[i] = (fastrand() & 0xff); \
} \
memset(dst_argb, 1, kDestWidth * 4 * kDestHeight); \
memset(dst_argb_2, 1, kDestWidth * 4 * kDestHeight); \
\
Android420To##FMT_B(src_y, kWidth, src_u, src_stride_uv, src_v, \
src_stride_uv, PIXEL_STRIDE, dst_argb_2, \
kDestWidth * 4, kWidth, NEG kHeight); \
\
BASELINE(src_y, kWidth, src_uv, src_stride_uv, dst_argb, \
kDestWidth * 4, kDestWidth, NEG kDestHeight); \
\
for (int i = 0; i < kDestHeight; ++i) { \
for (int j = 0; j < kDestWidth * 4; ++j) { \
EXPECT_EQ(dst_argb[i * kWidth + j], dst_argb_2[i * kWidth + j]); \
} \
} \
free_aligned_buffer_page_end(dst_argb); \
free_aligned_buffer_page_end(dst_argb_2); \
free_aligned_buffer_page_end(src_y); \
}
#define TESTANDROID420TOB(FMT_A, PIXEL_STRIDE, OFF_U, OFF_V, FMT_B, BASELINE) \
TESTANDROID420TOBI(FMT_A, PIXEL_STRIDE, OFF_U, OFF_V, FMT_B, BASELINE, \
+, ) \
TESTANDROID420TOBI(FMT_A, PIXEL_STRIDE, OFF_U, OFF_V, FMT_B, BASELINE, \
-, _Invert)
// I420ToARGB/ABGR matching the NV12ToI420 signature, requires kSizeUV in scope.
#define I420TOARGB_I(src_y, src_stride_y, src_uv, src_stride_uv, \
dst_argb, dst_stride_argb, width, height) \
I420ToARGB(src_y, src_stride_y, src_uv, src_stride_uv, \
src_uv + kSizeUV, src_stride_uv, dst_argb, \
dst_stride_argb, width, height)
#define I420TOABGR_I(src_y, src_stride_y, src_uv, src_stride_uv, \
dst_argb, dst_stride_argb, width, height) \
I420ToABGR(src_y, src_stride_y, src_uv, src_stride_uv, \
src_uv + kSizeUV, src_stride_uv, dst_argb, \
dst_stride_argb, width, height)
TESTANDROID420TOB(NV12, 2, 0, 1, ARGB, NV12ToARGB)
TESTANDROID420TOB(NV21, 2, 1, 0, ARGB, NV21ToARGB)
TESTANDROID420TOB(I420, 1, 0, 0, ARGB, I420TOARGB_I)
TESTANDROID420TOB(NV12, 2, 0, 1, ABGR, NV12ToABGR)
TESTANDROID420TOB(NV21, 2, 1, 0, ABGR, NV21ToABGR)
TESTANDROID420TOB(I420, 1, 0, 0, ABGR, I420TOABGR_I)
#undef I420TOABGR_I
#undef I420TOARGB_I
TEST_F(LibYUVConvertTest, NV12Crop) {
const int SUBSAMP_X = 2;
const int SUBSAMP_Y = 2;
const int kWidth = benchmark_width_;
const int kHeight = benchmark_height_;
const int crop_y =
((benchmark_height_ - (benchmark_height_ * 360 / 480)) / 2 + 1) & ~1;
const int kDestWidth = benchmark_width_;
const int kDestHeight = benchmark_height_ - crop_y * 2;
const int kStrideUV = SUBSAMPLE(kWidth, SUBSAMP_X);
const int sample_size =
kWidth * kHeight + kStrideUV * SUBSAMPLE(kHeight, SUBSAMP_Y) * 2;
align_buffer_page_end(src_y, sample_size);
uint8_t* src_uv = src_y + kWidth * kHeight;
align_buffer_page_end(dst_y, kDestWidth * kDestHeight);
align_buffer_page_end(dst_u, SUBSAMPLE(kDestWidth, SUBSAMP_X) *
SUBSAMPLE(kDestHeight, SUBSAMP_Y));
align_buffer_page_end(dst_v, SUBSAMPLE(kDestWidth, SUBSAMP_X) *
SUBSAMPLE(kDestHeight, SUBSAMP_Y));
align_buffer_page_end(dst_y_2, kDestWidth * kDestHeight);
align_buffer_page_end(dst_u_2, SUBSAMPLE(kDestWidth, SUBSAMP_X) *
SUBSAMPLE(kDestHeight, SUBSAMP_Y));
align_buffer_page_end(dst_v_2, SUBSAMPLE(kDestWidth, SUBSAMP_X) *
SUBSAMPLE(kDestHeight, SUBSAMP_Y));
for (int i = 0; i < kHeight * kWidth; ++i) {
src_y[i] = (fastrand() & 0xff);
}
for (int i = 0; i < (SUBSAMPLE(kHeight, SUBSAMP_Y) * kStrideUV) * 2; ++i) {
src_uv[i] = (fastrand() & 0xff);
}
memset(dst_y, 1, kDestWidth * kDestHeight);
memset(dst_u, 2,
SUBSAMPLE(kDestWidth, SUBSAMP_X) * SUBSAMPLE(kDestHeight, SUBSAMP_Y));
memset(dst_v, 3,
SUBSAMPLE(kDestWidth, SUBSAMP_X) * SUBSAMPLE(kDestHeight, SUBSAMP_Y));
memset(dst_y_2, 1, kDestWidth * kDestHeight);
memset(dst_u_2, 2,
SUBSAMPLE(kDestWidth, SUBSAMP_X) * SUBSAMPLE(kDestHeight, SUBSAMP_Y));
memset(dst_v_2, 3,
SUBSAMPLE(kDestWidth, SUBSAMP_X) * SUBSAMPLE(kDestHeight, SUBSAMP_Y));
ConvertToI420(src_y, sample_size, dst_y_2, kDestWidth, dst_u_2,
SUBSAMPLE(kDestWidth, SUBSAMP_X), dst_v_2,
SUBSAMPLE(kDestWidth, SUBSAMP_X), 0, crop_y, kWidth, kHeight,
kDestWidth, kDestHeight, libyuv::kRotate0, libyuv::FOURCC_NV12);
NV12ToI420(src_y + crop_y * kWidth, kWidth,
src_uv + (crop_y / 2) * kStrideUV * 2, kStrideUV * 2, dst_y,
kDestWidth, dst_u, SUBSAMPLE(kDestWidth, SUBSAMP_X), dst_v,
SUBSAMPLE(kDestWidth, SUBSAMP_X), kDestWidth, kDestHeight);
for (int i = 0; i < kDestHeight; ++i) {
for (int j = 0; j < kDestWidth; ++j) {
EXPECT_EQ(dst_y[i * kWidth + j], dst_y_2[i * kWidth + j]);
}
}
for (int i = 0; i < SUBSAMPLE(kDestHeight, SUBSAMP_Y); ++i) {
for (int j = 0; j < SUBSAMPLE(kDestWidth, SUBSAMP_X); ++j) {
EXPECT_EQ(dst_u[i * SUBSAMPLE(kDestWidth, SUBSAMP_X) + j],
dst_u_2[i * SUBSAMPLE(kDestWidth, SUBSAMP_X) + j]);
}
}
for (int i = 0; i < SUBSAMPLE(kDestHeight, SUBSAMP_Y); ++i) {
for (int j = 0; j < SUBSAMPLE(kDestWidth, SUBSAMP_X); ++j) {
EXPECT_EQ(dst_v[i * SUBSAMPLE(kDestWidth, SUBSAMP_X) + j],
dst_v_2[i * SUBSAMPLE(kDestWidth, SUBSAMP_X) + j]);
}
}
free_aligned_buffer_page_end(dst_y);
free_aligned_buffer_page_end(dst_u);
free_aligned_buffer_page_end(dst_v);
free_aligned_buffer_page_end(dst_y_2);
free_aligned_buffer_page_end(dst_u_2);
free_aligned_buffer_page_end(dst_v_2);
free_aligned_buffer_page_end(src_y);
}
TEST_F(LibYUVConvertTest, TestYToARGB) {
uint8_t y[32];
......
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