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.
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"
21 #include "base/win/scoped_com_initializer.h"
22 #include "media/video/capture/win/video_capture_device_mf_win.h"
25 #if defined(OS_ANDROID)
26 #include "base/android/jni_android.h"
27 #include "media/video/capture/android/video_capture_device_android.h"
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
36 #define MAYBE_AllocateBadSize AllocateBadSize
37 // Windows currently uses DirectShow to convert from MJPEG and a raw format is
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
53 #define MAYBE_AllocateBadSize AllocateBadSize
54 #define MAYBE_CaptureMjpeg CaptureMjpeg
58 using ::testing::AnyNumber
;
59 using ::testing::Return
;
60 using ::testing::AtLeast
;
61 using ::testing::SaveArg
;
65 class MockClient
: public media::VideoCaptureDevice::Client
{
67 MOCK_METHOD1(ReserveOutputBuffer
,
68 scoped_refptr
<media::VideoFrame
>(const gfx::Size
&));
69 MOCK_METHOD0(OnErr
, void());
70 MOCK_METHOD1(OnFrameInfo
, void(const VideoCaptureCapability
&));
71 MOCK_METHOD1(OnFrameInfoChanged
, void(const VideoCaptureCapability
&));
74 base::Closure frame_cb
)
75 : main_thread_(base::MessageLoopProxy::current()),
76 frame_cb_(frame_cb
) {}
78 virtual void OnError() OVERRIDE
{
82 virtual void OnIncomingCapturedFrame(
88 bool flip_horiz
) OVERRIDE
{
89 main_thread_
->PostTask(FROM_HERE
, frame_cb_
);
92 virtual void OnIncomingCapturedVideoFrame(
93 const scoped_refptr
<media::VideoFrame
>& frame
,
94 base::Time timestamp
) OVERRIDE
{
95 main_thread_
->PostTask(FROM_HERE
, frame_cb_
);
99 scoped_refptr
<base::MessageLoopProxy
> main_thread_
;
100 base::Closure frame_cb_
;
103 class VideoCaptureDeviceTest
: public testing::Test
{
105 typedef media::VideoCaptureDevice::Client Client
;
107 virtual void SetUp() {
108 loop_
.reset(new base::MessageLoopForUI());
109 client_
.reset(new MockClient(loop_
->QuitClosure()));
110 #if defined(OS_ANDROID)
111 media::VideoCaptureDeviceAndroid::RegisterVideoCaptureDevice(
112 base::android::AttachCurrentThread());
116 void WaitForCapturedFrame() {
121 base::win::ScopedCOMInitializer initialize_com_
;
123 scoped_ptr
<MockClient
> client_
;
124 VideoCaptureDevice::Names names_
;
125 scoped_ptr
<base::MessageLoop
> loop_
;
128 TEST_F(VideoCaptureDeviceTest
, OpenInvalidDevice
) {
130 VideoCaptureDevice::Name::CaptureApiType api_type
=
131 VideoCaptureDeviceMFWin::PlatformSupported()
132 ? VideoCaptureDevice::Name::MEDIA_FOUNDATION
133 : VideoCaptureDevice::Name::DIRECT_SHOW
;
134 VideoCaptureDevice::Name
device_name("jibberish", "jibberish", api_type
);
136 VideoCaptureDevice::Name
device_name("jibberish", "jibberish");
138 VideoCaptureDevice
* device
= VideoCaptureDevice::Create(device_name
);
139 EXPECT_TRUE(device
== NULL
);
142 TEST_F(VideoCaptureDeviceTest
, CaptureVGA
) {
143 VideoCaptureDevice::GetDeviceNames(&names_
);
144 if (!names_
.size()) {
145 DVLOG(1) << "No camera available. Exiting test.";
149 scoped_ptr
<VideoCaptureDevice
> device(
150 VideoCaptureDevice::Create(names_
.front()));
151 ASSERT_FALSE(device
.get() == NULL
);
152 DVLOG(1) << names_
.front().id();
153 // Get info about the new resolution.
154 VideoCaptureCapability rx_capability
;
155 EXPECT_CALL(*client_
, OnFrameInfo(_
))
156 .Times(1).WillOnce(SaveArg
<0>(&rx_capability
));
158 EXPECT_CALL(*client_
, OnErr())
161 VideoCaptureCapability
capture_format(640,
165 ConstantResolutionVideoCaptureDevice
);
166 device
->AllocateAndStart(capture_format
,
167 client_
.PassAs
<Client
>());
168 // Get captured video frames.
170 EXPECT_EQ(rx_capability
.width
, 640);
171 EXPECT_EQ(rx_capability
.height
, 480);
172 device
->StopAndDeAllocate();
175 TEST_F(VideoCaptureDeviceTest
, Capture720p
) {
176 VideoCaptureDevice::GetDeviceNames(&names_
);
177 if (!names_
.size()) {
178 DVLOG(1) << "No camera available. Exiting test.";
182 scoped_ptr
<VideoCaptureDevice
> device(
183 VideoCaptureDevice::Create(names_
.front()));
184 ASSERT_FALSE(device
.get() == NULL
);
186 // Get info about the new resolution.
187 // We don't care about the resulting resolution or frame rate as it might
188 // be different from one machine to the next.
189 EXPECT_CALL(*client_
, OnFrameInfo(_
))
192 EXPECT_CALL(*client_
, OnErr())
195 VideoCaptureCapability
capture_format(1280,
199 ConstantResolutionVideoCaptureDevice
);
200 device
->AllocateAndStart(capture_format
,
201 client_
.PassAs
<Client
>());
202 // Get captured video frames.
203 WaitForCapturedFrame();
204 device
->StopAndDeAllocate();
207 TEST_F(VideoCaptureDeviceTest
, MAYBE_AllocateBadSize
) {
208 VideoCaptureDevice::GetDeviceNames(&names_
);
209 if (!names_
.size()) {
210 DVLOG(1) << "No camera available. Exiting test.";
213 scoped_ptr
<VideoCaptureDevice
> device(
214 VideoCaptureDevice::Create(names_
.front()));
215 ASSERT_TRUE(device
.get() != NULL
);
217 EXPECT_CALL(*client_
, OnErr())
220 // Get info about the new resolution.
221 VideoCaptureCapability rx_capability
;
222 EXPECT_CALL(*client_
, OnFrameInfo(_
))
223 .Times(AtLeast(1)).WillOnce(SaveArg
<0>(&rx_capability
));
225 VideoCaptureCapability
capture_format(637,
229 ConstantResolutionVideoCaptureDevice
);
230 device
->AllocateAndStart(capture_format
,
231 client_
.PassAs
<Client
>());
232 device
->StopAndDeAllocate();
233 EXPECT_EQ(rx_capability
.width
, 640);
234 EXPECT_EQ(rx_capability
.height
, 480);
237 TEST_F(VideoCaptureDeviceTest
, ReAllocateCamera
) {
238 VideoCaptureDevice::GetDeviceNames(&names_
);
239 if (!names_
.size()) {
240 DVLOG(1) << "No camera available. Exiting test.";
244 // First, do a number of very fast device start/stops.
245 for (int i
= 0; i
<= 5; i
++) {
246 scoped_ptr
<MockClient
> client(
247 new MockClient(base::Bind(&base::DoNothing
)));
248 scoped_ptr
<VideoCaptureDevice
> device(
249 VideoCaptureDevice::Create(names_
.front()));
250 gfx::Size resolution
;
252 resolution
= gfx::Size(640, 480);
254 resolution
= gfx::Size(1280, 1024);
256 VideoCaptureCapability
requested_format(
261 ConstantResolutionVideoCaptureDevice
);
263 // The device (if it is an async implementation) may or may not get as far
264 // as the OnFrameInfo() step; we're intentionally not going to wait for it
266 EXPECT_CALL(*client
, OnFrameInfo(_
)).Times(testing::AtMost(1));
267 device
->AllocateAndStart(requested_format
,
268 client
.PassAs
<Client
>());
269 device
->StopAndDeAllocate();
272 // Finally, do a device start and wait for it to finish.
273 gfx::Size resolution
;
274 VideoCaptureCapability
requested_format(
279 ConstantResolutionVideoCaptureDevice
);
281 base::RunLoop run_loop
;
282 scoped_ptr
<MockClient
> client(
283 new MockClient(base::Bind(run_loop
.QuitClosure())));
284 scoped_ptr
<VideoCaptureDevice
> device(
285 VideoCaptureDevice::Create(names_
.front()));
287 // The device (if it is an async implementation) may or may not get as far
288 // as the OnFrameInfo() step; we're intentionally not going to wait for it
290 VideoCaptureCapability final_format
;
291 EXPECT_CALL(*client
, OnFrameInfo(_
))
292 .Times(1).WillOnce(SaveArg
<0>(&final_format
));
293 device
->AllocateAndStart(requested_format
,
294 client
.PassAs
<Client
>());
295 run_loop
.Run(); // Waits for a frame.
296 device
->StopAndDeAllocate();
298 EXPECT_EQ(final_format
.width
, 320);
299 EXPECT_EQ(final_format
.height
, 240);
302 TEST_F(VideoCaptureDeviceTest
, DeAllocateCameraWhileRunning
) {
303 VideoCaptureDevice::GetDeviceNames(&names_
);
304 if (!names_
.size()) {
305 DVLOG(1) << "No camera available. Exiting test.";
308 scoped_ptr
<VideoCaptureDevice
> device(
309 VideoCaptureDevice::Create(names_
.front()));
310 ASSERT_TRUE(device
.get() != NULL
);
312 EXPECT_CALL(*client_
, OnErr())
314 // Get info about the new resolution.
315 VideoCaptureCapability rx_capability
;
316 EXPECT_CALL(*client_
, OnFrameInfo(_
))
317 .WillOnce(SaveArg
<0>(&rx_capability
));
319 VideoCaptureCapability
capture_format(640,
323 ConstantResolutionVideoCaptureDevice
);
324 device
->AllocateAndStart(capture_format
, client_
.PassAs
<Client
>());
325 // Get captured video frames.
326 WaitForCapturedFrame();
327 EXPECT_EQ(rx_capability
.width
, 640);
328 EXPECT_EQ(rx_capability
.height
, 480);
329 EXPECT_EQ(rx_capability
.frame_rate
, 30);
330 device
->StopAndDeAllocate();
333 TEST_F(VideoCaptureDeviceTest
, FakeCapture
) {
334 VideoCaptureDevice::Names names
;
336 FakeVideoCaptureDevice::GetDeviceNames(&names
);
338 ASSERT_GT(static_cast<int>(names
.size()), 0);
340 scoped_ptr
<VideoCaptureDevice
> device(
341 FakeVideoCaptureDevice::Create(names
.front()));
342 ASSERT_TRUE(device
.get() != NULL
);
344 // Get info about the new resolution.
345 VideoCaptureCapability rx_capability
;
346 EXPECT_CALL(*client_
, OnFrameInfo(_
))
347 .Times(1).WillOnce(SaveArg
<0>(&rx_capability
));
349 EXPECT_CALL(*client_
, OnErr())
352 VideoCaptureCapability
capture_format(640,
356 ConstantResolutionVideoCaptureDevice
);
357 device
->AllocateAndStart(capture_format
,
358 client_
.PassAs
<Client
>());
359 WaitForCapturedFrame();
360 EXPECT_EQ(rx_capability
.width
, 640);
361 EXPECT_EQ(rx_capability
.height
, 480);
362 EXPECT_EQ(rx_capability
.frame_rate
, 30);
363 device
->StopAndDeAllocate();
366 // Start the camera in 720p to capture MJPEG instead of a raw format.
367 TEST_F(VideoCaptureDeviceTest
, MAYBE_CaptureMjpeg
) {
368 VideoCaptureDevice::GetDeviceNames(&names_
);
369 if (!names_
.size()) {
370 DVLOG(1) << "No camera available. Exiting test.";
373 scoped_ptr
<VideoCaptureDevice
> device(
374 VideoCaptureDevice::Create(names_
.front()));
375 ASSERT_TRUE(device
.get() != NULL
);
377 EXPECT_CALL(*client_
, OnErr())
379 // Verify we get MJPEG from the device. Not all devices can capture 1280x720
380 // @ 30 fps, so we don't care about the exact resolution we get.
381 VideoCaptureCapability rx_capability
;
382 EXPECT_CALL(*client_
, OnFrameInfo(_
))
383 .WillOnce(SaveArg
<0>(&rx_capability
));
385 VideoCaptureCapability
capture_format(1280,
389 ConstantResolutionVideoCaptureDevice
);
390 device
->AllocateAndStart(capture_format
, client_
.PassAs
<Client
>());
391 // Get captured video frames.
392 WaitForCapturedFrame();
393 EXPECT_EQ(rx_capability
.color
, PIXEL_FORMAT_MJPEG
);
394 device
->StopAndDeAllocate();
397 TEST_F(VideoCaptureDeviceTest
, GetDeviceSupportedFormats
) {
398 VideoCaptureDevice::GetDeviceNames(&names_
);
399 if (!names_
.size()) {
400 DVLOG(1) << "No camera available. Exiting test.";
403 VideoCaptureCapabilities capture_formats
;
404 VideoCaptureDevice::Names::iterator names_iterator
;
405 for (names_iterator
= names_
.begin(); names_iterator
!= names_
.end();
407 VideoCaptureDevice::GetDeviceSupportedFormats(*names_iterator
,
409 // Nothing to test here since we cannot forecast the hardware capabilities.
413 TEST_F(VideoCaptureDeviceTest
, FakeCaptureVariableResolution
) {
414 VideoCaptureDevice::Names names
;
416 FakeVideoCaptureDevice::GetDeviceNames(&names
);
417 media::VideoCaptureCapability capture_format
;
418 capture_format
.width
= 640;
419 capture_format
.height
= 480;
420 capture_format
.frame_rate
= 30;
421 capture_format
.frame_size_type
= media::VariableResolutionVideoCaptureDevice
;
423 ASSERT_GT(static_cast<int>(names
.size()), 0);
425 scoped_ptr
<VideoCaptureDevice
> device(
426 FakeVideoCaptureDevice::Create(names
.front()));
427 ASSERT_TRUE(device
.get() != NULL
);
429 // Get info about the new resolution.
430 EXPECT_CALL(*client_
, OnFrameInfo(_
))
433 EXPECT_CALL(*client_
, OnErr())
435 int action_count
= 200;
436 EXPECT_CALL(*client_
, OnFrameInfoChanged(_
))
437 .Times(AtLeast(action_count
/ 30));
439 device
->AllocateAndStart(capture_format
, client_
.PassAs
<Client
>());
441 // The amount of times the OnFrameInfoChanged gets called depends on how often
442 // FakeDevice is supposed to change and what is its actual frame rate.
443 // We set TimeWait to 200 action timeouts and this should be enough for at
444 // least action_count/kFakeCaptureCapabilityChangePeriod calls.
445 for (int i
= 0; i
< action_count
; ++i
) {
446 WaitForCapturedFrame();
448 device
->StopAndDeAllocate();
451 TEST_F(VideoCaptureDeviceTest
, FakeGetDeviceSupportedFormats
) {
452 VideoCaptureDevice::Names names
;
453 FakeVideoCaptureDevice::GetDeviceNames(&names
);
455 VideoCaptureCapabilities capture_formats
;
456 VideoCaptureDevice::Names::iterator names_iterator
;
458 for (names_iterator
= names
.begin(); names_iterator
!= names
.end();
460 FakeVideoCaptureDevice::GetDeviceSupportedFormats(*names_iterator
,
462 EXPECT_GE(capture_formats
.size(), 1u);
463 EXPECT_EQ(capture_formats
[0].width
, 640);
464 EXPECT_EQ(capture_formats
[0].height
, 480);
465 EXPECT_EQ(capture_formats
[0].color
, media::PIXEL_FORMAT_I420
);
466 EXPECT_GE(capture_formats
[0].frame_rate
, 20);
470 }; // namespace media