/* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_DESKTOP_CAPTURE_WIN_DXGI_OUTPUT_DUPLICATOR_H_ #define MODULES_DESKTOP_CAPTURE_WIN_DXGI_OUTPUT_DUPLICATOR_H_ #include #include #include #include #include #include #include #include "modules/desktop_capture/desktop_frame_rotation.h" #include "modules/desktop_capture/desktop_geometry.h" #include "modules/desktop_capture/desktop_region.h" #include "modules/desktop_capture/shared_desktop_frame.h" #include "modules/desktop_capture/win/d3d_device.h" #include "modules/desktop_capture/win/dxgi_context.h" #include "modules/desktop_capture/win/dxgi_texture.h" #include "rtc_base/thread_annotations.h" namespace webrtc { // Duplicates the content on one IDXGIOutput, i.e. one monitor attached to one // video card. None of functions in this class is thread-safe. class DxgiOutputDuplicator { public: using Context = DxgiOutputContext; // Creates an instance of DxgiOutputDuplicator from a D3dDevice and one of its // IDXGIOutput1. Caller must maintain the lifetime of device, to make sure it // outlives this instance. Only DxgiAdapterDuplicator can create an instance. DxgiOutputDuplicator(const D3dDevice& device, const Microsoft::WRL::ComPtr& output, const DXGI_OUTPUT_DESC& desc); // To allow this class to work with vector. DxgiOutputDuplicator(DxgiOutputDuplicator&& other); // Destructs this instance. We need to make sure texture_ has been released // before duplication_. ~DxgiOutputDuplicator(); // Initializes duplication_ object. bool Initialize(); // Copies the content of current IDXGIOutput to the `target`. To improve the // performance, this function copies only regions merged from // `context`->updated_region and DetectUpdatedRegion(). The `offset` decides // the offset in the `target` where the content should be copied to. i.e. this // 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); // Returns the desktop rect covered by this DxgiOutputDuplicator. DesktopRect desktop_rect() const { return desktop_rect_; } // Returns the device name from DXGI_OUTPUT_DESC in utf8 encoding. const std::string& device_name() const { return device_name_; } void Setup(Context* context); void Unregister(const Context* const context); // How many frames have been captured by this DxigOutputDuplicator. int64_t num_frames_captured() const; // Moves `desktop_rect_`. See DxgiDuplicatorController::TranslateRect(). void TranslateRect(const DesktopVector& position); private: // Calls DoDetectUpdatedRegion(). If it fails, this function sets the // `updated_region` as entire UntranslatedDesktopRect(). void DetectUpdatedRegion(const DXGI_OUTDUPL_FRAME_INFO& frame_info, DesktopRegion* updated_region); // Returns untranslated updated region, which are directly returned by Windows // APIs. Returns false in case of a failure. bool DoDetectUpdatedRegion(const DXGI_OUTDUPL_FRAME_INFO& frame_info, DesktopRegion* updated_region); // Returns true if the mouse cursor is embedded in the captured frame and // false if not. Also logs the same boolean as // WebRTC.DesktopCapture.Win.DirectXCursorEmbedded UMA. bool ContainsMouseCursor(const DXGI_OUTDUPL_FRAME_INFO& frame_info); bool ReleaseFrame(); // Initializes duplication_ instance. Expects duplication_ is in empty status. // Returns false if system does not support IDXGIOutputDuplication. bool DuplicateOutput(); // Returns a DesktopRect with the same size of desktop_size(), but translated // by offset. DesktopRect GetTranslatedDesktopRect(DesktopVector offset) const; // Returns a DesktopRect with the same size of desktop_size(), but starts from // (0, 0). DesktopRect GetUntranslatedDesktopRect() const; // Spreads changes from `context` to other registered Context(s) in // contexts_. void SpreadContextChange(const Context* const context); // Returns the size of desktop rectangle current instance representing. DesktopSize desktop_size() const; const D3dDevice device_; const Microsoft::WRL::ComPtr output_; const std::string device_name_; DesktopRect desktop_rect_; Microsoft::WRL::ComPtr duplication_; DXGI_OUTDUPL_DESC desc_; std::vector metadata_; std::unique_ptr texture_; Rotation rotation_; DesktopSize unrotated_size_; // After each AcquireNextFrame() function call, updated_region_(s) of all // active Context(s) need to be updated. Since they have missed the // change this time. And during next Duplicate() function call, their // updated_region_ will be merged and copied. std::vector contexts_; // The last full frame of this output and its offset. If on AcquireNextFrame() // failed because of timeout, i.e. no update, we can copy content from // `last_frame_`. std::unique_ptr last_frame_; DesktopVector last_frame_offset_; int64_t num_frames_captured_ = 0; }; } // namespace webrtc #endif // MODULES_DESKTOP_CAPTURE_WIN_DXGI_OUTPUT_DUPLICATOR_H_