blob: a4b55c1c13b6c83968d74f11d796ec9d493676e8 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
2 * Copyright (c) 2011 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
pbos@webrtc.org6f3d8fc2013-05-27 14:12:16 +000011#include "webrtc/modules/video_processing/main/source/deflickering.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000012
13#include <math.h>
14#include <stdlib.h>
15
pbos@webrtc.org6f3d8fc2013-05-27 14:12:16 +000016#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
17#include "webrtc/system_wrappers/interface/sort.h"
18#include "webrtc/system_wrappers/interface/trace.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000019
20namespace webrtc {
21
22// Detection constants
23enum { kFrequencyDeviation = 39 }; // (Q4) Maximum allowed deviation for detection
24enum { kMinFrequencyToDetect = 32 }; // (Q4) Minimum frequency that can be detected
25enum { kNumFlickerBeforeDetect = 2 }; // Number of flickers before we accept detection
26enum { kMeanValueScaling = 4 }; // (Q4) In power of 2
27enum { kZeroCrossingDeadzone = 10 }; // Deadzone region in terms of pixel values
28
29// Deflickering constants
30// Compute the quantiles over 1 / DownsamplingFactor of the image.
31enum { kDownsamplingFactor = 8 };
32enum { kLog2OfDownsamplingFactor = 3 };
33
34// To generate in Matlab:
35// >> probUW16 = round(2^11 * [0.05,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,0.95,0.97]);
36// >> fprintf('%d, ', probUW16)
37// Resolution reduced to avoid overflow when multiplying with the (potentially) large
38// number of pixels.
pbos@webrtc.org1ab45f62013-04-09 13:38:10 +000039const uint16_t VPMDeflickering::_probUW16[kNumProbs] =
niklase@google.com470e71d2011-07-07 08:21:25 +000040 {102, 205, 410, 614, 819, 1024, 1229, 1434, 1638, 1843, 1946, 1987}; // <Q11>
41
42// To generate in Matlab:
43// >> numQuants = 14; maxOnlyLength = 5;
44// >> weightUW16 = round(2^15 * [linspace(0.5, 1.0, numQuants - maxOnlyLength)]);
45// >> fprintf('%d, %d,\n ', weightUW16);
pbos@webrtc.org1ab45f62013-04-09 13:38:10 +000046const uint16_t VPMDeflickering::_weightUW16[kNumQuants - kMaxOnlyLength] =
niklase@google.com470e71d2011-07-07 08:21:25 +000047 {16384, 18432, 20480, 22528, 24576, 26624, 28672, 30720, 32768}; // <Q15>
48
49VPMDeflickering::VPMDeflickering() :
50 _id(0)
51{
52 Reset();
53}
54
55VPMDeflickering::~VPMDeflickering()
56{
57}
58
pbos@webrtc.org1ab45f62013-04-09 13:38:10 +000059int32_t
60VPMDeflickering::ChangeUniqueId(const int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +000061{
62 _id = id;
63 return 0;
64}
65
66void
67VPMDeflickering::Reset()
68{
69 _meanBufferLength = 0;
70 _detectionState = 0;
71 _frameRate = 0;
72
pbos@webrtc.org1ab45f62013-04-09 13:38:10 +000073 memset(_meanBuffer, 0, sizeof(int32_t) * kMeanBufferLength);
74 memset(_timestampBuffer, 0, sizeof(int32_t) * kMeanBufferLength);
niklase@google.com470e71d2011-07-07 08:21:25 +000075
76 // Initialize the history with a uniformly distributed histogram
77 _quantHistUW8[0][0] = 0;
78 _quantHistUW8[0][kNumQuants - 1] = 255;
pbos@webrtc.org1ab45f62013-04-09 13:38:10 +000079 for (int32_t i = 0; i < kNumProbs; i++)
niklase@google.com470e71d2011-07-07 08:21:25 +000080 {
pbos@webrtc.org1ab45f62013-04-09 13:38:10 +000081 _quantHistUW8[0][i + 1] = static_cast<uint8_t>((WEBRTC_SPL_UMUL_16_16(
niklase@google.com470e71d2011-07-07 08:21:25 +000082 _probUW16[i], 255) + (1 << 10)) >> 11); // Unsigned round. <Q0>
83 }
84
pbos@webrtc.org1ab45f62013-04-09 13:38:10 +000085 for (int32_t i = 1; i < kFrameHistorySize; i++)
niklase@google.com470e71d2011-07-07 08:21:25 +000086 {
pbos@webrtc.org1ab45f62013-04-09 13:38:10 +000087 memcpy(_quantHistUW8[i], _quantHistUW8[0], sizeof(uint8_t) * kNumQuants);
niklase@google.com470e71d2011-07-07 08:21:25 +000088 }
89}
90
pbos@webrtc.org1ab45f62013-04-09 13:38:10 +000091int32_t
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +000092VPMDeflickering::ProcessFrame(I420VideoFrame* frame,
mikhal@webrtc.org0e196e12012-10-19 15:43:31 +000093 VideoProcessingModule::FrameStats* stats)
niklase@google.com470e71d2011-07-07 08:21:25 +000094{
mikhal@webrtc.org0e196e12012-10-19 15:43:31 +000095 assert(frame);
pbos@webrtc.org1ab45f62013-04-09 13:38:10 +000096 uint32_t frameMemory;
97 uint8_t quantUW8[kNumQuants];
98 uint8_t maxQuantUW8[kNumQuants];
99 uint8_t minQuantUW8[kNumQuants];
100 uint16_t targetQuantUW16[kNumQuants];
101 uint16_t incrementUW16;
102 uint8_t mapUW8[256];
niklase@google.com470e71d2011-07-07 08:21:25 +0000103
pbos@webrtc.org1ab45f62013-04-09 13:38:10 +0000104 uint16_t tmpUW16;
105 uint32_t tmpUW32;
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000106 int width = frame->width();
107 int height = frame->height();
niklase@google.com470e71d2011-07-07 08:21:25 +0000108
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000109 if (frame->IsZeroSize())
niklase@google.com470e71d2011-07-07 08:21:25 +0000110 {
mikhal@webrtc.org0e196e12012-10-19 15:43:31 +0000111 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoPreocessing, _id,
112 "Null frame pointer");
niklase@google.com470e71d2011-07-07 08:21:25 +0000113 return VPM_GENERAL_ERROR;
114 }
115
116 // Stricter height check due to subsampling size calculation below.
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000117 if (height < 2)
niklase@google.com470e71d2011-07-07 08:21:25 +0000118 {
mikhal@webrtc.org0e196e12012-10-19 15:43:31 +0000119 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoPreocessing, _id,
120 "Invalid frame size");
niklase@google.com470e71d2011-07-07 08:21:25 +0000121 return VPM_GENERAL_ERROR;
122 }
123
mikhal@webrtc.org0e196e12012-10-19 15:43:31 +0000124 if (!VideoProcessingModule::ValidFrameStats(*stats))
niklase@google.com470e71d2011-07-07 08:21:25 +0000125 {
mikhal@webrtc.org0e196e12012-10-19 15:43:31 +0000126 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoPreocessing, _id,
127 "Invalid frame stats");
niklase@google.com470e71d2011-07-07 08:21:25 +0000128 return VPM_GENERAL_ERROR;
129 }
130
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000131 if (PreDetection(frame->timestamp(), *stats) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000132 {
133 return VPM_GENERAL_ERROR;
134 }
135
136 // Flicker detection
pbos@webrtc.org1ab45f62013-04-09 13:38:10 +0000137 int32_t detFlicker = DetectFlicker();
niklase@google.com470e71d2011-07-07 08:21:25 +0000138 if (detFlicker < 0)
139 { // Error
140 return VPM_GENERAL_ERROR;
141 }
142 else if (detFlicker != 1)
143 {
144 return 0;
145 }
146
147 // Size of luminance component
pbos@webrtc.org1ab45f62013-04-09 13:38:10 +0000148 const uint32_t ySize = height * width;
niklase@google.com470e71d2011-07-07 08:21:25 +0000149
pbos@webrtc.org1ab45f62013-04-09 13:38:10 +0000150 const uint32_t ySubSize = width * (((height - 1) >>
niklase@google.com470e71d2011-07-07 08:21:25 +0000151 kLog2OfDownsamplingFactor) + 1);
pbos@webrtc.org1ab45f62013-04-09 13:38:10 +0000152 uint8_t* ySorted = new uint8_t[ySubSize];
153 uint32_t sortRowIdx = 0;
mikhal@webrtc.org0e196e12012-10-19 15:43:31 +0000154 for (int i = 0; i < height; i += kDownsamplingFactor)
niklase@google.com470e71d2011-07-07 08:21:25 +0000155 {
mikhal@webrtc.org0e196e12012-10-19 15:43:31 +0000156 memcpy(ySorted + sortRowIdx * width,
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000157 frame->buffer(kYPlane) + i * width, width);
niklase@google.com470e71d2011-07-07 08:21:25 +0000158 sortRowIdx++;
159 }
160
161 webrtc::Sort(ySorted, ySubSize, webrtc::TYPE_UWord8);
162
pbos@webrtc.org1ab45f62013-04-09 13:38:10 +0000163 uint32_t probIdxUW32 = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000164 quantUW8[0] = 0;
165 quantUW8[kNumQuants - 1] = 255;
166
167 // Ensure we won't get an overflow below.
168 // In practice, the number of subsampled pixels will not become this large.
169 if (ySubSize > (1 << 21) - 1)
170 {
171 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoPreocessing, _id,
172 "Subsampled number of pixels too large");
173 return -1;
174 }
175
pbos@webrtc.org1ab45f62013-04-09 13:38:10 +0000176 for (int32_t i = 0; i < kNumProbs; i++)
niklase@google.com470e71d2011-07-07 08:21:25 +0000177 {
178 probIdxUW32 = WEBRTC_SPL_UMUL_32_16(ySubSize, _probUW16[i]) >> 11; // <Q0>
179 quantUW8[i + 1] = ySorted[probIdxUW32];
180 }
181
182 delete [] ySorted;
183 ySorted = NULL;
184
185 // Shift history for new frame.
186 memmove(_quantHistUW8[1], _quantHistUW8[0], (kFrameHistorySize - 1) * kNumQuants *
pbos@webrtc.org1ab45f62013-04-09 13:38:10 +0000187 sizeof(uint8_t));
niklase@google.com470e71d2011-07-07 08:21:25 +0000188 // Store current frame in history.
pbos@webrtc.org1ab45f62013-04-09 13:38:10 +0000189 memcpy(_quantHistUW8[0], quantUW8, kNumQuants * sizeof(uint8_t));
niklase@google.com470e71d2011-07-07 08:21:25 +0000190
191 // We use a frame memory equal to the ceiling of half the frame rate to ensure we
192 // capture an entire period of flicker.
193 frameMemory = (_frameRate + (1 << 5)) >> 5; // Unsigned ceiling. <Q0>
194 // _frameRate in Q4.
195 if (frameMemory > kFrameHistorySize)
196 {
197 frameMemory = kFrameHistorySize;
198 }
199
200 // Get maximum and minimum.
pbos@webrtc.org1ab45f62013-04-09 13:38:10 +0000201 for (int32_t i = 0; i < kNumQuants; i++)
niklase@google.com470e71d2011-07-07 08:21:25 +0000202 {
203 maxQuantUW8[i] = 0;
204 minQuantUW8[i] = 255;
pbos@webrtc.org1ab45f62013-04-09 13:38:10 +0000205 for (uint32_t j = 0; j < frameMemory; j++)
niklase@google.com470e71d2011-07-07 08:21:25 +0000206 {
207 if (_quantHistUW8[j][i] > maxQuantUW8[i])
208 {
209 maxQuantUW8[i] = _quantHistUW8[j][i];
210 }
211
212 if (_quantHistUW8[j][i] < minQuantUW8[i])
213 {
214 minQuantUW8[i] = _quantHistUW8[j][i];
215 }
216 }
217 }
218
219 // Get target quantiles.
pbos@webrtc.org1ab45f62013-04-09 13:38:10 +0000220 for (int32_t i = 0; i < kNumQuants - kMaxOnlyLength; i++)
niklase@google.com470e71d2011-07-07 08:21:25 +0000221 {
pbos@webrtc.org1ab45f62013-04-09 13:38:10 +0000222 targetQuantUW16[i] = static_cast<uint16_t>((WEBRTC_SPL_UMUL_16_16(
niklase@google.com470e71d2011-07-07 08:21:25 +0000223 _weightUW16[i], maxQuantUW8[i]) + WEBRTC_SPL_UMUL_16_16((1 << 15) -
224 _weightUW16[i], minQuantUW8[i])) >> 8); // <Q7>
225 }
226
pbos@webrtc.org1ab45f62013-04-09 13:38:10 +0000227 for (int32_t i = kNumQuants - kMaxOnlyLength; i < kNumQuants; i++)
niklase@google.com470e71d2011-07-07 08:21:25 +0000228 {
pbos@webrtc.org1ab45f62013-04-09 13:38:10 +0000229 targetQuantUW16[i] = ((uint16_t)maxQuantUW8[i]) << 7;
niklase@google.com470e71d2011-07-07 08:21:25 +0000230 }
231
232 // Compute the map from input to output pixels.
pbos@webrtc.org1ab45f62013-04-09 13:38:10 +0000233 uint16_t mapUW16; // <Q7>
234 for (int32_t i = 1; i < kNumQuants; i++)
niklase@google.com470e71d2011-07-07 08:21:25 +0000235 {
236 // As quant and targetQuant are limited to UWord8, we're safe to use Q7 here.
pbos@webrtc.org1ab45f62013-04-09 13:38:10 +0000237 tmpUW32 = static_cast<uint32_t>(targetQuantUW16[i] -
niklase@google.com470e71d2011-07-07 08:21:25 +0000238 targetQuantUW16[i - 1]); // <Q7>
pbos@webrtc.org1ab45f62013-04-09 13:38:10 +0000239 tmpUW16 = static_cast<uint16_t>(quantUW8[i] - quantUW8[i - 1]); // <Q0>
niklase@google.com470e71d2011-07-07 08:21:25 +0000240
241 if (tmpUW16 > 0)
242 {
pbos@webrtc.org1ab45f62013-04-09 13:38:10 +0000243 incrementUW16 = static_cast<uint16_t>(WebRtcSpl_DivU32U16(tmpUW32,
niklase@google.com470e71d2011-07-07 08:21:25 +0000244 tmpUW16)); // <Q7>
245 }
246 else
247 {
248 // The value is irrelevant; the loop below will only iterate once.
249 incrementUW16 = 0;
250 }
251
252 mapUW16 = targetQuantUW16[i - 1];
pbos@webrtc.org1ab45f62013-04-09 13:38:10 +0000253 for (uint32_t j = quantUW8[i - 1]; j < (uint32_t)(quantUW8[i] + 1); j++)
niklase@google.com470e71d2011-07-07 08:21:25 +0000254 {
pbos@webrtc.org1ab45f62013-04-09 13:38:10 +0000255 mapUW8[j] = (uint8_t)((mapUW16 + (1 << 6)) >> 7); // Unsigned round. <Q0>
niklase@google.com470e71d2011-07-07 08:21:25 +0000256 mapUW16 += incrementUW16;
257 }
258 }
259
260 // Map to the output frame.
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000261 uint8_t* buffer = frame->buffer(kYPlane);
pbos@webrtc.org1ab45f62013-04-09 13:38:10 +0000262 for (uint32_t i = 0; i < ySize; i++)
niklase@google.com470e71d2011-07-07 08:21:25 +0000263 {
mikhal@webrtc.org0e196e12012-10-19 15:43:31 +0000264 buffer[i] = mapUW8[buffer[i]];
niklase@google.com470e71d2011-07-07 08:21:25 +0000265 }
266
267 // Frame was altered, so reset stats.
268 VideoProcessingModule::ClearFrameStats(stats);
269
270 return 0;
271}
272
273/**
274 Performs some pre-detection operations. Must be called before
275 DetectFlicker().
276
277 \param[in] timestamp Timestamp of the current frame.
278 \param[in] stats Statistics of the current frame.
279
280 \return 0: Success\n
281 2: Detection not possible due to flickering frequency too close to
282 zero.\n
283 -1: Error
284*/
pbos@webrtc.org1ab45f62013-04-09 13:38:10 +0000285int32_t
286VPMDeflickering::PreDetection(const uint32_t timestamp,
niklase@google.com470e71d2011-07-07 08:21:25 +0000287 const VideoProcessingModule::FrameStats& stats)
288{
pbos@webrtc.org1ab45f62013-04-09 13:38:10 +0000289 int32_t meanVal; // Mean value of frame (Q4)
290 uint32_t frameRate = 0;
291 int32_t meanBufferLength; // Temp variable
niklase@google.com470e71d2011-07-07 08:21:25 +0000292
293 meanVal = ((stats.sum << kMeanValueScaling) / stats.numPixels);
294 /* Update mean value buffer.
295 * This should be done even though we might end up in an unreliable detection.
296 */
pbos@webrtc.org1ab45f62013-04-09 13:38:10 +0000297 memmove(_meanBuffer + 1, _meanBuffer, (kMeanBufferLength - 1) * sizeof(int32_t));
niklase@google.com470e71d2011-07-07 08:21:25 +0000298 _meanBuffer[0] = meanVal;
299
300 /* Update timestamp buffer.
301 * This should be done even though we might end up in an unreliable detection.
302 */
303 memmove(_timestampBuffer + 1, _timestampBuffer, (kMeanBufferLength - 1) *
pbos@webrtc.org1ab45f62013-04-09 13:38:10 +0000304 sizeof(uint32_t));
niklase@google.com470e71d2011-07-07 08:21:25 +0000305 _timestampBuffer[0] = timestamp;
306
307 /* Compute current frame rate (Q4) */
308 if (_timestampBuffer[kMeanBufferLength - 1] != 0)
309 {
310 frameRate = ((90000 << 4) * (kMeanBufferLength - 1));
311 frameRate /= (_timestampBuffer[0] - _timestampBuffer[kMeanBufferLength - 1]);
312 }else if (_timestampBuffer[1] != 0)
313 {
314 frameRate = (90000 << 4) / (_timestampBuffer[0] - _timestampBuffer[1]);
315 }
316
317 /* Determine required size of mean value buffer (_meanBufferLength) */
318 if (frameRate == 0) {
319 meanBufferLength = 1;
320 }
321 else {
322 meanBufferLength = (kNumFlickerBeforeDetect * frameRate) / kMinFrequencyToDetect;
323 }
324 /* Sanity check of buffer length */
325 if (meanBufferLength >= kMeanBufferLength)
326 {
327 /* Too long buffer. The flickering frequency is too close to zero, which
328 * makes the estimation unreliable.
329 */
330 _meanBufferLength = 0;
331 return 2;
332 }
333 _meanBufferLength = meanBufferLength;
334
335 if ((_timestampBuffer[_meanBufferLength - 1] != 0) && (_meanBufferLength != 1))
336 {
337 frameRate = ((90000 << 4) * (_meanBufferLength - 1));
338 frameRate /= (_timestampBuffer[0] - _timestampBuffer[_meanBufferLength - 1]);
339 }else if (_timestampBuffer[1] != 0)
340 {
341 frameRate = (90000 << 4) / (_timestampBuffer[0] - _timestampBuffer[1]);
342 }
343 _frameRate = frameRate;
344
345 return 0;
346}
347
348/**
349 This function detects flicker in the video stream. As a side effect the mean value
350 buffer is updated with the new mean value.
351
352 \return 0: No flickering detected\n
353 1: Flickering detected\n
354 2: Detection not possible due to unreliable frequency interval
355 -1: Error
356*/
pbos@webrtc.org1ab45f62013-04-09 13:38:10 +0000357int32_t VPMDeflickering::DetectFlicker()
niklase@google.com470e71d2011-07-07 08:21:25 +0000358{
359 /* Local variables */
pbos@webrtc.org1ab45f62013-04-09 13:38:10 +0000360 uint32_t i;
361 int32_t freqEst; // (Q4) Frequency estimate to base detection upon
362 int32_t retVal = -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000363
364 /* Sanity check for _meanBufferLength */
365 if (_meanBufferLength < 2)
366 {
367 /* Not possible to estimate frequency */
368 return(2);
369 }
370 /* Count zero crossings with a dead zone to be robust against noise.
371 * If the noise std is 2 pixel this corresponds to about 95% confidence interval.
372 */
pbos@webrtc.org1ab45f62013-04-09 13:38:10 +0000373 int32_t deadzone = (kZeroCrossingDeadzone << kMeanValueScaling); // Q4
374 int32_t meanOfBuffer = 0; // Mean value of mean value buffer
375 int32_t numZeros = 0; // Number of zeros that cross the deadzone
376 int32_t cntState = 0; // State variable for zero crossing regions
377 int32_t cntStateOld = 0; // Previous state variable for zero crossing regions
niklase@google.com470e71d2011-07-07 08:21:25 +0000378
379 for (i = 0; i < _meanBufferLength; i++)
380 {
381 meanOfBuffer += _meanBuffer[i];
382 }
383 meanOfBuffer += (_meanBufferLength >> 1); // Rounding, not truncation
384 meanOfBuffer /= _meanBufferLength;
385
386 /* Count zero crossings */
387 cntStateOld = (_meanBuffer[0] >= (meanOfBuffer + deadzone));
388 cntStateOld -= (_meanBuffer[0] <= (meanOfBuffer - deadzone));
389 for (i = 1; i < _meanBufferLength; i++)
390 {
391 cntState = (_meanBuffer[i] >= (meanOfBuffer + deadzone));
392 cntState -= (_meanBuffer[i] <= (meanOfBuffer - deadzone));
393 if (cntStateOld == 0)
394 {
395 cntStateOld = -cntState;
396 }
397 if (((cntState + cntStateOld) == 0) && (cntState != 0))
398 {
399 numZeros++;
400 cntStateOld = cntState;
401 }
402 }
403 /* END count zero crossings */
404
405 /* Frequency estimation according to:
406 * freqEst = numZeros * frameRate / 2 / _meanBufferLength;
407 *
408 * Resolution is set to Q4
409 */
410 freqEst = ((numZeros * 90000) << 3);
411 freqEst /= (_timestampBuffer[0] - _timestampBuffer[_meanBufferLength - 1]);
412
413 /* Translate frequency estimate to regions close to 100 and 120 Hz */
pbos@webrtc.org1ab45f62013-04-09 13:38:10 +0000414 uint8_t freqState = 0; // Current translation state;
niklase@google.com470e71d2011-07-07 08:21:25 +0000415 // (0) Not in interval,
416 // (1) Within valid interval,
417 // (2) Out of range
pbos@webrtc.org1ab45f62013-04-09 13:38:10 +0000418 int32_t freqAlias = freqEst;
niklase@google.com470e71d2011-07-07 08:21:25 +0000419 if (freqEst > kMinFrequencyToDetect)
420 {
pbos@webrtc.org1ab45f62013-04-09 13:38:10 +0000421 uint8_t aliasState = 1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000422 while(freqState == 0)
423 {
424 /* Increase frequency */
425 freqAlias += (aliasState * _frameRate);
426 freqAlias += ((freqEst << 1) * (1 - (aliasState << 1)));
427 /* Compute state */
428 freqState = (abs(freqAlias - (100 << 4)) <= kFrequencyDeviation);
429 freqState += (abs(freqAlias - (120 << 4)) <= kFrequencyDeviation);
430 freqState += 2 * (freqAlias > ((120 << 4) + kFrequencyDeviation));
431 /* Switch alias state */
432 aliasState++;
433 aliasState &= 0x01;
434 }
435 }
436 /* Is frequency estimate within detection region? */
437 if (freqState == 1)
438 {
439 retVal = 1;
440 }else if (freqState == 0)
441 {
442 retVal = 2;
443 }else
444 {
445 retVal = 0;
446 }
447 return retVal;
448}
449
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +0000450} // namespace