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

Side by Side Diff: media/capture/video/chromeos/stream_buffer_manager_unittest.cc

Issue 2837273004: media: add video capture device for ARC++ camera HAL v3 (Closed)
Patch Set: restore patch set 24 Created 3 years, 6 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 "media/capture/video/chromeos/stream_buffer_manager.h"
6
7 #include "base/run_loop.h"
8 #include "base/test/scoped_task_environment.h"
9 #include "base/threading/thread.h"
10 #include "base/threading/thread_task_runner_handle.h"
11 #include "media/capture/video/chromeos/camera_device_context.h"
12 #include "media/capture/video/chromeos/camera_device_delegate.h"
13 #include "media/capture/video/chromeos/mock_video_capture_client.h"
14 #include "media/capture/video/chromeos/mojo/arc_camera3.mojom.h"
15 #include "testing/gmock/include/gmock/gmock.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17
18 using testing::_;
19 using testing::A;
20 using testing::AtLeast;
21 using testing::Invoke;
22 using testing::InvokeWithoutArgs;
23
24 namespace media {
25
26 namespace {
27
28 class MockStreamCaptureInterface : public StreamCaptureInterface {
29 public:
30 void RegisterBuffer(uint64_t buffer_id,
31 arc::mojom::Camera3DeviceOps::BufferType type,
32 std::vector<mojo::ScopedHandle> fds,
33 uint32_t drm_format,
34 arc::mojom::HalPixelFormat hal_pixel_format,
35 uint32_t width,
36 uint32_t height,
37 std::vector<uint32_t> strides,
38 std::vector<uint32_t> offsets,
39 base::OnceCallback<void(int32_t)> callback) {
40 DoRegisterBuffer(buffer_id, type, fds, drm_format, hal_pixel_format, width,
41 height, strides, offsets, callback);
42 }
43 MOCK_METHOD10(DoRegisterBuffer,
44 void(uint64_t buffer_id,
45 arc::mojom::Camera3DeviceOps::BufferType type,
46 std::vector<mojo::ScopedHandle>& fds,
47 uint32_t drm_format,
48 arc::mojom::HalPixelFormat hal_pixel_format,
49 uint32_t width,
50 uint32_t height,
51 const std::vector<uint32_t>& strides,
52 const std::vector<uint32_t>& offsets,
53 base::OnceCallback<void(int32_t)>& callback));
54
55 void ProcessCaptureRequest(arc::mojom::Camera3CaptureRequestPtr request,
56 base::OnceCallback<void(int32_t)> callback) {
57 DoProcessCaptureRequest(request, callback);
58 }
59 MOCK_METHOD2(DoProcessCaptureRequest,
60 void(arc::mojom::Camera3CaptureRequestPtr& request,
61 base::OnceCallback<void(int32_t)>& callback));
62 };
63
64 const VideoCaptureFormat kDefaultCaptureFormat(gfx::Size(1280, 720),
65 30.0,
66 PIXEL_FORMAT_NV12);
67
68 } // namespace
69
70 class StreamBufferManagerTest : public ::testing::Test {
71 public:
72 void SetUp() override {
73 quit_ = false;
74 arc::mojom::Camera3CallbackOpsRequest callback_ops_request =
75 mojo::MakeRequest(&mock_callback_ops_);
76 std::unique_ptr<VideoCaptureDevice::Client> mock_client(
77 new unittest_internal::MockVideoCaptureClient());
78 device_context_.reset(new CameraDeviceContext(std::move(mock_client)));
chfremer 2017/06/08 21:58:38 nit: Not sure what the style guide says here, but
jcliang 2017/06/09 05:16:01 Done.
79
80 stream_buffer_manager_ = new StreamBufferManager(
81 std::move(callback_ops_request),
82 std::unique_ptr<StreamCaptureInterface>(
83 new MockStreamCaptureInterface()),
chfremer 2017/06/08 21:58:38 base::MakeUnique<>
jcliang 2017/06/09 05:16:01 Done.
84 device_context_.get(), base::ThreadTaskRunnerHandle::Get());
85 }
86
87 void TearDown() override {
88 while (!stream_buffer_manager_->HasOneRef()) {
89 base::PlatformThread::YieldCurrentThread();
90 }
chfremer 2017/06/08 21:58:38 I still don't think that this is a clean solution.
jcliang 2017/06/09 05:16:01 This pattern in the unit test is mainly to make su
chfremer 2017/06/09 17:53:18 Wouldn't it be possible to add a method to StreamB
91 stream_buffer_manager_ = nullptr;
92 }
93
94 void DoLoop() {
95 run_loop_.reset(new base::RunLoop());
96 run_loop_->Run();
97 }
98
99 void QuitCaptureLoop() {
100 quit_ = true;
101 if (run_loop_) {
102 run_loop_->Quit();
103 }
104 }
105
106 void RegisterBuffer(uint64_t buffer_id,
107 arc::mojom::Camera3DeviceOps::BufferType type,
108 std::vector<mojo::ScopedHandle>& fds,
109 uint32_t drm_format,
110 arc::mojom::HalPixelFormat hal_pixel_format,
111 uint32_t width,
112 uint32_t height,
113 const std::vector<uint32_t>& strides,
114 const std::vector<uint32_t>& offsets,
115 base::OnceCallback<void(int32_t)>& callback) {
116 if (quit_) {
117 return;
118 }
119 std::move(callback).Run(0);
120 }
121
122 void ProcessCaptureRequest(arc::mojom::Camera3CaptureRequestPtr& request,
123 base::OnceCallback<void(int32_t)>& callback) {
124 if (quit_) {
125 return;
126 }
127 std::move(callback).Run(0);
128 mock_callback_ops_->Notify(PrepareShutterNotifyMessage(
129 request->frame_number, base::TimeTicks::Now().ToInternalValue()));
130 mock_callback_ops_->ProcessCaptureResult(PrepareCapturedResult(
131 request->frame_number, arc::mojom::CameraMetadata::New(), 1,
132 std::move(request->output_buffers)));
133 }
134
135 MockStreamCaptureInterface* GetMockCaptureInterface() {
136 EXPECT_NE(nullptr, stream_buffer_manager_.get());
137 return reinterpret_cast<MockStreamCaptureInterface*>(
138 stream_buffer_manager_->capture_interface_.get());
139 }
140
141 unittest_internal::MockVideoCaptureClient* GetMockVideoCaptureClient() {
142 EXPECT_NE(nullptr, device_context_);
143 return reinterpret_cast<unittest_internal::MockVideoCaptureClient*>(
144 device_context_->client_.get());
145 }
146
147 std::map<uint32_t, StreamBufferManager::CaptureResult>& GetPartialResults() {
148 EXPECT_NE(nullptr, stream_buffer_manager_.get());
149 return stream_buffer_manager_->partial_results_;
150 }
151
152 arc::mojom::Camera3StreamPtr PrepareCaptureStream(uint32_t max_buffers) {
153 auto stream = arc::mojom::Camera3Stream::New();
154 stream->id = 0;
155 stream->stream_type = arc::mojom::Camera3StreamType::CAMERA3_STREAM_OUTPUT;
156 stream->width = kDefaultCaptureFormat.frame_size.width();
157 stream->height = kDefaultCaptureFormat.frame_size.height();
158 stream->format = arc::mojom::HalPixelFormat::HAL_PIXEL_FORMAT_YCbCr_420_888;
159 stream->usage = 0;
160 stream->max_buffers = max_buffers;
161 stream->data_space = 0;
162 stream->rotation =
163 arc::mojom::Camera3StreamRotation::CAMERA3_STREAM_ROTATION_0;
164 return stream;
165 }
166
167 arc::mojom::Camera3NotifyMsgPtr PrepareErrorNotifyMessage(
168 uint32_t frame_number,
169 arc::mojom::Camera3ErrorMsgCode error_code) {
170 auto error_msg = arc::mojom::Camera3ErrorMsg::New();
171 error_msg->frame_number = frame_number;
172 // There is only the preview stream.
173 error_msg->error_stream_id = 1;
174 error_msg->error_code = error_code;
175 auto notify_msg = arc::mojom::Camera3NotifyMsg::New();
176 notify_msg->message = arc::mojom::Camera3NotifyMsgMessage::New();
177 notify_msg->type = arc::mojom::Camera3MsgType::CAMERA3_MSG_ERROR;
178 notify_msg->message->set_error(std::move(error_msg));
179 return notify_msg;
180 }
181
182 arc::mojom::Camera3NotifyMsgPtr PrepareShutterNotifyMessage(
183 uint32_t frame_number,
184 uint64_t timestamp) {
185 auto shutter_msg = arc::mojom::Camera3ShutterMsg::New();
186 shutter_msg->frame_number = frame_number;
187 shutter_msg->timestamp = timestamp;
188 auto notify_msg = arc::mojom::Camera3NotifyMsg::New();
189 notify_msg->message = arc::mojom::Camera3NotifyMsgMessage::New();
190 notify_msg->type = arc::mojom::Camera3MsgType::CAMERA3_MSG_SHUTTER;
191 notify_msg->message->set_shutter(std::move(shutter_msg));
192 return notify_msg;
193 }
194
195 arc::mojom::Camera3CaptureResultPtr PrepareCapturedResult(
196 uint32_t frame_number,
197 arc::mojom::CameraMetadataPtr result_metadata,
198 uint32_t partial_result,
199 std::vector<arc::mojom::Camera3StreamBufferPtr> output_buffers) {
200 auto result = arc::mojom::Camera3CaptureResult::New();
201 result->frame_number = frame_number;
202 result->result = std::move(result_metadata);
203 if (output_buffers.size()) {
204 result->output_buffers = std::move(output_buffers);
205 }
206 result->partial_result = partial_result;
207 return result;
208 }
209
210 protected:
211 scoped_refptr<StreamBufferManager> stream_buffer_manager_;
212 arc::mojom::Camera3CallbackOpsPtr mock_callback_ops_;
213 std::unique_ptr<CameraDeviceContext> device_context_;
214 arc::mojom::Camera3StreamPtr stream;
215
216 private:
217 std::unique_ptr<base::RunLoop> run_loop_;
218 bool quit_;
219 base::test::ScopedTaskEnvironment scoped_test_environment_;
220 };
221
222 // A basic sanity test to capture one frame with the capture loop.
223 TEST_F(StreamBufferManagerTest, SimpleCaptureTest) {
224 GetMockVideoCaptureClient()->SetFrameCb(base::BindOnce(
225 &StreamBufferManagerTest::QuitCaptureLoop, base::Unretained(this)));
226 EXPECT_CALL(*GetMockCaptureInterface(),
227 DoRegisterBuffer(0, arc::mojom::Camera3DeviceOps::BufferType::SHM,
228 _, _, _, _, _, _, _, _))
229 .Times(AtLeast(1))
230 .WillOnce(Invoke(this, &StreamBufferManagerTest::RegisterBuffer));
231 EXPECT_CALL(*GetMockCaptureInterface(), DoProcessCaptureRequest(_, _))
232 .Times(1)
233 .WillOnce(Invoke(this, &StreamBufferManagerTest::ProcessCaptureRequest));
234
235 stream_buffer_manager_->SetUpStreamAndBuffers(
236 kDefaultCaptureFormat, /* partial_result_count */ 1,
237 PrepareCaptureStream(/* max_buffers */ 1));
238 stream_buffer_manager_->StartCapture(arc::mojom::CameraMetadata::New());
239
240 // Wait until a captured frame is received by MockVideoCaptureClient.
241 DoLoop();
242 }
243
244 // Test that the StreamBufferManager submits a captured result only after all
245 // partial metadata are received.
246 TEST_F(StreamBufferManagerTest, PartialResultTest) {
247 GetMockVideoCaptureClient()->SetFrameCb(base::BindOnce(
248 [](StreamBufferManagerTest* test) {
249 EXPECT_EQ(1u, test->GetPartialResults().size());
250 // Make sure all the three partial metadata are received before the
251 // captured result is submitted.
252 EXPECT_EQ(
253 3u, test->GetPartialResults()[0].partial_metadata_received.size());
254 test->QuitCaptureLoop();
255 },
256 base::Unretained(this)));
257 EXPECT_CALL(*GetMockCaptureInterface(),
258 DoRegisterBuffer(0, arc::mojom::Camera3DeviceOps::BufferType::SHM,
259 _, _, _, _, _, _, _, _))
260 .Times(AtLeast(1))
261 .WillOnce(Invoke(this, &StreamBufferManagerTest::RegisterBuffer));
262 EXPECT_CALL(*GetMockCaptureInterface(), DoProcessCaptureRequest(_, _))
263 .Times(1)
264 .WillOnce(Invoke([this](arc::mojom::Camera3CaptureRequestPtr& request,
265 base::OnceCallback<void(int32_t)>& callback) {
266 std::move(callback).Run(0);
267 mock_callback_ops_->Notify(PrepareShutterNotifyMessage(
268 request->frame_number, base::TimeTicks::Now().ToInternalValue()));
269 mock_callback_ops_->ProcessCaptureResult(PrepareCapturedResult(
270 request->frame_number, arc::mojom::CameraMetadata::New(), 1,
271 std::move(request->output_buffers)));
272
273 mock_callback_ops_->ProcessCaptureResult(PrepareCapturedResult(
274 request->frame_number, arc::mojom::CameraMetadata::New(), 2,
275 std::vector<arc::mojom::Camera3StreamBufferPtr>()));
276
277 mock_callback_ops_->ProcessCaptureResult(PrepareCapturedResult(
278 request->frame_number, arc::mojom::CameraMetadata::New(), 3,
279 std::vector<arc::mojom::Camera3StreamBufferPtr>()));
280 }));
281
282 stream_buffer_manager_->SetUpStreamAndBuffers(
283 kDefaultCaptureFormat, /* partial_result_count */ 3,
284 PrepareCaptureStream(/* max_buffers */ 1));
285 stream_buffer_manager_->StartCapture(arc::mojom::CameraMetadata::New());
286
287 // Wait until a captured frame is received by MockVideoCaptureClient.
288 DoLoop();
289 }
290
291 // Test that the capture loop is stopped and no frame is submitted when a device
292 // error happens.
293 TEST_F(StreamBufferManagerTest, DeviceErrorTest) {
294 GetMockVideoCaptureClient()->SetFrameCb(base::BindOnce(
295 [](StreamBufferManagerTest* test) {
296 ADD_FAILURE() << "No frame should be submitted";
297 test->QuitCaptureLoop();
298 },
299 base::Unretained(this)));
300 EXPECT_CALL(*GetMockVideoCaptureClient(), OnError(_, _))
301 .Times(1)
302 .WillOnce(
303 InvokeWithoutArgs(this, &StreamBufferManagerTest::QuitCaptureLoop));
304 EXPECT_CALL(*GetMockCaptureInterface(),
305 DoRegisterBuffer(0, arc::mojom::Camera3DeviceOps::BufferType::SHM,
306 _, _, _, _, _, _, _, _))
307 .Times(1)
308 .WillOnce(Invoke(this, &StreamBufferManagerTest::RegisterBuffer));
309 EXPECT_CALL(*GetMockCaptureInterface(), DoProcessCaptureRequest(_, _))
310 .Times(1)
311 .WillOnce(Invoke([this](arc::mojom::Camera3CaptureRequestPtr& request,
312 base::OnceCallback<void(int32_t)>& callback) {
313 std::move(callback).Run(0);
314 mock_callback_ops_->Notify(PrepareErrorNotifyMessage(
315 request->frame_number,
316 arc::mojom::Camera3ErrorMsgCode::CAMERA3_MSG_ERROR_DEVICE));
chfremer 2017/06/08 21:58:38 Out of curiosity, does the order of running |callb
jcliang 2017/06/09 05:16:01 It shouldn't matter in this case. I believe device
317 }));
318
319 stream_buffer_manager_->SetUpStreamAndBuffers(
320 kDefaultCaptureFormat, /* partial_result_count */ 1,
321 PrepareCaptureStream(/* max_buffers */ 1));
322 stream_buffer_manager_->StartCapture(arc::mojom::CameraMetadata::New());
323
324 // Wait until the MockVideoCaptureClient is deleted.
325 DoLoop();
326 }
327
328 // Test that upon request error the erroneous frame is dropped, and the capture
329 // loop continues.
330 TEST_F(StreamBufferManagerTest, RequestErrorTest) {
331 GetMockVideoCaptureClient()->SetFrameCb(base::BindOnce(
332 [](StreamBufferManagerTest* test) {
333 // Frame 0 should be dropped, and the frame callback should be called
334 // with frame 1.
335 EXPECT_EQ(test->GetPartialResults().end(),
336 test->GetPartialResults().find(0));
337 EXPECT_NE(test->GetPartialResults().end(),
338 test->GetPartialResults().find(1));
339 test->QuitCaptureLoop();
340 },
341 base::Unretained(this)));
342 EXPECT_CALL(*GetMockCaptureInterface(),
343 DoRegisterBuffer(0, arc::mojom::Camera3DeviceOps::BufferType::SHM,
344 _, _, _, _, _, _, _, _))
345 .Times(AtLeast(2))
346 .WillOnce(Invoke(this, &StreamBufferManagerTest::RegisterBuffer))
347 .WillOnce(Invoke(this, &StreamBufferManagerTest::RegisterBuffer));
348 EXPECT_CALL(*GetMockCaptureInterface(), DoProcessCaptureRequest(_, _))
349 .Times(2)
350 .WillOnce(Invoke([this](arc::mojom::Camera3CaptureRequestPtr& request,
351 base::OnceCallback<void(int32_t)>& callback) {
352 std::move(callback).Run(0);
353 mock_callback_ops_->Notify(PrepareErrorNotifyMessage(
354 request->frame_number,
355 arc::mojom::Camera3ErrorMsgCode::CAMERA3_MSG_ERROR_REQUEST));
356 request->output_buffers[0]->status =
357 arc::mojom::Camera3BufferStatus::CAMERA3_BUFFER_STATUS_ERROR;
358 mock_callback_ops_->ProcessCaptureResult(PrepareCapturedResult(
359 request->frame_number, arc::mojom::CameraMetadata::New(), 1,
360 std::move(request->output_buffers)));
361 }))
362 .WillOnce(Invoke(this, &StreamBufferManagerTest::ProcessCaptureRequest));
363
364 stream_buffer_manager_->SetUpStreamAndBuffers(
365 kDefaultCaptureFormat, /* partial_result_count */ 1,
366 PrepareCaptureStream(/* max_buffers */ 1));
367 stream_buffer_manager_->StartCapture(arc::mojom::CameraMetadata::New());
368
369 // Wait until the MockVideoCaptureClient is deleted.
370 DoLoop();
371 }
372
373 // Test that upon result error the captured buffer is submitted despite of the
374 // missing result metadata, and the capture loop continues.
375 TEST_F(StreamBufferManagerTest, ResultErrorTest) {
376 GetMockVideoCaptureClient()->SetFrameCb(base::BindOnce(
377 [](StreamBufferManagerTest* test) {
378 // Frame 0 should be submitted.
379 EXPECT_NE(test->GetPartialResults().end(),
380 test->GetPartialResults().find(0));
381 test->QuitCaptureLoop();
382 },
383 base::Unretained(this)));
384 EXPECT_CALL(*GetMockCaptureInterface(),
385 DoRegisterBuffer(0, arc::mojom::Camera3DeviceOps::BufferType::SHM,
386 _, _, _, _, _, _, _, _))
387 .Times(AtLeast(1))
388 .WillOnce(Invoke(this, &StreamBufferManagerTest::RegisterBuffer));
389 EXPECT_CALL(*GetMockCaptureInterface(), DoProcessCaptureRequest(_, _))
390 .Times(1)
391 .WillOnce(Invoke([this](arc::mojom::Camera3CaptureRequestPtr& request,
392 base::OnceCallback<void(int32_t)>& callback) {
393 std::move(callback).Run(0);
394 mock_callback_ops_->Notify(PrepareShutterNotifyMessage(
395 request->frame_number, base::TimeTicks::Now().ToInternalValue()));
396 mock_callback_ops_->ProcessCaptureResult(PrepareCapturedResult(
397 request->frame_number, arc::mojom::CameraMetadata::New(), 1,
398 std::move(request->output_buffers)));
399 // Send a result error notify without sending the second partial result.
400 // StreamBufferManager should submit the buffer when it receives the
401 // result error.
402 mock_callback_ops_->Notify(PrepareErrorNotifyMessage(
403 request->frame_number,
404 arc::mojom::Camera3ErrorMsgCode::CAMERA3_MSG_ERROR_RESULT));
405 }))
406 .WillOnce(Invoke(this, &StreamBufferManagerTest::ProcessCaptureRequest));
407
408 stream_buffer_manager_->SetUpStreamAndBuffers(
409 kDefaultCaptureFormat, /* partial_result_count */ 2,
410 PrepareCaptureStream(/* max_buffers */ 1));
411 stream_buffer_manager_->StartCapture(arc::mojom::CameraMetadata::New());
412
413 // Wait until the MockVideoCaptureClient is deleted.
414 DoLoop();
415 }
416
417 // Test that upon buffer error the erroneous buffer is dropped, and the capture
418 // loop continues.
419 TEST_F(StreamBufferManagerTest, BufferErrorTest) {
420 GetMockVideoCaptureClient()->SetFrameCb(base::BindOnce(
421 [](StreamBufferManagerTest* test) {
422 // Frame 0 should be dropped, and the frame callback should be called
423 // with frame 1.
424 EXPECT_EQ(test->GetPartialResults().end(),
425 test->GetPartialResults().find(0));
426 EXPECT_NE(test->GetPartialResults().end(),
427 test->GetPartialResults().find(1));
428 test->QuitCaptureLoop();
429 },
430 base::Unretained(this)));
431 EXPECT_CALL(*GetMockCaptureInterface(),
432 DoRegisterBuffer(0, arc::mojom::Camera3DeviceOps::BufferType::SHM,
433 _, _, _, _, _, _, _, _))
434 .Times(AtLeast(2))
435 .WillOnce(Invoke(this, &StreamBufferManagerTest::RegisterBuffer))
436 .WillOnce(Invoke(this, &StreamBufferManagerTest::RegisterBuffer));
437 EXPECT_CALL(*GetMockCaptureInterface(), DoProcessCaptureRequest(_, _))
438 .Times(2)
439 .WillOnce(Invoke([this](arc::mojom::Camera3CaptureRequestPtr& request,
440 base::OnceCallback<void(int32_t)>& callback) {
441 std::move(callback).Run(0);
442 mock_callback_ops_->Notify(PrepareShutterNotifyMessage(
443 request->frame_number, base::TimeTicks::Now().ToInternalValue()));
444 mock_callback_ops_->Notify(PrepareErrorNotifyMessage(
445 request->frame_number,
446 arc::mojom::Camera3ErrorMsgCode::CAMERA3_MSG_ERROR_BUFFER));
447 request->output_buffers[0]->status =
448 arc::mojom::Camera3BufferStatus::CAMERA3_BUFFER_STATUS_ERROR;
449 mock_callback_ops_->ProcessCaptureResult(PrepareCapturedResult(
450 request->frame_number, arc::mojom::CameraMetadata::New(), 1,
451 std::move(request->output_buffers)));
452 }))
453 .WillOnce(Invoke(this, &StreamBufferManagerTest::ProcessCaptureRequest));
454
455 stream_buffer_manager_->SetUpStreamAndBuffers(
456 kDefaultCaptureFormat, /* partial_result_count */ 1,
457 PrepareCaptureStream(/* max_buffers */ 1));
458 stream_buffer_manager_->StartCapture(arc::mojom::CameraMetadata::New());
459
460 // Wait until the MockVideoCaptureClient is deleted.
461 DoLoop();
462 }
463
464 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698