mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-13 05:40:42 +01:00
DXGI now consumes may_contain_cursor
Before: No attempt was made to figure out of the cursor was embedded into the captured video frame when using DXGI on Windows as screen capturer. Instead the cursor is superimposed on the frame by an external mouse and cursor composer. After: We now check if the display adapter supports embedding the mouse cursor and if so use it as is and thereby avoid adding it independently. Bug: chromium:1421656 Change-Id: Ie07fe13e1c8f9583769961328bb41fbc689cd8e0 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/299241 Reviewed-by: Alexander Cooper <alcooper@chromium.org> Commit-Queue: Henrik Andreassson <henrika@webrtc.org> Cr-Commit-Position: refs/heads/main@{#39742}
This commit is contained in:
parent
a0e4ce0e81
commit
d549e4b6ce
6 changed files with 39 additions and 19 deletions
|
@ -133,6 +133,7 @@ void DesktopFrame::CopyFrameInfoFrom(const DesktopFrame& other) {
|
||||||
*mutable_updated_region() = other.updated_region();
|
*mutable_updated_region() = other.updated_region();
|
||||||
set_top_left(other.top_left());
|
set_top_left(other.top_left());
|
||||||
set_icc_profile(other.icc_profile());
|
set_icc_profile(other.icc_profile());
|
||||||
|
set_may_contain_cursor(other.may_contain_cursor());
|
||||||
}
|
}
|
||||||
|
|
||||||
void DesktopFrame::MoveFrameInfoFrom(DesktopFrame* other) {
|
void DesktopFrame::MoveFrameInfoFrom(DesktopFrame* other) {
|
||||||
|
@ -142,6 +143,7 @@ void DesktopFrame::MoveFrameInfoFrom(DesktopFrame* other) {
|
||||||
mutable_updated_region()->Swap(other->mutable_updated_region());
|
mutable_updated_region()->Swap(other->mutable_updated_region());
|
||||||
set_top_left(other->top_left());
|
set_top_left(other->top_left());
|
||||||
set_icc_profile(other->icc_profile());
|
set_icc_profile(other->icc_profile());
|
||||||
|
set_may_contain_cursor(other->may_contain_cursor());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DesktopFrame::FrameDataIsBlack() const {
|
bool DesktopFrame::FrameDataIsBlack() const {
|
||||||
|
|
|
@ -24,8 +24,10 @@ namespace webrtc {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
std::unique_ptr<DesktopCapturer> CreateScreenCapturerWinDirectx() {
|
std::unique_ptr<DesktopCapturer> CreateScreenCapturerWinDirectx(
|
||||||
std::unique_ptr<DesktopCapturer> capturer(new ScreenCapturerWinDirectx());
|
const DesktopCaptureOptions& options) {
|
||||||
|
std::unique_ptr<DesktopCapturer> capturer(
|
||||||
|
new ScreenCapturerWinDirectx(options));
|
||||||
capturer.reset(new BlankDetectorDesktopCapturerWrapper(
|
capturer.reset(new BlankDetectorDesktopCapturerWrapper(
|
||||||
std::move(capturer), RgbaColor(0, 0, 0, 0)));
|
std::move(capturer), RgbaColor(0, 0, 0, 0)));
|
||||||
return capturer;
|
return capturer;
|
||||||
|
@ -51,7 +53,7 @@ std::unique_ptr<DesktopCapturer> DesktopCapturer::CreateRawScreenCapturer(
|
||||||
auto dxgi_duplicator_controller = DxgiDuplicatorController::Instance();
|
auto dxgi_duplicator_controller = DxgiDuplicatorController::Instance();
|
||||||
if (ScreenCapturerWinDirectx::IsSupported()) {
|
if (ScreenCapturerWinDirectx::IsSupported()) {
|
||||||
capturer.reset(new FallbackDesktopCapturerWrapper(
|
capturer.reset(new FallbackDesktopCapturerWrapper(
|
||||||
CreateScreenCapturerWinDirectx(), std::move(capturer)));
|
CreateScreenCapturerWinDirectx(options), std::move(capturer)));
|
||||||
return capturer;
|
return capturer;
|
||||||
}
|
}
|
||||||
} else if (options.allow_use_magnification_api()) {
|
} else if (options.allow_use_magnification_api()) {
|
||||||
|
|
|
@ -147,12 +147,18 @@ bool DxgiOutputDuplicator::ReleaseFrame() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DxgiOutputDuplicator::LogMouseCursor(
|
bool DxgiOutputDuplicator::ContainsMouseCursor(
|
||||||
const DXGI_OUTDUPL_FRAME_INFO& frame_info) {
|
const DXGI_OUTDUPL_FRAME_INFO& frame_info) {
|
||||||
|
// The DXGI_OUTDUPL_POINTER_POSITION structure that describes the most recent
|
||||||
|
// mouse position is only valid if the LastMouseUpdateTime member is a non-
|
||||||
|
// zero value.
|
||||||
|
if (frame_info.LastMouseUpdateTime.QuadPart == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
// Ignore cases when the mouse shape has changed and not the position.
|
// Ignore cases when the mouse shape has changed and not the position.
|
||||||
const bool new_pointer_shape = (frame_info.PointerShapeBufferSize != 0);
|
const bool new_pointer_shape = (frame_info.PointerShapeBufferSize != 0);
|
||||||
if (new_pointer_shape)
|
if (new_pointer_shape)
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
// The mouse cursor has moved and we can now query if the mouse pointer is
|
// The mouse cursor has moved and we can now query if the mouse pointer is
|
||||||
// drawn onto the desktop image or not to decide if we must draw the mouse
|
// drawn onto the desktop image or not to decide if we must draw the mouse
|
||||||
|
@ -163,12 +169,10 @@ void DxgiOutputDuplicator::LogMouseCursor(
|
||||||
// desktop image, the pointer position data that is reported by
|
// desktop image, the pointer position data that is reported by
|
||||||
// AcquireNextFrame indicates that a separate pointer isn’t visible, hence
|
// AcquireNextFrame indicates that a separate pointer isn’t visible, hence
|
||||||
// `frame_info.PointerPosition.Visible` is false.
|
// `frame_info.PointerPosition.Visible` is false.
|
||||||
// TODO(http://crbug.com/1421656): evaluate this UMA and possibly call
|
|
||||||
// set_may_contain_cursor(cursor_embedded_in_frame) on the captured frame to
|
|
||||||
// avoid rendering the cursor twice.
|
|
||||||
const bool cursor_embedded_in_frame = !frame_info.PointerPosition.Visible;
|
const bool cursor_embedded_in_frame = !frame_info.PointerPosition.Visible;
|
||||||
RTC_HISTOGRAM_BOOLEAN("WebRTC.DesktopCapture.Win.DirectXCursorEmbedded",
|
RTC_HISTOGRAM_BOOLEAN("WebRTC.DesktopCapture.Win.DirectXCursorEmbedded",
|
||||||
cursor_embedded_in_frame);
|
cursor_embedded_in_frame);
|
||||||
|
return cursor_embedded_in_frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DxgiOutputDuplicator::Duplicate(Context* context,
|
bool DxgiOutputDuplicator::Duplicate(Context* context,
|
||||||
|
@ -194,12 +198,7 @@ bool DxgiOutputDuplicator::Duplicate(Context* context,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The DXGI_OUTDUPL_POINTER_POSITION structure that describes the most recent
|
const bool cursor_embedded_in_frame = ContainsMouseCursor(frame_info);
|
||||||
// mouse position is only valid if the LastMouseUpdateTime member is a non-
|
|
||||||
// zero value.
|
|
||||||
if (frame_info.LastMouseUpdateTime.QuadPart != 0) {
|
|
||||||
LogMouseCursor(frame_info);
|
|
||||||
}
|
|
||||||
|
|
||||||
// We need to merge updated region with the one from context, but only spread
|
// We need to merge updated region with the one from context, but only spread
|
||||||
// updated region from current frame. So keeps a copy of updated region from
|
// updated region from current frame. So keeps a copy of updated region from
|
||||||
|
@ -239,6 +238,7 @@ bool DxgiOutputDuplicator::Duplicate(Context* context,
|
||||||
last_frame_offset_ = offset;
|
last_frame_offset_ = offset;
|
||||||
updated_region.Translate(offset.x(), offset.y());
|
updated_region.Translate(offset.x(), offset.y());
|
||||||
target->mutable_updated_region()->AddRegion(updated_region);
|
target->mutable_updated_region()->AddRegion(updated_region);
|
||||||
|
target->set_may_contain_cursor(cursor_embedded_in_frame);
|
||||||
num_frames_captured_++;
|
num_frames_captured_++;
|
||||||
return texture_->Release() && ReleaseFrame();
|
return texture_->Release() && ReleaseFrame();
|
||||||
}
|
}
|
||||||
|
@ -258,6 +258,7 @@ bool DxgiOutputDuplicator::Duplicate(Context* context,
|
||||||
}
|
}
|
||||||
updated_region.Translate(offset.x(), offset.y());
|
updated_region.Translate(offset.x(), offset.y());
|
||||||
target->mutable_updated_region()->AddRegion(updated_region);
|
target->mutable_updated_region()->AddRegion(updated_region);
|
||||||
|
target->set_may_contain_cursor(cursor_embedded_in_frame);
|
||||||
} else {
|
} else {
|
||||||
// If we were at the very first frame, and capturing failed, the
|
// If we were at the very first frame, and capturing failed, the
|
||||||
// context->updated_region should be kept unchanged for next attempt.
|
// context->updated_region should be kept unchanged for next attempt.
|
||||||
|
|
|
@ -97,10 +97,10 @@ class DxgiOutputDuplicator {
|
||||||
bool DoDetectUpdatedRegion(const DXGI_OUTDUPL_FRAME_INFO& frame_info,
|
bool DoDetectUpdatedRegion(const DXGI_OUTDUPL_FRAME_INFO& frame_info,
|
||||||
DesktopRegion* updated_region);
|
DesktopRegion* updated_region);
|
||||||
|
|
||||||
// Adds boolean WebRTC.DesktopCapture.Win.DirectXCursorEmbedded UMA stat which
|
// Returns true if the mouse cursor is embedded in the captured frame and
|
||||||
// contains true if the mouse cursor is embedded in the captured frame and
|
// false if not. Also logs the same boolean as
|
||||||
// false if not.
|
// WebRTC.DesktopCapture.Win.DirectXCursorEmbedded UMA.
|
||||||
void LogMouseCursor(const DXGI_OUTDUPL_FRAME_INFO& frame_info);
|
bool ContainsMouseCursor(const DXGI_OUTDUPL_FRAME_INFO& frame_info);
|
||||||
|
|
||||||
bool ReleaseFrame();
|
bool ReleaseFrame();
|
||||||
|
|
||||||
|
|
|
@ -104,6 +104,12 @@ int ScreenCapturerWinDirectx::GetIndexFromScreenId(
|
||||||
ScreenCapturerWinDirectx::ScreenCapturerWinDirectx()
|
ScreenCapturerWinDirectx::ScreenCapturerWinDirectx()
|
||||||
: controller_(DxgiDuplicatorController::Instance()) {}
|
: controller_(DxgiDuplicatorController::Instance()) {}
|
||||||
|
|
||||||
|
ScreenCapturerWinDirectx::ScreenCapturerWinDirectx(
|
||||||
|
const DesktopCaptureOptions& options)
|
||||||
|
: ScreenCapturerWinDirectx() {
|
||||||
|
options_ = options;
|
||||||
|
}
|
||||||
|
|
||||||
ScreenCapturerWinDirectx::~ScreenCapturerWinDirectx() = default;
|
ScreenCapturerWinDirectx::~ScreenCapturerWinDirectx() = default;
|
||||||
|
|
||||||
void ScreenCapturerWinDirectx::Start(Callback* callback) {
|
void ScreenCapturerWinDirectx::Start(Callback* callback) {
|
||||||
|
@ -191,6 +197,12 @@ void ScreenCapturerWinDirectx::CaptureFrame() {
|
||||||
capture_time_ms);
|
capture_time_ms);
|
||||||
frame->set_capture_time_ms(capture_time_ms);
|
frame->set_capture_time_ms(capture_time_ms);
|
||||||
frame->set_capturer_id(DesktopCapturerId::kScreenCapturerWinDirectx);
|
frame->set_capturer_id(DesktopCapturerId::kScreenCapturerWinDirectx);
|
||||||
|
// The DXGI Output Duplicator supports embedding the cursor but it is
|
||||||
|
// only supported on very few display adapters. This switch allows us
|
||||||
|
// to exclude an integrated cursor for all captured frames.
|
||||||
|
if (!options_.prefer_cursor_embedded()) {
|
||||||
|
frame->set_may_contain_cursor(false);
|
||||||
|
}
|
||||||
|
|
||||||
// TODO(julien.isorce): http://crbug.com/945468. Set the icc profile on
|
// TODO(julien.isorce): http://crbug.com/945468. Set the icc profile on
|
||||||
// the frame, see WindowCapturerMac::CaptureFrame.
|
// the frame, see WindowCapturerMac::CaptureFrame.
|
||||||
|
|
|
@ -70,7 +70,9 @@ class RTC_EXPORT ScreenCapturerWinDirectx : public DesktopCapturer {
|
||||||
static int GetIndexFromScreenId(ScreenId id,
|
static int GetIndexFromScreenId(ScreenId id,
|
||||||
const std::vector<std::string>& device_names);
|
const std::vector<std::string>& device_names);
|
||||||
|
|
||||||
explicit ScreenCapturerWinDirectx();
|
// This constructor is deprecated. Please don't use it in new implementations.
|
||||||
|
ScreenCapturerWinDirectx();
|
||||||
|
explicit ScreenCapturerWinDirectx(const DesktopCaptureOptions& options);
|
||||||
|
|
||||||
~ScreenCapturerWinDirectx() override;
|
~ScreenCapturerWinDirectx() override;
|
||||||
|
|
||||||
|
@ -87,6 +89,7 @@ class RTC_EXPORT ScreenCapturerWinDirectx : public DesktopCapturer {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const rtc::scoped_refptr<DxgiDuplicatorController> controller_;
|
const rtc::scoped_refptr<DxgiDuplicatorController> controller_;
|
||||||
|
DesktopCaptureOptions options_;
|
||||||
|
|
||||||
// The underlying DxgiDuplicators may retain a reference to the frames that
|
// The underlying DxgiDuplicators may retain a reference to the frames that
|
||||||
// we ask them to duplicate so that they can continue returning valid frames
|
// we ask them to duplicate so that they can continue returning valid frames
|
||||||
|
|
Loading…
Reference in a new issue