Lint fix for webrtc/modules/video_coding PART 3!
Trying to submit all changes at once proved impossible since there were too many changes in too many files. The changes to PRESUBMIT.py will be uploaded in the last CL. (original CL: https://codereview.webrtc.org/1528503003/) BUG=webrtc:5309 TBR=mflodman@webrtc.org Review URL: https://codereview.webrtc.org/1540243002 Cr-Commit-Position: refs/heads/master@{#11105}
This commit is contained in:
@ -12,8 +12,7 @@
|
||||
|
||||
#include "webrtc/system_wrappers/include/trace.h"
|
||||
|
||||
namespace webrtc
|
||||
{
|
||||
namespace webrtc {
|
||||
|
||||
const float kDefaultKeyFrameSizeAvgKBits = 0.9f;
|
||||
const float kDefaultKeyFrameRatio = 0.99f;
|
||||
@ -22,339 +21,266 @@ const float kDefaultDropRatioMax = 0.96f;
|
||||
const float kDefaultMaxTimeToDropFrames = 4.0f; // In seconds.
|
||||
|
||||
FrameDropper::FrameDropper()
|
||||
:
|
||||
_keyFrameSizeAvgKbits(kDefaultKeyFrameSizeAvgKBits),
|
||||
_keyFrameRatio(kDefaultKeyFrameRatio),
|
||||
_dropRatio(kDefaultDropRatioAlpha, kDefaultDropRatioMax),
|
||||
_enabled(true),
|
||||
_max_time_drops(kDefaultMaxTimeToDropFrames)
|
||||
{
|
||||
Reset();
|
||||
: _keyFrameSizeAvgKbits(kDefaultKeyFrameSizeAvgKBits),
|
||||
_keyFrameRatio(kDefaultKeyFrameRatio),
|
||||
_dropRatio(kDefaultDropRatioAlpha, kDefaultDropRatioMax),
|
||||
_enabled(true),
|
||||
_max_time_drops(kDefaultMaxTimeToDropFrames) {
|
||||
Reset();
|
||||
}
|
||||
|
||||
FrameDropper::FrameDropper(float max_time_drops)
|
||||
:
|
||||
_keyFrameSizeAvgKbits(kDefaultKeyFrameSizeAvgKBits),
|
||||
_keyFrameRatio(kDefaultKeyFrameRatio),
|
||||
_dropRatio(kDefaultDropRatioAlpha, kDefaultDropRatioMax),
|
||||
_enabled(true),
|
||||
_max_time_drops(max_time_drops)
|
||||
{
|
||||
Reset();
|
||||
: _keyFrameSizeAvgKbits(kDefaultKeyFrameSizeAvgKBits),
|
||||
_keyFrameRatio(kDefaultKeyFrameRatio),
|
||||
_dropRatio(kDefaultDropRatioAlpha, kDefaultDropRatioMax),
|
||||
_enabled(true),
|
||||
_max_time_drops(max_time_drops) {
|
||||
Reset();
|
||||
}
|
||||
|
||||
void
|
||||
FrameDropper::Reset()
|
||||
{
|
||||
_keyFrameRatio.Reset(0.99f);
|
||||
_keyFrameRatio.Apply(1.0f, 1.0f/300.0f); // 1 key frame every 10th second in 30 fps
|
||||
_keyFrameSizeAvgKbits.Reset(0.9f);
|
||||
_keyFrameCount = 0;
|
||||
void FrameDropper::Reset() {
|
||||
_keyFrameRatio.Reset(0.99f);
|
||||
_keyFrameRatio.Apply(
|
||||
1.0f, 1.0f / 300.0f); // 1 key frame every 10th second in 30 fps
|
||||
_keyFrameSizeAvgKbits.Reset(0.9f);
|
||||
_keyFrameCount = 0;
|
||||
_accumulator = 0.0f;
|
||||
_accumulatorMax = 150.0f; // assume 300 kb/s and 0.5 s window
|
||||
_targetBitRate = 300.0f;
|
||||
_incoming_frame_rate = 30;
|
||||
_keyFrameSpreadFrames = 0.5f * _incoming_frame_rate;
|
||||
_dropNext = false;
|
||||
_dropRatio.Reset(0.9f);
|
||||
_dropRatio.Apply(0.0f, 0.0f); // Initialize to 0
|
||||
_dropCount = 0;
|
||||
_windowSize = 0.5f;
|
||||
_wasBelowMax = true;
|
||||
_fastMode = false; // start with normal (non-aggressive) mode
|
||||
// Cap for the encoder buffer level/accumulator, in secs.
|
||||
_cap_buffer_size = 3.0f;
|
||||
// Cap on maximum amount of dropped frames between kept frames, in secs.
|
||||
_max_time_drops = 4.0f;
|
||||
}
|
||||
|
||||
void FrameDropper::Enable(bool enable) {
|
||||
_enabled = enable;
|
||||
}
|
||||
|
||||
void FrameDropper::Fill(size_t frameSizeBytes, bool deltaFrame) {
|
||||
if (!_enabled) {
|
||||
return;
|
||||
}
|
||||
float frameSizeKbits = 8.0f * static_cast<float>(frameSizeBytes) / 1000.0f;
|
||||
if (!deltaFrame &&
|
||||
!_fastMode) { // fast mode does not treat key-frames any different
|
||||
_keyFrameSizeAvgKbits.Apply(1, frameSizeKbits);
|
||||
_keyFrameRatio.Apply(1.0, 1.0);
|
||||
if (frameSizeKbits > _keyFrameSizeAvgKbits.filtered()) {
|
||||
// Remove the average key frame size since we
|
||||
// compensate for key frames when adding delta
|
||||
// frames.
|
||||
frameSizeKbits -= _keyFrameSizeAvgKbits.filtered();
|
||||
} else {
|
||||
// Shouldn't be negative, so zero is the lower bound.
|
||||
frameSizeKbits = 0;
|
||||
}
|
||||
if (_keyFrameRatio.filtered() > 1e-5 &&
|
||||
1 / _keyFrameRatio.filtered() < _keyFrameSpreadFrames) {
|
||||
// We are sending key frames more often than our upper bound for
|
||||
// how much we allow the key frame compensation to be spread
|
||||
// out in time. Therefor we must use the key frame ratio rather
|
||||
// than keyFrameSpreadFrames.
|
||||
_keyFrameCount =
|
||||
static_cast<int32_t>(1 / _keyFrameRatio.filtered() + 0.5);
|
||||
} else {
|
||||
// Compensate for the key frame the following frames
|
||||
_keyFrameCount = static_cast<int32_t>(_keyFrameSpreadFrames + 0.5);
|
||||
}
|
||||
} else {
|
||||
// Decrease the keyFrameRatio
|
||||
_keyFrameRatio.Apply(1.0, 0.0);
|
||||
}
|
||||
// Change the level of the accumulator (bucket)
|
||||
_accumulator += frameSizeKbits;
|
||||
CapAccumulator();
|
||||
}
|
||||
|
||||
void FrameDropper::Leak(uint32_t inputFrameRate) {
|
||||
if (!_enabled) {
|
||||
return;
|
||||
}
|
||||
if (inputFrameRate < 1) {
|
||||
return;
|
||||
}
|
||||
if (_targetBitRate < 0.0f) {
|
||||
return;
|
||||
}
|
||||
_keyFrameSpreadFrames = 0.5f * inputFrameRate;
|
||||
// T is the expected bits per frame (target). If all frames were the same
|
||||
// size,
|
||||
// we would get T bits per frame. Notice that T is also weighted to be able to
|
||||
// force a lower frame rate if wanted.
|
||||
float T = _targetBitRate / inputFrameRate;
|
||||
if (_keyFrameCount > 0) {
|
||||
// Perform the key frame compensation
|
||||
if (_keyFrameRatio.filtered() > 0 &&
|
||||
1 / _keyFrameRatio.filtered() < _keyFrameSpreadFrames) {
|
||||
T -= _keyFrameSizeAvgKbits.filtered() * _keyFrameRatio.filtered();
|
||||
} else {
|
||||
T -= _keyFrameSizeAvgKbits.filtered() / _keyFrameSpreadFrames;
|
||||
}
|
||||
_keyFrameCount--;
|
||||
}
|
||||
_accumulator -= T;
|
||||
if (_accumulator < 0.0f) {
|
||||
_accumulator = 0.0f;
|
||||
_accumulatorMax = 150.0f; // assume 300 kb/s and 0.5 s window
|
||||
_targetBitRate = 300.0f;
|
||||
_incoming_frame_rate = 30;
|
||||
_keyFrameSpreadFrames = 0.5f * _incoming_frame_rate;
|
||||
_dropNext = false;
|
||||
_dropRatio.Reset(0.9f);
|
||||
_dropRatio.Apply(0.0f, 0.0f); // Initialize to 0
|
||||
_dropCount = 0;
|
||||
_windowSize = 0.5f;
|
||||
_wasBelowMax = true;
|
||||
_fastMode = false; // start with normal (non-aggressive) mode
|
||||
// Cap for the encoder buffer level/accumulator, in secs.
|
||||
_cap_buffer_size = 3.0f;
|
||||
// Cap on maximum amount of dropped frames between kept frames, in secs.
|
||||
_max_time_drops = 4.0f;
|
||||
}
|
||||
UpdateRatio();
|
||||
}
|
||||
|
||||
void
|
||||
FrameDropper::Enable(bool enable)
|
||||
{
|
||||
_enabled = enable;
|
||||
void FrameDropper::UpdateNack(uint32_t nackBytes) {
|
||||
if (!_enabled) {
|
||||
return;
|
||||
}
|
||||
_accumulator += static_cast<float>(nackBytes) * 8.0f / 1000.0f;
|
||||
}
|
||||
|
||||
void
|
||||
FrameDropper::Fill(size_t frameSizeBytes, bool deltaFrame)
|
||||
{
|
||||
if (!_enabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
float frameSizeKbits = 8.0f * static_cast<float>(frameSizeBytes) / 1000.0f;
|
||||
if (!deltaFrame && !_fastMode) // fast mode does not treat key-frames any different
|
||||
{
|
||||
_keyFrameSizeAvgKbits.Apply(1, frameSizeKbits);
|
||||
_keyFrameRatio.Apply(1.0, 1.0);
|
||||
if (frameSizeKbits > _keyFrameSizeAvgKbits.filtered())
|
||||
{
|
||||
// Remove the average key frame size since we
|
||||
// compensate for key frames when adding delta
|
||||
// frames.
|
||||
frameSizeKbits -= _keyFrameSizeAvgKbits.filtered();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Shouldn't be negative, so zero is the lower bound.
|
||||
frameSizeKbits = 0;
|
||||
}
|
||||
if (_keyFrameRatio.filtered() > 1e-5 &&
|
||||
1 / _keyFrameRatio.filtered() < _keyFrameSpreadFrames)
|
||||
{
|
||||
// We are sending key frames more often than our upper bound for
|
||||
// how much we allow the key frame compensation to be spread
|
||||
// out in time. Therefor we must use the key frame ratio rather
|
||||
// than keyFrameSpreadFrames.
|
||||
_keyFrameCount =
|
||||
static_cast<int32_t>(1 / _keyFrameRatio.filtered() + 0.5);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Compensate for the key frame the following frames
|
||||
_keyFrameCount = static_cast<int32_t>(_keyFrameSpreadFrames + 0.5);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Decrease the keyFrameRatio
|
||||
_keyFrameRatio.Apply(1.0, 0.0);
|
||||
}
|
||||
// Change the level of the accumulator (bucket)
|
||||
_accumulator += frameSizeKbits;
|
||||
CapAccumulator();
|
||||
void FrameDropper::FillBucket(float inKbits, float outKbits) {
|
||||
_accumulator += (inKbits - outKbits);
|
||||
}
|
||||
|
||||
void
|
||||
FrameDropper::Leak(uint32_t inputFrameRate)
|
||||
{
|
||||
if (!_enabled)
|
||||
{
|
||||
return;
|
||||
void FrameDropper::UpdateRatio() {
|
||||
if (_accumulator > 1.3f * _accumulatorMax) {
|
||||
// Too far above accumulator max, react faster
|
||||
_dropRatio.UpdateBase(0.8f);
|
||||
} else {
|
||||
// Go back to normal reaction
|
||||
_dropRatio.UpdateBase(0.9f);
|
||||
}
|
||||
if (_accumulator > _accumulatorMax) {
|
||||
// We are above accumulator max, and should ideally
|
||||
// drop a frame. Increase the dropRatio and drop
|
||||
// the frame later.
|
||||
if (_wasBelowMax) {
|
||||
_dropNext = true;
|
||||
}
|
||||
if (inputFrameRate < 1)
|
||||
{
|
||||
return;
|
||||
if (_fastMode) {
|
||||
// always drop in aggressive mode
|
||||
_dropNext = true;
|
||||
}
|
||||
if (_targetBitRate < 0.0f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_keyFrameSpreadFrames = 0.5f * inputFrameRate;
|
||||
// T is the expected bits per frame (target). If all frames were the same size,
|
||||
// we would get T bits per frame. Notice that T is also weighted to be able to
|
||||
// force a lower frame rate if wanted.
|
||||
float T = _targetBitRate / inputFrameRate;
|
||||
if (_keyFrameCount > 0)
|
||||
{
|
||||
// Perform the key frame compensation
|
||||
if (_keyFrameRatio.filtered() > 0 &&
|
||||
1 / _keyFrameRatio.filtered() < _keyFrameSpreadFrames)
|
||||
{
|
||||
T -= _keyFrameSizeAvgKbits.filtered() * _keyFrameRatio.filtered();
|
||||
}
|
||||
else
|
||||
{
|
||||
T -= _keyFrameSizeAvgKbits.filtered() / _keyFrameSpreadFrames;
|
||||
}
|
||||
_keyFrameCount--;
|
||||
}
|
||||
_accumulator -= T;
|
||||
if (_accumulator < 0.0f)
|
||||
{
|
||||
_accumulator = 0.0f;
|
||||
}
|
||||
UpdateRatio();
|
||||
|
||||
_dropRatio.Apply(1.0f, 1.0f);
|
||||
_dropRatio.UpdateBase(0.9f);
|
||||
} else {
|
||||
_dropRatio.Apply(1.0f, 0.0f);
|
||||
}
|
||||
_wasBelowMax = _accumulator < _accumulatorMax;
|
||||
}
|
||||
|
||||
void
|
||||
FrameDropper::UpdateNack(uint32_t nackBytes)
|
||||
{
|
||||
if (!_enabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_accumulator += static_cast<float>(nackBytes) * 8.0f / 1000.0f;
|
||||
}
|
||||
|
||||
void
|
||||
FrameDropper::FillBucket(float inKbits, float outKbits)
|
||||
{
|
||||
_accumulator += (inKbits - outKbits);
|
||||
}
|
||||
|
||||
void
|
||||
FrameDropper::UpdateRatio()
|
||||
{
|
||||
if (_accumulator > 1.3f * _accumulatorMax)
|
||||
{
|
||||
// Too far above accumulator max, react faster
|
||||
_dropRatio.UpdateBase(0.8f);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Go back to normal reaction
|
||||
_dropRatio.UpdateBase(0.9f);
|
||||
}
|
||||
if (_accumulator > _accumulatorMax)
|
||||
{
|
||||
// We are above accumulator max, and should ideally
|
||||
// drop a frame. Increase the dropRatio and drop
|
||||
// the frame later.
|
||||
if (_wasBelowMax)
|
||||
{
|
||||
_dropNext = true;
|
||||
}
|
||||
if (_fastMode)
|
||||
{
|
||||
// always drop in aggressive mode
|
||||
_dropNext = true;
|
||||
}
|
||||
|
||||
_dropRatio.Apply(1.0f, 1.0f);
|
||||
_dropRatio.UpdateBase(0.9f);
|
||||
}
|
||||
else
|
||||
{
|
||||
_dropRatio.Apply(1.0f, 0.0f);
|
||||
}
|
||||
_wasBelowMax = _accumulator < _accumulatorMax;
|
||||
}
|
||||
|
||||
// This function signals when to drop frames to the caller. It makes use of the dropRatio
|
||||
// This function signals when to drop frames to the caller. It makes use of the
|
||||
// dropRatio
|
||||
// to smooth out the drops over time.
|
||||
bool
|
||||
FrameDropper::DropFrame()
|
||||
{
|
||||
if (!_enabled)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (_dropNext)
|
||||
{
|
||||
_dropNext = false;
|
||||
_dropCount = 0;
|
||||
}
|
||||
|
||||
if (_dropRatio.filtered() >= 0.5f) // Drops per keep
|
||||
{
|
||||
// limit is the number of frames we should drop between each kept frame
|
||||
// to keep our drop ratio. limit is positive in this case.
|
||||
float denom = 1.0f - _dropRatio.filtered();
|
||||
if (denom < 1e-5)
|
||||
{
|
||||
denom = (float)1e-5;
|
||||
}
|
||||
int32_t limit = static_cast<int32_t>(1.0f / denom - 1.0f + 0.5f);
|
||||
// Put a bound on the max amount of dropped frames between each kept
|
||||
// frame, in terms of frame rate and window size (secs).
|
||||
int max_limit = static_cast<int>(_incoming_frame_rate *
|
||||
_max_time_drops);
|
||||
if (limit > max_limit) {
|
||||
limit = max_limit;
|
||||
}
|
||||
if (_dropCount < 0)
|
||||
{
|
||||
// Reset the _dropCount since it was negative and should be positive.
|
||||
if (_dropRatio.filtered() > 0.4f)
|
||||
{
|
||||
_dropCount = -_dropCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
_dropCount = 0;
|
||||
}
|
||||
}
|
||||
if (_dropCount < limit)
|
||||
{
|
||||
// As long we are below the limit we should drop frames.
|
||||
_dropCount++;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Only when we reset _dropCount a frame should be kept.
|
||||
_dropCount = 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (_dropRatio.filtered() > 0.0f &&
|
||||
_dropRatio.filtered() < 0.5f) // Keeps per drop
|
||||
{
|
||||
// limit is the number of frames we should keep between each drop
|
||||
// in order to keep the drop ratio. limit is negative in this case,
|
||||
// and the _dropCount is also negative.
|
||||
float denom = _dropRatio.filtered();
|
||||
if (denom < 1e-5)
|
||||
{
|
||||
denom = (float)1e-5;
|
||||
}
|
||||
int32_t limit = -static_cast<int32_t>(1.0f / denom - 1.0f + 0.5f);
|
||||
if (_dropCount > 0)
|
||||
{
|
||||
// Reset the _dropCount since we have a positive
|
||||
// _dropCount, and it should be negative.
|
||||
if (_dropRatio.filtered() < 0.6f)
|
||||
{
|
||||
_dropCount = -_dropCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
_dropCount = 0;
|
||||
}
|
||||
}
|
||||
if (_dropCount > limit)
|
||||
{
|
||||
if (_dropCount == 0)
|
||||
{
|
||||
// Drop frames when we reset _dropCount.
|
||||
_dropCount--;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Keep frames as long as we haven't reached limit.
|
||||
_dropCount--;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_dropCount = 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
_dropCount = 0;
|
||||
bool FrameDropper::DropFrame() {
|
||||
if (!_enabled) {
|
||||
return false;
|
||||
}
|
||||
if (_dropNext) {
|
||||
_dropNext = false;
|
||||
_dropCount = 0;
|
||||
}
|
||||
|
||||
// A simpler version, unfiltered and quicker
|
||||
//bool dropNext = _dropNext;
|
||||
//_dropNext = false;
|
||||
//return dropNext;
|
||||
if (_dropRatio.filtered() >= 0.5f) { // Drops per keep
|
||||
// limit is the number of frames we should drop between each kept frame
|
||||
// to keep our drop ratio. limit is positive in this case.
|
||||
float denom = 1.0f - _dropRatio.filtered();
|
||||
if (denom < 1e-5) {
|
||||
denom = 1e-5f;
|
||||
}
|
||||
int32_t limit = static_cast<int32_t>(1.0f / denom - 1.0f + 0.5f);
|
||||
// Put a bound on the max amount of dropped frames between each kept
|
||||
// frame, in terms of frame rate and window size (secs).
|
||||
int max_limit = static_cast<int>(_incoming_frame_rate * _max_time_drops);
|
||||
if (limit > max_limit) {
|
||||
limit = max_limit;
|
||||
}
|
||||
if (_dropCount < 0) {
|
||||
// Reset the _dropCount since it was negative and should be positive.
|
||||
if (_dropRatio.filtered() > 0.4f) {
|
||||
_dropCount = -_dropCount;
|
||||
} else {
|
||||
_dropCount = 0;
|
||||
}
|
||||
}
|
||||
if (_dropCount < limit) {
|
||||
// As long we are below the limit we should drop frames.
|
||||
_dropCount++;
|
||||
return true;
|
||||
} else {
|
||||
// Only when we reset _dropCount a frame should be kept.
|
||||
_dropCount = 0;
|
||||
return false;
|
||||
}
|
||||
} else if (_dropRatio.filtered() > 0.0f &&
|
||||
_dropRatio.filtered() < 0.5f) { // Keeps per drop
|
||||
// limit is the number of frames we should keep between each drop
|
||||
// in order to keep the drop ratio. limit is negative in this case,
|
||||
// and the _dropCount is also negative.
|
||||
float denom = _dropRatio.filtered();
|
||||
if (denom < 1e-5) {
|
||||
denom = 1e-5f;
|
||||
}
|
||||
int32_t limit = -static_cast<int32_t>(1.0f / denom - 1.0f + 0.5f);
|
||||
if (_dropCount > 0) {
|
||||
// Reset the _dropCount since we have a positive
|
||||
// _dropCount, and it should be negative.
|
||||
if (_dropRatio.filtered() < 0.6f) {
|
||||
_dropCount = -_dropCount;
|
||||
} else {
|
||||
_dropCount = 0;
|
||||
}
|
||||
}
|
||||
if (_dropCount > limit) {
|
||||
if (_dropCount == 0) {
|
||||
// Drop frames when we reset _dropCount.
|
||||
_dropCount--;
|
||||
return true;
|
||||
} else {
|
||||
// Keep frames as long as we haven't reached limit.
|
||||
_dropCount--;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
_dropCount = 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
_dropCount = 0;
|
||||
return false;
|
||||
|
||||
// A simpler version, unfiltered and quicker
|
||||
// bool dropNext = _dropNext;
|
||||
// _dropNext = false;
|
||||
// return dropNext;
|
||||
}
|
||||
|
||||
void
|
||||
FrameDropper::SetRates(float bitRate, float incoming_frame_rate)
|
||||
{
|
||||
// Bit rate of -1 means infinite bandwidth.
|
||||
_accumulatorMax = bitRate * _windowSize; // bitRate * windowSize (in seconds)
|
||||
if (_targetBitRate > 0.0f && bitRate < _targetBitRate && _accumulator > _accumulatorMax)
|
||||
{
|
||||
// Rescale the accumulator level if the accumulator max decreases
|
||||
_accumulator = bitRate / _targetBitRate * _accumulator;
|
||||
}
|
||||
_targetBitRate = bitRate;
|
||||
CapAccumulator();
|
||||
_incoming_frame_rate = incoming_frame_rate;
|
||||
void FrameDropper::SetRates(float bitRate, float incoming_frame_rate) {
|
||||
// Bit rate of -1 means infinite bandwidth.
|
||||
_accumulatorMax = bitRate * _windowSize; // bitRate * windowSize (in seconds)
|
||||
if (_targetBitRate > 0.0f && bitRate < _targetBitRate &&
|
||||
_accumulator > _accumulatorMax) {
|
||||
// Rescale the accumulator level if the accumulator max decreases
|
||||
_accumulator = bitRate / _targetBitRate * _accumulator;
|
||||
}
|
||||
_targetBitRate = bitRate;
|
||||
CapAccumulator();
|
||||
_incoming_frame_rate = incoming_frame_rate;
|
||||
}
|
||||
|
||||
float
|
||||
FrameDropper::ActualFrameRate(uint32_t inputFrameRate) const
|
||||
{
|
||||
if (!_enabled)
|
||||
{
|
||||
return static_cast<float>(inputFrameRate);
|
||||
}
|
||||
return inputFrameRate * (1.0f - _dropRatio.filtered());
|
||||
float FrameDropper::ActualFrameRate(uint32_t inputFrameRate) const {
|
||||
if (!_enabled) {
|
||||
return static_cast<float>(inputFrameRate);
|
||||
}
|
||||
return inputFrameRate * (1.0f - _dropRatio.filtered());
|
||||
}
|
||||
|
||||
// Put a cap on the accumulator, i.e., don't let it grow beyond some level.
|
||||
@ -366,5 +292,4 @@ void FrameDropper::CapAccumulator() {
|
||||
_accumulator = max_accumulator;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace webrtc
|
||||
|
||||
@ -23,72 +23,72 @@ namespace webrtc {
|
||||
// over use when the encoder can't keep its bit rate.
|
||||
class FrameDropper {
|
||||
public:
|
||||
FrameDropper();
|
||||
explicit FrameDropper(float max_time_drops);
|
||||
virtual ~FrameDropper() {}
|
||||
FrameDropper();
|
||||
explicit FrameDropper(float max_time_drops);
|
||||
virtual ~FrameDropper() {}
|
||||
|
||||
// Resets the FrameDropper to its initial state.
|
||||
// This means that the frameRateWeight is set to its
|
||||
// default value as well.
|
||||
virtual void Reset();
|
||||
// Resets the FrameDropper to its initial state.
|
||||
// This means that the frameRateWeight is set to its
|
||||
// default value as well.
|
||||
virtual void Reset();
|
||||
|
||||
virtual void Enable(bool enable);
|
||||
// Answers the question if it's time to drop a frame
|
||||
// if we want to reach a given frame rate. Must be
|
||||
// called for every frame.
|
||||
//
|
||||
// Return value : True if we should drop the current frame
|
||||
virtual bool DropFrame();
|
||||
// Updates the FrameDropper with the size of the latest encoded
|
||||
// frame. The FrameDropper calculates a new drop ratio (can be
|
||||
// seen as the probability to drop a frame) and updates its
|
||||
// internal statistics.
|
||||
//
|
||||
// Input:
|
||||
// - frameSizeBytes : The size of the latest frame
|
||||
// returned from the encoder.
|
||||
// - deltaFrame : True if the encoder returned
|
||||
// a key frame.
|
||||
virtual void Fill(size_t frameSizeBytes, bool deltaFrame);
|
||||
virtual void Enable(bool enable);
|
||||
// Answers the question if it's time to drop a frame
|
||||
// if we want to reach a given frame rate. Must be
|
||||
// called for every frame.
|
||||
//
|
||||
// Return value : True if we should drop the current frame
|
||||
virtual bool DropFrame();
|
||||
// Updates the FrameDropper with the size of the latest encoded
|
||||
// frame. The FrameDropper calculates a new drop ratio (can be
|
||||
// seen as the probability to drop a frame) and updates its
|
||||
// internal statistics.
|
||||
//
|
||||
// Input:
|
||||
// - frameSizeBytes : The size of the latest frame
|
||||
// returned from the encoder.
|
||||
// - deltaFrame : True if the encoder returned
|
||||
// a key frame.
|
||||
virtual void Fill(size_t frameSizeBytes, bool deltaFrame);
|
||||
|
||||
virtual void Leak(uint32_t inputFrameRate);
|
||||
virtual void Leak(uint32_t inputFrameRate);
|
||||
|
||||
void UpdateNack(uint32_t nackBytes);
|
||||
void UpdateNack(uint32_t nackBytes);
|
||||
|
||||
// Sets the target bit rate and the frame rate produced by
|
||||
// the camera.
|
||||
//
|
||||
// Input:
|
||||
// - bitRate : The target bit rate
|
||||
virtual void SetRates(float bitRate, float incoming_frame_rate);
|
||||
// Sets the target bit rate and the frame rate produced by
|
||||
// the camera.
|
||||
//
|
||||
// Input:
|
||||
// - bitRate : The target bit rate
|
||||
virtual void SetRates(float bitRate, float incoming_frame_rate);
|
||||
|
||||
// Return value : The current average frame rate produced
|
||||
// if the DropFrame() function is used as
|
||||
// instruction of when to drop frames.
|
||||
virtual float ActualFrameRate(uint32_t inputFrameRate) const;
|
||||
// Return value : The current average frame rate produced
|
||||
// if the DropFrame() function is used as
|
||||
// instruction of when to drop frames.
|
||||
virtual float ActualFrameRate(uint32_t inputFrameRate) const;
|
||||
|
||||
private:
|
||||
void FillBucket(float inKbits, float outKbits);
|
||||
void UpdateRatio();
|
||||
void CapAccumulator();
|
||||
void FillBucket(float inKbits, float outKbits);
|
||||
void UpdateRatio();
|
||||
void CapAccumulator();
|
||||
|
||||
rtc::ExpFilter _keyFrameSizeAvgKbits;
|
||||
rtc::ExpFilter _keyFrameRatio;
|
||||
float _keyFrameSpreadFrames;
|
||||
int32_t _keyFrameCount;
|
||||
float _accumulator;
|
||||
float _accumulatorMax;
|
||||
float _targetBitRate;
|
||||
bool _dropNext;
|
||||
rtc::ExpFilter _dropRatio;
|
||||
int32_t _dropCount;
|
||||
float _windowSize;
|
||||
float _incoming_frame_rate;
|
||||
bool _wasBelowMax;
|
||||
bool _enabled;
|
||||
bool _fastMode;
|
||||
float _cap_buffer_size;
|
||||
float _max_time_drops;
|
||||
rtc::ExpFilter _keyFrameSizeAvgKbits;
|
||||
rtc::ExpFilter _keyFrameRatio;
|
||||
float _keyFrameSpreadFrames;
|
||||
int32_t _keyFrameCount;
|
||||
float _accumulator;
|
||||
float _accumulatorMax;
|
||||
float _targetBitRate;
|
||||
bool _dropNext;
|
||||
rtc::ExpFilter _dropRatio;
|
||||
int32_t _dropCount;
|
||||
float _windowSize;
|
||||
float _incoming_frame_rate;
|
||||
bool _wasBelowMax;
|
||||
bool _enabled;
|
||||
bool _fastMode;
|
||||
float _cap_buffer_size;
|
||||
float _max_time_drops;
|
||||
}; // end of VCMFrameDropper class
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
@ -20,20 +20,13 @@ namespace webrtc {
|
||||
|
||||
class MockFrameDropper : public FrameDropper {
|
||||
public:
|
||||
MOCK_METHOD0(Reset,
|
||||
void());
|
||||
MOCK_METHOD1(Enable,
|
||||
void(bool enable));
|
||||
MOCK_METHOD0(DropFrame,
|
||||
bool());
|
||||
MOCK_METHOD2(Fill,
|
||||
void(size_t frameSizeBytes, bool deltaFrame));
|
||||
MOCK_METHOD1(Leak,
|
||||
void(uint32_t inputFrameRate));
|
||||
MOCK_METHOD2(SetRates,
|
||||
void(float bitRate, float incoming_frame_rate));
|
||||
MOCK_CONST_METHOD1(ActualFrameRate,
|
||||
float(uint32_t inputFrameRate));
|
||||
MOCK_METHOD0(Reset, void());
|
||||
MOCK_METHOD1(Enable, void(bool enable));
|
||||
MOCK_METHOD0(DropFrame, bool());
|
||||
MOCK_METHOD2(Fill, void(size_t frameSizeBytes, bool deltaFrame));
|
||||
MOCK_METHOD1(Leak, void(uint32_t inputFrameRate));
|
||||
MOCK_METHOD2(SetRates, void(float bitRate, float incoming_frame_rate));
|
||||
MOCK_CONST_METHOD1(ActualFrameRate, float(uint32_t inputFrameRate));
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
namespace webrtc {
|
||||
template<class T>
|
||||
template <class T>
|
||||
class MovingAverage {
|
||||
public:
|
||||
MovingAverage();
|
||||
@ -30,17 +30,17 @@ class MovingAverage {
|
||||
std::list<T> samples_;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
MovingAverage<T>::MovingAverage() : sum_(static_cast<T>(0)) {
|
||||
}
|
||||
template <class T>
|
||||
MovingAverage<T>::MovingAverage()
|
||||
: sum_(static_cast<T>(0)) {}
|
||||
|
||||
template<class T>
|
||||
template <class T>
|
||||
void MovingAverage<T>::AddSample(T sample) {
|
||||
samples_.push_back(sample);
|
||||
sum_ += sample;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
template <class T>
|
||||
bool MovingAverage<T>::GetAverage(size_t num_samples, T* avg) {
|
||||
if (num_samples > samples_.size())
|
||||
return false;
|
||||
@ -55,13 +55,13 @@ bool MovingAverage<T>::GetAverage(size_t num_samples, T* avg) {
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
template <class T>
|
||||
void MovingAverage<T>::Reset() {
|
||||
sum_ = static_cast<T>(0);
|
||||
samples_.clear();
|
||||
}
|
||||
|
||||
template<class T>
|
||||
template <class T>
|
||||
int MovingAverage<T>::size() {
|
||||
return samples_.size();
|
||||
}
|
||||
|
||||
@ -26,8 +26,7 @@ QualityScaler::QualityScaler()
|
||||
downscale_shift_(0),
|
||||
framerate_down_(false),
|
||||
min_width_(kDefaultMinDownscaleDimension),
|
||||
min_height_(kDefaultMinDownscaleDimension) {
|
||||
}
|
||||
min_height_(kDefaultMinDownscaleDimension) {}
|
||||
|
||||
void QualityScaler::Init(int low_qp_threshold,
|
||||
int high_qp_threshold,
|
||||
@ -91,7 +90,7 @@ void QualityScaler::OnEncodeFrame(const VideoFrame& frame) {
|
||||
AdjustScale(false);
|
||||
}
|
||||
} else if (average_qp_.GetAverage(num_samples_, &avg_qp) &&
|
||||
avg_qp <= low_qp_threshold_) {
|
||||
avg_qp <= low_qp_threshold_) {
|
||||
if (use_framerate_reduction_ && framerate_down_) {
|
||||
target_framerate_ = -1;
|
||||
framerate_down_ = false;
|
||||
@ -104,7 +103,7 @@ void QualityScaler::OnEncodeFrame(const VideoFrame& frame) {
|
||||
assert(downscale_shift_ >= 0);
|
||||
for (int shift = downscale_shift_;
|
||||
shift > 0 && (res_.width / 2 >= min_width_) &&
|
||||
(res_.height / 2 >= min_height_);
|
||||
(res_.height / 2 >= min_height_);
|
||||
--shift) {
|
||||
res_.width /= 2;
|
||||
res_.height /= 2;
|
||||
@ -124,13 +123,8 @@ const VideoFrame& QualityScaler::GetScaledFrame(const VideoFrame& frame) {
|
||||
if (res.width == frame.width())
|
||||
return frame;
|
||||
|
||||
scaler_.Set(frame.width(),
|
||||
frame.height(),
|
||||
res.width,
|
||||
res.height,
|
||||
kI420,
|
||||
kI420,
|
||||
kScaleBox);
|
||||
scaler_.Set(frame.width(), frame.height(), res.width, res.height, kI420,
|
||||
kI420, kScaleBox);
|
||||
if (scaler_.Scale(frame, &scaled_frame_) != 0)
|
||||
return frame;
|
||||
|
||||
|
||||
@ -33,6 +33,7 @@ class QualityScalerTest : public ::testing::Test {
|
||||
int width;
|
||||
int height;
|
||||
};
|
||||
|
||||
protected:
|
||||
enum ScaleDirection {
|
||||
kKeepScaleAtHighQp,
|
||||
@ -43,8 +44,8 @@ class QualityScalerTest : public ::testing::Test {
|
||||
enum BadQualityMetric { kDropFrame, kReportLowQP };
|
||||
|
||||
QualityScalerTest() {
|
||||
input_frame_.CreateEmptyFrame(
|
||||
kWidth, kHeight, kWidth, kHalfWidth, kHalfWidth);
|
||||
input_frame_.CreateEmptyFrame(kWidth, kHeight, kWidth, kHalfWidth,
|
||||
kHalfWidth);
|
||||
qs_.Init(kMaxQp / QualityScaler::kDefaultLowQpDenominator, kHighQp, false);
|
||||
qs_.ReportFramerate(kFramerate);
|
||||
qs_.OnEncodeFrame(input_frame_);
|
||||
@ -97,7 +98,8 @@ class QualityScalerTest : public ::testing::Test {
|
||||
int num_second,
|
||||
int initial_framerate);
|
||||
|
||||
void VerifyQualityAdaptation(int initial_framerate, int seconds,
|
||||
void VerifyQualityAdaptation(int initial_framerate,
|
||||
int seconds,
|
||||
bool expect_spatial_resize,
|
||||
bool expect_framerate_reduction);
|
||||
|
||||
@ -183,8 +185,8 @@ TEST_F(QualityScalerTest, DoesNotDownscaleAfterHalfFramedrop) {
|
||||
|
||||
void QualityScalerTest::ContinuouslyDownscalesByHalfDimensionsAndBackUp() {
|
||||
const int initial_min_dimension = input_frame_.width() < input_frame_.height()
|
||||
? input_frame_.width()
|
||||
: input_frame_.height();
|
||||
? input_frame_.width()
|
||||
: input_frame_.height();
|
||||
int min_dimension = initial_min_dimension;
|
||||
int current_shift = 0;
|
||||
// Drop all frames to force-trigger downscaling.
|
||||
@ -229,14 +231,14 @@ TEST_F(QualityScalerTest,
|
||||
const int kOddWidth = 517;
|
||||
const int kHalfOddWidth = (kOddWidth + 1) / 2;
|
||||
const int kOddHeight = 1239;
|
||||
input_frame_.CreateEmptyFrame(
|
||||
kOddWidth, kOddHeight, kOddWidth, kHalfOddWidth, kHalfOddWidth);
|
||||
input_frame_.CreateEmptyFrame(kOddWidth, kOddHeight, kOddWidth, kHalfOddWidth,
|
||||
kHalfOddWidth);
|
||||
ContinuouslyDownscalesByHalfDimensionsAndBackUp();
|
||||
}
|
||||
|
||||
void QualityScalerTest::DoesNotDownscaleFrameDimensions(int width, int height) {
|
||||
input_frame_.CreateEmptyFrame(
|
||||
width, height, width, (width + 1) / 2, (width + 1) / 2);
|
||||
input_frame_.CreateEmptyFrame(width, height, width, (width + 1) / 2,
|
||||
(width + 1) / 2);
|
||||
|
||||
for (int i = 0; i < kFramerate * kNumSeconds; ++i) {
|
||||
qs_.ReportDroppedFrame();
|
||||
@ -259,7 +261,9 @@ TEST_F(QualityScalerTest, DoesNotDownscaleFrom1Px) {
|
||||
}
|
||||
|
||||
QualityScalerTest::Resolution QualityScalerTest::TriggerResolutionChange(
|
||||
BadQualityMetric dropframe_lowqp, int num_second, int initial_framerate) {
|
||||
BadQualityMetric dropframe_lowqp,
|
||||
int num_second,
|
||||
int initial_framerate) {
|
||||
QualityScalerTest::Resolution res;
|
||||
res.framerate = initial_framerate;
|
||||
qs_.OnEncodeFrame(input_frame_);
|
||||
@ -288,7 +292,9 @@ QualityScalerTest::Resolution QualityScalerTest::TriggerResolutionChange(
|
||||
}
|
||||
|
||||
void QualityScalerTest::VerifyQualityAdaptation(
|
||||
int initial_framerate, int seconds, bool expect_spatial_resize,
|
||||
int initial_framerate,
|
||||
int seconds,
|
||||
bool expect_spatial_resize,
|
||||
bool expect_framerate_reduction) {
|
||||
const int kDisabledBadQpThreshold = kMaxQp + 1;
|
||||
qs_.Init(kMaxQp / QualityScaler::kDefaultLowQpDenominator,
|
||||
@ -298,8 +304,8 @@ void QualityScalerTest::VerifyQualityAdaptation(
|
||||
int init_height = qs_.GetScaledResolution().height;
|
||||
|
||||
// Test reducing framerate by dropping frame continuously.
|
||||
QualityScalerTest::Resolution res = TriggerResolutionChange(
|
||||
kDropFrame, seconds, initial_framerate);
|
||||
QualityScalerTest::Resolution res =
|
||||
TriggerResolutionChange(kDropFrame, seconds, initial_framerate);
|
||||
|
||||
if (expect_framerate_reduction) {
|
||||
EXPECT_LT(res.framerate, initial_framerate);
|
||||
|
||||
@ -43,12 +43,12 @@ static void VP8LoadNewBytes(VP8BitReader* const br) {
|
||||
const uint32_t in_bits = *(const uint32_t*)(br->buf_);
|
||||
br->buf_ += BITS >> 3;
|
||||
#if defined(WEBRTC_ARCH_BIG_ENDIAN)
|
||||
bits = static_cast<uint32_t>(in_bits);
|
||||
if (BITS != 8 * sizeof(uint32_t))
|
||||
bits >>= (8 * sizeof(uint32_t) - BITS);
|
||||
bits = static_cast<uint32_t>(in_bits);
|
||||
if (BITS != 8 * sizeof(uint32_t))
|
||||
bits >>= (8 * sizeof(uint32_t) - BITS);
|
||||
#else
|
||||
bits = BSwap32(in_bits);
|
||||
bits >>= 32 - BITS;
|
||||
bits = BSwap32(in_bits);
|
||||
bits >>= 32 - BITS;
|
||||
#endif
|
||||
br->value_ = bits | (br->value_ << BITS);
|
||||
br->bits_ += BITS;
|
||||
@ -60,12 +60,12 @@ static void VP8LoadNewBytes(VP8BitReader* const br) {
|
||||
static void VP8InitBitReader(VP8BitReader* const br,
|
||||
const uint8_t* const start,
|
||||
const uint8_t* const end) {
|
||||
br->range_ = 255 - 1;
|
||||
br->buf_ = start;
|
||||
br->range_ = 255 - 1;
|
||||
br->buf_ = start;
|
||||
br->buf_end_ = end;
|
||||
br->value_ = 0;
|
||||
br->bits_ = -8; // To load the very first 8bits.
|
||||
br->eof_ = 0;
|
||||
br->value_ = 0;
|
||||
br->bits_ = -8; // To load the very first 8bits.
|
||||
br->eof_ = 0;
|
||||
VP8LoadNewBytes(br);
|
||||
}
|
||||
|
||||
@ -122,7 +122,7 @@ static void ParseSegmentHeader(VP8BitReader* br) {
|
||||
int s;
|
||||
VP8Get(br);
|
||||
for (s = 0; s < NUM_MB_SEGMENTS; ++s) {
|
||||
VP8Get(br) ? VP8GetSignedValue(br, 7) : 0;
|
||||
VP8Get(br) ? VP8GetSignedValue(br, 7) : 0;
|
||||
}
|
||||
for (s = 0; s < NUM_MB_SEGMENTS; ++s) {
|
||||
VP8Get(br) ? VP8GetSignedValue(br, 6) : 0;
|
||||
|
||||
@ -28,46 +28,34 @@ enum {
|
||||
typedef struct VP8BitReader VP8BitReader;
|
||||
struct VP8BitReader {
|
||||
// Boolean decoder.
|
||||
uint32_t value_; // Current value.
|
||||
uint32_t range_; // Current range minus 1. In [127, 254] interval.
|
||||
int bits_; // Number of valid bits left.
|
||||
uint32_t value_; // Current value.
|
||||
uint32_t range_; // Current range minus 1. In [127, 254] interval.
|
||||
int bits_; // Number of valid bits left.
|
||||
// Read buffer.
|
||||
const uint8_t* buf_; // Next byte to be read.
|
||||
const uint8_t* buf_end_; // End of read buffer.
|
||||
int eof_; // True if input is exhausted.
|
||||
const uint8_t* buf_; // Next byte to be read.
|
||||
const uint8_t* buf_end_; // End of read buffer.
|
||||
int eof_; // True if input is exhausted.
|
||||
};
|
||||
|
||||
const uint8_t kVP8Log2Range[128] = {
|
||||
7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
0
|
||||
};
|
||||
7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0};
|
||||
|
||||
// range = ((range - 1) << kVP8Log2Range[range]) + 1
|
||||
const uint8_t kVP8NewRange[128] = {
|
||||
127, 127, 191, 127, 159, 191, 223, 127,
|
||||
143, 159, 175, 191, 207, 223, 239, 127,
|
||||
135, 143, 151, 159, 167, 175, 183, 191,
|
||||
199, 207, 215, 223, 231, 239, 247, 127,
|
||||
131, 135, 139, 143, 147, 151, 155, 159,
|
||||
163, 167, 171, 175, 179, 183, 187, 191,
|
||||
195, 199, 203, 207, 211, 215, 219, 223,
|
||||
227, 231, 235, 239, 243, 247, 251, 127,
|
||||
129, 131, 133, 135, 137, 139, 141, 143,
|
||||
145, 147, 149, 151, 153, 155, 157, 159,
|
||||
161, 163, 165, 167, 169, 171, 173, 175,
|
||||
177, 179, 181, 183, 185, 187, 189, 191,
|
||||
193, 195, 197, 199, 201, 203, 205, 207,
|
||||
209, 211, 213, 215, 217, 219, 221, 223,
|
||||
225, 227, 229, 231, 233, 235, 237, 239,
|
||||
241, 243, 245, 247, 249, 251, 253, 127
|
||||
};
|
||||
127, 127, 191, 127, 159, 191, 223, 127, 143, 159, 175, 191, 207, 223, 239,
|
||||
127, 135, 143, 151, 159, 167, 175, 183, 191, 199, 207, 215, 223, 231, 239,
|
||||
247, 127, 131, 135, 139, 143, 147, 151, 155, 159, 163, 167, 171, 175, 179,
|
||||
183, 187, 191, 195, 199, 203, 207, 211, 215, 219, 223, 227, 231, 235, 239,
|
||||
243, 247, 251, 127, 129, 131, 133, 135, 137, 139, 141, 143, 145, 147, 149,
|
||||
151, 153, 155, 157, 159, 161, 163, 165, 167, 169, 171, 173, 175, 177, 179,
|
||||
181, 183, 185, 187, 189, 191, 193, 195, 197, 199, 201, 203, 205, 207, 209,
|
||||
211, 213, 215, 217, 219, 221, 223, 225, 227, 229, 231, 233, 235, 237, 239,
|
||||
241, 243, 245, 247, 249, 251, 253, 127};
|
||||
|
||||
// Gets the QP, QP range: [0, 127].
|
||||
// Returns true on success, false otherwise.
|
||||
|
||||
Reference in New Issue
Block a user