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:
Sebastian Jansson 2019-03-01 15:40:49 +01:00 committed by Commit Bot
parent e64a688167
commit b678940d3a
4 changed files with 24 additions and 21 deletions

View File

@ -18,7 +18,6 @@
#include "rtc_base/logging.h" #include "rtc_base/logging.h"
#include "rtc_base/numerics/exp_filter.h" #include "rtc_base/numerics/exp_filter.h"
#include "rtc_base/task_queue.h" #include "rtc_base/task_queue.h"
#include "rtc_base/time_utils.h"
// TODO(kthelgason): Some versions of Android have issues with log2. // TODO(kthelgason): Some versions of Android have issues with log2.
// See https://code.google.com/p/android/issues/detail?id=212634 for details // 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 { class QualityScaler::QpSmoother {
public: public:
explicit QpSmoother(float alpha) 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 { absl::optional<int> GetAvg() const {
float value = smoother_.filtered(); float value = smoother_.filtered();
@ -51,8 +54,8 @@ class QualityScaler::QpSmoother {
return static_cast<int>(value); return static_cast<int>(value);
} }
void Add(float sample) { void Add(float sample, int64_t time_sent_us) {
int64_t now_ms = rtc::TimeMillis(); int64_t now_ms = time_sent_us / 1000;
smoother_.Apply(static_cast<float>(now_ms - last_sample_ms_), sample); smoother_.Apply(static_cast<float>(now_ms - last_sample_ms_), sample);
last_sample_ms_ = now_ms; last_sample_ms_ = now_ms;
} }
@ -128,15 +131,15 @@ void QualityScaler::ReportDroppedFrameByEncoder() {
framedrop_percent_all_.AddSample(100); 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_); RTC_DCHECK_CALLED_SEQUENTIALLY(&task_checker_);
framedrop_percent_media_opt_.AddSample(0); framedrop_percent_media_opt_.AddSample(0);
framedrop_percent_all_.AddSample(0); framedrop_percent_all_.AddSample(0);
average_qp_.AddSample(qp); average_qp_.AddSample(qp);
if (qp_smoother_high_) if (qp_smoother_high_)
qp_smoother_high_->Add(qp); qp_smoother_high_->Add(qp, time_sent_us);
if (qp_smoother_low_) if (qp_smoother_low_)
qp_smoother_low_->Add(qp); qp_smoother_low_->Add(qp, time_sent_us);
} }
void QualityScaler::CheckQp() { void QualityScaler::CheckQp() {

View File

@ -55,7 +55,7 @@ class QualityScaler {
void ReportDroppedFrameByMediaOpt(); void ReportDroppedFrameByMediaOpt();
void ReportDroppedFrameByEncoder(); void ReportDroppedFrameByEncoder();
// Inform the QualityScaler of the last seen QP. // 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. // The following members declared protected for testing purposes.
protected: protected:

View File

@ -93,19 +93,19 @@ class QualityScalerTest : public ::testing::Test,
for (int i = 0; i < kFramerate * 5; ++i) { for (int i = 0; i < kFramerate * 5; ++i) {
switch (scale_direction) { switch (scale_direction) {
case kKeepScaleAboveLowQp: case kKeepScaleAboveLowQp:
qs_->ReportQp(kLowQp + 1); qs_->ReportQp(kLowQp + 1, 0);
break; break;
case kScaleUp: case kScaleUp:
qs_->ReportQp(kLowQp); qs_->ReportQp(kLowQp, 0);
break; break;
case kScaleDown: case kScaleDown:
qs_->ReportDroppedFrameByMediaOpt(); qs_->ReportDroppedFrameByMediaOpt();
break; break;
case kKeepScaleAtHighQp: case kKeepScaleAtHighQp:
qs_->ReportQp(kHighQp); qs_->ReportQp(kHighQp, 0);
break; break;
case kScaleDownAboveHighQp: case kScaleDownAboveHighQp:
qs_->ReportQp(kHighQp + 1); qs_->ReportQp(kHighQp + 1, 0);
break; break;
} }
} }
@ -150,7 +150,7 @@ TEST_P(QualityScalerTest, DownscalesAfterTwoThirdsFramedrop) {
for (int i = 0; i < kFramerate * 5; ++i) { for (int i = 0; i < kFramerate * 5; ++i) {
qs_->ReportDroppedFrameByMediaOpt(); qs_->ReportDroppedFrameByMediaOpt();
qs_->ReportDroppedFrameByMediaOpt(); qs_->ReportDroppedFrameByMediaOpt();
qs_->ReportQp(kHighQp); qs_->ReportQp(kHighQp, 0);
} }
}); });
EXPECT_TRUE(observer_->event.Wait(kDefaultTimeoutMs)); EXPECT_TRUE(observer_->event.Wait(kDefaultTimeoutMs));
@ -162,7 +162,7 @@ TEST_P(QualityScalerTest, DoesNotDownscaleAfterHalfFramedrop) {
DO_SYNC(q_, { DO_SYNC(q_, {
for (int i = 0; i < kFramerate * 5; ++i) { for (int i = 0; i < kFramerate * 5; ++i) {
qs_->ReportDroppedFrameByMediaOpt(); qs_->ReportDroppedFrameByMediaOpt();
qs_->ReportQp(kHighQp); qs_->ReportQp(kHighQp, 0);
} }
}); });
EXPECT_FALSE(observer_->event.Wait(kDefaultTimeoutMs)); EXPECT_FALSE(observer_->event.Wait(kDefaultTimeoutMs));
@ -176,7 +176,7 @@ TEST_P(QualityScalerTest, DownscalesAfterTwoThirdsIfFieldTrialEnabled) {
for (int i = 0; i < kFramerate * 5; ++i) { for (int i = 0; i < kFramerate * 5; ++i) {
qs_->ReportDroppedFrameByMediaOpt(); qs_->ReportDroppedFrameByMediaOpt();
qs_->ReportDroppedFrameByEncoder(); qs_->ReportDroppedFrameByEncoder();
qs_->ReportQp(kHighQp); qs_->ReportQp(kHighQp, 0);
} }
}); });
EXPECT_EQ(kDownScaleExpected, observer_->event.Wait(kDefaultTimeoutMs)); EXPECT_EQ(kDownScaleExpected, observer_->event.Wait(kDefaultTimeoutMs));
@ -213,13 +213,13 @@ TEST_P(QualityScalerTest, DoesNotScaleUntilEnoughFramesObserved) {
DO_SYNC(q_, { DO_SYNC(q_, {
// Not enough frames to make a decision. // Not enough frames to make a decision.
for (int i = 0; i < kMinFramesNeededToScale - 1; ++i) { for (int i = 0; i < kMinFramesNeededToScale - 1; ++i) {
qs_->ReportQp(kLowQp); qs_->ReportQp(kLowQp, 0);
} }
}); });
EXPECT_FALSE(observer_->event.Wait(kDefaultTimeoutMs)); EXPECT_FALSE(observer_->event.Wait(kDefaultTimeoutMs));
DO_SYNC(q_, { DO_SYNC(q_, {
// Send 1 more. Enough frames observed, should result in an adapt request. // 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_TRUE(observer_->event.Wait(kDefaultTimeoutMs));
EXPECT_EQ(0, observer_->adapt_down_events_); EXPECT_EQ(0, observer_->adapt_down_events_);
@ -228,7 +228,7 @@ TEST_P(QualityScalerTest, DoesNotScaleUntilEnoughFramesObserved) {
// Samples should be cleared after an adapt request. // Samples should be cleared after an adapt request.
DO_SYNC(q_, { DO_SYNC(q_, {
// Not enough frames to make a decision. // Not enough frames to make a decision.
qs_->ReportQp(kLowQp); qs_->ReportQp(kLowQp, 0);
}); });
EXPECT_FALSE(observer_->event.Wait(kDefaultTimeoutMs)); EXPECT_FALSE(observer_->event.Wait(kDefaultTimeoutMs));
EXPECT_EQ(0, observer_->adapt_down_events_); EXPECT_EQ(0, observer_->adapt_down_events_);
@ -238,7 +238,7 @@ TEST_P(QualityScalerTest, DoesNotScaleUntilEnoughFramesObserved) {
TEST_P(QualityScalerTest, ScalesDownAndBackUpWithMinFramesNeeded) { TEST_P(QualityScalerTest, ScalesDownAndBackUpWithMinFramesNeeded) {
DO_SYNC(q_, { DO_SYNC(q_, {
for (int i = 0; i < kMinFramesNeededToScale; ++i) { for (int i = 0; i < kMinFramesNeededToScale; ++i) {
qs_->ReportQp(kHighQp + 1); qs_->ReportQp(kHighQp + 1, 0);
} }
}); });
EXPECT_TRUE(observer_->event.Wait(kDefaultTimeoutMs)); EXPECT_TRUE(observer_->event.Wait(kDefaultTimeoutMs));
@ -247,7 +247,7 @@ TEST_P(QualityScalerTest, ScalesDownAndBackUpWithMinFramesNeeded) {
// Samples cleared. // Samples cleared.
DO_SYNC(q_, { DO_SYNC(q_, {
for (int i = 0; i < kMinFramesNeededToScale; ++i) { for (int i = 0; i < kMinFramesNeededToScale; ++i) {
qs_->ReportQp(kLowQp); qs_->ReportQp(kLowQp, 0);
} }
}); });
EXPECT_TRUE(observer_->event.Wait(kDefaultTimeoutMs)); EXPECT_TRUE(observer_->event.Wait(kDefaultTimeoutMs));

View File

@ -1749,7 +1749,7 @@ void VideoStreamEncoder::RunPostEncode(EncodedImage encoded_image,
encoded_image.capture_time_ms_ * rtc::kNumMicrosecsPerMillisec, encoded_image.capture_time_ms_ * rtc::kNumMicrosecsPerMillisec,
encode_duration_us); encode_duration_us);
if (quality_scaler_ && encoded_image.qp_ >= 0) 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_) { if (bitrate_adjuster_) {
bitrate_adjuster_->OnEncodedFrame(encoded_image, temporal_index); bitrate_adjuster_->OnEncodedFrame(encoded_image, temporal_index);
} }