Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(58)

Unified Diff: webrtc/modules/desktop_capture/win/dxgi_duplicator_controller.cc

Issue 2703123002: Skips the first frame in DxgiDuplicatorController (Closed)
Patch Set: Resolve review comments Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: webrtc/modules/desktop_capture/win/dxgi_duplicator_controller.cc
diff --git a/webrtc/modules/desktop_capture/win/dxgi_duplicator_controller.cc b/webrtc/modules/desktop_capture/win/dxgi_duplicator_controller.cc
index 065a6148c06ba85ded23d9db3943eca650e1a306..a5f09f00407b301b112ecd7d6d2d0b62d4508564 100644
--- a/webrtc/modules/desktop_capture/win/dxgi_duplicator_controller.cc
+++ b/webrtc/modules/desktop_capture/win/dxgi_duplicator_controller.cc
@@ -16,8 +16,10 @@
#include <string>
#include "webrtc/base/checks.h"
+#include "webrtc/base/timeutils.h"
#include "webrtc/modules/desktop_capture/desktop_capture_types.h"
#include "webrtc/modules/desktop_capture/win/screen_capture_utils.h"
+#include "webrtc/system_wrappers/include/sleep.h"
namespace webrtc {
@@ -104,14 +106,7 @@ DesktopRect DxgiDuplicatorController::ScreenRect(int id) {
int DxgiDuplicatorController::ScreenCount() {
rtc::CritScope lock(&lock_);
- if (!Initialize()) {
- return 0;
- }
- int result = 0;
- for (auto& duplicator : duplicators_) {
- result += duplicator.screen_count();
- }
- return result;
+ return ScreenCountUnlocked();
}
void DxgiDuplicatorController::Unregister(const Context* const context) {
@@ -235,7 +230,11 @@ bool DxgiDuplicatorController::DoDuplicate(Context* context,
if (DoDuplicateUnlocked(context, monitor_id, target)) {
return true;
}
- Deinitialize();
+ if (monitor_id < ScreenCountUnlocked()) {
+ // It's a user error to provide a |monitor_id| larger than screen count. We
+ // do not need to deinitialize.
+ Deinitialize();
+ }
return false;
}
@@ -256,18 +255,41 @@ bool DxgiDuplicatorController::DoDuplicateUnlocked(Context* context,
}
Setup(context);
+
+ if (!EnsureFrameCaptured(context, target)) {
+ return false;
+ }
+
+ bool result = false;
if (monitor_id < 0) {
// Capture entire screen.
- for (size_t i = 0; i < duplicators_.size(); i++) {
- if (!duplicators_[i].Duplicate(&context->contexts_[i], target)) {
- return false;
- }
- }
+ result = DoDuplicateAll(context, target);
+ } else {
+ result = DoDuplicateOne(context, monitor_id, target);
+ }
+
+ if (result) {
target->set_dpi(dpi());
return true;
}
- // Capture one monitor.
+ return false;
+}
+
+bool DxgiDuplicatorController::DoDuplicateAll(Context* context,
+ SharedDesktopFrame* target) {
+ for (size_t i = 0; i < duplicators_.size(); i++) {
+ if (!duplicators_[i].Duplicate(&context->contexts_[i], target)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool DxgiDuplicatorController::DoDuplicateOne(Context* context,
+ int monitor_id,
+ SharedDesktopFrame* target) {
+ RTC_DCHECK(monitor_id >= 0);
for (size_t i = 0; i < duplicators_.size() && i < context->contexts_.size();
i++) {
if (monitor_id >= duplicators_[i].screen_count()) {
@@ -275,15 +297,83 @@ bool DxgiDuplicatorController::DoDuplicateUnlocked(Context* context,
} else {
if (duplicators_[i].DuplicateMonitor(&context->contexts_[i], monitor_id,
target)) {
- target->set_dpi(dpi());
return true;
}
return false;
}
}
- // id >= ScreenCount(). This is a user error, so we do not need to
- // deinitialize.
return false;
}
+int64_t DxgiDuplicatorController::GetNumFramesCaptured() const {
+ int64_t min = INT64_MAX;
+ for (const auto& duplicator : duplicators_) {
+ min = std::min(min, duplicator.GetNumFramesCaptured());
+ }
+
+ return min;
+}
+
+int DxgiDuplicatorController::ScreenCountUnlocked() {
+ if (!Initialize()) {
+ return 0;
+ }
+ int result = 0;
+ for (auto& duplicator : duplicators_) {
+ result += duplicator.screen_count();
+ }
+ return result;
+}
+
+bool DxgiDuplicatorController::EnsureFrameCaptured(Context* context,
+ 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.
+ const int64_t ms_per_frame = 17;
+ // Skips the first frame to ensure a full frame refresh has happened before
+ // this function returns.
+ const int64_t frames_to_skip = 1;
+ // The total time out milliseconds for this function. If we cannot get enough
+ // frames during this time interval, this function returns false, and cause
+ // the DXGI components to be reinitialized. This usually should not happen
+ // unless the system is switching display mode when this function is being
+ // called. 500 milliseconds should be enough for ~30 frames.
+ const int64_t timeout_ms = 500;
+ if (GetNumFramesCaptured() >= 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|.
+ shared_frame = target;
+ } else {
+ fallback_frame = SharedDesktopFrame::Wrap(std::unique_ptr<DesktopFrame>(
+ new BasicDesktopFrame(desktop_size())));
+ shared_frame = fallback_frame.get();
+ }
+
+ const int64_t start_ms = rtc::TimeMillis();
+ int64_t last_frame_start_ms = 0;
+ while (GetNumFramesCaptured() < frames_to_skip) {
+ if (GetNumFramesCaptured() > 0) {
+ // Sleep |ms_per_frame| before capturing next frame to ensure the screen
+ // has been updated by the video adapter.
+ webrtc::SleepMs(
+ ms_per_frame - (rtc::TimeMillis() - last_frame_start_ms));
+ }
+ last_frame_start_ms = rtc::TimeMillis();
+ if (!DoDuplicateAll(context, shared_frame)) {
+ return false;
+ }
+ if (rtc::TimeMillis() - start_ms > timeout_ms) {
+ return false;
+ }
+ }
+ return true;
+}
+
} // namespace webrtc

Powered by Google App Engine
This is Rietveld 408576698