mirror of https://github.com/NekoX-Dev/NekoX.git
99 lines
4.3 KiB
Java
99 lines
4.3 KiB
Java
|
/*
|
||
|
* Copyright 2017 The WebRTC project authors. All Rights Reserved.
|
||
|
*
|
||
|
* Use of this source code is governed by a BSD-style license
|
||
|
* that can be found in the LICENSE file in the root of the source
|
||
|
* tree. An additional intellectual property rights grant can be found
|
||
|
* in the file PATENTS. All contributing project authors may
|
||
|
* be found in the AUTHORS file in the root of the source tree.
|
||
|
*/
|
||
|
|
||
|
package org.webrtc;
|
||
|
|
||
|
/**
|
||
|
* BitrateAdjuster that tracks the bandwidth produced by an encoder and dynamically adjusts the
|
||
|
* bitrate. Used for hardware codecs that pay attention to framerate but still deviate from the
|
||
|
* target bitrate by unacceptable margins.
|
||
|
*/
|
||
|
class DynamicBitrateAdjuster extends BaseBitrateAdjuster {
|
||
|
// Change the bitrate at most once every three seconds.
|
||
|
private static final double BITRATE_ADJUSTMENT_SEC = 3.0;
|
||
|
// Maximum bitrate adjustment scale - no more than 4 times.
|
||
|
private static final double BITRATE_ADJUSTMENT_MAX_SCALE = 4;
|
||
|
// Amount of adjustment steps to reach maximum scale.
|
||
|
private static final int BITRATE_ADJUSTMENT_STEPS = 20;
|
||
|
|
||
|
private static final double BITS_PER_BYTE = 8.0;
|
||
|
|
||
|
// How far the codec has deviated above (or below) the target bitrate (tracked in bytes).
|
||
|
private double deviationBytes;
|
||
|
private double timeSinceLastAdjustmentMs;
|
||
|
private int bitrateAdjustmentScaleExp;
|
||
|
|
||
|
@Override
|
||
|
public void setTargets(int targetBitrateBps, int targetFps) {
|
||
|
if (this.targetBitrateBps > 0 && targetBitrateBps < this.targetBitrateBps) {
|
||
|
// Rescale the accumulator level if the accumulator max decreases
|
||
|
deviationBytes = deviationBytes * targetBitrateBps / this.targetBitrateBps;
|
||
|
}
|
||
|
super.setTargets(targetBitrateBps, targetFps);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void reportEncodedFrame(int size) {
|
||
|
if (targetFps == 0) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Accumulate the difference between actual and expected frame sizes.
|
||
|
double expectedBytesPerFrame = (targetBitrateBps / BITS_PER_BYTE) / targetFps;
|
||
|
deviationBytes += (size - expectedBytesPerFrame);
|
||
|
timeSinceLastAdjustmentMs += 1000.0 / targetFps;
|
||
|
|
||
|
// Adjust the bitrate when the encoder accumulates one second's worth of data in excess or
|
||
|
// shortfall of the target.
|
||
|
double deviationThresholdBytes = targetBitrateBps / BITS_PER_BYTE;
|
||
|
|
||
|
// Cap the deviation, i.e., don't let it grow beyond some level to avoid using too old data for
|
||
|
// bitrate adjustment. This also prevents taking more than 3 "steps" in a given 3-second cycle.
|
||
|
double deviationCap = BITRATE_ADJUSTMENT_SEC * deviationThresholdBytes;
|
||
|
deviationBytes = Math.min(deviationBytes, deviationCap);
|
||
|
deviationBytes = Math.max(deviationBytes, -deviationCap);
|
||
|
|
||
|
// Do bitrate adjustment every 3 seconds if actual encoder bitrate deviates too much
|
||
|
// from the target value.
|
||
|
if (timeSinceLastAdjustmentMs <= 1000 * BITRATE_ADJUSTMENT_SEC) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (deviationBytes > deviationThresholdBytes) {
|
||
|
// Encoder generates too high bitrate - need to reduce the scale.
|
||
|
int bitrateAdjustmentInc = (int) (deviationBytes / deviationThresholdBytes + 0.5);
|
||
|
bitrateAdjustmentScaleExp -= bitrateAdjustmentInc;
|
||
|
// Don't let the adjustment scale drop below -BITRATE_ADJUSTMENT_STEPS.
|
||
|
// This sets a minimum exponent of -1 (bitrateAdjustmentScaleExp / BITRATE_ADJUSTMENT_STEPS).
|
||
|
bitrateAdjustmentScaleExp = Math.max(bitrateAdjustmentScaleExp, -BITRATE_ADJUSTMENT_STEPS);
|
||
|
deviationBytes = deviationThresholdBytes;
|
||
|
} else if (deviationBytes < -deviationThresholdBytes) {
|
||
|
// Encoder generates too low bitrate - need to increase the scale.
|
||
|
int bitrateAdjustmentInc = (int) (-deviationBytes / deviationThresholdBytes + 0.5);
|
||
|
bitrateAdjustmentScaleExp += bitrateAdjustmentInc;
|
||
|
// Don't let the adjustment scale exceed BITRATE_ADJUSTMENT_STEPS.
|
||
|
// This sets a maximum exponent of 1 (bitrateAdjustmentScaleExp / BITRATE_ADJUSTMENT_STEPS).
|
||
|
bitrateAdjustmentScaleExp = Math.min(bitrateAdjustmentScaleExp, BITRATE_ADJUSTMENT_STEPS);
|
||
|
deviationBytes = -deviationThresholdBytes;
|
||
|
}
|
||
|
timeSinceLastAdjustmentMs = 0;
|
||
|
}
|
||
|
|
||
|
private double getBitrateAdjustmentScale() {
|
||
|
return Math.pow(BITRATE_ADJUSTMENT_MAX_SCALE,
|
||
|
(double) bitrateAdjustmentScaleExp / BITRATE_ADJUSTMENT_STEPS);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public int getAdjustedBitrateBps() {
|
||
|
return (int) (targetBitrateBps * getBitrateAdjustmentScale());
|
||
|
}
|
||
|
}
|