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

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: miguel@ 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.
miu 2017/03/06 21:54:10 Consideration about file location: content/browser
chfremer 2017/03/06 23:39:38 Good point. I believe that fact that there was no
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) {
miu 2017/03/06 21:54:10 Why are two methods public, and the rest protected
chfremer 2017/03/06 23:39:38 These two methods are used in base::Bind() express
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 void SetUpRequiringBrowserMainLoopOnMainThread() {
miu 2017/03/06 21:54:10 Seems like this should be: void SetUp() overrid
chfremer 2017/03/06 23:39:38 Added code commment for clarification: // This c
122 BrowserMainLoop* browser_main_loop = BrowserMainLoop::GetInstance();
123 ASSERT_TRUE(browser_main_loop);
124 media_stream_manager_ = browser_main_loop->media_stream_manager();
125 ASSERT_TRUE(media_stream_manager_);
126 }
127
128 void OnDeviceDescriptorsReceived(
129 base::Closure continuation,
130 const media::VideoCaptureDeviceDescriptors& descriptors) {
131 ASSERT_TRUE(GetParam().device_index_to_use < descriptors.size());
132 const auto& descriptor = descriptors[GetParam().device_index_to_use];
133 MediaStreamDevice media_stream_device(
134 MEDIA_DEVICE_VIDEO_CAPTURE, descriptor.device_id,
135 descriptor.display_name, descriptor.facing);
136 session_id_ = video_capture_manager_->Open(media_stream_device);
137 media::VideoCaptureParams capture_params;
138 capture_params.requested_format = media::VideoCaptureFormat(
139 GetParam().resolution_to_use, GetParam().frame_rate_to_use,
140 GetParam().pixel_format_to_use);
141 video_capture_manager_->StartCaptureForClient(
142 session_id_, capture_params, stub_client_id_,
143 &mock_controller_event_handler_,
144 base::Bind(&VideoCaptureBrowserTest::OnConnectClientToControllerAnswer,
145 base::Unretained(this), std::move(continuation)));
146 }
147
148 void OnConnectClientToControllerAnswer(
149 base::Closure continuation,
150 const base::WeakPtr<VideoCaptureController>& controller) {
151 ASSERT_TRUE(controller.get());
152 controller_ = controller;
153 if (!continuation)
154 return;
155 continuation.Run();
156 }
157
158 protected:
159 MediaStreamManager* media_stream_manager_ = nullptr;
160 VideoCaptureManager* video_capture_manager_ = nullptr;
161 int session_id_ = 0;
162 const VideoCaptureControllerID stub_client_id_ = 123;
163 MockMediaStreamProviderListener mock_stream_provider_listener_;
164 MockVideoCaptureControllerEventHandler mock_controller_event_handler_;
165 base::WeakPtr<VideoCaptureController> controller_;
166 };
167
168 IN_PROC_BROWSER_TEST_P(VideoCaptureBrowserTest, StartAndImmediatelyStop) {
169 SetUpRequiringBrowserMainLoopOnMainThread();
170 base::RunLoop run_loop;
171 auto quit_run_loop_on_current_thread_cb =
172 media::BindToCurrentLoop(run_loop.QuitClosure());
173 auto after_start_continuation =
174 base::Bind(&VideoCaptureBrowserTest::TearDownCaptureDeviceOnIOThread,
175 base::Unretained(this),
176 std::move(quit_run_loop_on_current_thread_cb), true);
177 BrowserThread::PostTask(
178 content::BrowserThread::IO, FROM_HERE,
179 base::Bind(&VideoCaptureBrowserTest::SetUpAndStartCaptureDeviceOnIOThread,
180 base::Unretained(this), std::move(after_start_continuation)));
181 run_loop.Run();
182 }
183
184 IN_PROC_BROWSER_TEST_P(VideoCaptureBrowserTest,
185 ReceiveFramesFromFakeCaptureDevice) {
186 SetUpRequiringBrowserMainLoopOnMainThread();
187
188 std::vector<FrameInfo> received_frame_infos;
189 static const size_t kNumFramesToReceive = 3;
190 base::RunLoop run_loop;
191
192 auto quit_run_loop_on_current_thread_cb =
193 media::BindToCurrentLoop(run_loop.QuitClosure());
194 auto finish_test_cb =
195 base::Bind(&VideoCaptureBrowserTest::TearDownCaptureDeviceOnIOThread,
196 base::Unretained(this),
197 std::move(quit_run_loop_on_current_thread_cb), true);
198
199 EXPECT_CALL(mock_controller_event_handler_, DoOnBufferCreated(_, _, _, _))
200 .Times(AtLeast(1));
201 EXPECT_CALL(mock_controller_event_handler_, OnBufferReady(_, _, _))
202 .WillRepeatedly(
203 Invoke([&received_frame_infos, &finish_test_cb](
204 VideoCaptureControllerID id, int buffer_id,
205 const media::mojom::VideoFrameInfoPtr& frame_info) {
206 FrameInfo received_frame_info;
207 received_frame_info.pixel_format = frame_info->pixel_format;
208 received_frame_info.storage_type = frame_info->storage_type;
209 received_frame_info.size = frame_info->coded_size;
210 received_frame_info.timestamp = frame_info->timestamp;
211 received_frame_infos.emplace_back(received_frame_info);
212 if (received_frame_infos.size() >= kNumFramesToReceive) {
213 finish_test_cb.Run();
214 }
215 }));
216
217 base::Closure do_nothing;
218 BrowserThread::PostTask(
219 content::BrowserThread::IO, FROM_HERE,
220 base::Bind(&VideoCaptureBrowserTest::SetUpAndStartCaptureDeviceOnIOThread,
221 base::Unretained(this), std::move(do_nothing)));
222 run_loop.Run();
223
224 EXPECT_GE(received_frame_infos.size(), kNumFramesToReceive);
225 base::TimeDelta previous_timestamp;
226 bool first_frame = true;
227 for (const auto& frame_info : received_frame_infos) {
228 EXPECT_EQ(GetParam().pixel_format_to_use, frame_info.pixel_format);
229 EXPECT_EQ(media::PIXEL_STORAGE_CPU, frame_info.storage_type);
230 EXPECT_EQ(GetParam().resolution_to_use, frame_info.size);
231 // Timestamps are expected to increase
232 if (!first_frame)
233 EXPECT_GT(frame_info.timestamp, previous_timestamp);
234 first_frame = false;
235 previous_timestamp = frame_info.timestamp;
236 }
237 }
238
239 INSTANTIATE_TEST_CASE_P(
240 ,
241 VideoCaptureBrowserTest,
242 Values(TestParams{"fps=25,device-count=2", 0, media::PIXEL_FORMAT_I420,
243 gfx::Size(1280, 720), 25.0f},
244 // The 2nd device outputs Y16
245 TestParams{"fps=25,device-count=2", 1, media::PIXEL_FORMAT_Y16,
246 gfx::Size(1280, 720), 25.0f},
247 TestParams{"fps=15,device-count=2", 1, media::PIXEL_FORMAT_Y16,
248 gfx::Size(640, 480), 15.0f},
249 // The 3rd device outputs MJPEG, which is converted to I420.
250 TestParams{"fps=15,device-count=3", 2, media::PIXEL_FORMAT_I420,
251 gfx::Size(640, 480), 25.0f}));
252
253 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698