Updating XTBs based on .GRDs from branch master
[chromium-blink-merge.git] / media / capture / video / video_capture_device_unittest.cc
blob44bcaca5f87e1ea7fd398f7f4699f0f7597862c8
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.
5 #include "base/bind.h"
6 #include "base/bind_helpers.h"
7 #include "base/memory/ref_counted.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/run_loop.h"
10 #include "base/single_thread_task_runner.h"
11 #include "base/test/test_timeouts.h"
12 #include "base/thread_task_runner_handle.h"
13 #include "base/threading/thread.h"
14 #include "media/base/video_capture_types.h"
15 #include "media/capture/video/video_capture_device.h"
16 #include "media/capture/video/video_capture_device_factory.h"
17 #include "testing/gmock/include/gmock/gmock.h"
18 #include "testing/gtest/include/gtest/gtest.h"
20 #if defined(OS_WIN)
21 #include "base/win/scoped_com_initializer.h"
22 #include "media/capture/video/win/video_capture_device_factory_win.h"
23 #endif
25 #if defined(OS_MACOSX)
26 #include "media/base/mac/avfoundation_glue.h"
27 #include "media/capture/video/mac/video_capture_device_factory_mac.h"
28 #endif
30 #if defined(OS_ANDROID)
31 #include "base/android/jni_android.h"
32 #include "media/capture/video/android/video_capture_device_android.h"
33 #endif
35 #if defined(OS_MACOSX)
36 // Mac/QTKit will always give you the size you ask for and this case will fail.
37 #define MAYBE_AllocateBadSize DISABLED_AllocateBadSize
38 // We will always get YUYV from the Mac QTKit/AVFoundation implementations.
39 #define MAYBE_CaptureMjpeg DISABLED_CaptureMjpeg
40 #elif defined(OS_WIN)
41 #define MAYBE_AllocateBadSize AllocateBadSize
42 #define MAYBE_CaptureMjpeg CaptureMjpeg
43 #elif defined(OS_ANDROID)
44 // TODO(wjia): enable those tests on Android.
45 // On Android, native camera (JAVA) delivers frames on UI thread which is the
46 // main thread for tests. This results in no frame received by
47 // VideoCaptureAndroid.
48 #define MAYBE_AllocateBadSize DISABLED_AllocateBadSize
49 #define ReAllocateCamera DISABLED_ReAllocateCamera
50 #define DeAllocateCameraWhileRunning DISABLED_DeAllocateCameraWhileRunning
51 #define DeAllocateCameraWhileRunning DISABLED_DeAllocateCameraWhileRunning
52 #define MAYBE_CaptureMjpeg DISABLED_CaptureMjpeg
53 #else
54 #define MAYBE_AllocateBadSize AllocateBadSize
55 #define MAYBE_CaptureMjpeg CaptureMjpeg
56 #endif
58 using ::testing::_;
59 using ::testing::SaveArg;
61 namespace media {
62 namespace {
64 static const gfx::Size kCaptureSizes[] = {gfx::Size(640, 480),
65 gfx::Size(1280, 720)};
67 class MockClient : public VideoCaptureDevice::Client {
68 public:
69 MOCK_METHOD9(OnIncomingCapturedYuvData,
70 void(const uint8* y_data,
71 const uint8* u_data,
72 const uint8* v_data,
73 size_t y_stride,
74 size_t u_stride,
75 size_t v_stride,
76 const VideoCaptureFormat& frame_format,
77 int clockwise_rotation,
78 const base::TimeTicks& timestamp));
79 MOCK_METHOD0(DoReserveOutputBuffer, void(void));
80 MOCK_METHOD0(DoOnIncomingCapturedBuffer, void(void));
81 MOCK_METHOD0(DoOnIncomingCapturedVideoFrame, void(void));
82 MOCK_METHOD1(OnError, void(const std::string& reason));
83 MOCK_CONST_METHOD0(GetBufferPoolUtilization, double(void));
85 explicit MockClient(base::Callback<void(const VideoCaptureFormat&)> frame_cb)
86 : main_thread_(base::ThreadTaskRunnerHandle::Get()),
87 frame_cb_(frame_cb) {}
89 void OnIncomingCapturedData(const uint8* data,
90 int length,
91 const VideoCaptureFormat& format,
92 int rotation,
93 const base::TimeTicks& timestamp) override {
94 ASSERT_GT(length, 0);
95 ASSERT_TRUE(data != NULL);
96 main_thread_->PostTask(FROM_HERE, base::Bind(frame_cb_, format));
99 // Trampoline methods to workaround GMOCK problems with scoped_ptr<>.
100 scoped_ptr<Buffer> ReserveOutputBuffer(
101 const gfx::Size& dimensions,
102 media::VideoCapturePixelFormat format,
103 media::VideoPixelStorage storage) override {
104 DoReserveOutputBuffer();
105 NOTREACHED() << "This should never be called";
106 return scoped_ptr<Buffer>();
108 void OnIncomingCapturedBuffer(scoped_ptr<Buffer> buffer,
109 const VideoCaptureFormat& frame_format,
110 const base::TimeTicks& timestamp) override {
111 DoOnIncomingCapturedBuffer();
113 void OnIncomingCapturedVideoFrame(scoped_ptr<Buffer> buffer,
114 const scoped_refptr<VideoFrame>& frame,
115 const base::TimeTicks& timestamp) override {
116 DoOnIncomingCapturedVideoFrame();
119 private:
120 scoped_refptr<base::SingleThreadTaskRunner> main_thread_;
121 base::Callback<void(const VideoCaptureFormat&)> frame_cb_;
124 class DeviceEnumerationListener
125 : public base::RefCounted<DeviceEnumerationListener> {
126 public:
127 MOCK_METHOD1(OnEnumeratedDevicesCallbackPtr,
128 void(VideoCaptureDevice::Names* names));
129 // GMock doesn't support move-only arguments, so we use this forward method.
130 void OnEnumeratedDevicesCallback(
131 scoped_ptr<VideoCaptureDevice::Names> names) {
132 OnEnumeratedDevicesCallbackPtr(names.release());
135 private:
136 friend class base::RefCounted<DeviceEnumerationListener>;
137 virtual ~DeviceEnumerationListener() {}
140 } // namespace
142 class VideoCaptureDeviceTest : public testing::TestWithParam<gfx::Size> {
143 protected:
144 typedef VideoCaptureDevice::Client Client;
146 VideoCaptureDeviceTest()
147 : loop_(new base::MessageLoop()),
148 client_(
149 new MockClient(base::Bind(&VideoCaptureDeviceTest::OnFrameCaptured,
150 base::Unretained(this)))),
151 video_capture_device_factory_(VideoCaptureDeviceFactory::CreateFactory(
152 base::ThreadTaskRunnerHandle::Get())) {
153 device_enumeration_listener_ = new DeviceEnumerationListener();
156 void SetUp() override {
157 #if defined(OS_ANDROID)
158 VideoCaptureDeviceAndroid::RegisterVideoCaptureDevice(
159 base::android::AttachCurrentThread());
160 #endif
161 #if defined(OS_MACOSX)
162 AVFoundationGlue::InitializeAVFoundation();
163 #endif
164 EXPECT_CALL(*client_, OnIncomingCapturedYuvData(_, _, _, _, _, _, _, _, _))
165 .Times(0);
166 EXPECT_CALL(*client_, DoReserveOutputBuffer()).Times(0);
167 EXPECT_CALL(*client_, DoOnIncomingCapturedBuffer()).Times(0);
168 EXPECT_CALL(*client_, DoOnIncomingCapturedVideoFrame()).Times(0);
171 void ResetWithNewClient() {
172 client_.reset(new MockClient(base::Bind(
173 &VideoCaptureDeviceTest::OnFrameCaptured, base::Unretained(this))));
176 void OnFrameCaptured(const VideoCaptureFormat& format) {
177 last_format_ = format;
178 run_loop_->QuitClosure().Run();
181 void WaitForCapturedFrame() {
182 run_loop_.reset(new base::RunLoop());
183 run_loop_->Run();
186 scoped_ptr<VideoCaptureDevice::Names> EnumerateDevices() {
187 VideoCaptureDevice::Names* names;
188 EXPECT_CALL(*device_enumeration_listener_.get(),
189 OnEnumeratedDevicesCallbackPtr(_)).WillOnce(SaveArg<0>(&names));
191 video_capture_device_factory_->EnumerateDeviceNames(
192 base::Bind(&DeviceEnumerationListener::OnEnumeratedDevicesCallback,
193 device_enumeration_listener_));
194 base::MessageLoop::current()->RunUntilIdle();
195 return scoped_ptr<VideoCaptureDevice::Names>(names);
198 const VideoCaptureFormat& last_format() const { return last_format_; }
200 scoped_ptr<VideoCaptureDevice::Name> GetFirstDeviceNameSupportingPixelFormat(
201 const VideoCapturePixelFormat& pixel_format) {
202 names_ = EnumerateDevices();
203 if (names_->empty()) {
204 DVLOG(1) << "No camera available.";
205 return scoped_ptr<VideoCaptureDevice::Name>();
207 for (const auto& names_iterator : *names_) {
208 VideoCaptureFormats supported_formats;
209 video_capture_device_factory_->GetDeviceSupportedFormats(
210 names_iterator, &supported_formats);
211 for (const auto& formats_iterator : supported_formats) {
212 if (formats_iterator.pixel_format == pixel_format) {
213 return scoped_ptr<VideoCaptureDevice::Name>(
214 new VideoCaptureDevice::Name(names_iterator));
218 DVLOG_IF(1, pixel_format != VIDEO_CAPTURE_PIXEL_FORMAT_MAX)
219 << "No camera can capture the"
220 << " format: " << VideoCaptureFormat::PixelFormatToString(pixel_format);
221 return scoped_ptr<VideoCaptureDevice::Name>();
224 bool IsCaptureSizeSupported(const VideoCaptureDevice::Name& device,
225 const gfx::Size& size) {
226 VideoCaptureFormats supported_formats;
227 video_capture_device_factory_->GetDeviceSupportedFormats(
228 device, &supported_formats);
229 const auto it = std::find_if(
230 supported_formats.begin(), supported_formats.end(),
231 [&size](VideoCaptureFormat const& f) { return f.frame_size == size; });
232 if (it == supported_formats.end()) {
233 DVLOG(1) << "Size " << size.ToString() << " is not supported.";
234 return false;
236 return true;
239 #if defined(OS_WIN)
240 base::win::ScopedCOMInitializer initialize_com_;
241 #endif
242 scoped_ptr<VideoCaptureDevice::Names> names_;
243 scoped_ptr<base::MessageLoop> loop_;
244 scoped_ptr<base::RunLoop> run_loop_;
245 scoped_ptr<MockClient> client_;
246 scoped_refptr<DeviceEnumerationListener> device_enumeration_listener_;
247 VideoCaptureFormat last_format_;
248 scoped_ptr<VideoCaptureDeviceFactory> video_capture_device_factory_;
251 // Cause hangs on Windows Debug. http://crbug.com/417824
252 #if defined(OS_WIN) && !defined(NDEBUG)
253 #define MAYBE_OpenInvalidDevice DISABLED_OpenInvalidDevice
254 #else
255 #define MAYBE_OpenInvalidDevice OpenInvalidDevice
256 #endif
258 TEST_F(VideoCaptureDeviceTest, MAYBE_OpenInvalidDevice) {
259 #if defined(OS_WIN)
260 VideoCaptureDevice::Name::CaptureApiType api_type =
261 VideoCaptureDeviceFactoryWin::PlatformSupportsMediaFoundation()
262 ? VideoCaptureDevice::Name::MEDIA_FOUNDATION
263 : VideoCaptureDevice::Name::DIRECT_SHOW;
264 VideoCaptureDevice::Name device_name("jibberish", "jibberish", api_type);
265 #elif defined(OS_MACOSX)
266 VideoCaptureDevice::Name device_name(
267 "jibberish", "jibberish",
268 VideoCaptureDeviceFactoryMac::PlatformSupportsAVFoundation()
269 ? VideoCaptureDevice::Name::AVFOUNDATION
270 : VideoCaptureDevice::Name::QTKIT);
271 #else
272 VideoCaptureDevice::Name device_name("jibberish", "jibberish");
273 #endif
274 scoped_ptr<VideoCaptureDevice> device =
275 video_capture_device_factory_->Create(device_name);
276 #if !defined(OS_MACOSX)
277 EXPECT_TRUE(device == NULL);
278 #else
279 if (VideoCaptureDeviceFactoryMac::PlatformSupportsAVFoundation()) {
280 EXPECT_TRUE(device == NULL);
281 } else {
282 // The presence of the actual device is only checked on AllocateAndStart()
283 // and not on creation for QTKit API in Mac OS X platform.
284 EXPECT_CALL(*client_, OnError(_)).Times(1);
286 VideoCaptureParams capture_params;
287 capture_params.requested_format.frame_size.SetSize(640, 480);
288 capture_params.requested_format.frame_rate = 30;
289 capture_params.requested_format.pixel_format =
290 VIDEO_CAPTURE_PIXEL_FORMAT_I420;
291 device->AllocateAndStart(capture_params, client_.Pass());
292 device->StopAndDeAllocate();
294 #endif
297 TEST_P(VideoCaptureDeviceTest, CaptureWithSize) {
298 names_ = EnumerateDevices();
299 if (names_->empty()) {
300 DVLOG(1) << "No camera available. Exiting test.";
301 return;
304 const gfx::Size& size = GetParam();
305 if (!IsCaptureSizeSupported(names_->front(), size))
306 return;
307 const int width = size.width();
308 const int height = size.height();
310 scoped_ptr<VideoCaptureDevice> device(
311 video_capture_device_factory_->Create(names_->front()));
312 ASSERT_TRUE(device);
313 DVLOG(1) << names_->front().id();
315 EXPECT_CALL(*client_, OnError(_)).Times(0);
317 VideoCaptureParams capture_params;
318 capture_params.requested_format.frame_size.SetSize(width, height);
319 capture_params.requested_format.frame_rate = 30.0f;
320 capture_params.requested_format.pixel_format =
321 VIDEO_CAPTURE_PIXEL_FORMAT_I420;
322 device->AllocateAndStart(capture_params, client_.Pass());
323 // Get captured video frames.
324 WaitForCapturedFrame();
325 EXPECT_EQ(last_format().frame_size.width(), width);
326 EXPECT_EQ(last_format().frame_size.height(), height);
327 if (last_format().pixel_format != VIDEO_CAPTURE_PIXEL_FORMAT_MJPEG)
328 EXPECT_EQ(size.GetArea(), last_format().frame_size.GetArea());
329 device->StopAndDeAllocate();
332 #if !defined(OS_ANDROID)
333 INSTANTIATE_TEST_CASE_P(MAYBE_VideoCaptureDeviceTests,
334 VideoCaptureDeviceTest,
335 testing::ValuesIn(kCaptureSizes));
336 #endif
338 TEST_F(VideoCaptureDeviceTest, MAYBE_AllocateBadSize) {
339 names_ = EnumerateDevices();
340 if (names_->empty()) {
341 DVLOG(1) << "No camera available. Exiting test.";
342 return;
344 scoped_ptr<VideoCaptureDevice> device(
345 video_capture_device_factory_->Create(names_->front()));
346 ASSERT_TRUE(device);
348 EXPECT_CALL(*client_, OnError(_)).Times(0);
350 const gfx::Size input_size(640, 480);
351 VideoCaptureParams capture_params;
352 capture_params.requested_format.frame_size.SetSize(637, 472);
353 capture_params.requested_format.frame_rate = 35;
354 capture_params.requested_format.pixel_format =
355 VIDEO_CAPTURE_PIXEL_FORMAT_I420;
356 device->AllocateAndStart(capture_params, client_.Pass());
357 WaitForCapturedFrame();
358 device->StopAndDeAllocate();
359 EXPECT_EQ(last_format().frame_size.width(), input_size.width());
360 EXPECT_EQ(last_format().frame_size.height(), input_size.height());
361 if (last_format().pixel_format != VIDEO_CAPTURE_PIXEL_FORMAT_MJPEG)
362 EXPECT_EQ(input_size.GetArea(), last_format().frame_size.GetArea());
365 // Cause hangs on Windows Debug. http://crbug.com/417824
366 #if defined(OS_WIN) && !defined(NDEBUG)
367 #define MAYBE_ReAllocateCamera DISABLED_ReAllocateCamera
368 #else
369 #define MAYBE_ReAllocateCamera ReAllocateCamera
370 #endif
372 TEST_F(VideoCaptureDeviceTest, MAYBE_ReAllocateCamera) {
373 names_ = EnumerateDevices();
374 if (names_->empty()) {
375 DVLOG(1) << "No camera available. Exiting test.";
376 return;
379 // First, do a number of very fast device start/stops.
380 for (int i = 0; i <= 5; i++) {
381 ResetWithNewClient();
382 scoped_ptr<VideoCaptureDevice> device(
383 video_capture_device_factory_->Create(names_->front()));
384 gfx::Size resolution;
385 if (i % 2) {
386 resolution = gfx::Size(640, 480);
387 } else {
388 resolution = gfx::Size(1280, 1024);
390 VideoCaptureParams capture_params;
391 capture_params.requested_format.frame_size = resolution;
392 capture_params.requested_format.frame_rate = 30;
393 capture_params.requested_format.pixel_format =
394 VIDEO_CAPTURE_PIXEL_FORMAT_I420;
395 device->AllocateAndStart(capture_params, client_.Pass());
396 device->StopAndDeAllocate();
399 // Finally, do a device start and wait for it to finish.
400 VideoCaptureParams capture_params;
401 capture_params.requested_format.frame_size.SetSize(320, 240);
402 capture_params.requested_format.frame_rate = 30;
403 capture_params.requested_format.pixel_format =
404 VIDEO_CAPTURE_PIXEL_FORMAT_I420;
406 ResetWithNewClient();
407 scoped_ptr<VideoCaptureDevice> device(
408 video_capture_device_factory_->Create(names_->front()));
410 device->AllocateAndStart(capture_params, client_.Pass());
411 WaitForCapturedFrame();
412 device->StopAndDeAllocate();
413 device.reset();
414 EXPECT_EQ(last_format().frame_size.width(), 320);
415 EXPECT_EQ(last_format().frame_size.height(), 240);
418 TEST_F(VideoCaptureDeviceTest, DeAllocateCameraWhileRunning) {
419 names_ = EnumerateDevices();
420 if (names_->empty()) {
421 DVLOG(1) << "No camera available. Exiting test.";
422 return;
424 scoped_ptr<VideoCaptureDevice> device(
425 video_capture_device_factory_->Create(names_->front()));
426 ASSERT_TRUE(device);
428 EXPECT_CALL(*client_, OnError(_)).Times(0);
430 VideoCaptureParams capture_params;
431 capture_params.requested_format.frame_size.SetSize(640, 480);
432 capture_params.requested_format.frame_rate = 30;
433 capture_params.requested_format.pixel_format =
434 VIDEO_CAPTURE_PIXEL_FORMAT_I420;
435 device->AllocateAndStart(capture_params, client_.Pass());
436 // Get captured video frames.
437 WaitForCapturedFrame();
438 EXPECT_EQ(last_format().frame_size.width(), 640);
439 EXPECT_EQ(last_format().frame_size.height(), 480);
440 EXPECT_EQ(last_format().frame_rate, 30);
441 device->StopAndDeAllocate();
444 // Start the camera in 720p to capture MJPEG instead of a raw format.
445 TEST_F(VideoCaptureDeviceTest, MAYBE_CaptureMjpeg) {
446 scoped_ptr<VideoCaptureDevice::Name> name =
447 GetFirstDeviceNameSupportingPixelFormat(VIDEO_CAPTURE_PIXEL_FORMAT_MJPEG);
448 if (!name) {
449 DVLOG(1) << "No camera supports MJPEG format. Exiting test.";
450 return;
452 scoped_ptr<VideoCaptureDevice> device(
453 video_capture_device_factory_->Create(*name));
454 ASSERT_TRUE(device);
456 EXPECT_CALL(*client_, OnError(_)).Times(0);
458 VideoCaptureParams capture_params;
459 capture_params.requested_format.frame_size.SetSize(1280, 720);
460 capture_params.requested_format.frame_rate = 30;
461 capture_params.requested_format.pixel_format =
462 VIDEO_CAPTURE_PIXEL_FORMAT_MJPEG;
463 device->AllocateAndStart(capture_params, client_.Pass());
464 // Get captured video frames.
465 WaitForCapturedFrame();
466 // Verify we get MJPEG from the device. Not all devices can capture 1280x720
467 // @ 30 fps, so we don't care about the exact resolution we get.
468 EXPECT_EQ(last_format().pixel_format, VIDEO_CAPTURE_PIXEL_FORMAT_MJPEG);
469 EXPECT_GE(static_cast<size_t>(1280 * 720),
470 last_format().ImageAllocationSize());
471 device->StopAndDeAllocate();
474 TEST_F(VideoCaptureDeviceTest, GetDeviceSupportedFormats) {
475 // Use VIDEO_CAPTURE_PIXEL_FORMAT_MAX to iterate all device names for testing
476 // GetDeviceSupportedFormats().
477 scoped_ptr<VideoCaptureDevice::Name> name =
478 GetFirstDeviceNameSupportingPixelFormat(VIDEO_CAPTURE_PIXEL_FORMAT_MAX);
479 // Verify no camera returned for VIDEO_CAPTURE_PIXEL_FORMAT_MAX. Nothing else
480 // to test here
481 // since we cannot forecast the hardware capabilities.
482 ASSERT_FALSE(name);
485 }; // namespace media