| 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
|
|
|