deflickering.cc revision 0d394f3609e039db3c4168bf3f8273b3a1e02acb
1470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com/*
2470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
3470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *
4470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *  Use of this source code is governed by a BSD-style license
5470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *  that can be found in the LICENSE file in the root of the source
6470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *  tree. An additional intellectual property rights grant can be found
7470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *  in the file PATENTS.  All contributing project authors may
8470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *  be found in the AUTHORS file in the root of the source tree.
9470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com */
10470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
116f3d8fcfc08686a9e8852ad225d54cca6e197875pbos@webrtc.org#include "webrtc/modules/video_processing/main/source/deflickering.h"
12470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
13470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#include <math.h>
14470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#include <stdlib.h>
15470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
166f3d8fcfc08686a9e8852ad225d54cca6e197875pbos@webrtc.org#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
172a770828d8594584b1275db06ad43fbe0d081279asapersson@webrtc.org#include "webrtc/system_wrappers/interface/logging.h"
186f3d8fcfc08686a9e8852ad225d54cca6e197875pbos@webrtc.org#include "webrtc/system_wrappers/interface/sort.h"
19470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
20470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comnamespace webrtc {
21470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
22470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com// Detection constants
23b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org// (Q4) Maximum allowed deviation for detection.
24b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.orgenum { kFrequencyDeviation = 39 };
25b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org// (Q4) Minimum frequency that can be detected.
26b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.orgenum { kMinFrequencyToDetect = 32 };
27b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org// Number of flickers before we accept detection
28b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.orgenum { kNumFlickerBeforeDetect = 2 };
29b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.orgenum { kmean_valueScaling = 4 };  // (Q4) In power of 2
30b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org// Dead-zone region in terms of pixel values
31b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.orgenum { kZeroCrossingDeadzone = 10 };
32b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org// Deflickering constants.
33470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com// Compute the quantiles over 1 / DownsamplingFactor of the image.
34470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comenum { kDownsamplingFactor = 8 };
35470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comenum { kLog2OfDownsamplingFactor = 3 };
36470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
37470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com// To generate in Matlab:
38b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org// >> probUW16 = round(2^11 *
39b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org//     [0.05,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,0.95,0.97]);
40470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com// >> fprintf('%d, ', probUW16)
41b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org// Resolution reduced to avoid overflow when multiplying with the
42b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org// (potentially) large number of pixels.
43b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.orgconst uint16_t VPMDeflickering::prob_uw16_[kNumProbs] = {102, 205, 410, 614,
44b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org    819, 1024, 1229, 1434, 1638, 1843, 1946, 1987}; // <Q11>
45470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
46470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com// To generate in Matlab:
47470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com// >> numQuants = 14; maxOnlyLength = 5;
48b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org// >> weightUW16 = round(2^15 *
49b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org//    [linspace(0.5, 1.0, numQuants - maxOnlyLength)]);
50470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com// >> fprintf('%d, %d,\n ', weightUW16);
51b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.orgconst uint16_t VPMDeflickering::weight_uw16_[kNumQuants - kMaxOnlyLength] =
52470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {16384, 18432, 20480, 22528, 24576, 26624, 28672, 30720, 32768}; // <Q15>
53470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
54b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.orgVPMDeflickering::VPMDeflickering()
55b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org    : id_(0) {
56b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  Reset();
57470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
58470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
59b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.orgVPMDeflickering::~VPMDeflickering() {}
60470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
61b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.orgint32_t VPMDeflickering::ChangeUniqueId(const int32_t id) {
62b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  id_ = id;
63b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  return 0;
64470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
65470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
66b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.orgvoid VPMDeflickering::Reset() {
67b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  mean_buffer_length_ = 0;
68b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  detection_state_ = 0;
69b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  frame_rate_ = 0;
70b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org
71b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  memset(mean_buffer_, 0, sizeof(int32_t) * kMeanBufferLength);
72b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  memset(timestamp_buffer_, 0, sizeof(int32_t) * kMeanBufferLength);
73b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org
74b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  // Initialize the history with a uniformly distributed histogram.
75b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  quant_hist_uw8_[0][0] = 0;
76b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  quant_hist_uw8_[0][kNumQuants - 1] = 255;
77b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  for (int32_t i = 0; i < kNumProbs; i++) {
780d394f3609e039db3c4168bf3f8273b3a1e02acbbjornv@webrtc.org    // Unsigned round. <Q0>
790d394f3609e039db3c4168bf3f8273b3a1e02acbbjornv@webrtc.org    quant_hist_uw8_[0][i + 1] = static_cast<uint8_t>(
800d394f3609e039db3c4168bf3f8273b3a1e02acbbjornv@webrtc.org        (prob_uw16_[i] * 255 + (1 << 10)) >> 11);
81b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  }
82b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org
83b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  for (int32_t i = 1; i < kFrameHistory_size; i++) {
84b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org    memcpy(quant_hist_uw8_[i], quant_hist_uw8_[0],
85b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org           sizeof(uint8_t) * kNumQuants);
86b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  }
87b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org}
88470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
89b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.orgint32_t VPMDeflickering::ProcessFrame(I420VideoFrame* frame,
90b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org    VideoProcessingModule::FrameStats* stats) {
91b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  assert(frame);
92b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  uint32_t frame_memory;
93b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  uint8_t quant_uw8[kNumQuants];
94b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  uint8_t maxquant_uw8[kNumQuants];
95b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  uint8_t minquant_uw8[kNumQuants];
96b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  uint16_t target_quant_uw16[kNumQuants];
97b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  uint16_t increment_uw16;
98b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  uint8_t map_uw8[256];
99b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org
100b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  uint16_t tmp_uw16;
101b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  uint32_t tmp_uw32;
102b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  int width = frame->width();
103b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  int height = frame->height();
104b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org
105b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  if (frame->IsZeroSize()) {
106b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org    return VPM_GENERAL_ERROR;
107b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  }
108b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org
109b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  // Stricter height check due to subsampling size calculation below.
110b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  if (height < 2) {
1112a770828d8594584b1275db06ad43fbe0d081279asapersson@webrtc.org    LOG(LS_ERROR) << "Invalid frame size.";
112b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org    return VPM_GENERAL_ERROR;
113b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  }
114b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org
115b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  if (!VideoProcessingModule::ValidFrameStats(*stats)) {
116b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org    return VPM_GENERAL_ERROR;
117b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  }
118b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org
119b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  if (PreDetection(frame->timestamp(), *stats) == -1) return VPM_GENERAL_ERROR;
120b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org
121b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  // Flicker detection
122b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  int32_t det_flicker = DetectFlicker();
123b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  if (det_flicker < 0) {
124b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org    return VPM_GENERAL_ERROR;
125b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  } else if (det_flicker != 1) {
126b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org    return 0;
127b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  }
128b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org
129b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  // Size of luminance component.
130b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  const uint32_t y_size = height * width;
131b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org
132b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  const uint32_t y_sub_size = width * (((height - 1) >>
133b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org      kLog2OfDownsamplingFactor) + 1);
134b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  uint8_t* y_sorted = new uint8_t[y_sub_size];
135b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  uint32_t sort_row_idx = 0;
136b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  for (int i = 0; i < height; i += kDownsamplingFactor) {
137b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org    memcpy(y_sorted + sort_row_idx * width,
138b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org        frame->buffer(kYPlane) + i * width, width);
139b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org    sort_row_idx++;
140b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  }
141b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org
142b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  webrtc::Sort(y_sorted, y_sub_size, webrtc::TYPE_UWord8);
143b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org
144b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  uint32_t prob_idx_uw32 = 0;
145b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  quant_uw8[0] = 0;
146b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  quant_uw8[kNumQuants - 1] = 255;
147b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org
148b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  // Ensure we won't get an overflow below.
149b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  // In practice, the number of subsampled pixels will not become this large.
150b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  if (y_sub_size > (1 << 21) - 1) {
1512a770828d8594584b1275db06ad43fbe0d081279asapersson@webrtc.org    LOG(LS_ERROR) << "Subsampled number of pixels too large.";
152b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org    return -1;
153b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  }
154b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org
155b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  for (int32_t i = 0; i < kNumProbs; i++) {
156b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org    // <Q0>.
157b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org    prob_idx_uw32 = WEBRTC_SPL_UMUL_32_16(y_sub_size, prob_uw16_[i]) >> 11;
158b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org    quant_uw8[i + 1] = y_sorted[prob_idx_uw32];
159b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  }
160b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org
161b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  delete [] y_sorted;
162b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  y_sorted = NULL;
163b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org
164b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  // Shift history for new frame.
165b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  memmove(quant_hist_uw8_[1], quant_hist_uw8_[0],
166b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org      (kFrameHistory_size - 1) * kNumQuants * sizeof(uint8_t));
167b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  // Store current frame in history.
168b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  memcpy(quant_hist_uw8_[0], quant_uw8, kNumQuants * sizeof(uint8_t));
169b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org
170b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  // We use a frame memory equal to the ceiling of half the frame rate to
171b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  // ensure we capture an entire period of flicker.
172b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  frame_memory = (frame_rate_ + (1 << 5)) >> 5;  // Unsigned ceiling. <Q0>
173b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org                                                 // frame_rate_ in Q4.
174b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  if (frame_memory > kFrameHistory_size) {
175b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org    frame_memory = kFrameHistory_size;
176b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  }
177b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org
178b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  // Get maximum and minimum.
179b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  for (int32_t i = 0; i < kNumQuants; i++) {
180b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org    maxquant_uw8[i] = 0;
181b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org    minquant_uw8[i] = 255;
182b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org    for (uint32_t j = 0; j < frame_memory; j++) {
183b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org      if (quant_hist_uw8_[j][i] > maxquant_uw8[i]) {
184b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org        maxquant_uw8[i] = quant_hist_uw8_[j][i];
185b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org      }
186b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org
187b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org      if (quant_hist_uw8_[j][i] < minquant_uw8[i]) {
188b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org        minquant_uw8[i] = quant_hist_uw8_[j][i];
189b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org      }
190470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
191b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  }
192b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org
193b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  // Get target quantiles.
194b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  for (int32_t i = 0; i < kNumQuants - kMaxOnlyLength; i++) {
1950d394f3609e039db3c4168bf3f8273b3a1e02acbbjornv@webrtc.org    // target = w * maxquant_uw8 + (1 - w) * minquant_uw8
1960d394f3609e039db3c4168bf3f8273b3a1e02acbbjornv@webrtc.org    // Weights w = |weight_uw16_| are in Q15, hence the final output has to be
1970d394f3609e039db3c4168bf3f8273b3a1e02acbbjornv@webrtc.org    // right shifted by 8 to end up in Q7.
1980d394f3609e039db3c4168bf3f8273b3a1e02acbbjornv@webrtc.org    target_quant_uw16[i] = static_cast<uint16_t>((
1990d394f3609e039db3c4168bf3f8273b3a1e02acbbjornv@webrtc.org        weight_uw16_[i] * maxquant_uw8[i] +
2000d394f3609e039db3c4168bf3f8273b3a1e02acbbjornv@webrtc.org        ((1 << 15) - weight_uw16_[i]) * minquant_uw8[i]) >> 8);  // <Q7>
201b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  }
202b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org
203b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  for (int32_t i = kNumQuants - kMaxOnlyLength; i < kNumQuants; i++) {
204b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org    target_quant_uw16[i] = ((uint16_t)maxquant_uw8[i]) << 7;
205b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  }
206b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org
207b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  // Compute the map from input to output pixels.
208b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  uint16_t mapUW16;  // <Q7>
209b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  for (int32_t i = 1; i < kNumQuants; i++) {
210b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org    // As quant and targetQuant are limited to UWord8, it's safe to use Q7 here.
211b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org    tmp_uw32 = static_cast<uint32_t>(target_quant_uw16[i] -
212b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org        target_quant_uw16[i - 1]);
213b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org    tmp_uw16 = static_cast<uint16_t>(quant_uw8[i] - quant_uw8[i - 1]);  // <Q0>
214b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org
215b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org    if (tmp_uw16 > 0) {
216b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org      increment_uw16 = static_cast<uint16_t>(WebRtcSpl_DivU32U16(tmp_uw32,
217b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org          tmp_uw16)); // <Q7>
218b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org    } else {
219b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org      // The value is irrelevant; the loop below will only iterate once.
220b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org      increment_uw16 = 0;
221470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
222470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
223b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org    mapUW16 = target_quant_uw16[i - 1];
224b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org    for (uint32_t j = quant_uw8[i - 1]; j < (uint32_t)(quant_uw8[i] + 1); j++) {
225b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org      // Unsigned round. <Q0>
226b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org      map_uw8[j] = (uint8_t)((mapUW16 + (1 << 6)) >> 7);
227b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org      mapUW16 += increment_uw16;
228470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
229b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  }
230470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
231b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  // Map to the output frame.
232b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  uint8_t* buffer = frame->buffer(kYPlane);
233b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  for (uint32_t i = 0; i < y_size; i++) {
234b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org    buffer[i] = map_uw8[buffer[i]];
235b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  }
236470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
237b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  // Frame was altered, so reset stats.
238b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  VideoProcessingModule::ClearFrameStats(stats);
239470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
240b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  return VPM_OK;
241470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
242470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
243470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com/**
244b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org   Performs some pre-detection operations. Must be called before
245470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com   DetectFlicker().
246470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
247470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com   \param[in] timestamp Timestamp of the current frame.
248470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com   \param[in] stats     Statistics of the current frame.
249b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org
250470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com   \return 0: Success\n
251470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com           2: Detection not possible due to flickering frequency too close to
252470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com              zero.\n
253470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          -1: Error
254470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com*/
255b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.orgint32_t VPMDeflickering::PreDetection(const uint32_t timestamp,
256b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  const VideoProcessingModule::FrameStats& stats) {
257b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  int32_t mean_val;  // Mean value of frame (Q4)
258b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  uint32_t frame_rate = 0;
259b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  int32_t meanBufferLength;  // Temp variable.
260b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org
261b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  mean_val = ((stats.sum << kmean_valueScaling) / stats.num_pixels);
262b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  // Update mean value buffer.
263b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  // This should be done even though we might end up in an unreliable detection.
264b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  memmove(mean_buffer_ + 1, mean_buffer_,
265b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org      (kMeanBufferLength - 1) * sizeof(int32_t));
266b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  mean_buffer_[0] = mean_val;
267b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org
268b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  // Update timestamp buffer.
269b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  // This should be done even though we might end up in an unreliable detection.
270b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  memmove(timestamp_buffer_ + 1, timestamp_buffer_, (kMeanBufferLength - 1) *
271b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org      sizeof(uint32_t));
272b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  timestamp_buffer_[0] = timestamp;
273b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org
274b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org/* Compute current frame rate (Q4) */
275b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  if (timestamp_buffer_[kMeanBufferLength - 1] != 0) {
276b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org    frame_rate = ((90000 << 4) * (kMeanBufferLength - 1));
277b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org    frame_rate /=
278b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org        (timestamp_buffer_[0] - timestamp_buffer_[kMeanBufferLength - 1]);
279b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  } else if (timestamp_buffer_[1] != 0) {
280b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org    frame_rate = (90000 << 4) / (timestamp_buffer_[0] - timestamp_buffer_[1]);
281b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  }
282b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org
283b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  /* Determine required size of mean value buffer (mean_buffer_length_) */
284b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  if (frame_rate == 0) {
285b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org    meanBufferLength = 1;
286b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  } else {
287b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org    meanBufferLength =
288b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org        (kNumFlickerBeforeDetect * frame_rate) / kMinFrequencyToDetect;
289b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  }
290b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  /* Sanity check of buffer length */
291b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  if (meanBufferLength >= kMeanBufferLength) {
292b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org    /* Too long buffer. The flickering frequency is too close to zero, which
293b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org     * makes the estimation unreliable.
294470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com     */
295b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org    mean_buffer_length_ = 0;
296b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org    return 2;
297b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  }
298b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  mean_buffer_length_ = meanBufferLength;
299b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org
300b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  if ((timestamp_buffer_[mean_buffer_length_ - 1] != 0) &&
301b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org      (mean_buffer_length_ != 1)) {
302b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org    frame_rate = ((90000 << 4) * (mean_buffer_length_ - 1));
303b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org    frame_rate /=
304b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org        (timestamp_buffer_[0] - timestamp_buffer_[mean_buffer_length_ - 1]);
305b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  } else if (timestamp_buffer_[1] != 0) {
306b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org    frame_rate = (90000 << 4) / (timestamp_buffer_[0] - timestamp_buffer_[1]);
307b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  }
308b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  frame_rate_ = frame_rate;
309b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org
310b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  return VPM_OK;
311470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
312470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
313470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com/**
314b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org   This function detects flicker in the video stream. As a side effect the
315b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org   mean value buffer is updated with the new mean value.
316b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org
317470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com   \return 0: No flickering detected\n
318470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com           1: Flickering detected\n
319470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com           2: Detection not possible due to unreliable frequency interval
320470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          -1: Error
321470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com*/
322b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.orgint32_t VPMDeflickering::DetectFlicker() {
323b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  uint32_t  i;
324b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  int32_t  freqEst;       // (Q4) Frequency estimate to base detection upon
325b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  int32_t  ret_val = -1;
326b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org
327b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  /* Sanity check for mean_buffer_length_ */
328b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  if (mean_buffer_length_ < 2) {
329b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org    /* Not possible to estimate frequency */
330b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org    return(2);
331b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  }
332b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  // Count zero crossings with a dead zone to be robust against noise. If the
333b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  // noise std is 2 pixel this corresponds to about 95% confidence interval.
334b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  int32_t deadzone = (kZeroCrossingDeadzone << kmean_valueScaling);  // Q4
335b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  int32_t meanOfBuffer = 0;  // Mean value of mean value buffer.
336b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  int32_t numZeros     = 0;  // Number of zeros that cross the dead-zone.
337b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  int32_t cntState     = 0;  // State variable for zero crossing regions.
338b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  int32_t cntStateOld  = 0;  // Previous state for zero crossing regions.
339b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org
340b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  for (i = 0; i < mean_buffer_length_; i++) {
341b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org    meanOfBuffer += mean_buffer_[i];
342b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  }
343b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  meanOfBuffer += (mean_buffer_length_ >> 1);  // Rounding, not truncation.
344b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  meanOfBuffer /= mean_buffer_length_;
345b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org
346b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  // Count zero crossings.
347b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  cntStateOld = (mean_buffer_[0] >= (meanOfBuffer + deadzone));
348b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  cntStateOld -= (mean_buffer_[0] <= (meanOfBuffer - deadzone));
349b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  for (i = 1; i < mean_buffer_length_; i++) {
350b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org    cntState = (mean_buffer_[i] >= (meanOfBuffer + deadzone));
351b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org    cntState -= (mean_buffer_[i] <= (meanOfBuffer - deadzone));
352b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org    if (cntStateOld == 0) {
353b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org      cntStateOld = -cntState;
354470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
355b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org    if (((cntState + cntStateOld) == 0) && (cntState != 0)) {
356b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org      numZeros++;
357b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org      cntStateOld = cntState;
358470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
359b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  }
360b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  // END count zero crossings.
361b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org
362b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  /* Frequency estimation according to:
363b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  * freqEst = numZeros * frame_rate / 2 / mean_buffer_length_;
364b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  *
365b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  * Resolution is set to Q4
366b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  */
367b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  freqEst = ((numZeros * 90000) << 3);
368b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  freqEst /=
369b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org      (timestamp_buffer_[0] - timestamp_buffer_[mean_buffer_length_ - 1]);
370b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org
371b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  /* Translate frequency estimate to regions close to 100 and 120 Hz */
372b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  uint8_t freqState = 0;  // Current translation state;
373b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org                          // (0) Not in interval,
374b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org                          // (1) Within valid interval,
375b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org                          // (2) Out of range
376b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  int32_t freqAlias = freqEst;
377b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  if (freqEst > kMinFrequencyToDetect) {
378b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org    uint8_t aliasState = 1;
379b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org    while(freqState == 0) {
380b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org      /* Increase frequency */
381b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org      freqAlias += (aliasState * frame_rate_);
382b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org      freqAlias += ((freqEst << 1) * (1 - (aliasState << 1)));
383b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org      /* Compute state */
384b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org      freqState = (abs(freqAlias - (100 << 4)) <= kFrequencyDeviation);
385b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org      freqState += (abs(freqAlias - (120 << 4)) <= kFrequencyDeviation);
386b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org      freqState += 2 * (freqAlias > ((120 << 4) + kFrequencyDeviation));
387b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org      /* Switch alias state */
388b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org      aliasState++;
389b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org      aliasState &= 0x01;
390470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
391b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  }
392b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  /* Is frequency estimate within detection region? */
393b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  if (freqState == 1) {
394b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org    ret_val = 1;
395b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  } else if (freqState == 0) {
396b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org    ret_val = 2;
397b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  } else {
398b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org    ret_val = 0;
399b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  }
400b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org  return ret_val;
401470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
402470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
403b43d8078a152d91037b25175712a57a9a377220amikhal@webrtc.org}  // namespace webrtc
404