chromium/third_party/blink/renderer/platform/video_capture/video_capture_impl_test.cc

// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "third_party/blink/renderer/platform/video_capture/video_capture_impl.h"

#include <stddef.h>

#include <memory>
#include <utility>

#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/memory/read_only_shared_memory_region.h"
#include "base/memory/unsafe_shared_memory_region.h"
#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "base/token.h"
#include "build/build_config.h"
#include "gpu/command_buffer/common/capabilities.h"
#include "gpu/command_buffer/common/shared_image_capabilities.h"
#include "media/capture/mojom/video_capture.mojom-blink.h"
#include "media/capture/mojom/video_capture_buffer.mojom-blink.h"
#include "media/capture/mojom/video_capture_types.mojom-blink.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/platform/browser_interface_broker_proxy.h"
#include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h"
#include "third_party/blink/renderer/platform/video_capture/gpu_memory_buffer_test_support.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"

_;
DoAll;
InSequence;
Invoke;
InvokeWithoutArgs;
Mock;
SaveArg;
WithArgs;

namespace blink {

void RunEmptyFormatsCallback(
    media::mojom::blink::VideoCaptureHost::GetDeviceSupportedFormatsCallback&
        callback) {}

ACTION(DoNothing) {}

// Mock implementation of the Mojo Host service.
class MockMojoVideoCaptureHost : public media::mojom::blink::VideoCaptureHost {};

// This class encapsulates a VideoCaptureImpl under test and the necessary
// accessory classes, namely:
// - a MockMojoVideoCaptureHost, mimicking the RendererHost;
// - a few callbacks that are bound when calling operations of VideoCaptureImpl
//  and on which we set expectations.
class VideoCaptureImplTest : public ::testing::Test {};

TEST_F(VideoCaptureImplTest, Simple) {}

TEST_F(VideoCaptureImplTest, TwoClientsInSequence) {}

TEST_F(VideoCaptureImplTest, LargeAndSmall) {}

TEST_F(VideoCaptureImplTest, SmallAndLarge) {}

// Checks that a request to GetDeviceSupportedFormats() ends up eventually in
// the provided callback.
TEST_F(VideoCaptureImplTest, GetDeviceFormats) {}

// Checks that two requests to GetDeviceSupportedFormats() end up eventually
// calling the provided callbacks.
TEST_F(VideoCaptureImplTest, TwoClientsGetDeviceFormats) {}

// Checks that a request to GetDeviceFormatsInUse() ends up eventually in the
// provided callback.
TEST_F(VideoCaptureImplTest, GetDeviceFormatsInUse) {}

TEST_F(VideoCaptureImplTest, BufferReceived) {}

TEST_F(VideoCaptureImplTest, BufferReceived_ReadOnlyShmemRegion) {}

TEST_F(VideoCaptureImplTest, BufferReceived_GpuMemoryBufferHandle) {}

TEST_F(VideoCaptureImplTest, OnFrameDropped) {}

TEST_F(VideoCaptureImplTest, BufferReceivedAfterStop) {}

TEST_F(VideoCaptureImplTest, BufferReceivedAfterStop_ReadOnlyShmemRegion) {}

TEST_F(VideoCaptureImplTest, BufferReceivedAfterStop_GpuMemoryBufferHandle) {}

TEST_F(VideoCaptureImplTest, AlreadyStarted) {}

TEST_F(VideoCaptureImplTest, EndedBeforeStop) {}

TEST_F(VideoCaptureImplTest, ErrorBeforeStop) {}

TEST_F(VideoCaptureImplTest, WinSystemPermissionsErrorUpdatesCorrectState) {}

TEST_F(VideoCaptureImplTest, BufferReceivedBeforeOnStarted) {}

TEST_F(VideoCaptureImplTest,
       BufferReceivedBeforeOnStarted_ReadOnlyShmemRegion) {}

TEST_F(VideoCaptureImplTest,
       BufferReceivedBeforeOnStarted_GpuMemoryBufferHandle) {}

TEST_F(VideoCaptureImplTest, StartTimeout) {}

TEST_F(VideoCaptureImplTest, StartTimeout_FeatureDisabled) {}

TEST_F(VideoCaptureImplTest, ErrorBeforeStart) {}

#if BUILDFLAG(IS_WIN)
// This is windows-only scenario.
TEST_F(VideoCaptureImplTest, FallbacksToPremappedGmbsWhenNotSupported) {
  const int kArbitraryBufferId = 11;

  // With GpuMemoryBufferHandle, the buffer handle is received on the IO thread
  // and passed to a media thread to create a SharedImage. After the SharedImage
  // is created and wrapped in a video frame, we pass the video frame back to
  // the IO thread to pass to the clients by calling their frame-ready
  // callbacks.
  base::Thread testing_io_thread("TestingIOThread");
  base::WaitableEvent frame_ready_event;
  media::VideoCaptureFeedback feedback;

  SetSharedImageCapabilities(/* shared_image_d3d = */ false);
  EXPECT_CALL(*this, OnStateUpdate(blink::VIDEO_CAPTURE_STATE_STARTED));
  EXPECT_CALL(*this, OnStateUpdate(blink::VIDEO_CAPTURE_STATE_STOPPED));
  EXPECT_CALL(mock_video_capture_host_, DoStart(_, session_id_, params_small_));
  EXPECT_CALL(mock_video_capture_host_, Stop(_));
  EXPECT_CALL(mock_video_capture_host_, ReleaseBuffer(_, kArbitraryBufferId, _))
      .WillOnce(
          Invoke([&](const base::UnguessableToken& device_id, int32_t buffer_id,
                     const media::VideoCaptureFeedback& fb) {
            // Hold on a reference to the video frame to emulate that we're
            // actively using the buffer.
            feedback = fb;
            frame_ready_event.Signal();
          }));

  // The first half of the test: Create and queue the GpuMemoryBufferHandle.
  // VideoCaptureImpl would:
  //   1. create a GpuMemoryBuffer out of the handle on |testing_io_thread|
  //   2. create a SharedImage from the GpuMemoryBuffer on |media_thread_|
  //   3. invoke OnFrameReady callback on |testing_io_thread|
  auto create_and_queue_buffer = [&]() {
    gfx::GpuMemoryBufferHandle gmb_handle;
    gmb_handle.type = gfx::NATIVE_PIXMAP;
    gmb_handle.id = gfx::GpuMemoryBufferId(kArbitraryBufferId);

    StartCapture(0, params_small_);
    SimulateGpuMemoryBufferCreated(kArbitraryBufferId, std::move(gmb_handle));
    SimulateBufferReceived(BufferDescription(
        kArbitraryBufferId, params_small_.requested_format.frame_size,
        media::PIXEL_FORMAT_NV12));
  };

  // The second half of the test: Stop capture and destroy the buffer.
  // Everything should happen on |testing_io_thread| here.
  auto stop_capture_and_destroy_buffer = [&]() {
    StopCapture(0);
    SimulateBufferDestroyed(kArbitraryBufferId);
    // Explicitly destroy |video_capture_impl_| to make sure it's destroyed on
    // the right thread.
    video_capture_impl_.reset();
  };

  testing_io_thread.Start();
  testing_io_thread.task_runner()->PostTask(
      FROM_HERE, base::BindLambdaForTesting(create_and_queue_buffer));

  // Wait until OnFrameReady is called on |testing_io_thread|.
  EXPECT_TRUE(frame_ready_event.TimedWait(base::Seconds(3)));

  EXPECT_TRUE(feedback.require_mapped_frame);

  testing_io_thread.task_runner()->PostTask(
      FROM_HERE, base::BindLambdaForTesting(stop_capture_and_destroy_buffer));
  testing_io_thread.Stop();

  EXPECT_EQ(mock_video_capture_host_.released_buffer_count(), 0);
}
#endif

TEST_F(VideoCaptureImplTest, WinCameraBusyErrorUpdatesCorrectState) {}

}  // namespace blink