blob: fb24b3a676f8e7d0730ce1ada9cd386dfdcec55a [file] [log] [blame]
/*
* 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 WEBRTC_MODULES_DESKTOP_CAPTURE_WIN_DXGI_DUPLICATOR_CONTROLLER_H_
#define WEBRTC_MODULES_DESKTOP_CAPTURE_WIN_DXGI_DUPLICATOR_CONTROLLER_H_
#include <memory>
#include <vector>
#include "webrtc/base/criticalsection.h"
#include "webrtc/modules/desktop_capture/desktop_geometry.h"
#include "webrtc/modules/desktop_capture/desktop_region.h"
#include "webrtc/modules/desktop_capture/shared_desktop_frame.h"
#include "webrtc/modules/desktop_capture/win/d3d_device.h"
#include "webrtc/modules/desktop_capture/win/dxgi_adapter_duplicator.h"
namespace webrtc {
// A controller for all the objects we need to call Windows DirectX capture APIs
// It's a singleton because, only one IDXGIOutputDuplication instance per
// monitor is allowed per application.
//
// Consumers should create a DxgiDuplicatorController::Context and keep it
// throughout their lifetime, and pass it when calling Duplicate(). Consumers
// can also call IsSupported() to determine whether the system supports DXGI
// duplicator or not. If a previous IsSupported() function call returns true,
// 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.)
class DxgiDuplicatorController {
public:
// A context to store the status of a single consumer of
// DxgiDuplicatorController.
class Context {
public:
// Unregister this Context instance from all Dxgi duplicators during
// destructing.
~Context();
private:
friend class DxgiDuplicatorController;
// A Context will have an exactly same |identity_| as
// DxgiDuplicatorController, to ensure it has been correctly setted up after
// each DxgiDuplicatorController::Initialize().
int identity_ = 0;
// Child DxgiAdapterDuplicator::Context belongs to this Context.
std::vector<DxgiAdapterDuplicator::Context> contexts_;
};
// Returns the singleton instance of DxgiDuplicatorController.
static DxgiDuplicatorController* Instance();
// Destructs current instance. We need to make sure COM components and their
// containers are destructed in correct order.
~DxgiDuplicatorController();
// Detects whether the system supports DXGI based capturer.
bool IsSupported();
// Captures current screen and writes into target. Since we are using double
// buffering, |last_frame|.updated_region() is used to represent the not
// updated regions in current |target| frame, which should also be copied this
// time.
// 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
// synchronize them manually. We should find a way to do it.
bool Duplicate(Context* context, SharedDesktopFrame* target);
// 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.
bool DuplicateMonitor(Context* context,
int monitor_id,
SharedDesktopFrame* target);
// Returns dpi of current system. Returns an empty DesktopVector if system
// does not support DXGI based capturer.
DesktopVector dpi();
// Returns entire desktop size. Returns an empty DesktopRect if system does
// not support DXGI based capturer.
DesktopRect desktop_rect();
// Returns a DesktopSize to cover entire desktop_rect. This may be different
// than desktop_rect().size(), since top-left screen does not need to start
// from (0, 0).
DesktopSize desktop_size();
// Returns the size of one screen. |monitor_id| should be >= 0. If system does
// not support DXGI based capturer, or |monitor_id| is greater than the total
// screen count of all the Duplicators, this function returns an empty
// DesktopRect.
DesktopRect ScreenRect(int id);
// Returns the count of screens on the system. These screens can be retrieved
// by an integer in the range of [0, ScreenCount()). If system does not
// support DXGI based capturer, this function returns 0.
int ScreenCount();
private:
// Context calls private Unregister(Context*) function during
// destructing.
friend class Context;
// A private constructor to ensure consumers to use
// DxgiDuplicatorController::Instance().
DxgiDuplicatorController();
// Unregisters Context from this instance and all DxgiAdapterDuplicator(s)
// it owns.
void Unregister(const Context* const context);
// All functions below should be called in |lock_| locked scope.
// If current instance has not been initialized, executes DoInitialize
// function, and returns initialize result. Otherwise directly returns true.
bool Initialize();
bool DoInitialize();
// Clears all COM components referred by this instance. So next Duplicate()
// call will eventually initialize this instance again.
void Deinitialize();
// A helper function to check whether a Context has been expired.
bool ContextExpired(const Context* const context) const;
// Updates Context if needed.
void Setup(Context* context);
// Do the real duplication work. |monitor_id < 0| to capture entire screen.
bool DoDuplicate(Context* context,
int monitor_id,
SharedDesktopFrame* target);
// This lock must be locked whenever accessing any of the following objects.
rtc::CriticalSection lock_;
// A self-incremented integer to compare with the one in Context, to
// ensure a Context has been initialized after DxgiDuplicatorController.
int identity_ = 0;
DesktopRect desktop_rect_;
DesktopVector dpi_;
std::vector<DxgiAdapterDuplicator> duplicators_;
};
} // namespace webrtc
#endif // WEBRTC_MODULES_DESKTOP_CAPTURE_WIN_DXGI_DUPLICATOR_CONTROLLER_H_