Add stats googHasEnteredLowResolution.
Indicates if the forced sw fallback has had an effect (or would have had an effect if it had been
enabled).
Bug: webrtc:6634
Change-Id: I574b9001a2fae650fb894a1caa0d0f84257658e3
Reviewed-on: https://webrtc-review.googlesource.com/23300
Reviewed-by: Stefan Holmer <stefan@webrtc.org>
Reviewed-by: Rasmus Brandt <brandtr@webrtc.org>
Commit-Queue: Åsa Persson <asapersson@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#20729}
diff --git a/api/statstypes.cc b/api/statstypes.cc
index 940fb73..ff70bac 100644
--- a/api/statstypes.cc
+++ b/api/statstypes.cc
@@ -547,6 +547,8 @@
return "googFrameWidthReceived";
case kStatsValueNameFrameWidthSent:
return "googFrameWidthSent";
+ case kStatsValueNameHasEnteredLowResolution:
+ return "googHasEnteredLowResolution";
case kStatsValueNameInitiator:
return "googInitiator";
case kStatsValueNameInterframeDelayMaxMs:
diff --git a/api/statstypes.h b/api/statstypes.h
index 9e7f08c..80f0eb5 100644
--- a/api/statstypes.h
+++ b/api/statstypes.h
@@ -185,6 +185,7 @@
kStatsValueNameFrameWidthInput,
kStatsValueNameFrameWidthReceived,
kStatsValueNameFrameWidthSent,
+ kStatsValueNameHasEnteredLowResolution,
kStatsValueNameInitiator,
kStatsValueNameInterframeDelayMaxMs, // Max over last 10 seconds.
kStatsValueNameIssuerId,
diff --git a/call/video_send_stream.h b/call/video_send_stream.h
index 3bdb8ce..e57307d 100644
--- a/call/video_send_stream.h
+++ b/call/video_send_stream.h
@@ -85,6 +85,7 @@
// CPU/quality adaptation.
int number_of_cpu_adapt_changes = 0;
int number_of_quality_adapt_changes = 0;
+ bool has_entered_low_resolution = false;
std::map<uint32_t, StreamStats> substreams;
webrtc::VideoContentType content_type =
webrtc::VideoContentType::UNSPECIFIED;
diff --git a/media/base/mediachannel.h b/media/base/mediachannel.h
index b101dc7..0b84ff7 100644
--- a/media/base/mediachannel.h
+++ b/media/base/mediachannel.h
@@ -723,6 +723,7 @@
avg_encode_ms(0),
encode_usage_percent(0),
frames_encoded(0),
+ has_entered_low_resolution(false),
content_type(webrtc::VideoContentType::UNSPECIFIED) {}
std::vector<SsrcGroup> ssrc_groups;
@@ -743,6 +744,7 @@
int avg_encode_ms;
int encode_usage_percent;
uint32_t frames_encoded;
+ bool has_entered_low_resolution;
rtc::Optional<uint64_t> qp_sum;
webrtc::VideoContentType content_type;
};
diff --git a/media/engine/webrtcvideoengine.cc b/media/engine/webrtcvideoengine.cc
index d2457f8..7d5e2f5 100644
--- a/media/engine/webrtcvideoengine.cc
+++ b/media/engine/webrtcvideoengine.cc
@@ -1975,6 +1975,7 @@
info.adapt_changes = stats.number_of_cpu_adapt_changes;
info.adapt_reason =
stats.cpu_limited_resolution ? ADAPTREASON_CPU : ADAPTREASON_NONE;
+ info.has_entered_low_resolution = stats.has_entered_low_resolution;
// Get bandwidth limitation info from stream_->GetStats().
// Input resolution (output from video_adapter) can be further scaled down or
diff --git a/pc/statscollector.cc b/pc/statscollector.cc
index c81b368..9520176 100644
--- a/pc/statscollector.cc
+++ b/pc/statscollector.cc
@@ -317,6 +317,9 @@
(info.adapt_reason & 0x2) > 0);
report->AddBoolean(StatsReport::kStatsValueNameCpuLimitedResolution,
(info.adapt_reason & 0x1) > 0);
+ report->AddBoolean(StatsReport::kStatsValueNameHasEnteredLowResolution,
+ info.has_entered_low_resolution);
+
if (info.qp_sum)
report->AddInt(StatsReport::kStatsValueNameQpSum, *info.qp_sum);
diff --git a/video/send_statistics_proxy.cc b/video/send_statistics_proxy.cc
index cc7d034..71c9348 100644
--- a/video/send_statistics_proxy.cc
+++ b/video/send_statistics_proxy.cc
@@ -85,29 +85,37 @@
codec_info->codecSpecific.VP8.temporalIdx == kNoTemporalIdx);
}
-rtc::Optional<int> GetFallbackMaxPixelsFromFieldTrial() {
- if (!webrtc::field_trial::IsEnabled(kVp8ForcedFallbackEncoderFieldTrial))
- return rtc::Optional<int>();
-
- std::string group =
- webrtc::field_trial::FindFullName(kVp8ForcedFallbackEncoderFieldTrial);
+rtc::Optional<int> GetFallbackMaxPixels(const std::string& group) {
if (group.empty())
return rtc::Optional<int>();
int min_pixels;
int max_pixels;
int min_bps;
- if (sscanf(group.c_str(), "Enabled-%d,%d,%d", &min_pixels, &max_pixels,
- &min_bps) != 3) {
+ if (sscanf(group.c_str(), "-%d,%d,%d", &min_pixels, &max_pixels, &min_bps) !=
+ 3) {
return rtc::Optional<int>();
}
- if (min_pixels <= 0 || max_pixels <= 0 || max_pixels < min_pixels ||
- min_bps <= 0) {
- return rtc::Optional<int>(); // Do not log stats.
- }
+ if (min_pixels <= 0 || max_pixels <= 0 || max_pixels < min_pixels)
+ return rtc::Optional<int>();
+
return rtc::Optional<int>(max_pixels);
}
+
+rtc::Optional<int> GetFallbackMaxPixelsIfFieldTrialEnabled() {
+ std::string group =
+ webrtc::field_trial::FindFullName(kVp8ForcedFallbackEncoderFieldTrial);
+ return (group.find("Enabled") == 0) ? GetFallbackMaxPixels(group.substr(7))
+ : rtc::Optional<int>();
+}
+
+rtc::Optional<int> GetFallbackMaxPixelsIfFieldTrialDisabled() {
+ std::string group =
+ webrtc::field_trial::FindFullName(kVp8ForcedFallbackEncoderFieldTrial);
+ return (group.find("Disabled") == 0) ? GetFallbackMaxPixels(group.substr(8))
+ : rtc::Optional<int>();
+}
} // namespace
@@ -120,7 +128,8 @@
: clock_(clock),
payload_name_(config.encoder_settings.payload_name),
rtp_config_(config.rtp),
- fallback_max_pixels_(GetFallbackMaxPixelsFromFieldTrial()),
+ fallback_max_pixels_(GetFallbackMaxPixelsIfFieldTrialEnabled()),
+ fallback_max_pixels_disabled_(GetFallbackMaxPixelsIfFieldTrialDisabled()),
content_type_(content_type),
start_ms_(clock->TimeInMilliseconds()),
encode_time_(kEncodeTimeWeigthFactor),
@@ -729,6 +738,8 @@
void SendStatisticsProxy::UpdateEncoderFallbackStats(
const CodecSpecificInfo* codec_info,
int pixels) {
+ UpdateFallbackDisabledStats(codec_info, pixels);
+
if (!fallback_max_pixels_ || !uma_container_->fallback_info_.is_possible) {
return;
}
@@ -755,6 +766,7 @@
fallback_info->is_possible = false;
return;
}
+ stats_.has_entered_low_resolution = true;
++fallback_info->on_off_events;
}
@@ -772,6 +784,32 @@
fallback_info->last_update_ms.emplace(now_ms);
}
+void SendStatisticsProxy::UpdateFallbackDisabledStats(
+ const CodecSpecificInfo* codec_info,
+ int pixels) {
+ if (!fallback_max_pixels_disabled_ ||
+ !uma_container_->fallback_info_disabled_.is_possible ||
+ stats_.has_entered_low_resolution) {
+ return;
+ }
+
+ if (!IsForcedFallbackPossible(codec_info) ||
+ strcmp(codec_info->codec_name, kVp8SwCodecName) == 0) {
+ uma_container_->fallback_info_disabled_.is_possible = false;
+ return;
+ }
+
+ if (pixels <= *fallback_max_pixels_disabled_ ||
+ uma_container_->fallback_info_disabled_.min_pixel_limit_reached) {
+ stats_.has_entered_low_resolution = true;
+ }
+}
+
+void SendStatisticsProxy::OnMinPixelLimitReached() {
+ rtc::CritScope lock(&crit_);
+ uma_container_->fallback_info_disabled_.min_pixel_limit_reached = true;
+}
+
void SendStatisticsProxy::OnSendEncodedImage(
const EncodedImage& encoded_image,
const CodecSpecificInfo* codec_info) {
diff --git a/video/send_statistics_proxy.h b/video/send_statistics_proxy.h
index a543d92..094e78f 100644
--- a/video/send_statistics_proxy.h
+++ b/video/send_statistics_proxy.h
@@ -73,6 +73,7 @@
void OnQualityAdaptationChanged(
const VideoStreamEncoder::AdaptCounts& cpu_counts,
const VideoStreamEncoder::AdaptCounts& quality_counts);
+ void OnMinPixelLimitReached();
void OnSuspendChange(bool is_suspended);
void OnInactiveSsrc(uint32_t ssrc);
@@ -163,6 +164,10 @@
rtc::Optional<int64_t> last_update_ms;
const int max_frame_diff_ms = 2000;
};
+ struct FallbackEncoderInfoDisabled {
+ bool is_possible = true;
+ bool min_pixel_limit_reached = false;
+ };
struct StatsTimer {
void Start(int64_t now_ms);
void Stop(int64_t now_ms);
@@ -208,11 +213,15 @@
void UpdateEncoderFallbackStats(const CodecSpecificInfo* codec_info,
int pixels)
RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_);
+ void UpdateFallbackDisabledStats(const CodecSpecificInfo* codec_info,
+ int pixels)
+ RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_);
Clock* const clock_;
const std::string payload_name_;
const VideoSendStream::Config::Rtp rtp_config_;
const rtc::Optional<int> fallback_max_pixels_;
+ const rtc::Optional<int> fallback_max_pixels_disabled_;
rtc::CriticalSection crit_;
VideoEncoderConfig::ContentType content_type_ RTC_GUARDED_BY(crit_);
const int64_t start_ms_;
@@ -273,6 +282,7 @@
TargetRateUpdates target_rate_updates_;
BoolSampleCounter fallback_active_counter_;
FallbackEncoderInfo fallback_info_;
+ FallbackEncoderInfoDisabled fallback_info_disabled_;
ReportBlockStats report_block_stats_;
const VideoSendStream::Stats start_stats_;
EncodedFrameMap encoded_frames_;
diff --git a/video/send_statistics_proxy_unittest.cc b/video/send_statistics_proxy_unittest.cc
index 881aa7c..a204a46 100644
--- a/video/send_statistics_proxy_unittest.cc
+++ b/video/send_statistics_proxy_unittest.cc
@@ -1867,7 +1867,8 @@
class ForcedFallbackDisabled : public ForcedFallbackTest {
public:
ForcedFallbackDisabled()
- : ForcedFallbackTest("WebRTC-VP8-Forced-Fallback-Encoder-v2/Disabled/") {}
+ : ForcedFallbackTest("WebRTC-VP8-Forced-Fallback-Encoder-v2/Disabled-1," +
+ std::to_string(kWidth * kHeight) + ",3/") {}
};
class ForcedFallbackEnabled : public ForcedFallbackTest {
@@ -1886,6 +1887,7 @@
TEST_F(ForcedFallbackEnabled, StatsUpdated) {
InsertEncodedFrames(kMinFrames, kFrameIntervalMs);
+ EXPECT_FALSE(statistics_proxy_->GetStats().has_entered_low_resolution);
statistics_proxy_.reset();
EXPECT_EQ(1, metrics::NumSamples(kPrefix + "FallbackTimeInPercent.Vp8"));
EXPECT_EQ(1, metrics::NumEvents(kPrefix + "FallbackTimeInPercent.Vp8", 0));
@@ -1924,11 +1926,50 @@
EXPECT_EQ(0, metrics::NumSamples(kPrefix + "FallbackChangesPerMinute.Vp8"));
}
+TEST_F(ForcedFallbackDisabled, EnteredLowResolutionSetIfAtMaxPixels) {
+ InsertEncodedFrames(1, kFrameIntervalMs);
+ EXPECT_TRUE(statistics_proxy_->GetStats().has_entered_low_resolution);
+}
+
+TEST_F(ForcedFallbackEnabled, EnteredLowResolutionNotSetIfNotLibvpx) {
+ InsertEncodedFrames(1, kFrameIntervalMs);
+ EXPECT_FALSE(statistics_proxy_->GetStats().has_entered_low_resolution);
+}
+
+TEST_F(ForcedFallbackEnabled, EnteredLowResolutionSetIfLibvpx) {
+ codec_info_.codec_name = "libvpx";
+ InsertEncodedFrames(1, kFrameIntervalMs);
+ EXPECT_TRUE(statistics_proxy_->GetStats().has_entered_low_resolution);
+}
+
+TEST_F(ForcedFallbackDisabled, EnteredLowResolutionNotSetIfAboveMaxPixels) {
+ encoded_image_._encodedWidth = kWidth + 1;
+ InsertEncodedFrames(1, kFrameIntervalMs);
+ EXPECT_FALSE(statistics_proxy_->GetStats().has_entered_low_resolution);
+}
+
+TEST_F(ForcedFallbackDisabled, EnteredLowResolutionNotSetIfLibvpx) {
+ codec_info_.codec_name = "libvpx";
+ InsertEncodedFrames(1, kFrameIntervalMs);
+ EXPECT_FALSE(statistics_proxy_->GetStats().has_entered_low_resolution);
+}
+
+TEST_F(ForcedFallbackDisabled,
+ EnteredLowResolutionSetIfOnMinPixelLimitReached) {
+ encoded_image_._encodedWidth = kWidth + 1;
+ statistics_proxy_->OnMinPixelLimitReached();
+ InsertEncodedFrames(1, kFrameIntervalMs);
+ EXPECT_TRUE(statistics_proxy_->GetStats().has_entered_low_resolution);
+}
+
TEST_F(ForcedFallbackEnabled, OneFallbackEvent) {
// One change. Video: 20000 ms, fallback: 5000 ms (25%).
+ EXPECT_FALSE(statistics_proxy_->GetStats().has_entered_low_resolution);
InsertEncodedFrames(15, 1000);
+ EXPECT_FALSE(statistics_proxy_->GetStats().has_entered_low_resolution);
codec_info_.codec_name = "libvpx";
InsertEncodedFrames(5, 1000);
+ EXPECT_TRUE(statistics_proxy_->GetStats().has_entered_low_resolution);
statistics_proxy_.reset();
EXPECT_EQ(1, metrics::NumSamples(kPrefix + "FallbackTimeInPercent.Vp8"));
@@ -1943,16 +1984,21 @@
// Three changes. Video: 60000 ms, fallback: 15000 ms (25%).
InsertEncodedFrames(10, 1000);
+ EXPECT_FALSE(statistics_proxy_->GetStats().has_entered_low_resolution);
codec_info_.codec_name = "libvpx";
InsertEncodedFrames(15, 500);
+ EXPECT_TRUE(statistics_proxy_->GetStats().has_entered_low_resolution);
codec_info_.codec_name = "notlibvpx";
InsertEncodedFrames(20, 1000);
InsertEncodedFrames(3, kMaxFrameDiffMs); // Should not be included.
InsertEncodedFrames(10, 1000);
+ EXPECT_TRUE(statistics_proxy_->GetStats().has_entered_low_resolution);
codec_info_.codec_name = "notlibvpx2";
InsertEncodedFrames(10, 500);
+ EXPECT_TRUE(statistics_proxy_->GetStats().has_entered_low_resolution);
codec_info_.codec_name = "libvpx";
InsertEncodedFrames(15, 500);
+ EXPECT_TRUE(statistics_proxy_->GetStats().has_entered_low_resolution);
statistics_proxy_.reset();
EXPECT_EQ(1, metrics::NumSamples(kPrefix + "FallbackTimeInPercent.Vp8"));
@@ -1966,6 +2012,7 @@
codec_info_.codec_name = "libvpx";
InsertEncodedFrames(kMinFrames, kFrameIntervalMs);
+ EXPECT_FALSE(statistics_proxy_->GetStats().has_entered_low_resolution);
statistics_proxy_.reset();
EXPECT_EQ(0, metrics::NumSamples(kPrefix + "FallbackTimeInPercent.Vp8"));
EXPECT_EQ(0, metrics::NumSamples(kPrefix + "FallbackChangesPerMinute.Vp8"));
@@ -1976,6 +2023,7 @@
codec_info_.codec_name = "libvpx";
InsertEncodedFrames(kMinFrames, kFrameIntervalMs);
+ EXPECT_TRUE(statistics_proxy_->GetStats().has_entered_low_resolution);
statistics_proxy_.reset();
EXPECT_EQ(1, metrics::NumSamples(kPrefix + "FallbackTimeInPercent.Vp8"));
EXPECT_EQ(1, metrics::NumSamples(kPrefix + "FallbackChangesPerMinute.Vp8"));
diff --git a/video/video_stream_encoder.cc b/video/video_stream_encoder.cc
index 6c59670..77945dc 100644
--- a/video/video_stream_encoder.cc
+++ b/video/video_stream_encoder.cc
@@ -228,7 +228,9 @@
source_->AddOrUpdateSink(video_stream_encoder_, sink_wants_);
}
- bool RequestResolutionLowerThan(int pixel_count, int min_pixels_per_frame) {
+ bool RequestResolutionLowerThan(int pixel_count,
+ int min_pixels_per_frame,
+ bool* min_pixels_reached) {
// Called on the encoder task queue.
rtc::CritScope lock(&crit_);
if (!source_ || !IsResolutionScalingEnabled(degradation_preference_)) {
@@ -239,8 +241,11 @@
// The input video frame size will have a resolution less than or equal to
// |max_pixel_count| depending on how the source can scale the frame size.
const int pixels_wanted = (pixel_count * 3) / 5;
- if (pixels_wanted < min_pixels_per_frame ||
- pixels_wanted >= sink_wants_.max_pixel_count) {
+ if (pixels_wanted >= sink_wants_.max_pixel_count) {
+ return false;
+ }
+ if (pixels_wanted < min_pixels_per_frame) {
+ *min_pixels_reached = true;
return false;
}
RTC_LOG(LS_INFO) << "Scaling down resolution, max pixels: "
@@ -977,15 +982,20 @@
// Scale down resolution.
FALLTHROUGH();
}
- case VideoSendStream::DegradationPreference::kMaintainFramerate:
+ case VideoSendStream::DegradationPreference::kMaintainFramerate: {
// Scale down resolution.
+ bool min_pixels_reached = false;
if (!source_proxy_->RequestResolutionLowerThan(
adaptation_request.input_pixel_count_,
- settings_.encoder->GetScalingSettings().min_pixels_per_frame)) {
+ settings_.encoder->GetScalingSettings().min_pixels_per_frame,
+ &min_pixels_reached)) {
+ if (min_pixels_reached)
+ stats_proxy_->OnMinPixelLimitReached();
return;
}
GetAdaptCounter().IncrementResolution(reason);
break;
+ }
case VideoSendStream::DegradationPreference::kMaintainResolution: {
// Scale down framerate.
const int requested_framerate = source_proxy_->RequestFramerateLowerThan(