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/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() {
|
||||||
|
|||||||
@ -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:
|
||||||
|
|||||||
@ -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));
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user