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.
|
// UI responsive.
|
||||||
const int kDefaultMaximumCpuConsumptionPercentage = 50;
|
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(
|
webrtc::DesktopRect ComputeLetterboxRect(
|
||||||
const webrtc::DesktopSize& max_size,
|
const webrtc::DesktopSize& max_size,
|
||||||
const webrtc::DesktopSize& source_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
|
} // namespace
|
||||||
|
|
||||||
class DesktopCaptureDevice::Core : public webrtc::DesktopCapturer::Callback {
|
class DesktopCaptureDevice::Core : public webrtc::DesktopCapturer::Callback {
|
||||||
@@ -205,6 +220,11 @@ class DesktopCaptureDevice::Core : public webrtc::DesktopCapturer::Callback {
|
|||||||
// Inverse of the requested frame rate.
|
// Inverse of the requested frame rate.
|
||||||
base::TimeDelta requested_frame_duration_;
|
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.
|
// Records time of last call to CaptureFrame.
|
||||||
base::TimeTicks capture_start_time_;
|
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.
|
// The system time when we receive the first frame.
|
||||||
base::TimeTicks first_ref_time_;
|
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
|
// TODO(jiayl): Remove wake_lock_ when there is an API to keep the
|
||||||
// screen from sleeping for the drive-by web.
|
// screen from sleeping for the drive-by web.
|
||||||
mojo::Remote<device::mojom::WakeLock> wake_lock_;
|
mojo::Remote<device::mojom::WakeLock> wake_lock_;
|
||||||
@@ -300,6 +325,7 @@ void DesktopCaptureDevice::Core::AllocateAndStart(
|
|||||||
|
|
||||||
client_ = std::move(client);
|
client_ = std::move(client);
|
||||||
requested_frame_rate_ = params.requested_format.frame_rate;
|
requested_frame_rate_ = params.requested_format.frame_rate;
|
||||||
|
frame_rate_ = requested_frame_rate_;
|
||||||
requested_frame_duration_ = base::Microseconds(static_cast<int64_t>(
|
requested_frame_duration_ = base::Microseconds(static_cast<int64_t>(
|
||||||
static_cast<double>(base::Time::kMicrosecondsPerSecond) /
|
static_cast<double>(base::Time::kMicrosecondsPerSecond) /
|
||||||
requested_frame_rate_ +
|
requested_frame_rate_ +
|
||||||
@@ -313,7 +339,10 @@ void DesktopCaptureDevice::Core::AllocateAndStart(
|
|||||||
constraints.fixed_aspect_ratio);
|
constraints.fixed_aspect_ratio);
|
||||||
VLOG(2) << __func__ << " (requested_frame_rate=" << requested_frame_rate_
|
VLOG(2) << __func__ << " (requested_frame_rate=" << requested_frame_rate_
|
||||||
<< ", max_frame_size=" << constraints.max_frame_size.ToString()
|
<< ", 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_);
|
DCHECK(!wake_lock_);
|
||||||
RequestWakeLock();
|
RequestWakeLock();
|
||||||
@@ -577,6 +606,28 @@ void DesktopCaptureDevice::Core::CaptureFrame() {
|
|||||||
capture_start_time_ = NowTicks();
|
capture_start_time_ = NowTicks();
|
||||||
capture_in_progress_ = true;
|
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();
|
desktop_capturer_->CaptureFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -593,6 +644,7 @@ void DesktopCaptureDevice::Core::ScheduleNextCaptureFrame() {
|
|||||||
std::max((last_capture_duration * 100) / max_cpu_consumption_percentage_,
|
std::max((last_capture_duration * 100) / max_cpu_consumption_percentage_,
|
||||||
requested_frame_duration_);
|
requested_frame_duration_);
|
||||||
|
|
||||||
|
VLOG(2) << " capture_period=" << capture_period.InMilliseconds();
|
||||||
VLOG(2) << " timer(dT="
|
VLOG(2) << " timer(dT="
|
||||||
<< (capture_period - last_capture_duration).InMilliseconds() << ")";
|
<< (capture_period - last_capture_duration).InMilliseconds() << ")";
|
||||||
// Schedule a task for the next frame.
|
// Schedule a task for the next frame.
|
||||||
|
@@ -977,6 +977,22 @@ chromium-metrics-reviews@google.com.
|
|||||||
</token>
|
</token>
|
||||||
</histogram>
|
</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}"
|
<histogram name="WebRTC.DesktopCapture.IsZeroHzActive.{CapturerType}"
|
||||||
enum="BooleanActive" expires_after="2024-02-03">
|
enum="BooleanActive" expires_after="2024-02-03">
|
||||||
<owner>henrika@chromium.org</owner>
|
<owner>henrika@chromium.org</owner>
|
||||||
|
Reference in New Issue
Block a user