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

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

Issue 2729783003: [Mojo Video Capture] Add content_browsertest for exercising video capture (Closed)
Patch Set: 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 protected:
80 void SetUpCommandLine(base::CommandLine* command_line) override {
81 command_line->AppendSwitchASCII(
82 switches::kUseFakeDeviceForMediaStream,
83 GetParam().fake_device_factory_config_string);
84 command_line->AppendSwitch(switches::kUseFakeUIForMediaStream);
85 }
86
87 void SetUpRequiringBrowserMainLoopOnMainThread() {
88 BrowserMainLoop* browser_main_loop = BrowserMainLoop::GetInstance();
89 ASSERT_TRUE(browser_main_loop);
90 media_stream_manager_ = browser_main_loop->media_stream_manager();
91 ASSERT_TRUE(media_stream_manager_);
92 }
93
94 void SetUpAndStartCaptureDeviceOnIOThread(base::Closure continuation) {
95 video_capture_manager_ = media_stream_manager_->video_capture_manager();
96 ASSERT_TRUE(video_capture_manager_);
97 video_capture_manager_->RegisterListener(&mock_stream_provider_listener_);
98 video_capture_manager_->EnumerateDevices(
99 base::Bind(&VideoCaptureBrowserTest::OnDeviceDescriptorsReceived,
100 base::Unretained(this), std::move(continuation)));
101 }
102
103 void OnDeviceDescriptorsReceived(
104 base::Closure continuation,
105 const media::VideoCaptureDeviceDescriptors& descriptors) {
106 ASSERT_TRUE(GetParam().device_index_to_use < descriptors.size());
107 const auto& descriptor = descriptors[GetParam().device_index_to_use];
108 MediaStreamDevice media_stream_device(
109 MEDIA_DEVICE_VIDEO_CAPTURE, descriptor.device_id,
110 descriptor.display_name, descriptor.facing);
111 session_id_ = video_capture_manager_->Open(media_stream_device);
112 media::VideoCaptureParams capture_params;
113 capture_params.requested_format = media::VideoCaptureFormat(
114 GetParam().resolution_to_use, GetParam().frame_rate_to_use,
115 GetParam().pixel_format_to_use);
116 video_capture_manager_->StartCaptureForClient(
117 session_id_, capture_params, stub_client_id_,
118 &mock_controller_event_handler_,
119 base::Bind(&VideoCaptureBrowserTest::OnConnectClientToControllerAnswer,
120 base::Unretained(this), std::move(continuation)));
121 }
122
123 void OnConnectClientToControllerAnswer(
124 base::Closure continuation,
125 const base::WeakPtr<VideoCaptureController>& controller) {
126 ASSERT_TRUE(controller.get());
127 controller_ = controller;
128 if (!continuation)
129 return;
130 continuation.Run();
131 }
132
133 void TearDownCaptureDeviceOnIOThread(base::Closure continuation,
134 bool post_to_end_of_message_queue) {
135 // StopCaptureForClient must not be called synchronously from either the
136 // |done_cb| passed to StartCaptureForClient() nor any callback made to a
137 // VideoCaptureControllerEventHandler. To satisfy this, we have to post our
138 // invocation to the end of the IO message queue.
139 if (post_to_end_of_message_queue) {
140 base::ThreadTaskRunnerHandle::Get()->PostTask(
141 FROM_HERE,
142 base::Bind(&VideoCaptureBrowserTest::TearDownCaptureDeviceOnIOThread,
143 base::Unretained(this), continuation, false));
144 return;
145 }
146
147 video_capture_manager_->StopCaptureForClient(
148 controller_.get(), stub_client_id_, &mock_controller_event_handler_,
149 false);
150
151 EXPECT_CALL(mock_stream_provider_listener_, Closed(_, _))
152 .WillOnce(InvokeWithoutArgs([continuation]() { continuation.Run(); }));
153
154 video_capture_manager_->Close(session_id_);
155 }
156
157 void RunStartAndImmediatelyStopTest() {
158 SetUpRequiringBrowserMainLoopOnMainThread();
159 base::RunLoop run_loop;
160 auto quit_run_loop_on_current_thread_cb =
161 media::BindToCurrentLoop(run_loop.QuitClosure());
162 auto after_start_continuation =
163 base::Bind(&VideoCaptureBrowserTest::TearDownCaptureDeviceOnIOThread,
164 base::Unretained(this),
165 std::move(quit_run_loop_on_current_thread_cb), true);
166 BrowserThread::PostTask(
167 content::BrowserThread::IO, FROM_HERE,
168 base::Bind(
169 &VideoCaptureBrowserTest::SetUpAndStartCaptureDeviceOnIOThread,
170 base::Unretained(this), std::move(after_start_continuation)));
171 run_loop.Run();
172 }
173
174 void RunReceiveFramesFromFakeCaptureDeviceTest() {
175 SetUpRequiringBrowserMainLoopOnMainThread();
176
177 std::vector<FrameInfo> received_frame_infos;
178 static const size_t num_frames_to_receive = 3;
mcasas 2017/03/03 00:21:12 nit: s/num_frames_to_receive/kNumFramesToReceive/
chfremer 2017/03/03 18:21:13 Done.
179 base::RunLoop run_loop;
180
181 auto quit_run_loop_on_current_thread_cb =
182 media::BindToCurrentLoop(run_loop.QuitClosure());
183 auto finish_test_cb =
184 base::Bind(&VideoCaptureBrowserTest::TearDownCaptureDeviceOnIOThread,
185 base::Unretained(this),
186 std::move(quit_run_loop_on_current_thread_cb), true);
187
188 EXPECT_CALL(mock_controller_event_handler_, DoOnBufferCreated(_, _, _, _))
189 .Times(AtLeast(1));
190 EXPECT_CALL(mock_controller_event_handler_, OnBufferReady(_, _, _))
191 .WillRepeatedly(
192 Invoke([&received_frame_infos, &finish_test_cb](
193 VideoCaptureControllerID id, int buffer_id,
194 const media::mojom::VideoFrameInfoPtr& frame_info) {
195 FrameInfo received_frame_info;
196 received_frame_info.pixel_format = frame_info->pixel_format;
197 received_frame_info.storage_type = frame_info->storage_type;
198 received_frame_info.size = frame_info->coded_size;
199 received_frame_info.timestamp = frame_info->timestamp;
200 received_frame_infos.emplace_back(received_frame_info);
201 if (received_frame_infos.size() >= num_frames_to_receive) {
202 finish_test_cb.Run();
203 return;
mcasas 2017/03/03 00:21:13 No need to return here since the callback does not
chfremer 2017/03/03 18:21:13 Done.
204 }
205 }));
206
207 base::Closure do_nothing;
208 BrowserThread::PostTask(
209 content::BrowserThread::IO, FROM_HERE,
210 base::Bind(
211 &VideoCaptureBrowserTest::SetUpAndStartCaptureDeviceOnIOThread,
212 base::Unretained(this), std::move(do_nothing)));
213 run_loop.Run();
214
215 EXPECT_GE(received_frame_infos.size(), num_frames_to_receive);
216 base::TimeDelta previous_timestamp;
217 bool first_frame = true;
218 for (const auto& frame_info : received_frame_infos) {
219 EXPECT_EQ(GetParam().pixel_format_to_use, frame_info.pixel_format);
220 EXPECT_EQ(media::PIXEL_STORAGE_CPU, frame_info.storage_type);
221 EXPECT_EQ(GetParam().resolution_to_use, frame_info.size);
222 // Timestamps are expected to increase
223 if (!first_frame)
224 EXPECT_GT(frame_info.timestamp, previous_timestamp);
225 first_frame = false;
226 previous_timestamp = frame_info.timestamp;
227 }
228 }
229
230 private:
231 MediaStreamManager* media_stream_manager_ = nullptr;
232 VideoCaptureManager* video_capture_manager_ = nullptr;
233 int session_id_ = 0;
234 const VideoCaptureControllerID stub_client_id_ = 123;
235 MockMediaStreamProviderListener mock_stream_provider_listener_;
236 MockVideoCaptureControllerEventHandler mock_controller_event_handler_;
237 base::WeakPtr<VideoCaptureController> controller_;
238 };
239
240 IN_PROC_BROWSER_TEST_P(VideoCaptureBrowserTest, StartAndImmediatelyStop) {
241 RunStartAndImmediatelyStopTest();
mcasas 2017/03/03 00:21:12 Instead of adding this function to VideoCaptureBro
chfremer 2017/03/03 18:21:13 Done.
242 }
243
244 IN_PROC_BROWSER_TEST_P(VideoCaptureBrowserTest,
245 ReceiveFramesFromFakeCaptureDevice) {
246 RunReceiveFramesFromFakeCaptureDeviceTest();
247 }
248
249 INSTANTIATE_TEST_CASE_P(
250 ,
251 VideoCaptureBrowserTest,
252 Values(TestParams{"fps=25,device-count=2", 0, media::PIXEL_FORMAT_I420,
253 gfx::Size(1280, 720), 25.0f},
254 // The 2nd device outputs Y16
255 TestParams{"fps=25,device-count=2", 1, media::PIXEL_FORMAT_Y16,
256 gfx::Size(1280, 720), 25.0f},
257 TestParams{"fps=15,device-count=2", 1, media::PIXEL_FORMAT_Y16,
258 gfx::Size(640, 480), 15.0f},
259 // The 3rd device outputs MJPEG, which is converted to I420.
260 TestParams{"fps=15,device-count=3", 2, media::PIXEL_FORMAT_I420,
261 gfx::Size(640, 480), 25.0f}));
262
263 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698