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