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 <stdlib.h>
12
13#include "webrtc/modules/video_processing/util/denoiser_filter_c.h"
14
15namespace webrtc {
16
17void DenoiserFilterC::CopyMem16x16(const uint8_t* src,
18                                   int src_stride,
19                                   uint8_t* dst,
20                                   int dst_stride) {
21  for (int i = 0; i < 16; i++) {
22    memcpy(dst, src, 16);
23    src += src_stride;
24    dst += dst_stride;
25  }
26}
27
28void DenoiserFilterC::CopyMem8x8(const uint8_t* src,
29                                 int src_stride,
30                                 uint8_t* dst,
31                                 int dst_stride) {
32  for (int i = 0; i < 8; i++) {
33    memcpy(dst, src, 8);
34    src += src_stride;
35    dst += dst_stride;
36  }
37}
38
39uint32_t DenoiserFilterC::Variance16x8(const uint8_t* a,
40                                       int a_stride,
41                                       const uint8_t* b,
42                                       int b_stride,
43                                       uint32_t* sse) {
44  int sum = 0;
45  *sse = 0;
46  a_stride <<= 1;
47  b_stride <<= 1;
48
49  for (int i = 0; i < 8; i++) {
50    for (int j = 0; j < 16; j++) {
51      const int diff = a[j] - b[j];
52      sum += diff;
53      *sse += diff * diff;
54    }
55
56    a += a_stride;
57    b += b_stride;
58  }
59  return *sse - ((static_cast<int64_t>(sum) * sum) >> 7);
60}
61
62DenoiserDecision DenoiserFilterC::MbDenoise(uint8_t* mc_running_avg_y,
63                                            int mc_avg_y_stride,
64                                            uint8_t* running_avg_y,
65                                            int avg_y_stride,
66                                            const uint8_t* sig,
67                                            int sig_stride,
68                                            uint8_t motion_magnitude,
69                                            int increase_denoising) {
70  int sum_diff_thresh = 0;
71  int sum_diff = 0;
72  int adj_val[3] = {3, 4, 6};
73  int shift_inc1 = 0;
74  int shift_inc2 = 1;
75  int col_sum[16] = {0};
76  if (motion_magnitude <= kMotionMagnitudeThreshold) {
77    if (increase_denoising) {
78      shift_inc1 = 1;
79      shift_inc2 = 2;
80    }
81    adj_val[0] += shift_inc2;
82    adj_val[1] += shift_inc2;
83    adj_val[2] += shift_inc2;
84  }
85
86  for (int r = 0; r < 16; ++r) {
87    for (int c = 0; c < 16; ++c) {
88      int diff = 0;
89      int adjustment = 0;
90      int absdiff = 0;
91
92      diff = mc_running_avg_y[c] - sig[c];
93      absdiff = abs(diff);
94
95      // When |diff| <= |3 + shift_inc1|, use pixel value from
96      // last denoised raw.
97      if (absdiff <= 3 + shift_inc1) {
98        running_avg_y[c] = mc_running_avg_y[c];
99        col_sum[c] += diff;
100      } else {
101        if (absdiff >= 4 + shift_inc1 && absdiff <= 7)
102          adjustment = adj_val[0];
103        else if (absdiff >= 8 && absdiff <= 15)
104          adjustment = adj_val[1];
105        else
106          adjustment = adj_val[2];
107
108        if (diff > 0) {
109          if ((sig[c] + adjustment) > 255)
110            running_avg_y[c] = 255;
111          else
112            running_avg_y[c] = sig[c] + adjustment;
113
114          col_sum[c] += adjustment;
115        } else {
116          if ((sig[c] - adjustment) < 0)
117            running_avg_y[c] = 0;
118          else
119            running_avg_y[c] = sig[c] - adjustment;
120
121          col_sum[c] -= adjustment;
122        }
123      }
124    }
125
126    // Update pointers for next iteration.
127    sig += sig_stride;
128    mc_running_avg_y += mc_avg_y_stride;
129    running_avg_y += avg_y_stride;
130  }
131
132  for (int c = 0; c < 16; ++c) {
133    if (col_sum[c] >= 128) {
134      col_sum[c] = 127;
135    }
136    sum_diff += col_sum[c];
137  }
138
139  sum_diff_thresh = kSumDiffThreshold;
140  if (increase_denoising)
141    sum_diff_thresh = kSumDiffThresholdHigh;
142  if (abs(sum_diff) > sum_diff_thresh) {
143    int delta = ((abs(sum_diff) - sum_diff_thresh) >> 8) + 1;
144    // Only apply the adjustment for max delta up to 3.
145    if (delta < 4) {
146      sig -= sig_stride * 16;
147      mc_running_avg_y -= mc_avg_y_stride * 16;
148      running_avg_y -= avg_y_stride * 16;
149      for (int r = 0; r < 16; ++r) {
150        for (int c = 0; c < 16; ++c) {
151          int diff = mc_running_avg_y[c] - sig[c];
152          int adjustment = abs(diff);
153          if (adjustment > delta)
154            adjustment = delta;
155          if (diff > 0) {
156            // Bring denoised signal down.
157            if (running_avg_y[c] - adjustment < 0)
158              running_avg_y[c] = 0;
159            else
160              running_avg_y[c] = running_avg_y[c] - adjustment;
161            col_sum[c] -= adjustment;
162          } else if (diff < 0) {
163            // Bring denoised signal up.
164            if (running_avg_y[c] + adjustment > 255)
165              running_avg_y[c] = 255;
166            else
167              running_avg_y[c] = running_avg_y[c] + adjustment;
168            col_sum[c] += adjustment;
169          }
170        }
171        sig += sig_stride;
172        mc_running_avg_y += mc_avg_y_stride;
173        running_avg_y += avg_y_stride;
174      }
175
176      sum_diff = 0;
177      for (int c = 0; c < 16; ++c) {
178        if (col_sum[c] >= 128) {
179          col_sum[c] = 127;
180        }
181        sum_diff += col_sum[c];
182      }
183
184      if (abs(sum_diff) > sum_diff_thresh)
185        return COPY_BLOCK;
186    } else {
187      return COPY_BLOCK;
188    }
189  }
190
191  return FILTER_BLOCK;
192}
193
194}  // namespace webrtc
195