Reduce redundant memory allocation when capturing a single monitor.

When capturing only one display, it is unnecessary to use
DoDuplicateAll, which allocates bitmap image memory for a rectangle
encompassing all screens and captures all displays. In this case, I
switch to DoDuplicateOne.

I have added an int parameter to GetNumFrameCaptured and
EnsureFrameCaptured to distinguish which display's skip behavior is
currently being executed.

After the modification, when capturing a single monitor in a
multi-monitor environment, only the bitmap image memory of the size of
the captured monitor will be allocated, rather than for all monitors.

Bug: webrtc:391914255
Change-Id: Iee56796c50282beaf1dbeef47f5937fe7fe94a05
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/375181
Reviewed-by: Joe Downing <joedow@chromium.org>
Commit-Queue: Alexander Cooper <alcooper@chromium.org>
Reviewed-by: Alexander Cooper <alcooper@chromium.org>
Cr-Commit-Position: refs/heads/main@{#43822}
This commit is contained in:
fizzfang 2025-01-24 16:47:11 +08:00 committed by WebRTC LUCI CQ
parent eb688d6e80
commit feabcdb76b
5 changed files with 38 additions and 23 deletions

View File

@ -159,6 +159,7 @@ Yusuke Suzuki <utatane.tea@gmail.com>
Pengfei Han <hanpfei@gmail.com> Pengfei Han <hanpfei@gmail.com>
Yingying Ma <yingying.ma@intel.com> Yingying Ma <yingying.ma@intel.com>
Hailin Zhao <lynnworld7@gmail.com> Hailin Zhao <lynnworld7@gmail.com>
Fizz Fang <fangkb555@gmail.com>
# END individuals section. # END individuals section.
# BEGIN organizations section. # BEGIN organizations section.

View File

@ -164,12 +164,15 @@ int DxgiAdapterDuplicator::screen_count() const {
return static_cast<int>(duplicators_.size()); return static_cast<int>(duplicators_.size());
} }
int64_t DxgiAdapterDuplicator::GetNumFramesCaptured() const { int64_t DxgiAdapterDuplicator::GetNumFramesCaptured(int monitor_id) const {
int64_t min = INT64_MAX; int64_t min = INT64_MAX;
for (const auto& duplicator : duplicators_) { if (monitor_id < 0) {
min = std::min(min, duplicator.num_frames_captured()); for (const auto& duplicator : duplicators_) {
min = std::min(min, duplicator.num_frames_captured());
}
} else if (static_cast<size_t>(monitor_id) < duplicators_.size()) {
min = duplicators_[monitor_id].num_frames_captured();
} }
return min; return min;
} }

View File

@ -73,7 +73,7 @@ class DxgiAdapterDuplicator {
void Unregister(const Context* const context); void Unregister(const Context* const context);
// The minimum num_frames_captured() returned by `duplicators_`. // The minimum num_frames_captured() returned by `duplicators_`.
int64_t GetNumFramesCaptured() const; int64_t GetNumFramesCaptured(int monitor_id) const;
// Moves `desktop_rect_` and all underlying `duplicators_`. See // Moves `desktop_rect_` and all underlying `duplicators_`. See
// DxgiDuplicatorController::TranslateRect(). // DxgiDuplicatorController::TranslateRect().

View File

@ -331,7 +331,7 @@ bool DxgiDuplicatorController::DoDuplicateUnlocked(Context* context,
SharedDesktopFrame* target) { SharedDesktopFrame* target) {
Setup(context); Setup(context);
if (!EnsureFrameCaptured(context, target)) { if (!EnsureFrameCaptured(context, monitor_id, target)) {
return false; return false;
} }
@ -381,12 +381,11 @@ bool DxgiDuplicatorController::DoDuplicateOne(Context* context,
return false; return false;
} }
int64_t DxgiDuplicatorController::GetNumFramesCaptured() const { int64_t DxgiDuplicatorController::GetNumFramesCaptured(int monitor_id) const {
int64_t min = INT64_MAX; int64_t min = INT64_MAX;
for (const auto& duplicator : duplicators_) { for (const auto& duplicator : duplicators_) {
min = std::min(min, duplicator.GetNumFramesCaptured()); min = std::min(min, duplicator.GetNumFramesCaptured(monitor_id));
} }
return min; return min;
} }
@ -434,6 +433,7 @@ DesktopSize DxgiDuplicatorController::SelectedDesktopSize(
} }
bool DxgiDuplicatorController::EnsureFrameCaptured(Context* context, bool DxgiDuplicatorController::EnsureFrameCaptured(Context* context,
int monitor_id,
SharedDesktopFrame* target) { SharedDesktopFrame* target) {
// On a modern system, the FPS / monitor refresh rate is usually larger than // On a modern system, the FPS / monitor refresh rate is usually larger than
// or equal to 60. So 17 milliseconds is enough to capture at least one frame. // or equal to 60. So 17 milliseconds is enough to capture at least one frame.
@ -448,7 +448,7 @@ bool DxgiDuplicatorController::EnsureFrameCaptured(Context* context,
// called. 500 milliseconds should be enough for ~30 frames. // called. 500 milliseconds should be enough for ~30 frames.
const int64_t timeout_ms = 500; const int64_t timeout_ms = 500;
if (GetNumFramesCaptured() == 0 && !IsConsoleSession()) { if (GetNumFramesCaptured(monitor_id) == 0 && !IsConsoleSession()) {
// When capturing a console session, waiting for a single frame is // When capturing a console session, waiting for a single frame is
// sufficient to ensure that DXGI output duplication is working. When the // sufficient to ensure that DXGI output duplication is working. When the
// session is not attached to the console, it has been observed that DXGI // session is not attached to the console, it has been observed that DXGI
@ -460,31 +460,38 @@ bool DxgiDuplicatorController::EnsureFrameCaptured(Context* context,
frames_to_skip = 5; frames_to_skip = 5;
} }
if (GetNumFramesCaptured() >= frames_to_skip) { if (GetNumFramesCaptured(monitor_id) >= frames_to_skip) {
return true; return true;
} }
std::unique_ptr<SharedDesktopFrame> fallback_frame; std::unique_ptr<SharedDesktopFrame> fallback_frame;
SharedDesktopFrame* shared_frame = nullptr; SharedDesktopFrame* shared_frame = nullptr;
if (target->size().width() >= desktop_size().width() && DesktopSize selected_size = SelectedDesktopSize(monitor_id);
target->size().height() >= desktop_size().height()) { if (target->size().width() >= selected_size.width() &&
// `target` is large enough to cover entire screen, we do not need to use target->size().height() >= selected_size.height()) {
// `fallback_frame`. // `target` is large enough to cover the currently captured screen,
// we do not need to use `fallback_frame`.
shared_frame = target; shared_frame = target;
} else { } else {
fallback_frame = SharedDesktopFrame::Wrap( fallback_frame = SharedDesktopFrame::Wrap(
std::unique_ptr<DesktopFrame>(new BasicDesktopFrame(desktop_size()))); std::unique_ptr<DesktopFrame>(new BasicDesktopFrame(selected_size)));
shared_frame = fallback_frame.get(); shared_frame = fallback_frame.get();
} }
const int64_t start_ms = rtc::TimeMillis(); const int64_t start_ms = rtc::TimeMillis();
while (GetNumFramesCaptured() < frames_to_skip) { while (GetNumFramesCaptured(monitor_id) < frames_to_skip) {
if (!DoDuplicateAll(context, shared_frame)) { if (monitor_id < 0) {
return false; if (!DoDuplicateAll(context, shared_frame)) {
return false;
}
} else {
if (!DoDuplicateOne(context, monitor_id, shared_frame)) {
return false;
}
} }
// Calling DoDuplicateAll() may change the number of frames captured. // Calling DoDuplicateAll() may change the number of frames captured.
if (GetNumFramesCaptured() >= frames_to_skip) { if (GetNumFramesCaptured(monitor_id) >= frames_to_skip) {
break; break;
} }

View File

@ -198,8 +198,10 @@ class RTC_EXPORT DxgiDuplicatorController {
SharedDesktopFrame* target) SharedDesktopFrame* target)
RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_); RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
// The minimum GetNumFramesCaptured() returned by `duplicators_`. // When monitor_id is kFullDesktopScreenId, meaning capturing all screens,
int64_t GetNumFramesCaptured() const RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_); // the minimum GetNumFramesCaptured(int monitor_id) returned by duplicators_.
int64_t GetNumFramesCaptured(int monitor_id) const
RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
// Returns a DesktopSize to cover entire `desktop_rect_`. // Returns a DesktopSize to cover entire `desktop_rect_`.
DesktopSize desktop_size() const RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_); DesktopSize desktop_size() const RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
@ -224,7 +226,9 @@ class RTC_EXPORT DxgiDuplicatorController {
// GetNumFramesCaptured() has never reached the requirement. // GetNumFramesCaptured() has never reached the requirement.
// According to http://crbug.com/682112, dxgi capturer returns a black frame // According to http://crbug.com/682112, dxgi capturer returns a black frame
// during first several capture attempts. // during first several capture attempts.
bool EnsureFrameCaptured(Context* context, SharedDesktopFrame* target) bool EnsureFrameCaptured(Context* context,
int monitor_id,
SharedDesktopFrame* target)
RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_); RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
// Moves `desktop_rect_` and all underlying `duplicators_`, putting top left // Moves `desktop_rect_` and all underlying `duplicators_`, putting top left