Adds support of continuous frame-rate calculations for desktop capturing
Bug: 1400204 Change-Id: I383ef0d2c8eadace5b911d35bbdc4bb744f77309 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4472543 Commit-Queue: Henrik Andreasson <henrika@chromium.org> Reviewed-by: Alexander Cooper <alcooper@chromium.org> Code-Coverage: Findit <findit-for-me@appspot.gserviceaccount.com> Cr-Commit-Position: refs/heads/main@{#1136371}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
0d3edf74fc
commit
2ce2155e47
content/browser/media/capture
tools/metrics/histograms/metadata/web_rtc
@@ -68,6 +68,10 @@ namespace {
|
||||
// UI responsive.
|
||||
const int kDefaultMaximumCpuConsumptionPercentage = 50;
|
||||
|
||||
// Constant which sets the cutoff frequency in an an exponential moving average
|
||||
// (EMA) filter used to calculate the current frame rate (in frames per second).
|
||||
constexpr float kAlpha = 0.1;
|
||||
|
||||
webrtc::DesktopRect ComputeLetterboxRect(
|
||||
const webrtc::DesktopSize& max_size,
|
||||
const webrtc::DesktopSize& source_size) {
|
||||
@@ -133,6 +137,17 @@ void LogDesktopCaptureFrameIsRefresh(DesktopMediaID::Type capturer_type,
|
||||
}
|
||||
}
|
||||
|
||||
void LogDesktopCaptureFrameRate(DesktopMediaID::Type capturer_type,
|
||||
int frame_rate_fps) {
|
||||
if (capturer_type == DesktopMediaID::TYPE_SCREEN) {
|
||||
UMA_HISTOGRAM_COUNTS_100("WebRTC.DesktopCapture.FrameRate.Screen",
|
||||
frame_rate_fps);
|
||||
} else {
|
||||
UMA_HISTOGRAM_COUNTS_100("WebRTC.DesktopCapture.FrameRate.Window",
|
||||
frame_rate_fps);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
class DesktopCaptureDevice::Core : public webrtc::DesktopCapturer::Callback {
|
||||
@@ -205,6 +220,11 @@ class DesktopCaptureDevice::Core : public webrtc::DesktopCapturer::Callback {
|
||||
// Inverse of the requested frame rate.
|
||||
base::TimeDelta requested_frame_duration_;
|
||||
|
||||
// Contains the actual (measured) frame rate using an exponential moving
|
||||
// average (EMA) filter. Uses a simple filter with 0.1 weight of the current
|
||||
// sample. Unit is in frames per second (fps).
|
||||
float frame_rate_;
|
||||
|
||||
// Records time of last call to CaptureFrame.
|
||||
base::TimeTicks capture_start_time_;
|
||||
|
||||
@@ -260,6 +280,11 @@ class DesktopCaptureDevice::Core : public webrtc::DesktopCapturer::Callback {
|
||||
// The system time when we receive the first frame.
|
||||
base::TimeTicks first_ref_time_;
|
||||
|
||||
// The time when Core::CaptureFrame() is called. Used to derive the delta
|
||||
// time since last call. The delta time then drives the frame-rate filter
|
||||
// which results in an average capture frame rate in `frame_rate_`.
|
||||
base::TimeTicks last_capture_time_;
|
||||
|
||||
// TODO(jiayl): Remove wake_lock_ when there is an API to keep the
|
||||
// screen from sleeping for the drive-by web.
|
||||
mojo::Remote<device::mojom::WakeLock> wake_lock_;
|
||||
@@ -300,6 +325,7 @@ void DesktopCaptureDevice::Core::AllocateAndStart(
|
||||
|
||||
client_ = std::move(client);
|
||||
requested_frame_rate_ = params.requested_format.frame_rate;
|
||||
frame_rate_ = requested_frame_rate_;
|
||||
requested_frame_duration_ = base::Microseconds(static_cast<int64_t>(
|
||||
static_cast<double>(base::Time::kMicrosecondsPerSecond) /
|
||||
requested_frame_rate_ +
|
||||
@@ -313,7 +339,10 @@ void DesktopCaptureDevice::Core::AllocateAndStart(
|
||||
constraints.fixed_aspect_ratio);
|
||||
VLOG(2) << __func__ << " (requested_frame_rate=" << requested_frame_rate_
|
||||
<< ", max_frame_size=" << constraints.max_frame_size.ToString()
|
||||
<< ")";
|
||||
<< ", requested_frame_duration="
|
||||
<< requested_frame_duration_.InMilliseconds()
|
||||
<< ", max_cpu_consumption_percentage="
|
||||
<< max_cpu_consumption_percentage_ << ")";
|
||||
|
||||
DCHECK(!wake_lock_);
|
||||
RequestWakeLock();
|
||||
@@ -577,6 +606,28 @@ void DesktopCaptureDevice::Core::CaptureFrame() {
|
||||
capture_start_time_ = NowTicks();
|
||||
capture_in_progress_ = true;
|
||||
|
||||
if (last_capture_time_.is_null()) {
|
||||
last_capture_time_ = capture_start_time_;
|
||||
} else {
|
||||
const base::TimeDelta delta_ms = capture_start_time_ - last_capture_time_;
|
||||
// We use an exponential moving average (EMA) filter to calculate the
|
||||
// current frame rate (in frames per second). The filter has the following
|
||||
// difference (time-domain) equation:
|
||||
// y[i]=α⋅x[i]+(1-α)⋅y[i−1]
|
||||
// where
|
||||
// y is the output, [i] denotes the sample number, x is the input, and α
|
||||
// is a constant which sets the cutoff frequency (a value between 0 and
|
||||
// 1 where 1 corresponds to "no filtering").
|
||||
// A value of α=0.1 results in a suitable amount of smoothing.
|
||||
const float input_frame_rate_fps = (1000.0 / delta_ms.InMillisecondsF());
|
||||
frame_rate_ = kAlpha * input_frame_rate_fps + (1.0 - kAlpha) * frame_rate_;
|
||||
last_capture_time_ = capture_start_time_;
|
||||
VLOG(2) << " delta_ms=" << delta_ms.InMillisecondsF()
|
||||
<< ", frame_rate=" << frame_rate_ << " [fps]";
|
||||
const int frame_rate_fps = base::saturated_cast<int>(frame_rate_ + 0.5);
|
||||
LogDesktopCaptureFrameRate(capturer_type_, frame_rate_fps);
|
||||
}
|
||||
|
||||
desktop_capturer_->CaptureFrame();
|
||||
}
|
||||
|
||||
@@ -593,6 +644,7 @@ void DesktopCaptureDevice::Core::ScheduleNextCaptureFrame() {
|
||||
std::max((last_capture_duration * 100) / max_cpu_consumption_percentage_,
|
||||
requested_frame_duration_);
|
||||
|
||||
VLOG(2) << " capture_period=" << capture_period.InMilliseconds();
|
||||
VLOG(2) << " timer(dT="
|
||||
<< (capture_period - last_capture_duration).InMilliseconds() << ")";
|
||||
// Schedule a task for the next frame.
|
||||
|
@@ -977,6 +977,22 @@ chromium-metrics-reviews@google.com.
|
||||
</token>
|
||||
</histogram>
|
||||
|
||||
<histogram name="WebRTC.DesktopCapture.FrameRate.{CapturerType}" units="fps"
|
||||
expires_after="2024-04-25">
|
||||
<owner>henrika@chromium.org</owner>
|
||||
<owner>webrtc-dev@chromium.org</owner>
|
||||
<summary>
|
||||
An integer value is recorded to this histogram for each captured video frame
|
||||
where the desktop media source is given by {CapturerType}. The value is an
|
||||
estimation of the current frame capture rate and the unit is in frames per
|
||||
second.
|
||||
</summary>
|
||||
<token key="CapturerType">
|
||||
<variant name="Screen" summary="Screen capture type"/>
|
||||
<variant name="Window" summary="Window capture type"/>
|
||||
</token>
|
||||
</histogram>
|
||||
|
||||
<histogram name="WebRTC.DesktopCapture.IsZeroHzActive.{CapturerType}"
|
||||
enum="BooleanActive" expires_after="2024-02-03">
|
||||
<owner>henrika@chromium.org</owner>
|
||||
|
Reference in New Issue
Block a user