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
11b7ce96470b99510937e489bcb4dc3165a9ab1b28kjellander@webrtc.org#include "webrtc/modules/video_coding/utility/frame_dropper.h"
12eb91792cfd98a76192a855365bb785c0f581b94bstefan@webrtc.org
1398f53510b222f71fdd8b799b2f33737ceeb28c61Henrik Kjellander#include "webrtc/system_wrappers/include/trace.h"
14470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
155908c71128aea207e42f86468aedb0a6fce3cccbphilipelnamespace webrtc {
16470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1784cd8e39cf2a998248daa16cae7b7713f79da0d8stefan@webrtc.orgconst float kDefaultKeyFrameSizeAvgKBits = 0.9f;
1884cd8e39cf2a998248daa16cae7b7713f79da0d8stefan@webrtc.orgconst float kDefaultKeyFrameRatio = 0.99f;
1984cd8e39cf2a998248daa16cae7b7713f79da0d8stefan@webrtc.orgconst float kDefaultDropRatioAlpha = 0.9f;
2084cd8e39cf2a998248daa16cae7b7713f79da0d8stefan@webrtc.orgconst float kDefaultDropRatioMax = 0.96f;
2184cd8e39cf2a998248daa16cae7b7713f79da0d8stefan@webrtc.orgconst float kDefaultMaxTimeToDropFrames = 4.0f;  // In seconds.
2284cd8e39cf2a998248daa16cae7b7713f79da0d8stefan@webrtc.org
23eb91792cfd98a76192a855365bb785c0f581b94bstefan@webrtc.orgFrameDropper::FrameDropper()
245908c71128aea207e42f86468aedb0a6fce3cccbphilipel    : _keyFrameSizeAvgKbits(kDefaultKeyFrameSizeAvgKBits),
255908c71128aea207e42f86468aedb0a6fce3cccbphilipel      _keyFrameRatio(kDefaultKeyFrameRatio),
265908c71128aea207e42f86468aedb0a6fce3cccbphilipel      _dropRatio(kDefaultDropRatioAlpha, kDefaultDropRatioMax),
275908c71128aea207e42f86468aedb0a6fce3cccbphilipel      _enabled(true),
285908c71128aea207e42f86468aedb0a6fce3cccbphilipel      _max_time_drops(kDefaultMaxTimeToDropFrames) {
295908c71128aea207e42f86468aedb0a6fce3cccbphilipel  Reset();
3084cd8e39cf2a998248daa16cae7b7713f79da0d8stefan@webrtc.org}
3184cd8e39cf2a998248daa16cae7b7713f79da0d8stefan@webrtc.org
3284cd8e39cf2a998248daa16cae7b7713f79da0d8stefan@webrtc.orgFrameDropper::FrameDropper(float max_time_drops)
335908c71128aea207e42f86468aedb0a6fce3cccbphilipel    : _keyFrameSizeAvgKbits(kDefaultKeyFrameSizeAvgKBits),
345908c71128aea207e42f86468aedb0a6fce3cccbphilipel      _keyFrameRatio(kDefaultKeyFrameRatio),
355908c71128aea207e42f86468aedb0a6fce3cccbphilipel      _dropRatio(kDefaultDropRatioAlpha, kDefaultDropRatioMax),
365908c71128aea207e42f86468aedb0a6fce3cccbphilipel      _enabled(true),
375908c71128aea207e42f86468aedb0a6fce3cccbphilipel      _max_time_drops(max_time_drops) {
385908c71128aea207e42f86468aedb0a6fce3cccbphilipel  Reset();
39470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
40470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
415908c71128aea207e42f86468aedb0a6fce3cccbphilipelvoid FrameDropper::Reset() {
425908c71128aea207e42f86468aedb0a6fce3cccbphilipel  _keyFrameRatio.Reset(0.99f);
435908c71128aea207e42f86468aedb0a6fce3cccbphilipel  _keyFrameRatio.Apply(
445908c71128aea207e42f86468aedb0a6fce3cccbphilipel      1.0f, 1.0f / 300.0f);  // 1 key frame every 10th second in 30 fps
455908c71128aea207e42f86468aedb0a6fce3cccbphilipel  _keyFrameSizeAvgKbits.Reset(0.9f);
465908c71128aea207e42f86468aedb0a6fce3cccbphilipel  _keyFrameCount = 0;
475908c71128aea207e42f86468aedb0a6fce3cccbphilipel  _accumulator = 0.0f;
485908c71128aea207e42f86468aedb0a6fce3cccbphilipel  _accumulatorMax = 150.0f;  // assume 300 kb/s and 0.5 s window
495908c71128aea207e42f86468aedb0a6fce3cccbphilipel  _targetBitRate = 300.0f;
505908c71128aea207e42f86468aedb0a6fce3cccbphilipel  _incoming_frame_rate = 30;
515908c71128aea207e42f86468aedb0a6fce3cccbphilipel  _keyFrameSpreadFrames = 0.5f * _incoming_frame_rate;
525908c71128aea207e42f86468aedb0a6fce3cccbphilipel  _dropNext = false;
535908c71128aea207e42f86468aedb0a6fce3cccbphilipel  _dropRatio.Reset(0.9f);
545908c71128aea207e42f86468aedb0a6fce3cccbphilipel  _dropRatio.Apply(0.0f, 0.0f);  // Initialize to 0
555908c71128aea207e42f86468aedb0a6fce3cccbphilipel  _dropCount = 0;
565908c71128aea207e42f86468aedb0a6fce3cccbphilipel  _windowSize = 0.5f;
575908c71128aea207e42f86468aedb0a6fce3cccbphilipel  _wasBelowMax = true;
585908c71128aea207e42f86468aedb0a6fce3cccbphilipel  _fastMode = false;  // start with normal (non-aggressive) mode
595908c71128aea207e42f86468aedb0a6fce3cccbphilipel  // Cap for the encoder buffer level/accumulator, in secs.
605908c71128aea207e42f86468aedb0a6fce3cccbphilipel  _cap_buffer_size = 3.0f;
615908c71128aea207e42f86468aedb0a6fce3cccbphilipel  // Cap on maximum amount of dropped frames between kept frames, in secs.
625908c71128aea207e42f86468aedb0a6fce3cccbphilipel  _max_time_drops = 4.0f;
63470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
64470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
655908c71128aea207e42f86468aedb0a6fce3cccbphilipelvoid FrameDropper::Enable(bool enable) {
665908c71128aea207e42f86468aedb0a6fce3cccbphilipel  _enabled = enable;
67470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
68470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
695908c71128aea207e42f86468aedb0a6fce3cccbphilipelvoid FrameDropper::Fill(size_t frameSizeBytes, bool deltaFrame) {
705908c71128aea207e42f86468aedb0a6fce3cccbphilipel  if (!_enabled) {
715908c71128aea207e42f86468aedb0a6fce3cccbphilipel    return;
725908c71128aea207e42f86468aedb0a6fce3cccbphilipel  }
735908c71128aea207e42f86468aedb0a6fce3cccbphilipel  float frameSizeKbits = 8.0f * static_cast<float>(frameSizeBytes) / 1000.0f;
745908c71128aea207e42f86468aedb0a6fce3cccbphilipel  if (!deltaFrame &&
755908c71128aea207e42f86468aedb0a6fce3cccbphilipel      !_fastMode) {  // fast mode does not treat key-frames any different
765908c71128aea207e42f86468aedb0a6fce3cccbphilipel    _keyFrameSizeAvgKbits.Apply(1, frameSizeKbits);
775908c71128aea207e42f86468aedb0a6fce3cccbphilipel    _keyFrameRatio.Apply(1.0, 1.0);
785908c71128aea207e42f86468aedb0a6fce3cccbphilipel    if (frameSizeKbits > _keyFrameSizeAvgKbits.filtered()) {
795908c71128aea207e42f86468aedb0a6fce3cccbphilipel      // Remove the average key frame size since we
805908c71128aea207e42f86468aedb0a6fce3cccbphilipel      // compensate for key frames when adding delta
815908c71128aea207e42f86468aedb0a6fce3cccbphilipel      // frames.
825908c71128aea207e42f86468aedb0a6fce3cccbphilipel      frameSizeKbits -= _keyFrameSizeAvgKbits.filtered();
835908c71128aea207e42f86468aedb0a6fce3cccbphilipel    } else {
845908c71128aea207e42f86468aedb0a6fce3cccbphilipel      // Shouldn't be negative, so zero is the lower bound.
855908c71128aea207e42f86468aedb0a6fce3cccbphilipel      frameSizeKbits = 0;
86470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
875908c71128aea207e42f86468aedb0a6fce3cccbphilipel    if (_keyFrameRatio.filtered() > 1e-5 &&
885908c71128aea207e42f86468aedb0a6fce3cccbphilipel        1 / _keyFrameRatio.filtered() < _keyFrameSpreadFrames) {
895908c71128aea207e42f86468aedb0a6fce3cccbphilipel      // We are sending key frames more often than our upper bound for
905908c71128aea207e42f86468aedb0a6fce3cccbphilipel      // how much we allow the key frame compensation to be spread
915908c71128aea207e42f86468aedb0a6fce3cccbphilipel      // out in time. Therefor we must use the key frame ratio rather
925908c71128aea207e42f86468aedb0a6fce3cccbphilipel      // than keyFrameSpreadFrames.
935908c71128aea207e42f86468aedb0a6fce3cccbphilipel      _keyFrameCount =
945908c71128aea207e42f86468aedb0a6fce3cccbphilipel          static_cast<int32_t>(1 / _keyFrameRatio.filtered() + 0.5);
955908c71128aea207e42f86468aedb0a6fce3cccbphilipel    } else {
965908c71128aea207e42f86468aedb0a6fce3cccbphilipel      // Compensate for the key frame the following frames
975908c71128aea207e42f86468aedb0a6fce3cccbphilipel      _keyFrameCount = static_cast<int32_t>(_keyFrameSpreadFrames + 0.5);
98470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
995908c71128aea207e42f86468aedb0a6fce3cccbphilipel  } else {
1005908c71128aea207e42f86468aedb0a6fce3cccbphilipel    // Decrease the keyFrameRatio
1015908c71128aea207e42f86468aedb0a6fce3cccbphilipel    _keyFrameRatio.Apply(1.0, 0.0);
1025908c71128aea207e42f86468aedb0a6fce3cccbphilipel  }
1035908c71128aea207e42f86468aedb0a6fce3cccbphilipel  // Change the level of the accumulator (bucket)
1045908c71128aea207e42f86468aedb0a6fce3cccbphilipel  _accumulator += frameSizeKbits;
1055908c71128aea207e42f86468aedb0a6fce3cccbphilipel  CapAccumulator();
106470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
107470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1085908c71128aea207e42f86468aedb0a6fce3cccbphilipelvoid FrameDropper::Leak(uint32_t inputFrameRate) {
1095908c71128aea207e42f86468aedb0a6fce3cccbphilipel  if (!_enabled) {
1105908c71128aea207e42f86468aedb0a6fce3cccbphilipel    return;
1115908c71128aea207e42f86468aedb0a6fce3cccbphilipel  }
1125908c71128aea207e42f86468aedb0a6fce3cccbphilipel  if (inputFrameRate < 1) {
1135908c71128aea207e42f86468aedb0a6fce3cccbphilipel    return;
1145908c71128aea207e42f86468aedb0a6fce3cccbphilipel  }
1155908c71128aea207e42f86468aedb0a6fce3cccbphilipel  if (_targetBitRate < 0.0f) {
1165908c71128aea207e42f86468aedb0a6fce3cccbphilipel    return;
1175908c71128aea207e42f86468aedb0a6fce3cccbphilipel  }
1185908c71128aea207e42f86468aedb0a6fce3cccbphilipel  _keyFrameSpreadFrames = 0.5f * inputFrameRate;
1195908c71128aea207e42f86468aedb0a6fce3cccbphilipel  // T is the expected bits per frame (target). If all frames were the same
1205908c71128aea207e42f86468aedb0a6fce3cccbphilipel  // size,
1215908c71128aea207e42f86468aedb0a6fce3cccbphilipel  // we would get T bits per frame. Notice that T is also weighted to be able to
1225908c71128aea207e42f86468aedb0a6fce3cccbphilipel  // force a lower frame rate if wanted.
1235908c71128aea207e42f86468aedb0a6fce3cccbphilipel  float T = _targetBitRate / inputFrameRate;
1245908c71128aea207e42f86468aedb0a6fce3cccbphilipel  if (_keyFrameCount > 0) {
1255908c71128aea207e42f86468aedb0a6fce3cccbphilipel    // Perform the key frame compensation
1265908c71128aea207e42f86468aedb0a6fce3cccbphilipel    if (_keyFrameRatio.filtered() > 0 &&
1275908c71128aea207e42f86468aedb0a6fce3cccbphilipel        1 / _keyFrameRatio.filtered() < _keyFrameSpreadFrames) {
1285908c71128aea207e42f86468aedb0a6fce3cccbphilipel      T -= _keyFrameSizeAvgKbits.filtered() * _keyFrameRatio.filtered();
1295908c71128aea207e42f86468aedb0a6fce3cccbphilipel    } else {
1305908c71128aea207e42f86468aedb0a6fce3cccbphilipel      T -= _keyFrameSizeAvgKbits.filtered() / _keyFrameSpreadFrames;
13184cd8e39cf2a998248daa16cae7b7713f79da0d8stefan@webrtc.org    }
1325908c71128aea207e42f86468aedb0a6fce3cccbphilipel    _keyFrameCount--;
1335908c71128aea207e42f86468aedb0a6fce3cccbphilipel  }
1345908c71128aea207e42f86468aedb0a6fce3cccbphilipel  _accumulator -= T;
1355908c71128aea207e42f86468aedb0a6fce3cccbphilipel  if (_accumulator < 0.0f) {
1365908c71128aea207e42f86468aedb0a6fce3cccbphilipel    _accumulator = 0.0f;
1375908c71128aea207e42f86468aedb0a6fce3cccbphilipel  }
1385908c71128aea207e42f86468aedb0a6fce3cccbphilipel  UpdateRatio();
139470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
140470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1415908c71128aea207e42f86468aedb0a6fce3cccbphilipelvoid FrameDropper::UpdateNack(uint32_t nackBytes) {
1425908c71128aea207e42f86468aedb0a6fce3cccbphilipel  if (!_enabled) {
1435908c71128aea207e42f86468aedb0a6fce3cccbphilipel    return;
1445908c71128aea207e42f86468aedb0a6fce3cccbphilipel  }
1455908c71128aea207e42f86468aedb0a6fce3cccbphilipel  _accumulator += static_cast<float>(nackBytes) * 8.0f / 1000.0f;
146470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
147470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1485908c71128aea207e42f86468aedb0a6fce3cccbphilipelvoid FrameDropper::FillBucket(float inKbits, float outKbits) {
1495908c71128aea207e42f86468aedb0a6fce3cccbphilipel  _accumulator += (inKbits - outKbits);
150470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
151470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1525908c71128aea207e42f86468aedb0a6fce3cccbphilipelvoid FrameDropper::UpdateRatio() {
1535908c71128aea207e42f86468aedb0a6fce3cccbphilipel  if (_accumulator > 1.3f * _accumulatorMax) {
1545908c71128aea207e42f86468aedb0a6fce3cccbphilipel    // Too far above accumulator max, react faster
1555908c71128aea207e42f86468aedb0a6fce3cccbphilipel    _dropRatio.UpdateBase(0.8f);
1565908c71128aea207e42f86468aedb0a6fce3cccbphilipel  } else {
1575908c71128aea207e42f86468aedb0a6fce3cccbphilipel    // Go back to normal reaction
1585908c71128aea207e42f86468aedb0a6fce3cccbphilipel    _dropRatio.UpdateBase(0.9f);
1595908c71128aea207e42f86468aedb0a6fce3cccbphilipel  }
1605908c71128aea207e42f86468aedb0a6fce3cccbphilipel  if (_accumulator > _accumulatorMax) {
1615908c71128aea207e42f86468aedb0a6fce3cccbphilipel    // We are above accumulator max, and should ideally
1625908c71128aea207e42f86468aedb0a6fce3cccbphilipel    // drop a frame. Increase the dropRatio and drop
1635908c71128aea207e42f86468aedb0a6fce3cccbphilipel    // the frame later.
1645908c71128aea207e42f86468aedb0a6fce3cccbphilipel    if (_wasBelowMax) {
1655908c71128aea207e42f86468aedb0a6fce3cccbphilipel      _dropNext = true;
166470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1675908c71128aea207e42f86468aedb0a6fce3cccbphilipel    if (_fastMode) {
1685908c71128aea207e42f86468aedb0a6fce3cccbphilipel      // always drop in aggressive mode
1695908c71128aea207e42f86468aedb0a6fce3cccbphilipel      _dropNext = true;
170470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
171470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1725908c71128aea207e42f86468aedb0a6fce3cccbphilipel    _dropRatio.Apply(1.0f, 1.0f);
1735908c71128aea207e42f86468aedb0a6fce3cccbphilipel    _dropRatio.UpdateBase(0.9f);
1745908c71128aea207e42f86468aedb0a6fce3cccbphilipel  } else {
1755908c71128aea207e42f86468aedb0a6fce3cccbphilipel    _dropRatio.Apply(1.0f, 0.0f);
1765908c71128aea207e42f86468aedb0a6fce3cccbphilipel  }
1775908c71128aea207e42f86468aedb0a6fce3cccbphilipel  _wasBelowMax = _accumulator < _accumulatorMax;
178470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
179470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1805908c71128aea207e42f86468aedb0a6fce3cccbphilipel// This function signals when to drop frames to the caller. It makes use of the
1815908c71128aea207e42f86468aedb0a6fce3cccbphilipel// dropRatio
182470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com// to smooth out the drops over time.
1835908c71128aea207e42f86468aedb0a6fce3cccbphilipelbool FrameDropper::DropFrame() {
1845908c71128aea207e42f86468aedb0a6fce3cccbphilipel  if (!_enabled) {
1855908c71128aea207e42f86468aedb0a6fce3cccbphilipel    return false;
1865908c71128aea207e42f86468aedb0a6fce3cccbphilipel  }
1875908c71128aea207e42f86468aedb0a6fce3cccbphilipel  if (_dropNext) {
1885908c71128aea207e42f86468aedb0a6fce3cccbphilipel    _dropNext = false;
1895908c71128aea207e42f86468aedb0a6fce3cccbphilipel    _dropCount = 0;
1905908c71128aea207e42f86468aedb0a6fce3cccbphilipel  }
1915908c71128aea207e42f86468aedb0a6fce3cccbphilipel
1925908c71128aea207e42f86468aedb0a6fce3cccbphilipel  if (_dropRatio.filtered() >= 0.5f) {  // Drops per keep
1935908c71128aea207e42f86468aedb0a6fce3cccbphilipel    // limit is the number of frames we should drop between each kept frame
1945908c71128aea207e42f86468aedb0a6fce3cccbphilipel    // to keep our drop ratio. limit is positive in this case.
1955908c71128aea207e42f86468aedb0a6fce3cccbphilipel    float denom = 1.0f - _dropRatio.filtered();
1965908c71128aea207e42f86468aedb0a6fce3cccbphilipel    if (denom < 1e-5) {
1975908c71128aea207e42f86468aedb0a6fce3cccbphilipel      denom = 1e-5f;
1985908c71128aea207e42f86468aedb0a6fce3cccbphilipel    }
1995908c71128aea207e42f86468aedb0a6fce3cccbphilipel    int32_t limit = static_cast<int32_t>(1.0f / denom - 1.0f + 0.5f);
2005908c71128aea207e42f86468aedb0a6fce3cccbphilipel    // Put a bound on the max amount of dropped frames between each kept
2015908c71128aea207e42f86468aedb0a6fce3cccbphilipel    // frame, in terms of frame rate and window size (secs).
2025908c71128aea207e42f86468aedb0a6fce3cccbphilipel    int max_limit = static_cast<int>(_incoming_frame_rate * _max_time_drops);
2035908c71128aea207e42f86468aedb0a6fce3cccbphilipel    if (limit > max_limit) {
2045908c71128aea207e42f86468aedb0a6fce3cccbphilipel      limit = max_limit;
205470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2065908c71128aea207e42f86468aedb0a6fce3cccbphilipel    if (_dropCount < 0) {
2075908c71128aea207e42f86468aedb0a6fce3cccbphilipel      // Reset the _dropCount since it was negative and should be positive.
2085908c71128aea207e42f86468aedb0a6fce3cccbphilipel      if (_dropRatio.filtered() > 0.4f) {
2095908c71128aea207e42f86468aedb0a6fce3cccbphilipel        _dropCount = -_dropCount;
2105908c71128aea207e42f86468aedb0a6fce3cccbphilipel      } else {
211470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _dropCount = 0;
2125908c71128aea207e42f86468aedb0a6fce3cccbphilipel      }
213470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2145908c71128aea207e42f86468aedb0a6fce3cccbphilipel    if (_dropCount < limit) {
2155908c71128aea207e42f86468aedb0a6fce3cccbphilipel      // As long we are below the limit we should drop frames.
2165908c71128aea207e42f86468aedb0a6fce3cccbphilipel      _dropCount++;
2175908c71128aea207e42f86468aedb0a6fce3cccbphilipel      return true;
2185908c71128aea207e42f86468aedb0a6fce3cccbphilipel    } else {
2195908c71128aea207e42f86468aedb0a6fce3cccbphilipel      // Only when we reset _dropCount a frame should be kept.
2205908c71128aea207e42f86468aedb0a6fce3cccbphilipel      _dropCount = 0;
2215908c71128aea207e42f86468aedb0a6fce3cccbphilipel      return false;
222470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2235908c71128aea207e42f86468aedb0a6fce3cccbphilipel  } else if (_dropRatio.filtered() > 0.0f &&
2245908c71128aea207e42f86468aedb0a6fce3cccbphilipel             _dropRatio.filtered() < 0.5f) {  // Keeps per drop
2255908c71128aea207e42f86468aedb0a6fce3cccbphilipel    // limit is the number of frames we should keep between each drop
2265908c71128aea207e42f86468aedb0a6fce3cccbphilipel    // in order to keep the drop ratio. limit is negative in this case,
2275908c71128aea207e42f86468aedb0a6fce3cccbphilipel    // and the _dropCount is also negative.
2285908c71128aea207e42f86468aedb0a6fce3cccbphilipel    float denom = _dropRatio.filtered();
2295908c71128aea207e42f86468aedb0a6fce3cccbphilipel    if (denom < 1e-5) {
2305908c71128aea207e42f86468aedb0a6fce3cccbphilipel      denom = 1e-5f;
231470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
2325908c71128aea207e42f86468aedb0a6fce3cccbphilipel    int32_t limit = -static_cast<int32_t>(1.0f / denom - 1.0f + 0.5f);
2335908c71128aea207e42f86468aedb0a6fce3cccbphilipel    if (_dropCount > 0) {
2345908c71128aea207e42f86468aedb0a6fce3cccbphilipel      // Reset the _dropCount since we have a positive
2355908c71128aea207e42f86468aedb0a6fce3cccbphilipel      // _dropCount, and it should be negative.
2365908c71128aea207e42f86468aedb0a6fce3cccbphilipel      if (_dropRatio.filtered() < 0.6f) {
2375908c71128aea207e42f86468aedb0a6fce3cccbphilipel        _dropCount = -_dropCount;
2385908c71128aea207e42f86468aedb0a6fce3cccbphilipel      } else {
2395908c71128aea207e42f86468aedb0a6fce3cccbphilipel        _dropCount = 0;
2405908c71128aea207e42f86468aedb0a6fce3cccbphilipel      }
2415908c71128aea207e42f86468aedb0a6fce3cccbphilipel    }
2425908c71128aea207e42f86468aedb0a6fce3cccbphilipel    if (_dropCount > limit) {
2435908c71128aea207e42f86468aedb0a6fce3cccbphilipel      if (_dropCount == 0) {
2445908c71128aea207e42f86468aedb0a6fce3cccbphilipel        // Drop frames when we reset _dropCount.
2455908c71128aea207e42f86468aedb0a6fce3cccbphilipel        _dropCount--;
2465908c71128aea207e42f86468aedb0a6fce3cccbphilipel        return true;
2475908c71128aea207e42f86468aedb0a6fce3cccbphilipel      } else {
2485908c71128aea207e42f86468aedb0a6fce3cccbphilipel        // Keep frames as long as we haven't reached limit.
2495908c71128aea207e42f86468aedb0a6fce3cccbphilipel        _dropCount--;
2505908c71128aea207e42f86468aedb0a6fce3cccbphilipel        return false;
2515908c71128aea207e42f86468aedb0a6fce3cccbphilipel      }
2525908c71128aea207e42f86468aedb0a6fce3cccbphilipel    } else {
2535908c71128aea207e42f86468aedb0a6fce3cccbphilipel      _dropCount = 0;
2545908c71128aea207e42f86468aedb0a6fce3cccbphilipel      return false;
2555908c71128aea207e42f86468aedb0a6fce3cccbphilipel    }
2565908c71128aea207e42f86468aedb0a6fce3cccbphilipel  }
2575908c71128aea207e42f86468aedb0a6fce3cccbphilipel  _dropCount = 0;
2585908c71128aea207e42f86468aedb0a6fce3cccbphilipel  return false;
259470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2605908c71128aea207e42f86468aedb0a6fce3cccbphilipel  // A simpler version, unfiltered and quicker
2615908c71128aea207e42f86468aedb0a6fce3cccbphilipel  // bool dropNext = _dropNext;
2625908c71128aea207e42f86468aedb0a6fce3cccbphilipel  // _dropNext = false;
2635908c71128aea207e42f86468aedb0a6fce3cccbphilipel  // return dropNext;
264470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
265470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2665908c71128aea207e42f86468aedb0a6fce3cccbphilipelvoid FrameDropper::SetRates(float bitRate, float incoming_frame_rate) {
2675908c71128aea207e42f86468aedb0a6fce3cccbphilipel  // Bit rate of -1 means infinite bandwidth.
2685908c71128aea207e42f86468aedb0a6fce3cccbphilipel  _accumulatorMax = bitRate * _windowSize;  // bitRate * windowSize (in seconds)
2695908c71128aea207e42f86468aedb0a6fce3cccbphilipel  if (_targetBitRate > 0.0f && bitRate < _targetBitRate &&
2705908c71128aea207e42f86468aedb0a6fce3cccbphilipel      _accumulator > _accumulatorMax) {
2715908c71128aea207e42f86468aedb0a6fce3cccbphilipel    // Rescale the accumulator level if the accumulator max decreases
2725908c71128aea207e42f86468aedb0a6fce3cccbphilipel    _accumulator = bitRate / _targetBitRate * _accumulator;
2735908c71128aea207e42f86468aedb0a6fce3cccbphilipel  }
2745908c71128aea207e42f86468aedb0a6fce3cccbphilipel  _targetBitRate = bitRate;
2755908c71128aea207e42f86468aedb0a6fce3cccbphilipel  CapAccumulator();
2765908c71128aea207e42f86468aedb0a6fce3cccbphilipel  _incoming_frame_rate = incoming_frame_rate;
277470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
278470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2795908c71128aea207e42f86468aedb0a6fce3cccbphilipelfloat FrameDropper::ActualFrameRate(uint32_t inputFrameRate) const {
2805908c71128aea207e42f86468aedb0a6fce3cccbphilipel  if (!_enabled) {
2815908c71128aea207e42f86468aedb0a6fce3cccbphilipel    return static_cast<float>(inputFrameRate);
2825908c71128aea207e42f86468aedb0a6fce3cccbphilipel  }
2835908c71128aea207e42f86468aedb0a6fce3cccbphilipel  return inputFrameRate * (1.0f - _dropRatio.filtered());
284470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
285470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2861dd8d4bca49482c4c1f776bdc89c09c2704cd685marpan@webrtc.org// Put a cap on the accumulator, i.e., don't let it grow beyond some level.
2871dd8d4bca49482c4c1f776bdc89c09c2704cd685marpan@webrtc.org// This is a temporary fix for screencasting where very large frames from
2881dd8d4bca49482c4c1f776bdc89c09c2704cd685marpan@webrtc.org// encoder will cause very slow response (too many frame drops).
289eb91792cfd98a76192a855365bb785c0f581b94bstefan@webrtc.orgvoid FrameDropper::CapAccumulator() {
2901dd8d4bca49482c4c1f776bdc89c09c2704cd685marpan@webrtc.org  float max_accumulator = _targetBitRate * _cap_buffer_size;
2911dd8d4bca49482c4c1f776bdc89c09c2704cd685marpan@webrtc.org  if (_accumulator > max_accumulator) {
2921dd8d4bca49482c4c1f776bdc89c09c2704cd685marpan@webrtc.org    _accumulator = max_accumulator;
2931dd8d4bca49482c4c1f776bdc89c09c2704cd685marpan@webrtc.org  }
2941dd8d4bca49482c4c1f776bdc89c09c2704cd685marpan@webrtc.org}
2955908c71128aea207e42f86468aedb0a6fce3cccbphilipel}  // namespace webrtc
296