| 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 | 10 |
| 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 #include "libyuv/planar_functions.h" |
| 13 | 14 |
| 14 namespace webrtc { | 15 namespace webrtc { |
| 15 | 16 |
| 16 #if DISPLAY || DISPLAYNEON | 17 #if DISPLAY || DISPLAYNEON |
| 17 static void CopyMem8x8(const uint8_t* src, | 18 static void CopyMem8x8(const uint8_t* src, |
| 18 int src_stride, | 19 int src_stride, |
| 19 uint8_t* dst, | 20 uint8_t* dst, |
| 20 int dst_stride) { | 21 int dst_stride) { |
| 21 for (int i = 0; i < 8; i++) { | 22 for (int i = 0; i < 8; i++) { |
| 22 memcpy(dst, src, 8); | 23 memcpy(dst, src, 8); |
| 23 src += src_stride; | 24 src += src_stride; |
| 24 dst += dst_stride; | 25 dst += dst_stride; |
| 25 } | 26 } |
| 26 } | 27 } |
| 27 | 28 |
| 28 static void ShowRect(const std::unique_ptr<DenoiserFilter>& filter, | 29 static void ShowRect(const std::unique_ptr<DenoiserFilter>& filter, |
| 29 const std::unique_ptr<uint8_t[]>& d_status, | 30 const std::unique_ptr<uint8_t[]>& d_status, |
| 30 const std::unique_ptr<uint8_t[]>& moving_edge_red, | 31 const std::unique_ptr<uint8_t[]>& moving_edge_red, |
| 31 const std::unique_ptr<uint8_t[]>& x_density, | 32 const std::unique_ptr<uint8_t[]>& x_density, |
| 32 const std::unique_ptr<uint8_t[]>& y_density, | 33 const std::unique_ptr<uint8_t[]>& y_density, |
| 33 const uint8_t* u_src, | 34 const uint8_t* u_src, int stride_u_src, |
| 34 const uint8_t* v_src, | 35 const uint8_t* v_src, int stride_v_src, |
| 35 uint8_t* u_dst, | 36 uint8_t* u_dst, int stride_u_dst, |
| 36 uint8_t* v_dst, | 37 uint8_t* v_dst, int stride_v_dst, |
| 37 int mb_rows_, | 38 int mb_rows_, |
| 38 int mb_cols_, | 39 int mb_cols_) { |
| 39 int stride_u_, | |
| 40 int stride_v_) { | |
| 41 for (int mb_row = 0; mb_row < mb_rows_; ++mb_row) { | 40 for (int mb_row = 0; mb_row < mb_rows_; ++mb_row) { |
| 42 for (int mb_col = 0; mb_col < mb_cols_; ++mb_col) { | 41 for (int mb_col = 0; mb_col < mb_cols_; ++mb_col) { |
| 43 int mb_index = mb_row * mb_cols_ + mb_col; | 42 int mb_index = mb_row * mb_cols_ + mb_col; |
| 44 const uint8_t* mb_src_u = | 43 const uint8_t* mb_src_u = |
| 45 u_src + (mb_row << 3) * stride_u_ + (mb_col << 3); | 44 u_src + (mb_row << 3) * stride_u_src + (mb_col << 3); |
| 46 const uint8_t* mb_src_v = | 45 const uint8_t* mb_src_v = |
| 47 v_src + (mb_row << 3) * stride_v_ + (mb_col << 3); | 46 v_src + (mb_row << 3) * stride_v_src + (mb_col << 3); |
| 48 uint8_t* mb_dst_u = u_dst + (mb_row << 3) * stride_u_ + (mb_col << 3); | 47 uint8_t* mb_dst_u = u_dst + (mb_row << 3) * stride_u_dst + (mb_col << 3); |
| 49 uint8_t* mb_dst_v = v_dst + (mb_row << 3) * stride_v_ + (mb_col << 3); | 48 uint8_t* mb_dst_v = v_dst + (mb_row << 3) * stride_v_dst + (mb_col << 3); |
| 50 uint8_t uv_tmp[8 * 8]; | 49 uint8_t uv_tmp[8 * 8]; |
| 51 memset(uv_tmp, 200, 8 * 8); | 50 memset(uv_tmp, 200, 8 * 8); |
| 52 if (d_status[mb_index] == 1) { | 51 if (d_status[mb_index] == 1) { |
| 53 // Paint to red. | 52 // Paint to red. |
| 54 CopyMem8x8(mb_src_u, stride_u_, mb_dst_u, stride_u_); | 53 CopyMem8x8(mb_src_u, stride_u_src, mb_dst_u, stride_u_dst); |
| 55 CopyMem8x8(uv_tmp, 8, mb_dst_v, stride_v_); | 54 CopyMem8x8(uv_tmp, 8, mb_dst_v, stride_v_dst); |
| 56 } else if (moving_edge_red[mb_row * mb_cols_ + mb_col] && | 55 } else if (moving_edge_red[mb_row * mb_cols_ + mb_col] && |
| 57 x_density[mb_col] * y_density[mb_row]) { | 56 x_density[mb_col] * y_density[mb_row]) { |
| 58 // Paint to blue. | 57 // Paint to blue. |
| 59 CopyMem8x8(uv_tmp, 8, mb_dst_u, stride_u_); | 58 CopyMem8x8(uv_tmp, 8, mb_dst_u, stride_u_dst); |
| 60 CopyMem8x8(mb_src_v, stride_v_, mb_dst_v, stride_v_); | 59 CopyMem8x8(mb_src_v, stride_v_src, mb_dst_v, stride_v_dst); |
| 61 } else { | 60 } else { |
| 62 CopyMem8x8(mb_src_u, stride_u_, mb_dst_u, stride_u_); | 61 CopyMem8x8(mb_src_u, stride_u_src, mb_dst_u, stride_u_dst); |
| 63 CopyMem8x8(mb_src_v, stride_v_, mb_dst_v, stride_v_); | 62 CopyMem8x8(mb_src_v, stride_v_src, mb_dst_v, stride_v_dst); |
| 64 } | 63 } |
| 65 } | 64 } |
| 66 } | 65 } |
| 67 } | 66 } |
| 68 #endif | 67 #endif |
| 69 | 68 |
| 70 VideoDenoiser::VideoDenoiser(bool runtime_cpu_detection) | 69 VideoDenoiser::VideoDenoiser(bool runtime_cpu_detection) |
| 71 : width_(0), | 70 : width_(0), |
| 72 height_(0), | 71 height_(0), |
| 73 filter_(DenoiserFilter::Create(runtime_cpu_detection, &cpu_type_)), | 72 filter_(DenoiserFilter::Create(runtime_cpu_detection, &cpu_type_)), |
| 74 ne_(new NoiseEstimation()) {} | 73 ne_(new NoiseEstimation()) {} |
| 75 | 74 |
| 76 void VideoDenoiser::DenoiserReset( | 75 void VideoDenoiser::DenoiserReset(rtc::scoped_refptr<VideoFrameBuffer> frame) { |
| 77 const rtc::scoped_refptr<VideoFrameBuffer>& frame, | |
| 78 rtc::scoped_refptr<I420Buffer>* denoised_frame, | |
| 79 rtc::scoped_refptr<I420Buffer>* denoised_frame_prev) { | |
| 80 width_ = frame->width(); | 76 width_ = frame->width(); |
| 81 height_ = frame->height(); | 77 height_ = frame->height(); |
| 82 mb_cols_ = width_ >> 4; | 78 mb_cols_ = width_ >> 4; |
| 83 mb_rows_ = height_ >> 4; | 79 mb_rows_ = height_ >> 4; |
| 84 stride_y_ = frame->StrideY(); | |
| 85 stride_u_ = frame->StrideU(); | |
| 86 stride_v_ = frame->StrideV(); | |
| 87 | |
| 88 // Allocate an empty buffer for denoised_frame_prev. | |
| 89 *denoised_frame_prev = I420Buffer::Create( | |
| 90 width_, height_, stride_y_, stride_u_, stride_v_); | |
| 91 // Allocate and initialize denoised_frame with key frame. | |
| 92 *denoised_frame = I420Buffer::CopyKeepStride(frame); | |
| 93 | 80 |
| 94 // Init noise estimator and allocate buffers. | 81 // Init noise estimator and allocate buffers. |
| 95 ne_->Init(width_, height_, cpu_type_); | 82 ne_->Init(width_, height_, cpu_type_); |
| 96 moving_edge_.reset(new uint8_t[mb_cols_ * mb_rows_]); | 83 moving_edge_.reset(new uint8_t[mb_cols_ * mb_rows_]); |
| 97 mb_filter_decision_.reset(new DenoiserDecision[mb_cols_ * mb_rows_]); | 84 mb_filter_decision_.reset(new DenoiserDecision[mb_cols_ * mb_rows_]); |
| 98 x_density_.reset(new uint8_t[mb_cols_]); | 85 x_density_.reset(new uint8_t[mb_cols_]); |
| 99 y_density_.reset(new uint8_t[mb_rows_]); | 86 y_density_.reset(new uint8_t[mb_rows_]); |
| 100 moving_object_.reset(new uint8_t[mb_cols_ * mb_rows_]); | 87 moving_object_.reset(new uint8_t[mb_cols_ * mb_rows_]); |
| 101 } | 88 } |
| 102 | 89 |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 169 bool ret = false; | 156 bool ret = false; |
| 170 int mb_index = mb_row * mb_cols_ + mb_col; | 157 int mb_index = mb_row * mb_cols_ + mb_col; |
| 171 if (!mb_row || !mb_col || mb_row == mb_rows_ - 1 || mb_col == mb_cols_ - 1) | 158 if (!mb_row || !mb_col || mb_row == mb_rows_ - 1 || mb_col == mb_cols_ - 1) |
| 172 ret = false; | 159 ret = false; |
| 173 else | 160 else |
| 174 ret = d_status[mb_index + 1] || d_status[mb_index - 1] || | 161 ret = d_status[mb_index + 1] || d_status[mb_index - 1] || |
| 175 d_status[mb_index + mb_cols_] || d_status[mb_index - mb_cols_]; | 162 d_status[mb_index + mb_cols_] || d_status[mb_index - mb_cols_]; |
| 176 return ret; | 163 return ret; |
| 177 } | 164 } |
| 178 | 165 |
| 179 void VideoDenoiser::CopySrcOnMOB(const uint8_t* y_src, uint8_t* y_dst) { | 166 void VideoDenoiser::CopySrcOnMOB(const uint8_t* y_src, |
| 167 int stride_src, |
| 168 uint8_t* y_dst, |
| 169 int stride_dst) { |
| 180 // Loop over to copy src block if the block is marked as moving object block | 170 // Loop over to copy src block if the block is marked as moving object block |
| 181 // or if the block may cause trailing artifacts. | 171 // or if the block may cause trailing artifacts. |
| 182 for (int mb_row = 0; mb_row < mb_rows_; ++mb_row) { | 172 for (int mb_row = 0; mb_row < mb_rows_; ++mb_row) { |
| 183 const int mb_index_base = mb_row * mb_cols_; | 173 const int mb_index_base = mb_row * mb_cols_; |
| 184 const int offset_base = (mb_row << 4) * stride_y_; | 174 const uint8_t* mb_src_base = y_src + (mb_row << 4) * stride_src; |
| 185 const uint8_t* mb_src_base = y_src + offset_base; | 175 uint8_t* mb_dst_base = y_dst + (mb_row << 4) * stride_dst; |
| 186 uint8_t* mb_dst_base = y_dst + offset_base; | |
| 187 for (int mb_col = 0; mb_col < mb_cols_; ++mb_col) { | 176 for (int mb_col = 0; mb_col < mb_cols_; ++mb_col) { |
| 188 const int mb_index = mb_index_base + mb_col; | 177 const int mb_index = mb_index_base + mb_col; |
| 189 const uint32_t offset_col = mb_col << 4; | 178 const uint32_t offset_col = mb_col << 4; |
| 190 const uint8_t* mb_src = mb_src_base + offset_col; | 179 const uint8_t* mb_src = mb_src_base + offset_col; |
| 191 uint8_t* mb_dst = mb_dst_base + offset_col; | 180 uint8_t* mb_dst = mb_dst_base + offset_col; |
| 192 // Check if the block is a moving object block or may cause a trailing | 181 // Check if the block is a moving object block or may cause a trailing |
| 193 // artifacts. | 182 // artifacts. |
| 194 if (mb_filter_decision_[mb_index] != FILTER_BLOCK || | 183 if (mb_filter_decision_[mb_index] != FILTER_BLOCK || |
| 195 IsTrailingBlock(moving_edge_, mb_row, mb_col) || | 184 IsTrailingBlock(moving_edge_, mb_row, mb_col) || |
| 196 (x_density_[mb_col] * y_density_[mb_row] && | 185 (x_density_[mb_col] * y_density_[mb_row] && |
| 197 moving_object_[mb_row * mb_cols_ + mb_col])) { | 186 moving_object_[mb_row * mb_cols_ + mb_col])) { |
| 198 // Copy y source. | 187 // Copy y source. |
| 199 filter_->CopyMem16x16(mb_src, stride_y_, mb_dst, stride_y_); | 188 filter_->CopyMem16x16(mb_src, stride_src, mb_dst, stride_dst); |
| 200 } | 189 } |
| 201 } | 190 } |
| 202 } | 191 } |
| 203 } | 192 } |
| 204 | 193 |
| 205 void VideoDenoiser::CopyLumaOnMargin(const uint8_t* y_src, uint8_t* y_dst) { | 194 void VideoDenoiser::CopyLumaOnMargin(const uint8_t* y_src, |
| 206 if ((mb_rows_ << 4) != height_) { | 195 int stride_src, |
| 207 const uint8_t* margin_y_src = y_src + (mb_rows_ << 4) * stride_y_; | 196 uint8_t* y_dst, |
| 208 uint8_t* margin_y_dst = y_dst + (mb_rows_ << 4) * stride_y_; | 197 int stride_dst) { |
| 209 memcpy(margin_y_dst, margin_y_src, (height_ - (mb_rows_ << 4)) * stride_y_); | 198 int height_margin = height_ - (mb_rows_ << 4); |
| 199 if (height_margin > 0) { |
| 200 const uint8_t* margin_y_src = y_src + (mb_rows_ << 4) * stride_src; |
| 201 uint8_t* margin_y_dst = y_dst + (mb_rows_ << 4) * stride_dst; |
| 202 libyuv::CopyPlane(margin_y_src, stride_src, margin_y_dst, stride_dst, |
| 203 width_, height_margin); |
| 210 } | 204 } |
| 211 if ((mb_cols_ << 4) != width_) { | 205 int width_margin = width_ - (mb_cols_ << 4); |
| 206 if (width_margin > 0) { |
| 212 const uint8_t* margin_y_src = y_src + (mb_cols_ << 4); | 207 const uint8_t* margin_y_src = y_src + (mb_cols_ << 4); |
| 213 uint8_t* margin_y_dst = y_dst + (mb_cols_ << 4); | 208 uint8_t* margin_y_dst = y_dst + (mb_cols_ << 4); |
| 214 for (int i = 0; i < height_; ++i) { | 209 libyuv::CopyPlane(margin_y_src, stride_src, margin_y_dst, stride_dst, |
| 215 for (int j = mb_cols_ << 4; j < width_; ++j) { | 210 width_ - (mb_cols_ << 4), mb_rows_ << 4); |
| 216 margin_y_dst[i * stride_y_ + j] = margin_y_src[i * stride_y_ + j]; | |
| 217 } | |
| 218 } | |
| 219 } | 211 } |
| 220 } | 212 } |
| 221 | 213 |
| 222 void VideoDenoiser::DenoiseFrame( | 214 rtc::scoped_refptr<VideoFrameBuffer> VideoDenoiser::DenoiseFrame( |
| 223 const rtc::scoped_refptr<VideoFrameBuffer>& frame, | 215 rtc::scoped_refptr<VideoFrameBuffer> frame, |
| 224 rtc::scoped_refptr<I420Buffer>* denoised_frame, | |
| 225 rtc::scoped_refptr<I420Buffer>* denoised_frame_prev, | |
| 226 bool noise_estimation_enabled) { | 216 bool noise_estimation_enabled) { |
| 227 // If previous width and height are different from current frame's, need to | 217 // If previous width and height are different from current frame's, need to |
| 228 // reallocate the buffers and no denoising for the current frame. | 218 // reallocate the buffers and no denoising for the current frame. |
| 229 if (width_ != frame->width() || height_ != frame->height()) { | 219 if (!prev_buffer_ || width_ != frame->width() || height_ != frame->height()) { |
| 230 DenoiserReset(frame, denoised_frame, denoised_frame_prev); | 220 DenoiserReset(frame); |
| 231 return; | 221 prev_buffer_ = frame; |
| 222 return frame; |
| 232 } | 223 } |
| 233 | 224 |
| 234 // Set buffer pointers. | 225 // Set buffer pointers. |
| 235 const uint8_t* y_src = frame->DataY(); | 226 const uint8_t* y_src = frame->DataY(); |
| 236 const uint8_t* u_src = frame->DataU(); | 227 int stride_y_src = frame->StrideY(); |
| 237 const uint8_t* v_src = frame->DataV(); | 228 rtc::scoped_refptr<I420Buffer> dst = |
| 238 uint8_t* y_dst = (*denoised_frame)->MutableDataY(); | 229 buffer_pool_.CreateBuffer(width_, height_); |
| 239 uint8_t* u_dst = (*denoised_frame)->MutableDataU(); | 230 |
| 240 uint8_t* v_dst = (*denoised_frame)->MutableDataV(); | 231 uint8_t* y_dst = dst->MutableDataY(); |
| 241 uint8_t* y_dst_prev = (*denoised_frame_prev)->MutableDataY(); | 232 int stride_y_dst = dst->StrideY(); |
| 233 |
| 234 const uint8_t* y_dst_prev = prev_buffer_->DataY(); |
| 235 int stride_prev = prev_buffer_->StrideY(); |
| 236 |
| 242 memset(x_density_.get(), 0, mb_cols_); | 237 memset(x_density_.get(), 0, mb_cols_); |
| 243 memset(y_density_.get(), 0, mb_rows_); | 238 memset(y_density_.get(), 0, mb_rows_); |
| 244 memset(moving_object_.get(), 1, mb_cols_ * mb_rows_); | 239 memset(moving_object_.get(), 1, mb_cols_ * mb_rows_); |
| 245 | 240 |
| 246 uint8_t noise_level = noise_estimation_enabled ? ne_->GetNoiseLevel() : 0; | 241 uint8_t noise_level = noise_estimation_enabled ? ne_->GetNoiseLevel() : 0; |
| 247 int thr_var_base = 16 * 16 * 2; | 242 int thr_var_base = 16 * 16 * 2; |
| 248 // Loop over blocks to accumulate/extract noise level and update x/y_density | 243 // Loop over blocks to accumulate/extract noise level and update x/y_density |
| 249 // factors for moving object detection. | 244 // factors for moving object detection. |
| 250 for (int mb_row = 0; mb_row < mb_rows_; ++mb_row) { | 245 for (int mb_row = 0; mb_row < mb_rows_; ++mb_row) { |
| 251 const int mb_index_base = mb_row * mb_cols_; | 246 const int mb_index_base = mb_row * mb_cols_; |
| 252 const int offset_base = (mb_row << 4) * stride_y_; | 247 const uint8_t* mb_src_base = y_src + (mb_row << 4) * stride_y_src; |
| 253 const uint8_t* mb_src_base = y_src + offset_base; | 248 uint8_t* mb_dst_base = y_dst + (mb_row << 4) * stride_y_dst; |
| 254 uint8_t* mb_dst_base = y_dst + offset_base; | 249 const uint8_t* mb_dst_prev_base = y_dst_prev + (mb_row << 4) * stride_prev; |
| 255 uint8_t* mb_dst_prev_base = y_dst_prev + offset_base; | |
| 256 for (int mb_col = 0; mb_col < mb_cols_; ++mb_col) { | 250 for (int mb_col = 0; mb_col < mb_cols_; ++mb_col) { |
| 257 const int mb_index = mb_index_base + mb_col; | 251 const int mb_index = mb_index_base + mb_col; |
| 258 const bool ne_enable = (mb_index % NOISE_SUBSAMPLE_INTERVAL == 0); | 252 const bool ne_enable = (mb_index % NOISE_SUBSAMPLE_INTERVAL == 0); |
| 259 const int pos_factor = PositionCheck(mb_row, mb_col, noise_level); | 253 const int pos_factor = PositionCheck(mb_row, mb_col, noise_level); |
| 260 const uint32_t thr_var_adp = thr_var_base * pos_factor; | 254 const uint32_t thr_var_adp = thr_var_base * pos_factor; |
| 261 const uint32_t offset_col = mb_col << 4; | 255 const uint32_t offset_col = mb_col << 4; |
| 262 const uint8_t* mb_src = mb_src_base + offset_col; | 256 const uint8_t* mb_src = mb_src_base + offset_col; |
| 263 uint8_t* mb_dst = mb_dst_base + offset_col; | 257 uint8_t* mb_dst = mb_dst_base + offset_col; |
| 264 uint8_t* mb_dst_prev = mb_dst_prev_base + offset_col; | 258 const uint8_t* mb_dst_prev = mb_dst_prev_base + offset_col; |
| 265 | 259 |
| 266 // TODO(jackychen): Need SSE2/NEON opt. | 260 // TODO(jackychen): Need SSE2/NEON opt. |
| 267 int luma = 0; | 261 int luma = 0; |
| 268 if (ne_enable) { | 262 if (ne_enable) { |
| 269 for (int i = 4; i < 12; ++i) { | 263 for (int i = 4; i < 12; ++i) { |
| 270 for (int j = 4; j < 12; ++j) { | 264 for (int j = 4; j < 12; ++j) { |
| 271 luma += mb_src[i * stride_y_ + j]; | 265 luma += mb_src[i * stride_y_src + j]; |
| 272 } | 266 } |
| 273 } | 267 } |
| 274 } | 268 } |
| 275 | 269 |
| 276 // Get the filtered block and filter_decision. | 270 // Get the filtered block and filter_decision. |
| 277 mb_filter_decision_[mb_index] = | 271 mb_filter_decision_[mb_index] = |
| 278 filter_->MbDenoise(mb_dst_prev, stride_y_, mb_dst, stride_y_, mb_src, | 272 filter_->MbDenoise(mb_dst_prev, stride_prev, mb_dst, stride_y_dst, |
| 279 stride_y_, 0, noise_level); | 273 mb_src, stride_y_src, 0, noise_level); |
| 280 | 274 |
| 281 // If filter decision is FILTER_BLOCK, no need to check moving edge. | 275 // If filter decision is FILTER_BLOCK, no need to check moving edge. |
| 282 // It is unlikely for a moving edge block to be filtered in current | 276 // It is unlikely for a moving edge block to be filtered in current |
| 283 // setting. | 277 // setting. |
| 284 if (mb_filter_decision_[mb_index] == FILTER_BLOCK) { | 278 if (mb_filter_decision_[mb_index] == FILTER_BLOCK) { |
| 285 uint32_t sse_t = 0; | 279 uint32_t sse_t = 0; |
| 286 if (ne_enable) { | 280 if (ne_enable) { |
| 287 // The variance used in noise estimation is based on the src block in | 281 // The variance used in noise estimation is based on the src block in |
| 288 // time t (mb_src) and filtered block in time t-1 (mb_dist_prev). | 282 // time t (mb_src) and filtered block in time t-1 (mb_dist_prev). |
| 289 uint32_t noise_var = filter_->Variance16x8(mb_dst_prev, stride_y_, | 283 uint32_t noise_var = filter_->Variance16x8( |
| 290 mb_src, stride_y_, &sse_t); | 284 mb_dst_prev, stride_y_dst, mb_src, stride_y_src, &sse_t); |
| 291 ne_->GetNoise(mb_index, noise_var, luma); | 285 ne_->GetNoise(mb_index, noise_var, luma); |
| 292 } | 286 } |
| 293 moving_edge_[mb_index] = 0; // Not a moving edge block. | 287 moving_edge_[mb_index] = 0; // Not a moving edge block. |
| 294 } else { | 288 } else { |
| 295 uint32_t sse_t = 0; | 289 uint32_t sse_t = 0; |
| 296 // The variance used in MOD is based on the filtered blocks in time | 290 // The variance used in MOD is based on the filtered blocks in time |
| 297 // T (mb_dst) and T-1 (mb_dst_prev). | 291 // T (mb_dst) and T-1 (mb_dst_prev). |
| 298 uint32_t noise_var = filter_->Variance16x8(mb_dst_prev, stride_y_, | 292 uint32_t noise_var = filter_->Variance16x8( |
| 299 mb_dst, stride_y_, &sse_t); | 293 mb_dst_prev, stride_prev, mb_dst, stride_y_dst, &sse_t); |
| 300 if (noise_var > thr_var_adp) { // Moving edge checking. | 294 if (noise_var > thr_var_adp) { // Moving edge checking. |
| 301 if (ne_enable) { | 295 if (ne_enable) { |
| 302 ne_->ResetConsecLowVar(mb_index); | 296 ne_->ResetConsecLowVar(mb_index); |
| 303 } | 297 } |
| 304 moving_edge_[mb_index] = 1; // Mark as moving edge block. | 298 moving_edge_[mb_index] = 1; // Mark as moving edge block. |
| 305 x_density_[mb_col] += (pos_factor < 3); | 299 x_density_[mb_col] += (pos_factor < 3); |
| 306 y_density_[mb_row] += (pos_factor < 3); | 300 y_density_[mb_row] += (pos_factor < 3); |
| 307 } else { | 301 } else { |
| 308 moving_edge_[mb_index] = 0; | 302 moving_edge_[mb_index] = 0; |
| 309 if (ne_enable) { | 303 if (ne_enable) { |
| 310 // The variance used in noise estimation is based on the src block | 304 // The variance used in noise estimation is based on the src block |
| 311 // in time t (mb_src) and filtered block in time t-1 (mb_dist_prev). | 305 // in time t (mb_src) and filtered block in time t-1 (mb_dist_prev). |
| 312 uint32_t noise_var = filter_->Variance16x8( | 306 uint32_t noise_var = filter_->Variance16x8( |
| 313 mb_dst_prev, stride_y_, mb_src, stride_y_, &sse_t); | 307 mb_dst_prev, stride_prev, mb_src, stride_y_src, &sse_t); |
| 314 ne_->GetNoise(mb_index, noise_var, luma); | 308 ne_->GetNoise(mb_index, noise_var, luma); |
| 315 } | 309 } |
| 316 } | 310 } |
| 317 } | 311 } |
| 318 } // End of for loop | 312 } // End of for loop |
| 319 } // End of for loop | 313 } // End of for loop |
| 320 | 314 |
| 321 ReduceFalseDetection(moving_edge_, &moving_object_, noise_level); | 315 ReduceFalseDetection(moving_edge_, &moving_object_, noise_level); |
| 322 | 316 |
| 323 CopySrcOnMOB(y_src, y_dst); | 317 CopySrcOnMOB(y_src, stride_y_src, y_dst, stride_y_dst); |
| 324 | 318 |
| 325 // When frame width/height not divisible by 16, copy the margin to | 319 // When frame width/height not divisible by 16, copy the margin to |
| 326 // denoised_frame. | 320 // denoised_frame. |
| 327 if ((mb_rows_ << 4) != height_ || (mb_cols_ << 4) != width_) | 321 if ((mb_rows_ << 4) != height_ || (mb_cols_ << 4) != width_) |
| 328 CopyLumaOnMargin(y_src, y_dst); | 322 CopyLumaOnMargin(y_src, stride_y_src, y_dst, stride_y_dst); |
| 329 | 323 |
| 330 // TODO(jackychen): Need SSE2/NEON opt. | |
| 331 // Copy u/v planes. | 324 // Copy u/v planes. |
| 332 memcpy(u_dst, u_src, (height_ >> 1) * stride_u_); | 325 libyuv::CopyPlane(frame->DataU(), frame->StrideU(), |
| 333 memcpy(v_dst, v_src, (height_ >> 1) * stride_v_); | 326 dst->MutableDataU(), dst->StrideU(), |
| 327 (width_ + 1) >> 1, (height_ + 1) >> 1); |
| 328 libyuv::CopyPlane(frame->DataV(), frame->StrideV(), |
| 329 dst->MutableDataV(), dst->StrideV(), |
| 330 (width_ + 1) >> 1, (height_ + 1) >> 1); |
| 334 | 331 |
| 335 #if DISPLAY || DISPLAYNEON | 332 #if DISPLAY || DISPLAYNEON |
| 336 // Show rectangular region | 333 // Show rectangular region |
| 337 ShowRect(filter_, moving_edge_, moving_object_, x_density_, y_density_, u_src, | 334 ShowRect(filter_, moving_edge_, moving_object_, x_density_, y_density_, |
| 338 v_src, u_dst, v_dst, mb_rows_, mb_cols_, stride_u_, stride_v_); | 335 frame->DataU(), frame->StrideU(), frame->DataV(), frame->StrideV(), |
| 336 dst->MutableDataU(), dst->StrideU(), |
| 337 dst->MutableDataV(), dst->StrideV(), |
| 338 mb_rows_, mb_cols_); |
| 339 #endif | 339 #endif |
| 340 prev_buffer_ = dst; |
| 341 return dst; |
| 340 } | 342 } |
| 341 | 343 |
| 342 } // namespace webrtc | 344 } // namespace webrtc |
| OLD | NEW |