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.
10 #include "base/bind_helpers.h"
11 #include "base/location.h"
12 #include "base/memory/ref_counted.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "base/run_loop.h"
15 #include "base/single_thread_task_runner.h"
16 #include "base/thread_task_runner_handle.h"
17 #include "content/browser/renderer_host/media/media_stream_provider.h"
18 #include "content/browser/renderer_host/media/video_capture_controller.h"
19 #include "content/browser/renderer_host/media/video_capture_controller_event_handler.h"
20 #include "content/browser/renderer_host/media/video_capture_manager.h"
21 #include "content/common/gpu/client/gl_helper.h"
22 #include "content/common/media/media_stream_options.h"
23 #include "content/public/test/test_browser_thread_bundle.h"
24 #include "gpu/command_buffer/common/mailbox_holder.h"
25 #include "media/base/video_capture_types.h"
26 #include "media/base/video_frame_metadata.h"
27 #include "media/base/video_util.h"
28 #include "testing/gmock/include/gmock/gmock.h"
29 #include "testing/gtest/include/gtest/gtest.h"
31 #if !defined(OS_ANDROID)
32 #include "content/browser/compositor/test/no_transport_image_transport_factory.h"
36 using ::testing::InSequence
;
37 using ::testing::Mock
;
38 using ::testing::SaveArg
;
42 class MockVideoCaptureControllerEventHandler
43 : public VideoCaptureControllerEventHandler
{
45 explicit MockVideoCaptureControllerEventHandler(
46 VideoCaptureController
* controller
)
47 : controller_(controller
),
48 resource_utilization_(-1.0) {}
49 ~MockVideoCaptureControllerEventHandler() override
{}
51 // These mock methods are delegated to by our fake implementation of
52 // VideoCaptureControllerEventHandler, to be used in EXPECT_CALL().
53 MOCK_METHOD1(DoBufferCreated
, void(VideoCaptureControllerID
));
54 MOCK_METHOD1(DoBufferCreated2
, void(VideoCaptureControllerID
));
55 MOCK_METHOD1(DoBufferDestroyed
, void(VideoCaptureControllerID
));
56 MOCK_METHOD2(DoI420BufferReady
,
57 void(VideoCaptureControllerID
, const gfx::Size
&));
58 MOCK_METHOD2(DoTextureBufferReady
,
59 void(VideoCaptureControllerID
, const gfx::Size
&));
60 MOCK_METHOD1(DoEnded
, void(VideoCaptureControllerID
));
61 MOCK_METHOD1(DoError
, void(VideoCaptureControllerID
));
63 void OnError(VideoCaptureControllerID id
) override
{
66 void OnBufferCreated(VideoCaptureControllerID id
,
67 base::SharedMemoryHandle handle
,
68 int length
, int buffer_id
) override
{
71 void OnBufferCreated2(
72 VideoCaptureControllerID id
,
73 const std::vector
<gfx::GpuMemoryBufferHandle
>& handles
,
74 const gfx::Size
& size
,
75 int buffer_id
) override
{
78 void OnBufferDestroyed(VideoCaptureControllerID id
, int buffer_id
) override
{
79 DoBufferDestroyed(id
);
81 void OnBufferReady(VideoCaptureControllerID id
,
83 const scoped_refptr
<media::VideoFrame
>& frame
,
84 const base::TimeTicks
& timestamp
) override
{
85 if (!frame
->HasTextures()) {
86 EXPECT_EQ(frame
->format(), media::PIXEL_FORMAT_I420
);
87 DoI420BufferReady(id
, frame
->coded_size());
88 base::ThreadTaskRunnerHandle::Get()->PostTask(
89 FROM_HERE
, base::Bind(&VideoCaptureController::ReturnBuffer
,
90 base::Unretained(controller_
), id
, this,
91 buffer_id
, 0, resource_utilization_
));
93 EXPECT_EQ(frame
->format(), media::PIXEL_FORMAT_ARGB
);
94 DoTextureBufferReady(id
, frame
->coded_size());
95 base::ThreadTaskRunnerHandle::Get()->PostTask(
96 FROM_HERE
, base::Bind(&VideoCaptureController::ReturnBuffer
,
97 base::Unretained(controller_
), id
, this,
98 buffer_id
, frame
->mailbox_holder(0).sync_point
,
99 resource_utilization_
));
102 void OnEnded(VideoCaptureControllerID id
) override
{
104 // OnEnded() must respond by (eventually) unregistering the client.
105 base::ThreadTaskRunnerHandle::Get()->PostTask(
107 base::Bind(base::IgnoreResult(&VideoCaptureController::RemoveClient
),
108 base::Unretained(controller_
), id
, this));
111 VideoCaptureController
* controller_
;
112 double resource_utilization_
;
116 class VideoCaptureControllerTest
: public testing::Test
{
118 VideoCaptureControllerTest() {}
119 ~VideoCaptureControllerTest() override
{}
122 static const int kPoolSize
= 3;
124 void SetUp() override
{
125 controller_
.reset(new VideoCaptureController(kPoolSize
));
126 device_
= controller_
->NewDeviceClient(
127 base::ThreadTaskRunnerHandle::Get());
128 client_a_
.reset(new MockVideoCaptureControllerEventHandler(
130 client_b_
.reset(new MockVideoCaptureControllerEventHandler(
134 void TearDown() override
{ base::RunLoop().RunUntilIdle(); }
136 scoped_refptr
<media::VideoFrame
> WrapI420Buffer(gfx::Size dimensions
,
138 return media::VideoFrame::WrapExternalData(
139 media::PIXEL_FORMAT_I420
, dimensions
, gfx::Rect(dimensions
), dimensions
,
141 media::VideoFrame::AllocationSize(media::PIXEL_FORMAT_I420
, dimensions
),
145 scoped_refptr
<media::VideoFrame
> WrapMailboxBuffer(
146 const gpu::MailboxHolder
& holder
,
147 const media::VideoFrame::ReleaseMailboxCB
& release_cb
,
148 gfx::Size dimensions
) {
149 return media::VideoFrame::WrapNativeTexture(
150 media::PIXEL_FORMAT_ARGB
, holder
, release_cb
, dimensions
,
151 gfx::Rect(dimensions
), dimensions
, base::TimeDelta());
154 TestBrowserThreadBundle bundle_
;
155 scoped_ptr
<MockVideoCaptureControllerEventHandler
> client_a_
;
156 scoped_ptr
<MockVideoCaptureControllerEventHandler
> client_b_
;
157 scoped_ptr
<VideoCaptureController
> controller_
;
158 scoped_ptr
<media::VideoCaptureDevice::Client
> device_
;
161 DISALLOW_COPY_AND_ASSIGN(VideoCaptureControllerTest
);
164 // A simple test of VideoCaptureController's ability to add, remove, and keep
166 TEST_F(VideoCaptureControllerTest
, AddAndRemoveClients
) {
167 media::VideoCaptureParams session_100
;
168 session_100
.requested_format
= media::VideoCaptureFormat(
169 gfx::Size(320, 240), 30, media::PIXEL_FORMAT_I420
);
170 media::VideoCaptureParams session_200
= session_100
;
172 media::VideoCaptureParams session_300
= session_100
;
174 media::VideoCaptureParams session_400
= session_100
;
176 // Intentionally use the same route ID for two of the clients: the device_ids
177 // are a per-VideoCaptureHost namespace, and can overlap across hosts.
178 const VideoCaptureControllerID
client_a_route_1(44);
179 const VideoCaptureControllerID
client_a_route_2(30);
180 const VideoCaptureControllerID
client_b_route_1(30);
181 const VideoCaptureControllerID
client_b_route_2(1);
183 // Clients in controller: []
184 ASSERT_EQ(0, controller_
->GetClientCount())
185 << "Client count should initially be zero.";
186 controller_
->AddClient(client_a_route_1
,
188 base::kNullProcessHandle
,
191 // Clients in controller: [A/1]
192 ASSERT_EQ(1, controller_
->GetClientCount())
193 << "Adding client A/1 should bump client count.";
194 controller_
->AddClient(client_a_route_2
,
196 base::kNullProcessHandle
,
199 // Clients in controller: [A/1, A/2]
200 ASSERT_EQ(2, controller_
->GetClientCount())
201 << "Adding client A/2 should bump client count.";
202 controller_
->AddClient(client_b_route_1
,
204 base::kNullProcessHandle
,
207 // Clients in controller: [A/1, A/2, B/1]
208 ASSERT_EQ(3, controller_
->GetClientCount())
209 << "Adding client B/1 should bump client count.";
211 controller_
->RemoveClient(client_a_route_2
, client_a_
.get()))
212 << "Removing client A/1 should return its session_id.";
213 // Clients in controller: [A/1, B/1]
214 ASSERT_EQ(2, controller_
->GetClientCount());
215 ASSERT_EQ(static_cast<int>(kInvalidMediaCaptureSessionId
),
216 controller_
->RemoveClient(client_a_route_2
, client_a_
.get()))
217 << "Removing a nonexistant client should fail.";
218 // Clients in controller: [A/1, B/1]
219 ASSERT_EQ(2, controller_
->GetClientCount());
221 controller_
->RemoveClient(client_b_route_1
, client_b_
.get()))
222 << "Removing client B/1 should return its session_id.";
223 // Clients in controller: [A/1]
224 ASSERT_EQ(1, controller_
->GetClientCount());
225 controller_
->AddClient(client_b_route_2
,
227 base::kNullProcessHandle
,
230 // Clients in controller: [A/1, B/2]
232 EXPECT_CALL(*client_a_
, DoEnded(client_a_route_1
)).Times(1);
233 controller_
->StopSession(100); // Session 100 == client A/1
234 Mock::VerifyAndClearExpectations(client_a_
.get());
235 ASSERT_EQ(2, controller_
->GetClientCount())
236 << "Client should be closed but still exist after StopSession.";
237 // Clients in controller: [A/1 (closed, removal pending), B/2]
238 base::RunLoop().RunUntilIdle();
239 // Clients in controller: [B/2]
240 ASSERT_EQ(1, controller_
->GetClientCount())
241 << "Client A/1 should be deleted by now.";
242 controller_
->StopSession(200); // Session 200 does not exist anymore
243 // Clients in controller: [B/2]
244 ASSERT_EQ(1, controller_
->GetClientCount())
245 << "Stopping non-existant session 200 should be a no-op.";
246 controller_
->StopSession(256); // Session 256 never existed.
247 // Clients in controller: [B/2]
248 ASSERT_EQ(1, controller_
->GetClientCount())
249 << "Stopping non-existant session 256 should be a no-op.";
250 ASSERT_EQ(static_cast<int>(kInvalidMediaCaptureSessionId
),
251 controller_
->RemoveClient(client_a_route_1
, client_a_
.get()))
252 << "Removing already-removed client A/1 should fail.";
253 // Clients in controller: [B/2]
254 ASSERT_EQ(1, controller_
->GetClientCount())
255 << "Removing non-existant session 200 should be a no-op.";
257 controller_
->RemoveClient(client_b_route_2
, client_b_
.get()))
258 << "Removing client B/2 should return its session_id.";
259 // Clients in controller: []
260 ASSERT_EQ(0, controller_
->GetClientCount())
261 << "Client count should return to zero after all clients are gone.";
264 static void CacheSyncPoint(uint32
* called_release_sync_point
,
265 uint32 release_sync_point
) {
266 *called_release_sync_point
= release_sync_point
;
269 // This test will connect and disconnect several clients while simulating an
270 // active capture device being started and generating frames. It runs on one
271 // thread and is intended to behave deterministically.
272 TEST_F(VideoCaptureControllerTest
, NormalCaptureMultipleClients
) {
273 // VideoCaptureController::ReturnBuffer() uses ImageTransportFactory.
274 #if !defined(OS_ANDROID)
275 ImageTransportFactory::InitializeForUnitTests(
276 scoped_ptr
<ImageTransportFactory
>(new NoTransportImageTransportFactory
));
279 media::VideoCaptureParams session_100
;
280 session_100
.requested_format
= media::VideoCaptureFormat(
281 gfx::Size(320, 240), 30, media::PIXEL_FORMAT_I420
);
283 media::VideoCaptureParams session_200
= session_100
;
285 media::VideoCaptureParams session_300
= session_100
;
287 media::VideoCaptureParams session_1
= session_100
;
289 const gfx::Size
capture_resolution(444, 200);
291 // The device format needn't match the VideoCaptureParams (the camera can do
292 // what it wants). Pick something random.
293 media::VideoCaptureFormat
device_format(
294 gfx::Size(10, 10), 25, media::PIXEL_FORMAT_RGB24
);
296 const VideoCaptureControllerID
client_a_route_1(0xa1a1a1a1);
297 const VideoCaptureControllerID
client_a_route_2(0xa2a2a2a2);
298 const VideoCaptureControllerID
client_b_route_1(0xb1b1b1b1);
299 const VideoCaptureControllerID
client_b_route_2(0xb2b2b2b2);
301 // Start with two clients.
302 controller_
->AddClient(client_a_route_1
,
304 base::kNullProcessHandle
,
307 controller_
->AddClient(client_b_route_1
,
309 base::kNullProcessHandle
,
312 controller_
->AddClient(client_a_route_2
,
314 base::kNullProcessHandle
,
317 ASSERT_EQ(3, controller_
->GetClientCount());
319 // Now, simulate an incoming captured buffer from the capture device. As a
320 // side effect this will cause the first buffer to be shared with clients.
322 ASSERT_EQ(0.0, device_
->GetBufferPoolUtilization());
323 scoped_ptr
<media::VideoCaptureDevice::Client::Buffer
> buffer(
324 device_
->ReserveOutputBuffer(capture_resolution
,
325 media::PIXEL_FORMAT_I420
,
326 media::PIXEL_STORAGE_CPU
));
327 ASSERT_TRUE(buffer
.get());
328 ASSERT_EQ(1.0 / kPoolSize
, device_
->GetBufferPoolUtilization());
329 memset(buffer
->data(), buffer_no
++, buffer
->mapped_size());
332 EXPECT_CALL(*client_a_
, DoBufferCreated(client_a_route_1
)).Times(1);
333 EXPECT_CALL(*client_a_
,
334 DoI420BufferReady(client_a_route_1
, capture_resolution
))
339 EXPECT_CALL(*client_b_
, DoBufferCreated(client_b_route_1
)).Times(1);
340 EXPECT_CALL(*client_b_
,
341 DoI420BufferReady(client_b_route_1
, capture_resolution
))
346 EXPECT_CALL(*client_a_
, DoBufferCreated(client_a_route_2
)).Times(1);
347 EXPECT_CALL(*client_a_
,
348 DoI420BufferReady(client_a_route_2
, capture_resolution
))
351 scoped_refptr
<media::VideoFrame
> video_frame
=
352 WrapI420Buffer(capture_resolution
, static_cast<uint8
*>(buffer
->data()));
353 ASSERT_FALSE(video_frame
->metadata()->HasKey(
354 media::VideoFrameMetadata::RESOURCE_UTILIZATION
));
355 client_a_
->resource_utilization_
= 0.5;
356 client_b_
->resource_utilization_
= -1.0;
357 device_
->OnIncomingCapturedVideoFrame(buffer
.Pass(), video_frame
,
360 base::RunLoop().RunUntilIdle();
361 Mock::VerifyAndClearExpectations(client_a_
.get());
362 Mock::VerifyAndClearExpectations(client_b_
.get());
363 // Expect VideoCaptureController set the metadata in |video_frame| to hold a
364 // resource utilization of 0.5 (the largest of all reported values).
365 double resource_utilization_in_metadata
= -1.0;
366 ASSERT_TRUE(video_frame
->metadata()->GetDouble(
367 media::VideoFrameMetadata::RESOURCE_UTILIZATION
,
368 &resource_utilization_in_metadata
));
369 ASSERT_EQ(0.5, resource_utilization_in_metadata
);
371 // Second buffer which ought to use the same shared memory buffer. In this
372 // case pretend that the Buffer pointer is held by the device for a long
373 // delay. This shouldn't affect anything.
374 scoped_ptr
<media::VideoCaptureDevice::Client::Buffer
> buffer2
=
375 device_
->ReserveOutputBuffer(capture_resolution
,
376 media::PIXEL_FORMAT_I420
,
377 media::PIXEL_STORAGE_CPU
);
378 ASSERT_TRUE(buffer2
.get());
379 memset(buffer2
->data(), buffer_no
++, buffer2
->mapped_size());
381 WrapI420Buffer(capture_resolution
, static_cast<uint8
*>(buffer2
->data()));
382 ASSERT_FALSE(video_frame
->metadata()->HasKey(
383 media::VideoFrameMetadata::RESOURCE_UTILIZATION
));
384 client_a_
->resource_utilization_
= 0.5;
385 client_b_
->resource_utilization_
= 3.14;
386 device_
->OnIncomingCapturedVideoFrame(buffer2
.Pass(), video_frame
,
389 // The buffer should be delivered to the clients in any order.
390 EXPECT_CALL(*client_a_
,
391 DoI420BufferReady(client_a_route_1
, capture_resolution
))
393 EXPECT_CALL(*client_b_
,
394 DoI420BufferReady(client_b_route_1
, capture_resolution
))
396 EXPECT_CALL(*client_a_
,
397 DoI420BufferReady(client_a_route_2
, capture_resolution
))
399 base::RunLoop().RunUntilIdle();
400 Mock::VerifyAndClearExpectations(client_a_
.get());
401 Mock::VerifyAndClearExpectations(client_b_
.get());
402 // Expect VideoCaptureController set the metadata in |video_frame| to hold a
403 // resource utilization of 3.14 (the largest of all reported values).
404 resource_utilization_in_metadata
= -1.0;
405 ASSERT_TRUE(video_frame
->metadata()->GetDouble(
406 media::VideoFrameMetadata::RESOURCE_UTILIZATION
,
407 &resource_utilization_in_metadata
));
408 ASSERT_EQ(3.14, resource_utilization_in_metadata
);
410 // Add a fourth client now that some buffers have come through.
411 controller_
->AddClient(client_b_route_2
,
413 base::kNullProcessHandle
,
416 Mock::VerifyAndClearExpectations(client_b_
.get());
418 // Third, fourth, and fifth buffers. Pretend they all arrive at the same time.
419 for (int i
= 0; i
< kPoolSize
; i
++) {
420 scoped_ptr
<media::VideoCaptureDevice::Client::Buffer
> buffer
=
421 device_
->ReserveOutputBuffer(capture_resolution
,
422 media::PIXEL_FORMAT_I420
,
423 media::PIXEL_STORAGE_CPU
);
424 ASSERT_TRUE(buffer
.get());
425 memset(buffer
->data(), buffer_no
++, buffer
->mapped_size());
427 WrapI420Buffer(capture_resolution
, static_cast<uint8
*>(buffer
->data()));
428 device_
->OnIncomingCapturedVideoFrame(buffer
.Pass(), video_frame
,
431 // ReserveOutputBuffer ought to fail now, because the pool is depleted.
433 device_
->ReserveOutputBuffer(capture_resolution
,
434 media::PIXEL_FORMAT_I420
,
435 media::PIXEL_STORAGE_CPU
).get());
437 // The new client needs to be told of 3 buffers; the old clients only 2.
438 EXPECT_CALL(*client_b_
, DoBufferCreated(client_b_route_2
)).Times(kPoolSize
);
439 EXPECT_CALL(*client_b_
,
440 DoI420BufferReady(client_b_route_2
, capture_resolution
))
442 EXPECT_CALL(*client_a_
, DoBufferCreated(client_a_route_1
))
443 .Times(kPoolSize
- 1);
444 EXPECT_CALL(*client_a_
,
445 DoI420BufferReady(client_a_route_1
, capture_resolution
))
447 EXPECT_CALL(*client_a_
, DoBufferCreated(client_a_route_2
))
448 .Times(kPoolSize
- 1);
449 EXPECT_CALL(*client_a_
,
450 DoI420BufferReady(client_a_route_2
, capture_resolution
))
452 EXPECT_CALL(*client_b_
, DoBufferCreated(client_b_route_1
))
453 .Times(kPoolSize
- 1);
454 EXPECT_CALL(*client_b_
,
455 DoI420BufferReady(client_b_route_1
, capture_resolution
))
457 base::RunLoop().RunUntilIdle();
458 Mock::VerifyAndClearExpectations(client_a_
.get());
459 Mock::VerifyAndClearExpectations(client_b_
.get());
461 // Now test the interaction of client shutdown and buffer delivery.
462 // Kill A1 via renderer disconnect (synchronous).
463 controller_
->RemoveClient(client_a_route_1
, client_a_
.get());
464 // Kill B1 via session close (posts a task to disconnect).
465 EXPECT_CALL(*client_b_
, DoEnded(client_b_route_1
)).Times(1);
466 controller_
->StopSession(300);
467 // Queue up another buffer.
468 scoped_ptr
<media::VideoCaptureDevice::Client::Buffer
> buffer3
=
469 device_
->ReserveOutputBuffer(capture_resolution
,
470 media::PIXEL_FORMAT_I420
,
471 media::PIXEL_STORAGE_CPU
);
472 ASSERT_TRUE(buffer3
.get());
473 memset(buffer3
->data(), buffer_no
++, buffer3
->mapped_size());
475 WrapI420Buffer(capture_resolution
, static_cast<uint8
*>(buffer3
->data()));
476 device_
->OnIncomingCapturedVideoFrame(buffer3
.Pass(), video_frame
,
479 scoped_ptr
<media::VideoCaptureDevice::Client::Buffer
> buffer4
=
480 device_
->ReserveOutputBuffer(capture_resolution
,
481 media::PIXEL_FORMAT_I420
,
482 media::PIXEL_STORAGE_CPU
);
484 // Kill A2 via session close (posts a task to disconnect, but A2 must not
485 // be sent either of these two buffers).
486 EXPECT_CALL(*client_a_
, DoEnded(client_a_route_2
)).Times(1);
487 controller_
->StopSession(200);
489 ASSERT_TRUE(buffer4
.get());
490 memset(buffer4
->data(), buffer_no
++, buffer4
->mapped_size());
492 WrapI420Buffer(capture_resolution
, static_cast<uint8
*>(buffer4
->data()));
493 device_
->OnIncomingCapturedVideoFrame(buffer4
.Pass(), video_frame
,
495 // B2 is the only client left, and is the only one that should
497 EXPECT_CALL(*client_b_
,
498 DoI420BufferReady(client_b_route_2
, capture_resolution
))
500 base::RunLoop().RunUntilIdle();
501 Mock::VerifyAndClearExpectations(client_a_
.get());
502 Mock::VerifyAndClearExpectations(client_b_
.get());
504 // Allocate all buffers from the buffer pool, half as SHM buffer and half as
505 // mailbox buffers. Make sure of different counts though.
506 #if defined(OS_ANDROID)
507 int mailbox_buffers
= 0;
509 int mailbox_buffers
= kPoolSize
/ 2;
511 int shm_buffers
= kPoolSize
- mailbox_buffers
;
512 if (shm_buffers
== mailbox_buffers
) {
517 for (int i
= 0; i
< shm_buffers
; ++i
) {
518 scoped_ptr
<media::VideoCaptureDevice::Client::Buffer
> buffer
=
519 device_
->ReserveOutputBuffer(capture_resolution
,
520 media::PIXEL_FORMAT_I420
,
521 media::PIXEL_STORAGE_CPU
);
522 ASSERT_TRUE(buffer
.get());
524 WrapI420Buffer(capture_resolution
, static_cast<uint8
*>(buffer
->data()));
525 device_
->OnIncomingCapturedVideoFrame(buffer
.Pass(), video_frame
,
528 std::vector
<uint32
> mailbox_syncpoints(mailbox_buffers
);
529 std::vector
<uint32
> release_syncpoints(mailbox_buffers
);
530 for (int i
= 0; i
< mailbox_buffers
; ++i
) {
531 scoped_ptr
<media::VideoCaptureDevice::Client::Buffer
> buffer
=
532 device_
->ReserveOutputBuffer(capture_resolution
,
533 media::PIXEL_FORMAT_ARGB
,
534 media::PIXEL_STORAGE_TEXTURE
);
535 ASSERT_TRUE(buffer
.get());
536 #if !defined(OS_ANDROID)
537 mailbox_syncpoints
[i
] =
538 ImageTransportFactory::GetInstance()->GetGLHelper()->InsertSyncPoint();
540 device_
->OnIncomingCapturedVideoFrame(
542 WrapMailboxBuffer(gpu::MailboxHolder(gpu::Mailbox::Generate(), 0,
543 mailbox_syncpoints
[i
]),
544 base::Bind(&CacheSyncPoint
, &release_syncpoints
[i
]),
548 // ReserveOutputBuffers ought to fail now regardless of buffer format, because
549 // the pool is depleted.
551 device_
->ReserveOutputBuffer(capture_resolution
,
552 media::PIXEL_FORMAT_I420
,
553 media::PIXEL_STORAGE_CPU
).get());
555 device_
->ReserveOutputBuffer(capture_resolution
,
556 media::PIXEL_FORMAT_ARGB
,
557 media::PIXEL_STORAGE_TEXTURE
).get());
558 EXPECT_CALL(*client_b_
,
559 DoI420BufferReady(client_b_route_2
, capture_resolution
))
561 EXPECT_CALL(*client_b_
,
562 DoTextureBufferReady(client_b_route_2
, capture_resolution
))
563 .Times(mailbox_buffers
);
564 #if !defined(OS_ANDROID)
565 EXPECT_CALL(*client_b_
, DoBufferDestroyed(client_b_route_2
));
567 base::RunLoop().RunUntilIdle();
568 for (size_t i
= 0; i
< mailbox_syncpoints
.size(); ++i
) {
569 // A new release sync point must be inserted when the video frame is
570 // returned to the Browser process.
571 // See: MockVideoCaptureControllerEventHandler::OnMailboxBufferReady() and
572 // VideoCaptureController::ReturnBuffer()
573 ASSERT_NE(mailbox_syncpoints
[i
], release_syncpoints
[i
]);
575 Mock::VerifyAndClearExpectations(client_b_
.get());
577 #if !defined(OS_ANDROID)
578 ImageTransportFactory::Terminate();
582 // Exercises the OnError() codepath of VideoCaptureController, and tests the
583 // behavior of various operations after the error state has been signalled.
584 TEST_F(VideoCaptureControllerTest
, ErrorBeforeDeviceCreation
) {
585 media::VideoCaptureParams session_100
;
586 session_100
.requested_format
= media::VideoCaptureFormat(
587 gfx::Size(320, 240), 30, media::PIXEL_FORMAT_I420
);
589 media::VideoCaptureParams session_200
= session_100
;
591 const gfx::Size
capture_resolution(320, 240);
593 const VideoCaptureControllerID
route_id(0x99);
595 // Start with one client.
596 controller_
->AddClient(
597 route_id
, client_a_
.get(), base::kNullProcessHandle
, 100, session_100
);
598 device_
->OnError("Test Error");
599 EXPECT_CALL(*client_a_
, DoError(route_id
)).Times(1);
600 base::RunLoop().RunUntilIdle();
601 Mock::VerifyAndClearExpectations(client_a_
.get());
603 // Second client connects after the error state. It also should get told of
605 EXPECT_CALL(*client_b_
, DoError(route_id
)).Times(1);
606 controller_
->AddClient(
607 route_id
, client_b_
.get(), base::kNullProcessHandle
, 200, session_200
);
608 base::RunLoop().RunUntilIdle();
609 Mock::VerifyAndClearExpectations(client_b_
.get());
611 scoped_ptr
<media::VideoCaptureDevice::Client::Buffer
> buffer(
612 device_
->ReserveOutputBuffer(capture_resolution
,
613 media::PIXEL_FORMAT_I420
,
614 media::PIXEL_STORAGE_CPU
));
615 ASSERT_TRUE(buffer
.get());
616 scoped_refptr
<media::VideoFrame
> video_frame
=
617 WrapI420Buffer(capture_resolution
, static_cast<uint8
*>(buffer
->data()));
618 device_
->OnIncomingCapturedVideoFrame(buffer
.Pass(), video_frame
,
621 base::RunLoop().RunUntilIdle();
624 // Exercises the OnError() codepath of VideoCaptureController, and tests the
625 // behavior of various operations after the error state has been signalled.
626 TEST_F(VideoCaptureControllerTest
, ErrorAfterDeviceCreation
) {
627 media::VideoCaptureParams session_100
;
628 session_100
.requested_format
= media::VideoCaptureFormat(
629 gfx::Size(320, 240), 30, media::PIXEL_FORMAT_I420
);
631 media::VideoCaptureParams session_200
= session_100
;
633 const VideoCaptureControllerID
route_id(0x99);
635 // Start with one client.
636 controller_
->AddClient(
637 route_id
, client_a_
.get(), base::kNullProcessHandle
, 100, session_100
);
638 media::VideoCaptureFormat
device_format(
639 gfx::Size(10, 10), 25, media::PIXEL_FORMAT_ARGB
);
641 // Start the device. Then, before the first buffer, signal an error and
642 // deliver the buffer. The error should be propagated to clients; the buffer
644 base::RunLoop().RunUntilIdle();
645 Mock::VerifyAndClearExpectations(client_a_
.get());
647 const gfx::Size
dims(320, 240);
648 scoped_ptr
<media::VideoCaptureDevice::Client::Buffer
> buffer(
649 device_
->ReserveOutputBuffer(dims
, media::PIXEL_FORMAT_I420
,
650 media::PIXEL_STORAGE_CPU
));
651 ASSERT_TRUE(buffer
.get());
653 scoped_refptr
<media::VideoFrame
> video_frame
=
654 WrapI420Buffer(dims
, static_cast<uint8
*>(buffer
->data()));
655 device_
->OnError("Test Error");
656 device_
->OnIncomingCapturedVideoFrame(buffer
.Pass(), video_frame
,
659 EXPECT_CALL(*client_a_
, DoError(route_id
)).Times(1);
660 base::RunLoop().RunUntilIdle();
661 Mock::VerifyAndClearExpectations(client_a_
.get());
663 // Second client connects after the error state. It also should get told of
665 EXPECT_CALL(*client_b_
, DoError(route_id
)).Times(1);
666 controller_
->AddClient(
667 route_id
, client_b_
.get(), base::kNullProcessHandle
, 200, session_200
);
668 Mock::VerifyAndClearExpectations(client_b_
.get());
671 } // namespace content