| Index: media/capture/video/chromeos/camera_device_delegate_unittest.cc
|
| diff --git a/media/capture/video/chromeos/camera_device_delegate_unittest.cc b/media/capture/video/chromeos/camera_device_delegate_unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..48340dd366a7c578e7b05181458e7d1eb6de0d08
|
| --- /dev/null
|
| +++ b/media/capture/video/chromeos/camera_device_delegate_unittest.cc
|
| @@ -0,0 +1,327 @@
|
| +// Copyright 2017 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "media/capture/video/chromeos/camera_device_delegate.h"
|
| +
|
| +#include <stddef.h>
|
| +#include <stdint.h>
|
| +
|
| +#include <memory>
|
| +#include <utility>
|
| +
|
| +#include "base/message_loop/message_loop.h"
|
| +#include "base/run_loop.h"
|
| +#include "media/capture/video/chromeos/camera_hal_delegate_unittest.h"
|
| +#include "media/capture/video/chromeos/mojo/arc_camera3.mojom.h"
|
| +#include "testing/gmock/include/gmock/gmock.h"
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +
|
| +using testing::_;
|
| +using testing::A;
|
| +using testing::Invoke;
|
| +
|
| +namespace media {
|
| +
|
| +namespace {
|
| +
|
| +void DumpError(const tracked_objects::Location& location,
|
| + const std::string& message) {
|
| + DPLOG(ERROR) << location.ToString() << " " << message;
|
| +}
|
| +
|
| +class MockVideoCaptureClient : public VideoCaptureDevice::Client {
|
| + public:
|
| + MOCK_METHOD0(DoReserveOutputBuffer, void(void));
|
| + MOCK_METHOD0(DoOnIncomingCapturedBuffer, void(void));
|
| + MOCK_METHOD0(DoOnIncomingCapturedVideoFrame, void(void));
|
| + MOCK_METHOD0(DoResurrectLastOutputBuffer, void(void));
|
| + MOCK_METHOD2(OnError,
|
| + void(const tracked_objects::Location& from_here,
|
| + const std::string& reason));
|
| + MOCK_CONST_METHOD0(GetBufferPoolUtilization, double(void));
|
| + MOCK_METHOD0(OnStarted, void(void));
|
| +
|
| + explicit MockVideoCaptureClient(
|
| + base::Callback<void(const VideoCaptureFormat&)> frame_cb)
|
| + : main_thread_(base::ThreadTaskRunnerHandle::Get()), frame_cb_(frame_cb) {
|
| + ON_CALL(*this, OnError(_, _)).WillByDefault(Invoke(DumpError));
|
| + }
|
| +
|
| + void OnIncomingCapturedData(const uint8_t* data,
|
| + int length,
|
| + const VideoCaptureFormat& format,
|
| + int rotation,
|
| + base::TimeTicks reference_time,
|
| + base::TimeDelta timestamp,
|
| + int frame_feedback_id) override {
|
| + ASSERT_GT(length, 0);
|
| + ASSERT_TRUE(data);
|
| + main_thread_->PostTask(FROM_HERE, base::Bind(frame_cb_, format));
|
| + }
|
| +
|
| + // Trampoline methods to workaround GMOCK problems with std::unique_ptr<>.
|
| + Buffer ReserveOutputBuffer(const gfx::Size& dimensions,
|
| + media::VideoPixelFormat format,
|
| + media::VideoPixelStorage storage,
|
| + int frame_feedback_id) override {
|
| + DoReserveOutputBuffer();
|
| + NOTREACHED() << "This should never be called";
|
| + return Buffer();
|
| + }
|
| + void OnIncomingCapturedBuffer(Buffer buffer,
|
| + const VideoCaptureFormat& format,
|
| + base::TimeTicks reference_time,
|
| + base::TimeDelta timestamp) override {
|
| + DoOnIncomingCapturedBuffer();
|
| + }
|
| + void OnIncomingCapturedBufferExt(
|
| + Buffer buffer,
|
| + const VideoCaptureFormat& format,
|
| + base::TimeTicks reference_time,
|
| + base::TimeDelta timestamp,
|
| + gfx::Rect visible_rect,
|
| + const VideoFrameMetadata& additional_metadata) override {
|
| + DoOnIncomingCapturedVideoFrame();
|
| + }
|
| + Buffer ResurrectLastOutputBuffer(const gfx::Size& dimensions,
|
| + media::VideoPixelFormat format,
|
| + media::VideoPixelStorage storage,
|
| + int frame_feedback_id) {
|
| + DoResurrectLastOutputBuffer();
|
| + NOTREACHED() << "This should never be called";
|
| + return Buffer();
|
| + }
|
| +
|
| + private:
|
| + scoped_refptr<base::SingleThreadTaskRunner> main_thread_;
|
| + base::Callback<void(const VideoCaptureFormat&)> frame_cb_;
|
| +};
|
| +
|
| +class MockCameraDevice : public arc::mojom::Camera3DeviceOps {
|
| + public:
|
| + MockCameraDevice() : mock_device_thread_("MockDeviceThread"), binding_(this) {
|
| + mock_device_thread_.Start();
|
| + }
|
| +
|
| + ~MockCameraDevice() {
|
| + mock_device_thread_.task_runner()->PostTask(
|
| + FROM_HERE, base::Bind(&MockCameraDevice::CloseBindingOnThread,
|
| + base::Unretained(this)));
|
| + mock_device_thread_.Stop();
|
| + }
|
| +
|
| + void Initialize(arc::mojom::Camera3CallbackOpsPtr callback_ops,
|
| + InitializeCallback callback) override {
|
| + DoInitialize(callback_ops, callback);
|
| + callback_ops_ = std::move(callback_ops);
|
| + std::move(callback).Run(0);
|
| + }
|
| + MOCK_METHOD2(DoInitialize,
|
| + void(arc::mojom::Camera3CallbackOpsPtr& callback_ops,
|
| + InitializeCallback& callback));
|
| +
|
| + void ConfigureStreams(arc::mojom::Camera3StreamConfigurationPtr config,
|
| + ConfigureStreamsCallback callback) override {
|
| + DoConfigureStreams(config, callback);
|
| + }
|
| + MOCK_METHOD2(DoConfigureStreams,
|
| + void(arc::mojom::Camera3StreamConfigurationPtr& config,
|
| + ConfigureStreamsCallback& callback));
|
| +
|
| + void ConstructDefaultRequestSettings(
|
| + arc::mojom::Camera3RequestTemplate type,
|
| + ConstructDefaultRequestSettingsCallback callback) {
|
| + DoConstructDefaultRequestSettings(type, callback);
|
| + }
|
| + MOCK_METHOD2(DoConstructDefaultRequestSettings,
|
| + void(arc::mojom::Camera3RequestTemplate type,
|
| + ConstructDefaultRequestSettingsCallback& callback));
|
| +
|
| + void ProcessCaptureRequest(arc::mojom::Camera3CaptureRequestPtr request,
|
| + ProcessCaptureRequestCallback callback) override {
|
| + DoProcessCaptureRequest(request, callback);
|
| + }
|
| + MOCK_METHOD2(DoProcessCaptureRequest,
|
| + void(arc::mojom::Camera3CaptureRequestPtr& request,
|
| + ProcessCaptureRequestCallback& callback));
|
| +
|
| + void Dump(mojo::ScopedHandle fd) override { DoDump(fd); }
|
| + MOCK_METHOD1(DoDump, void(mojo::ScopedHandle& fd));
|
| +
|
| + void Flush(FlushCallback callback) { DoFlush(callback); }
|
| + MOCK_METHOD1(DoFlush, void(FlushCallback& callback));
|
| +
|
| + void RegisterBuffer(uint64_t buffer_id,
|
| + arc::mojom::Camera3DeviceOps::BufferType type,
|
| + std::vector<mojo::ScopedHandle> fds,
|
| + uint32_t drm_format,
|
| + arc::mojom::HalPixelFormat hal_pixel_format,
|
| + uint32_t width,
|
| + uint32_t height,
|
| + const std::vector<uint32_t>& strides,
|
| + const std::vector<uint32_t>& offsets,
|
| + RegisterBufferCallback callback) override {
|
| + DoRegisterBuffer(buffer_id, type, fds, drm_format, hal_pixel_format, width,
|
| + height, strides, offsets, callback);
|
| + }
|
| + MOCK_METHOD10(DoRegisterBuffer,
|
| + void(uint64_t buffer_id,
|
| + arc::mojom::Camera3DeviceOps::BufferType type,
|
| + std::vector<mojo::ScopedHandle>& fds,
|
| + uint32_t drm_format,
|
| + arc::mojom::HalPixelFormat hal_pixel_format,
|
| + uint32_t width,
|
| + uint32_t height,
|
| + const std::vector<uint32_t>& strides,
|
| + const std::vector<uint32_t>& offsets,
|
| + RegisterBufferCallback& callback));
|
| +
|
| + void Close(CloseCallback callback) { DoClose(callback); }
|
| + MOCK_METHOD1(DoClose, void(CloseCallback& callback));
|
| +
|
| + arc::mojom::Camera3DeviceOpsPtrInfo GetInterfacePtrInfo() {
|
| + base::WaitableEvent done(base::WaitableEvent::ResetPolicy::MANUAL,
|
| + base::WaitableEvent::InitialState::NOT_SIGNALED);
|
| + arc::mojom::Camera3DeviceOpsPtrInfo ptr_info;
|
| + mock_device_thread_.task_runner()->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&MockCameraDevice::BindOnThread, base::Unretained(this),
|
| + base::Unretained(&done), base::Unretained(&ptr_info)));
|
| + done.Wait();
|
| + return ptr_info;
|
| + }
|
| +
|
| + private:
|
| + void CloseBindingOnThread() {
|
| + if (binding_.is_bound()) {
|
| + binding_.Close();
|
| + }
|
| + }
|
| +
|
| + void BindOnThread(base::WaitableEvent* done,
|
| + arc::mojom::Camera3DeviceOpsPtrInfo* ptr_info) {
|
| + *ptr_info = binding_.CreateInterfacePtrAndBind().PassInterface();
|
| + done->Signal();
|
| + }
|
| +
|
| + base::Thread mock_device_thread_;
|
| + mojo::Binding<arc::mojom::Camera3DeviceOps> binding_;
|
| + arc::mojom::Camera3CallbackOpsPtr callback_ops_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(MockCameraDevice);
|
| +};
|
| +
|
| +} // namespace
|
| +
|
| +class CameraDeviceDelegateTest : public ::testing::Test {
|
| + public:
|
| + CameraDeviceDelegateTest()
|
| + : device_delegate_thread_("DeviceDelegateThread"),
|
| + message_loop_(new base::MessageLoop),
|
| + hal_delegate_thread_("HalDelegateThread") {}
|
| +
|
| + void SetUp() override {
|
| + hal_delegate_thread_.Start();
|
| + camera_hal_delegate_ =
|
| + new CameraHalDelegate(hal_delegate_thread_.task_runner());
|
| + camera_hal_delegate_->StartForTesting(
|
| + mock_camera_module_.GetInterfacePtrInfo());
|
| + }
|
| +
|
| + void TearDown() override {
|
| + while (!camera_hal_delegate_->HasOneRef()) {
|
| + base::PlatformThread::YieldCurrentThread();
|
| + }
|
| + camera_hal_delegate_ = nullptr;
|
| + hal_delegate_thread_.Stop();
|
| + }
|
| +
|
| + void AllocateDeviceWithDescriptor(VideoCaptureDeviceDescriptor descriptor) {
|
| + ASSERT_FALSE(device_delegate_thread_.IsRunning());
|
| + ASSERT_FALSE(camera_device_delegate_);
|
| + device_delegate_thread_.Start();
|
| + camera_device_delegate_ =
|
| + new CameraDeviceDelegate(descriptor, camera_hal_delegate_,
|
| + device_delegate_thread_.task_runner());
|
| + }
|
| +
|
| + void ResetDevice() {
|
| + ASSERT_TRUE(device_delegate_thread_.IsRunning());
|
| + ASSERT_TRUE(camera_device_delegate_);
|
| + while (!camera_device_delegate_->HasOneRef()) {
|
| + base::PlatformThread::YieldCurrentThread();
|
| + }
|
| + camera_device_delegate_ = nullptr;
|
| + device_delegate_thread_.Stop();
|
| + }
|
| +
|
| + void Wait() {
|
| + run_loop_.reset(new base::RunLoop());
|
| + run_loop_->Run();
|
| + }
|
| +
|
| + protected:
|
| + scoped_refptr<CameraHalDelegate> camera_hal_delegate_;
|
| + scoped_refptr<CameraDeviceDelegate> camera_device_delegate_;
|
| + testing::StrictMock<unittest_internal::MockCameraModule> mock_camera_module_;
|
| + testing::StrictMock<MockCameraDevice> mock_camera_device_;
|
| + base::Thread device_delegate_thread_;
|
| +
|
| + private:
|
| + std::unique_ptr<base::MessageLoop> message_loop_;
|
| + base::Thread hal_delegate_thread_;
|
| + std::unique_ptr<base::RunLoop> run_loop_;
|
| + DISALLOW_COPY_AND_ASSIGN(CameraDeviceDelegateTest);
|
| +};
|
| +
|
| +TEST_F(CameraDeviceDelegateTest, AllocateAndStop) {
|
| + VideoCaptureDeviceDescriptor descriptor("Fake device", "0");
|
| + AllocateDeviceWithDescriptor(descriptor);
|
| +
|
| + auto get_camera_info_cb =
|
| + [](uint32_t camera_id,
|
| + arc::mojom::CameraModule::GetCameraInfoCallback& cb) {
|
| + arc::mojom::CameraInfoPtr camera_info = arc::mojom::CameraInfo::New();
|
| + arc::mojom::CameraMetadataPtr static_metadata =
|
| + arc::mojom::CameraMetadata::New();
|
| + switch (camera_id) {
|
| + case 0:
|
| + camera_info->facing = arc::mojom::CameraFacing::CAMERA_FACING_BACK;
|
| + camera_info->orientation = 0;
|
| + camera_info->static_camera_characteristics =
|
| + std::move(static_metadata);
|
| + break;
|
| + default:
|
| + FAIL() << "Invalid camera id";
|
| + }
|
| + std::move(cb).Run(0, std::move(camera_info));
|
| + };
|
| +
|
| + VideoCaptureParams params;
|
| + params.requested_format =
|
| + VideoCaptureFormat(gfx::Size(1280, 720), 30.0, PIXEL_FORMAT_I420);
|
| +
|
| + base::Callback<void(const VideoCaptureFormat&)> frame_cb =
|
| + base::BindRepeating([](const VideoCaptureFormat& format) {});
|
| +
|
| + std::unique_ptr<VideoCaptureDevice::Client> mock_client(
|
| + new MockVideoCaptureClient(frame_cb));
|
| +
|
| + EXPECT_CALL(mock_camera_module_, DoGetCameraInfo(0, _))
|
| + .Times(1)
|
| + .WillOnce(Invoke(get_camera_info_cb));
|
| +
|
| + device_delegate_thread_.task_runner()->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&CameraDeviceDelegate::AllocateAndStart,
|
| + camera_device_delegate_, params, base::Passed(&mock_client)));
|
| +
|
| + device_delegate_thread_.task_runner()->PostTask(
|
| + FROM_HERE, base::Bind(&CameraDeviceDelegate::StopAndDeAllocate,
|
| + camera_device_delegate_));
|
| +
|
| + ResetDevice();
|
| +}
|
| +
|
| +} // namespace media
|
|
|