Harmonic frame rate metric.
This adds calculation and reporting of harmonic frame rate (HFR) metric. HFR is calculated as call_duration_secs / sum(frame_duration_secs ^ 2). It penalizes long freezes and could better represent user experience related to smoothness of playback. Bug: none Change-Id: I4d2d46deaa44bb4221b53969a1c0a334e0c1bde9 Reviewed-on: https://webrtc-review.googlesource.com/c/117661 Commit-Queue: Sergey Silkin <ssilkin@webrtc.org> Reviewed-by: Erik Språng <sprang@webrtc.org> Cr-Commit-Position: refs/heads/master@{#26279}
This commit is contained in:
parent
dcc70297cd
commit
50e77457db
@ -1104,6 +1104,41 @@ TEST_P(ReceiveStatisticsProxyTest, FreezesAreReported) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(ReceiveStatisticsProxyTest, HarmonicFrameRateIsReported) {
|
||||
const VideoContentType content_type = GetParam();
|
||||
const int kInterFrameDelayMs = 33;
|
||||
const int kFreezeDelayMs = 200;
|
||||
const int kCallDurationMs =
|
||||
kMinRequiredSamples * kInterFrameDelayMs + kFreezeDelayMs;
|
||||
webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight);
|
||||
|
||||
for (int i = 0; i < kMinRequiredSamples; ++i) {
|
||||
fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs);
|
||||
statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, content_type);
|
||||
statistics_proxy_->OnRenderedFrame(frame);
|
||||
}
|
||||
// Add extra freeze.
|
||||
fake_clock_.AdvanceTimeMilliseconds(kFreezeDelayMs);
|
||||
statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, content_type);
|
||||
statistics_proxy_->OnRenderedFrame(frame);
|
||||
|
||||
statistics_proxy_.reset();
|
||||
double kSumSquaredInterframeDelaysSecs =
|
||||
(kMinRequiredSamples - 1) *
|
||||
(kInterFrameDelayMs / 1000.0 * kInterFrameDelayMs / 1000.0);
|
||||
kSumSquaredInterframeDelaysSecs +=
|
||||
kFreezeDelayMs / 1000.0 * kFreezeDelayMs / 1000.0;
|
||||
const int kExpectedHarmonicFrameRateFps =
|
||||
std::round(kCallDurationMs / (1000 * kSumSquaredInterframeDelaysSecs));
|
||||
if (videocontenttypehelpers::IsScreenshare(content_type)) {
|
||||
EXPECT_EQ(kExpectedHarmonicFrameRateFps,
|
||||
metrics::MinSample("WebRTC.Video.Screenshare.HarmonicFrameRate"));
|
||||
} else {
|
||||
EXPECT_EQ(kExpectedHarmonicFrameRateFps,
|
||||
metrics::MinSample("WebRTC.Video.HarmonicFrameRate"));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(ReceiveStatisticsProxyTest, PausesAreIgnored) {
|
||||
const VideoContentType content_type = GetParam();
|
||||
const int kInterFrameDelayMs = 33;
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
#include "video/video_quality_observer.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
@ -41,6 +42,7 @@ VideoQualityObserver::VideoQualityObserver(VideoContentType content_type)
|
||||
last_frame_pixels_(0),
|
||||
is_last_frame_blocky_(false),
|
||||
last_unfreeze_time_(0),
|
||||
sum_squared_interframe_delays_secs_(0.0),
|
||||
time_in_resolution_ms_(3, 0),
|
||||
current_resolution_(Resolution::Low),
|
||||
num_resolution_downgrades_(0),
|
||||
@ -118,6 +120,15 @@ void VideoQualityObserver::UpdateHistograms() {
|
||||
num_freezes_per_minute);
|
||||
log_stream << uma_prefix << ".NumberFreezesPerMinute "
|
||||
<< num_freezes_per_minute << "\n";
|
||||
|
||||
if (sum_squared_interframe_delays_secs_ > 0.0) {
|
||||
int harmonic_framerate_fps = std::round(
|
||||
video_duration_ms / (1000 * sum_squared_interframe_delays_secs_));
|
||||
RTC_HISTOGRAM_COUNTS_SPARSE_100(uma_prefix + ".HarmonicFrameRate",
|
||||
harmonic_framerate_fps);
|
||||
log_stream << uma_prefix << ".HarmonicFrameRate "
|
||||
<< harmonic_framerate_fps << "\n";
|
||||
}
|
||||
}
|
||||
RTC_LOG(LS_INFO) << log_stream.str();
|
||||
}
|
||||
@ -134,7 +145,10 @@ void VideoQualityObserver::OnRenderedFrame(const VideoFrame& frame,
|
||||
|
||||
if (!is_paused_ && num_frames_rendered_ > 1) {
|
||||
// Process inter-frame delay.
|
||||
int64_t interframe_delay_ms = now_ms - last_frame_rendered_ms_;
|
||||
const int64_t interframe_delay_ms = now_ms - last_frame_rendered_ms_;
|
||||
const float interframe_delays_secs = interframe_delay_ms / 1000.0;
|
||||
sum_squared_interframe_delays_secs_ +=
|
||||
interframe_delays_secs * interframe_delays_secs;
|
||||
render_interframe_delays_.Add(interframe_delay_ms);
|
||||
absl::optional<int> avg_interframe_delay =
|
||||
render_interframe_delays_.Avg(kMinFrameSamplesToDetectFreeze);
|
||||
|
||||
@ -57,7 +57,7 @@ class VideoQualityObserver {
|
||||
// Decoded timestamp of the last delayed frame.
|
||||
int64_t last_unfreeze_time_;
|
||||
rtc::SampleCounter render_interframe_delays_;
|
||||
rtc::SampleCounter decode_interframe_delays_;
|
||||
double sum_squared_interframe_delays_secs_;
|
||||
// An inter-frame delay is counted as a freeze if it's significantly longer
|
||||
// than average inter-frame delay.
|
||||
rtc::SampleCounter freezes_durations_;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user