• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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