diff --git a/webrtc/modules/desktop_capture/win/dxgi_output_duplicator.cc b/webrtc/modules/desktop_capture/win/dxgi_output_duplicator.cc index 04f466455f..fb8dacb720 100644 --- a/webrtc/modules/desktop_capture/win/dxgi_output_duplicator.cc +++ b/webrtc/modules/desktop_capture/win/dxgi_output_duplicator.cc @@ -57,12 +57,6 @@ Rotation DxgiRotationToRotation(DXGI_MODE_ROTATION rotation) { return Rotation::CLOCK_WISE_0; } -// Translates |rect| with the reverse of |offset| -DesktopRect ReverseTranslate(DesktopRect rect, DesktopVector offset) { - rect.Translate(-offset.x(), -offset.y()); - return rect; -} - } // namespace DxgiOutputDuplicator::DxgiOutputDuplicator(const D3dDevice& device, @@ -132,8 +126,7 @@ bool DxgiOutputDuplicator::DuplicateOutput() { } rotation_ = DxgiRotationToRotation(desc_.Rotation); - unrotated_size_ = - RotateSize(desktop_rect_.size(), ReverseRotation(rotation_)); + unrotated_size_ = RotateSize(desktop_size(), ReverseRotation(rotation_)); return true; } @@ -157,7 +150,7 @@ bool DxgiOutputDuplicator::Duplicate(Context* context, RTC_DCHECK(texture_); RTC_DCHECK(target); if (!DesktopRect::MakeSize(target->size()) - .ContainsRect(TranslatedDesktopRect(offset))) { + .ContainsRect(GetTranslatedDesktopRect(offset))) { // target size is not large enough to cover current output region. return false; } @@ -175,37 +168,43 @@ bool DxgiOutputDuplicator::Duplicate(Context* context, // 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 - // context here. + // context here. The |updated_region| always starts from (0, 0). DesktopRegion updated_region; updated_region.Swap(&context->updated_region); if (error.Error() == S_OK && frame_info.AccumulatedFrames > 0 && resource) { - DetectUpdatedRegion(frame_info, offset, &context->updated_region); + DetectUpdatedRegion(frame_info, &context->updated_region); + SpreadContextChange(context); if (!texture_->CopyFrom(frame_info, resource.Get())) { return false; } - SpreadContextChange(context); updated_region.AddRegion(context->updated_region); + // TODO(zijiehe): Figure out why clearing context->updated_region() here + // triggers screen flickering? const DesktopFrame& source = texture_->AsDesktopFrame(); if (rotation_ != Rotation::CLOCK_WISE_0) { for (DesktopRegion::Iterator it(updated_region); !it.IsAtEnd(); it.Advance()) { - const DesktopRect source_rect = - RotateRect(ReverseTranslate(it.rect(), offset), - desktop_rect().size(), ReverseRotation(rotation_)); + // The |updated_region| returned by Windows is rotated, but the |source| + // frame is not. So we need to rotate it reversely. + const DesktopRect source_rect = RotateRect( + it.rect(), desktop_size(), ReverseRotation(rotation_)); RotateDesktopFrame(source, source_rect, rotation_, offset, target); } } else { for (DesktopRegion::Iterator it(updated_region); !it.IsAtEnd(); it.Advance()) { - target->CopyPixelsFrom( - source, ReverseTranslate(it.rect(), offset).top_left(), it.rect()); + // The DesktopRect in |target|, starts from offset. + DesktopRect dest_rect = it.rect(); + dest_rect.Translate(offset); + target->CopyPixelsFrom(source, it.rect().top_left(), dest_rect); } } last_frame_ = target->Share(); last_frame_offset_ = offset; + updated_region.Translate(offset.x(), offset.y()); target->mutable_updated_region()->AddRegion(updated_region); num_frames_captured_++; return texture_->Release() && ReleaseFrame(); @@ -216,8 +215,15 @@ bool DxgiOutputDuplicator::Duplicate(Context* context, // export last frame to the target. for (DesktopRegion::Iterator it(updated_region); !it.IsAtEnd(); it.Advance()) { - target->CopyPixelsFrom(*last_frame_, it.rect().top_left(), it.rect()); + // The DesktopRect in |source|, starts from last_frame_offset_. + DesktopRect source_rect = it.rect(); + // The DesktopRect in |target|, starts from offset. + DesktopRect target_rect = source_rect; + source_rect.Translate(last_frame_offset_); + target_rect.Translate(offset); + target->CopyPixelsFrom(*last_frame_, source_rect.top_left(), target_rect); } + updated_region.Translate(offset.x(), offset.y()); target->mutable_updated_region()->AddRegion(updated_region); } else { // If we were at the very first frame, and capturing failed, the @@ -229,23 +235,26 @@ bool DxgiOutputDuplicator::Duplicate(Context* context, return error.Error() == DXGI_ERROR_WAIT_TIMEOUT || ReleaseFrame(); } -DesktopRect DxgiOutputDuplicator::TranslatedDesktopRect(DesktopVector offset) { - DesktopRect result(DesktopRect::MakeSize(desktop_rect_.size())); +DesktopRect DxgiOutputDuplicator::GetTranslatedDesktopRect( + DesktopVector offset) const { + DesktopRect result(DesktopRect::MakeSize(desktop_size())); result.Translate(offset); return result; } +DesktopRect DxgiOutputDuplicator::GetUntranslatedDesktopRect() const { + return DesktopRect::MakeSize(desktop_size()); +} + void DxgiOutputDuplicator::DetectUpdatedRegion( const DXGI_OUTDUPL_FRAME_INFO& frame_info, - DesktopVector offset, DesktopRegion* updated_region) { if (DoDetectUpdatedRegion(frame_info, updated_region)) { - updated_region->Translate(offset.x(), offset.y()); // Make sure even a region returned by Windows API is out of the scope of // desktop_rect_, we still won't export it to the target DesktopFrame. - updated_region->IntersectWith(TranslatedDesktopRect(offset)); + updated_region->IntersectWith(GetUntranslatedDesktopRect()); } else { - updated_region->SetRect(TranslatedDesktopRect(offset)); + updated_region->SetRect(GetUntranslatedDesktopRect()); } } @@ -340,7 +349,7 @@ bool DxgiOutputDuplicator::DoDetectUpdatedRegion( void DxgiOutputDuplicator::Setup(Context* context) { RTC_DCHECK(context->updated_region.is_empty()); // Always copy entire monitor during the first Duplicate() function call. - context->updated_region.AddRect(desktop_rect_); + context->updated_region.AddRect(GetUntranslatedDesktopRect()); RTC_DCHECK(std::find(contexts_.begin(), contexts_.end(), context) == contexts_.end()); contexts_.push_back(context); @@ -361,6 +370,10 @@ void DxgiOutputDuplicator::SpreadContextChange(const Context* const source) { } } +DesktopSize DxgiOutputDuplicator::desktop_size() const { + return desktop_rect_.size(); +} + int64_t DxgiOutputDuplicator::num_frames_captured() const { #if !defined(NDEBUG) RTC_DCHECK_EQ(!!last_frame_, num_frames_captured_ > 0); diff --git a/webrtc/modules/desktop_capture/win/dxgi_output_duplicator.h b/webrtc/modules/desktop_capture/win/dxgi_output_duplicator.h index 2ac0a75eab..2e85bf7a08 100644 --- a/webrtc/modules/desktop_capture/win/dxgi_output_duplicator.h +++ b/webrtc/modules/desktop_capture/win/dxgi_output_duplicator.h @@ -36,8 +36,8 @@ class DxgiOutputDuplicator { public: struct Context { // The updated region DxgiOutputDuplicator::DetectUpdatedRegion() output - // during last Duplicate() function call. It's a DesktopRegion translated by - // offset of each DxgiOutputDuplicator instance. + // during last Duplicate() function call. It's always relative to the + // (0, 0). DesktopRegion updated_region; }; @@ -80,11 +80,9 @@ class DxgiOutputDuplicator { int64_t num_frames_captured() const; private: - // Detects updated region translated by offset from IDXGIOutput1. This - // function will set the |updated_region| as entire DesktopRect starts from - // offset if it failed to execute Windows APIs. + // Calls DoDetectUpdatedRegion(). If it fails, this function sets the + // |updated_region| as entire UntranslatedDesktopRect(). void DetectUpdatedRegion(const DXGI_OUTDUPL_FRAME_INFO& frame_info, - DesktopVector offset, DesktopRegion* updated_region); // Returns untranslated updated region, which are directly returned by Windows @@ -98,14 +96,21 @@ class DxgiOutputDuplicator { // Returns false if system does not support IDXGIOutputDuplication. bool DuplicateOutput(); - // Returns a DesktopRect with the same size of desktop_size_, but translated + // Returns a DesktopRect with the same size of desktop_size(), but translated // by offset. - DesktopRect TranslatedDesktopRect(DesktopVector 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 DesktopRect desktop_rect_;