• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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