1 // Copyright (c) 2012 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/bind_helpers.h"
7 #include "base/memory/scoped_ptr.h"
8 #include "base/message_loop/message_loop.h"
9 #include "base/message_loop/message_loop_proxy.h"
10 #include "base/run_loop.h"
11 #include "base/synchronization/waitable_event.h"
12 #include "base/test/test_timeouts.h"
13 #include "base/threading/thread.h"
14 #include "media/video/capture/fake_video_capture_device.h"
15 #include "media/video/capture/video_capture_device.h"
16 #include "media/video/capture/video_capture_types.h"
17 #include "testing/gmock/include/gmock/gmock.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19
20 #if defined(OS_WIN)
21 #include "base/win/scoped_com_initializer.h"
22 #include "media/video/capture/win/video_capture_device_mf_win.h"
23 #endif
24
25 #if defined(OS_ANDROID)
26 #include "base/android/jni_android.h"
27 #include "media/video/capture/android/video_capture_device_android.h"
28 #endif
29
30 #if defined(OS_MACOSX)
31 // Mac/QTKit will always give you the size you ask for and this case will fail.
32 #define MAYBE_AllocateBadSize DISABLED_AllocateBadSize
33 // We will always get ARGB from the Mac/QTKit implementation.
34 #define MAYBE_CaptureMjpeg DISABLED_CaptureMjpeg
35 #elif defined(OS_WIN)
36 #define MAYBE_AllocateBadSize AllocateBadSize
37 // Windows currently uses DirectShow to convert from MJPEG and a raw format is
38 // always delivered.
39 #define MAYBE_CaptureMjpeg DISABLED_CaptureMjpeg
40 #elif defined(OS_ANDROID)
41 // TODO(wjia): enable those tests on Android.
42 // On Android, native camera (JAVA) delivers frames on UI thread which is the
43 // main thread for tests. This results in no frame received by
44 // VideoCaptureAndroid.
45 #define CaptureVGA DISABLED_CaptureVGA
46 #define Capture720p DISABLED_Capture720p
47 #define MAYBE_AllocateBadSize DISABLED_AllocateBadSize
48 #define ReAllocateCamera DISABLED_ReAllocateCamera
49 #define DeAllocateCameraWhileRunning DISABLED_DeAllocateCameraWhileRunning
50 #define DeAllocateCameraWhileRunning DISABLED_DeAllocateCameraWhileRunning
51 #define MAYBE_CaptureMjpeg DISABLED_CaptureMjpeg
52 #else
53 #define MAYBE_AllocateBadSize AllocateBadSize
54 #define MAYBE_CaptureMjpeg CaptureMjpeg
55 #endif
56
57 using ::testing::_;
58 using ::testing::AnyNumber;
59 using ::testing::Return;
60 using ::testing::AtLeast;
61
62 namespace media {
63
64 class MockClient : public media::VideoCaptureDevice::Client {
65 public:
66 MOCK_METHOD2(ReserveOutputBuffer,
67 scoped_refptr<Buffer>(media::VideoFrame::Format format,
68 const gfx::Size& dimensions));
69 MOCK_METHOD0(OnErr, void());
70
MockClient(base::Callback<void (const VideoCaptureFormat &)> frame_cb)71 explicit MockClient(base::Callback<void(const VideoCaptureFormat&)> frame_cb)
72 : main_thread_(base::MessageLoopProxy::current()), frame_cb_(frame_cb) {}
73
OnError()74 virtual void OnError() OVERRIDE {
75 OnErr();
76 }
77
OnIncomingCapturedFrame(const uint8 * data,int length,base::Time timestamp,int rotation,const VideoCaptureFormat & format)78 virtual void OnIncomingCapturedFrame(const uint8* data,
79 int length,
80 base::Time timestamp,
81 int rotation,
82 const VideoCaptureFormat& format)
83 OVERRIDE {
84 main_thread_->PostTask(FROM_HERE, base::Bind(frame_cb_, format));
85 }
86
OnIncomingCapturedBuffer(const scoped_refptr<Buffer> & buffer,media::VideoFrame::Format format,const gfx::Size & dimensions,base::Time timestamp,int frame_rate)87 virtual void OnIncomingCapturedBuffer(const scoped_refptr<Buffer>& buffer,
88 media::VideoFrame::Format format,
89 const gfx::Size& dimensions,
90 base::Time timestamp,
91 int frame_rate) OVERRIDE {
92 NOTREACHED();
93 }
94
95 private:
96 scoped_refptr<base::MessageLoopProxy> main_thread_;
97 base::Callback<void(const VideoCaptureFormat&)> frame_cb_;
98 };
99
100 class VideoCaptureDeviceTest : public testing::Test {
101 protected:
102 typedef media::VideoCaptureDevice::Client Client;
103
VideoCaptureDeviceTest()104 VideoCaptureDeviceTest()
105 : loop_(new base::MessageLoop()),
106 client_(
107 new MockClient(base::Bind(&VideoCaptureDeviceTest::OnFrameCaptured,
108 base::Unretained(this)))) {}
109
SetUp()110 virtual void SetUp() {
111 #if defined(OS_ANDROID)
112 media::VideoCaptureDeviceAndroid::RegisterVideoCaptureDevice(
113 base::android::AttachCurrentThread());
114 #endif
115 }
116
ResetWithNewClient()117 void ResetWithNewClient() {
118 client_.reset(new MockClient(base::Bind(
119 &VideoCaptureDeviceTest::OnFrameCaptured, base::Unretained(this))));
120 }
121
OnFrameCaptured(const VideoCaptureFormat & format)122 void OnFrameCaptured(const VideoCaptureFormat& format) {
123 last_format_ = format;
124 run_loop_->QuitClosure().Run();
125 }
126
WaitForCapturedFrame()127 void WaitForCapturedFrame() {
128 run_loop_.reset(new base::RunLoop());
129 run_loop_->Run();
130 }
131
last_format() const132 const VideoCaptureFormat& last_format() const { return last_format_; }
133
134 #if defined(OS_WIN)
135 base::win::ScopedCOMInitializer initialize_com_;
136 #endif
137 VideoCaptureDevice::Names names_;
138 scoped_ptr<base::MessageLoop> loop_;
139 scoped_ptr<base::RunLoop> run_loop_;
140 scoped_ptr<MockClient> client_;
141 VideoCaptureFormat last_format_;
142 };
143
TEST_F(VideoCaptureDeviceTest,OpenInvalidDevice)144 TEST_F(VideoCaptureDeviceTest, OpenInvalidDevice) {
145 #if defined(OS_WIN)
146 VideoCaptureDevice::Name::CaptureApiType api_type =
147 VideoCaptureDeviceMFWin::PlatformSupported()
148 ? VideoCaptureDevice::Name::MEDIA_FOUNDATION
149 : VideoCaptureDevice::Name::DIRECT_SHOW;
150 VideoCaptureDevice::Name device_name("jibberish", "jibberish", api_type);
151 #else
152 VideoCaptureDevice::Name device_name("jibberish", "jibberish");
153 #endif
154 VideoCaptureDevice* device = VideoCaptureDevice::Create(device_name);
155 EXPECT_TRUE(device == NULL);
156 }
157
TEST_F(VideoCaptureDeviceTest,CaptureVGA)158 TEST_F(VideoCaptureDeviceTest, CaptureVGA) {
159 VideoCaptureDevice::GetDeviceNames(&names_);
160 if (!names_.size()) {
161 DVLOG(1) << "No camera available. Exiting test.";
162 return;
163 }
164
165 scoped_ptr<VideoCaptureDevice> device(
166 VideoCaptureDevice::Create(names_.front()));
167 ASSERT_FALSE(device.get() == NULL);
168 DVLOG(1) << names_.front().id();
169
170 EXPECT_CALL(*client_, OnErr())
171 .Times(0);
172
173 VideoCaptureParams capture_params;
174 capture_params.requested_format.frame_size.SetSize(640, 480);
175 capture_params.requested_format.frame_rate = 30;
176 capture_params.requested_format.pixel_format = PIXEL_FORMAT_I420;
177 capture_params.allow_resolution_change = false;
178 device->AllocateAndStart(capture_params, client_.PassAs<Client>());
179 // Get captured video frames.
180 WaitForCapturedFrame();
181 EXPECT_EQ(last_format().frame_size.width(), 640);
182 EXPECT_EQ(last_format().frame_size.height(), 480);
183 device->StopAndDeAllocate();
184 }
185
TEST_F(VideoCaptureDeviceTest,Capture720p)186 TEST_F(VideoCaptureDeviceTest, Capture720p) {
187 VideoCaptureDevice::GetDeviceNames(&names_);
188 if (!names_.size()) {
189 DVLOG(1) << "No camera available. Exiting test.";
190 return;
191 }
192
193 scoped_ptr<VideoCaptureDevice> device(
194 VideoCaptureDevice::Create(names_.front()));
195 ASSERT_FALSE(device.get() == NULL);
196
197 EXPECT_CALL(*client_, OnErr())
198 .Times(0);
199
200 VideoCaptureParams capture_params;
201 capture_params.requested_format.frame_size.SetSize(1280, 720);
202 capture_params.requested_format.frame_rate = 30;
203 capture_params.requested_format.pixel_format = PIXEL_FORMAT_I420;
204 capture_params.allow_resolution_change = false;
205 device->AllocateAndStart(capture_params, client_.PassAs<Client>());
206 // Get captured video frames.
207 WaitForCapturedFrame();
208 device->StopAndDeAllocate();
209 }
210
TEST_F(VideoCaptureDeviceTest,MAYBE_AllocateBadSize)211 TEST_F(VideoCaptureDeviceTest, MAYBE_AllocateBadSize) {
212 VideoCaptureDevice::GetDeviceNames(&names_);
213 if (!names_.size()) {
214 DVLOG(1) << "No camera available. Exiting test.";
215 return;
216 }
217 scoped_ptr<VideoCaptureDevice> device(
218 VideoCaptureDevice::Create(names_.front()));
219 ASSERT_TRUE(device.get() != NULL);
220
221 EXPECT_CALL(*client_, OnErr())
222 .Times(0);
223
224 VideoCaptureParams capture_params;
225 capture_params.requested_format.frame_size.SetSize(637, 472);
226 capture_params.requested_format.frame_rate = 35;
227 capture_params.requested_format.pixel_format = PIXEL_FORMAT_I420;
228 capture_params.allow_resolution_change = false;
229 device->AllocateAndStart(capture_params, client_.PassAs<Client>());
230 WaitForCapturedFrame();
231 device->StopAndDeAllocate();
232 EXPECT_EQ(last_format().frame_size.width(), 640);
233 EXPECT_EQ(last_format().frame_size.height(), 480);
234 }
235
TEST_F(VideoCaptureDeviceTest,ReAllocateCamera)236 TEST_F(VideoCaptureDeviceTest, ReAllocateCamera) {
237 VideoCaptureDevice::GetDeviceNames(&names_);
238 if (!names_.size()) {
239 DVLOG(1) << "No camera available. Exiting test.";
240 return;
241 }
242
243 // First, do a number of very fast device start/stops.
244 for (int i = 0; i <= 5; i++) {
245 ResetWithNewClient();
246 scoped_ptr<VideoCaptureDevice> device(
247 VideoCaptureDevice::Create(names_.front()));
248 gfx::Size resolution;
249 if (i % 2) {
250 resolution = gfx::Size(640, 480);
251 } else {
252 resolution = gfx::Size(1280, 1024);
253 }
254 VideoCaptureParams capture_params;
255 capture_params.requested_format.frame_size = resolution;
256 capture_params.requested_format.frame_rate = 30;
257 capture_params.requested_format.pixel_format = PIXEL_FORMAT_I420;
258 capture_params.allow_resolution_change = false;
259 device->AllocateAndStart(capture_params, client_.PassAs<Client>());
260 device->StopAndDeAllocate();
261 }
262
263 // Finally, do a device start and wait for it to finish.
264 VideoCaptureParams capture_params;
265 capture_params.requested_format.frame_size.SetSize(320, 240);
266 capture_params.requested_format.frame_rate = 30;
267 capture_params.requested_format.pixel_format = PIXEL_FORMAT_I420;
268 capture_params.allow_resolution_change = false;
269
270 ResetWithNewClient();
271 scoped_ptr<VideoCaptureDevice> device(
272 VideoCaptureDevice::Create(names_.front()));
273
274 device->AllocateAndStart(capture_params, client_.PassAs<Client>());
275 WaitForCapturedFrame();
276 device->StopAndDeAllocate();
277 device.reset();
278 EXPECT_EQ(last_format().frame_size.width(), 320);
279 EXPECT_EQ(last_format().frame_size.height(), 240);
280 }
281
TEST_F(VideoCaptureDeviceTest,DeAllocateCameraWhileRunning)282 TEST_F(VideoCaptureDeviceTest, DeAllocateCameraWhileRunning) {
283 VideoCaptureDevice::GetDeviceNames(&names_);
284 if (!names_.size()) {
285 DVLOG(1) << "No camera available. Exiting test.";
286 return;
287 }
288 scoped_ptr<VideoCaptureDevice> device(
289 VideoCaptureDevice::Create(names_.front()));
290 ASSERT_TRUE(device.get() != NULL);
291
292 EXPECT_CALL(*client_, OnErr())
293 .Times(0);
294
295 VideoCaptureParams capture_params;
296 capture_params.requested_format.frame_size.SetSize(640, 480);
297 capture_params.requested_format.frame_rate = 30;
298 capture_params.requested_format.pixel_format = PIXEL_FORMAT_I420;
299 capture_params.allow_resolution_change = false;
300 device->AllocateAndStart(capture_params, client_.PassAs<Client>());
301 // Get captured video frames.
302 WaitForCapturedFrame();
303 EXPECT_EQ(last_format().frame_size.width(), 640);
304 EXPECT_EQ(last_format().frame_size.height(), 480);
305 EXPECT_EQ(last_format().frame_rate, 30);
306 device->StopAndDeAllocate();
307 }
308
TEST_F(VideoCaptureDeviceTest,FakeCapture)309 TEST_F(VideoCaptureDeviceTest, FakeCapture) {
310 VideoCaptureDevice::Names names;
311
312 FakeVideoCaptureDevice::GetDeviceNames(&names);
313
314 ASSERT_GT(static_cast<int>(names.size()), 0);
315
316 scoped_ptr<VideoCaptureDevice> device(
317 FakeVideoCaptureDevice::Create(names.front()));
318 ASSERT_TRUE(device.get() != NULL);
319
320 EXPECT_CALL(*client_, OnErr())
321 .Times(0);
322
323 VideoCaptureParams capture_params;
324 capture_params.requested_format.frame_size.SetSize(640, 480);
325 capture_params.requested_format.frame_rate = 30;
326 capture_params.requested_format.pixel_format = PIXEL_FORMAT_I420;
327 capture_params.allow_resolution_change = false;
328 device->AllocateAndStart(capture_params, client_.PassAs<Client>());
329 WaitForCapturedFrame();
330 EXPECT_EQ(last_format().frame_size.width(), 640);
331 EXPECT_EQ(last_format().frame_size.height(), 480);
332 EXPECT_EQ(last_format().frame_rate, 30);
333 device->StopAndDeAllocate();
334 }
335
336 // Start the camera in 720p to capture MJPEG instead of a raw format.
TEST_F(VideoCaptureDeviceTest,MAYBE_CaptureMjpeg)337 TEST_F(VideoCaptureDeviceTest, MAYBE_CaptureMjpeg) {
338 VideoCaptureDevice::GetDeviceNames(&names_);
339 if (!names_.size()) {
340 DVLOG(1) << "No camera available. Exiting test.";
341 return;
342 }
343 scoped_ptr<VideoCaptureDevice> device(
344 VideoCaptureDevice::Create(names_.front()));
345 ASSERT_TRUE(device.get() != NULL);
346
347 EXPECT_CALL(*client_, OnErr())
348 .Times(0);
349
350 VideoCaptureParams capture_params;
351 capture_params.requested_format.frame_size.SetSize(1280, 720);
352 capture_params.requested_format.frame_rate = 30;
353 capture_params.requested_format.pixel_format = PIXEL_FORMAT_MJPEG;
354 capture_params.allow_resolution_change = false;
355 device->AllocateAndStart(capture_params, client_.PassAs<Client>());
356 // Get captured video frames.
357 WaitForCapturedFrame();
358 // Verify we get MJPEG from the device. Not all devices can capture 1280x720
359 // @ 30 fps, so we don't care about the exact resolution we get.
360 EXPECT_EQ(last_format().pixel_format, PIXEL_FORMAT_MJPEG);
361 device->StopAndDeAllocate();
362 }
363
TEST_F(VideoCaptureDeviceTest,GetDeviceSupportedFormats)364 TEST_F(VideoCaptureDeviceTest, GetDeviceSupportedFormats) {
365 VideoCaptureDevice::GetDeviceNames(&names_);
366 if (!names_.size()) {
367 DVLOG(1) << "No camera available. Exiting test.";
368 return;
369 }
370 VideoCaptureFormats supported_formats;
371 VideoCaptureDevice::Names::iterator names_iterator;
372 for (names_iterator = names_.begin(); names_iterator != names_.end();
373 ++names_iterator) {
374 VideoCaptureDevice::GetDeviceSupportedFormats(*names_iterator,
375 &supported_formats);
376 // Nothing to test here since we cannot forecast the hardware capabilities.
377 }
378 }
379
TEST_F(VideoCaptureDeviceTest,FakeCaptureVariableResolution)380 TEST_F(VideoCaptureDeviceTest, FakeCaptureVariableResolution) {
381 VideoCaptureDevice::Names names;
382
383 FakeVideoCaptureDevice::GetDeviceNames(&names);
384 VideoCaptureParams capture_params;
385 capture_params.requested_format.frame_size.SetSize(640, 480);
386 capture_params.requested_format.frame_rate = 30;
387 capture_params.requested_format.pixel_format = PIXEL_FORMAT_I420;
388 capture_params.allow_resolution_change = true;
389
390 ASSERT_GT(static_cast<int>(names.size()), 0);
391
392 scoped_ptr<VideoCaptureDevice> device(
393 FakeVideoCaptureDevice::Create(names.front()));
394 ASSERT_TRUE(device.get() != NULL);
395
396 EXPECT_CALL(*client_, OnErr())
397 .Times(0);
398 int action_count = 200;
399
400 device->AllocateAndStart(capture_params, client_.PassAs<Client>());
401
402 // We set TimeWait to 200 action timeouts and this should be enough for at
403 // least action_count/kFakeCaptureCapabilityChangePeriod calls.
404 for (int i = 0; i < action_count; ++i) {
405 WaitForCapturedFrame();
406 }
407 device->StopAndDeAllocate();
408 }
409
TEST_F(VideoCaptureDeviceTest,FakeGetDeviceSupportedFormats)410 TEST_F(VideoCaptureDeviceTest, FakeGetDeviceSupportedFormats) {
411 VideoCaptureDevice::Names names;
412 FakeVideoCaptureDevice::GetDeviceNames(&names);
413
414 VideoCaptureFormats supported_formats;
415 VideoCaptureDevice::Names::iterator names_iterator;
416
417 for (names_iterator = names.begin(); names_iterator != names.end();
418 ++names_iterator) {
419 FakeVideoCaptureDevice::GetDeviceSupportedFormats(*names_iterator,
420 &supported_formats);
421 EXPECT_EQ(supported_formats.size(), 2u);
422 EXPECT_EQ(supported_formats[0].frame_size.width(), 640);
423 EXPECT_EQ(supported_formats[0].frame_size.height(), 480);
424 EXPECT_EQ(supported_formats[0].pixel_format, media::PIXEL_FORMAT_I420);
425 EXPECT_GE(supported_formats[0].frame_rate, 20);
426 EXPECT_EQ(supported_formats[1].frame_size.width(), 320);
427 EXPECT_EQ(supported_formats[1].frame_size.height(), 240);
428 EXPECT_EQ(supported_formats[1].pixel_format, media::PIXEL_FORMAT_I420);
429 EXPECT_GE(supported_formats[1].frame_rate, 20);
430 }
431 }
432
433 }; // namespace media
434