| Index: video/send_statistics_proxy.cc
|
| diff --git a/video/send_statistics_proxy.cc b/video/send_statistics_proxy.cc
|
| index 83a25ecd86aed255d0e6c65db12d3b6d12b8e6a1..4042a5198e13734967aefe73baed13678eb45df9 100644
|
| --- a/video/send_statistics_proxy.cc
|
| +++ b/video/send_statistics_proxy.cc
|
| @@ -15,16 +15,21 @@
|
| #include <map>
|
| #include <vector>
|
|
|
| -#include "common_types.h"
|
| +#include "common_types.h" // NOLINT(build/include)
|
| #include "modules/video_coding/include/video_codec_interface.h"
|
| #include "rtc_base/checks.h"
|
| #include "rtc_base/logging.h"
|
| +#include "system_wrappers/include/field_trial.h"
|
| #include "system_wrappers/include/metrics.h"
|
|
|
| namespace webrtc {
|
| namespace {
|
| const float kEncodeTimeWeigthFactor = 0.5f;
|
|
|
| +const char kVp8ForcedFallbackEncoderFieldTrial[] =
|
| + "WebRTC-VP8-Forced-Fallback-Encoder";
|
| +const char kVp8SwCodecName[] = "libvpx";
|
| +
|
| // Used by histograms. Values of entries should not be changed.
|
| enum HistogramCodecType {
|
| kVideoUnknown = 0,
|
| @@ -68,6 +73,38 @@ void UpdateCodecTypeHistogram(const std::string& payload_name) {
|
| PayloadNameToHistogramCodecType(payload_name),
|
| kVideoMax);
|
| }
|
| +
|
| +bool IsForcedFallbackPossible(const CodecSpecificInfo* codec_info) {
|
| + return codec_info->codecType == kVideoCodecVP8 &&
|
| + codec_info->codecSpecific.VP8.simulcastIdx == 0 &&
|
| + (codec_info->codecSpecific.VP8.temporalIdx == 0 ||
|
| + codec_info->codecSpecific.VP8.temporalIdx == kNoTemporalIdx);
|
| +}
|
| +
|
| +rtc::Optional<int> GetFallbackIntervalFromFieldTrial() {
|
| + if (!webrtc::field_trial::IsEnabled(kVp8ForcedFallbackEncoderFieldTrial))
|
| + return rtc::Optional<int>();
|
| +
|
| + std::string group =
|
| + webrtc::field_trial::FindFullName(kVp8ForcedFallbackEncoderFieldTrial);
|
| + if (group.empty())
|
| + return rtc::Optional<int>();
|
| +
|
| + int low_kbps;
|
| + int high_kbps;
|
| + int min_low_ms;
|
| + int min_pixels;
|
| + if (sscanf(group.c_str(), "Enabled-%d,%d,%d,%d", &low_kbps, &high_kbps,
|
| + &min_low_ms, &min_pixels) != 4) {
|
| + return rtc::Optional<int>();
|
| + }
|
| +
|
| + if (min_low_ms <= 0 || min_pixels <= 0 || low_kbps <= 0 ||
|
| + high_kbps <= low_kbps) {
|
| + return rtc::Optional<int>();
|
| + }
|
| + return rtc::Optional<int>(min_low_ms);
|
| +}
|
| } // namespace
|
|
|
|
|
| @@ -80,6 +117,7 @@ SendStatisticsProxy::SendStatisticsProxy(
|
| : clock_(clock),
|
| payload_name_(config.encoder_settings.payload_name),
|
| rtp_config_(config.rtp),
|
| + min_first_fallback_interval_ms_(GetFallbackIntervalFromFieldTrial()),
|
| content_type_(content_type),
|
| start_ms_(clock->TimeInMilliseconds()),
|
| last_sent_frame_timestamp_(0),
|
| @@ -410,6 +448,21 @@ void SendStatisticsProxy::UmaSamplesContainer::UpdateHistograms(
|
| }
|
| }
|
|
|
| + if (fallback_info_.is_possible) {
|
| + // Double interval since there is some time before fallback may occur.
|
| + const int kMinRunTimeMs = 2 * metrics::kMinRunTimeInSeconds * 1000;
|
| + int64_t elapsed_ms = fallback_info_.elapsed_ms;
|
| + int fallback_time_percent = fallback_active_counter_.Percent(kMinRunTimeMs);
|
| + if (fallback_time_percent != -1 && elapsed_ms >= kMinRunTimeMs) {
|
| + RTC_HISTOGRAMS_PERCENTAGE(
|
| + kIndex, uma_prefix_ + "Encoder.ForcedSwFallbackTimeInPercent.Vp8",
|
| + fallback_time_percent);
|
| + RTC_HISTOGRAMS_COUNTS_100(
|
| + kIndex, uma_prefix_ + "Encoder.ForcedSwFallbackChangesPerMinute.Vp8",
|
| + fallback_info_.on_off_events * 60 / (elapsed_ms / 1000));
|
| + }
|
| + }
|
| +
|
| AggregatedStats total_bytes_per_sec = total_byte_counter_.GetStats();
|
| if (total_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) {
|
| RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "BitrateSentInKbps",
|
| @@ -620,6 +673,57 @@ void SendStatisticsProxy::OnSetEncoderTargetRate(uint32_t bitrate_bps) {
|
| stats_.target_media_bitrate_bps = bitrate_bps;
|
| }
|
|
|
| +void SendStatisticsProxy::UpdateEncoderFallbackStats(
|
| + const CodecSpecificInfo* codec_info) {
|
| + if (!min_first_fallback_interval_ms_ ||
|
| + !uma_container_->fallback_info_.is_possible) {
|
| + return;
|
| + }
|
| +
|
| + if (!IsForcedFallbackPossible(codec_info)) {
|
| + uma_container_->fallback_info_.is_possible = false;
|
| + return;
|
| + }
|
| +
|
| + FallbackEncoderInfo* fallback_info = &uma_container_->fallback_info_;
|
| +
|
| + const int64_t now_ms = clock_->TimeInMilliseconds();
|
| + bool is_active = fallback_info->is_active;
|
| + if (codec_info->codec_name != stats_.encoder_implementation_name) {
|
| + // Implementation changed.
|
| + is_active = strcmp(codec_info->codec_name, kVp8SwCodecName) == 0;
|
| + if (!is_active && stats_.encoder_implementation_name != kVp8SwCodecName) {
|
| + // First or not a VP8 SW change, update stats on next call.
|
| + return;
|
| + }
|
| + if (is_active && fallback_info->on_off_events == 0) {
|
| + // The minimum set time should have passed for the first fallback (else
|
| + // skip to avoid fallback due to failure).
|
| + int64_t elapsed_ms = fallback_info->elapsed_ms;
|
| + if (fallback_info->last_update_ms)
|
| + elapsed_ms += now_ms - *(fallback_info->last_update_ms);
|
| + if (elapsed_ms < *min_first_fallback_interval_ms_) {
|
| + fallback_info->is_possible = false;
|
| + return;
|
| + }
|
| + }
|
| + ++fallback_info->on_off_events;
|
| + }
|
| +
|
| + if (fallback_info->last_update_ms) {
|
| + int64_t diff_ms = now_ms - *(fallback_info->last_update_ms);
|
| + // If the time diff since last update is greater than |max_frame_diff_ms|,
|
| + // video is considered paused/muted and the change is not included.
|
| + if (diff_ms < fallback_info->max_frame_diff_ms) {
|
| + uma_container_->fallback_active_counter_.Add(fallback_info->is_active,
|
| + diff_ms);
|
| + fallback_info->elapsed_ms += diff_ms;
|
| + }
|
| + }
|
| + fallback_info->is_active = is_active;
|
| + fallback_info->last_update_ms.emplace(now_ms);
|
| +}
|
| +
|
| void SendStatisticsProxy::OnSendEncodedImage(
|
| const EncodedImage& encoded_image,
|
| const CodecSpecificInfo* codec_info) {
|
| @@ -634,6 +738,7 @@ void SendStatisticsProxy::OnSendEncodedImage(
|
| simulcast_idx = codec_info->codecSpecific.generic.simulcast_idx;
|
| }
|
| if (codec_info->codec_name) {
|
| + UpdateEncoderFallbackStats(codec_info);
|
| stats_.encoder_implementation_name = codec_info->codec_name;
|
| }
|
| }
|
|
|