1 // Copyright 2015 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.
6 #include "base/memory/scoped_ptr.h"
7 #include "base/run_loop.h"
8 #include "base/single_thread_task_runner.h"
9 #include "base/thread_task_runner_handle.h"
10 #include "content/browser/renderer_host/media/video_capture_buffer_pool.h"
11 #include "content/browser/renderer_host/media/video_capture_controller.h"
12 #include "content/browser/renderer_host/media/video_capture_device_client.h"
13 #include "content/public/test/test_browser_thread_bundle.h"
14 #include "media/base/limits.h"
15 #include "testing/gmock/include/gmock/gmock.h"
16 #include "testing/gtest/include/gtest/gtest.h"
19 using ::testing::Mock
;
20 using ::testing::InSequence
;
21 using ::testing::SaveArg
;
27 class MockVideoCaptureController
: public VideoCaptureController
{
29 explicit MockVideoCaptureController(int max_buffers
)
30 : VideoCaptureController(max_buffers
) {}
31 ~MockVideoCaptureController() override
{}
33 MOCK_METHOD1(MockDoIncomingCapturedVideoFrameOnIOThread
,
34 void(const gfx::Size
&));
35 MOCK_METHOD0(DoErrorOnIOThread
, void());
36 MOCK_METHOD1(DoLogOnIOThread
, void(const std::string
& message
));
37 MOCK_METHOD1(DoBufferDestroyedOnIOThread
, void(int buffer_id_to_drop
));
39 void DoIncomingCapturedVideoFrameOnIOThread(
40 scoped_ptr
<media::VideoCaptureDevice::Client::Buffer
> buffer
,
41 const scoped_refptr
<media::VideoFrame
>& frame
,
42 const base::TimeTicks
& timestamp
) override
{
43 MockDoIncomingCapturedVideoFrameOnIOThread(frame
->coded_size());
47 class VideoCaptureDeviceClientTest
: public ::testing::Test
{
49 VideoCaptureDeviceClientTest()
50 : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP
),
51 controller_(new MockVideoCaptureController(1)),
53 controller_
->NewDeviceClient(base::ThreadTaskRunnerHandle::Get())) {
55 ~VideoCaptureDeviceClientTest() override
{}
57 void TearDown() override
{ base::RunLoop().RunUntilIdle(); }
60 const content::TestBrowserThreadBundle thread_bundle_
;
61 const scoped_ptr
<MockVideoCaptureController
> controller_
;
62 const scoped_ptr
<media::VideoCaptureDevice::Client
> device_client_
;
65 DISALLOW_COPY_AND_ASSIGN(VideoCaptureDeviceClientTest
);
70 // A small test for reference and to verify VideoCaptureDeviceClient is
71 // minimally functional.
72 TEST_F(VideoCaptureDeviceClientTest
, Minimal
) {
73 const size_t kScratchpadSizeInBytes
= 400;
74 unsigned char data
[kScratchpadSizeInBytes
] = {};
75 const media::VideoCaptureFormat
kFrameFormat(
76 gfx::Size(10, 10), 30.0f
/*frame_rate*/,
77 media::PIXEL_FORMAT_I420
,
78 media::PIXEL_STORAGE_CPU
);
79 DCHECK(device_client_
.get());
80 EXPECT_CALL(*controller_
, MockDoIncomingCapturedVideoFrameOnIOThread(_
))
82 device_client_
->OnIncomingCapturedData(data
, kScratchpadSizeInBytes
,
83 kFrameFormat
, 0 /*clockwise rotation*/,
85 base::RunLoop().RunUntilIdle();
86 Mock::VerifyAndClearExpectations(controller_
.get());
89 // Tests that we don't try to pass on frames with an invalid frame format.
90 TEST_F(VideoCaptureDeviceClientTest
, FailsSilentlyGivenInvalidFrameFormat
) {
91 const size_t kScratchpadSizeInBytes
= 400;
92 unsigned char data
[kScratchpadSizeInBytes
] = {};
93 // kFrameFormat is invalid in a number of ways.
94 const media::VideoCaptureFormat
kFrameFormat(
95 gfx::Size(media::limits::kMaxDimension
+ 1, media::limits::kMaxDimension
),
96 media::limits::kMaxFramesPerSecond
+ 1,
97 media::VideoPixelFormat::PIXEL_FORMAT_I420
,
98 media::VideoPixelStorage::PIXEL_STORAGE_CPU
);
99 DCHECK(device_client_
.get());
100 // Expect the the call to fail silently inside the VideoCaptureDeviceClient.
101 EXPECT_CALL(*controller_
, MockDoIncomingCapturedVideoFrameOnIOThread(_
))
103 device_client_
->OnIncomingCapturedData(data
, kScratchpadSizeInBytes
,
104 kFrameFormat
, 0 /*clockwise rotation*/,
106 base::RunLoop().RunUntilIdle();
107 Mock::VerifyAndClearExpectations(controller_
.get());
110 // Tests that we fail silently if no available buffers to use.
111 TEST_F(VideoCaptureDeviceClientTest
, DropsFrameIfNoBuffer
) {
112 const size_t kScratchpadSizeInBytes
= 400;
113 unsigned char data
[kScratchpadSizeInBytes
] = {};
114 const media::VideoCaptureFormat
kFrameFormat(
115 gfx::Size(10, 10), 30.0f
/*frame_rate*/,
116 media::PIXEL_FORMAT_I420
,
117 media::PIXEL_STORAGE_CPU
);
118 // We expect the second frame to be silently dropped, so these should
119 // only be called once despite the two frames.
120 EXPECT_CALL(*controller_
, MockDoIncomingCapturedVideoFrameOnIOThread(_
))
122 // Pass two frames. The second will be dropped.
123 device_client_
->OnIncomingCapturedData(data
, kScratchpadSizeInBytes
,
124 kFrameFormat
, 0 /*clockwise rotation*/,
126 device_client_
->OnIncomingCapturedData(data
, kScratchpadSizeInBytes
,
127 kFrameFormat
, 0 /*clockwise rotation*/,
129 base::RunLoop().RunUntilIdle();
130 Mock::VerifyAndClearExpectations(controller_
.get());
133 // Tests that buffer-based capture API accepts all memory-backed pixel formats.
134 TEST_F(VideoCaptureDeviceClientTest
, DataCaptureInEachVideoFormatInSequence
) {
135 // The usual ReserveOutputBuffer() -> OnIncomingCapturedVideoFrame() cannot
136 // be used since it does not accept all pixel formats. The memory backed
137 // buffer OnIncomingCapturedData() is used instead, with a dummy scratchpad
139 const size_t kScratchpadSizeInBytes
= 400;
140 unsigned char data
[kScratchpadSizeInBytes
] = {};
141 const gfx::Size
capture_resolution(10, 10);
142 ASSERT_GE(kScratchpadSizeInBytes
, capture_resolution
.GetArea() * 4u)
143 << "Scratchpad is too small to hold the largest pixel format (ARGB).";
145 for (int format
= 0; format
< media::PIXEL_FORMAT_MAX
;
147 // Conversion from some formats are unsupported.
148 if (format
== media::PIXEL_FORMAT_UNKNOWN
||
149 format
== media::PIXEL_FORMAT_YV16
||
150 format
== media::PIXEL_FORMAT_YV12A
||
151 format
== media::PIXEL_FORMAT_YV24
||
152 format
== media::PIXEL_FORMAT_ARGB
||
153 format
== media::PIXEL_FORMAT_XRGB
||
154 format
== media::PIXEL_FORMAT_MJPEG
||
155 format
== media::PIXEL_FORMAT_MT21
) {
158 #if !defined(OS_LINUX) && !defined(OS_WIN)
159 if (format
== media::PIXEL_FORMAT_RGB24
){
163 media::VideoCaptureParams params
;
164 params
.requested_format
= media::VideoCaptureFormat(
165 capture_resolution
, 30.0f
, media::VideoPixelFormat(format
));
166 EXPECT_CALL(*controller_
, MockDoIncomingCapturedVideoFrameOnIOThread(_
))
168 device_client_
->OnIncomingCapturedData(
169 data
, params
.requested_format
.ImageAllocationSize(),
170 params
.requested_format
, 0 /* clockwise_rotation */, base::TimeTicks());
171 base::RunLoop().RunUntilIdle();
172 Mock::VerifyAndClearExpectations(controller_
.get());
176 // Test that we receive the expected resolution for a given captured frame
177 // resolution and rotation. Odd resolutions are also cropped.
178 TEST_F(VideoCaptureDeviceClientTest
, CheckRotationsAndCrops
) {
179 const struct SizeAndRotation
{
180 gfx::Size input_resolution
;
182 gfx::Size output_resolution
;
183 } kSizeAndRotations
[] = {{{6, 4}, 0, {6, 4}},
184 {{6, 4}, 90, {4, 6}},
185 {{6, 4}, 180, {6, 4}},
186 {{6, 4}, 270, {4, 6}},
188 {{7, 4}, 90, {4, 6}},
189 {{7, 4}, 180, {6, 4}},
190 {{7, 4}, 270, {4, 6}}};
192 // The usual ReserveOutputBuffer() -> OnIncomingCapturedVideoFrame() cannot
193 // be used since it does not resolve rotations or crops. The memory backed
194 // buffer OnIncomingCapturedData() is used instead, with a dummy scratchpad
196 const size_t kScratchpadSizeInBytes
= 400;
197 unsigned char data
[kScratchpadSizeInBytes
] = {};
199 media::VideoCaptureParams params
;
200 for (const auto& size_and_rotation
: kSizeAndRotations
) {
201 ASSERT_GE(kScratchpadSizeInBytes
,
202 size_and_rotation
.input_resolution
.GetArea() * 4u)
203 << "Scratchpad is too small to hold the largest pixel format (ARGB).";
204 params
.requested_format
=
205 media::VideoCaptureFormat(size_and_rotation
.input_resolution
, 30.0f
,
206 media::PIXEL_FORMAT_ARGB
);
207 gfx::Size coded_size
;
208 EXPECT_CALL(*controller_
, MockDoIncomingCapturedVideoFrameOnIOThread(_
))
210 .WillOnce(SaveArg
<0>(&coded_size
));
211 device_client_
->OnIncomingCapturedData(
212 data
, params
.requested_format
.ImageAllocationSize(),
213 params
.requested_format
, size_and_rotation
.rotation
, base::TimeTicks());
214 base::RunLoop().RunUntilIdle();
216 EXPECT_EQ(coded_size
.width(), size_and_rotation
.output_resolution
.width());
217 EXPECT_EQ(coded_size
.height(),
218 size_and_rotation
.output_resolution
.height());
220 Mock::VerifyAndClearExpectations(controller_
.get());
224 } // namespace content