// Copyright 2013 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifdef UNSAFE_BUFFERS_BUILD // TODO(crbug.com/342213636): Remove this and spanify to fix the errors. #pragma allow_unsafe_buffers #endif #include "content/browser/media/capture/desktop_capture_device.h" #include <stddef.h> #include <stdint.h> #include <string.h> #include <algorithm> #include <limits> #include <memory> #include <string> #include <utility> #include <vector> #include "base/command_line.h" #include "base/functional/bind.h" #include "base/memory/raw_ptr.h" #include "base/strings/string_number_conversions.h" #include "base/synchronization/waitable_event.h" #include "base/task/single_thread_task_runner.h" #include "base/test/metrics/histogram_tester.h" #include "base/test/test_mock_time_task_runner.h" #include "base/test/test_timeouts.h" #include "base/time/tick_clock.h" #include "base/time/time.h" #include "build/build_config.h" #include "media/capture/video/mock_video_capture_device_client.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/webrtc/modules/desktop_capture/desktop_capture_options.h" #include "third_party/webrtc/modules/desktop_capture/desktop_capturer.h" #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" #include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h" #include "ui/base/ozone_buildflags.h" #if BUILDFLAG(IS_OZONE) #include "ui/ozone/public/ozone_platform.h" #endif // BUILDFLAG(IS_OZONE) _; AnyNumber; DoAll; Expectation; Invoke; InvokeWithoutArgs; NiceMock; SaveArg; WithArg; namespace content { namespace { const int kTestFrameWidth1 = …; const int kTestFrameHeight1 = …; const int kTestFrameWidth2 = …; const int kTestFrameHeight2 = …; const int kTestFrameWidth3 = …; const int kTestFrameHeight3 = …; const int kFrameRate = …; constexpr base::TimeDelta kVirtualTestDurationSeconds = …; // The value of the padding bytes in unpacked frames. const uint8_t kFramePaddingValue = …; // Use a special value for frame pixels to tell pixel bytes apart from the // padding bytes in the unpacked frame test. const uint8_t kFakePixelValue = …; // Use a special value for the first pixel to verify the result in the inverted // frame test. const uint8_t kFakePixelValueFirst = …; const char kFrameIsRefresh[] = …; // Creates a DesktopFrame that has the first pixel bytes set to // kFakePixelValueFirst, and the rest of the bytes set to kFakePixelValue, for // UnpackedFrame and InvertedFrame verification. // The complete frame is marked as updated by default independently of size, // position and content to ensure that the frame is not marked as "not changed" // by the DesktopCaptureDevice since that would prevent the frame from being // forwarded to the client. // See DesktopCapturerDifferWrapperTest for a more realistic example of how the // content of frames should affect the updated region part of each frame. std::unique_ptr<webrtc::BasicDesktopFrame> CreateBasicFrame( const webrtc::DesktopSize& size) { … } // DesktopFrame wrapper that flips wrapped frame upside down by inverting // stride. class InvertedDesktopFrame : public webrtc::DesktopFrame { … }; // DesktopFrame wrapper that copies the input frame and doubles the stride. class UnpackedDesktopFrame : public webrtc::DesktopFrame { … }; // TODO(sergeyu): Move this to a separate file where it can be reused. class FakeScreenCapturer : public webrtc::DesktopCapturer { … }; // Helper used to check that only two specific frame sizes are delivered to the // OnIncomingCapturedData() callback. class FormatChecker { … }; } // namespace class DesktopCaptureDeviceTest : public testing::Test { … }; // Capturer implementation for Fuchsia is not fully functional. #if !BUILDFLAG(IS_FUCHSIA) TEST_F(DesktopCaptureDeviceTest, Capture) { … } #endif // !BUILDFLAG(IS_FUCHSIA) // Test that screen capturer behaves correctly if the source frame size changes // but the caller cannot cope with variable resolution output. TEST_F(DesktopCaptureDeviceTest, ScreenResolutionChangeConstantResolution) { … } // Test that screen capturer behaves correctly if the source frame size changes, // where the video frames sent the the client vary in resolution but maintain // the same aspect ratio. TEST_F(DesktopCaptureDeviceTest, ScreenResolutionChangeFixedAspectRatio) { … } // Test that screen capturer behaves correctly if the source frame size changes // and the caller can cope with variable resolution output. TEST_F(DesktopCaptureDeviceTest, ScreenResolutionChangeVariableResolution) { … } // This test verifies that an unpacked frame is converted to a packed frame. TEST_F(DesktopCaptureDeviceTest, UnpackedFrame) { … } // The test verifies that a bottom-to-top frame is converted to top-to-bottom. TEST_F(DesktopCaptureDeviceTest, InvertedFrame) { … } // This test verifies that calling RequestRefreshFrame() on the screen capturer // before AllocateAndStart() does not provide any refresh frame. TEST_F(DesktopCaptureDeviceTest, RequestRefreshFrameBeforeStart) { … } // This test verifies that calling RequestRefreshFrame() on the screen capturer // after StopAndDeAllocate() does not result in any refresh frame even if one // frame has been captured before StopAndDeAllocate() was called. TEST_F(DesktopCaptureDeviceTest, RequestRefreshFrameAfterStop) { … } // Verify that calling RequestRefreshFrame() results in an extra frame being // captured and sent to the client. The content should not be the same as for // the first default frame. TEST_F(DesktopCaptureDeviceTest, RequestRefreshFrameSendsExtraFrame) { … } // Verifies that only captured frames which contains updated regions are // forwarded to the client. In reality such a "no change" event should be an // effect of static size, content and position of the frame, but to allow for a // less complex verification, frames are here periodically marked as // "not updated" independently of its own content or the content of the previous // frame. TEST_F(DesktopCaptureDeviceTest, OnlyCapturedFramesWithUpdatedRegionsAreForwardedToTheClient) { … } // Verifies that RequestRefreshFrame() forces a new captured frame even when the // content has not changed since the last frame. This is to ensure that the // client gets a new frame when explicitly asking for it. TEST_F(DesktopCaptureDeviceTest, RequestRefreshFrameSendsFrameEvenIfNoRegionsAreUpdated) { … } class DesktopCaptureDeviceThrottledTest : public DesktopCaptureDeviceTest { … }; // The test verifies that the capture pipeline is throttled as defined with // kDefaultMaximumCpuConsumptionPercentage. TEST_F(DesktopCaptureDeviceThrottledTest, ThrottledOn) { … } // Same tests as above but runs callbacks asynchronously to verify that that // doesn't disrupt the throttling machinery. TEST_F(DesktopCaptureDeviceThrottledTest, ThrottledOn_Async) { … } } // namespace content