[Session restore] Rename group name Enabled to Restore.
[chromium-blink-merge.git] / content / browser / renderer_host / media / video_capture_controller_unittest.cc
blob7e8f055aa130e36147e4dcf337ed678cc0698622
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 // Unit test for VideoCaptureController.
7 #include <string>
9 #include "base/bind.h"
10 #include "base/bind_helpers.h"
11 #include "base/memory/ref_counted.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/message_loop/message_loop.h"
14 #include "base/run_loop.h"
15 #include "content/browser/renderer_host/media/media_stream_provider.h"
16 #include "content/browser/renderer_host/media/video_capture_controller.h"
17 #include "content/browser/renderer_host/media/video_capture_controller_event_handler.h"
18 #include "content/browser/renderer_host/media/video_capture_manager.h"
19 #include "content/common/gpu/client/gl_helper.h"
20 #include "content/common/media/media_stream_options.h"
21 #include "content/public/test/test_browser_thread_bundle.h"
22 #include "gpu/command_buffer/common/mailbox_holder.h"
23 #include "media/base/video_capture_types.h"
24 #include "media/base/video_util.h"
25 #include "testing/gmock/include/gmock/gmock.h"
26 #include "testing/gtest/include/gtest/gtest.h"
28 #if !defined(OS_ANDROID)
29 #include "content/browser/compositor/test/no_transport_image_transport_factory.h"
30 #endif
32 using ::testing::_;
33 using ::testing::InSequence;
34 using ::testing::Mock;
35 using ::testing::SaveArg;
37 namespace content {
39 class MockVideoCaptureControllerEventHandler
40 : public VideoCaptureControllerEventHandler {
41 public:
42 explicit MockVideoCaptureControllerEventHandler(
43 VideoCaptureController* controller)
44 : controller_(controller) {}
45 virtual ~MockVideoCaptureControllerEventHandler() {}
47 // These mock methods are delegated to by our fake implementation of
48 // VideoCaptureControllerEventHandler, to be used in EXPECT_CALL().
49 MOCK_METHOD1(DoBufferCreated, void(VideoCaptureControllerID));
50 MOCK_METHOD1(DoBufferDestroyed, void(VideoCaptureControllerID));
51 MOCK_METHOD2(DoBufferReady, void(VideoCaptureControllerID, const gfx::Size&));
52 MOCK_METHOD1(DoMailboxBufferReady, void(VideoCaptureControllerID));
53 MOCK_METHOD1(DoEnded, void(VideoCaptureControllerID));
54 MOCK_METHOD1(DoError, void(VideoCaptureControllerID));
56 virtual void OnError(VideoCaptureControllerID id) override {
57 DoError(id);
59 virtual void OnBufferCreated(VideoCaptureControllerID id,
60 base::SharedMemoryHandle handle,
61 int length, int buffer_id) override {
62 DoBufferCreated(id);
64 virtual void OnBufferDestroyed(VideoCaptureControllerID id,
65 int buffer_id) override {
66 DoBufferDestroyed(id);
68 virtual void OnBufferReady(
69 VideoCaptureControllerID id,
70 int buffer_id,
71 const gfx::Size& coded_size,
72 const gfx::Rect& visible_rect,
73 const base::TimeTicks& timestamp,
74 scoped_ptr<base::DictionaryValue> metadata) override {
75 DoBufferReady(id, coded_size);
76 base::MessageLoop::current()->PostTask(
77 FROM_HERE,
78 base::Bind(&VideoCaptureController::ReturnBuffer,
79 base::Unretained(controller_),
80 id,
81 this,
82 buffer_id,
83 0));
85 virtual void OnMailboxBufferReady(
86 VideoCaptureControllerID id,
87 int buffer_id,
88 const gpu::MailboxHolder& mailbox_holder,
89 const gfx::Size& packed_frame_size,
90 const base::TimeTicks& timestamp,
91 scoped_ptr<base::DictionaryValue> metadata) override {
92 DoMailboxBufferReady(id);
93 base::MessageLoop::current()->PostTask(
94 FROM_HERE,
95 base::Bind(&VideoCaptureController::ReturnBuffer,
96 base::Unretained(controller_),
97 id,
98 this,
99 buffer_id,
100 mailbox_holder.sync_point));
102 virtual void OnEnded(VideoCaptureControllerID id) override {
103 DoEnded(id);
104 // OnEnded() must respond by (eventually) unregistering the client.
105 base::MessageLoop::current()->PostTask(FROM_HERE,
106 base::Bind(base::IgnoreResult(&VideoCaptureController::RemoveClient),
107 base::Unretained(controller_), id, this));
110 VideoCaptureController* controller_;
113 // Test class.
114 class VideoCaptureControllerTest : public testing::Test {
115 public:
116 VideoCaptureControllerTest() {}
117 ~VideoCaptureControllerTest() override {}
119 protected:
120 static const int kPoolSize = 3;
122 void SetUp() override {
123 controller_.reset(new VideoCaptureController(kPoolSize));
124 device_ = controller_->NewDeviceClient(
125 base::MessageLoopProxy::current(),
126 controller_->GetVideoCaptureFormat());
127 client_a_.reset(new MockVideoCaptureControllerEventHandler(
128 controller_.get()));
129 client_b_.reset(new MockVideoCaptureControllerEventHandler(
130 controller_.get()));
133 void TearDown() override { base::RunLoop().RunUntilIdle(); }
135 scoped_refptr<media::VideoFrame> WrapI420Buffer(
136 const scoped_refptr<media::VideoCaptureDevice::Client::Buffer>& buffer,
137 gfx::Size dimensions) {
138 return media::VideoFrame::WrapExternalPackedMemory(
139 media::VideoFrame::I420,
140 dimensions,
141 gfx::Rect(dimensions),
142 dimensions,
143 reinterpret_cast<uint8*>(buffer->data()),
144 media::VideoFrame::AllocationSize(media::VideoFrame::I420, dimensions),
145 base::SharedMemory::NULLHandle(),
147 base::TimeDelta(),
148 base::Closure());
151 scoped_refptr<media::VideoFrame> WrapMailboxBuffer(
152 scoped_ptr<gpu::MailboxHolder> holder,
153 const media::VideoFrame::ReleaseMailboxCB& release_cb,
154 gfx::Size dimensions) {
155 return media::VideoFrame::WrapNativeTexture(
156 holder.Pass(), release_cb, dimensions, gfx::Rect(dimensions),
157 dimensions, base::TimeDelta(), false);
160 TestBrowserThreadBundle bundle_;
161 scoped_ptr<MockVideoCaptureControllerEventHandler> client_a_;
162 scoped_ptr<MockVideoCaptureControllerEventHandler> client_b_;
163 scoped_ptr<VideoCaptureController> controller_;
164 scoped_ptr<media::VideoCaptureDevice::Client> device_;
166 private:
167 DISALLOW_COPY_AND_ASSIGN(VideoCaptureControllerTest);
170 // A simple test of VideoCaptureController's ability to add, remove, and keep
171 // track of clients.
172 TEST_F(VideoCaptureControllerTest, AddAndRemoveClients) {
173 media::VideoCaptureParams session_100;
174 session_100.requested_format = media::VideoCaptureFormat(
175 gfx::Size(320, 240), 30, media::PIXEL_FORMAT_I420);
176 media::VideoCaptureParams session_200 = session_100;
178 media::VideoCaptureParams session_300 = session_100;
180 media::VideoCaptureParams session_400 = session_100;
182 // Intentionally use the same route ID for two of the clients: the device_ids
183 // are a per-VideoCaptureHost namespace, and can overlap across hosts.
184 const VideoCaptureControllerID client_a_route_1(44);
185 const VideoCaptureControllerID client_a_route_2(30);
186 const VideoCaptureControllerID client_b_route_1(30);
187 const VideoCaptureControllerID client_b_route_2(1);
189 // Clients in controller: []
190 ASSERT_EQ(0, controller_->GetClientCount())
191 << "Client count should initially be zero.";
192 controller_->AddClient(client_a_route_1,
193 client_a_.get(),
194 base::kNullProcessHandle,
195 100,
196 session_100);
197 // Clients in controller: [A/1]
198 ASSERT_EQ(1, controller_->GetClientCount())
199 << "Adding client A/1 should bump client count.";
200 controller_->AddClient(client_a_route_2,
201 client_a_.get(),
202 base::kNullProcessHandle,
203 200,
204 session_200);
205 // Clients in controller: [A/1, A/2]
206 ASSERT_EQ(2, controller_->GetClientCount())
207 << "Adding client A/2 should bump client count.";
208 controller_->AddClient(client_b_route_1,
209 client_b_.get(),
210 base::kNullProcessHandle,
211 300,
212 session_300);
213 // Clients in controller: [A/1, A/2, B/1]
214 ASSERT_EQ(3, controller_->GetClientCount())
215 << "Adding client B/1 should bump client count.";
216 ASSERT_EQ(200,
217 controller_->RemoveClient(client_a_route_2, client_a_.get()))
218 << "Removing client A/1 should return its session_id.";
219 // Clients in controller: [A/1, B/1]
220 ASSERT_EQ(2, controller_->GetClientCount());
221 ASSERT_EQ(static_cast<int>(kInvalidMediaCaptureSessionId),
222 controller_->RemoveClient(client_a_route_2, client_a_.get()))
223 << "Removing a nonexistant client should fail.";
224 // Clients in controller: [A/1, B/1]
225 ASSERT_EQ(2, controller_->GetClientCount());
226 ASSERT_EQ(300,
227 controller_->RemoveClient(client_b_route_1, client_b_.get()))
228 << "Removing client B/1 should return its session_id.";
229 // Clients in controller: [A/1]
230 ASSERT_EQ(1, controller_->GetClientCount());
231 controller_->AddClient(client_b_route_2,
232 client_b_.get(),
233 base::kNullProcessHandle,
234 400,
235 session_400);
236 // Clients in controller: [A/1, B/2]
238 EXPECT_CALL(*client_a_, DoEnded(client_a_route_1)).Times(1);
239 controller_->StopSession(100); // Session 100 == client A/1
240 Mock::VerifyAndClearExpectations(client_a_.get());
241 ASSERT_EQ(2, controller_->GetClientCount())
242 << "Client should be closed but still exist after StopSession.";
243 // Clients in controller: [A/1 (closed, removal pending), B/2]
244 base::RunLoop().RunUntilIdle();
245 // Clients in controller: [B/2]
246 ASSERT_EQ(1, controller_->GetClientCount())
247 << "Client A/1 should be deleted by now.";
248 controller_->StopSession(200); // Session 200 does not exist anymore
249 // Clients in controller: [B/2]
250 ASSERT_EQ(1, controller_->GetClientCount())
251 << "Stopping non-existant session 200 should be a no-op.";
252 controller_->StopSession(256); // Session 256 never existed.
253 // Clients in controller: [B/2]
254 ASSERT_EQ(1, controller_->GetClientCount())
255 << "Stopping non-existant session 256 should be a no-op.";
256 ASSERT_EQ(static_cast<int>(kInvalidMediaCaptureSessionId),
257 controller_->RemoveClient(client_a_route_1, client_a_.get()))
258 << "Removing already-removed client A/1 should fail.";
259 // Clients in controller: [B/2]
260 ASSERT_EQ(1, controller_->GetClientCount())
261 << "Removing non-existant session 200 should be a no-op.";
262 ASSERT_EQ(400,
263 controller_->RemoveClient(client_b_route_2, client_b_.get()))
264 << "Removing client B/2 should return its session_id.";
265 // Clients in controller: []
266 ASSERT_EQ(0, controller_->GetClientCount())
267 << "Client count should return to zero after all clients are gone.";
270 static void CacheSyncPoint(uint32* called_release_sync_point,
271 uint32 release_sync_point) {
272 *called_release_sync_point = release_sync_point;
275 // This test will connect and disconnect several clients while simulating an
276 // active capture device being started and generating frames. It runs on one
277 // thread and is intended to behave deterministically.
278 TEST_F(VideoCaptureControllerTest, NormalCaptureMultipleClients) {
279 // VideoCaptureController::ReturnBuffer() uses ImageTransportFactory.
280 #if !defined(OS_ANDROID)
281 ImageTransportFactory::InitializeForUnitTests(
282 scoped_ptr<ImageTransportFactory>(new NoTransportImageTransportFactory));
283 #endif
285 media::VideoCaptureParams session_100;
286 session_100.requested_format = media::VideoCaptureFormat(
287 gfx::Size(320, 240), 30, media::PIXEL_FORMAT_I420);
289 media::VideoCaptureParams session_200 = session_100;
291 media::VideoCaptureParams session_300 = session_100;
293 media::VideoCaptureParams session_1 = session_100;
295 const gfx::Size capture_resolution(444, 200);
297 // The device format needn't match the VideoCaptureParams (the camera can do
298 // what it wants). Pick something random.
299 media::VideoCaptureFormat device_format(
300 gfx::Size(10, 10), 25, media::PIXEL_FORMAT_RGB24);
302 const VideoCaptureControllerID client_a_route_1(0xa1a1a1a1);
303 const VideoCaptureControllerID client_a_route_2(0xa2a2a2a2);
304 const VideoCaptureControllerID client_b_route_1(0xb1b1b1b1);
305 const VideoCaptureControllerID client_b_route_2(0xb2b2b2b2);
307 // Start with two clients.
308 controller_->AddClient(client_a_route_1,
309 client_a_.get(),
310 base::kNullProcessHandle,
311 100,
312 session_100);
313 controller_->AddClient(client_b_route_1,
314 client_b_.get(),
315 base::kNullProcessHandle,
316 300,
317 session_300);
318 controller_->AddClient(client_a_route_2,
319 client_a_.get(),
320 base::kNullProcessHandle,
321 200,
322 session_200);
323 ASSERT_EQ(3, controller_->GetClientCount());
325 // Now, simulate an incoming captured buffer from the capture device. As a
326 // side effect this will cause the first buffer to be shared with clients.
327 uint8 buffer_no = 1;
328 scoped_refptr<media::VideoCaptureDevice::Client::Buffer> buffer;
329 buffer =
330 device_->ReserveOutputBuffer(media::VideoFrame::I420, capture_resolution);
331 ASSERT_TRUE(buffer.get());
332 memset(buffer->data(), buffer_no++, buffer->size());
334 InSequence s;
335 EXPECT_CALL(*client_a_, DoBufferCreated(client_a_route_1)).Times(1);
336 EXPECT_CALL(*client_a_, DoBufferReady(client_a_route_1,_)).Times(1);
339 InSequence s;
340 EXPECT_CALL(*client_b_, DoBufferCreated(client_b_route_1)).Times(1);
341 EXPECT_CALL(*client_b_, DoBufferReady(client_b_route_1,_)).Times(1);
344 InSequence s;
345 EXPECT_CALL(*client_a_, DoBufferCreated(client_a_route_2)).Times(1);
346 EXPECT_CALL(*client_a_, DoBufferReady(client_a_route_2,_)).Times(1);
348 device_->OnIncomingCapturedVideoFrame(
349 buffer,
350 WrapI420Buffer(buffer, capture_resolution),
351 base::TimeTicks());
352 buffer = NULL;
354 base::RunLoop().RunUntilIdle();
355 Mock::VerifyAndClearExpectations(client_a_.get());
356 Mock::VerifyAndClearExpectations(client_b_.get());
358 // Second buffer which ought to use the same shared memory buffer. In this
359 // case pretend that the Buffer pointer is held by the device for a long
360 // delay. This shouldn't affect anything.
361 buffer =
362 device_->ReserveOutputBuffer(media::VideoFrame::I420, capture_resolution);
363 ASSERT_TRUE(buffer.get());
364 memset(buffer->data(), buffer_no++, buffer->size());
365 device_->OnIncomingCapturedVideoFrame(
366 buffer,
367 WrapI420Buffer(buffer, capture_resolution),
368 base::TimeTicks());
369 buffer = NULL;
371 // The buffer should be delivered to the clients in any order.
372 EXPECT_CALL(*client_a_, DoBufferReady(client_a_route_1,_)).Times(1);
373 EXPECT_CALL(*client_b_, DoBufferReady(client_b_route_1,_)).Times(1);
374 EXPECT_CALL(*client_a_, DoBufferReady(client_a_route_2,_)).Times(1);
375 base::RunLoop().RunUntilIdle();
376 Mock::VerifyAndClearExpectations(client_a_.get());
377 Mock::VerifyAndClearExpectations(client_b_.get());
379 // Add a fourth client now that some buffers have come through.
380 controller_->AddClient(client_b_route_2,
381 client_b_.get(),
382 base::kNullProcessHandle,
384 session_1);
385 Mock::VerifyAndClearExpectations(client_b_.get());
387 // Third, fourth, and fifth buffers. Pretend they all arrive at the same time.
388 for (int i = 0; i < kPoolSize; i++) {
389 buffer = device_->ReserveOutputBuffer(media::VideoFrame::I420,
390 capture_resolution);
391 ASSERT_TRUE(buffer.get());
392 memset(buffer->data(), buffer_no++, buffer->size());
393 device_->OnIncomingCapturedVideoFrame(
394 buffer,
395 WrapI420Buffer(buffer, capture_resolution),
396 base::TimeTicks());
397 buffer = NULL;
399 // ReserveOutputBuffer ought to fail now, because the pool is depleted.
400 ASSERT_FALSE(device_->ReserveOutputBuffer(media::VideoFrame::I420,
401 capture_resolution).get());
403 // The new client needs to be told of 3 buffers; the old clients only 2.
404 EXPECT_CALL(*client_b_, DoBufferCreated(client_b_route_2)).Times(kPoolSize);
405 EXPECT_CALL(*client_b_, DoBufferReady(client_b_route_2,_)).Times(kPoolSize);
406 EXPECT_CALL(*client_a_, DoBufferCreated(client_a_route_1))
407 .Times(kPoolSize - 1);
408 EXPECT_CALL(*client_a_, DoBufferReady(client_a_route_1,_)).Times(kPoolSize);
409 EXPECT_CALL(*client_a_, DoBufferCreated(client_a_route_2))
410 .Times(kPoolSize - 1);
411 EXPECT_CALL(*client_a_, DoBufferReady(client_a_route_2,_)).Times(kPoolSize);
412 EXPECT_CALL(*client_b_, DoBufferCreated(client_b_route_1))
413 .Times(kPoolSize - 1);
414 EXPECT_CALL(*client_b_, DoBufferReady(client_b_route_1,_)).Times(kPoolSize);
415 base::RunLoop().RunUntilIdle();
416 Mock::VerifyAndClearExpectations(client_a_.get());
417 Mock::VerifyAndClearExpectations(client_b_.get());
419 // Now test the interaction of client shutdown and buffer delivery.
420 // Kill A1 via renderer disconnect (synchronous).
421 controller_->RemoveClient(client_a_route_1, client_a_.get());
422 // Kill B1 via session close (posts a task to disconnect).
423 EXPECT_CALL(*client_b_, DoEnded(client_b_route_1)).Times(1);
424 controller_->StopSession(300);
425 // Queue up another buffer.
426 buffer =
427 device_->ReserveOutputBuffer(media::VideoFrame::I420, capture_resolution);
428 ASSERT_TRUE(buffer.get());
429 memset(buffer->data(), buffer_no++, buffer->size());
430 device_->OnIncomingCapturedVideoFrame(
431 buffer,
432 WrapI420Buffer(buffer, capture_resolution),
433 base::TimeTicks());
434 buffer = NULL;
435 buffer =
436 device_->ReserveOutputBuffer(media::VideoFrame::I420, capture_resolution);
438 // Kill A2 via session close (posts a task to disconnect, but A2 must not
439 // be sent either of these two buffers).
440 EXPECT_CALL(*client_a_, DoEnded(client_a_route_2)).Times(1);
441 controller_->StopSession(200);
443 ASSERT_TRUE(buffer.get());
444 memset(buffer->data(), buffer_no++, buffer->size());
445 device_->OnIncomingCapturedVideoFrame(
446 buffer,
447 WrapI420Buffer(buffer, capture_resolution),
448 base::TimeTicks());
449 buffer = NULL;
450 // B2 is the only client left, and is the only one that should
451 // get the buffer.
452 EXPECT_CALL(*client_b_, DoBufferReady(client_b_route_2,_)).Times(2);
453 base::RunLoop().RunUntilIdle();
454 Mock::VerifyAndClearExpectations(client_a_.get());
455 Mock::VerifyAndClearExpectations(client_b_.get());
457 // Allocate all buffers from the buffer pool, half as SHM buffer and half as
458 // mailbox buffers. Make sure of different counts though.
459 #if defined(OS_ANDROID)
460 int mailbox_buffers = 0;
461 #else
462 int mailbox_buffers = kPoolSize / 2;
463 GLHelper* gl_helper = ImageTransportFactory::GetInstance()->GetGLHelper();
464 #endif
465 int shm_buffers = kPoolSize - mailbox_buffers;
466 if (shm_buffers == mailbox_buffers) {
467 shm_buffers--;
468 mailbox_buffers++;
471 for (int i = 0; i < shm_buffers; ++i) {
472 buffer = device_->ReserveOutputBuffer(media::VideoFrame::I420,
473 capture_resolution);
474 ASSERT_TRUE(buffer.get());
475 device_->OnIncomingCapturedVideoFrame(
476 buffer,
477 WrapI420Buffer(buffer, capture_resolution),
478 base::TimeTicks());
479 buffer = NULL;
481 std::vector<uint32> mailbox_syncpoints(mailbox_buffers);
482 std::vector<uint32> release_syncpoints(mailbox_buffers);
483 for (int i = 0; i < mailbox_buffers; ++i) {
484 buffer = device_->ReserveOutputBuffer(media::VideoFrame::NATIVE_TEXTURE,
485 gfx::Size(0, 0));
486 ASSERT_TRUE(buffer.get());
487 #if !defined(OS_ANDROID)
488 mailbox_syncpoints[i] = gl_helper->InsertSyncPoint();
489 #endif
490 device_->OnIncomingCapturedVideoFrame(
491 buffer,
492 WrapMailboxBuffer(make_scoped_ptr(new gpu::MailboxHolder(
493 gpu::Mailbox(), 0, mailbox_syncpoints[i])),
494 base::Bind(&CacheSyncPoint, &release_syncpoints[i]),
495 capture_resolution),
496 base::TimeTicks());
497 buffer = NULL;
499 // ReserveOutputBuffers ought to fail now regardless of buffer format, because
500 // the pool is depleted.
501 ASSERT_FALSE(device_->ReserveOutputBuffer(media::VideoFrame::I420,
502 capture_resolution).get());
503 ASSERT_FALSE(device_->ReserveOutputBuffer(media::VideoFrame::NATIVE_TEXTURE,
504 gfx::Size(0, 0)).get());
505 EXPECT_CALL(*client_b_, DoBufferReady(client_b_route_2,_)).Times(shm_buffers);
506 EXPECT_CALL(*client_b_, DoMailboxBufferReady(client_b_route_2))
507 .Times(mailbox_buffers);
508 base::RunLoop().RunUntilIdle();
509 for (size_t i = 0; i < mailbox_syncpoints.size(); ++i) {
510 // A new release sync point must be inserted when the video frame is
511 // returned to the Browser process.
512 // See: MockVideoCaptureControllerEventHandler::OnMailboxBufferReady() and
513 // VideoCaptureController::ReturnBuffer()
514 ASSERT_NE(mailbox_syncpoints[i], release_syncpoints[i]);
516 Mock::VerifyAndClearExpectations(client_b_.get());
518 #if !defined(OS_ANDROID)
519 ImageTransportFactory::Terminate();
520 #endif
523 // Exercises the OnError() codepath of VideoCaptureController, and tests the
524 // behavior of various operations after the error state has been signalled.
525 TEST_F(VideoCaptureControllerTest, ErrorBeforeDeviceCreation) {
526 media::VideoCaptureParams session_100;
527 session_100.requested_format = media::VideoCaptureFormat(
528 gfx::Size(320, 240), 30, media::PIXEL_FORMAT_I420);
530 media::VideoCaptureParams session_200 = session_100;
532 const gfx::Size capture_resolution(320, 240);
534 const VideoCaptureControllerID route_id(0x99);
536 // Start with one client.
537 controller_->AddClient(
538 route_id, client_a_.get(), base::kNullProcessHandle, 100, session_100);
539 device_->OnError("Test Error");
540 EXPECT_CALL(*client_a_, DoError(route_id)).Times(1);
541 base::RunLoop().RunUntilIdle();
542 Mock::VerifyAndClearExpectations(client_a_.get());
544 // Second client connects after the error state. It also should get told of
545 // the error.
546 EXPECT_CALL(*client_b_, DoError(route_id)).Times(1);
547 controller_->AddClient(
548 route_id, client_b_.get(), base::kNullProcessHandle, 200, session_200);
549 base::RunLoop().RunUntilIdle();
550 Mock::VerifyAndClearExpectations(client_b_.get());
552 scoped_refptr<media::VideoCaptureDevice::Client::Buffer> buffer =
553 device_->ReserveOutputBuffer(media::VideoFrame::I420, capture_resolution);
554 ASSERT_TRUE(buffer.get());
556 device_->OnIncomingCapturedVideoFrame(
557 buffer,
558 WrapI420Buffer(buffer, capture_resolution),
559 base::TimeTicks());
560 buffer = NULL;
562 base::RunLoop().RunUntilIdle();
565 // Exercises the OnError() codepath of VideoCaptureController, and tests the
566 // behavior of various operations after the error state has been signalled.
567 TEST_F(VideoCaptureControllerTest, ErrorAfterDeviceCreation) {
568 media::VideoCaptureParams session_100;
569 session_100.requested_format = media::VideoCaptureFormat(
570 gfx::Size(320, 240), 30, media::PIXEL_FORMAT_I420);
572 media::VideoCaptureParams session_200 = session_100;
574 const VideoCaptureControllerID route_id(0x99);
576 // Start with one client.
577 controller_->AddClient(
578 route_id, client_a_.get(), base::kNullProcessHandle, 100, session_100);
579 media::VideoCaptureFormat device_format(
580 gfx::Size(10, 10), 25, media::PIXEL_FORMAT_ARGB);
582 // Start the device. Then, before the first buffer, signal an error and
583 // deliver the buffer. The error should be propagated to clients; the buffer
584 // should not be.
585 base::RunLoop().RunUntilIdle();
586 Mock::VerifyAndClearExpectations(client_a_.get());
588 const gfx::Size dims(320, 240);
589 scoped_refptr<media::VideoCaptureDevice::Client::Buffer> buffer =
590 device_->ReserveOutputBuffer(media::VideoFrame::I420, dims);
591 ASSERT_TRUE(buffer.get());
593 device_->OnError("Test error");
594 device_->OnIncomingCapturedVideoFrame(
595 buffer,
596 WrapI420Buffer(buffer, dims),
597 base::TimeTicks());
598 buffer = NULL;
600 EXPECT_CALL(*client_a_, DoError(route_id)).Times(1);
601 base::RunLoop().RunUntilIdle();
602 Mock::VerifyAndClearExpectations(client_a_.get());
604 // Second client connects after the error state. It also should get told of
605 // the error.
606 EXPECT_CALL(*client_b_, DoError(route_id)).Times(1);
607 controller_->AddClient(
608 route_id, client_b_.get(), base::kNullProcessHandle, 200, session_200);
609 Mock::VerifyAndClearExpectations(client_b_.get());
612 // Tests that buffer-based capture API accepts all memory-backed pixel formats.
613 TEST_F(VideoCaptureControllerTest, DataCaptureInEachVideoFormatInSequence) {
614 // The usual ReserveOutputBuffer() -> OnIncomingCapturedVideoFrame() cannot
615 // be used since it does not accept all pixel formats. The memory backed
616 // buffer OnIncomingCapturedData() is used instead, with a dummy scratchpad
617 // buffer.
618 const size_t kScratchpadSizeInBytes = 400;
619 unsigned char data[kScratchpadSizeInBytes];
620 const gfx::Size capture_resolution(10, 10);
621 ASSERT_GE(kScratchpadSizeInBytes, capture_resolution.GetArea() * 4u)
622 << "Scratchpad is too small to hold the largest pixel format (ARGB).";
624 const int kSessionId = 100;
625 // This Test skips PIXEL_FORMAT_TEXTURE and PIXEL_FORMAT_UNKNOWN.
626 for (int format = 0; format < media::PIXEL_FORMAT_TEXTURE; ++format) {
627 media::VideoCaptureParams params;
628 params.requested_format = media::VideoCaptureFormat(
629 capture_resolution, 30, media::VideoPixelFormat(format));
631 // Start with one client.
632 const VideoCaptureControllerID route_id(0x99);
633 controller_->AddClient(route_id,
634 client_a_.get(),
635 base::kNullProcessHandle,
636 kSessionId,
637 params);
638 ASSERT_EQ(1, controller_->GetClientCount());
639 device_->OnIncomingCapturedData(
640 data,
641 params.requested_format.ImageAllocationSize(),
642 params.requested_format,
643 0 /* clockwise_rotation */,
644 base::TimeTicks());
645 EXPECT_EQ(kSessionId, controller_->RemoveClient(route_id, client_a_.get()));
646 Mock::VerifyAndClearExpectations(client_a_.get());
650 // Test that we receive the expected resolution for a given captured frame
651 // resolution and rotation. Odd resolutions are also cropped.
652 TEST_F(VideoCaptureControllerTest, CheckRotationsAndCrops) {
653 const int kSessionId = 100;
654 const struct SizeAndRotation {
655 gfx::Size input_resolution;
656 int rotation;
657 gfx::Size output_resolution;
658 } kSizeAndRotations[] = {{{6, 4}, 0, {6, 4}},
659 {{6, 4}, 90, {4, 6}},
660 {{6, 4}, 180, {6, 4}},
661 {{6, 4}, 270, {4, 6}},
662 {{7, 4}, 0, {6, 4}},
663 {{7, 4}, 90, {4, 6}},
664 {{7, 4}, 180, {6, 4}},
665 {{7, 4}, 270, {4, 6}}};
666 // The usual ReserveOutputBuffer() -> OnIncomingCapturedVideoFrame() cannot
667 // be used since it does not resolve rotations or crops. The memory backed
668 // buffer OnIncomingCapturedData() is used instead, with a dummy scratchpad
669 // buffer.
670 const size_t kScratchpadSizeInBytes = 400;
671 unsigned char data[kScratchpadSizeInBytes] = {};
673 media::VideoCaptureParams params;
674 for (const auto& size_and_rotation : kSizeAndRotations) {
675 ASSERT_GE(kScratchpadSizeInBytes,
676 size_and_rotation.input_resolution.GetArea() * 4u)
677 << "Scratchpad is too small to hold the largest pixel format (ARGB).";
679 params.requested_format = media::VideoCaptureFormat(
680 size_and_rotation.input_resolution, 30, media::PIXEL_FORMAT_ARGB);
682 const VideoCaptureControllerID route_id(0x99);
683 controller_->AddClient(route_id, client_a_.get(), base::kNullProcessHandle,
684 kSessionId, params);
685 ASSERT_EQ(1, controller_->GetClientCount());
687 device_->OnIncomingCapturedData(
688 data,
689 params.requested_format.ImageAllocationSize(),
690 params.requested_format,
691 size_and_rotation.rotation,
692 base::TimeTicks());
693 gfx::Size coded_size;
695 InSequence s;
696 EXPECT_CALL(*client_a_, DoBufferCreated(route_id)).Times(1);
697 EXPECT_CALL(*client_a_, DoBufferReady(route_id, _))
698 .Times(1)
699 .WillOnce(SaveArg<1>(&coded_size));
701 base::RunLoop().RunUntilIdle();
703 EXPECT_EQ(coded_size.width(), size_and_rotation.output_resolution.width());
704 EXPECT_EQ(coded_size.height(),
705 size_and_rotation.output_resolution.height());
707 EXPECT_EQ(kSessionId, controller_->RemoveClient(route_id, client_a_.get()));
708 Mock::VerifyAndClearExpectations(client_a_.get());
712 } // namespace content