Unregister from GCM when the only GCM app is removed
[chromium-blink-merge.git] / media / video / capture / video_capture_device_unittest.cc
blobf365213d0f11260cb6faddb849c8c548525cad2f
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/message_loop/message_loop_proxy.h"
10 #include "base/run_loop.h"
11 #include "base/test/test_timeouts.h"
12 #include "base/threading/thread.h"
13 #include "media/video/capture/video_capture_device.h"
14 #include "media/video/capture/video_capture_device_factory.h"
15 #include "media/video/capture/video_capture_types.h"
16 #include "testing/gmock/include/gmock/gmock.h"
17 #include "testing/gtest/include/gtest/gtest.h"
19 #if defined(OS_WIN)
20 #include "base/win/scoped_com_initializer.h"
21 #include "media/video/capture/win/video_capture_device_factory_win.h"
22 #endif
24 #if defined(OS_MACOSX)
25 #include "media/video/capture/mac/video_capture_device_factory_mac.h"
26 #endif
28 #if defined(OS_ANDROID)
29 #include "base/android/jni_android.h"
30 #include "media/video/capture/android/video_capture_device_android.h"
31 #endif
33 #if defined(OS_MACOSX)
34 // Mac/QTKit will always give you the size you ask for and this case will fail.
35 #define MAYBE_AllocateBadSize DISABLED_AllocateBadSize
36 // We will always get YUYV from the Mac QTKit/AVFoundation implementations.
37 #define MAYBE_CaptureMjpeg DISABLED_CaptureMjpeg
38 #elif defined(OS_WIN)
39 #define MAYBE_AllocateBadSize AllocateBadSize
40 #define MAYBE_CaptureMjpeg CaptureMjpeg
41 #elif defined(OS_ANDROID)
42 // TODO(wjia): enable those tests on Android.
43 // On Android, native camera (JAVA) delivers frames on UI thread which is the
44 // main thread for tests. This results in no frame received by
45 // VideoCaptureAndroid.
46 #define CaptureVGA DISABLED_CaptureVGA
47 #define Capture720p DISABLED_Capture720p
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 {
63 namespace {
65 class MockClient : public VideoCaptureDevice::Client {
66 public:
67 MOCK_METHOD2(ReserveOutputBuffer,
68 scoped_refptr<Buffer>(VideoFrame::Format format,
69 const gfx::Size& dimensions));
70 MOCK_METHOD0(OnErr, void());
72 explicit MockClient(base::Callback<void(const VideoCaptureFormat&)> frame_cb)
73 : main_thread_(base::MessageLoopProxy::current()), frame_cb_(frame_cb) {}
75 void OnError(const std::string& error_message) override {
76 OnErr();
79 void OnIncomingCapturedData(const uint8* data,
80 int length,
81 const VideoCaptureFormat& format,
82 int rotation,
83 base::TimeTicks timestamp) override {
84 ASSERT_GT(length, 0);
85 ASSERT_TRUE(data != NULL);
86 main_thread_->PostTask(FROM_HERE, base::Bind(frame_cb_, format));
89 void OnIncomingCapturedVideoFrame(
90 const scoped_refptr<Buffer>& buffer,
91 const VideoCaptureFormat& buffer_format,
92 const scoped_refptr<VideoFrame>& frame,
93 base::TimeTicks timestamp) override {
94 NOTREACHED();
97 private:
98 scoped_refptr<base::SingleThreadTaskRunner> main_thread_;
99 base::Callback<void(const VideoCaptureFormat&)> frame_cb_;
102 class DeviceEnumerationListener :
103 public base::RefCounted<DeviceEnumerationListener> {
104 public:
105 MOCK_METHOD1(OnEnumeratedDevicesCallbackPtr,
106 void(VideoCaptureDevice::Names* names));
107 // GMock doesn't support move-only arguments, so we use this forward method.
108 void OnEnumeratedDevicesCallback(
109 scoped_ptr<VideoCaptureDevice::Names> names) {
110 OnEnumeratedDevicesCallbackPtr(names.release());
112 private:
113 friend class base::RefCounted<DeviceEnumerationListener>;
114 virtual ~DeviceEnumerationListener() {}
117 } // namespace
119 class VideoCaptureDeviceTest : public testing::Test {
120 protected:
121 typedef VideoCaptureDevice::Client Client;
123 VideoCaptureDeviceTest()
124 : loop_(new base::MessageLoop()),
125 client_(
126 new MockClient(base::Bind(&VideoCaptureDeviceTest::OnFrameCaptured,
127 base::Unretained(this)))),
128 video_capture_device_factory_(VideoCaptureDeviceFactory::CreateFactory(
129 base::MessageLoopProxy::current())) {
130 device_enumeration_listener_ = new DeviceEnumerationListener();
133 #if defined(OS_ANDROID)
134 void SetUp() override {
135 VideoCaptureDeviceAndroid::RegisterVideoCaptureDevice(
136 base::android::AttachCurrentThread());
138 #endif
140 void ResetWithNewClient() {
141 client_.reset(new MockClient(base::Bind(
142 &VideoCaptureDeviceTest::OnFrameCaptured, base::Unretained(this))));
145 void OnFrameCaptured(const VideoCaptureFormat& format) {
146 last_format_ = format;
147 run_loop_->QuitClosure().Run();
150 void WaitForCapturedFrame() {
151 run_loop_.reset(new base::RunLoop());
152 run_loop_->Run();
155 scoped_ptr<VideoCaptureDevice::Names> EnumerateDevices() {
156 VideoCaptureDevice::Names* names;
157 EXPECT_CALL(*device_enumeration_listener_.get(),
158 OnEnumeratedDevicesCallbackPtr(_)).WillOnce(SaveArg<0>(&names));
160 video_capture_device_factory_->EnumerateDeviceNames(
161 base::Bind(&DeviceEnumerationListener::OnEnumeratedDevicesCallback,
162 device_enumeration_listener_));
163 base::MessageLoop::current()->RunUntilIdle();
164 return scoped_ptr<VideoCaptureDevice::Names>(names);
167 const VideoCaptureFormat& last_format() const { return last_format_; }
169 scoped_ptr<VideoCaptureDevice::Name> GetFirstDeviceNameSupportingPixelFormat(
170 const VideoPixelFormat& pixel_format) {
171 names_ = EnumerateDevices();
172 if (names_->empty()) {
173 DVLOG(1) << "No camera available.";
174 return scoped_ptr<VideoCaptureDevice::Name>();
176 for (const auto& names_iterator : *names_) {
177 VideoCaptureFormats supported_formats;
178 video_capture_device_factory_->GetDeviceSupportedFormats(
179 names_iterator,
180 &supported_formats);
181 for (const auto& formats_iterator : supported_formats) {
182 if (formats_iterator.pixel_format == pixel_format) {
183 return scoped_ptr<VideoCaptureDevice::Name>(
184 new VideoCaptureDevice::Name(names_iterator));
188 DVLOG(1) << "No camera can capture the format: " << pixel_format;
189 return scoped_ptr<VideoCaptureDevice::Name>();
192 #if defined(OS_WIN)
193 base::win::ScopedCOMInitializer initialize_com_;
194 #endif
195 scoped_ptr<VideoCaptureDevice::Names> names_;
196 scoped_ptr<base::MessageLoop> loop_;
197 scoped_ptr<base::RunLoop> run_loop_;
198 scoped_ptr<MockClient> client_;
199 scoped_refptr<DeviceEnumerationListener> device_enumeration_listener_;
200 VideoCaptureFormat last_format_;
201 scoped_ptr<VideoCaptureDeviceFactory> video_capture_device_factory_;
204 // Cause hangs on Windows Debug. http://crbug.com/417824
205 #if defined(OS_WIN) && !defined(NDEBUG)
206 #define MAYBE_OpenInvalidDevice DISABLED_OpenInvalidDevice
207 #else
208 #define MAYBE_OpenInvalidDevice OpenInvalidDevice
209 #endif
211 TEST_F(VideoCaptureDeviceTest, MAYBE_OpenInvalidDevice) {
212 #if defined(OS_WIN)
213 VideoCaptureDevice::Name::CaptureApiType api_type =
214 VideoCaptureDeviceFactoryWin::PlatformSupportsMediaFoundation()
215 ? VideoCaptureDevice::Name::MEDIA_FOUNDATION
216 : VideoCaptureDevice::Name::DIRECT_SHOW;
217 VideoCaptureDevice::Name device_name("jibberish", "jibberish", api_type);
218 #elif defined(OS_MACOSX)
219 VideoCaptureDevice::Name device_name("jibberish", "jibberish",
220 VideoCaptureDeviceFactoryMac::PlatformSupportsAVFoundation()
221 ? VideoCaptureDevice::Name::AVFOUNDATION
222 : VideoCaptureDevice::Name::QTKIT);
223 #else
224 VideoCaptureDevice::Name device_name("jibberish", "jibberish");
225 #endif
226 scoped_ptr<VideoCaptureDevice> device =
227 video_capture_device_factory_->Create(device_name);
228 #if !defined(OS_MACOSX)
229 EXPECT_TRUE(device == NULL);
230 #else
231 if (VideoCaptureDeviceFactoryMac::PlatformSupportsAVFoundation()) {
232 EXPECT_TRUE(device == NULL);
233 } else {
234 // The presence of the actual device is only checked on AllocateAndStart()
235 // and not on creation for QTKit API in Mac OS X platform.
236 EXPECT_CALL(*client_, OnErr()).Times(1);
238 VideoCaptureParams capture_params;
239 capture_params.requested_format.frame_size.SetSize(640, 480);
240 capture_params.requested_format.frame_rate = 30;
241 capture_params.requested_format.pixel_format = PIXEL_FORMAT_I420;
242 device->AllocateAndStart(capture_params, client_.Pass());
243 device->StopAndDeAllocate();
245 #endif
248 TEST_F(VideoCaptureDeviceTest, CaptureVGA) {
249 names_ = EnumerateDevices();
250 if (names_->empty()) {
251 DVLOG(1) << "No camera available. Exiting test.";
252 return;
255 scoped_ptr<VideoCaptureDevice> device(
256 video_capture_device_factory_->Create(names_->front()));
257 ASSERT_TRUE(device);
258 DVLOG(1) << names_->front().id();
260 EXPECT_CALL(*client_, OnErr()).Times(0);
262 VideoCaptureParams capture_params;
263 capture_params.requested_format.frame_size.SetSize(640, 480);
264 capture_params.requested_format.frame_rate = 30;
265 capture_params.requested_format.pixel_format = PIXEL_FORMAT_I420;
266 device->AllocateAndStart(capture_params, client_.Pass());
267 // Get captured video frames.
268 WaitForCapturedFrame();
269 EXPECT_EQ(last_format().frame_size.width(), 640);
270 EXPECT_EQ(last_format().frame_size.height(), 480);
271 device->StopAndDeAllocate();
274 TEST_F(VideoCaptureDeviceTest, Capture720p) {
275 names_ = EnumerateDevices();
276 if (names_->empty()) {
277 DVLOG(1) << "No camera available. Exiting test.";
278 return;
281 scoped_ptr<VideoCaptureDevice> device(
282 video_capture_device_factory_->Create(names_->front()));
283 ASSERT_TRUE(device);
285 EXPECT_CALL(*client_, OnErr()).Times(0);
287 VideoCaptureParams capture_params;
288 capture_params.requested_format.frame_size.SetSize(1280, 720);
289 capture_params.requested_format.frame_rate = 30;
290 capture_params.requested_format.pixel_format = PIXEL_FORMAT_I420;
291 device->AllocateAndStart(capture_params, client_.Pass());
292 // Get captured video frames.
293 WaitForCapturedFrame();
294 device->StopAndDeAllocate();
297 TEST_F(VideoCaptureDeviceTest, MAYBE_AllocateBadSize) {
298 names_ = EnumerateDevices();
299 if (names_->empty()) {
300 DVLOG(1) << "No camera available. Exiting test.";
301 return;
303 scoped_ptr<VideoCaptureDevice> device(
304 video_capture_device_factory_->Create(names_->front()));
305 ASSERT_TRUE(device);
307 EXPECT_CALL(*client_, OnErr()).Times(0);
309 VideoCaptureParams capture_params;
310 capture_params.requested_format.frame_size.SetSize(637, 472);
311 capture_params.requested_format.frame_rate = 35;
312 capture_params.requested_format.pixel_format = PIXEL_FORMAT_I420;
313 device->AllocateAndStart(capture_params, client_.Pass());
314 WaitForCapturedFrame();
315 device->StopAndDeAllocate();
316 EXPECT_EQ(last_format().frame_size.width(), 640);
317 EXPECT_EQ(last_format().frame_size.height(), 480);
320 // Cause hangs on Windows Debug. http://crbug.com/417824
321 #if defined(OS_WIN) && !defined(NDEBUG)
322 #define MAYBE_ReAllocateCamera DISABLED_ReAllocateCamera
323 #else
324 #define MAYBE_ReAllocateCamera ReAllocateCamera
325 #endif
327 TEST_F(VideoCaptureDeviceTest, MAYBE_ReAllocateCamera) {
328 names_ = EnumerateDevices();
329 if (names_->empty()) {
330 DVLOG(1) << "No camera available. Exiting test.";
331 return;
334 // First, do a number of very fast device start/stops.
335 for (int i = 0; i <= 5; i++) {
336 ResetWithNewClient();
337 scoped_ptr<VideoCaptureDevice> device(
338 video_capture_device_factory_->Create(names_->front()));
339 gfx::Size resolution;
340 if (i % 2) {
341 resolution = gfx::Size(640, 480);
342 } else {
343 resolution = gfx::Size(1280, 1024);
345 VideoCaptureParams capture_params;
346 capture_params.requested_format.frame_size = resolution;
347 capture_params.requested_format.frame_rate = 30;
348 capture_params.requested_format.pixel_format = PIXEL_FORMAT_I420;
349 device->AllocateAndStart(capture_params, client_.Pass());
350 device->StopAndDeAllocate();
353 // Finally, do a device start and wait for it to finish.
354 VideoCaptureParams capture_params;
355 capture_params.requested_format.frame_size.SetSize(320, 240);
356 capture_params.requested_format.frame_rate = 30;
357 capture_params.requested_format.pixel_format = PIXEL_FORMAT_I420;
359 ResetWithNewClient();
360 scoped_ptr<VideoCaptureDevice> device(
361 video_capture_device_factory_->Create(names_->front()));
363 device->AllocateAndStart(capture_params, client_.Pass());
364 WaitForCapturedFrame();
365 device->StopAndDeAllocate();
366 device.reset();
367 EXPECT_EQ(last_format().frame_size.width(), 320);
368 EXPECT_EQ(last_format().frame_size.height(), 240);
371 TEST_F(VideoCaptureDeviceTest, DeAllocateCameraWhileRunning) {
372 names_ = EnumerateDevices();
373 if (names_->empty()) {
374 DVLOG(1) << "No camera available. Exiting test.";
375 return;
377 scoped_ptr<VideoCaptureDevice> device(
378 video_capture_device_factory_->Create(names_->front()));
379 ASSERT_TRUE(device);
381 EXPECT_CALL(*client_, OnErr()).Times(0);
383 VideoCaptureParams capture_params;
384 capture_params.requested_format.frame_size.SetSize(640, 480);
385 capture_params.requested_format.frame_rate = 30;
386 capture_params.requested_format.pixel_format = PIXEL_FORMAT_I420;
387 device->AllocateAndStart(capture_params, client_.Pass());
388 // Get captured video frames.
389 WaitForCapturedFrame();
390 EXPECT_EQ(last_format().frame_size.width(), 640);
391 EXPECT_EQ(last_format().frame_size.height(), 480);
392 EXPECT_EQ(last_format().frame_rate, 30);
393 device->StopAndDeAllocate();
396 // Start the camera in 720p to capture MJPEG instead of a raw format.
397 TEST_F(VideoCaptureDeviceTest, MAYBE_CaptureMjpeg) {
398 scoped_ptr<VideoCaptureDevice::Name> name =
399 GetFirstDeviceNameSupportingPixelFormat(PIXEL_FORMAT_MJPEG);
400 if (!name) {
401 DVLOG(1) << "No camera supports MJPEG format. Exiting test.";
402 return;
404 scoped_ptr<VideoCaptureDevice> device(
405 video_capture_device_factory_->Create(*name));
406 ASSERT_TRUE(device);
408 EXPECT_CALL(*client_, OnErr()).Times(0);
410 VideoCaptureParams capture_params;
411 capture_params.requested_format.frame_size.SetSize(1280, 720);
412 capture_params.requested_format.frame_rate = 30;
413 capture_params.requested_format.pixel_format = PIXEL_FORMAT_MJPEG;
414 device->AllocateAndStart(capture_params, client_.Pass());
415 // Get captured video frames.
416 WaitForCapturedFrame();
417 // Verify we get MJPEG from the device. Not all devices can capture 1280x720
418 // @ 30 fps, so we don't care about the exact resolution we get.
419 EXPECT_EQ(last_format().pixel_format, PIXEL_FORMAT_MJPEG);
420 device->StopAndDeAllocate();
423 TEST_F(VideoCaptureDeviceTest, GetDeviceSupportedFormats) {
424 // Use PIXEL_FORMAT_MAX to iterate all device names for testing
425 // GetDeviceSupportedFormats().
426 scoped_ptr<VideoCaptureDevice::Name> name =
427 GetFirstDeviceNameSupportingPixelFormat(PIXEL_FORMAT_MAX);
428 // Verify no camera returned for PIXEL_FORMAT_MAX. Nothing else to test here
429 // since we cannot forecast the hardware capabilities.
430 ASSERT_FALSE(name);
433 }; // namespace media