DevTools: cut host and port from webSocketDebuggerUrl in addition to ws:// prefix
[chromium-blink-merge.git] / content / browser / renderer_host / media / video_capture_controller_unittest.cc
bloba69705ebccf0288e0c60b8f1a1f63832f907f2f3
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/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"
33 #endif
35 using ::testing::_;
36 using ::testing::InSequence;
37 using ::testing::Mock;
38 using ::testing::SaveArg;
40 namespace content {
42 class MockVideoCaptureControllerEventHandler
43 : public VideoCaptureControllerEventHandler {
44 public:
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(DoBufferDestroyed, void(VideoCaptureControllerID));
55 MOCK_METHOD2(DoI420BufferReady,
56 void(VideoCaptureControllerID, const gfx::Size&));
57 MOCK_METHOD2(DoTextureBufferReady,
58 void(VideoCaptureControllerID, const gfx::Size&));
59 MOCK_METHOD1(DoEnded, void(VideoCaptureControllerID));
60 MOCK_METHOD1(DoError, void(VideoCaptureControllerID));
62 void OnError(VideoCaptureControllerID id) override {
63 DoError(id);
65 void OnBufferCreated(VideoCaptureControllerID id,
66 base::SharedMemoryHandle handle,
67 int length, int buffer_id) override {
68 DoBufferCreated(id);
70 void OnBufferDestroyed(VideoCaptureControllerID id, int buffer_id) override {
71 DoBufferDestroyed(id);
73 void OnBufferReady(VideoCaptureControllerID id,
74 int buffer_id,
75 const scoped_refptr<media::VideoFrame>& frame,
76 const base::TimeTicks& timestamp) override {
77 if (!frame->HasTextures()) {
78 EXPECT_EQ(frame->format(), media::VideoFrame::I420);
79 DoI420BufferReady(id, frame->coded_size());
80 base::ThreadTaskRunnerHandle::Get()->PostTask(
81 FROM_HERE, base::Bind(&VideoCaptureController::ReturnBuffer,
82 base::Unretained(controller_), id, this,
83 buffer_id, 0, resource_utilization_));
84 } else {
85 EXPECT_EQ(frame->format(), media::VideoFrame::ARGB);
86 DoTextureBufferReady(id, frame->coded_size());
87 base::ThreadTaskRunnerHandle::Get()->PostTask(
88 FROM_HERE, base::Bind(&VideoCaptureController::ReturnBuffer,
89 base::Unretained(controller_), id, this,
90 buffer_id, frame->mailbox_holder(0).sync_point,
91 resource_utilization_));
94 void OnEnded(VideoCaptureControllerID id) override {
95 DoEnded(id);
96 // OnEnded() must respond by (eventually) unregistering the client.
97 base::ThreadTaskRunnerHandle::Get()->PostTask(
98 FROM_HERE,
99 base::Bind(base::IgnoreResult(&VideoCaptureController::RemoveClient),
100 base::Unretained(controller_), id, this));
103 VideoCaptureController* controller_;
104 double resource_utilization_;
107 // Test class.
108 class VideoCaptureControllerTest : public testing::Test {
109 public:
110 VideoCaptureControllerTest() {}
111 ~VideoCaptureControllerTest() override {}
113 protected:
114 static const int kPoolSize = 3;
116 void SetUp() override {
117 controller_.reset(new VideoCaptureController(kPoolSize));
118 device_ = controller_->NewDeviceClient(
119 base::ThreadTaskRunnerHandle::Get());
120 client_a_.reset(new MockVideoCaptureControllerEventHandler(
121 controller_.get()));
122 client_b_.reset(new MockVideoCaptureControllerEventHandler(
123 controller_.get()));
126 void TearDown() override { base::RunLoop().RunUntilIdle(); }
128 scoped_refptr<media::VideoFrame> WrapI420Buffer(gfx::Size dimensions,
129 uint8* data) {
130 return media::VideoFrame::WrapExternalData(
131 media::VideoFrame::I420,
132 dimensions,
133 gfx::Rect(dimensions),
134 dimensions,
135 data,
136 media::VideoFrame::AllocationSize(media::VideoFrame::I420, dimensions),
137 base::TimeDelta());
140 scoped_refptr<media::VideoFrame> WrapMailboxBuffer(
141 const gpu::MailboxHolder& holder,
142 const media::VideoFrame::ReleaseMailboxCB& release_cb,
143 gfx::Size dimensions) {
144 return media::VideoFrame::WrapNativeTexture(
145 media::VideoFrame::ARGB, holder, release_cb, dimensions,
146 gfx::Rect(dimensions), dimensions, base::TimeDelta());
149 TestBrowserThreadBundle bundle_;
150 scoped_ptr<MockVideoCaptureControllerEventHandler> client_a_;
151 scoped_ptr<MockVideoCaptureControllerEventHandler> client_b_;
152 scoped_ptr<VideoCaptureController> controller_;
153 scoped_ptr<media::VideoCaptureDevice::Client> device_;
155 private:
156 DISALLOW_COPY_AND_ASSIGN(VideoCaptureControllerTest);
159 // A simple test of VideoCaptureController's ability to add, remove, and keep
160 // track of clients.
161 TEST_F(VideoCaptureControllerTest, AddAndRemoveClients) {
162 media::VideoCaptureParams session_100;
163 session_100.requested_format = media::VideoCaptureFormat(
164 gfx::Size(320, 240), 30, media::PIXEL_FORMAT_I420);
165 media::VideoCaptureParams session_200 = session_100;
167 media::VideoCaptureParams session_300 = session_100;
169 media::VideoCaptureParams session_400 = session_100;
171 // Intentionally use the same route ID for two of the clients: the device_ids
172 // are a per-VideoCaptureHost namespace, and can overlap across hosts.
173 const VideoCaptureControllerID client_a_route_1(44);
174 const VideoCaptureControllerID client_a_route_2(30);
175 const VideoCaptureControllerID client_b_route_1(30);
176 const VideoCaptureControllerID client_b_route_2(1);
178 // Clients in controller: []
179 ASSERT_EQ(0, controller_->GetClientCount())
180 << "Client count should initially be zero.";
181 controller_->AddClient(client_a_route_1,
182 client_a_.get(),
183 base::kNullProcessHandle,
184 100,
185 session_100);
186 // Clients in controller: [A/1]
187 ASSERT_EQ(1, controller_->GetClientCount())
188 << "Adding client A/1 should bump client count.";
189 controller_->AddClient(client_a_route_2,
190 client_a_.get(),
191 base::kNullProcessHandle,
192 200,
193 session_200);
194 // Clients in controller: [A/1, A/2]
195 ASSERT_EQ(2, controller_->GetClientCount())
196 << "Adding client A/2 should bump client count.";
197 controller_->AddClient(client_b_route_1,
198 client_b_.get(),
199 base::kNullProcessHandle,
200 300,
201 session_300);
202 // Clients in controller: [A/1, A/2, B/1]
203 ASSERT_EQ(3, controller_->GetClientCount())
204 << "Adding client B/1 should bump client count.";
205 ASSERT_EQ(200,
206 controller_->RemoveClient(client_a_route_2, client_a_.get()))
207 << "Removing client A/1 should return its session_id.";
208 // Clients in controller: [A/1, B/1]
209 ASSERT_EQ(2, controller_->GetClientCount());
210 ASSERT_EQ(static_cast<int>(kInvalidMediaCaptureSessionId),
211 controller_->RemoveClient(client_a_route_2, client_a_.get()))
212 << "Removing a nonexistant client should fail.";
213 // Clients in controller: [A/1, B/1]
214 ASSERT_EQ(2, controller_->GetClientCount());
215 ASSERT_EQ(300,
216 controller_->RemoveClient(client_b_route_1, client_b_.get()))
217 << "Removing client B/1 should return its session_id.";
218 // Clients in controller: [A/1]
219 ASSERT_EQ(1, controller_->GetClientCount());
220 controller_->AddClient(client_b_route_2,
221 client_b_.get(),
222 base::kNullProcessHandle,
223 400,
224 session_400);
225 // Clients in controller: [A/1, B/2]
227 EXPECT_CALL(*client_a_, DoEnded(client_a_route_1)).Times(1);
228 controller_->StopSession(100); // Session 100 == client A/1
229 Mock::VerifyAndClearExpectations(client_a_.get());
230 ASSERT_EQ(2, controller_->GetClientCount())
231 << "Client should be closed but still exist after StopSession.";
232 // Clients in controller: [A/1 (closed, removal pending), B/2]
233 base::RunLoop().RunUntilIdle();
234 // Clients in controller: [B/2]
235 ASSERT_EQ(1, controller_->GetClientCount())
236 << "Client A/1 should be deleted by now.";
237 controller_->StopSession(200); // Session 200 does not exist anymore
238 // Clients in controller: [B/2]
239 ASSERT_EQ(1, controller_->GetClientCount())
240 << "Stopping non-existant session 200 should be a no-op.";
241 controller_->StopSession(256); // Session 256 never existed.
242 // Clients in controller: [B/2]
243 ASSERT_EQ(1, controller_->GetClientCount())
244 << "Stopping non-existant session 256 should be a no-op.";
245 ASSERT_EQ(static_cast<int>(kInvalidMediaCaptureSessionId),
246 controller_->RemoveClient(client_a_route_1, client_a_.get()))
247 << "Removing already-removed client A/1 should fail.";
248 // Clients in controller: [B/2]
249 ASSERT_EQ(1, controller_->GetClientCount())
250 << "Removing non-existant session 200 should be a no-op.";
251 ASSERT_EQ(400,
252 controller_->RemoveClient(client_b_route_2, client_b_.get()))
253 << "Removing client B/2 should return its session_id.";
254 // Clients in controller: []
255 ASSERT_EQ(0, controller_->GetClientCount())
256 << "Client count should return to zero after all clients are gone.";
259 static void CacheSyncPoint(uint32* called_release_sync_point,
260 uint32 release_sync_point) {
261 *called_release_sync_point = release_sync_point;
264 // This test will connect and disconnect several clients while simulating an
265 // active capture device being started and generating frames. It runs on one
266 // thread and is intended to behave deterministically.
267 TEST_F(VideoCaptureControllerTest, NormalCaptureMultipleClients) {
268 // VideoCaptureController::ReturnBuffer() uses ImageTransportFactory.
269 #if !defined(OS_ANDROID)
270 ImageTransportFactory::InitializeForUnitTests(
271 scoped_ptr<ImageTransportFactory>(new NoTransportImageTransportFactory));
272 #endif
274 media::VideoCaptureParams session_100;
275 session_100.requested_format = media::VideoCaptureFormat(
276 gfx::Size(320, 240), 30, media::PIXEL_FORMAT_I420);
278 media::VideoCaptureParams session_200 = session_100;
280 media::VideoCaptureParams session_300 = session_100;
282 media::VideoCaptureParams session_1 = session_100;
284 const gfx::Size capture_resolution(444, 200);
286 // The device format needn't match the VideoCaptureParams (the camera can do
287 // what it wants). Pick something random.
288 media::VideoCaptureFormat device_format(
289 gfx::Size(10, 10), 25, media::PIXEL_FORMAT_RGB24);
291 const VideoCaptureControllerID client_a_route_1(0xa1a1a1a1);
292 const VideoCaptureControllerID client_a_route_2(0xa2a2a2a2);
293 const VideoCaptureControllerID client_b_route_1(0xb1b1b1b1);
294 const VideoCaptureControllerID client_b_route_2(0xb2b2b2b2);
296 // Start with two clients.
297 controller_->AddClient(client_a_route_1,
298 client_a_.get(),
299 base::kNullProcessHandle,
300 100,
301 session_100);
302 controller_->AddClient(client_b_route_1,
303 client_b_.get(),
304 base::kNullProcessHandle,
305 300,
306 session_300);
307 controller_->AddClient(client_a_route_2,
308 client_a_.get(),
309 base::kNullProcessHandle,
310 200,
311 session_200);
312 ASSERT_EQ(3, controller_->GetClientCount());
314 // Now, simulate an incoming captured buffer from the capture device. As a
315 // side effect this will cause the first buffer to be shared with clients.
316 uint8 buffer_no = 1;
317 ASSERT_EQ(0.0, device_->GetBufferPoolUtilization());
318 scoped_ptr<media::VideoCaptureDevice::Client::Buffer> buffer(
319 device_->ReserveOutputBuffer(capture_resolution, media::PIXEL_FORMAT_I420,
320 media::PIXEL_STORAGE_CPU));
321 ASSERT_TRUE(buffer.get());
322 ASSERT_EQ(1.0 / kPoolSize, device_->GetBufferPoolUtilization());
323 memset(buffer->data(), buffer_no++, buffer->size());
325 InSequence s;
326 EXPECT_CALL(*client_a_, DoBufferCreated(client_a_route_1)).Times(1);
327 EXPECT_CALL(*client_a_,
328 DoI420BufferReady(client_a_route_1, capture_resolution))
329 .Times(1);
332 InSequence s;
333 EXPECT_CALL(*client_b_, DoBufferCreated(client_b_route_1)).Times(1);
334 EXPECT_CALL(*client_b_,
335 DoI420BufferReady(client_b_route_1, capture_resolution))
336 .Times(1);
339 InSequence s;
340 EXPECT_CALL(*client_a_, DoBufferCreated(client_a_route_2)).Times(1);
341 EXPECT_CALL(*client_a_,
342 DoI420BufferReady(client_a_route_2, capture_resolution))
343 .Times(1);
345 scoped_refptr<media::VideoFrame> video_frame =
346 WrapI420Buffer(capture_resolution, static_cast<uint8*>(buffer->data()));
347 ASSERT_FALSE(video_frame->metadata()->HasKey(
348 media::VideoFrameMetadata::RESOURCE_UTILIZATION));
349 client_a_->resource_utilization_ = 0.5;
350 client_b_->resource_utilization_ = -1.0;
351 device_->OnIncomingCapturedVideoFrame(buffer.Pass(), video_frame,
352 base::TimeTicks());
354 base::RunLoop().RunUntilIdle();
355 Mock::VerifyAndClearExpectations(client_a_.get());
356 Mock::VerifyAndClearExpectations(client_b_.get());
357 // Expect VideoCaptureController set the metadata in |video_frame| to hold a
358 // resource utilization of 0.5 (the largest of all reported values).
359 double resource_utilization_in_metadata = -1.0;
360 ASSERT_TRUE(video_frame->metadata()->GetDouble(
361 media::VideoFrameMetadata::RESOURCE_UTILIZATION,
362 &resource_utilization_in_metadata));
363 ASSERT_EQ(0.5, resource_utilization_in_metadata);
365 // Second buffer which ought to use the same shared memory buffer. In this
366 // case pretend that the Buffer pointer is held by the device for a long
367 // delay. This shouldn't affect anything.
368 scoped_ptr<media::VideoCaptureDevice::Client::Buffer> buffer2 =
369 device_->ReserveOutputBuffer(capture_resolution, media::PIXEL_FORMAT_I420,
370 media::PIXEL_STORAGE_CPU);
371 ASSERT_TRUE(buffer2.get());
372 memset(buffer2->data(), buffer_no++, buffer2->size());
373 video_frame =
374 WrapI420Buffer(capture_resolution, static_cast<uint8*>(buffer2->data()));
375 ASSERT_FALSE(video_frame->metadata()->HasKey(
376 media::VideoFrameMetadata::RESOURCE_UTILIZATION));
377 client_a_->resource_utilization_ = 0.5;
378 client_b_->resource_utilization_ = 3.14;
379 device_->OnIncomingCapturedVideoFrame(buffer2.Pass(), video_frame,
380 base::TimeTicks());
382 // The buffer should be delivered to the clients in any order.
383 EXPECT_CALL(*client_a_,
384 DoI420BufferReady(client_a_route_1, capture_resolution))
385 .Times(1);
386 EXPECT_CALL(*client_b_,
387 DoI420BufferReady(client_b_route_1, capture_resolution))
388 .Times(1);
389 EXPECT_CALL(*client_a_,
390 DoI420BufferReady(client_a_route_2, capture_resolution))
391 .Times(1);
392 base::RunLoop().RunUntilIdle();
393 Mock::VerifyAndClearExpectations(client_a_.get());
394 Mock::VerifyAndClearExpectations(client_b_.get());
395 // Expect VideoCaptureController set the metadata in |video_frame| to hold a
396 // resource utilization of 3.14 (the largest of all reported values).
397 resource_utilization_in_metadata = -1.0;
398 ASSERT_TRUE(video_frame->metadata()->GetDouble(
399 media::VideoFrameMetadata::RESOURCE_UTILIZATION,
400 &resource_utilization_in_metadata));
401 ASSERT_EQ(3.14, resource_utilization_in_metadata);
403 // Add a fourth client now that some buffers have come through.
404 controller_->AddClient(client_b_route_2,
405 client_b_.get(),
406 base::kNullProcessHandle,
408 session_1);
409 Mock::VerifyAndClearExpectations(client_b_.get());
411 // Third, fourth, and fifth buffers. Pretend they all arrive at the same time.
412 for (int i = 0; i < kPoolSize; i++) {
413 scoped_ptr<media::VideoCaptureDevice::Client::Buffer> buffer =
414 device_->ReserveOutputBuffer(capture_resolution,
415 media::PIXEL_FORMAT_I420,
416 media::PIXEL_STORAGE_CPU);
417 ASSERT_TRUE(buffer.get());
418 memset(buffer->data(), buffer_no++, buffer->size());
419 video_frame =
420 WrapI420Buffer(capture_resolution, static_cast<uint8*>(buffer->data()));
421 device_->OnIncomingCapturedVideoFrame(buffer.Pass(), video_frame,
422 base::TimeTicks());
424 // ReserveOutputBuffer ought to fail now, because the pool is depleted.
425 ASSERT_FALSE(
426 device_->ReserveOutputBuffer(capture_resolution, media::PIXEL_FORMAT_I420,
427 media::PIXEL_STORAGE_CPU).get());
429 // The new client needs to be told of 3 buffers; the old clients only 2.
430 EXPECT_CALL(*client_b_, DoBufferCreated(client_b_route_2)).Times(kPoolSize);
431 EXPECT_CALL(*client_b_,
432 DoI420BufferReady(client_b_route_2, capture_resolution))
433 .Times(kPoolSize);
434 EXPECT_CALL(*client_a_, DoBufferCreated(client_a_route_1))
435 .Times(kPoolSize - 1);
436 EXPECT_CALL(*client_a_,
437 DoI420BufferReady(client_a_route_1, capture_resolution))
438 .Times(kPoolSize);
439 EXPECT_CALL(*client_a_, DoBufferCreated(client_a_route_2))
440 .Times(kPoolSize - 1);
441 EXPECT_CALL(*client_a_,
442 DoI420BufferReady(client_a_route_2, capture_resolution))
443 .Times(kPoolSize);
444 EXPECT_CALL(*client_b_, DoBufferCreated(client_b_route_1))
445 .Times(kPoolSize - 1);
446 EXPECT_CALL(*client_b_,
447 DoI420BufferReady(client_b_route_1, capture_resolution))
448 .Times(kPoolSize);
449 base::RunLoop().RunUntilIdle();
450 Mock::VerifyAndClearExpectations(client_a_.get());
451 Mock::VerifyAndClearExpectations(client_b_.get());
453 // Now test the interaction of client shutdown and buffer delivery.
454 // Kill A1 via renderer disconnect (synchronous).
455 controller_->RemoveClient(client_a_route_1, client_a_.get());
456 // Kill B1 via session close (posts a task to disconnect).
457 EXPECT_CALL(*client_b_, DoEnded(client_b_route_1)).Times(1);
458 controller_->StopSession(300);
459 // Queue up another buffer.
460 scoped_ptr<media::VideoCaptureDevice::Client::Buffer> buffer3 =
461 device_->ReserveOutputBuffer(capture_resolution, media::PIXEL_FORMAT_I420,
462 media::PIXEL_STORAGE_CPU);
463 ASSERT_TRUE(buffer3.get());
464 memset(buffer3->data(), buffer_no++, buffer3->size());
465 video_frame =
466 WrapI420Buffer(capture_resolution, static_cast<uint8*>(buffer3->data()));
467 device_->OnIncomingCapturedVideoFrame(buffer3.Pass(), video_frame,
468 base::TimeTicks());
470 scoped_ptr<media::VideoCaptureDevice::Client::Buffer> buffer4 =
471 device_->ReserveOutputBuffer(capture_resolution, media::PIXEL_FORMAT_I420,
472 media::PIXEL_STORAGE_CPU);
474 // Kill A2 via session close (posts a task to disconnect, but A2 must not
475 // be sent either of these two buffers).
476 EXPECT_CALL(*client_a_, DoEnded(client_a_route_2)).Times(1);
477 controller_->StopSession(200);
479 ASSERT_TRUE(buffer4.get());
480 memset(buffer4->data(), buffer_no++, buffer4->size());
481 video_frame =
482 WrapI420Buffer(capture_resolution, static_cast<uint8*>(buffer4->data()));
483 device_->OnIncomingCapturedVideoFrame(buffer4.Pass(), video_frame,
484 base::TimeTicks());
485 // B2 is the only client left, and is the only one that should
486 // get the buffer.
487 EXPECT_CALL(*client_b_,
488 DoI420BufferReady(client_b_route_2, capture_resolution))
489 .Times(2);
490 base::RunLoop().RunUntilIdle();
491 Mock::VerifyAndClearExpectations(client_a_.get());
492 Mock::VerifyAndClearExpectations(client_b_.get());
494 // Allocate all buffers from the buffer pool, half as SHM buffer and half as
495 // mailbox buffers. Make sure of different counts though.
496 #if defined(OS_ANDROID)
497 int mailbox_buffers = 0;
498 #else
499 int mailbox_buffers = kPoolSize / 2;
500 #endif
501 int shm_buffers = kPoolSize - mailbox_buffers;
502 if (shm_buffers == mailbox_buffers) {
503 shm_buffers--;
504 mailbox_buffers++;
507 for (int i = 0; i < shm_buffers; ++i) {
508 scoped_ptr<media::VideoCaptureDevice::Client::Buffer> buffer =
509 device_->ReserveOutputBuffer(capture_resolution,
510 media::PIXEL_FORMAT_I420,
511 media::PIXEL_STORAGE_CPU);
512 ASSERT_TRUE(buffer.get());
513 video_frame =
514 WrapI420Buffer(capture_resolution, static_cast<uint8*>(buffer->data()));
515 device_->OnIncomingCapturedVideoFrame(buffer.Pass(), video_frame,
516 base::TimeTicks());
518 std::vector<uint32> mailbox_syncpoints(mailbox_buffers);
519 std::vector<uint32> release_syncpoints(mailbox_buffers);
520 for (int i = 0; i < mailbox_buffers; ++i) {
521 scoped_ptr<media::VideoCaptureDevice::Client::Buffer> buffer =
522 device_->ReserveOutputBuffer(capture_resolution,
523 media::PIXEL_FORMAT_ARGB,
524 media::PIXEL_STORAGE_TEXTURE);
525 ASSERT_TRUE(buffer.get());
526 #if !defined(OS_ANDROID)
527 mailbox_syncpoints[i] =
528 ImageTransportFactory::GetInstance()->GetGLHelper()->InsertSyncPoint();
529 #endif
530 device_->OnIncomingCapturedVideoFrame(
531 buffer.Pass(),
532 WrapMailboxBuffer(gpu::MailboxHolder(gpu::Mailbox::Generate(), 0,
533 mailbox_syncpoints[i]),
534 base::Bind(&CacheSyncPoint, &release_syncpoints[i]),
535 capture_resolution),
536 base::TimeTicks());
538 // ReserveOutputBuffers ought to fail now regardless of buffer format, because
539 // the pool is depleted.
540 ASSERT_FALSE(
541 device_->ReserveOutputBuffer(capture_resolution, media::PIXEL_FORMAT_I420,
542 media::PIXEL_STORAGE_CPU).get());
543 ASSERT_FALSE(
544 device_->ReserveOutputBuffer(capture_resolution, media::PIXEL_FORMAT_ARGB,
545 media::PIXEL_STORAGE_TEXTURE).get());
546 EXPECT_CALL(*client_b_,
547 DoI420BufferReady(client_b_route_2, capture_resolution))
548 .Times(shm_buffers);
549 EXPECT_CALL(*client_b_,
550 DoTextureBufferReady(client_b_route_2, capture_resolution))
551 .Times(mailbox_buffers);
552 #if !defined(OS_ANDROID)
553 EXPECT_CALL(*client_b_, DoBufferDestroyed(client_b_route_2));
554 #endif
555 base::RunLoop().RunUntilIdle();
556 for (size_t i = 0; i < mailbox_syncpoints.size(); ++i) {
557 // A new release sync point must be inserted when the video frame is
558 // returned to the Browser process.
559 // See: MockVideoCaptureControllerEventHandler::OnMailboxBufferReady() and
560 // VideoCaptureController::ReturnBuffer()
561 ASSERT_NE(mailbox_syncpoints[i], release_syncpoints[i]);
563 Mock::VerifyAndClearExpectations(client_b_.get());
565 #if !defined(OS_ANDROID)
566 ImageTransportFactory::Terminate();
567 #endif
570 // Exercises the OnError() codepath of VideoCaptureController, and tests the
571 // behavior of various operations after the error state has been signalled.
572 TEST_F(VideoCaptureControllerTest, ErrorBeforeDeviceCreation) {
573 media::VideoCaptureParams session_100;
574 session_100.requested_format = media::VideoCaptureFormat(
575 gfx::Size(320, 240), 30, media::PIXEL_FORMAT_I420);
577 media::VideoCaptureParams session_200 = session_100;
579 const gfx::Size capture_resolution(320, 240);
581 const VideoCaptureControllerID route_id(0x99);
583 // Start with one client.
584 controller_->AddClient(
585 route_id, client_a_.get(), base::kNullProcessHandle, 100, session_100);
586 device_->OnError("Test Error");
587 EXPECT_CALL(*client_a_, DoError(route_id)).Times(1);
588 base::RunLoop().RunUntilIdle();
589 Mock::VerifyAndClearExpectations(client_a_.get());
591 // Second client connects after the error state. It also should get told of
592 // the error.
593 EXPECT_CALL(*client_b_, DoError(route_id)).Times(1);
594 controller_->AddClient(
595 route_id, client_b_.get(), base::kNullProcessHandle, 200, session_200);
596 base::RunLoop().RunUntilIdle();
597 Mock::VerifyAndClearExpectations(client_b_.get());
599 scoped_ptr<media::VideoCaptureDevice::Client::Buffer> buffer(
600 device_->ReserveOutputBuffer(capture_resolution, media::PIXEL_FORMAT_I420,
601 media::PIXEL_STORAGE_CPU));
602 ASSERT_TRUE(buffer.get());
603 scoped_refptr<media::VideoFrame> video_frame =
604 WrapI420Buffer(capture_resolution, static_cast<uint8*>(buffer->data()));
605 device_->OnIncomingCapturedVideoFrame(buffer.Pass(), video_frame,
606 base::TimeTicks());
608 base::RunLoop().RunUntilIdle();
611 // Exercises the OnError() codepath of VideoCaptureController, and tests the
612 // behavior of various operations after the error state has been signalled.
613 TEST_F(VideoCaptureControllerTest, ErrorAfterDeviceCreation) {
614 media::VideoCaptureParams session_100;
615 session_100.requested_format = media::VideoCaptureFormat(
616 gfx::Size(320, 240), 30, media::PIXEL_FORMAT_I420);
618 media::VideoCaptureParams session_200 = session_100;
620 const VideoCaptureControllerID route_id(0x99);
622 // Start with one client.
623 controller_->AddClient(
624 route_id, client_a_.get(), base::kNullProcessHandle, 100, session_100);
625 media::VideoCaptureFormat device_format(
626 gfx::Size(10, 10), 25, media::PIXEL_FORMAT_ARGB);
628 // Start the device. Then, before the first buffer, signal an error and
629 // deliver the buffer. The error should be propagated to clients; the buffer
630 // should not be.
631 base::RunLoop().RunUntilIdle();
632 Mock::VerifyAndClearExpectations(client_a_.get());
634 const gfx::Size dims(320, 240);
635 scoped_ptr<media::VideoCaptureDevice::Client::Buffer> buffer(
636 device_->ReserveOutputBuffer(dims, media::PIXEL_FORMAT_I420,
637 media::PIXEL_STORAGE_CPU));
638 ASSERT_TRUE(buffer.get());
640 scoped_refptr<media::VideoFrame> video_frame =
641 WrapI420Buffer(dims, static_cast<uint8*>(buffer->data()));
642 device_->OnError("Test Error");
643 device_->OnIncomingCapturedVideoFrame(buffer.Pass(), video_frame,
644 base::TimeTicks());
646 EXPECT_CALL(*client_a_, DoError(route_id)).Times(1);
647 base::RunLoop().RunUntilIdle();
648 Mock::VerifyAndClearExpectations(client_a_.get());
650 // Second client connects after the error state. It also should get told of
651 // the error.
652 EXPECT_CALL(*client_b_, DoError(route_id)).Times(1);
653 controller_->AddClient(
654 route_id, client_b_.get(), base::kNullProcessHandle, 200, session_200);
655 Mock::VerifyAndClearExpectations(client_b_.get());
658 // Tests that buffer-based capture API accepts all memory-backed pixel formats.
659 TEST_F(VideoCaptureControllerTest, DataCaptureInEachVideoFormatInSequence) {
660 // The usual ReserveOutputBuffer() -> OnIncomingCapturedVideoFrame() cannot
661 // be used since it does not accept all pixel formats. The memory backed
662 // buffer OnIncomingCapturedData() is used instead, with a dummy scratchpad
663 // buffer.
664 const size_t kScratchpadSizeInBytes = 400;
665 unsigned char data[kScratchpadSizeInBytes];
666 // Initialize memory to satisfy DrMemory tests.
667 memset(data, 0, kScratchpadSizeInBytes);
668 const gfx::Size capture_resolution(10, 10);
669 ASSERT_GE(kScratchpadSizeInBytes, capture_resolution.GetArea() * 4u)
670 << "Scratchpad is too small to hold the largest pixel format (ARGB).";
672 const int kSessionId = 100;
673 for (int format = 0; format < media::PIXEL_FORMAT_MAX; ++format) {
674 if (format == media::PIXEL_FORMAT_UNKNOWN)
675 continue;
676 media::VideoCaptureParams params;
677 params.requested_format = media::VideoCaptureFormat(
678 capture_resolution, 30, media::VideoPixelFormat(format));
680 // Start with one client.
681 const VideoCaptureControllerID route_id(0x99);
682 controller_->AddClient(route_id,
683 client_a_.get(),
684 base::kNullProcessHandle,
685 kSessionId,
686 params);
687 ASSERT_EQ(1, controller_->GetClientCount());
688 device_->OnIncomingCapturedData(
689 data,
690 params.requested_format.ImageAllocationSize(),
691 params.requested_format,
692 0 /* clockwise_rotation */,
693 base::TimeTicks());
694 EXPECT_EQ(kSessionId, controller_->RemoveClient(route_id, client_a_.get()));
695 Mock::VerifyAndClearExpectations(client_a_.get());
699 // Test that we receive the expected resolution for a given captured frame
700 // resolution and rotation. Odd resolutions are also cropped.
701 TEST_F(VideoCaptureControllerTest, CheckRotationsAndCrops) {
702 const int kSessionId = 100;
703 const struct SizeAndRotation {
704 gfx::Size input_resolution;
705 int rotation;
706 gfx::Size output_resolution;
707 } kSizeAndRotations[] = {{{6, 4}, 0, {6, 4}},
708 {{6, 4}, 90, {4, 6}},
709 {{6, 4}, 180, {6, 4}},
710 {{6, 4}, 270, {4, 6}},
711 {{7, 4}, 0, {6, 4}},
712 {{7, 4}, 90, {4, 6}},
713 {{7, 4}, 180, {6, 4}},
714 {{7, 4}, 270, {4, 6}}};
715 // The usual ReserveOutputBuffer() -> OnIncomingCapturedVideoFrame() cannot
716 // be used since it does not resolve rotations or crops. The memory backed
717 // buffer OnIncomingCapturedData() is used instead, with a dummy scratchpad
718 // buffer.
719 const size_t kScratchpadSizeInBytes = 400;
720 unsigned char data[kScratchpadSizeInBytes] = {};
722 media::VideoCaptureParams params;
723 for (const auto& size_and_rotation : kSizeAndRotations) {
724 ASSERT_GE(kScratchpadSizeInBytes,
725 size_and_rotation.input_resolution.GetArea() * 4u)
726 << "Scratchpad is too small to hold the largest pixel format (ARGB).";
728 params.requested_format = media::VideoCaptureFormat(
729 size_and_rotation.input_resolution, 30, media::PIXEL_FORMAT_ARGB);
731 const VideoCaptureControllerID route_id(0x99);
732 controller_->AddClient(route_id, client_a_.get(), base::kNullProcessHandle,
733 kSessionId, params);
734 ASSERT_EQ(1, controller_->GetClientCount());
736 device_->OnIncomingCapturedData(
737 data,
738 params.requested_format.ImageAllocationSize(),
739 params.requested_format,
740 size_and_rotation.rotation,
741 base::TimeTicks());
742 gfx::Size coded_size;
744 InSequence s;
745 EXPECT_CALL(*client_a_, DoBufferCreated(route_id)).Times(1);
746 EXPECT_CALL(*client_a_, DoI420BufferReady(route_id, _))
747 .Times(1)
748 .WillOnce(SaveArg<1>(&coded_size));
750 base::RunLoop().RunUntilIdle();
752 EXPECT_EQ(coded_size.width(), size_and_rotation.output_resolution.width());
753 EXPECT_EQ(coded_size.height(),
754 size_and_rotation.output_resolution.height());
756 EXPECT_EQ(kSessionId, controller_->RemoveClient(route_id, client_a_.get()));
757 Mock::VerifyAndClearExpectations(client_a_.get());
761 } // namespace content