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 usually happen. |
37 if (metrics_[mb_index].denoise && | 35 if (metrics_[mb_index].denoise && |
38 metrics_[mb_index + 1].denoise + | 36 metrics_[mb_index + 1].denoise + metrics_[mb_index - 1].denoise + |
39 metrics_[mb_index - 1].denoise + | 37 metrics_[mb_index + mb_cols].denoise + |
40 metrics_[mb_index + mb_cols].denoise + | 38 metrics_[mb_index - mb_cols].denoise <= |
41 metrics_[mb_index - mb_cols].denoise <= 2) { | 39 2) { |
42 metrics_[mb_index].denoise = 0; | 40 metrics_[mb_index].denoise = 0; |
43 filter_->CopyMem16x16(mb_src, stride_y, mb_dst, stride_y); | 41 filter_->CopyMem16x16(mb_src, stride_y, mb_dst, stride_y); |
44 } | 42 } |
45 } else if (metrics_[mb_index].denoise && | 43 } else if (metrics_[mb_index].denoise && |
46 metrics_[mb_index + 1].denoise + | 44 metrics_[mb_index + 1].denoise + |
47 metrics_[mb_index - 1].denoise + | 45 metrics_[mb_index - 1].denoise + |
48 metrics_[mb_index + mb_cols + 1].denoise + | 46 metrics_[mb_index + mb_cols + 1].denoise + |
49 metrics_[mb_index + mb_cols - 1].denoise + | 47 metrics_[mb_index + mb_cols - 1].denoise + |
50 metrics_[mb_index - mb_cols + 1].denoise + | 48 metrics_[mb_index - mb_cols + 1].denoise + |
51 metrics_[mb_index - mb_cols - 1].denoise + | 49 metrics_[mb_index - mb_cols - 1].denoise + |
52 metrics_[mb_index + mb_cols].denoise + | 50 metrics_[mb_index + mb_cols].denoise + |
53 metrics_[mb_index - mb_cols].denoise <= 7) { | 51 metrics_[mb_index - mb_cols].denoise <= |
| 52 7) { |
54 filter_->CopyMem16x16(mb_src, stride_y, mb_dst, stride_y); | 53 filter_->CopyMem16x16(mb_src, stride_y, mb_dst, stride_y); |
55 } | 54 } |
56 } | 55 } |
57 } | 56 } |
58 } | 57 } |
59 | 58 |
60 void VideoDenoiser::DenoiseFrame(const VideoFrame& frame, | 59 void VideoDenoiser::DenoiseFrame(const VideoFrame& frame, |
61 VideoFrame* denoised_frame) { | 60 VideoFrame* denoised_frame) { |
62 int stride_y = frame.stride(kYPlane); | 61 int stride_y = frame.stride(kYPlane); |
63 int stride_u = frame.stride(kUPlane); | 62 int stride_u = frame.stride(kUPlane); |
(...skipping 20 matching lines...) Expand all Loading... |
84 uint8_t* y_dst = denoised_frame->buffer(kYPlane); | 83 uint8_t* y_dst = denoised_frame->buffer(kYPlane); |
85 uint8_t* u_dst = denoised_frame->buffer(kUPlane); | 84 uint8_t* u_dst = denoised_frame->buffer(kUPlane); |
86 uint8_t* v_dst = denoised_frame->buffer(kVPlane); | 85 uint8_t* v_dst = denoised_frame->buffer(kVPlane); |
87 const uint8_t* y_src = frame.buffer(kYPlane); | 86 const uint8_t* y_src = frame.buffer(kYPlane); |
88 const uint8_t* u_src = frame.buffer(kUPlane); | 87 const uint8_t* u_src = frame.buffer(kUPlane); |
89 const uint8_t* v_src = frame.buffer(kVPlane); | 88 const uint8_t* v_src = frame.buffer(kVPlane); |
90 // Temporary buffer to store denoising result. | 89 // Temporary buffer to store denoising result. |
91 uint8_t y_tmp[16 * 16] = {0}; | 90 uint8_t y_tmp[16 * 16] = {0}; |
92 for (int mb_row = 0; mb_row < mb_rows; ++mb_row) { | 91 for (int mb_row = 0; mb_row < mb_rows; ++mb_row) { |
93 for (int mb_col = 0; mb_col < mb_cols; ++mb_col) { | 92 for (int mb_col = 0; mb_col < mb_cols; ++mb_col) { |
94 const uint8_t* mb_src = | 93 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); | 94 uint8_t* mb_dst = y_dst + (mb_row << 4) * stride_y + (mb_col << 4); |
97 int mb_index = mb_row * mb_cols + mb_col; | 95 int mb_index = mb_row * mb_cols + mb_col; |
98 // Denoise each MB at the very start and save the result to a temporary | 96 // Denoise each MB at the very start and save the result to a temporary |
99 // buffer. | 97 // buffer. |
100 if (filter_->MbDenoise( | 98 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) == | 99 1) == FILTER_BLOCK) { |
102 FILTER_BLOCK) { | |
103 uint32_t thr_var = 0; | 100 uint32_t thr_var = 0; |
104 // Save var and sad to the buffer. | 101 // Save var and sad to the buffer. |
105 metrics_[mb_index].var = filter_->Variance16x8( | 102 metrics_[mb_index].var = filter_->Variance16x8( |
106 mb_dst, stride_y, y_tmp, 16, &metrics_[mb_index].sad); | 103 mb_dst, stride_y, y_tmp, 16, &metrics_[mb_index].sad); |
107 // Get skin map. | 104 // Get skin map. |
108 metrics_[mb_index].is_skin = | 105 metrics_[mb_index].is_skin = MbHasSkinColor( |
109 MbHasSkinColor(y_src, u_src, v_src, stride_y, stride_u, stride_v, | 106 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. | 107 // Variance threshold for skin/non-skin MB is different. |
112 // Skin MB use a small threshold to reduce blockiness. | 108 // Skin MB use a small threshold to reduce blockiness. |
113 thr_var = metrics_[mb_index].is_skin ? 128 : 12 * 128; | 109 thr_var = metrics_[mb_index].is_skin ? 128 : 12 * 128; |
114 if (metrics_[mb_index].var > thr_var) { | 110 if (metrics_[mb_index].var > thr_var) { |
115 metrics_[mb_index].denoise = 0; | 111 metrics_[mb_index].denoise = 0; |
116 // Use the source MB. | 112 // Use the source MB. |
117 filter_->CopyMem16x16(mb_src, stride_y, mb_dst, stride_y); | 113 filter_->CopyMem16x16(mb_src, stride_y, mb_dst, stride_y); |
118 } else { | 114 } else { |
119 metrics_[mb_index].denoise = 1; | 115 metrics_[mb_index].denoise = 1; |
120 // Use the denoised MB. | 116 // Use the denoised MB. |
(...skipping 19 matching lines...) Expand all Loading... |
140 // neighbors' denoising status. | 136 // neighbors' denoising status. |
141 TrailingReduction(mb_rows, mb_cols, y_src, stride_y, y_dst); | 137 TrailingReduction(mb_rows, mb_cols, y_src, stride_y, y_dst); |
142 | 138 |
143 // Setting time parameters to the output frame. | 139 // Setting time parameters to the output frame. |
144 denoised_frame->set_timestamp(frame.timestamp()); | 140 denoised_frame->set_timestamp(frame.timestamp()); |
145 denoised_frame->set_render_time_ms(frame.render_time_ms()); | 141 denoised_frame->set_render_time_ms(frame.render_time_ms()); |
146 return; | 142 return; |
147 } | 143 } |
148 | 144 |
149 } // namespace webrtc | 145 } // namespace webrtc |
OLD | NEW |