Using send time instead of system clock in quality scaler.
Bug: webrtc:10365 Change-Id: Ia0c0df462ecec5bd94c3eda8039831b70d088790 Reviewed-on: https://webrtc-review.googlesource.com/c/125185 Reviewed-by: Åsa Persson <asapersson@webrtc.org> Commit-Queue: Sebastian Jansson <srte@webrtc.org> Cr-Commit-Position: refs/heads/master@{#26947}
This commit is contained in:
parent
e64a688167
commit
b678940d3a
@ -18,7 +18,6 @@
|
||||
#include "rtc_base/logging.h"
|
||||
#include "rtc_base/numerics/exp_filter.h"
|
||||
#include "rtc_base/task_queue.h"
|
||||
#include "rtc_base/time_utils.h"
|
||||
|
||||
// TODO(kthelgason): Some versions of Android have issues with log2.
|
||||
// See https://code.google.com/p/android/issues/detail?id=212634 for details
|
||||
@ -41,7 +40,11 @@ static const int kMinFramesNeededToScale = 2 * 30;
|
||||
class QualityScaler::QpSmoother {
|
||||
public:
|
||||
explicit QpSmoother(float alpha)
|
||||
: alpha_(alpha), last_sample_ms_(rtc::TimeMillis()), smoother_(alpha) {}
|
||||
: alpha_(alpha),
|
||||
// The initial value of last_sample_ms doesn't matter since the smoother
|
||||
// will ignore the time delta for the first update.
|
||||
last_sample_ms_(0),
|
||||
smoother_(alpha) {}
|
||||
|
||||
absl::optional<int> GetAvg() const {
|
||||
float value = smoother_.filtered();
|
||||
@ -51,8 +54,8 @@ class QualityScaler::QpSmoother {
|
||||
return static_cast<int>(value);
|
||||
}
|
||||
|
||||
void Add(float sample) {
|
||||
int64_t now_ms = rtc::TimeMillis();
|
||||
void Add(float sample, int64_t time_sent_us) {
|
||||
int64_t now_ms = time_sent_us / 1000;
|
||||
smoother_.Apply(static_cast<float>(now_ms - last_sample_ms_), sample);
|
||||
last_sample_ms_ = now_ms;
|
||||
}
|
||||
@ -128,15 +131,15 @@ void QualityScaler::ReportDroppedFrameByEncoder() {
|
||||
framedrop_percent_all_.AddSample(100);
|
||||
}
|
||||
|
||||
void QualityScaler::ReportQp(int qp) {
|
||||
void QualityScaler::ReportQp(int qp, int64_t time_sent_us) {
|
||||
RTC_DCHECK_CALLED_SEQUENTIALLY(&task_checker_);
|
||||
framedrop_percent_media_opt_.AddSample(0);
|
||||
framedrop_percent_all_.AddSample(0);
|
||||
average_qp_.AddSample(qp);
|
||||
if (qp_smoother_high_)
|
||||
qp_smoother_high_->Add(qp);
|
||||
qp_smoother_high_->Add(qp, time_sent_us);
|
||||
if (qp_smoother_low_)
|
||||
qp_smoother_low_->Add(qp);
|
||||
qp_smoother_low_->Add(qp, time_sent_us);
|
||||
}
|
||||
|
||||
void QualityScaler::CheckQp() {
|
||||
|
||||
@ -55,7 +55,7 @@ class QualityScaler {
|
||||
void ReportDroppedFrameByMediaOpt();
|
||||
void ReportDroppedFrameByEncoder();
|
||||
// Inform the QualityScaler of the last seen QP.
|
||||
void ReportQp(int qp);
|
||||
void ReportQp(int qp, int64_t time_sent_us);
|
||||
|
||||
// The following members declared protected for testing purposes.
|
||||
protected:
|
||||
|
||||
@ -93,19 +93,19 @@ class QualityScalerTest : public ::testing::Test,
|
||||
for (int i = 0; i < kFramerate * 5; ++i) {
|
||||
switch (scale_direction) {
|
||||
case kKeepScaleAboveLowQp:
|
||||
qs_->ReportQp(kLowQp + 1);
|
||||
qs_->ReportQp(kLowQp + 1, 0);
|
||||
break;
|
||||
case kScaleUp:
|
||||
qs_->ReportQp(kLowQp);
|
||||
qs_->ReportQp(kLowQp, 0);
|
||||
break;
|
||||
case kScaleDown:
|
||||
qs_->ReportDroppedFrameByMediaOpt();
|
||||
break;
|
||||
case kKeepScaleAtHighQp:
|
||||
qs_->ReportQp(kHighQp);
|
||||
qs_->ReportQp(kHighQp, 0);
|
||||
break;
|
||||
case kScaleDownAboveHighQp:
|
||||
qs_->ReportQp(kHighQp + 1);
|
||||
qs_->ReportQp(kHighQp + 1, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -150,7 +150,7 @@ TEST_P(QualityScalerTest, DownscalesAfterTwoThirdsFramedrop) {
|
||||
for (int i = 0; i < kFramerate * 5; ++i) {
|
||||
qs_->ReportDroppedFrameByMediaOpt();
|
||||
qs_->ReportDroppedFrameByMediaOpt();
|
||||
qs_->ReportQp(kHighQp);
|
||||
qs_->ReportQp(kHighQp, 0);
|
||||
}
|
||||
});
|
||||
EXPECT_TRUE(observer_->event.Wait(kDefaultTimeoutMs));
|
||||
@ -162,7 +162,7 @@ TEST_P(QualityScalerTest, DoesNotDownscaleAfterHalfFramedrop) {
|
||||
DO_SYNC(q_, {
|
||||
for (int i = 0; i < kFramerate * 5; ++i) {
|
||||
qs_->ReportDroppedFrameByMediaOpt();
|
||||
qs_->ReportQp(kHighQp);
|
||||
qs_->ReportQp(kHighQp, 0);
|
||||
}
|
||||
});
|
||||
EXPECT_FALSE(observer_->event.Wait(kDefaultTimeoutMs));
|
||||
@ -176,7 +176,7 @@ TEST_P(QualityScalerTest, DownscalesAfterTwoThirdsIfFieldTrialEnabled) {
|
||||
for (int i = 0; i < kFramerate * 5; ++i) {
|
||||
qs_->ReportDroppedFrameByMediaOpt();
|
||||
qs_->ReportDroppedFrameByEncoder();
|
||||
qs_->ReportQp(kHighQp);
|
||||
qs_->ReportQp(kHighQp, 0);
|
||||
}
|
||||
});
|
||||
EXPECT_EQ(kDownScaleExpected, observer_->event.Wait(kDefaultTimeoutMs));
|
||||
@ -213,13 +213,13 @@ TEST_P(QualityScalerTest, DoesNotScaleUntilEnoughFramesObserved) {
|
||||
DO_SYNC(q_, {
|
||||
// Not enough frames to make a decision.
|
||||
for (int i = 0; i < kMinFramesNeededToScale - 1; ++i) {
|
||||
qs_->ReportQp(kLowQp);
|
||||
qs_->ReportQp(kLowQp, 0);
|
||||
}
|
||||
});
|
||||
EXPECT_FALSE(observer_->event.Wait(kDefaultTimeoutMs));
|
||||
DO_SYNC(q_, {
|
||||
// Send 1 more. Enough frames observed, should result in an adapt request.
|
||||
qs_->ReportQp(kLowQp);
|
||||
qs_->ReportQp(kLowQp, 0);
|
||||
});
|
||||
EXPECT_TRUE(observer_->event.Wait(kDefaultTimeoutMs));
|
||||
EXPECT_EQ(0, observer_->adapt_down_events_);
|
||||
@ -228,7 +228,7 @@ TEST_P(QualityScalerTest, DoesNotScaleUntilEnoughFramesObserved) {
|
||||
// Samples should be cleared after an adapt request.
|
||||
DO_SYNC(q_, {
|
||||
// Not enough frames to make a decision.
|
||||
qs_->ReportQp(kLowQp);
|
||||
qs_->ReportQp(kLowQp, 0);
|
||||
});
|
||||
EXPECT_FALSE(observer_->event.Wait(kDefaultTimeoutMs));
|
||||
EXPECT_EQ(0, observer_->adapt_down_events_);
|
||||
@ -238,7 +238,7 @@ TEST_P(QualityScalerTest, DoesNotScaleUntilEnoughFramesObserved) {
|
||||
TEST_P(QualityScalerTest, ScalesDownAndBackUpWithMinFramesNeeded) {
|
||||
DO_SYNC(q_, {
|
||||
for (int i = 0; i < kMinFramesNeededToScale; ++i) {
|
||||
qs_->ReportQp(kHighQp + 1);
|
||||
qs_->ReportQp(kHighQp + 1, 0);
|
||||
}
|
||||
});
|
||||
EXPECT_TRUE(observer_->event.Wait(kDefaultTimeoutMs));
|
||||
@ -247,7 +247,7 @@ TEST_P(QualityScalerTest, ScalesDownAndBackUpWithMinFramesNeeded) {
|
||||
// Samples cleared.
|
||||
DO_SYNC(q_, {
|
||||
for (int i = 0; i < kMinFramesNeededToScale; ++i) {
|
||||
qs_->ReportQp(kLowQp);
|
||||
qs_->ReportQp(kLowQp, 0);
|
||||
}
|
||||
});
|
||||
EXPECT_TRUE(observer_->event.Wait(kDefaultTimeoutMs));
|
||||
|
||||
@ -1749,7 +1749,7 @@ void VideoStreamEncoder::RunPostEncode(EncodedImage encoded_image,
|
||||
encoded_image.capture_time_ms_ * rtc::kNumMicrosecsPerMillisec,
|
||||
encode_duration_us);
|
||||
if (quality_scaler_ && encoded_image.qp_ >= 0)
|
||||
quality_scaler_->ReportQp(encoded_image.qp_);
|
||||
quality_scaler_->ReportQp(encoded_image.qp_, time_sent_us);
|
||||
if (bitrate_adjuster_) {
|
||||
bitrate_adjuster_->OnEncodedFrame(encoded_image, temporal_index);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user