| // Copyright 2017 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "media/capture/video/chromeos/request_manager.h" |
| |
| #include <map> |
| #include <memory> |
| #include <utility> |
| #include <vector> |
| |
| #include "base/functional/bind.h" |
| #include "base/run_loop.h" |
| #include "base/task/single_thread_task_runner.h" |
| #include "base/test/task_environment.h" |
| #include "base/threading/thread.h" |
| #include "media/capture/video/blob_utils.h" |
| #include "media/capture/video/chromeos/camera_buffer_factory.h" |
| #include "media/capture/video/chromeos/camera_device_context.h" |
| #include "media/capture/video/chromeos/camera_device_delegate.h" |
| #include "media/capture/video/chromeos/mock_video_capture_client.h" |
| #include "media/capture/video/chromeos/stream_buffer_manager.h" |
| #include "media/capture/video/mock_gpu_memory_buffer_manager.h" |
| #include "mojo/public/cpp/bindings/remote.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| using testing::_; |
| using testing::A; |
| using testing::AtLeast; |
| using testing::Invoke; |
| using testing::InvokeWithoutArgs; |
| using testing::Return; |
| |
| namespace media { |
| |
| namespace { |
| |
| class MockStreamCaptureInterface : public StreamCaptureInterface { |
| public: |
| void ProcessCaptureRequest( |
| cros::mojom::Camera3CaptureRequestPtr request, |
| base::OnceCallback<void(int32_t)> callback) override { |
| DoProcessCaptureRequest(request, callback); |
| } |
| MOCK_METHOD2(DoProcessCaptureRequest, |
| void(cros::mojom::Camera3CaptureRequestPtr& request, |
| base::OnceCallback<void(int32_t)>& callback)); |
| |
| void Flush(base::OnceCallback<void(int32_t)> callback) override { |
| DoFlush(callback); |
| } |
| MOCK_METHOD1(DoFlush, void(base::OnceCallback<void(int32_t)>& callback)); |
| }; |
| |
| const VideoCaptureFormat kDefaultCaptureFormat(gfx::Size(1280, 720), |
| 30.0, |
| PIXEL_FORMAT_NV12); |
| |
| class FakeCameraBufferFactory : public CameraBufferFactory { |
| public: |
| FakeCameraBufferFactory() { |
| gpu_memory_buffer_manager_ = |
| std::make_unique<unittest_internal::MockGpuMemoryBufferManager>(); |
| } |
| std::unique_ptr<gfx::GpuMemoryBuffer> CreateGpuMemoryBuffer( |
| const gfx::Size& size, |
| gfx::BufferFormat format, |
| gfx::BufferUsage usage) override { |
| return unittest_internal::MockGpuMemoryBufferManager:: |
| CreateFakeGpuMemoryBuffer(size, format, usage, gpu::kNullSurfaceHandle, |
| nullptr); |
| } |
| |
| ChromiumPixelFormat ResolveStreamBufferFormat( |
| cros::mojom::HalPixelFormat hal_format, |
| gfx::BufferUsage usage) override { |
| return ChromiumPixelFormat{PIXEL_FORMAT_NV12, |
| gfx::BufferFormat::YUV_420_BIPLANAR}; |
| } |
| |
| private: |
| std::unique_ptr<unittest_internal::MockGpuMemoryBufferManager> |
| gpu_memory_buffer_manager_; |
| }; |
| |
| } // namespace |
| |
| class RequestManagerTest : public ::testing::Test { |
| public: |
| void SetUp() override { |
| quit_ = false; |
| client_type_ = ClientType::kPreviewClient; |
| VideoCaptureParams params; |
| params.requested_format = kDefaultCaptureFormat; |
| capture_params_[client_type_] = params; |
| device_context_ = std::make_unique<CameraDeviceContext>(); |
| if (device_context_->AddClient( |
| client_type_, |
| std::make_unique<unittest_internal::MockVideoCaptureClient>())) { |
| std::string fake_device_id = "0"; |
| request_manager_ = std::make_unique<RequestManager>( |
| fake_device_id, mock_callback_ops_.BindNewPipeAndPassReceiver(), |
| std::make_unique<MockStreamCaptureInterface>(), device_context_.get(), |
| VideoCaptureBufferType::kSharedMemory, |
| std::make_unique<FakeCameraBufferFactory>(), |
| base::BindRepeating( |
| [](const uint8_t* buffer, const uint32_t bytesused, |
| const VideoCaptureFormat& capture_format, |
| const int rotation) { return mojom::Blob::New(); }), |
| base::SingleThreadTaskRunner::GetCurrentDefault(), |
| cros::mojom::CAMERA_DEVICE_API_VERSION_3_5); |
| } |
| } |
| |
| void TearDown() override { |
| device_context_->RemoveClient(client_type_); |
| request_manager_.reset(); |
| } |
| |
| void DoLoop() { |
| run_loop_ = std::make_unique<base::RunLoop>(); |
| run_loop_->Run(); |
| } |
| |
| void QuitCaptureLoop() { |
| quit_ = true; |
| if (run_loop_) { |
| run_loop_->Quit(); |
| } |
| } |
| |
| cros::mojom::CameraMetadataPtr GetFakeStaticMetadata( |
| int32_t partial_result_count) { |
| cros::mojom::CameraMetadataPtr static_metadata = |
| cros::mojom::CameraMetadata::New(); |
| static_metadata->entry_count = 2; |
| static_metadata->entry_capacity = 2; |
| static_metadata->entries = |
| std::vector<cros::mojom::CameraMetadataEntryPtr>(); |
| |
| cros::mojom::CameraMetadataEntryPtr entry = |
| cros::mojom::CameraMetadataEntry::New(); |
| entry->index = 0; |
| entry->tag = |
| cros::mojom::CameraMetadataTag::ANDROID_REQUEST_PARTIAL_RESULT_COUNT; |
| entry->type = cros::mojom::EntryType::TYPE_INT32; |
| entry->count = 1; |
| uint8_t* as_int8 = reinterpret_cast<uint8_t*>(&partial_result_count); |
| entry->data.assign(as_int8, as_int8 + entry->count * sizeof(int32_t)); |
| static_metadata->entries->push_back(std::move(entry)); |
| |
| entry = cros::mojom::CameraMetadataEntry::New(); |
| entry->index = 1; |
| entry->tag = cros::mojom::CameraMetadataTag::ANDROID_JPEG_MAX_SIZE; |
| entry->type = cros::mojom::EntryType::TYPE_INT32; |
| entry->count = 1; |
| int32_t jpeg_max_size = 65535; |
| as_int8 = reinterpret_cast<uint8_t*>(&jpeg_max_size); |
| entry->data.assign(as_int8, as_int8 + entry->count * sizeof(int32_t)); |
| static_metadata->entries->push_back(std::move(entry)); |
| |
| entry = cros::mojom::CameraMetadataEntry::New(); |
| entry->index = 2; |
| entry->tag = |
| cros::mojom::CameraMetadataTag::ANDROID_REQUEST_PIPELINE_MAX_DEPTH; |
| entry->type = cros::mojom::EntryType::TYPE_BYTE; |
| entry->count = 1; |
| uint8_t pipeline_max_depth = 1; |
| entry->data.assign(&pipeline_max_depth, |
| &pipeline_max_depth + entry->count * sizeof(uint8_t)); |
| static_metadata->entries->push_back(std::move(entry)); |
| |
| return static_metadata; |
| } |
| |
| void ProcessCaptureRequest(cros::mojom::Camera3CaptureRequestPtr& request, |
| base::OnceCallback<void(int32_t)>& callback) { |
| if (quit_) { |
| return; |
| } |
| std::move(callback).Run(0); |
| mock_callback_ops_->Notify(PrepareShutterNotifyMessage( |
| request->frame_number, |
| (base::TimeTicks::Now() - base::TimeTicks()).InMicroseconds())); |
| mock_callback_ops_->ProcessCaptureResult(PrepareCapturedResult( |
| request->frame_number, cros::mojom::CameraMetadata::New(), 1, |
| std::move(request->output_buffers))); |
| } |
| |
| MockStreamCaptureInterface* GetMockCaptureInterface() { |
| EXPECT_NE(nullptr, request_manager_.get()); |
| return reinterpret_cast<MockStreamCaptureInterface*>( |
| request_manager_->capture_interface_.get()); |
| } |
| |
| unittest_internal::MockVideoCaptureClient* GetMockVideoCaptureClient() { |
| EXPECT_NE(nullptr, device_context_); |
| base::AutoLock lock(device_context_->client_lock_); |
| EXPECT_TRUE(!device_context_->clients_.empty()); |
| return reinterpret_cast<unittest_internal::MockVideoCaptureClient*>( |
| device_context_->clients_[client_type_].get()); |
| } |
| |
| std::map<uint32_t, RequestManager::CaptureResult>& GetPendingResults() { |
| EXPECT_NE(nullptr, request_manager_.get()); |
| return request_manager_->pending_results_; |
| } |
| |
| std::vector<cros::mojom::Camera3StreamPtr> PrepareCaptureStream( |
| uint32_t max_buffers) { |
| std::vector<cros::mojom::Camera3StreamPtr> streams; |
| |
| auto preview_stream = cros::mojom::Camera3Stream::New(); |
| preview_stream->id = static_cast<uint64_t>(StreamType::kPreviewOutput); |
| preview_stream->stream_type = |
| cros::mojom::Camera3StreamType::CAMERA3_STREAM_OUTPUT; |
| preview_stream->width = kDefaultCaptureFormat.frame_size.width(); |
| preview_stream->height = kDefaultCaptureFormat.frame_size.height(); |
| preview_stream->format = |
| cros::mojom::HalPixelFormat::HAL_PIXEL_FORMAT_YCbCr_420_888; |
| preview_stream->usage = 0; |
| preview_stream->max_buffers = max_buffers; |
| preview_stream->data_space = 0; |
| preview_stream->rotation = |
| cros::mojom::Camera3StreamRotation::CAMERA3_STREAM_ROTATION_0; |
| streams.push_back(std::move(preview_stream)); |
| |
| auto still_capture_stream = cros::mojom::Camera3Stream::New(); |
| still_capture_stream->id = static_cast<uint64_t>(StreamType::kJpegOutput); |
| still_capture_stream->stream_type = |
| cros::mojom::Camera3StreamType::CAMERA3_STREAM_OUTPUT; |
| still_capture_stream->width = kDefaultCaptureFormat.frame_size.width(); |
| still_capture_stream->height = kDefaultCaptureFormat.frame_size.height(); |
| still_capture_stream->format = |
| cros::mojom::HalPixelFormat::HAL_PIXEL_FORMAT_BLOB; |
| still_capture_stream->usage = 0; |
| still_capture_stream->max_buffers = max_buffers; |
| still_capture_stream->data_space = 0; |
| still_capture_stream->rotation = |
| cros::mojom::Camera3StreamRotation::CAMERA3_STREAM_ROTATION_0; |
| streams.push_back(std::move(still_capture_stream)); |
| |
| return streams; |
| } |
| |
| cros::mojom::Camera3NotifyMsgPtr PrepareErrorNotifyMessage( |
| uint32_t frame_number, |
| cros::mojom::Camera3ErrorMsgCode error_code) { |
| auto error_msg = cros::mojom::Camera3ErrorMsg::New(); |
| error_msg->frame_number = frame_number; |
| // There is only the preview stream. |
| error_msg->error_stream_id = |
| static_cast<uint64_t>(StreamType::kPreviewOutput); |
| error_msg->error_code = error_code; |
| auto notify_msg = cros::mojom::Camera3NotifyMsg::New(); |
| notify_msg->type = cros::mojom::Camera3MsgType::CAMERA3_MSG_ERROR; |
| notify_msg->message = |
| cros::mojom::Camera3NotifyMsgMessage::NewError(std::move(error_msg)); |
| return notify_msg; |
| } |
| |
| cros::mojom::Camera3NotifyMsgPtr PrepareShutterNotifyMessage( |
| uint32_t frame_number, |
| uint64_t timestamp) { |
| auto shutter_msg = cros::mojom::Camera3ShutterMsg::New(); |
| shutter_msg->frame_number = frame_number; |
| shutter_msg->timestamp = timestamp; |
| auto notify_msg = cros::mojom::Camera3NotifyMsg::New(); |
| notify_msg->type = cros::mojom::Camera3MsgType::CAMERA3_MSG_SHUTTER; |
| notify_msg->message = cros::mojom::Camera3NotifyMsgMessage::NewShutter( |
| std::move(shutter_msg)); |
| return notify_msg; |
| } |
| |
| cros::mojom::Camera3CaptureResultPtr PrepareCapturedResult( |
| uint32_t frame_number, |
| cros::mojom::CameraMetadataPtr result_metadata, |
| uint32_t partial_result, |
| std::vector<cros::mojom::Camera3StreamBufferPtr> output_buffers) { |
| auto result = cros::mojom::Camera3CaptureResult::New(); |
| result->frame_number = frame_number; |
| result->result = std::move(result_metadata); |
| if (output_buffers.size()) { |
| result->output_buffers = std::move(output_buffers); |
| } |
| result->partial_result = partial_result; |
| return result; |
| } |
| |
| protected: |
| std::unique_ptr<RequestManager> request_manager_; |
| mojo::Remote<cros::mojom::Camera3CallbackOps> mock_callback_ops_; |
| std::unique_ptr<CameraDeviceContext> device_context_; |
| ClientType client_type_; |
| base::flat_map<ClientType, VideoCaptureParams> capture_params_; |
| |
| private: |
| std::unique_ptr<base::RunLoop> run_loop_; |
| bool quit_; |
| base::test::TaskEnvironment scoped_test_environment_; |
| }; |
| |
| // A basic sanity test to capture one frame with the capture loop. |
| TEST_F(RequestManagerTest, SimpleCaptureTest) { |
| GetMockVideoCaptureClient()->SetFrameCb(base::BindOnce( |
| &RequestManagerTest::QuitCaptureLoop, base::Unretained(this))); |
| EXPECT_CALL(*GetMockCaptureInterface(), DoProcessCaptureRequest(_, _)) |
| .Times(AtLeast(1)) |
| .WillRepeatedly(Invoke(this, &RequestManagerTest::ProcessCaptureRequest)); |
| |
| request_manager_->SetUpStreamsAndBuffers( |
| capture_params_, GetFakeStaticMetadata(/* partial_result_count */ 1), |
| PrepareCaptureStream(/* max_buffers */ 1)); |
| request_manager_->StartPreview(cros::mojom::CameraMetadata::New()); |
| |
| // Wait until a captured frame is received by MockVideoCaptureClient. |
| DoLoop(); |
| } |
| |
| // Test that the RequestManager submits a captured result only after all |
| // partial metadata are received. |
| TEST_F(RequestManagerTest, PartialResultTest) { |
| GetMockVideoCaptureClient()->SetFrameCb(base::BindOnce( |
| [](RequestManagerTest* test) { |
| EXPECT_EQ(1u, test->GetPendingResults().size()); |
| // Make sure all the three partial metadata are received before the |
| // captured result is submitted. |
| EXPECT_EQ( |
| 3u, test->GetPendingResults()[0].partial_metadata_received.size()); |
| test->QuitCaptureLoop(); |
| }, |
| base::Unretained(this))); |
| EXPECT_CALL(*GetMockCaptureInterface(), DoProcessCaptureRequest(_, _)) |
| .Times(AtLeast(1)) |
| .WillRepeatedly( |
| Invoke([this](cros::mojom::Camera3CaptureRequestPtr& request, |
| base::OnceCallback<void(int32_t)>& callback) { |
| std::move(callback).Run(0); |
| mock_callback_ops_->Notify(PrepareShutterNotifyMessage( |
| request->frame_number, |
| (base::TimeTicks::Now() - base::TimeTicks()).InMicroseconds())); |
| mock_callback_ops_->ProcessCaptureResult(PrepareCapturedResult( |
| request->frame_number, cros::mojom::CameraMetadata::New(), 1, |
| std::move(request->output_buffers))); |
| mock_callback_ops_->ProcessCaptureResult(PrepareCapturedResult( |
| request->frame_number, cros::mojom::CameraMetadata::New(), 2, |
| std::vector<cros::mojom::Camera3StreamBufferPtr>())); |
| mock_callback_ops_->ProcessCaptureResult(PrepareCapturedResult( |
| request->frame_number, cros::mojom::CameraMetadata::New(), 3, |
| std::vector<cros::mojom::Camera3StreamBufferPtr>())); |
| })); |
| |
| request_manager_->SetUpStreamsAndBuffers( |
| capture_params_, GetFakeStaticMetadata(/* partial_result_count */ 3), |
| PrepareCaptureStream(/* max_buffers */ 1)); |
| request_manager_->StartPreview(cros::mojom::CameraMetadata::New()); |
| |
| // Wait until a captured frame is received by MockVideoCaptureClient. |
| DoLoop(); |
| } |
| |
| // Test that the capture loop is stopped and no frame is submitted when a device |
| // error happens. |
| TEST_F(RequestManagerTest, DeviceErrorTest) { |
| GetMockVideoCaptureClient()->SetFrameCb(base::BindOnce( |
| [](RequestManagerTest* test) { |
| ADD_FAILURE() << "No frame should be submitted"; |
| test->QuitCaptureLoop(); |
| }, |
| base::Unretained(this))); |
| EXPECT_CALL(*GetMockVideoCaptureClient(), OnError(_, _, _)) |
| .Times(1) |
| .WillOnce(InvokeWithoutArgs(this, &RequestManagerTest::QuitCaptureLoop)); |
| EXPECT_CALL(*GetMockCaptureInterface(), DoProcessCaptureRequest(_, _)) |
| .Times(1) |
| .WillOnce(Invoke([this](cros::mojom::Camera3CaptureRequestPtr& request, |
| base::OnceCallback<void(int32_t)>& callback) { |
| std::move(callback).Run(0); |
| mock_callback_ops_->Notify(PrepareErrorNotifyMessage( |
| request->frame_number, |
| cros::mojom::Camera3ErrorMsgCode::CAMERA3_MSG_ERROR_DEVICE)); |
| })); |
| |
| request_manager_->SetUpStreamsAndBuffers( |
| capture_params_, GetFakeStaticMetadata(/* partial_result_count */ 1), |
| PrepareCaptureStream(/* max_buffers */ 1)); |
| request_manager_->StartPreview(cros::mojom::CameraMetadata::New()); |
| |
| // Wait until the MockVideoCaptureClient is deleted. |
| DoLoop(); |
| } |
| |
| // Test that upon request error the erroneous frame is dropped, and the capture |
| // loop continues. |
| TEST_F(RequestManagerTest, RequestErrorTest) { |
| GetMockVideoCaptureClient()->SetFrameCb(base::BindOnce( |
| [](RequestManagerTest* test) { |
| // Frame 0 should be dropped, and the frame callback should be called |
| // with frame 1. |
| EXPECT_EQ(test->GetPendingResults().end(), |
| test->GetPendingResults().find(0)); |
| EXPECT_NE(test->GetPendingResults().end(), |
| test->GetPendingResults().find(1)); |
| test->QuitCaptureLoop(); |
| }, |
| base::Unretained(this))); |
| EXPECT_CALL(*GetMockCaptureInterface(), DoProcessCaptureRequest(_, _)) |
| .Times(AtLeast(2)) |
| .WillOnce(Invoke([this](cros::mojom::Camera3CaptureRequestPtr& request, |
| base::OnceCallback<void(int32_t)>& callback) { |
| std::move(callback).Run(0); |
| mock_callback_ops_->Notify(PrepareErrorNotifyMessage( |
| request->frame_number, |
| cros::mojom::Camera3ErrorMsgCode::CAMERA3_MSG_ERROR_REQUEST)); |
| request->output_buffers[0]->status = |
| cros::mojom::Camera3BufferStatus::CAMERA3_BUFFER_STATUS_ERROR; |
| mock_callback_ops_->ProcessCaptureResult(PrepareCapturedResult( |
| request->frame_number, cros::mojom::CameraMetadata::New(), 1, |
| std::move(request->output_buffers))); |
| })) |
| .WillRepeatedly(Invoke(this, &RequestManagerTest::ProcessCaptureRequest)); |
| |
| request_manager_->SetUpStreamsAndBuffers( |
| capture_params_, GetFakeStaticMetadata(/* partial_result_count */ 1), |
| PrepareCaptureStream(/* max_buffers */ 1)); |
| request_manager_->StartPreview(cros::mojom::CameraMetadata::New()); |
| |
| // Wait until the MockVideoCaptureClient is deleted. |
| DoLoop(); |
| } |
| |
| // Test that upon result error the captured buffer is submitted despite of the |
| // missing result metadata, and the capture loop continues. |
| TEST_F(RequestManagerTest, ResultErrorTest) { |
| GetMockVideoCaptureClient()->SetFrameCb(base::BindOnce( |
| [](RequestManagerTest* test) { |
| // Frame 0 should be submitted. |
| EXPECT_NE(test->GetPendingResults().end(), |
| test->GetPendingResults().find(0)); |
| test->QuitCaptureLoop(); |
| }, |
| base::Unretained(this))); |
| EXPECT_CALL(*GetMockCaptureInterface(), DoProcessCaptureRequest(_, _)) |
| .Times(AtLeast(1)) |
| .WillOnce(Invoke([this](cros::mojom::Camera3CaptureRequestPtr& request, |
| base::OnceCallback<void(int32_t)>& callback) { |
| std::move(callback).Run(0); |
| mock_callback_ops_->Notify(PrepareShutterNotifyMessage( |
| request->frame_number, |
| (base::TimeTicks::Now() - base::TimeTicks()).InMicroseconds())); |
| mock_callback_ops_->ProcessCaptureResult(PrepareCapturedResult( |
| request->frame_number, cros::mojom::CameraMetadata::New(), 1, |
| std::move(request->output_buffers))); |
| // Send a result error notify without sending the second partial result. |
| // RequestManager should submit the buffer when it receives the |
| // result error. |
| mock_callback_ops_->Notify(PrepareErrorNotifyMessage( |
| request->frame_number, |
| cros::mojom::Camera3ErrorMsgCode::CAMERA3_MSG_ERROR_RESULT)); |
| })) |
| .WillRepeatedly(Invoke(this, &RequestManagerTest::ProcessCaptureRequest)); |
| |
| request_manager_->SetUpStreamsAndBuffers( |
| capture_params_, GetFakeStaticMetadata(/* partial_result_count */ 2), |
| PrepareCaptureStream(/* max_buffers */ 1)); |
| request_manager_->StartPreview(cros::mojom::CameraMetadata::New()); |
| |
| // Wait until the MockVideoCaptureClient is deleted. |
| DoLoop(); |
| } |
| |
| // Test that upon buffer error the erroneous buffer is dropped, and the capture |
| // loop continues. |
| TEST_F(RequestManagerTest, BufferErrorTest) { |
| GetMockVideoCaptureClient()->SetFrameCb(base::BindOnce( |
| [](RequestManagerTest* test) { |
| // Frame 0 should be dropped, and the frame callback should be called |
| // with frame 1. |
| EXPECT_EQ(test->GetPendingResults().end(), |
| test->GetPendingResults().find(0)); |
| EXPECT_NE(test->GetPendingResults().end(), |
| test->GetPendingResults().find(1)); |
| test->QuitCaptureLoop(); |
| }, |
| base::Unretained(this))); |
| EXPECT_CALL(*GetMockCaptureInterface(), DoProcessCaptureRequest(_, _)) |
| .Times(AtLeast(2)) |
| .WillOnce(Invoke([this](cros::mojom::Camera3CaptureRequestPtr& request, |
| base::OnceCallback<void(int32_t)>& callback) { |
| std::move(callback).Run(0); |
| mock_callback_ops_->Notify(PrepareShutterNotifyMessage( |
| request->frame_number, |
| (base::TimeTicks::Now() - base::TimeTicks()).InMicroseconds())); |
| mock_callback_ops_->Notify(PrepareErrorNotifyMessage( |
| request->frame_number, |
| cros::mojom::Camera3ErrorMsgCode::CAMERA3_MSG_ERROR_BUFFER)); |
| request->output_buffers[0]->status = |
| cros::mojom::Camera3BufferStatus::CAMERA3_BUFFER_STATUS_ERROR; |
| mock_callback_ops_->ProcessCaptureResult(PrepareCapturedResult( |
| request->frame_number, cros::mojom::CameraMetadata::New(), 1, |
| std::move(request->output_buffers))); |
| })) |
| .WillRepeatedly(Invoke(this, &RequestManagerTest::ProcessCaptureRequest)); |
| |
| request_manager_->SetUpStreamsAndBuffers( |
| capture_params_, GetFakeStaticMetadata(/* partial_result_count */ 1), |
| PrepareCaptureStream(/* max_buffers */ 1)); |
| request_manager_->StartPreview(cros::mojom::CameraMetadata::New()); |
| |
| // Wait until the MockVideoCaptureClient is deleted. |
| DoLoop(); |
| } |
| |
| // Test that preview and still capture buffers can be correctly submitted. |
| // TODO(crbug.com/917574): Add reprocess tests and take photo test. |
| |
| } // namespace media |