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