Index: webrtc/modules/desktop_capture/screen_capturer_unittest.cc |
diff --git a/webrtc/modules/desktop_capture/screen_capturer_unittest.cc b/webrtc/modules/desktop_capture/screen_capturer_unittest.cc |
index 6d2c0eb0658221f98ebb4f34d18a22076de8521a..66f1d7e52afbb5641dc7e29af0ba3f265c912561 100644 |
--- a/webrtc/modules/desktop_capture/screen_capturer_unittest.cc |
+++ b/webrtc/modules/desktop_capture/screen_capturer_unittest.cc |
@@ -8,8 +8,12 @@ |
* be found in the AUTHORS file in the root of the source tree. |
*/ |
+#include <string.h> |
+ |
+#include <algorithm> |
#include <memory> |
#include <utility> |
+#include <vector> |
#include "webrtc/modules/desktop_capture/screen_capturer.h" |
@@ -21,6 +25,8 @@ |
#include "webrtc/modules/desktop_capture/desktop_frame.h" |
#include "webrtc/modules/desktop_capture/desktop_region.h" |
#include "webrtc/modules/desktop_capture/screen_capturer_mock_objects.h" |
+#include "webrtc/modules/desktop_capture/screen_painter.h" |
+#include "webrtc/system_wrappers/include/sleep.h" |
#if defined(WEBRTC_WIN) |
#include "webrtc/modules/desktop_capture/win/screen_capturer_win_directx.h" |
@@ -34,6 +40,109 @@ const int kTestSharedMemoryId = 123; |
namespace webrtc { |
+namespace { |
+ |
+ACTION_P(SaveUniquePtrArg, dest) { |
+ *dest = std::move(*arg1); |
+} |
+ |
+// Expects |capturer| to successfully capture a frame, and returns it. |
+std::unique_ptr<DesktopFrame> CaptureFrame( |
+ ScreenCapturer* capturer, |
+ MockScreenCapturerCallback* callback) { |
+ std::unique_ptr<DesktopFrame> frame; |
+ EXPECT_CALL(*callback, |
+ OnCaptureResultPtr(DesktopCapturer::Result::SUCCESS, _)) |
+ .WillOnce(SaveUniquePtrArg(&frame)); |
+ capturer->Capture(DesktopRegion()); |
+ EXPECT_TRUE(frame); |
+ return frame; |
+} |
+ |
+// Expects color in |rect| of |frame| is |color|. |
+void ExpectPixelsAreColoredBy(const DesktopFrame& frame, |
+ DesktopRect rect, |
+ ScreenPainter::Color color) { |
+ uint8_t* row = frame.GetFrameDataAtPos(rect.top_left()); |
+ for (int i = 0; i < rect.height(); i++) { |
+ uint8_t* column = row; |
+ for (int j = 0; j < rect.width(); j++) { |
+ ASSERT_EQ(color, column); |
+ column += DesktopFrame::kBytesPerPixel; |
+ } |
+ row += frame.stride(); |
+ } |
+} |
+ |
+// Finds the visible region and offset of ScreenDrawer drawable region in |
+// ScreenCapturer reachable area. The top left of the DesktopRect returned is |
+// the offset of ScreenDrawer drawable region, which maps to (0, 0) of |
+// ScreenDrawer::DrawableRegion(). The size of the DesktopRect indicates the |
+// size of visible region. So to ensure rendering a shape in the visible area of |
+// ScreenCapturer, you can randomize points within the DesktopRect::size() and |
+// use DesktopRect::Translate(-top_left().left(), -top_left().top()) or |
+// DesktopVector::subtract(top_left()) to translate into the coordinate of |
+// ScreenDrawer. This function returns an empty DesktopRect if calibration |
+// failed. |
+DesktopRect CalibrateScreenDrawerPosition( |
+ ScreenPainter* painter, |
+ ScreenCapturer* capturer, |
+ MockScreenCapturerCallback* callback) { |
+ const int kAnchorSize = 20; |
+ if (painter->DrawableRegion().width() < kAnchorSize || |
+ painter->DrawableRegion().height() < 1) { |
+ LOG(LS_WARNING) << "DrawableRegion is too small for calibration."; |
+ return DesktopRect(); |
+ } |
+ std::vector<ScreenPainter::Color> anchor_colors; |
+ painter->Clear(); |
+ painter->DrawColorfulHorizontalLine(DesktopVector(), kAnchorSize, |
+ &anchor_colors); |
+ // We do not need a very accurate positiin, so reduce the sample rate by |
+ // 1/256. This usually does not make too much difference. |
+ for (int i = std::max(painter->DrawableRegion().width(), |
+ painter->DrawableRegion().height()) - |
+ 1; |
+ i > 0; i -= 16) { |
+ for (int j = i; j < std::max(painter->DrawableRegion().width(), |
+ painter->DrawableRegion().height()) - |
+ 1; |
+ j += anchor_colors.size() * 16) { |
+ painter->DrawColorfulHorizontalLine(DesktopVector(j, i), anchor_colors); |
+ } |
+ } |
+ painter->WaitForPendingPaintings(); |
+ |
+ std::unique_ptr<DesktopFrame> frame = CaptureFrame(capturer, callback); |
+ painter->Clear(); |
+ if (!frame) { |
+ return DesktopRect(); |
+ } |
+ |
+ const uint8_t* const end = |
+ frame->data() + frame->stride() * frame->size().height() - |
+ anchor_colors.size() * sizeof(ScreenPainter::Color); |
+ DesktopVector top_left(-1, -1); |
+ DesktopVector right_bottom; |
+ for (const uint8_t* i = frame->data(); i < end; |
+ i += DesktopFrame::kBytesPerPixel) { |
+ if (ScreenPainter::Color::PixelsMatch(anchor_colors, i)) { |
+ right_bottom = frame->GetPosAtFrameData(i); |
+ if (top_left.x() < 0 && top_left.y() < 0) { |
+ top_left = right_bottom; |
+ } |
+ } |
+ } |
+ |
+ if (top_left.x() >= 0 && top_left.y() >= 0) { |
+ return DesktopRect::MakeLTRB(top_left, right_bottom); |
+ } |
+ |
+ return DesktopRect(); |
+} |
+ |
+} // namespace |
+ |
class ScreenCapturerTest : public testing::Test { |
public: |
void SetUp() override { |
@@ -74,10 +183,6 @@ class FakeSharedMemoryFactory : public SharedMemoryFactory { |
RTC_DISALLOW_COPY_AND_ASSIGN(FakeSharedMemoryFactory); |
}; |
-ACTION_P(SaveUniquePtrArg, dest) { |
- *dest = std::move(*arg1); |
-} |
- |
TEST_F(ScreenCapturerTest, GetScreenListAndSelectScreen) { |
webrtc::ScreenCapturer::ScreenList screens; |
EXPECT_TRUE(capturer_->GetScreenList(&screens)); |
@@ -117,6 +222,44 @@ TEST_F(ScreenCapturerTest, Capture) { |
EXPECT_TRUE(it.IsAtEnd()); |
} |
+TEST_F(ScreenCapturerTest, CaptureUpdatedRegion) { |
+ std::unique_ptr<ScreenPainter> painter = ScreenPainter::Create(); |
+ if (!painter || painter->DrawableRegion().is_empty()) { |
+ LOG(LS_WARNING) << "No ScreenPainter implementation for current platform."; |
+ return; |
+ } |
+ capturer_->Start(&callback_); |
+ |
+ const DesktopRect anchor = |
+ CalibrateScreenDrawerPosition(painter.get(), capturer_.get(), &callback_); |
+ if (anchor.is_empty()) { |
+ LOG(LS_WARNING) << "Failed to calibrate ScreenDrawer, it usually means " |
+ "ScreenDrawer cannot draw in ScreenCapturer reachable " |
+ "area."; |
+ return; |
+ } |
+ |
+ painter->Clear(); |
+ ScreenPainter::Color color; |
+ DesktopRect rect; |
+ painter->DrawRandomColorRectangleIn(anchor.size(), &color, &rect); |
+ rect.Translate(anchor.top_left()); |
+ painter->WaitForPendingPaintings(); |
+ std::unique_ptr<DesktopFrame> frame = |
+ CaptureFrame(capturer_.get(), &callback_); |
+ if (!frame) { |
+ return; |
+ } |
+ |
+ // updated_region() should cover the painted area. |
+ DesktopRegion updated_region(frame->updated_region()); |
+ updated_region.IntersectWith(rect); |
+ ASSERT_TRUE(updated_region.Equals(DesktopRegion(rect))); |
+ |
+ // Color in the |rect| should be |color|. |
+ ExpectPixelsAreColoredBy(*frame, rect, color); |
+} |
+ |
#if defined(WEBRTC_WIN) |
TEST_F(ScreenCapturerTest, UseSharedBuffers) { |