1 /* 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 11 #include "webrtc/base/checks.h" 12 #include "webrtc/modules/video_processing/include/video_processing.h" 13 #include "webrtc/modules/video_processing/video_decimator.h" 14 #include "webrtc/system_wrappers/include/tick_util.h" 15 16 #define VD_MIN(a, b) ((a) < (b)) ? (a) : (b) 17 18 namespace webrtc { 19 VPMVideoDecimator()20VPMVideoDecimator::VPMVideoDecimator() { 21 Reset(); 22 } 23 ~VPMVideoDecimator()24VPMVideoDecimator::~VPMVideoDecimator() {} 25 Reset()26void VPMVideoDecimator::Reset() { 27 overshoot_modifier_ = 0; 28 drop_count_ = 0; 29 keep_count_ = 0; 30 target_frame_rate_ = 30; 31 incoming_frame_rate_ = 0.0f; 32 memset(incoming_frame_times_, 0, sizeof(incoming_frame_times_)); 33 enable_temporal_decimation_ = true; 34 } 35 EnableTemporalDecimation(bool enable)36void VPMVideoDecimator::EnableTemporalDecimation(bool enable) { 37 enable_temporal_decimation_ = enable; 38 } 39 SetTargetFramerate(int frame_rate)40void VPMVideoDecimator::SetTargetFramerate(int frame_rate) { 41 RTC_DCHECK(frame_rate); 42 target_frame_rate_ = frame_rate; 43 } 44 DropFrame()45bool VPMVideoDecimator::DropFrame() { 46 if (!enable_temporal_decimation_) 47 return false; 48 49 if (incoming_frame_rate_ <= 0) 50 return false; 51 52 const uint32_t incomingframe_rate = 53 static_cast<uint32_t>(incoming_frame_rate_ + 0.5f); 54 55 if (target_frame_rate_ == 0) 56 return true; 57 58 bool drop = false; 59 if (incomingframe_rate > target_frame_rate_) { 60 int32_t overshoot = 61 overshoot_modifier_ + (incomingframe_rate - target_frame_rate_); 62 if (overshoot < 0) { 63 overshoot = 0; 64 overshoot_modifier_ = 0; 65 } 66 67 if (overshoot && 2 * overshoot < (int32_t)incomingframe_rate) { 68 if (drop_count_) { // Just got here so drop to be sure. 69 drop_count_ = 0; 70 return true; 71 } 72 const uint32_t dropVar = incomingframe_rate / overshoot; 73 74 if (keep_count_ >= dropVar) { 75 drop = true; 76 overshoot_modifier_ = -((int32_t)incomingframe_rate % overshoot) / 3; 77 keep_count_ = 1; 78 } else { 79 keep_count_++; 80 } 81 } else { 82 keep_count_ = 0; 83 const uint32_t dropVar = overshoot / target_frame_rate_; 84 if (drop_count_ < dropVar) { 85 drop = true; 86 drop_count_++; 87 } else { 88 overshoot_modifier_ = overshoot % target_frame_rate_; 89 drop = false; 90 drop_count_ = 0; 91 } 92 } 93 } 94 return drop; 95 } 96 GetDecimatedFrameRate()97uint32_t VPMVideoDecimator::GetDecimatedFrameRate() { 98 ProcessIncomingframe_rate(TickTime::MillisecondTimestamp()); 99 if (!enable_temporal_decimation_) { 100 return static_cast<uint32_t>(incoming_frame_rate_ + 0.5f); 101 } 102 return VD_MIN(target_frame_rate_, 103 static_cast<uint32_t>(incoming_frame_rate_ + 0.5f)); 104 } 105 Inputframe_rate()106uint32_t VPMVideoDecimator::Inputframe_rate() { 107 ProcessIncomingframe_rate(TickTime::MillisecondTimestamp()); 108 return static_cast<uint32_t>(incoming_frame_rate_ + 0.5f); 109 } 110 UpdateIncomingframe_rate()111void VPMVideoDecimator::UpdateIncomingframe_rate() { 112 int64_t now = TickTime::MillisecondTimestamp(); 113 if (incoming_frame_times_[0] == 0) { 114 // First no shift. 115 } else { 116 // Shift. 117 for (int i = kFrameCountHistory_size - 2; i >= 0; i--) { 118 incoming_frame_times_[i + 1] = incoming_frame_times_[i]; 119 } 120 } 121 incoming_frame_times_[0] = now; 122 ProcessIncomingframe_rate(now); 123 } 124 ProcessIncomingframe_rate(int64_t now)125void VPMVideoDecimator::ProcessIncomingframe_rate(int64_t now) { 126 int32_t num = 0; 127 int32_t nrOfFrames = 0; 128 for (num = 1; num < (kFrameCountHistory_size - 1); num++) { 129 // Don't use data older than 2sec. 130 if (incoming_frame_times_[num] <= 0 || 131 now - incoming_frame_times_[num] > kFrameHistoryWindowMs) { 132 break; 133 } else { 134 nrOfFrames++; 135 } 136 } 137 if (num > 1) { 138 int64_t diff = now - incoming_frame_times_[num - 1]; 139 incoming_frame_rate_ = 1.0; 140 if (diff > 0) { 141 incoming_frame_rate_ = nrOfFrames * 1000.0f / static_cast<float>(diff); 142 } 143 } else { 144 incoming_frame_rate_ = static_cast<float>(nrOfFrames); 145 } 146 } 147 148 } // namespace webrtc 149