From 5c4dc242f41861f6b0764860e6492200023a89c4 Mon Sep 17 00:00:00 2001 From: Frank Barchard Date: Tue, 27 Oct 2020 09:39:59 -0700 Subject: [PATCH] MJPGToNV12 added and build files sorted Bug: None Change-Id: I87aa64a14bb3f0785f984f492e56fcf2313431ce Reviewed-on: https://chromium-review.googlesource.com/c/libyuv/libyuv/+/2502780 Reviewed-by: Evan Shrubsole Commit-Queue: Frank Barchard --- Android.bp | 16 ++-- Android.mk | 22 ++--- BUILD.gn | 10 +- include/libyuv/convert.h | 6 ++ linux.mk | 18 ++-- source/convert_jpeg.cc | 119 +++++++++++++++++++++++ unit_test/convert_test.cc | 195 ++++++++++++++++++++++++++++++++++++++ 7 files changed, 352 insertions(+), 34 deletions(-) diff --git a/Android.bp b/Android.bp index 06eec1003..d0b234326 100644 --- a/Android.bp +++ b/Android.bp @@ -9,17 +9,20 @@ cc_library { "source/compare.cc", "source/compare_common.cc", "source/compare_gcc.cc", - "source/compare_neon.cc", - "source/compare_neon64.cc", "source/compare_mmi.cc", "source/compare_msa.cc", + "source/compare_neon.cc", + "source/compare_neon64.cc", "source/convert.cc", "source/convert_argb.cc", "source/convert_from.cc", "source/convert_from_argb.cc", + "source/convert_jpeg.cc", "source/convert_to_argb.cc", "source/convert_to_i420.cc", "source/cpu_id.cc", + "source/mjpeg_decoder.cc", + "source/mjpeg_validate.cc", "source/planar_functions.cc", "source/rotate.cc", "source/rotate_any.cc", @@ -40,17 +43,14 @@ cc_library { "source/scale.cc", "source/scale_any.cc", "source/scale_argb.cc", - "source/scale_uv.cc", "source/scale_common.cc", "source/scale_gcc.cc", "source/scale_mmi.cc", "source/scale_msa.cc", "source/scale_neon.cc", "source/scale_neon64.cc", + "source/scale_uv.cc", "source/video_common.cc", - "source/convert_jpeg.cc", - "source/mjpeg_decoder.cc", - "source/mjpeg_validate.cc", ], cflags: [ @@ -80,7 +80,6 @@ cc_test { shared_libs: ["libjpeg"], cflags: ["-Wall", "-Werror"], srcs: [ - "unit_test/unit_test.cc", "unit_test/basictypes_test.cc", "unit_test/color_test.cc", "unit_test/compare_test.cc", @@ -92,8 +91,9 @@ cc_test { "unit_test/rotate_argb_test.cc", "unit_test/rotate_test.cc", "unit_test/scale_argb_test.cc", - "unit_test/scale_uv_test.cc", "unit_test/scale_test.cc", + "unit_test/scale_uv_test.cc", + "unit_test/unit_test.cc", "unit_test/video_common_test.cc", ], } diff --git a/Android.mk b/Android.mk index 47fbfb653..2ceb49281 100644 --- a/Android.mk +++ b/Android.mk @@ -11,45 +11,45 @@ LOCAL_SRC_FILES := \ source/compare_gcc.cc \ source/compare_mmi.cc \ source/compare_msa.cc \ - source/compare_neon64.cc \ source/compare_neon.cc \ + source/compare_neon64.cc \ source/compare_win.cc \ - source/convert_argb.cc \ source/convert.cc \ - source/convert_from_argb.cc \ + source/convert_argb.cc \ source/convert_from.cc \ + source/convert_from_argb.cc \ source/convert_to_argb.cc \ source/convert_to_i420.cc \ source/cpu_id.cc \ source/planar_functions.cc \ + source/rotate.cc \ source/rotate_any.cc \ source/rotate_argb.cc \ - source/rotate.cc \ source/rotate_common.cc \ source/rotate_gcc.cc \ source/rotate_mmi.cc \ source/rotate_msa.cc \ - source/rotate_neon64.cc \ source/rotate_neon.cc \ + source/rotate_neon64.cc \ source/rotate_win.cc \ source/row_any.cc \ source/row_common.cc \ source/row_gcc.cc \ source/row_mmi.cc \ source/row_msa.cc \ - source/row_neon64.cc \ source/row_neon.cc \ + source/row_neon64.cc \ source/row_win.cc \ + source/scale.cc \ source/scale_any.cc \ source/scale_argb.cc \ - source/scale_uv.cc \ - source/scale.cc \ source/scale_common.cc \ source/scale_gcc.cc \ source/scale_mmi.cc \ source/scale_msa.cc \ - source/scale_neon64.cc \ source/scale_neon.cc \ + source/scale_neon64.cc \ + source/scale_uv.cc \ source/scale_win.cc \ source/video_common.cc @@ -90,7 +90,6 @@ LOCAL_MODULE_TAGS := tests LOCAL_CPP_EXTENSION := .cc LOCAL_C_INCLUDES += $(LOCAL_PATH)/include LOCAL_SRC_FILES := \ - unit_test/unit_test.cc \ unit_test/basictypes_test.cc \ unit_test/color_test.cc \ unit_test/compare_test.cc \ @@ -102,8 +101,9 @@ LOCAL_SRC_FILES := \ unit_test/rotate_argb_test.cc \ unit_test/rotate_test.cc \ unit_test/scale_argb_test.cc \ - unit_test/scale_uv_test.cc \ unit_test/scale_test.cc \ + unit_test/scale_uv_test.cc \ + unit_test/unit_test.cc \ unit_test/video_common_test.cc LOCAL_MODULE := libyuv_unittest diff --git a/BUILD.gn b/BUILD.gn index 28a2a1a0d..da103a4a0 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -97,8 +97,8 @@ static_library("libyuv_internal") { "include/libyuv/row.h", "include/libyuv/scale.h", "include/libyuv/scale_argb.h", - "include/libyuv/scale_uv.h", "include/libyuv/scale_row.h", + "include/libyuv/scale_uv.h", "include/libyuv/version.h", "include/libyuv/video_common.h", @@ -131,9 +131,9 @@ static_library("libyuv_internal") { "source/scale.cc", "source/scale_any.cc", "source/scale_argb.cc", - "source/scale_uv.cc", "source/scale_common.cc", "source/scale_gcc.cc", + "source/scale_uv.cc", "source/scale_win.cc", "source/video_common.cc", ] @@ -280,8 +280,8 @@ if (libyuv_include_tests) { "unit_test/rotate_argb_test.cc", "unit_test/rotate_test.cc", "unit_test/scale_argb_test.cc", - "unit_test/scale_uv_test.cc", "unit_test/scale_test.cc", + "unit_test/scale_uv_test.cc", "unit_test/unit_test.cc", "unit_test/unit_test.h", "unit_test/video_common_test.cc", @@ -376,9 +376,7 @@ if (libyuv_include_tests) { # sources "util/i444tonv12_eg.cc", ] - deps = [ - ":libyuv", - ] + deps = [ ":libyuv" ] } executable("cpuid") { diff --git a/include/libyuv/convert.h b/include/libyuv/convert.h index 91d81ac05..70c5add40 100644 --- a/include/libyuv/convert.h +++ b/include/libyuv/convert.h @@ -458,6 +458,12 @@ int MJPGToNV21(const uint8_t* sample, int dst_width, int dst_height); +// JPEG to NV12 +LIBYUV_API +int MJPGToNV12(const uint8_t* sample, size_t sample_size, uint8_t* dst_y, + int dst_stride_y, uint8_t* dst_uv, int dst_stride_uv, + int src_width, int src_height, int dst_width, int dst_height); + // Query size of MJPG in pixels. LIBYUV_API int MJPGSize(const uint8_t* sample, diff --git a/linux.mk b/linux.mk index 3244b7d46..3e93b710d 100644 --- a/linux.mk +++ b/linux.mk @@ -15,13 +15,13 @@ LOCAL_OBJ_FILES := \ source/compare_gcc.o \ source/compare_mmi.o \ source/compare_msa.o \ - source/compare_neon64.o \ source/compare_neon.o \ + source/compare_neon64.o \ source/compare_win.o \ - source/convert_argb.o \ source/convert.o \ - source/convert_from_argb.o \ + source/convert_argb.o \ source/convert_from.o \ + source/convert_from_argb.o \ source/convert_jpeg.o \ source/convert_to_argb.o \ source/convert_to_i420.o \ @@ -29,34 +29,34 @@ LOCAL_OBJ_FILES := \ source/mjpeg_decoder.o \ source/mjpeg_validate.o \ source/planar_functions.o \ + source/rotate.o \ source/rotate_any.o \ source/rotate_argb.o \ - source/rotate.o \ source/rotate_common.o \ source/rotate_gcc.o \ source/rotate_mmi.o \ source/rotate_msa.o \ - source/rotate_neon64.o \ source/rotate_neon.o \ + source/rotate_neon64.o \ source/rotate_win.o \ source/row_any.o \ source/row_common.o \ source/row_gcc.o \ source/row_mmi.o \ source/row_msa.o \ - source/row_neon64.o \ source/row_neon.o \ + source/row_neon64.o \ source/row_win.o \ + source/scale.o \ source/scale_any.o \ source/scale_argb.o \ - source/scale_uv.o \ - source/scale.o \ source/scale_common.o \ source/scale_gcc.o \ source/scale_mmi.o \ source/scale_msa.o \ - source/scale_neon64.o \ source/scale_neon.o \ + source/scale_neon64.o \ + source/scale_uv.o \ source/scale_win.o \ source/video_common.o diff --git a/source/convert_jpeg.cc b/source/convert_jpeg.cc index f440c7c2e..521b0032a 100644 --- a/source/convert_jpeg.cc +++ b/source/convert_jpeg.cc @@ -328,6 +328,125 @@ int MJPGToNV21(const uint8_t* src_mjpg, return ret ? 0 : 1; } +static void JpegI420ToNV12(void* opaque, const uint8_t* const* data, + const int* strides, int rows) { + NV21Buffers* dest = (NV21Buffers*)(opaque); + // Use NV21 with VU swapped. + I420ToNV21(data[0], strides[0], data[2], strides[2], data[1], strides[1], + dest->y, dest->y_stride, dest->vu, dest->vu_stride, dest->w, rows); + dest->y += rows * dest->y_stride; + dest->vu += ((rows + 1) >> 1) * dest->vu_stride; + dest->h -= rows; +} + +static void JpegI422ToNV12(void* opaque, const uint8_t* const* data, + const int* strides, int rows) { + NV21Buffers* dest = (NV21Buffers*)(opaque); + // Use NV21 with VU swapped. + I422ToNV21(data[0], strides[0], data[2], strides[2], data[1], strides[1], + dest->y, dest->y_stride, dest->vu, dest->vu_stride, dest->w, rows); + dest->y += rows * dest->y_stride; + dest->vu += ((rows + 1) >> 1) * dest->vu_stride; + dest->h -= rows; +} + +static void JpegI444ToNV12(void* opaque, const uint8_t* const* data, + const int* strides, int rows) { + NV21Buffers* dest = (NV21Buffers*)(opaque); + // Use NV21 with VU swapped. + I444ToNV21(data[0], strides[0], data[2], strides[2], data[1], strides[1], + dest->y, dest->y_stride, dest->vu, dest->vu_stride, dest->w, rows); + dest->y += rows * dest->y_stride; + dest->vu += ((rows + 1) >> 1) * dest->vu_stride; + dest->h -= rows; +} + +static void JpegI400ToNV12(void* opaque, const uint8_t* const* data, + const int* strides, int rows) { + NV21Buffers* dest = (NV21Buffers*)(opaque); + // Use NV21 since there is no UV plane. + I400ToNV21(data[0], strides[0], dest->y, dest->y_stride, dest->vu, + dest->vu_stride, dest->w, rows); + dest->y += rows * dest->y_stride; + dest->vu += ((rows + 1) >> 1) * dest->vu_stride; + dest->h -= rows; +} + +// MJPG (Motion JPEG) to NV12. +LIBYUV_API +int MJPGToNV12(const uint8_t* sample, size_t sample_size, uint8_t* dst_y, + int dst_stride_y, uint8_t* dst_uv, int dst_stride_uv, + int src_width, int src_height, int dst_width, int dst_height) { + if (sample_size == kUnknownDataSize) { + // ERROR: MJPEG frame size unknown + return -1; + } + + // TODO(fbarchard): Port MJpeg to C. + MJpegDecoder mjpeg_decoder; + LIBYUV_BOOL ret = mjpeg_decoder.LoadFrame(sample, sample_size); + if (ret && (mjpeg_decoder.GetWidth() != src_width || + mjpeg_decoder.GetHeight() != src_height)) { + // ERROR: MJPEG frame has unexpected dimensions + mjpeg_decoder.UnloadFrame(); + return 1; // runtime failure + } + if (ret) { + // Use NV21Buffers but with UV instead of VU. + NV21Buffers bufs = {dst_y, dst_stride_y, dst_uv, + dst_stride_uv, dst_width, dst_height}; + // YUV420 + if (mjpeg_decoder.GetColorSpace() == MJpegDecoder::kColorSpaceYCbCr && + mjpeg_decoder.GetNumComponents() == 3 && + mjpeg_decoder.GetVertSampFactor(0) == 2 && + mjpeg_decoder.GetHorizSampFactor(0) == 2 && + mjpeg_decoder.GetVertSampFactor(1) == 1 && + mjpeg_decoder.GetHorizSampFactor(1) == 1 && + mjpeg_decoder.GetVertSampFactor(2) == 1 && + mjpeg_decoder.GetHorizSampFactor(2) == 1) { + ret = mjpeg_decoder.DecodeToCallback(&JpegI420ToNV12, &bufs, dst_width, + dst_height); + // YUV422 + } else if (mjpeg_decoder.GetColorSpace() == + MJpegDecoder::kColorSpaceYCbCr && + mjpeg_decoder.GetNumComponents() == 3 && + mjpeg_decoder.GetVertSampFactor(0) == 1 && + mjpeg_decoder.GetHorizSampFactor(0) == 2 && + mjpeg_decoder.GetVertSampFactor(1) == 1 && + mjpeg_decoder.GetHorizSampFactor(1) == 1 && + mjpeg_decoder.GetVertSampFactor(2) == 1 && + mjpeg_decoder.GetHorizSampFactor(2) == 1) { + ret = mjpeg_decoder.DecodeToCallback(&JpegI422ToNV12, &bufs, dst_width, + dst_height); + // YUV444 + } else if (mjpeg_decoder.GetColorSpace() == + MJpegDecoder::kColorSpaceYCbCr && + mjpeg_decoder.GetNumComponents() == 3 && + mjpeg_decoder.GetVertSampFactor(0) == 1 && + mjpeg_decoder.GetHorizSampFactor(0) == 1 && + mjpeg_decoder.GetVertSampFactor(1) == 1 && + mjpeg_decoder.GetHorizSampFactor(1) == 1 && + mjpeg_decoder.GetVertSampFactor(2) == 1 && + mjpeg_decoder.GetHorizSampFactor(2) == 1) { + ret = mjpeg_decoder.DecodeToCallback(&JpegI444ToNV12, &bufs, dst_width, + dst_height); + // YUV400 + } else if (mjpeg_decoder.GetColorSpace() == + MJpegDecoder::kColorSpaceGrayscale && + mjpeg_decoder.GetNumComponents() == 1 && + mjpeg_decoder.GetVertSampFactor(0) == 1 && + mjpeg_decoder.GetHorizSampFactor(0) == 1) { + ret = mjpeg_decoder.DecodeToCallback(&JpegI400ToNV12, &bufs, dst_width, + dst_height); + } else { + // Unknown colorspace. + mjpeg_decoder.UnloadFrame(); + return 1; + } + } + return ret ? 0 : 1; +} + struct ARGBBuffers { uint8_t* argb; int argb_stride; diff --git a/unit_test/convert_test.cc b/unit_test/convert_test.cc index 00e3820cf..59a9480d6 100644 --- a/unit_test/convert_test.cc +++ b/unit_test/convert_test.cc @@ -1810,6 +1810,65 @@ TEST_F(LibYUVConvertTest, TestMJPGToI420_NV21) { free_aligned_buffer_page_end(dst_vu); } +TEST_F(LibYUVConvertTest, TestMJPGToI420_NV12) { + int width = 0; + int height = 0; + int ret = MJPGSize(kTest2Jpg, kTest2JpgLen, &width, &height); + EXPECT_EQ(0, ret); + + int half_width = (width + 1) / 2; + int half_height = (height + 1) / 2; + int benchmark_iterations = benchmark_iterations_ * benchmark_width_ * + benchmark_height_ / (width * height); + + // Convert to NV12 + align_buffer_page_end(dst_y, width * height); + align_buffer_page_end(dst_uv, half_width * half_height * 2); + + for (int times = 0; times < benchmark_iterations; ++times) { + ret = MJPGToNV12(kTest2Jpg, kTest2JpgLen, dst_y, width, dst_uv, + half_width * 2, width, height, width, height); + } + // Expect sucesss + EXPECT_EQ(0, ret); + + // Convert to I420 + align_buffer_page_end(dst2_y, width * height); + align_buffer_page_end(dst2_u, half_width * half_height); + align_buffer_page_end(dst2_v, half_width * half_height); + for (int times = 0; times < benchmark_iterations; ++times) { + ret = MJPGToI420(kTest2Jpg, kTest2JpgLen, dst2_y, width, dst2_u, half_width, + dst2_v, half_width, width, height, width, height); + } + // Expect sucesss + EXPECT_EQ(0, ret); + + // Convert I420 to NV12 + align_buffer_page_end(dst3_y, width * height); + align_buffer_page_end(dst3_uv, half_width * half_height * 2); + + I420ToNV12(dst2_y, width, dst2_u, half_width, dst2_v, half_width, dst3_y, + width, dst3_uv, half_width * 2, width, height); + + for (int i = 0; i < width * height; ++i) { + EXPECT_EQ(dst_y[i], dst3_y[i]); + } + for (int i = 0; i < half_width * half_height * 2; ++i) { + EXPECT_EQ(dst_uv[i], dst3_uv[i]); + EXPECT_EQ(dst_uv[i], dst3_uv[i]); + } + + free_aligned_buffer_page_end(dst3_y); + free_aligned_buffer_page_end(dst3_uv); + + free_aligned_buffer_page_end(dst2_y); + free_aligned_buffer_page_end(dst2_u); + free_aligned_buffer_page_end(dst2_v); + + free_aligned_buffer_page_end(dst_y); + free_aligned_buffer_page_end(dst_uv); +} + TEST_F(LibYUVConvertTest, TestMJPGToNV21_420) { int width = 0; int height = 0; @@ -1840,6 +1899,40 @@ TEST_F(LibYUVConvertTest, TestMJPGToNV21_420) { free_aligned_buffer_page_end(dst_uv); } +TEST_F(LibYUVConvertTest, TestMJPGToNV12_420) { + int width = 0; + int height = 0; + int ret = MJPGSize(kTest2Jpg, kTest2JpgLen, &width, &height); + EXPECT_EQ(0, ret); + + int half_width = (width + 1) / 2; + int half_height = (height + 1) / 2; + int benchmark_iterations = benchmark_iterations_ * benchmark_width_ * + benchmark_height_ / (width * height); + + align_buffer_page_end(dst_y, width * height); + align_buffer_page_end(dst_uv, half_width * half_height * 2); + for (int times = 0; times < benchmark_iterations; ++times) { + ret = MJPGToNV12(kTest2Jpg, kTest2JpgLen, dst_y, width, dst_uv, + half_width * 2, width, height, width, height); + } + // Expect sucesss + EXPECT_EQ(0, ret); + + // Test result matches known hash value. Hashes are for VU so flip the plane. + uint32_t dst_y_hash = HashDjb2(dst_y, width * height, 5381); + align_buffer_page_end(dst_vu, half_width * half_height * 2); + SwapUVPlane(dst_uv, half_width * 2, dst_vu, half_width * 2, half_width, + half_height); + uint32_t dst_vu_hash = HashDjb2(dst_vu, half_width * half_height * 2, 5381); + EXPECT_EQ(dst_y_hash, 2682851208u); + EXPECT_EQ(dst_vu_hash, 1069662856u); + + free_aligned_buffer_page_end(dst_y); + free_aligned_buffer_page_end(dst_uv); + free_aligned_buffer_page_end(dst_vu); +} + TEST_F(LibYUVConvertTest, TestMJPGToNV21_422) { int width = 0; int height = 0; @@ -1870,6 +1963,40 @@ TEST_F(LibYUVConvertTest, TestMJPGToNV21_422) { free_aligned_buffer_page_end(dst_uv); } +TEST_F(LibYUVConvertTest, TestMJPGToNV12_422) { + int width = 0; + int height = 0; + int ret = MJPGSize(kTest3Jpg, kTest3JpgLen, &width, &height); + EXPECT_EQ(0, ret); + + int half_width = (width + 1) / 2; + int half_height = (height + 1) / 2; + int benchmark_iterations = benchmark_iterations_ * benchmark_width_ * + benchmark_height_ / (width * height); + + align_buffer_page_end(dst_y, width * height); + align_buffer_page_end(dst_uv, half_width * half_height * 2); + for (int times = 0; times < benchmark_iterations; ++times) { + ret = MJPGToNV12(kTest3Jpg, kTest3JpgLen, dst_y, width, dst_uv, + half_width * 2, width, height, width, height); + } + // Expect sucesss + EXPECT_EQ(0, ret); + + // Test result matches known hash value. Hashes are for VU so flip the plane. + uint32_t dst_y_hash = HashDjb2(dst_y, width * height, 5381); + align_buffer_page_end(dst_vu, half_width * half_height * 2); + SwapUVPlane(dst_uv, half_width * 2, dst_vu, half_width * 2, half_width, + half_height); + uint32_t dst_vu_hash = HashDjb2(dst_vu, half_width * half_height * 2, 5381); + EXPECT_EQ(dst_y_hash, 2682851208u); + EXPECT_EQ(dst_vu_hash, 3543430771u); + + free_aligned_buffer_page_end(dst_y); + free_aligned_buffer_page_end(dst_uv); + free_aligned_buffer_page_end(dst_vu); +} + TEST_F(LibYUVConvertTest, TestMJPGToNV21_400) { int width = 0; int height = 0; @@ -1900,6 +2027,40 @@ TEST_F(LibYUVConvertTest, TestMJPGToNV21_400) { free_aligned_buffer_page_end(dst_uv); } +TEST_F(LibYUVConvertTest, TestMJPGToNV12_400) { + int width = 0; + int height = 0; + int ret = MJPGSize(kTest0Jpg, kTest0JpgLen, &width, &height); + EXPECT_EQ(0, ret); + + int half_width = (width + 1) / 2; + int half_height = (height + 1) / 2; + int benchmark_iterations = benchmark_iterations_ * benchmark_width_ * + benchmark_height_ / (width * height); + + align_buffer_page_end(dst_y, width * height); + align_buffer_page_end(dst_uv, half_width * half_height * 2); + for (int times = 0; times < benchmark_iterations; ++times) { + ret = MJPGToNV12(kTest0Jpg, kTest0JpgLen, dst_y, width, dst_uv, + half_width * 2, width, height, width, height); + } + // Expect sucesss + EXPECT_EQ(0, ret); + + // Test result matches known hash value. Hashes are for VU so flip the plane. + uint32_t dst_y_hash = HashDjb2(dst_y, width * height, 5381); + align_buffer_page_end(dst_vu, half_width * half_height * 2); + SwapUVPlane(dst_uv, half_width * 2, dst_vu, half_width * 2, half_width, + half_height); + uint32_t dst_vu_hash = HashDjb2(dst_vu, half_width * half_height * 2, 5381); + EXPECT_EQ(dst_y_hash, 330644005u); + EXPECT_EQ(dst_vu_hash, 135214341u); + + free_aligned_buffer_page_end(dst_y); + free_aligned_buffer_page_end(dst_uv); + free_aligned_buffer_page_end(dst_vu); +} + TEST_F(LibYUVConvertTest, TestMJPGToNV21_444) { int width = 0; int height = 0; @@ -1930,6 +2091,40 @@ TEST_F(LibYUVConvertTest, TestMJPGToNV21_444) { free_aligned_buffer_page_end(dst_uv); } +TEST_F(LibYUVConvertTest, TestMJPGToNV12_444) { + int width = 0; + int height = 0; + int ret = MJPGSize(kTest1Jpg, kTest1JpgLen, &width, &height); + EXPECT_EQ(0, ret); + + int half_width = (width + 1) / 2; + int half_height = (height + 1) / 2; + int benchmark_iterations = benchmark_iterations_ * benchmark_width_ * + benchmark_height_ / (width * height); + + align_buffer_page_end(dst_y, width * height); + align_buffer_page_end(dst_uv, half_width * half_height * 2); + for (int times = 0; times < benchmark_iterations; ++times) { + ret = MJPGToNV12(kTest1Jpg, kTest1JpgLen, dst_y, width, dst_uv, + half_width * 2, width, height, width, height); + } + // Expect sucesss + EXPECT_EQ(0, ret); + + // Test result matches known hash value. Hashes are for VU so flip the plane. + uint32_t dst_y_hash = HashDjb2(dst_y, width * height, 5381); + align_buffer_page_end(dst_vu, half_width * half_height * 2); + SwapUVPlane(dst_uv, half_width * 2, dst_vu, half_width * 2, half_width, + half_height); + uint32_t dst_vu_hash = HashDjb2(dst_vu, half_width * half_height * 2, 5381); + EXPECT_EQ(dst_y_hash, 2682851208u); + EXPECT_EQ(dst_vu_hash, 506143297u); + + free_aligned_buffer_page_end(dst_y); + free_aligned_buffer_page_end(dst_uv); + free_aligned_buffer_page_end(dst_vu); +} + TEST_F(LibYUVConvertTest, TestMJPGToARGB) { int width = 0; int height = 0;