blob: a45f933bb5425458ae17c0118d833318c3daeb84 [file] [log] [blame]
jackychen67e94fb2016-01-11 21:34:07 -08001/*
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
kwiberge065fcf2016-03-02 01:01:11 -080013#include <memory>
14
jackychen67e94fb2016-01-11 21:34:07 -080015#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
16#include "webrtc/modules/video_processing/include/video_processing.h"
17#include "webrtc/modules/video_processing/test/video_processing_unittest.h"
18#include "webrtc/modules/video_processing/video_denoiser.h"
Niels Möller739fcb92016-02-29 13:11:45 +010019#include "webrtc/test/frame_utils.h"
jackychen67e94fb2016-01-11 21:34:07 -080020
21namespace webrtc {
22
23TEST_F(VideoProcessingTest, CopyMem) {
jackychenfa0befe2016-04-01 07:46:58 -070024 std::unique_ptr<DenoiserFilter> df_c(DenoiserFilter::Create(false, nullptr));
25 std::unique_ptr<DenoiserFilter> df_sse_neon(
26 DenoiserFilter::Create(true, nullptr));
jackychen67e94fb2016-01-11 21:34:07 -080027 uint8_t src[16 * 16], dst[16 * 16];
28 for (int i = 0; i < 16; ++i) {
29 for (int j = 0; j < 16; ++j) {
30 src[i * 16 + j] = i * 16 + j;
31 }
32 }
33
34 memset(dst, 0, 8 * 8);
35 df_c->CopyMem8x8(src, 8, dst, 8);
36 EXPECT_EQ(0, memcmp(src, dst, 8 * 8));
37
38 memset(dst, 0, 16 * 16);
39 df_c->CopyMem16x16(src, 16, dst, 16);
40 EXPECT_EQ(0, memcmp(src, dst, 16 * 16));
41
42 memset(dst, 0, 8 * 8);
43 df_sse_neon->CopyMem16x16(src, 8, dst, 8);
44 EXPECT_EQ(0, memcmp(src, dst, 8 * 8));
45
46 memset(dst, 0, 16 * 16);
47 df_sse_neon->CopyMem16x16(src, 16, dst, 16);
48 EXPECT_EQ(0, memcmp(src, dst, 16 * 16));
49}
50
51TEST_F(VideoProcessingTest, Variance) {
jackychenfa0befe2016-04-01 07:46:58 -070052 std::unique_ptr<DenoiserFilter> df_c(DenoiserFilter::Create(false, nullptr));
53 std::unique_ptr<DenoiserFilter> df_sse_neon(
54 DenoiserFilter::Create(true, nullptr));
jackychen67e94fb2016-01-11 21:34:07 -080055 uint8_t src[16 * 16], dst[16 * 16];
56 uint32_t sum = 0, sse = 0, var;
57 for (int i = 0; i < 16; ++i) {
58 for (int j = 0; j < 16; ++j) {
59 src[i * 16 + j] = i * 16 + j;
60 }
61 }
62 // Compute the 16x8 variance of the 16x16 block.
63 for (int i = 0; i < 8; ++i) {
64 for (int j = 0; j < 16; ++j) {
65 sum += (i * 32 + j);
66 sse += (i * 32 + j) * (i * 32 + j);
67 }
68 }
69 var = sse - ((sum * sum) >> 7);
70 memset(dst, 0, 16 * 16);
71 EXPECT_EQ(var, df_c->Variance16x8(src, 16, dst, 16, &sse));
72 EXPECT_EQ(var, df_sse_neon->Variance16x8(src, 16, dst, 16, &sse));
73}
74
75TEST_F(VideoProcessingTest, MbDenoise) {
jackychenfa0befe2016-04-01 07:46:58 -070076 std::unique_ptr<DenoiserFilter> df_c(DenoiserFilter::Create(false, nullptr));
77 std::unique_ptr<DenoiserFilter> df_sse_neon(
78 DenoiserFilter::Create(true, nullptr));
79 uint8_t running_src[16 * 16], src[16 * 16];
80 uint8_t dst[16 * 16], dst_sse_neon[16 * 16];
jackychen67e94fb2016-01-11 21:34:07 -080081
82 // Test case: |diff| <= |3 + shift_inc1|
83 for (int i = 0; i < 16; ++i) {
84 for (int j = 0; j < 16; ++j) {
85 running_src[i * 16 + j] = i * 11 + j;
86 src[i * 16 + j] = i * 11 + j + 2;
jackychen67e94fb2016-01-11 21:34:07 -080087 }
88 }
89 memset(dst, 0, 16 * 16);
jackychenfa0befe2016-04-01 07:46:58 -070090 df_c->MbDenoise(running_src, 16, dst, 16, src, 16, 0, 1, false);
91 memset(dst_sse_neon, 0, 16 * 16);
92 df_sse_neon->MbDenoise(running_src, 16, dst_sse_neon, 16, src, 16, 0, 1,
93 false);
94 EXPECT_EQ(0, memcmp(dst, dst_sse_neon, 16 * 16));
jackychen67e94fb2016-01-11 21:34:07 -080095
96 // Test case: |diff| >= |4 + shift_inc1|
97 for (int i = 0; i < 16; ++i) {
98 for (int j = 0; j < 16; ++j) {
99 running_src[i * 16 + j] = i * 11 + j;
100 src[i * 16 + j] = i * 11 + j + 5;
jackychen67e94fb2016-01-11 21:34:07 -0800101 }
102 }
103 memset(dst, 0, 16 * 16);
jackychenfa0befe2016-04-01 07:46:58 -0700104 df_c->MbDenoise(running_src, 16, dst, 16, src, 16, 0, 1, false);
105 memset(dst_sse_neon, 0, 16 * 16);
106 df_sse_neon->MbDenoise(running_src, 16, dst_sse_neon, 16, src, 16, 0, 1,
107 false);
108 EXPECT_EQ(0, memcmp(dst, dst_sse_neon, 16 * 16));
jackychen67e94fb2016-01-11 21:34:07 -0800109
110 // Test case: |diff| >= 8
111 for (int i = 0; i < 16; ++i) {
112 for (int j = 0; j < 16; ++j) {
113 running_src[i * 16 + j] = i * 11 + j;
114 src[i * 16 + j] = i * 11 + j + 8;
jackychen67e94fb2016-01-11 21:34:07 -0800115 }
116 }
117 memset(dst, 0, 16 * 16);
jackychenfa0befe2016-04-01 07:46:58 -0700118 df_c->MbDenoise(running_src, 16, dst, 16, src, 16, 0, 1, false);
119 memset(dst_sse_neon, 0, 16 * 16);
120 df_sse_neon->MbDenoise(running_src, 16, dst_sse_neon, 16, src, 16, 0, 1,
121 false);
122 EXPECT_EQ(0, memcmp(dst, dst_sse_neon, 16 * 16));
jackychen67e94fb2016-01-11 21:34:07 -0800123
124 // Test case: |diff| > 15
125 for (int i = 0; i < 16; ++i) {
126 for (int j = 0; j < 16; ++j) {
127 running_src[i * 16 + j] = i * 11 + j;
128 src[i * 16 + j] = i * 11 + j + 16;
129 }
130 }
131 memset(dst, 0, 16 * 16);
132 DenoiserDecision decision =
jackychenfa0befe2016-04-01 07:46:58 -0700133 df_c->MbDenoise(running_src, 16, dst, 16, src, 16, 0, 1, false);
jackychen67e94fb2016-01-11 21:34:07 -0800134 EXPECT_EQ(COPY_BLOCK, decision);
jackychenfa0befe2016-04-01 07:46:58 -0700135 decision =
136 df_sse_neon->MbDenoise(running_src, 16, dst, 16, src, 16, 0, 1, false);
jackychen67e94fb2016-01-11 21:34:07 -0800137 EXPECT_EQ(COPY_BLOCK, decision);
138}
139
140TEST_F(VideoProcessingTest, Denoiser) {
141 // Create pure C denoiser.
142 VideoDenoiser denoiser_c(false);
143 // Create SSE or NEON denoiser.
144 VideoDenoiser denoiser_sse_neon(true);
145 VideoFrame denoised_frame_c;
jackychenfa0befe2016-04-01 07:46:58 -0700146 VideoFrame denoised_frame_track_c;
jackychen67e94fb2016-01-11 21:34:07 -0800147 VideoFrame denoised_frame_sse_neon;
jackychenfa0befe2016-04-01 07:46:58 -0700148 VideoFrame denoised_frame_track_sse_neon;
jackychen67e94fb2016-01-11 21:34:07 -0800149
kwiberge065fcf2016-03-02 01:01:11 -0800150 std::unique_ptr<uint8_t[]> video_buffer(new uint8_t[frame_length_]);
jackychen67e94fb2016-01-11 21:34:07 -0800151 while (fread(video_buffer.get(), 1, frame_length_, source_file_) ==
152 frame_length_) {
153 // Using ConvertToI420 to add stride to the image.
154 EXPECT_EQ(0, ConvertToI420(kI420, video_buffer.get(), 0, 0, width_, height_,
155 0, kVideoRotation_0, &video_frame_));
156
jackychenfa0befe2016-04-01 07:46:58 -0700157 denoiser_c.DenoiseFrame(video_frame_, &denoised_frame_c,
158 &denoised_frame_track_c, -1);
159 denoiser_sse_neon.DenoiseFrame(video_frame_, &denoised_frame_sse_neon,
160 &denoised_frame_track_sse_neon, -1);
jackychen67e94fb2016-01-11 21:34:07 -0800161
162 // Denoising results should be the same for C and SSE/NEON denoiser.
Niels Möller739fcb92016-02-29 13:11:45 +0100163 ASSERT_TRUE(test::FramesEqual(denoised_frame_c, denoised_frame_sse_neon));
jackychen67e94fb2016-01-11 21:34:07 -0800164 }
165 ASSERT_NE(0, feof(source_file_)) << "Error reading source file";
166}
167
168} // namespace webrtc