Chromium Code Reviews| 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..b5fe677e40cf932eeee38375845290f0174b8302 100644 |
| --- a/webrtc/modules/desktop_capture/win/dxgi_duplicator_controller.cc |
| +++ b/webrtc/modules/desktop_capture/win/dxgi_duplicator_controller.cc |
| @@ -16,11 +16,29 @@ |
| #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 { |
| +namespace { |
| + |
| +void SleepMoreThanMs(int milliseconds) { |
|
Sergey Ulanov
2017/02/23 19:07:30
Do you really need this function? webrtc::SleepMs(
Hzj_jie
2017/02/23 20:52:11
According to MSDN, the Sleep() function may still
Sergey Ulanov
2017/02/23 21:06:43
Where does it say that? I was reading these page:
Hzj_jie
2017/02/23 21:48:58
It states,
If dwMilliseconds is less than the reso
Sergey Ulanov
2017/02/24 00:40:40
Ah, I see. Sorry I missed it. Still, I don't think
Hzj_jie
2017/02/24 01:28:52
Done.
|
| + if (milliseconds <= 0) { |
| + return; |
| + } |
| + int64_t end_ms = rtc::TimeMillis() + milliseconds; |
| + int64_t current_ms = rtc::TimeMillis(); |
| + while (current_ms < end_ms) { |
| + webrtc::SleepMs(end_ms - current_ms); |
| + current_ms = rtc::TimeMillis(); |
| + } |
| +} |
| + |
| +} // namespace |
| + |
| DxgiDuplicatorController::Context::Context() = default; |
| DxgiDuplicatorController::Context::~Context() { |
| @@ -104,14 +122,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 +246,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 +271,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 +313,77 @@ 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::num_frames_captured() const { |
|
Sergey Ulanov
2017/02/23 19:07:30
GetNumFramesCaptured()
Hzj_jie
2017/02/23 20:52:11
Done.
|
| + int64_t min = INT64_MAX; |
| + for (size_t i = 0; i < duplicators_.size(); i++) { |
| + if (duplicators_[i].num_frames_captured() < min) { |
| + min = duplicators_[i].num_frames_captured(); |
| + } |
| + } |
| + |
| + 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; |
| + const int64_t skip_frames = 2; |
|
Sergey Ulanov
2017/02/23 19:07:30
Where does 2 come from? why 1 is not enough?
Sergey Ulanov
2017/02/23 19:07:30
maybe call it frames_to_skip?
Hzj_jie
2017/02/23 20:52:11
Done.
Hzj_jie
2017/02/23 20:52:11
By using 2, we can ensure we always wait for 17 mi
Sergey Ulanov
2017/02/23 21:06:43
But why do we need to ensure that at all? I think
Hzj_jie
2017/02/23 21:48:58
Here the real issue is, we need to ensure two succ
|
| + if (num_frames_captured() >= skip_frames) { |
| + 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()) { |
|
Sergey Ulanov
2017/02/23 19:07:30
Why is this necessary? Shouldn't the capturer make
Hzj_jie
2017/02/23 20:52:11
A ScreenCapturerWinDirectx may capture only one of
|
| + // |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(); |
| + } |
| + |
| + int64_t start_ms = rtc::TimeMillis(); |
| + int64_t last_frame_start_ms = 0; |
| + while (num_frames_captured() < skip_frames) { |
| + if (num_frames_captured() > 0) { |
| + // Sleep |ms_per_frame| before capturing next frame to ensure the screen |
| + // has been updated by the video adapter. |
| + SleepMoreThanMs( |
| + 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 > (ms_per_frame * skip_frames * 4)) { |
|
Sergey Ulanov
2017/02/23 19:07:30
Where does 4 come from? I suggest adding a separat
Hzj_jie
2017/02/23 20:52:11
It's a very random number. :)
Updated.
|
| + return false; |
| + } |
| + } |
| + return true; |
| +} |
| + |
| } // namespace webrtc |