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:
parent
eb688d6e80
commit
feabcdb76b
1
AUTHORS
1
AUTHORS
@ -159,6 +159,7 @@ Yusuke Suzuki <utatane.tea@gmail.com>
|
||||
Pengfei Han <hanpfei@gmail.com>
|
||||
Yingying Ma <yingying.ma@intel.com>
|
||||
Hailin Zhao <lynnworld7@gmail.com>
|
||||
Fizz Fang <fangkb555@gmail.com>
|
||||
# END individuals section.
|
||||
|
||||
# BEGIN organizations section.
|
||||
|
||||
@ -164,12 +164,15 @@ int DxgiAdapterDuplicator::screen_count() const {
|
||||
return static_cast<int>(duplicators_.size());
|
||||
}
|
||||
|
||||
int64_t DxgiAdapterDuplicator::GetNumFramesCaptured() const {
|
||||
int64_t DxgiAdapterDuplicator::GetNumFramesCaptured(int monitor_id) const {
|
||||
int64_t min = INT64_MAX;
|
||||
if (monitor_id < 0) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@ -73,7 +73,7 @@ class DxgiAdapterDuplicator {
|
||||
void Unregister(const Context* const context);
|
||||
|
||||
// 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
|
||||
// DxgiDuplicatorController::TranslateRect().
|
||||
|
||||
@ -331,7 +331,7 @@ bool DxgiDuplicatorController::DoDuplicateUnlocked(Context* context,
|
||||
SharedDesktopFrame* target) {
|
||||
Setup(context);
|
||||
|
||||
if (!EnsureFrameCaptured(context, target)) {
|
||||
if (!EnsureFrameCaptured(context, monitor_id, target)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -381,12 +381,11 @@ bool DxgiDuplicatorController::DoDuplicateOne(Context* context,
|
||||
return false;
|
||||
}
|
||||
|
||||
int64_t DxgiDuplicatorController::GetNumFramesCaptured() const {
|
||||
int64_t DxgiDuplicatorController::GetNumFramesCaptured(int monitor_id) const {
|
||||
int64_t min = INT64_MAX;
|
||||
for (const auto& duplicator : duplicators_) {
|
||||
min = std::min(min, duplicator.GetNumFramesCaptured());
|
||||
min = std::min(min, duplicator.GetNumFramesCaptured(monitor_id));
|
||||
}
|
||||
|
||||
return min;
|
||||
}
|
||||
|
||||
@ -434,6 +433,7 @@ DesktopSize DxgiDuplicatorController::SelectedDesktopSize(
|
||||
}
|
||||
|
||||
bool DxgiDuplicatorController::EnsureFrameCaptured(Context* context,
|
||||
int monitor_id,
|
||||
SharedDesktopFrame* target) {
|
||||
// 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.
|
||||
@ -448,7 +448,7 @@ bool DxgiDuplicatorController::EnsureFrameCaptured(Context* context,
|
||||
// called. 500 milliseconds should be enough for ~30 frames.
|
||||
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
|
||||
// sufficient to ensure that DXGI output duplication is working. When the
|
||||
// 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;
|
||||
}
|
||||
|
||||
if (GetNumFramesCaptured() >= frames_to_skip) {
|
||||
if (GetNumFramesCaptured(monitor_id) >= frames_to_skip) {
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<SharedDesktopFrame> fallback_frame;
|
||||
SharedDesktopFrame* shared_frame = nullptr;
|
||||
if (target->size().width() >= desktop_size().width() &&
|
||||
target->size().height() >= desktop_size().height()) {
|
||||
// `target` is large enough to cover entire screen, we do not need to use
|
||||
// `fallback_frame`.
|
||||
DesktopSize selected_size = SelectedDesktopSize(monitor_id);
|
||||
if (target->size().width() >= selected_size.width() &&
|
||||
target->size().height() >= selected_size.height()) {
|
||||
// `target` is large enough to cover the currently captured screen,
|
||||
// we do not need to use `fallback_frame`.
|
||||
shared_frame = target;
|
||||
} else {
|
||||
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();
|
||||
}
|
||||
|
||||
const int64_t start_ms = rtc::TimeMillis();
|
||||
while (GetNumFramesCaptured() < frames_to_skip) {
|
||||
while (GetNumFramesCaptured(monitor_id) < frames_to_skip) {
|
||||
if (monitor_id < 0) {
|
||||
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.
|
||||
if (GetNumFramesCaptured() >= frames_to_skip) {
|
||||
if (GetNumFramesCaptured(monitor_id) >= frames_to_skip) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@ -198,8 +198,10 @@ class RTC_EXPORT DxgiDuplicatorController {
|
||||
SharedDesktopFrame* target)
|
||||
RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
|
||||
|
||||
// The minimum GetNumFramesCaptured() returned by `duplicators_`.
|
||||
int64_t GetNumFramesCaptured() const RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
|
||||
// When monitor_id is kFullDesktopScreenId, meaning capturing all screens,
|
||||
// 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_`.
|
||||
DesktopSize desktop_size() const RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
|
||||
@ -224,7 +226,9 @@ class RTC_EXPORT DxgiDuplicatorController {
|
||||
// GetNumFramesCaptured() has never reached the requirement.
|
||||
// According to http://crbug.com/682112, dxgi capturer returns a black frame
|
||||
// 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_);
|
||||
|
||||
// Moves `desktop_rect_` and all underlying `duplicators_`, putting top left
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user