Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(64)

Side by Side Diff: content/browser/renderer_host/media/video_capture_browsertest.cc

Issue 2729783003: [Mojo Video Capture] Add content_browsertest for exercising video capture (Closed)
Patch Set: incorporated miu@'s suggestions Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2017 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.
4
5 #include "base/command_line.h"
6 #include "base/run_loop.h"
7 #include "build/build_config.h"
8 #include "content/browser/browser_main_loop.h"
9 #include "content/browser/renderer_host/media/media_stream_manager.h"
10 #include "content/browser/renderer_host/media/video_capture_manager.h"
11 #include "content/public/common/content_switches.h"
12 #include "content/public/test/content_browser_test.h"
13 #include "media/base/bind_to_current_loop.h"
14 #include "media/base/media_switches.h"
15 #include "media/capture/video_capture_types.h"
16 #include "testing/gmock/include/gmock/gmock.h"
17
18 using testing::_;
19 using testing::AtLeast;
20 using testing::Invoke;
21 using testing::InvokeWithoutArgs;
22 using testing::Values;
23
24 namespace content {
25
26 class MockVideoCaptureControllerEventHandler
27 : public VideoCaptureControllerEventHandler {
28 public:
29 MOCK_METHOD4(DoOnBufferCreated,
30 void(VideoCaptureControllerID id,
31 mojo::ScopedSharedBufferHandle* handle,
32 int length,
33 int buffer_id));
34 MOCK_METHOD2(OnBufferDestroyed,
35 void(VideoCaptureControllerID, int buffer_id));
36 MOCK_METHOD3(OnBufferReady,
37 void(VideoCaptureControllerID id,
38 int buffer_id,
39 const media::mojom::VideoFrameInfoPtr& frame_info));
40 MOCK_METHOD1(OnStarted, void(VideoCaptureControllerID));
41 MOCK_METHOD1(OnEnded, void(VideoCaptureControllerID));
42 MOCK_METHOD1(OnError, void(VideoCaptureControllerID));
43 MOCK_METHOD1(OnStartedUsingGpuDecode, void(VideoCaptureControllerID));
44 MOCK_METHOD1(OnStoppedUsingGpuDecode, void(VideoCaptureControllerID));
45
46 void OnBufferCreated(VideoCaptureControllerID id,
47 mojo::ScopedSharedBufferHandle handle,
48 int length,
49 int buffer_id) override {
50 DoOnBufferCreated(id, &handle, length, buffer_id);
51 }
52 };
53
54 class MockMediaStreamProviderListener : public MediaStreamProviderListener {
55 public:
56 MOCK_METHOD2(Opened, void(MediaStreamType, int));
57 MOCK_METHOD2(Closed, void(MediaStreamType, int));
58 MOCK_METHOD2(Aborted, void(MediaStreamType, int));
59 };
60
61 struct TestParams {
62 std::string fake_device_factory_config_string;
63 size_t device_index_to_use;
64 media::VideoPixelFormat pixel_format_to_use;
65 gfx::Size resolution_to_use;
66 float frame_rate_to_use;
67 };
68
69 struct FrameInfo {
70 gfx::Size size;
71 media::VideoPixelFormat pixel_format;
72 media::VideoPixelStorage storage_type;
73 base::TimeDelta timestamp;
74 };
75
76 class VideoCaptureBrowserTest
77 : public ContentBrowserTest,
78 public ::testing::WithParamInterface<TestParams> {
79 public:
80 void SetUpAndStartCaptureDeviceOnIOThread(base::Closure continuation) {
81 video_capture_manager_ = media_stream_manager_->video_capture_manager();
82 ASSERT_TRUE(video_capture_manager_);
83 video_capture_manager_->RegisterListener(&mock_stream_provider_listener_);
84 video_capture_manager_->EnumerateDevices(
85 base::Bind(&VideoCaptureBrowserTest::OnDeviceDescriptorsReceived,
86 base::Unretained(this), std::move(continuation)));
87 }
88
89 void TearDownCaptureDeviceOnIOThread(base::Closure continuation,
90 bool post_to_end_of_message_queue) {
91 // StopCaptureForClient must not be called synchronously from either the
92 // |done_cb| passed to StartCaptureForClient() nor any callback made to a
93 // VideoCaptureControllerEventHandler. To satisfy this, we have to post our
94 // invocation to the end of the IO message queue.
95 if (post_to_end_of_message_queue) {
96 base::ThreadTaskRunnerHandle::Get()->PostTask(
97 FROM_HERE,
98 base::Bind(&VideoCaptureBrowserTest::TearDownCaptureDeviceOnIOThread,
99 base::Unretained(this), continuation, false));
100 return;
101 }
102
103 video_capture_manager_->StopCaptureForClient(
104 controller_.get(), stub_client_id_, &mock_controller_event_handler_,
105 false);
106
107 EXPECT_CALL(mock_stream_provider_listener_, Closed(_, _))
108 .WillOnce(InvokeWithoutArgs([continuation]() { continuation.Run(); }));
109
110 video_capture_manager_->Close(session_id_);
111 }
112
113 protected:
114 void SetUpCommandLine(base::CommandLine* command_line) override {
115 command_line->AppendSwitchASCII(
116 switches::kUseFakeDeviceForMediaStream,
117 GetParam().fake_device_factory_config_string);
118 command_line->AppendSwitch(switches::kUseFakeUIForMediaStream);
119 }
120
121 // This cannot be part of an override of SetUp(), because at the time when
122 // SetUp() is invoked, the BrowserMainLoop does not exist yet.
123 void SetUpRequiringBrowserMainLoopOnMainThread() {
124 BrowserMainLoop* browser_main_loop = BrowserMainLoop::GetInstance();
125 ASSERT_TRUE(browser_main_loop);
126 media_stream_manager_ = browser_main_loop->media_stream_manager();
127 ASSERT_TRUE(media_stream_manager_);
128 }
129
130 void OnDeviceDescriptorsReceived(
131 base::Closure continuation,
132 const media::VideoCaptureDeviceDescriptors& descriptors) {
133 ASSERT_TRUE(GetParam().device_index_to_use < descriptors.size());
134 const auto& descriptor = descriptors[GetParam().device_index_to_use];
135 MediaStreamDevice media_stream_device(
136 MEDIA_DEVICE_VIDEO_CAPTURE, descriptor.device_id,
137 descriptor.display_name, descriptor.facing);
138 session_id_ = video_capture_manager_->Open(media_stream_device);
139 media::VideoCaptureParams capture_params;
140 capture_params.requested_format = media::VideoCaptureFormat(
141 GetParam().resolution_to_use, GetParam().frame_rate_to_use,
142 GetParam().pixel_format_to_use);
143 video_capture_manager_->StartCaptureForClient(
144 session_id_, capture_params, stub_client_id_,
145 &mock_controller_event_handler_,
146 base::Bind(&VideoCaptureBrowserTest::OnConnectClientToControllerAnswer,
147 base::Unretained(this), std::move(continuation)));
148 }
149
150 void OnConnectClientToControllerAnswer(
151 base::Closure continuation,
152 const base::WeakPtr<VideoCaptureController>& controller) {
153 ASSERT_TRUE(controller.get());
154 controller_ = controller;
155 if (!continuation)
156 return;
157 continuation.Run();
158 }
159
160 protected:
161 MediaStreamManager* media_stream_manager_ = nullptr;
162 VideoCaptureManager* video_capture_manager_ = nullptr;
163 int session_id_ = 0;
164 const VideoCaptureControllerID stub_client_id_ = 123;
165 MockMediaStreamProviderListener mock_stream_provider_listener_;
166 MockVideoCaptureControllerEventHandler mock_controller_event_handler_;
167 base::WeakPtr<VideoCaptureController> controller_;
168 };
169
170 IN_PROC_BROWSER_TEST_P(VideoCaptureBrowserTest, StartAndImmediatelyStop) {
171 SetUpRequiringBrowserMainLoopOnMainThread();
172 base::RunLoop run_loop;
173 auto quit_run_loop_on_current_thread_cb =
174 media::BindToCurrentLoop(run_loop.QuitClosure());
175 auto after_start_continuation =
176 base::Bind(&VideoCaptureBrowserTest::TearDownCaptureDeviceOnIOThread,
177 base::Unretained(this),
178 std::move(quit_run_loop_on_current_thread_cb), true);
179 BrowserThread::PostTask(
180 content::BrowserThread::IO, FROM_HERE,
181 base::Bind(&VideoCaptureBrowserTest::SetUpAndStartCaptureDeviceOnIOThread,
182 base::Unretained(this), std::move(after_start_continuation)));
183 run_loop.Run();
184 }
185
186 IN_PROC_BROWSER_TEST_P(VideoCaptureBrowserTest,
187 ReceiveFramesFromFakeCaptureDevice) {
188 SetUpRequiringBrowserMainLoopOnMainThread();
189
190 std::vector<FrameInfo> received_frame_infos;
191 static const size_t kNumFramesToReceive = 3;
192 base::RunLoop run_loop;
193
194 auto quit_run_loop_on_current_thread_cb =
195 media::BindToCurrentLoop(run_loop.QuitClosure());
196 auto finish_test_cb =
197 base::Bind(&VideoCaptureBrowserTest::TearDownCaptureDeviceOnIOThread,
198 base::Unretained(this),
199 std::move(quit_run_loop_on_current_thread_cb), true);
200
201 EXPECT_CALL(mock_controller_event_handler_, DoOnBufferCreated(_, _, _, _))
202 .Times(AtLeast(1));
203 EXPECT_CALL(mock_controller_event_handler_, OnBufferReady(_, _, _))
204 .WillRepeatedly(
205 Invoke([&received_frame_infos, &finish_test_cb](
206 VideoCaptureControllerID id, int buffer_id,
207 const media::mojom::VideoFrameInfoPtr& frame_info) {
208 FrameInfo received_frame_info;
209 received_frame_info.pixel_format = frame_info->pixel_format;
210 received_frame_info.storage_type = frame_info->storage_type;
211 received_frame_info.size = frame_info->coded_size;
212 received_frame_info.timestamp = frame_info->timestamp;
213 received_frame_infos.emplace_back(received_frame_info);
214 if (received_frame_infos.size() >= kNumFramesToReceive) {
215 finish_test_cb.Run();
216 }
217 }));
218
219 base::Closure do_nothing;
220 BrowserThread::PostTask(
221 content::BrowserThread::IO, FROM_HERE,
222 base::Bind(&VideoCaptureBrowserTest::SetUpAndStartCaptureDeviceOnIOThread,
223 base::Unretained(this), std::move(do_nothing)));
224 run_loop.Run();
225
226 EXPECT_GE(received_frame_infos.size(), kNumFramesToReceive);
227 base::TimeDelta previous_timestamp;
228 bool first_frame = true;
229 for (const auto& frame_info : received_frame_infos) {
230 EXPECT_EQ(GetParam().pixel_format_to_use, frame_info.pixel_format);
231 EXPECT_EQ(media::PIXEL_STORAGE_CPU, frame_info.storage_type);
232 EXPECT_EQ(GetParam().resolution_to_use, frame_info.size);
233 // Timestamps are expected to increase
234 if (!first_frame)
235 EXPECT_GT(frame_info.timestamp, previous_timestamp);
236 first_frame = false;
237 previous_timestamp = frame_info.timestamp;
238 }
239 }
240
241 INSTANTIATE_TEST_CASE_P(
242 ,
243 VideoCaptureBrowserTest,
244 Values(TestParams{"fps=25,device-count=2", 0, media::PIXEL_FORMAT_I420,
245 gfx::Size(1280, 720), 25.0f},
246 // The 2nd device outputs Y16
247 TestParams{"fps=25,device-count=2", 1, media::PIXEL_FORMAT_Y16,
248 gfx::Size(1280, 720), 25.0f},
249 TestParams{"fps=15,device-count=2", 1, media::PIXEL_FORMAT_Y16,
250 gfx::Size(640, 480), 15.0f},
251 // The 3rd device outputs MJPEG, which is converted to I420.
252 TestParams{"fps=15,device-count=3", 2, media::PIXEL_FORMAT_I420,
253 gfx::Size(640, 480), 25.0f}));
254
255 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698