diff --git a/modules/desktop_capture/win/dxgi_duplicator_controller.h b/modules/desktop_capture/win/dxgi_duplicator_controller.h index 43c1a79874..88c2939187 100644 --- a/modules/desktop_capture/win/dxgi_duplicator_controller.h +++ b/modules/desktop_capture/win/dxgi_duplicator_controller.h @@ -41,6 +41,10 @@ namespace webrtc { // but a later Duplicate() returns false, this usually means the display mode is // changing. Consumers should retry after a while. (Typically 50 milliseconds, // but according to hardware performance, this time may vary.) +// The underyling DxgiOutputDuplicators may take an additional reference on the +// frame passed in to the Duplicate methods so that they can guarantee delivery +// of new frames when requested; since if there have been no updates to the +// surface, they may be unable to capture a frame. class RTC_EXPORT DxgiDuplicatorController { public: using Context = DxgiFrameContext; @@ -89,7 +93,8 @@ class RTC_EXPORT DxgiDuplicatorController { // function returns false, the information in `info` may not accurate. bool RetrieveD3dInfo(D3dInfo* info); - // Captures current screen and writes into `frame`. + // Captures current screen and writes into `frame`. May retain a reference to + // `frame`'s underlying |SharedDesktopFrame|. // TODO(zijiehe): Windows cannot guarantee the frames returned by each // IDXGIOutputDuplication are synchronized. But we are using a totally // different threading model than the way Windows suggested, it's hard to @@ -98,7 +103,8 @@ class RTC_EXPORT DxgiDuplicatorController { // Captures one monitor and writes into target. `monitor_id` should >= 0. If // `monitor_id` is greater than the total screen count of all the Duplicators, - // this function returns false. + // this function returns false. May retain a reference to `frame`'s underlying + // |SharedDesktopFrame|. Result DuplicateMonitor(DxgiFrame* frame, int monitor_id); // Returns dpi of current system. Returns an empty DesktopVector if system diff --git a/modules/desktop_capture/win/dxgi_output_duplicator.h b/modules/desktop_capture/win/dxgi_output_duplicator.h index 198b5a636b..df15fe566e 100644 --- a/modules/desktop_capture/win/dxgi_output_duplicator.h +++ b/modules/desktop_capture/win/dxgi_output_duplicator.h @@ -61,6 +61,11 @@ class DxgiOutputDuplicator { // function copies the content to the rectangle of (offset.x(), offset.y()) to // (offset.x() + desktop_rect_.width(), offset.y() + desktop_rect_.height()). // Returns false in case of a failure. + // May retain a reference to `target` so that a "captured" frame can be + // returned in the event that a new frame is not ready to be captured yet. + // (Or in other words, if the call to IDXGIOutputDuplication::AcquireNextFrame + // indicates that there is not yet a new frame, this is usually because no + // updates have occurred to the frame). bool Duplicate(Context* context, DesktopVector offset, SharedDesktopFrame* target); diff --git a/modules/desktop_capture/win/screen_capturer_win_directx.cc b/modules/desktop_capture/win/screen_capturer_win_directx.cc index 1556d7c787..efa763993a 100644 --- a/modules/desktop_capture/win/screen_capturer_win_directx.cc +++ b/modules/desktop_capture/win/screen_capturer_win_directx.cc @@ -125,17 +125,23 @@ void ScreenCapturerWinDirectx::CaptureFrame() { int64_t capture_start_time_nanos = rtc::TimeNanos(); - frames_.MoveToNextFrame(); - if (!frames_.current_frame()) { - frames_.ReplaceCurrentFrame( + // Note that the [] operator will create the ScreenCaptureFrameQueue if it + // doesn't exist, so this is safe. + ScreenCaptureFrameQueue& frames = + frame_queue_map_[current_screen_id_]; + + frames.MoveToNextFrame(); + + if (!frames.current_frame()) { + frames.ReplaceCurrentFrame( std::make_unique(shared_memory_factory_.get())); } DxgiDuplicatorController::Result result; if (current_screen_id_ == kFullDesktopScreenId) { - result = controller_->Duplicate(frames_.current_frame()); + result = controller_->Duplicate(frames.current_frame()); } else { - result = controller_->DuplicateMonitor(frames_.current_frame(), + result = controller_->DuplicateMonitor(frames.current_frame(), current_screen_id_); } @@ -172,7 +178,7 @@ void ScreenCapturerWinDirectx::CaptureFrame() { } case DuplicateResult::SUCCEEDED: { std::unique_ptr frame = - frames_.current_frame()->frame()->Share(); + frames.current_frame()->frame()->Share(); int capture_time_ms = (rtc::TimeNanos() - capture_start_time_nanos) / rtc::kNumNanosecsPerMillisec; diff --git a/modules/desktop_capture/win/screen_capturer_win_directx.h b/modules/desktop_capture/win/screen_capturer_win_directx.h index d64913ed10..801a0632fc 100644 --- a/modules/desktop_capture/win/screen_capturer_win_directx.h +++ b/modules/desktop_capture/win/screen_capturer_win_directx.h @@ -14,6 +14,7 @@ #include #include +#include #include #include "api/scoped_refptr.h" @@ -86,7 +87,14 @@ class RTC_EXPORT ScreenCapturerWinDirectx : public DesktopCapturer { private: const rtc::scoped_refptr controller_; - ScreenCaptureFrameQueue frames_; + + // The underlying DxgiDuplicators may retain a reference to the frames that + // we ask them to duplicate so that they can continue returning valid frames + // in the event that the target has not been updated. Thus, we need to ensure + // that we have a separate frame queue for each source id, so that these held + // frames don't get overwritten with the data from another Duplicator/monitor. + std::unordered_map> + frame_queue_map_; std::unique_ptr shared_memory_factory_; Callback* callback_ = nullptr; SourceId current_screen_id_ = kFullDesktopScreenId;