chromium/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl_unittest.cc

// Copyright 2017 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/40285824): Remove this and convert code to safer constructs.
#pragma allow_unsafe_buffers
#endif

#include "components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.h"

#include <map>
#include <optional>
#include <string>
#include <tuple>
#include <utility>
#include <vector>

#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/shared_memory_mapping.h"
#include "base/notimplemented.h"
#include "base/run_loop.h"
#include "base/test/bind.h"
#include "base/test/test_mock_time_task_runner.h"
#include "base/time/time.h"
#include "base/token.h"
#include "cc/base/math_util.h"
#include "components/viz/common/frame_sinks/begin_frame_args.h"
#include "components/viz/common/frame_sinks/copy_output_request.h"
#include "components/viz/common/frame_sinks/copy_output_result.h"
#include "components/viz/common/frame_sinks/copy_output_util.h"
#include "components/viz/common/resources/shared_image_format_utils.h"
#include "components/viz/common/surfaces/subtree_capture_id.h"
#include "components/viz/common/surfaces/video_capture_target.h"
#include "components/viz/service/frame_sinks/gmb_video_frame_pool_context_provider.h"
#include "components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_manager.h"
#include "components/viz/test/test_context_provider.h"
#include "gpu/command_buffer/client/client_shared_image.h"
#include "media/base/format_utils.h"
#include "media/base/limits.h"
#include "media/base/test_helpers.h"
#include "media/base/video_util.h"
#include "media/capture/mojom/video_capture_buffer.mojom.h"
#include "media/capture/mojom/video_capture_types.mojom.h"
#include "media/video/fake_gpu_memory_buffer.h"
#include "media/video/renderable_gpu_memory_buffer_video_frame_pool.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "services/viz/privileged/mojom/compositing/frame_sink_video_capture.mojom.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/gfx/color_space.h"
#include "ui/gfx/color_utils.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"

VideoCaptureOracle;
VideoFrame;
VideoFrameMetadata;

_;
InvokeWithoutArgs;
NiceMock;
Return;

namespace viz {
namespace {

bool AlignsWithI420SubsamplingBoundaries(const gfx::Rect& update_rect) {}

// Returns true if |frame|'s device scale factor, page scale factor and root
// scroll offset are equal to the expected values.
bool CompareVarsInCompositorFrameMetadata(
    const VideoFrame& frame,
    float device_scale_factor,
    float page_scale_factor,
    const gfx::PointF& root_scroll_offset) {}

// The following functions, CopyOutputRequestFormatToVideoPixelFormat and
// GetColorSpaceForPixelFormat only deal with pixel_format_ which is the user
// requested format, so we only have to care media::PIXEL_FORMAT_ARGB, and
// ResultFormat::RGBA. GetBufferFormatForVideoPixelFormat and
// GetBufferSizeInPixelsForVideoPixelFormat needs to deal with the GMB and frame
// result passed from the capture callback, it could be RGBA/BGRA depends on
// which platform we are, so we have to handle both media::PIXEL_FORMAT_ARGB
// and media::PIXEL_FORMAT_ABGR.

media::VideoPixelFormat CopyOutputRequestFormatToVideoPixelFormat(
    CopyOutputRequest::ResultFormat format) {}

gfx::ColorSpace GetColorSpaceForPixelFormat(media::VideoPixelFormat format) {}

gfx::Size GetBufferSizeInPixelsForVideoPixelFormat(
    media::VideoPixelFormat format,
    const gfx::Size& coded_size) {}

// Dummy frame sink ID.
const VideoCaptureTarget kVideoCaptureTarget(FrameSinkId(1, 1));

// The compositor frame interval.
constexpr auto kVsyncInterval =;

const struct SizeSet {} kSizeSets[5] =;

constexpr float kDefaultDeviceScaleFactor =;
constexpr float kDefaultPageScaleFactor =;
constexpr gfx::PointF kDefaultRootScrollOffset =;

struct YUVColor {};

YUVColor RGBToYUV(uint32_t argb) {}

// Forces any pending Mojo method calls between the capturer and consumer to be
// made.
void PropagateMojoTasks(
    scoped_refptr<base::TestMockTimeTaskRunner> runner = nullptr) {}

class MockFrameSinkManager : public FrameSinkVideoCapturerManager {};

class MockConsumer : public mojom::FrameSinkVideoConsumer {};

class FakeGpuCopyResult : public CopyOutputResult {};

class SolidColorRGBAResult : public CopyOutputResult {};

class SolidColorI420Result : public CopyOutputResult {};

class FakeCapturableFrameSink : public CapturableFrameSink {};

class InstrumentedVideoCaptureOracle : public media::VideoCaptureOracle {};

namespace {
bool IsLetterboxedI420Plane(int plane,
                            uint8_t component,
                            gfx::Rect content_rect,
                            const VideoFrame& frame,
                            testing::MatchResultListener* result_listener) {}

bool IsLetterboxedRGBA(SkColor color,
                       gfx::Rect content_rect,
                       const VideoFrame& frame,
                       testing::MatchResultListener* result_listener) {}
}  // namespace

// Matcher that returns true if the content region of a letterboxed VideoFrame
// is filled with the given color, and black everywhere else.
MATCHER_P3(IsLetterboxedFrame, color, content_rect, pixel_format, "") {}

class TestVideoCaptureOverlay : public VideoCaptureOverlay {};

class TestGmbVideoFramePoolContext
    : public media::RenderableGpuMemoryBufferVideoFramePool::Context {};

class TestGmbVideoFramePoolContextProvider
    : public GmbVideoFramePoolContextProvider {};

}  // namespace

class FrameSinkVideoCapturerTest
    : public testing::Test,
      public testing::WithParamInterface<
          std::tuple<mojom::BufferFormatPreference, media::VideoPixelFormat>> {};

// Tests that the capturer attaches to a frame sink immediately, in the case
// where the frame sink was already known by the manager.
TEST_P(FrameSinkVideoCapturerTest, ResolvesTargetImmediately) {}

// Tests that the capturer attaches to a frame sink later, in the case where the
// frame sink becomes known to the manager at some later point.
TEST_P(FrameSinkVideoCapturerTest, ResolvesTargetLater) {}

// Tests that no initial frame is sent after Start() is called until after the
// target has been resolved.
TEST_P(FrameSinkVideoCapturerTest, PostponesCaptureWithoutATarget) {}

// An end-to-end pipeline test where compositor updates trigger the capturer to
// make copy requests, and a stream of video frames is delivered to the
// consumer.
TEST_P(FrameSinkVideoCapturerTest, CapturesCompositedFrames) {}

// Tests that frame capturing halts when too many frames are allocated, whether
// that is because there are too many copy requests in-flight or because the
// consumer has not finished consuming frames fast enough.
TEST_P(FrameSinkVideoCapturerTest, HaltsWhenPoolIsFull) {}

// Tests that copy requests completed out-of-order are accounted for by the
// capturer, with results delivered to the consumer in-order.
TEST_P(FrameSinkVideoCapturerTest, DeliversFramesInOrder) {}

// Tests that in-flight copy requests are canceled when the capturer is
// stopped. When it is started again with a new consumer, only the results from
// newer copy requests should appear in video frames delivered to the consumer.
TEST_P(FrameSinkVideoCapturerTest, CancelsInFlightCapturesOnStop) {}

// Tests that refresh requests ultimately result in a frame being delivered to
// the consumer.
TEST_P(FrameSinkVideoCapturerTest, EventuallySendsARefreshFrame) {}

// Tests that refresh demands result in a frame being delivered to
// the consumer in a timely fashion.
TEST_P(FrameSinkVideoCapturerTest, RefreshDemandsAreProperlyHandled) {}

// Tests that the capturer honors requested refresh frames (see
// crbug.com/1320798)
TEST_P(FrameSinkVideoCapturerTest, HonorsRequestRefreshFrame) {}

// Tests that full capture happens on capture resolution change due to oracle,
// but only once and resurrected frames are used after that.
TEST_P(FrameSinkVideoCapturerTest,
       ResurrectsFramesForChangingCaptureResolution) {}

// Tests that CompositorFrameMetadata variables (|device_scale_factor|,
// |page_scale_factor| and |root_scroll_offset|) are sent along with each frame,
// and refreshes cause variables of the cached CompositorFrameMetadata
// (|last_frame_metadata|) to be used.
TEST_P(FrameSinkVideoCapturerTest, CompositorFrameMetadataReachesConsumer) {}

// Tests that frame metadata CAPTURE_COUNTER and CAPTURE_UPDATE_RECT are sent to
// the consumer as part of each frame delivery.
TEST_P(FrameSinkVideoCapturerTest, DeliversUpdateRectAndCaptureCounter) {}

// Tests that when captured frames being dropped before delivery, the
// CAPTURE_COUNTER metadata value sent to the consumer reflects the frame drops
// indicating that CAPTURE_UPDATE_RECT must be ignored.
TEST_P(FrameSinkVideoCapturerTest, CaptureCounterSkipsWhenFramesAreDropped) {}

TEST_P(FrameSinkVideoCapturerTest, ClientCaptureStartsAndStops) {}

TEST_P(FrameSinkVideoCapturerTest, RegionCaptureCropId) {}

TEST_P(FrameSinkVideoCapturerTest,
       RegionCaptureTargetIsSetLaterWhenNotInitiallyAvailable) {}

// Tests that frames can be successfully delivered after one is dropped due to
// having a zero-sized capture region.
TEST_P(FrameSinkVideoCapturerTest, HandlesFrameWithEmptyRegion) {}

// Tests that frames can be successfully delivered after one is dropped due to
// having a capture region that does not intersect with the compositor frame. In
// the past, it was possible for a dropped frame to cause the delivery queue to
// no longer be emptied. See https://crbug.com/1300742.
TEST_P(FrameSinkVideoCapturerTest, HandlesFrameWithRegionCroppedToZero) {}

TEST_P(FrameSinkVideoCapturerTest, ProperlyHandlesCaptureSizeForOverlay) {}

TEST_P(FrameSinkVideoCapturerTest, HandlesSubtreeCaptureId) {}

TEST_P(FrameSinkVideoCapturerTest, ProperlyHandlesSubtreeSizeForOverlay) {}

TEST_P(FrameSinkVideoCapturerTest, HandlesNullSubTargetPtrCorrectly) {}

INSTANTIATE_TEST_SUITE_P();

}  // namespace viz