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::VideoCapturePixelFormat::VIDEO_CAPTURE_PIXEL_FORMAT_I420
,
78 media::VideoPixelStorage::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::VideoCapturePixelFormat::VIDEO_CAPTURE_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::VideoCapturePixelFormat::VIDEO_CAPTURE_PIXEL_FORMAT_I420
,
117 media::VideoPixelStorage::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::VIDEO_CAPTURE_PIXEL_FORMAT_MAX
;
147 // Conversion from MJPEG to I420 seems to be unsupported.
148 if (format
== media::VIDEO_CAPTURE_PIXEL_FORMAT_UNKNOWN
||
149 format
== media::VIDEO_CAPTURE_PIXEL_FORMAT_MJPEG
) {
152 #if !defined(OS_LINUX) && !defined(OS_WIN)
153 if (format
== media::VIDEO_CAPTURE_PIXEL_FORMAT_RGB24
){
157 media::VideoCaptureParams params
;
158 params
.requested_format
= media::VideoCaptureFormat(
159 capture_resolution
, 30.0f
, media::VideoCapturePixelFormat(format
));
160 EXPECT_CALL(*controller_
, MockDoIncomingCapturedVideoFrameOnIOThread(_
))
162 device_client_
->OnIncomingCapturedData(
163 data
, params
.requested_format
.ImageAllocationSize(),
164 params
.requested_format
, 0 /* clockwise_rotation */, base::TimeTicks());
165 base::RunLoop().RunUntilIdle();
166 Mock::VerifyAndClearExpectations(controller_
.get());
170 // Test that we receive the expected resolution for a given captured frame
171 // resolution and rotation. Odd resolutions are also cropped.
172 TEST_F(VideoCaptureDeviceClientTest
, CheckRotationsAndCrops
) {
173 const struct SizeAndRotation
{
174 gfx::Size input_resolution
;
176 gfx::Size output_resolution
;
177 } kSizeAndRotations
[] = {{{6, 4}, 0, {6, 4}},
178 {{6, 4}, 90, {4, 6}},
179 {{6, 4}, 180, {6, 4}},
180 {{6, 4}, 270, {4, 6}},
182 {{7, 4}, 90, {4, 6}},
183 {{7, 4}, 180, {6, 4}},
184 {{7, 4}, 270, {4, 6}}};
186 // The usual ReserveOutputBuffer() -> OnIncomingCapturedVideoFrame() cannot
187 // be used since it does not resolve rotations or crops. The memory backed
188 // buffer OnIncomingCapturedData() is used instead, with a dummy scratchpad
190 const size_t kScratchpadSizeInBytes
= 400;
191 unsigned char data
[kScratchpadSizeInBytes
] = {};
193 media::VideoCaptureParams params
;
194 for (const auto& size_and_rotation
: kSizeAndRotations
) {
195 ASSERT_GE(kScratchpadSizeInBytes
,
196 size_and_rotation
.input_resolution
.GetArea() * 4u)
197 << "Scratchpad is too small to hold the largest pixel format (ARGB).";
198 params
.requested_format
=
199 media::VideoCaptureFormat(size_and_rotation
.input_resolution
, 30.0f
,
200 media::VIDEO_CAPTURE_PIXEL_FORMAT_ARGB
);
201 gfx::Size coded_size
;
202 EXPECT_CALL(*controller_
, MockDoIncomingCapturedVideoFrameOnIOThread(_
))
204 .WillOnce(SaveArg
<0>(&coded_size
));
205 device_client_
->OnIncomingCapturedData(
206 data
, params
.requested_format
.ImageAllocationSize(),
207 params
.requested_format
, size_and_rotation
.rotation
, base::TimeTicks());
208 base::RunLoop().RunUntilIdle();
210 EXPECT_EQ(coded_size
.width(), size_and_rotation
.output_resolution
.width());
211 EXPECT_EQ(coded_size
.height(),
212 size_and_rotation
.output_resolution
.height());
214 Mock::VerifyAndClearExpectations(controller_
.get());
218 } // namespace content