1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "base/bind.h"
6#include "base/memory/scoped_ptr.h"
7#include "base/run_loop.h"
8#include "base/test/test_timeouts.h"
9#include "base/threading/thread.h"
10#include "media/video/capture/fake_video_capture_device.h"
11#include "media/video/capture/fake_video_capture_device_factory.h"
12#include "media/video/capture/video_capture_device.h"
13#include "media/video/capture/video_capture_types.h"
14#include "testing/gmock/include/gmock/gmock.h"
15#include "testing/gtest/include/gtest/gtest.h"
16
17using ::testing::_;
18using ::testing::SaveArg;
19
20namespace media {
21
22class MockClient : public media::VideoCaptureDevice::Client {
23 public:
24  MOCK_METHOD2(ReserveOutputBuffer,
25               scoped_refptr<Buffer>(media::VideoFrame::Format format,
26                                     const gfx::Size& dimensions));
27  MOCK_METHOD0(OnErr, void());
28
29  explicit MockClient(base::Callback<void(const VideoCaptureFormat&)> frame_cb)
30      : main_thread_(base::MessageLoopProxy::current()), frame_cb_(frame_cb) {}
31
32  virtual void OnError(const std::string& error_message) OVERRIDE {
33    OnErr();
34  }
35
36  virtual void OnIncomingCapturedData(const uint8* data,
37                                      int length,
38                                      const VideoCaptureFormat& format,
39                                      int rotation,
40                                      base::TimeTicks timestamp) OVERRIDE {
41    main_thread_->PostTask(FROM_HERE, base::Bind(frame_cb_, format));
42  }
43
44  virtual void OnIncomingCapturedVideoFrame(
45      const scoped_refptr<Buffer>& buffer,
46      const media::VideoCaptureFormat& buffer_format,
47      const scoped_refptr<media::VideoFrame>& frame,
48      base::TimeTicks timestamp) OVERRIDE {
49    NOTREACHED();
50  }
51
52 private:
53  scoped_refptr<base::SingleThreadTaskRunner> main_thread_;
54  base::Callback<void(const VideoCaptureFormat&)> frame_cb_;
55};
56
57class DeviceEnumerationListener :
58    public base::RefCounted<DeviceEnumerationListener> {
59 public:
60  MOCK_METHOD1(OnEnumeratedDevicesCallbackPtr,
61               void(media::VideoCaptureDevice::Names* names));
62  // GMock doesn't support move-only arguments, so we use this forward method.
63  void OnEnumeratedDevicesCallback(
64      scoped_ptr<media::VideoCaptureDevice::Names> names) {
65    OnEnumeratedDevicesCallbackPtr(names.release());
66  }
67
68 private:
69  friend class base::RefCounted<DeviceEnumerationListener>;
70  virtual ~DeviceEnumerationListener() {}
71};
72
73class FakeVideoCaptureDeviceTest : public testing::Test {
74 protected:
75  typedef media::VideoCaptureDevice::Client Client;
76
77  FakeVideoCaptureDeviceTest()
78      : loop_(new base::MessageLoop()),
79        client_(new MockClient(
80            base::Bind(&FakeVideoCaptureDeviceTest::OnFrameCaptured,
81                       base::Unretained(this)))),
82        video_capture_device_factory_(new FakeVideoCaptureDeviceFactory()) {
83    device_enumeration_listener_ = new DeviceEnumerationListener();
84  }
85
86  virtual void SetUp() {
87  }
88
89  void OnFrameCaptured(const VideoCaptureFormat& format) {
90    last_format_ = format;
91    run_loop_->QuitClosure().Run();
92  }
93
94  void WaitForCapturedFrame() {
95    run_loop_.reset(new base::RunLoop());
96    run_loop_->Run();
97  }
98
99  scoped_ptr<media::VideoCaptureDevice::Names> EnumerateDevices() {
100    media::VideoCaptureDevice::Names* names;
101    EXPECT_CALL(*device_enumeration_listener_.get(),
102                OnEnumeratedDevicesCallbackPtr(_)).WillOnce(SaveArg<0>(&names));
103
104    video_capture_device_factory_->EnumerateDeviceNames(
105        base::Bind(&DeviceEnumerationListener::OnEnumeratedDevicesCallback,
106                   device_enumeration_listener_));
107    base::MessageLoop::current()->RunUntilIdle();
108    return scoped_ptr<media::VideoCaptureDevice::Names>(names);
109  }
110
111  const VideoCaptureFormat& last_format() const { return last_format_; }
112
113  VideoCaptureDevice::Names names_;
114  scoped_ptr<base::MessageLoop> loop_;
115  scoped_ptr<base::RunLoop> run_loop_;
116  scoped_ptr<MockClient> client_;
117  scoped_refptr<DeviceEnumerationListener> device_enumeration_listener_;
118  VideoCaptureFormat last_format_;
119  scoped_ptr<VideoCaptureDeviceFactory> video_capture_device_factory_;
120};
121
122TEST_F(FakeVideoCaptureDeviceTest, Capture) {
123  scoped_ptr<media::VideoCaptureDevice::Names> names(EnumerateDevices());
124
125  ASSERT_GT(static_cast<int>(names->size()), 0);
126
127  scoped_ptr<VideoCaptureDevice> device(
128      video_capture_device_factory_->Create(names->front()));
129  ASSERT_TRUE(device);
130
131  EXPECT_CALL(*client_, OnErr()).Times(0);
132
133  VideoCaptureParams capture_params;
134  capture_params.requested_format.frame_size.SetSize(640, 480);
135  capture_params.requested_format.frame_rate = 30;
136  capture_params.requested_format.pixel_format = PIXEL_FORMAT_I420;
137  device->AllocateAndStart(capture_params, client_.PassAs<Client>());
138  WaitForCapturedFrame();
139  EXPECT_EQ(last_format().frame_size.width(), 640);
140  EXPECT_EQ(last_format().frame_size.height(), 480);
141  EXPECT_EQ(last_format().frame_rate, 30);
142  device->StopAndDeAllocate();
143}
144
145TEST_F(FakeVideoCaptureDeviceTest, GetDeviceSupportedFormats) {
146  scoped_ptr<VideoCaptureDevice::Names> names(EnumerateDevices());
147
148  VideoCaptureFormats supported_formats;
149  VideoCaptureDevice::Names::iterator names_iterator;
150
151  for (names_iterator = names->begin(); names_iterator != names->end();
152       ++names_iterator) {
153    video_capture_device_factory_->GetDeviceSupportedFormats(
154        *names_iterator, &supported_formats);
155    EXPECT_EQ(supported_formats.size(), 3u);
156    EXPECT_EQ(supported_formats[0].frame_size.width(), 320);
157    EXPECT_EQ(supported_formats[0].frame_size.height(), 240);
158    EXPECT_EQ(supported_formats[0].pixel_format, media::PIXEL_FORMAT_I420);
159    EXPECT_GE(supported_formats[0].frame_rate, 20);
160    EXPECT_EQ(supported_formats[1].frame_size.width(), 640);
161    EXPECT_EQ(supported_formats[1].frame_size.height(), 480);
162    EXPECT_EQ(supported_formats[1].pixel_format, media::PIXEL_FORMAT_I420);
163    EXPECT_GE(supported_formats[1].frame_rate, 20);
164    EXPECT_EQ(supported_formats[2].frame_size.width(), 1280);
165    EXPECT_EQ(supported_formats[2].frame_size.height(), 720);
166    EXPECT_EQ(supported_formats[2].pixel_format, media::PIXEL_FORMAT_I420);
167    EXPECT_GE(supported_formats[2].frame_rate, 20);
168  }
169}
170
171// Disabled, http://crbug.com/407061 .
172TEST_F(FakeVideoCaptureDeviceTest, DISABLED_CaptureVariableResolution) {
173  scoped_ptr<VideoCaptureDevice::Names> names(EnumerateDevices());
174
175  VideoCaptureParams capture_params;
176  capture_params.requested_format.frame_size.SetSize(640, 480);
177  capture_params.requested_format.frame_rate = 30;
178  capture_params.requested_format.pixel_format = PIXEL_FORMAT_I420;
179  capture_params.resolution_change_policy =
180      RESOLUTION_POLICY_DYNAMIC_WITHIN_LIMIT;
181
182  ASSERT_GT(static_cast<int>(names->size()), 0);
183
184  scoped_ptr<VideoCaptureDevice> device(
185      video_capture_device_factory_->Create(names->front()));
186  ASSERT_TRUE(device);
187
188  // Configure the FakeVideoCaptureDevice to use all its formats as roster.
189  VideoCaptureFormats formats;
190  video_capture_device_factory_->GetDeviceSupportedFormats(names->front(),
191                                                           &formats);
192  static_cast<FakeVideoCaptureDevice*>(device.get())->
193      PopulateVariableFormatsRoster(formats);
194
195  EXPECT_CALL(*client_, OnErr())
196      .Times(0);
197  int action_count = 200;
198
199  device->AllocateAndStart(capture_params, client_.PassAs<Client>());
200
201  // We set TimeWait to 200 action timeouts and this should be enough for at
202  // least action_count/kFakeCaptureCapabilityChangePeriod calls.
203  for (int i = 0; i < action_count; ++i) {
204    WaitForCapturedFrame();
205  }
206  device->StopAndDeAllocate();
207}
208
209};  // namespace media
210