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/memory/scoped_ptr.h"
7 #include "base/message_loop/message_loop_proxy.h"
8 #include "base/run_loop.h"
9 #include "base/test/test_timeouts.h"
10 #include "base/threading/thread.h"
11 #include "media/video/capture/video_capture_device.h"
12 #include "media/video/capture/video_capture_device_factory.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"
18 #include "base/win/scoped_com_initializer.h"
19 #include "media/video/capture/win/video_capture_device_factory_win.h"
22 #if defined(OS_ANDROID)
23 #include "base/android/jni_android.h"
24 #include "media/video/capture/android/video_capture_device_android.h"
27 #if defined(OS_MACOSX)
28 // Mac/QTKit will always give you the size you ask for and this case will fail.
29 #define MAYBE_AllocateBadSize DISABLED_AllocateBadSize
30 // We will always get YUYV from the Mac QTKit/AVFoundation implementations.
31 #define MAYBE_CaptureMjpeg DISABLED_CaptureMjpeg
33 #define MAYBE_AllocateBadSize AllocateBadSize
34 // Windows currently uses DirectShow to convert from MJPEG and a raw format is
36 #define MAYBE_CaptureMjpeg DISABLED_CaptureMjpeg
37 #elif defined(OS_ANDROID)
38 // TODO(wjia): enable those tests on Android.
39 // On Android, native camera (JAVA) delivers frames on UI thread which is the
40 // main thread for tests. This results in no frame received by
41 // VideoCaptureAndroid.
42 #define CaptureVGA DISABLED_CaptureVGA
43 #define Capture720p DISABLED_Capture720p
44 #define MAYBE_AllocateBadSize DISABLED_AllocateBadSize
45 #define ReAllocateCamera DISABLED_ReAllocateCamera
46 #define DeAllocateCameraWhileRunning DISABLED_DeAllocateCameraWhileRunning
47 #define DeAllocateCameraWhileRunning DISABLED_DeAllocateCameraWhileRunning
48 #define MAYBE_CaptureMjpeg DISABLED_CaptureMjpeg
50 #define MAYBE_AllocateBadSize AllocateBadSize
51 #define MAYBE_CaptureMjpeg CaptureMjpeg
56 class MockClient
: public media::VideoCaptureDevice::Client
{
58 MOCK_METHOD2(ReserveOutputBuffer
,
59 scoped_refptr
<Buffer
>(media::VideoFrame::Format format
,
60 const gfx::Size
& dimensions
));
61 MOCK_METHOD0(OnErr
, void());
63 explicit MockClient(base::Callback
<void(const VideoCaptureFormat
&)> frame_cb
)
64 : main_thread_(base::MessageLoopProxy::current()), frame_cb_(frame_cb
) {}
66 virtual void OnError(const std::string
& error_message
) OVERRIDE
{
70 virtual void OnIncomingCapturedData(const uint8
* data
,
72 const VideoCaptureFormat
& format
,
74 base::TimeTicks timestamp
) OVERRIDE
{
75 main_thread_
->PostTask(FROM_HERE
, base::Bind(frame_cb_
, format
));
78 virtual void OnIncomingCapturedVideoFrame(
79 const scoped_refptr
<Buffer
>& buffer
,
80 const media::VideoCaptureFormat
& buffer_format
,
81 const scoped_refptr
<media::VideoFrame
>& frame
,
82 base::TimeTicks timestamp
) OVERRIDE
{
87 scoped_refptr
<base::SingleThreadTaskRunner
> main_thread_
;
88 base::Callback
<void(const VideoCaptureFormat
&)> frame_cb_
;
91 class VideoCaptureDeviceTest
: public testing::Test
{
93 typedef media::VideoCaptureDevice::Client Client
;
95 VideoCaptureDeviceTest()
96 : loop_(new base::MessageLoop()),
98 new MockClient(base::Bind(&VideoCaptureDeviceTest::OnFrameCaptured
,
99 base::Unretained(this)))),
100 video_capture_device_factory_(
101 VideoCaptureDeviceFactory::CreateFactory()) {}
103 virtual void SetUp() {
104 #if defined(OS_ANDROID)
105 media::VideoCaptureDeviceAndroid::RegisterVideoCaptureDevice(
106 base::android::AttachCurrentThread());
110 void ResetWithNewClient() {
111 client_
.reset(new MockClient(base::Bind(
112 &VideoCaptureDeviceTest::OnFrameCaptured
, base::Unretained(this))));
115 void OnFrameCaptured(const VideoCaptureFormat
& format
) {
116 last_format_
= format
;
117 run_loop_
->QuitClosure().Run();
120 void WaitForCapturedFrame() {
121 run_loop_
.reset(new base::RunLoop());
125 const VideoCaptureFormat
& last_format() const { return last_format_
; }
127 scoped_ptr
<VideoCaptureDevice::Name
> GetFirstDeviceNameSupportingPixelFormat(
128 const VideoPixelFormat
& pixel_format
) {
129 video_capture_device_factory_
->GetDeviceNames(&names_
);
130 if (!names_
.size()) {
131 DVLOG(1) << "No camera available.";
132 return scoped_ptr
<VideoCaptureDevice::Name
>();
134 VideoCaptureDevice::Names::iterator names_iterator
;
135 for (names_iterator
= names_
.begin(); names_iterator
!= names_
.end();
137 VideoCaptureFormats supported_formats
;
138 video_capture_device_factory_
->GetDeviceSupportedFormats(
141 VideoCaptureFormats::iterator formats_iterator
;
142 for (formats_iterator
= supported_formats
.begin();
143 formats_iterator
!= supported_formats
.end(); ++formats_iterator
) {
144 if (formats_iterator
->pixel_format
== pixel_format
) {
145 return scoped_ptr
<VideoCaptureDevice::Name
>(
146 new VideoCaptureDevice::Name(*names_iterator
));
150 DVLOG(1) << "No camera can capture the format: " << pixel_format
;
151 return scoped_ptr
<VideoCaptureDevice::Name
>();
155 base::win::ScopedCOMInitializer initialize_com_
;
157 VideoCaptureDevice::Names names_
;
158 scoped_ptr
<base::MessageLoop
> loop_
;
159 scoped_ptr
<base::RunLoop
> run_loop_
;
160 scoped_ptr
<MockClient
> client_
;
161 VideoCaptureFormat last_format_
;
162 scoped_ptr
<VideoCaptureDeviceFactory
> video_capture_device_factory_
;
165 TEST_F(VideoCaptureDeviceTest
, OpenInvalidDevice
) {
167 VideoCaptureDevice::Name::CaptureApiType api_type
=
168 VideoCaptureDeviceFactoryWin::PlatformSupportsMediaFoundation()
169 ? VideoCaptureDevice::Name::MEDIA_FOUNDATION
170 : VideoCaptureDevice::Name::DIRECT_SHOW
;
171 VideoCaptureDevice::Name
device_name("jibberish", "jibberish", api_type
);
172 #elif defined(OS_MACOSX)
173 VideoCaptureDevice::Name
device_name("jibberish", "jibberish",
174 VideoCaptureDevice::Name::AVFOUNDATION
);
176 VideoCaptureDevice::Name
device_name("jibberish", "jibberish");
178 scoped_ptr
<VideoCaptureDevice
> device
=
179 video_capture_device_factory_
->Create(
180 base::MessageLoopProxy::current(),
182 EXPECT_TRUE(device
== NULL
);
185 TEST_F(VideoCaptureDeviceTest
, CaptureVGA
) {
186 video_capture_device_factory_
->GetDeviceNames(&names_
);
187 if (!names_
.size()) {
188 DVLOG(1) << "No camera available. Exiting test.";
192 scoped_ptr
<VideoCaptureDevice
> device(
193 video_capture_device_factory_
->Create(base::MessageLoopProxy::current(),
196 DVLOG(1) << names_
.front().id();
198 EXPECT_CALL(*client_
, OnErr())
201 VideoCaptureParams capture_params
;
202 capture_params
.requested_format
.frame_size
.SetSize(640, 480);
203 capture_params
.requested_format
.frame_rate
= 30;
204 capture_params
.requested_format
.pixel_format
= PIXEL_FORMAT_I420
;
205 capture_params
.allow_resolution_change
= false;
206 device
->AllocateAndStart(capture_params
, client_
.PassAs
<Client
>());
207 // Get captured video frames.
208 WaitForCapturedFrame();
209 EXPECT_EQ(last_format().frame_size
.width(), 640);
210 EXPECT_EQ(last_format().frame_size
.height(), 480);
211 device
->StopAndDeAllocate();
214 TEST_F(VideoCaptureDeviceTest
, Capture720p
) {
215 video_capture_device_factory_
->GetDeviceNames(&names_
);
216 if (!names_
.size()) {
217 DVLOG(1) << "No camera available. Exiting test.";
221 scoped_ptr
<VideoCaptureDevice
> device(
222 video_capture_device_factory_
->Create(base::MessageLoopProxy::current(),
226 EXPECT_CALL(*client_
, OnErr())
229 VideoCaptureParams capture_params
;
230 capture_params
.requested_format
.frame_size
.SetSize(1280, 720);
231 capture_params
.requested_format
.frame_rate
= 30;
232 capture_params
.requested_format
.pixel_format
= PIXEL_FORMAT_I420
;
233 capture_params
.allow_resolution_change
= false;
234 device
->AllocateAndStart(capture_params
, client_
.PassAs
<Client
>());
235 // Get captured video frames.
236 WaitForCapturedFrame();
237 device
->StopAndDeAllocate();
240 TEST_F(VideoCaptureDeviceTest
, MAYBE_AllocateBadSize
) {
241 video_capture_device_factory_
->GetDeviceNames(&names_
);
242 if (!names_
.size()) {
243 DVLOG(1) << "No camera available. Exiting test.";
246 scoped_ptr
<VideoCaptureDevice
> device(
247 video_capture_device_factory_
->Create(base::MessageLoopProxy::current(),
251 EXPECT_CALL(*client_
, OnErr())
254 VideoCaptureParams capture_params
;
255 capture_params
.requested_format
.frame_size
.SetSize(637, 472);
256 capture_params
.requested_format
.frame_rate
= 35;
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 WaitForCapturedFrame();
261 device
->StopAndDeAllocate();
262 EXPECT_EQ(last_format().frame_size
.width(), 640);
263 EXPECT_EQ(last_format().frame_size
.height(), 480);
266 TEST_F(VideoCaptureDeviceTest
, ReAllocateCamera
) {
267 video_capture_device_factory_
->GetDeviceNames(&names_
);
268 if (!names_
.size()) {
269 DVLOG(1) << "No camera available. Exiting test.";
273 // First, do a number of very fast device start/stops.
274 for (int i
= 0; i
<= 5; i
++) {
275 ResetWithNewClient();
276 scoped_ptr
<VideoCaptureDevice
> device(
277 video_capture_device_factory_
->Create(base::MessageLoopProxy::current(),
279 gfx::Size resolution
;
281 resolution
= gfx::Size(640, 480);
283 resolution
= gfx::Size(1280, 1024);
285 VideoCaptureParams capture_params
;
286 capture_params
.requested_format
.frame_size
= resolution
;
287 capture_params
.requested_format
.frame_rate
= 30;
288 capture_params
.requested_format
.pixel_format
= PIXEL_FORMAT_I420
;
289 capture_params
.allow_resolution_change
= false;
290 device
->AllocateAndStart(capture_params
, client_
.PassAs
<Client
>());
291 device
->StopAndDeAllocate();
294 // Finally, do a device start and wait for it to finish.
295 VideoCaptureParams capture_params
;
296 capture_params
.requested_format
.frame_size
.SetSize(320, 240);
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;
301 ResetWithNewClient();
302 scoped_ptr
<VideoCaptureDevice
> device(
303 video_capture_device_factory_
->Create(base::MessageLoopProxy::current(),
306 device
->AllocateAndStart(capture_params
, client_
.PassAs
<Client
>());
307 WaitForCapturedFrame();
308 device
->StopAndDeAllocate();
310 EXPECT_EQ(last_format().frame_size
.width(), 320);
311 EXPECT_EQ(last_format().frame_size
.height(), 240);
314 TEST_F(VideoCaptureDeviceTest
, DeAllocateCameraWhileRunning
) {
315 video_capture_device_factory_
->GetDeviceNames(&names_
);
316 if (!names_
.size()) {
317 DVLOG(1) << "No camera available. Exiting test.";
320 scoped_ptr
<VideoCaptureDevice
> device(
321 video_capture_device_factory_
->Create(base::MessageLoopProxy::current(),
325 EXPECT_CALL(*client_
, OnErr())
328 VideoCaptureParams capture_params
;
329 capture_params
.requested_format
.frame_size
.SetSize(640, 480);
330 capture_params
.requested_format
.frame_rate
= 30;
331 capture_params
.requested_format
.pixel_format
= PIXEL_FORMAT_I420
;
332 capture_params
.allow_resolution_change
= false;
333 device
->AllocateAndStart(capture_params
, client_
.PassAs
<Client
>());
334 // Get captured video frames.
335 WaitForCapturedFrame();
336 EXPECT_EQ(last_format().frame_size
.width(), 640);
337 EXPECT_EQ(last_format().frame_size
.height(), 480);
338 EXPECT_EQ(last_format().frame_rate
, 30);
339 device
->StopAndDeAllocate();
342 // Start the camera in 720p to capture MJPEG instead of a raw format.
343 TEST_F(VideoCaptureDeviceTest
, MAYBE_CaptureMjpeg
) {
344 scoped_ptr
<VideoCaptureDevice::Name
> name
=
345 GetFirstDeviceNameSupportingPixelFormat(PIXEL_FORMAT_MJPEG
);
347 DVLOG(1) << "No camera supports MJPEG format. Exiting test.";
350 scoped_ptr
<VideoCaptureDevice
> device(
351 video_capture_device_factory_
->Create(base::MessageLoopProxy::current(),
355 EXPECT_CALL(*client_
, OnErr())
358 VideoCaptureParams capture_params
;
359 capture_params
.requested_format
.frame_size
.SetSize(1280, 720);
360 capture_params
.requested_format
.frame_rate
= 30;
361 capture_params
.requested_format
.pixel_format
= PIXEL_FORMAT_MJPEG
;
362 capture_params
.allow_resolution_change
= false;
363 device
->AllocateAndStart(capture_params
, client_
.PassAs
<Client
>());
364 // Get captured video frames.
365 WaitForCapturedFrame();
366 // Verify we get MJPEG from the device. Not all devices can capture 1280x720
367 // @ 30 fps, so we don't care about the exact resolution we get.
368 EXPECT_EQ(last_format().pixel_format
, PIXEL_FORMAT_MJPEG
);
369 device
->StopAndDeAllocate();
372 TEST_F(VideoCaptureDeviceTest
, GetDeviceSupportedFormats
) {
373 // Use PIXEL_FORMAT_MAX to iterate all device names for testing
374 // GetDeviceSupportedFormats().
375 scoped_ptr
<VideoCaptureDevice::Name
> name
=
376 GetFirstDeviceNameSupportingPixelFormat(PIXEL_FORMAT_MAX
);
377 // Verify no camera returned for PIXEL_FORMAT_MAX. Nothing else to test here
378 // since we cannot forecast the hardware capabilities.
382 }; // namespace media