1 /* 2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #include <string.h> 12 13 #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h" 14 #include "webrtc/modules/video_processing/include/video_processing.h" 15 #include "webrtc/modules/video_processing/test/video_processing_unittest.h" 16 #include "webrtc/modules/video_processing/video_denoiser.h" 17 18 namespace webrtc { 19 20 TEST_F(VideoProcessingTest, CopyMem) { 21 rtc::scoped_ptr<DenoiserFilter> df_c(DenoiserFilter::Create(false)); 22 rtc::scoped_ptr<DenoiserFilter> df_sse_neon(DenoiserFilter::Create(true)); 23 uint8_t src[16 * 16], dst[16 * 16]; 24 for (int i = 0; i < 16; ++i) { 25 for (int j = 0; j < 16; ++j) { 26 src[i * 16 + j] = i * 16 + j; 27 } 28 } 29 30 memset(dst, 0, 8 * 8); 31 df_c->CopyMem8x8(src, 8, dst, 8); 32 EXPECT_EQ(0, memcmp(src, dst, 8 * 8)); 33 34 memset(dst, 0, 16 * 16); 35 df_c->CopyMem16x16(src, 16, dst, 16); 36 EXPECT_EQ(0, memcmp(src, dst, 16 * 16)); 37 38 memset(dst, 0, 8 * 8); 39 df_sse_neon->CopyMem16x16(src, 8, dst, 8); 40 EXPECT_EQ(0, memcmp(src, dst, 8 * 8)); 41 42 memset(dst, 0, 16 * 16); 43 df_sse_neon->CopyMem16x16(src, 16, dst, 16); 44 EXPECT_EQ(0, memcmp(src, dst, 16 * 16)); 45 } 46 47 TEST_F(VideoProcessingTest, Variance) { 48 rtc::scoped_ptr<DenoiserFilter> df_c(DenoiserFilter::Create(false)); 49 rtc::scoped_ptr<DenoiserFilter> df_sse_neon(DenoiserFilter::Create(true)); 50 uint8_t src[16 * 16], dst[16 * 16]; 51 uint32_t sum = 0, sse = 0, var; 52 for (int i = 0; i < 16; ++i) { 53 for (int j = 0; j < 16; ++j) { 54 src[i * 16 + j] = i * 16 + j; 55 } 56 } 57 // Compute the 16x8 variance of the 16x16 block. 58 for (int i = 0; i < 8; ++i) { 59 for (int j = 0; j < 16; ++j) { 60 sum += (i * 32 + j); 61 sse += (i * 32 + j) * (i * 32 + j); 62 } 63 } 64 var = sse - ((sum * sum) >> 7); 65 memset(dst, 0, 16 * 16); 66 EXPECT_EQ(var, df_c->Variance16x8(src, 16, dst, 16, &sse)); 67 EXPECT_EQ(var, df_sse_neon->Variance16x8(src, 16, dst, 16, &sse)); 68 } 69 70 TEST_F(VideoProcessingTest, MbDenoise) { 71 rtc::scoped_ptr<DenoiserFilter> df_c(DenoiserFilter::Create(false)); 72 rtc::scoped_ptr<DenoiserFilter> df_sse_neon(DenoiserFilter::Create(true)); 73 uint8_t running_src[16 * 16], src[16 * 16], dst[16 * 16], dst_ref[16 * 16]; 74 75 // Test case: |diff| <= |3 + shift_inc1| 76 for (int i = 0; i < 16; ++i) { 77 for (int j = 0; j < 16; ++j) { 78 running_src[i * 16 + j] = i * 11 + j; 79 src[i * 16 + j] = i * 11 + j + 2; 80 dst_ref[i * 16 + j] = running_src[i * 16 + j]; 81 } 82 } 83 memset(dst, 0, 16 * 16); 84 df_c->MbDenoise(running_src, 16, dst, 16, src, 16, 0, 1); 85 EXPECT_EQ(0, memcmp(dst, dst_ref, 16 * 16)); 86 87 // Test case: |diff| >= |4 + shift_inc1| 88 for (int i = 0; i < 16; ++i) { 89 for (int j = 0; j < 16; ++j) { 90 running_src[i * 16 + j] = i * 11 + j; 91 src[i * 16 + j] = i * 11 + j + 5; 92 dst_ref[i * 16 + j] = src[i * 16 + j] - 2; 93 } 94 } 95 memset(dst, 0, 16 * 16); 96 df_c->MbDenoise(running_src, 16, dst, 16, src, 16, 0, 1); 97 EXPECT_EQ(0, memcmp(dst, dst_ref, 16 * 16)); 98 memset(dst, 0, 16 * 16); 99 df_sse_neon->MbDenoise(running_src, 16, dst, 16, src, 16, 0, 1); 100 EXPECT_EQ(0, memcmp(dst, dst_ref, 16 * 16)); 101 102 // Test case: |diff| >= 8 103 for (int i = 0; i < 16; ++i) { 104 for (int j = 0; j < 16; ++j) { 105 running_src[i * 16 + j] = i * 11 + j; 106 src[i * 16 + j] = i * 11 + j + 8; 107 dst_ref[i * 16 + j] = src[i * 16 + j] - 6; 108 } 109 } 110 memset(dst, 0, 16 * 16); 111 df_c->MbDenoise(running_src, 16, dst, 16, src, 16, 0, 1); 112 EXPECT_EQ(0, memcmp(dst, dst_ref, 16 * 16)); 113 memset(dst, 0, 16 * 16); 114 df_sse_neon->MbDenoise(running_src, 16, dst, 16, src, 16, 0, 1); 115 EXPECT_EQ(0, memcmp(dst, dst_ref, 16 * 16)); 116 117 // Test case: |diff| > 15 118 for (int i = 0; i < 16; ++i) { 119 for (int j = 0; j < 16; ++j) { 120 running_src[i * 16 + j] = i * 11 + j; 121 src[i * 16 + j] = i * 11 + j + 16; 122 } 123 } 124 memset(dst, 0, 16 * 16); 125 DenoiserDecision decision = 126 df_c->MbDenoise(running_src, 16, dst, 16, src, 16, 0, 1); 127 EXPECT_EQ(COPY_BLOCK, decision); 128 decision = df_sse_neon->MbDenoise(running_src, 16, dst, 16, src, 16, 0, 1); 129 EXPECT_EQ(COPY_BLOCK, decision); 130 } 131 132 TEST_F(VideoProcessingTest, Denoiser) { 133 // Create pure C denoiser. 134 VideoDenoiser denoiser_c(false); 135 // Create SSE or NEON denoiser. 136 VideoDenoiser denoiser_sse_neon(true); 137 VideoFrame denoised_frame_c; 138 VideoFrame denoised_frame_sse_neon; 139 140 rtc::scoped_ptr<uint8_t[]> video_buffer(new uint8_t[frame_length_]); 141 while (fread(video_buffer.get(), 1, frame_length_, source_file_) == 142 frame_length_) { 143 // Using ConvertToI420 to add stride to the image. 144 EXPECT_EQ(0, ConvertToI420(kI420, video_buffer.get(), 0, 0, width_, height_, 145 0, kVideoRotation_0, &video_frame_)); 146 147 denoiser_c.DenoiseFrame(video_frame_, &denoised_frame_c); 148 denoiser_sse_neon.DenoiseFrame(video_frame_, &denoised_frame_sse_neon); 149 150 // Denoising results should be the same for C and SSE/NEON denoiser. 151 ASSERT_EQ(true, denoised_frame_c.EqualsFrame(denoised_frame_sse_neon)); 152 } 153 ASSERT_NE(0, feof(source_file_)) << "Error reading source file"; 154 } 155 156 } // namespace webrtc 157