Move default thresholds from QualityScaler to encoders.

Overriding implementations of VideoEncoder::GetScalingSettings that
want to enable quality scaling must now provide the thresholds.

Bug: webrtc:8830
Change-Id: I75c47cb56ac1b9cf77401684980b3167e485f51c
Reviewed-on: https://webrtc-review.googlesource.com/46622
Reviewed-by: Magnus Jedvert <magjed@webrtc.org>
Reviewed-by: Karl Wiberg <kwiberg@webrtc.org>
Reviewed-by: Sami Kalliomäki <sakal@webrtc.org>
Reviewed-by: Åsa Persson <asapersson@webrtc.org>
Reviewed-by: Kári Helgason <kthelgason@webrtc.org>
Commit-Queue: Niels Moller <nisse@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#22172}
This commit is contained in:
Niels Möller 2018-02-22 15:03:53 +01:00 committed by Commit Bot
parent 12fb17035c
commit 225c787c6e
16 changed files with 140 additions and 102 deletions

View File

@ -59,24 +59,26 @@ VideoCodecH264 VideoEncoder::GetDefaultH264Settings() {
return h264_settings;
}
VideoEncoder::ScalingSettings::ScalingSettings(bool on, int low, int high)
: enabled(on), thresholds(QpThresholds(low, high)) {}
VideoEncoder::ScalingSettings::ScalingSettings() = default;
VideoEncoder::ScalingSettings::ScalingSettings(bool on,
int low,
VideoEncoder::ScalingSettings::ScalingSettings(KOff) : ScalingSettings() {}
VideoEncoder::ScalingSettings::ScalingSettings(int low, int high)
: thresholds(QpThresholds(low, high)) {}
VideoEncoder::ScalingSettings::ScalingSettings(int low,
int high,
int min_pixels)
: enabled(on),
thresholds(QpThresholds(low, high)),
min_pixels_per_frame(min_pixels) {}
: thresholds(QpThresholds(low, high)), min_pixels_per_frame(min_pixels) {}
VideoEncoder::ScalingSettings::ScalingSettings(bool on, int min_pixels)
: enabled(on), min_pixels_per_frame(min_pixels) {}
VideoEncoder::ScalingSettings::ScalingSettings(bool on) : enabled(on) {}
VideoEncoder::ScalingSettings::ScalingSettings(const ScalingSettings&) =
default;
VideoEncoder::ScalingSettings::~ScalingSettings() {}
// static
constexpr VideoEncoder::ScalingSettings::KOff
VideoEncoder::ScalingSettings::kOff;
int32_t VideoEncoder::SetRates(uint32_t bitrate, uint32_t framerate) {
RTC_NOTREACHED() << "SetRate(uint32_t, uint32_t) is deprecated.";
@ -90,7 +92,7 @@ int32_t VideoEncoder::SetRateAllocation(
}
VideoEncoder::ScalingSettings VideoEncoder::GetScalingSettings() const {
return ScalingSettings(false);
return ScalingSettings::kOff;
}
int32_t VideoEncoder::SetPeriodicKeyFrames(bool enable) {

View File

@ -85,15 +85,27 @@ class VideoEncoder {
int low;
int high;
};
// Quality scaling is enabled if thresholds are provided.
struct ScalingSettings {
ScalingSettings(bool on, int low, int high);
ScalingSettings(bool on, int low, int high, int min_pixels);
ScalingSettings(bool on, int min_pixels);
explicit ScalingSettings(bool on);
private:
// Private magic type for kOff, implicitly convertible to
// ScalingSettings.
struct KOff {};
public:
// TODO(nisse): Would be nicer if kOff were a constant ScalingSettings
// rather than a magic value. However, rtc::Optional is not trivially copy
// constructible, and hence a constant ScalingSettings needs a static
// initializer, which is strongly discouraged in Chrome. We can hopefully
// fix this when we switch to absl::optional or std::optional.
static constexpr KOff kOff = {};
ScalingSettings(int low, int high);
ScalingSettings(int low, int high, int min_pixels);
ScalingSettings(const ScalingSettings&);
ScalingSettings(KOff); // NOLINT(runtime/explicit)
~ScalingSettings();
const bool enabled;
const rtc::Optional<QpThresholds> thresholds;
// We will never ask for a resolution lower than this.
@ -101,6 +113,11 @@ class VideoEncoder {
// on MediaCodec and fallback implementations are in place.
// See https://bugs.chromium.org/p/webrtc/issues/detail?id=7206
const int min_pixels_per_frame = 320 * 180;
private:
// Private constructor; to get an object without thresholds, use
// the magic constant ScalingSettings::kOff.
ScalingSettings();
};
static VideoCodecVP8 GetDefaultVp8Settings();

View File

@ -535,7 +535,7 @@ VideoEncoder::ScalingSettings SimulcastEncoderAdapter::GetScalingSettings()
// RTC_DCHECK_CALLED_SEQUENTIALLY(&encoder_queue_);
// Turn off quality scaling for simulcast.
if (!Initialized() || NumberOfStreams(codec_) != 1) {
return VideoEncoder::ScalingSettings(false);
return VideoEncoder::ScalingSettings::kOff;
}
return streaminfos_[0].encoder->GetScalingSettings();
}

View File

@ -220,19 +220,14 @@ bool VideoEncoderSoftwareFallbackWrapper::SupportsNativeHandle() const {
VideoEncoder::ScalingSettings
VideoEncoderSoftwareFallbackWrapper::GetScalingSettings() const {
if (forced_fallback_possible_) {
if (forced_fallback_.active_) {
return VideoEncoder::ScalingSettings(
codec_settings_.VP8().automaticResizeOn,
forced_fallback_.min_pixels_);
}
const auto settings = encoder_->GetScalingSettings();
if (settings.thresholds) {
return VideoEncoder::ScalingSettings(
settings.enabled, settings.thresholds->low, settings.thresholds->high,
forced_fallback_.min_pixels_);
}
return VideoEncoder::ScalingSettings(settings.enabled,
forced_fallback_.min_pixels_);
const auto settings = forced_fallback_.active_
? fallback_encoder_->GetScalingSettings()
: encoder_->GetScalingSettings();
return settings.thresholds
? VideoEncoder::ScalingSettings(settings.thresholds->low,
settings.thresholds->high,
forced_fallback_.min_pixels_)
: VideoEncoder::ScalingSettings::kOff;
}
return encoder_->GetScalingSettings();
}

View File

@ -100,7 +100,7 @@ class VideoEncoderSoftwareFallbackWrapperTest : public ::testing::Test {
}
VideoEncoder::ScalingSettings GetScalingSettings() const override {
return VideoEncoder::ScalingSettings(true, kLowThreshold, kHighThreshold);
return VideoEncoder::ScalingSettings(kLowThreshold, kHighThreshold);
}
int init_encode_count_ = 0;
@ -501,7 +501,7 @@ TEST_F(ForcedFallbackTestDisabled, GetScaleSettings) {
// Default min pixels per frame should be used.
const auto settings = fallback_wrapper_.GetScalingSettings();
EXPECT_TRUE(settings.enabled);
EXPECT_TRUE(settings.thresholds.has_value());
EXPECT_EQ(kDefaultMinPixelsPerFrame, settings.min_pixels_per_frame);
}
@ -512,7 +512,6 @@ TEST_F(ForcedFallbackTestEnabled, GetScaleSettingsWithNoFallback) {
// Configured min pixels per frame should be used.
const auto settings = fallback_wrapper_.GetScalingSettings();
EXPECT_TRUE(settings.enabled);
EXPECT_EQ(kMinPixelsPerFrame, settings.min_pixels_per_frame);
ASSERT_TRUE(settings.thresholds);
EXPECT_EQ(kLowThreshold, settings.thresholds->low);
@ -526,7 +525,7 @@ TEST_F(ForcedFallbackTestEnabled, GetScaleSettingsWithFallback) {
// Configured min pixels per frame should be used.
const auto settings = fallback_wrapper_.GetScalingSettings();
EXPECT_TRUE(settings.enabled);
EXPECT_TRUE(settings.thresholds.has_value());
EXPECT_EQ(kMinPixelsPerFrame, settings.min_pixels_per_frame);
}
@ -538,7 +537,7 @@ TEST_F(ForcedFallbackTestEnabled, ScalingDisabledIfResizeOff) {
// Should be disabled for automatic resize off.
const auto settings = fallback_wrapper_.GetScalingSettings();
EXPECT_FALSE(settings.enabled);
EXPECT_FALSE(settings.thresholds.has_value());
}
} // namespace webrtc

View File

@ -31,6 +31,10 @@ namespace {
const bool kOpenH264EncoderDetailedLogging = false;
// QP scaling thresholds.
static const int kLowH264QpThreshold = 24;
static const int kHighH264QpThreshold = 37;
// Used by histograms. Values of entries should not be changed.
enum H264EncoderImplEvent {
kH264EncoderEventInit = 0,
@ -503,7 +507,8 @@ int32_t H264EncoderImpl::SetPeriodicKeyFrames(bool enable) {
}
VideoEncoder::ScalingSettings H264EncoderImpl::GetScalingSettings() const {
return VideoEncoder::ScalingSettings(true);
return VideoEncoder::ScalingSettings(kLowH264QpThreshold,
kHighH264QpThreshold);
}
} // namespace webrtc

View File

@ -487,7 +487,7 @@ TEST_F(TestVp8Impl, ScalingDisabledIfAutomaticResizeOff) {
encoder_->InitEncode(&codec_settings_, kNumCores, kMaxPayloadSize));
VideoEncoder::ScalingSettings settings = encoder_->GetScalingSettings();
EXPECT_FALSE(settings.enabled);
EXPECT_FALSE(settings.thresholds.has_value());
}
TEST_F(TestVp8Impl, ScalingEnabledIfAutomaticResizeOn) {
@ -497,7 +497,7 @@ TEST_F(TestVp8Impl, ScalingEnabledIfAutomaticResizeOn) {
encoder_->InitEncode(&codec_settings_, kNumCores, kMaxPayloadSize));
VideoEncoder::ScalingSettings settings = encoder_->GetScalingSettings();
EXPECT_TRUE(settings.enabled);
EXPECT_TRUE(settings.thresholds.has_value());
EXPECT_EQ(kDefaultMinPixelsPerFrame, settings.min_pixels_per_frame);
}

View File

@ -42,6 +42,11 @@ namespace {
const char kVp8PostProcArmFieldTrial[] = "WebRTC-VP8-Postproc-Config-Arm";
const char kVp8GfBoostFieldTrial[] = "WebRTC-VP8-GfBoost";
// QP is obtained from VP8-bitstream for HW, so the QP corresponds to the
// bitstream range of [0, 127] and not the user-level range of [0,63].
static const int kLowVp8QpThreshold = 29;
static const int kHighVp8QpThreshold = 95;
const int kTokenPartitions = VP8_ONE_TOKENPARTITION;
enum { kVp8ErrorPropagationTh = 30 };
enum { kVp832ByteAlign = 32 };
@ -1010,7 +1015,9 @@ VideoEncoder::ScalingSettings VP8EncoderImpl::GetScalingSettings() const {
const bool enable_scaling = encoders_.size() == 1 &&
configurations_[0].rc_dropframe_thresh > 0 &&
codec_.VP8().automaticResizeOn;
return VideoEncoder::ScalingSettings(enable_scaling);
return enable_scaling ? VideoEncoder::ScalingSettings(kLowVp8QpThreshold,
kHighVp8QpThreshold)
: VideoEncoder::ScalingSettings::kOff;
}
int VP8EncoderImpl::SetChannelParameters(uint32_t packetLoss, int64_t rtt) {

View File

@ -28,46 +28,13 @@
namespace webrtc {
namespace {
// TODO(nisse): Delete, delegate to encoders.
// Threshold constant used until first downscale (to permit fast rampup).
static const int kMeasureMs = 2000;
static const float kSamplePeriodScaleFactor = 2.5;
static const int kFramedropPercentThreshold = 60;
// QP scaling threshold defaults:
static const int kLowH264QpThreshold = 24;
static const int kHighH264QpThreshold = 37;
// QP is obtained from VP8-bitstream for HW, so the QP corresponds to the
// bitstream range of [0, 127] and not the user-level range of [0,63].
static const int kLowVp8QpThreshold = 29;
static const int kHighVp8QpThreshold = 95;
// QP is obtained from VP9-bitstream for HW, so the QP corresponds to the
// bitstream range of [0, 255] and not the user-level range of [0,63].
// Current VP9 settings are mapped from VP8 thresholds above.
static const int kLowVp9QpThreshold = 96;
static const int kHighVp9QpThreshold = 185;
static const int kMinFramesNeededToScale = 2 * 30;
static VideoEncoder::QpThresholds CodecTypeToDefaultThresholds(
VideoCodecType codec_type) {
int low = -1;
int high = -1;
switch (codec_type) {
case kVideoCodecH264:
low = kLowH264QpThreshold;
high = kHighH264QpThreshold;
break;
case kVideoCodecVP8:
low = kLowVp8QpThreshold;
high = kHighVp8QpThreshold;
break;
case kVideoCodecVP9:
low = kLowVp9QpThreshold;
high = kHighVp9QpThreshold;
break;
default:
RTC_NOTREACHED() << "Invalid codec type for QualityScaler.";
}
return VideoEncoder::QpThresholds(low, high);
}
} // namespace
class QualityScaler::CheckQPTask : public rtc::QueuedTask {
@ -99,10 +66,6 @@ class QualityScaler::CheckQPTask : public rtc::QueuedTask {
rtc::SequencedTaskChecker task_checker_;
};
QualityScaler::QualityScaler(AdaptationObserverInterface* observer,
VideoCodecType codec_type)
: QualityScaler(observer, CodecTypeToDefaultThresholds(codec_type)) {}
QualityScaler::QualityScaler(AdaptationObserverInterface* observer,
VideoEncoder::QpThresholds thresholds)
: QualityScaler(observer, thresholds, kMeasureMs) {}

View File

@ -43,12 +43,9 @@ class AdaptationObserverInterface {
// signal an intent to scale up or down.
class QualityScaler {
public:
// Construct a QualityScaler with a given |observer|.
// Construct a QualityScaler with given |thresholds| and |observer|.
// This starts the quality scaler periodically checking what the average QP
// has been recently.
QualityScaler(AdaptationObserverInterface* observer,
VideoCodecType codec_type);
// If specific thresholds are desired these can be supplied as |thresholds|.
QualityScaler(AdaptationObserverInterface* observer,
VideoEncoder::QpThresholds thresholds);
virtual ~QualityScaler();

View File

@ -1205,8 +1205,11 @@ void MediaCodecVideoEncoder::LogStatistics(bool force_log) {
VideoEncoder::ScalingSettings MediaCodecVideoEncoder::GetScalingSettings()
const {
if (!scale_)
return VideoEncoder::ScalingSettings::kOff;
const VideoCodecType codec_type = GetCodecType();
if (field_trial::IsEnabled(kCustomQPThresholdsFieldTrial)) {
const VideoCodecType codec_type = GetCodecType();
std::string experiment_string =
field_trial::FindFullName(kCustomQPThresholdsFieldTrial);
ALOGD << "QP custom thresholds: " << experiment_string << " for codec "
@ -1224,15 +1227,38 @@ VideoEncoder::ScalingSettings MediaCodecVideoEncoder::GetScalingSettings()
RTC_CHECK_GT(high_h264_qp_threshold, low_h264_qp_threshold);
RTC_CHECK_GT(low_h264_qp_threshold, 0);
if (codec_type == kVideoCodecVP8) {
return VideoEncoder::ScalingSettings(scale_, low_vp8_qp_threshold,
return VideoEncoder::ScalingSettings(low_vp8_qp_threshold,
high_vp8_qp_threshold);
} else if (codec_type == kVideoCodecH264) {
return VideoEncoder::ScalingSettings(scale_, low_h264_qp_threshold,
return VideoEncoder::ScalingSettings(low_h264_qp_threshold,
high_h264_qp_threshold);
}
}
}
return VideoEncoder::ScalingSettings(scale_);
if (codec_type == kVideoCodecVP8) {
// Same as in vp8_impl.cc.
static const int kLowVp8QpThreshold = 29;
static const int kHighVp8QpThreshold = 95;
return VideoEncoder::ScalingSettings(kLowVp8QpThreshold,
kHighVp8QpThreshold);
} else if (codec_type == kVideoCodecVP9) {
// QP is obtained from VP9-bitstream, so the QP corresponds to the bitstream
// range of [0, 255] and not the user-level range of [0,63].
static const int kLowVp9QpThreshold = 96;
static const int kHighVp9QpThreshold = 185;
return VideoEncoder::ScalingSettings(kLowVp9QpThreshold,
kHighVp9QpThreshold);
} else if (codec_type == kVideoCodecH264) {
// Same as in h264_encoder_impl.cc.
static const int kLowH264QpThreshold = 24;
static const int kHighH264QpThreshold = 37;
return VideoEncoder::ScalingSettings(kLowH264QpThreshold,
kHighH264QpThreshold);
}
return VideoEncoder::ScalingSettings::kOff;
}
const char* MediaCodecVideoEncoder::ImplementationName() const {

View File

@ -165,6 +165,9 @@ VideoEncoderWrapper::ScalingSettings VideoEncoderWrapper::GetScalingSettings()
bool isOn =
Java_VideoEncoderWrapper_getScalingSettingsOn(jni, j_scaling_settings);
if (!isOn)
return ScalingSettings::kOff;
rtc::Optional<int> low = JavaToNativeOptionalInt(
jni,
Java_VideoEncoderWrapper_getScalingSettingsLow(jni, j_scaling_settings));
@ -172,8 +175,36 @@ VideoEncoderWrapper::ScalingSettings VideoEncoderWrapper::GetScalingSettings()
jni,
Java_VideoEncoderWrapper_getScalingSettingsHigh(jni, j_scaling_settings));
return (low && high) ? ScalingSettings(isOn, *low, *high)
: ScalingSettings(isOn);
if (low && high)
return ScalingSettings(*low, *high);
switch (codec_settings_.codecType) {
case kVideoCodecVP8: {
// Same as in vp8_impl.cc.
static const int kLowVp8QpThreshold = 29;
static const int kHighVp8QpThreshold = 95;
return ScalingSettings(low.value_or(kLowVp8QpThreshold),
high.value_or(kHighVp8QpThreshold));
}
case kVideoCodecVP9: {
// QP is obtained from VP9-bitstream, so the QP corresponds to the
// bitstream range of [0, 255] and not the user-level range of [0,63].
static const int kLowVp9QpThreshold = 96;
static const int kHighVp9QpThreshold = 185;
return VideoEncoder::ScalingSettings(kLowVp9QpThreshold,
kHighVp9QpThreshold);
}
case kVideoCodecH264: {
// Same as in h264_encoder_impl.cc.
static const int kLowH264QpThreshold = 24;
static const int kHighH264QpThreshold = 37;
return ScalingSettings(low.value_or(kLowH264QpThreshold),
high.value_or(kHighH264QpThreshold));
}
default:
return ScalingSettings::kOff;
}
}
const char* VideoEncoderWrapper::ImplementationName() const {

View File

@ -107,9 +107,8 @@ class ObjCVideoEncoder : public VideoEncoder {
VideoEncoder::ScalingSettings GetScalingSettings() const {
RTCVideoEncoderQpThresholds *qp_thresholds = [encoder_ scalingSettings];
return qp_thresholds ?
ScalingSettings(true /* enabled */, qp_thresholds.low, qp_thresholds.high) :
ScalingSettings(false /* enabled */);
return qp_thresholds ? ScalingSettings(qp_thresholds.low, qp_thresholds.high) :
ScalingSettings::kOff;
}
const char *ImplementationName() const { return implementation_name_.c_str(); }

View File

@ -393,7 +393,6 @@ VideoStreamEncoder::VideoStreamEncoder(
source_proxy_(new VideoSourceProxy(this)),
sink_(nullptr),
settings_(settings),
codec_type_(PayloadStringToCodecType(settings.payload_name)),
video_sender_(Clock::GetRealTimeClock(), this),
overuse_detector_(std::move(overuse_detector)),
stats_proxy_(stats_proxy),
@ -624,18 +623,17 @@ void VideoStreamEncoder::ConfigureQualityScaler() {
const auto scaling_settings = settings_.encoder->GetScalingSettings();
const bool quality_scaling_allowed =
IsResolutionScalingEnabled(degradation_preference_) &&
scaling_settings.enabled;
scaling_settings.thresholds;
if (quality_scaling_allowed) {
if (quality_scaler_.get() == nullptr) {
// Quality scaler has not already been configured.
// Drop frames and scale down until desired quality is achieved.
if (scaling_settings.thresholds) {
quality_scaler_.reset(
new QualityScaler(this, *(scaling_settings.thresholds)));
} else {
quality_scaler_.reset(new QualityScaler(this, codec_type_));
}
// Since the interface is non-public, MakeUnique can't do this upcast.
AdaptationObserverInterface* observer = this;
quality_scaler_ = rtc::MakeUnique<QualityScaler>(
observer, *(scaling_settings.thresholds));
}
} else {
quality_scaler_.reset(nullptr);

View File

@ -212,7 +212,6 @@ class VideoStreamEncoder : public rtc::VideoSinkInterface<VideoFrame>,
const std::unique_ptr<VideoSourceProxy> source_proxy_;
EncoderSink* sink_;
const VideoSendStream::Config::EncoderSettings settings_;
const VideoCodecType codec_type_;
vcm::VideoSender video_sender_ RTC_GUARDED_BY(&encoder_queue_);
const std::unique_ptr<OveruseFrameDetector> overuse_detector_

View File

@ -502,8 +502,8 @@ class VideoStreamEncoderTest : public ::testing::Test {
VideoEncoder::ScalingSettings GetScalingSettings() const override {
rtc::CritScope lock(&local_crit_sect_);
if (quality_scaling_)
return VideoEncoder::ScalingSettings(true, 1, 2, kMinPixelsPerFrame);
return VideoEncoder::ScalingSettings(false);
return VideoEncoder::ScalingSettings(1, 2, kMinPixelsPerFrame);
return VideoEncoder::ScalingSettings::kOff;
}
void ContinueEncode() { continue_encode_event_.Set(); }