OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 #include "webrtc/common_video/libyuv/include/scaler.h" | 10 #include "webrtc/common_video/libyuv/include/scaler.h" |
11 #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h" | 11 #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h" |
12 #include "webrtc/modules/video_processing/video_denoiser.h" | 12 #include "webrtc/modules/video_processing/video_denoiser.h" |
13 | 13 |
14 namespace webrtc { | 14 namespace webrtc { |
15 | 15 |
16 VideoDenoiser::VideoDenoiser() | 16 VideoDenoiser::VideoDenoiser() |
17 : width_(0), | 17 : width_(0), height_(0), filter_(DenoiserFilter::Create()) {} |
18 height_(0), | |
19 filter_(DenoiserFilter::Create()) {} | |
20 | 18 |
21 void VideoDenoiser::TrailingReduction(int mb_rows, | 19 void VideoDenoiser::TrailingReduction(int mb_rows, |
22 int mb_cols, | 20 int mb_cols, |
23 const uint8_t* y_src, | 21 const uint8_t* y_src, |
24 int stride_y, | 22 int stride_y, |
25 uint8_t* y_dst) { | 23 uint8_t* y_dst) { |
26 for (int mb_row = 1; mb_row < mb_rows - 1; ++mb_row) { | 24 for (int mb_row = 1; mb_row < mb_rows - 1; ++mb_row) { |
27 for (int mb_col = 1; mb_col < mb_cols - 1; ++mb_col) { | 25 for (int mb_col = 1; mb_col < mb_cols - 1; ++mb_col) { |
28 int mb_index = mb_row * mb_cols + mb_col; | 26 int mb_index = mb_row * mb_cols + mb_col; |
29 uint8_t* mb_dst = y_dst + (mb_row << 4) * stride_y + (mb_col << 4); | 27 uint8_t* mb_dst = y_dst + (mb_row << 4) * stride_y + (mb_col << 4); |
30 const uint8_t* mb_src = y_src + (mb_row << 4) * stride_y + (mb_col << 4); | 28 const uint8_t* mb_src = y_src + (mb_row << 4) * stride_y + (mb_col << 4); |
31 // If the number of denoised neighbors is less than a threshold, | 29 // If the number of denoised neighbors is less than a threshold, |
32 // do NOT denoise for the block. Set different threshold for skin MB. | 30 // do NOT denoise for the block. Set different threshold for skin MB. |
33 // The change of denoising status will not propagate. | 31 // The change of denoising status will not propagate. |
34 if (metrics_[mb_index].is_skin) { | 32 if (metrics_[mb_index].is_skin) { |
35 // The threshold is high (more strict) for non-skin MB where the trailing | 33 // The threshold is high (more strict) for non-skin MB where the |
36 // usually happen. | 34 // trailing |
| 35 // usually happen. |
37 if (metrics_[mb_index].denoise && | 36 if (metrics_[mb_index].denoise && |
38 metrics_[mb_index + 1].denoise + | 37 metrics_[mb_index + 1].denoise + metrics_[mb_index - 1].denoise + |
39 metrics_[mb_index - 1].denoise + | 38 metrics_[mb_index + mb_cols].denoise + |
40 metrics_[mb_index + mb_cols].denoise + | 39 metrics_[mb_index - mb_cols].denoise <= |
41 metrics_[mb_index - mb_cols].denoise <= 2) { | 40 2) { |
42 metrics_[mb_index].denoise = 0; | 41 metrics_[mb_index].denoise = 0; |
43 filter_->CopyMem16x16(mb_src, stride_y, mb_dst, stride_y); | 42 filter_->CopyMem16x16(mb_src, stride_y, mb_dst, stride_y); |
44 } | 43 } |
45 } else if (metrics_[mb_index].denoise && | 44 } else if (metrics_[mb_index].denoise && |
46 metrics_[mb_index + 1].denoise + | 45 metrics_[mb_index + 1].denoise + |
47 metrics_[mb_index - 1].denoise + | 46 metrics_[mb_index - 1].denoise + |
48 metrics_[mb_index + mb_cols + 1].denoise + | 47 metrics_[mb_index + mb_cols + 1].denoise + |
49 metrics_[mb_index + mb_cols - 1].denoise + | 48 metrics_[mb_index + mb_cols - 1].denoise + |
50 metrics_[mb_index - mb_cols + 1].denoise + | 49 metrics_[mb_index - mb_cols + 1].denoise + |
51 metrics_[mb_index - mb_cols - 1].denoise + | 50 metrics_[mb_index - mb_cols - 1].denoise + |
52 metrics_[mb_index + mb_cols].denoise + | 51 metrics_[mb_index + mb_cols].denoise + |
53 metrics_[mb_index - mb_cols].denoise <= 7) { | 52 metrics_[mb_index - mb_cols].denoise <= |
| 53 7) { |
54 filter_->CopyMem16x16(mb_src, stride_y, mb_dst, stride_y); | 54 filter_->CopyMem16x16(mb_src, stride_y, mb_dst, stride_y); |
55 } | 55 } |
56 } | 56 } |
57 } | 57 } |
58 } | 58 } |
59 | 59 |
60 void VideoDenoiser::DenoiseFrame(const VideoFrame& frame, | 60 void VideoDenoiser::DenoiseFrame(const VideoFrame& frame, |
61 VideoFrame* denoised_frame) { | 61 VideoFrame* denoised_frame) { |
62 int stride_y = frame.stride(kYPlane); | 62 int stride_y = frame.stride(kYPlane); |
63 int stride_u = frame.stride(kUPlane); | 63 int stride_u = frame.stride(kUPlane); |
(...skipping 20 matching lines...) Expand all Loading... |
84 uint8_t* y_dst = denoised_frame->buffer(kYPlane); | 84 uint8_t* y_dst = denoised_frame->buffer(kYPlane); |
85 uint8_t* u_dst = denoised_frame->buffer(kUPlane); | 85 uint8_t* u_dst = denoised_frame->buffer(kUPlane); |
86 uint8_t* v_dst = denoised_frame->buffer(kVPlane); | 86 uint8_t* v_dst = denoised_frame->buffer(kVPlane); |
87 const uint8_t* y_src = frame.buffer(kYPlane); | 87 const uint8_t* y_src = frame.buffer(kYPlane); |
88 const uint8_t* u_src = frame.buffer(kUPlane); | 88 const uint8_t* u_src = frame.buffer(kUPlane); |
89 const uint8_t* v_src = frame.buffer(kVPlane); | 89 const uint8_t* v_src = frame.buffer(kVPlane); |
90 // Temporary buffer to store denoising result. | 90 // Temporary buffer to store denoising result. |
91 uint8_t y_tmp[16 * 16] = {0}; | 91 uint8_t y_tmp[16 * 16] = {0}; |
92 for (int mb_row = 0; mb_row < mb_rows; ++mb_row) { | 92 for (int mb_row = 0; mb_row < mb_rows; ++mb_row) { |
93 for (int mb_col = 0; mb_col < mb_cols; ++mb_col) { | 93 for (int mb_col = 0; mb_col < mb_cols; ++mb_col) { |
94 const uint8_t* mb_src = | 94 const uint8_t* mb_src = y_src + (mb_row << 4) * stride_y + (mb_col << 4); |
95 y_src + (mb_row << 4) * stride_y + (mb_col << 4); | |
96 uint8_t* mb_dst = y_dst + (mb_row << 4) * stride_y + (mb_col << 4); | 95 uint8_t* mb_dst = y_dst + (mb_row << 4) * stride_y + (mb_col << 4); |
97 int mb_index = mb_row * mb_cols + mb_col; | 96 int mb_index = mb_row * mb_cols + mb_col; |
98 // Denoise each MB at the very start and save the result to a temporary | 97 // Denoise each MB at the very start and save the result to a temporary |
99 // buffer. | 98 // buffer. |
100 if (filter_->MbDenoise( | 99 if (filter_->MbDenoise(mb_dst, stride_y, y_tmp, 16, mb_src, stride_y, 0, |
101 mb_dst, stride_y, y_tmp, 16, mb_src, stride_y, 0, 1) == | 100 1) == FILTER_BLOCK) { |
102 FILTER_BLOCK) { | |
103 uint32_t thr_var = 0; | 101 uint32_t thr_var = 0; |
104 // Save var and sad to the buffer. | 102 // Save var and sad to the buffer. |
105 metrics_[mb_index].var = filter_->Variance16x8( | 103 metrics_[mb_index].var = filter_->Variance16x8( |
106 mb_dst, stride_y, y_tmp, 16, &metrics_[mb_index].sad); | 104 mb_dst, stride_y, y_tmp, 16, &metrics_[mb_index].sad); |
107 // Get skin map. | 105 // Get skin map. |
108 metrics_[mb_index].is_skin = | 106 metrics_[mb_index].is_skin = MbHasSkinColor( |
109 MbHasSkinColor(y_src, u_src, v_src, stride_y, stride_u, stride_v, | 107 y_src, u_src, v_src, stride_y, stride_u, stride_v, mb_row, mb_col); |
110 mb_row, mb_col); | |
111 // Variance threshold for skin/non-skin MB is different. | 108 // Variance threshold for skin/non-skin MB is different. |
112 // Skin MB use a small threshold to reduce blockiness. | 109 // Skin MB use a small threshold to reduce blockiness. |
113 thr_var = metrics_[mb_index].is_skin ? 128 : 12 * 128; | 110 thr_var = metrics_[mb_index].is_skin ? 128 : 12 * 128; |
114 if (metrics_[mb_index].var > thr_var) { | 111 if (metrics_[mb_index].var > thr_var) { |
115 metrics_[mb_index].denoise = 0; | 112 metrics_[mb_index].denoise = 0; |
116 // Use the source MB. | 113 // Use the source MB. |
117 filter_->CopyMem16x16(mb_src, stride_y, mb_dst, stride_y); | 114 filter_->CopyMem16x16(mb_src, stride_y, mb_dst, stride_y); |
118 } else { | 115 } else { |
119 metrics_[mb_index].denoise = 1; | 116 metrics_[mb_index].denoise = 1; |
120 // Use the denoised MB. | 117 // Use the denoised MB. |
(...skipping 19 matching lines...) Expand all Loading... |
140 // neighbors' denoising status. | 137 // neighbors' denoising status. |
141 TrailingReduction(mb_rows, mb_cols, y_src, stride_y, y_dst); | 138 TrailingReduction(mb_rows, mb_cols, y_src, stride_y, y_dst); |
142 | 139 |
143 // Setting time parameters to the output frame. | 140 // Setting time parameters to the output frame. |
144 denoised_frame->set_timestamp(frame.timestamp()); | 141 denoised_frame->set_timestamp(frame.timestamp()); |
145 denoised_frame->set_render_time_ms(frame.render_time_ms()); | 142 denoised_frame->set_render_time_ms(frame.render_time_ms()); |
146 return; | 143 return; |
147 } | 144 } |
148 | 145 |
149 } // namespace webrtc | 146 } // namespace webrtc |
OLD | NEW |