1 /* 2 * Copyright 2017 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 package org.webrtc; 12 13 /** 14 * BitrateAdjuster that tracks the bandwidth produced by an encoder and dynamically adjusts the 15 * bitrate. Used for hardware codecs that pay attention to framerate but still deviate from the 16 * target bitrate by unacceptable margins. 17 */ 18 class DynamicBitrateAdjuster extends BaseBitrateAdjuster { 19 // Change the bitrate at most once every three seconds. 20 private static final double BITRATE_ADJUSTMENT_SEC = 3.0; 21 // Maximum bitrate adjustment scale - no more than 4 times. 22 private static final double BITRATE_ADJUSTMENT_MAX_SCALE = 4; 23 // Amount of adjustment steps to reach maximum scale. 24 private static final int BITRATE_ADJUSTMENT_STEPS = 20; 25 26 private static final double BITS_PER_BYTE = 8.0; 27 28 // How far the codec has deviated above (or below) the target bitrate (tracked in bytes). 29 private double deviationBytes; 30 private double timeSinceLastAdjustmentMs; 31 private int bitrateAdjustmentScaleExp; 32 33 @Override setTargets(int targetBitrateBps, double targetFramerateFps)34 public void setTargets(int targetBitrateBps, double targetFramerateFps) { 35 if (this.targetBitrateBps > 0 && targetBitrateBps < this.targetBitrateBps) { 36 // Rescale the accumulator level if the accumulator max decreases 37 deviationBytes = deviationBytes * targetBitrateBps / this.targetBitrateBps; 38 } 39 super.setTargets(targetBitrateBps, targetFramerateFps); 40 } 41 42 @Override reportEncodedFrame(int size)43 public void reportEncodedFrame(int size) { 44 if (targetFramerateFps == 0) { 45 return; 46 } 47 48 // Accumulate the difference between actual and expected frame sizes. 49 double expectedBytesPerFrame = (targetBitrateBps / BITS_PER_BYTE) / targetFramerateFps; 50 deviationBytes += (size - expectedBytesPerFrame); 51 timeSinceLastAdjustmentMs += 1000.0 / targetFramerateFps; 52 53 // Adjust the bitrate when the encoder accumulates one second's worth of data in excess or 54 // shortfall of the target. 55 double deviationThresholdBytes = targetBitrateBps / BITS_PER_BYTE; 56 57 // Cap the deviation, i.e., don't let it grow beyond some level to avoid using too old data for 58 // bitrate adjustment. This also prevents taking more than 3 "steps" in a given 3-second cycle. 59 double deviationCap = BITRATE_ADJUSTMENT_SEC * deviationThresholdBytes; 60 deviationBytes = Math.min(deviationBytes, deviationCap); 61 deviationBytes = Math.max(deviationBytes, -deviationCap); 62 63 // Do bitrate adjustment every 3 seconds if actual encoder bitrate deviates too much 64 // from the target value. 65 if (timeSinceLastAdjustmentMs <= 1000 * BITRATE_ADJUSTMENT_SEC) { 66 return; 67 } 68 69 if (deviationBytes > deviationThresholdBytes) { 70 // Encoder generates too high bitrate - need to reduce the scale. 71 int bitrateAdjustmentInc = (int) (deviationBytes / deviationThresholdBytes + 0.5); 72 bitrateAdjustmentScaleExp -= bitrateAdjustmentInc; 73 // Don't let the adjustment scale drop below -BITRATE_ADJUSTMENT_STEPS. 74 // This sets a minimum exponent of -1 (bitrateAdjustmentScaleExp / BITRATE_ADJUSTMENT_STEPS). 75 bitrateAdjustmentScaleExp = Math.max(bitrateAdjustmentScaleExp, -BITRATE_ADJUSTMENT_STEPS); 76 deviationBytes = deviationThresholdBytes; 77 } else if (deviationBytes < -deviationThresholdBytes) { 78 // Encoder generates too low bitrate - need to increase the scale. 79 int bitrateAdjustmentInc = (int) (-deviationBytes / deviationThresholdBytes + 0.5); 80 bitrateAdjustmentScaleExp += bitrateAdjustmentInc; 81 // Don't let the adjustment scale exceed BITRATE_ADJUSTMENT_STEPS. 82 // This sets a maximum exponent of 1 (bitrateAdjustmentScaleExp / BITRATE_ADJUSTMENT_STEPS). 83 bitrateAdjustmentScaleExp = Math.min(bitrateAdjustmentScaleExp, BITRATE_ADJUSTMENT_STEPS); 84 deviationBytes = -deviationThresholdBytes; 85 } 86 timeSinceLastAdjustmentMs = 0; 87 } 88 getBitrateAdjustmentScale()89 private double getBitrateAdjustmentScale() { 90 return Math.pow(BITRATE_ADJUSTMENT_MAX_SCALE, 91 (double) bitrateAdjustmentScaleExp / BITRATE_ADJUSTMENT_STEPS); 92 } 93 94 @Override getAdjustedBitrateBps()95 public int getAdjustedBitrateBps() { 96 return (int) (targetBitrateBps * getBitrateAdjustmentScale()); 97 } 98 } 99