diff --git a/media/capture/BUILD.gn b/media/capture/BUILD.gn index b7161147e51754..c5c9c5df69c0c2 100644 --- a/media/capture/BUILD.gn +++ b/media/capture/BUILD.gn @@ -271,6 +271,8 @@ jumbo_component("capture_lib") { "video/chromeos/scoped_video_capture_jpeg_decoder.h", "video/chromeos/stream_buffer_manager.cc", "video/chromeos/stream_buffer_manager.h", + "video/chromeos/vendor_tag_ops_delegate.cc", + "video/chromeos/vendor_tag_ops_delegate.h", "video/chromeos/video_capture_device_chromeos_halv3.cc", "video/chromeos/video_capture_device_chromeos_halv3.h", "video/chromeos/video_capture_device_factory_chromeos.cc", @@ -403,6 +405,8 @@ test("capture_unittests") { "video/chromeos/local_gpu_memory_buffer_manager.cc", "video/chromeos/mock_camera_module.cc", "video/chromeos/mock_camera_module.h", + "video/chromeos/mock_vendor_tag_ops.cc", + "video/chromeos/mock_vendor_tag_ops.h", "video/chromeos/mock_video_capture_client.cc", "video/chromeos/mock_video_capture_client.h", "video/chromeos/request_manager_unittest.cc", diff --git a/media/capture/video/chromeos/camera_device_delegate_unittest.cc b/media/capture/video/chromeos/camera_device_delegate_unittest.cc index 427de1a4476cad..48b29f160ad653 100644 --- a/media/capture/video/chromeos/camera_device_delegate_unittest.cc +++ b/media/capture/video/chromeos/camera_device_delegate_unittest.cc @@ -426,6 +426,7 @@ class CameraDeviceDelegateTest : public ::testing::Test { } protected: + base::test::ScopedTaskEnvironment scoped_task_environment_; scoped_refptr camera_hal_delegate_; std::unique_ptr camera_device_delegate_; @@ -445,7 +446,6 @@ class CameraDeviceDelegateTest : public ::testing::Test { size_t num_streams_; private: - base::test::ScopedTaskEnvironment scoped_task_environment_; base::Thread hal_delegate_thread_; std::unique_ptr run_loop_; DISALLOW_COPY_AND_ASSIGN(CameraDeviceDelegateTest); diff --git a/media/capture/video/chromeos/camera_hal_delegate.cc b/media/capture/video/chromeos/camera_hal_delegate.cc index 68bdbfeda5b7c5..a4f2b17b50a998 100644 --- a/media/capture/video/chromeos/camera_hal_delegate.cc +++ b/media/capture/video/chromeos/camera_hal_delegate.cc @@ -14,6 +14,7 @@ #include "base/bind_helpers.h" #include "base/posix/safe_strerror.h" #include "base/process/launch.h" +#include "base/strings/strcat.h" #include "base/strings/string_piece.h" #include "base/strings/string_split.h" #include "base/system/system_monitor.h" @@ -99,7 +100,8 @@ CameraHalDelegate::CameraHalDelegate( num_builtin_cameras_(0), camera_buffer_factory_(new CameraBufferFactory()), ipc_task_runner_(std::move(ipc_task_runner)), - camera_module_callbacks_(this) { + camera_module_callbacks_(this), + vendor_tag_ops_delegate_(ipc_task_runner_) { DETACH_FROM_SEQUENCE(sequence_checker_); } @@ -248,12 +250,32 @@ void CameraHalDelegate::GetDeviceDescriptors( desc.facing = VideoFacingMode::MEDIA_VIDEO_FACING_USER; desc.set_display_name("Front Camera"); break; - case cros::mojom::CameraFacing::CAMERA_FACING_EXTERNAL: + case cros::mojom::CameraFacing::CAMERA_FACING_EXTERNAL: { desc.facing = VideoFacingMode::MEDIA_VIDEO_FACING_NONE; - desc.set_display_name("External Camera"); + + auto get_vendor_string = [&](const std::string& key) -> const char* { + const VendorTagInfo* info = + vendor_tag_ops_delegate_.GetInfoByName(key); + if (info == nullptr) { + return nullptr; + } + auto val = GetMetadataEntryAsSpan( + camera_info->static_camera_characteristics, info->tag); + return val.empty() ? nullptr : val.data(); + }; + + auto* name = get_vendor_string("com.google.usb.modelName"); + desc.set_display_name(name != nullptr ? name : "External Camera"); + + auto* vid = get_vendor_string("com.google.usb.vendorId"); + auto* pid = get_vendor_string("com.google.usb.productId"); + if (vid != nullptr && pid != nullptr) { + desc.model_id = base::StrCat({vid, ":", pid}); + } break; // Mojo validates the input parameters for us so we don't need to worry // about malformed values. + } } device_descriptors->push_back(desc); } @@ -309,6 +331,7 @@ void CameraHalDelegate::ResetMojoInterfaceOnIpcThread() { if (camera_module_callbacks_.is_bound()) { camera_module_callbacks_.Close(); } + vendor_tag_ops_delegate_.Reset(); builtin_camera_info_updated_.Reset(); camera_module_has_been_set_.Reset(); has_camera_connected_.Reset(); @@ -365,6 +388,10 @@ void CameraHalDelegate::OnGotNumberOfCamerasOnIpcThread(int32_t num_cameras) { camera_module_->SetCallbacks( std::move(camera_module_callbacks_ptr), base::BindOnce(&CameraHalDelegate::OnSetCallbacksOnIpcThread, this)); + + camera_module_->GetVendorTagOps( + vendor_tag_ops_delegate_.MakeRequest(), + base::BindOnce(&CameraHalDelegate::OnGotVendorTagOpsOnIpcThread, this)); } void CameraHalDelegate::OnSetCallbacksOnIpcThread(int32_t result) { @@ -390,6 +417,11 @@ void CameraHalDelegate::OnSetCallbacksOnIpcThread(int32_t result) { } } +void CameraHalDelegate::OnGotVendorTagOpsOnIpcThread() { + DCHECK(ipc_task_runner_->BelongsToCurrentThread()); + vendor_tag_ops_delegate_.Initialize(); +} + void CameraHalDelegate::GetCameraInfoOnIpcThread( int32_t camera_id, GetCameraInfoCallback callback) { diff --git a/media/capture/video/chromeos/camera_hal_delegate.h b/media/capture/video/chromeos/camera_hal_delegate.h index bad13be241fbf5..395ff32ba264d5 100644 --- a/media/capture/video/chromeos/camera_hal_delegate.h +++ b/media/capture/video/chromeos/camera_hal_delegate.h @@ -17,6 +17,7 @@ #include "base/threading/thread.h" #include "media/capture/video/chromeos/mojo/camera3.mojom.h" #include "media/capture/video/chromeos/mojo/camera_common.mojom.h" +#include "media/capture/video/chromeos/vendor_tag_ops_delegate.h" #include "media/capture/video/video_capture_device_factory.h" #include "media/capture/video_capture_types.h" #include "mojo/public/cpp/bindings/binding.h" @@ -47,7 +48,7 @@ class CAPTURE_EXPORT CameraHalDelegate final void SetCameraModule(cros::mojom::CameraModulePtrInfo camera_module_ptr_info); - // Resets |camera_module_| and |camera_module_callbacks_|. + // Resets various mojo bindings, WaitableEvents, and cached information. void Reset(); // Delegation methods for the VideoCaptureDeviceFactory interface. These @@ -94,13 +95,20 @@ class CAPTURE_EXPORT CameraHalDelegate final // GetDeviceDescriptors. bool UpdateBuiltInCameraInfo(); void UpdateBuiltInCameraInfoOnIpcThread(); + // Callback for GetNumberOfCameras Mojo IPC function. GetNumberOfCameras // returns the number of built-in cameras on the device. void OnGotNumberOfCamerasOnIpcThread(int32_t num_cameras); + // Callback for SetCallbacks Mojo IPC function. SetCallbacks is called after // GetNumberOfCameras is called for the first time, and before any other calls // to |camera_module_|. void OnSetCallbacksOnIpcThread(int32_t result); + + // Callback for GetVendorTagOps Mojo IPC function, which will initialize the + // |vendor_tag_ops_delegate_|. + void OnGotVendorTagOpsOnIpcThread(); + void GetCameraInfoOnIpcThread(int32_t camera_id, GetCameraInfoCallback callback); void OnGotCameraInfoOnIpcThread(int32_t camera_id, @@ -163,6 +171,10 @@ class CAPTURE_EXPORT CameraHalDelegate final // |ipc_task_runner_|. mojo::Binding camera_module_callbacks_; + // An internal delegate to handle VendorTagOps mojo connection and query + // information of vendor tags. Bound to |ipc_task_runner_|. + VendorTagOpsDelegate vendor_tag_ops_delegate_; + DISALLOW_COPY_AND_ASSIGN(CameraHalDelegate); }; diff --git a/media/capture/video/chromeos/camera_hal_delegate_unittest.cc b/media/capture/video/chromeos/camera_hal_delegate_unittest.cc index 4f1f101aa1a37b..44dcb1e0b8057c 100644 --- a/media/capture/video/chromeos/camera_hal_delegate_unittest.cc +++ b/media/capture/video/chromeos/camera_hal_delegate_unittest.cc @@ -12,7 +12,9 @@ #include "base/message_loop/message_loop.h" #include "base/run_loop.h" +#include "base/test/scoped_task_environment.h" #include "media/capture/video/chromeos/mock_camera_module.h" +#include "media/capture/video/chromeos/mock_vendor_tag_ops.h" #include "media/capture/video/chromeos/video_capture_device_factory_chromeos.h" #include "media/capture/video/mock_gpu_memory_buffer_manager.h" #include "testing/gmock/include/gmock/gmock.h" @@ -21,14 +23,13 @@ using testing::_; using testing::A; using testing::Invoke; +using testing::Return; namespace media { class CameraHalDelegateTest : public ::testing::Test { public: - CameraHalDelegateTest() - : message_loop_(new base::MessageLoop), - hal_delegate_thread_("HalDelegateThread") {} + CameraHalDelegateTest() : hal_delegate_thread_("HalDelegateThread") {} void SetUp() override { VideoCaptureDeviceFactoryChromeOS::SetGpuBufferManager( @@ -51,12 +52,13 @@ class CameraHalDelegateTest : public ::testing::Test { } protected: + base::test::ScopedTaskEnvironment scoped_task_environment_; scoped_refptr camera_hal_delegate_; testing::StrictMock mock_camera_module_; + testing::StrictMock mock_vendor_tag_ops_; unittest_internal::MockGpuMemoryBufferManager mock_gpu_memory_buffer_manager_; private: - std::unique_ptr message_loop_; base::Thread hal_delegate_thread_; std::unique_ptr run_loop_; DISALLOW_COPY_AND_ASSIGN(CameraHalDelegateTest); @@ -118,6 +120,12 @@ TEST_F(CameraHalDelegateTest, GetBuiltinCameraInfo) { std::move(cb).Run(0, std::move(camera_info)); }; + auto get_vendor_tag_ops_cb = + [&](cros::mojom::VendorTagOpsRequest& vendor_tag_ops_request, + cros::mojom::CameraModule::GetVendorTagOpsCallback& cb) { + mock_vendor_tag_ops_.Bind(std::move(vendor_tag_ops_request)); + }; + EXPECT_CALL(mock_camera_module_, DoGetNumberOfCameras(_)) .Times(1) .WillOnce(Invoke(get_number_of_cameras_cb)); @@ -126,6 +134,12 @@ TEST_F(CameraHalDelegateTest, GetBuiltinCameraInfo) { DoSetCallbacks(A(), A())) .Times(1); + EXPECT_CALL(mock_camera_module_, + DoGetVendorTagOps( + A(), + A())) + .Times(1) + .WillOnce(Invoke(get_vendor_tag_ops_cb)); EXPECT_CALL(mock_camera_module_, DoGetCameraInfo( 0, A())) @@ -137,6 +151,29 @@ TEST_F(CameraHalDelegateTest, GetBuiltinCameraInfo) { .Times(1) .WillOnce(Invoke(get_camera_info_cb)); + EXPECT_CALL(mock_vendor_tag_ops_, DoGetTagCount()) + .Times(1) + .WillOnce(Return(1)); + + const uint32_t kFakeTag = 0x80000000; + + EXPECT_CALL(mock_vendor_tag_ops_, DoGetAllTags()) + .Times(1) + .WillOnce(Return(std::vector{kFakeTag})); + + EXPECT_CALL(mock_vendor_tag_ops_, DoGetSectionName(kFakeTag)) + .Times(1) + .WillOnce(Return("com.google")); + + EXPECT_CALL(mock_vendor_tag_ops_, DoGetTagName(kFakeTag)) + .Times(1) + .WillOnce(Return("fake.foo.bar")); + + EXPECT_CALL(mock_vendor_tag_ops_, DoGetTagType(kFakeTag)) + .Times(1) + .WillOnce( + Return(static_cast(cros::mojom::EntryType::TYPE_BYTE))); + VideoCaptureDeviceDescriptors descriptors; camera_hal_delegate_->GetDeviceDescriptors(&descriptors); @@ -148,6 +185,9 @@ TEST_F(CameraHalDelegateTest, GetBuiltinCameraInfo) { ASSERT_EQ(VideoFacingMode::MEDIA_VIDEO_FACING_ENVIRONMENT, descriptors[1].facing); + // TODO(shik): Test external camera. Check the fields |display_name| and + // |model_id| are set properly according to the vendor tags. + EXPECT_CALL(mock_gpu_memory_buffer_manager_, CreateGpuMemoryBuffer(_, gfx::BufferFormat::YUV_420_BIPLANAR, gfx::BufferUsage::SCANOUT_CAMERA_READ_WRITE, diff --git a/media/capture/video/chromeos/mock_camera_module.cc b/media/capture/video/chromeos/mock_camera_module.cc index 86a840045dcb21..9f0d04e1550f4d 100644 --- a/media/capture/video/chromeos/mock_camera_module.cc +++ b/media/capture/video/chromeos/mock_camera_module.cc @@ -59,6 +59,13 @@ void MockCameraModule::SetTorchMode(int32_t camera_id, std::move(callback).Run(0); } +void MockCameraModule::GetVendorTagOps( + cros::mojom::VendorTagOpsRequest vendor_tag_ops_request, + GetVendorTagOpsCallback callback) { + DoGetVendorTagOps(vendor_tag_ops_request, callback); + std::move(callback).Run(); +} + cros::mojom::CameraModulePtrInfo MockCameraModule::GetInterfacePtrInfo() { base::WaitableEvent done(base::WaitableEvent::ResetPolicy::MANUAL, base::WaitableEvent::InitialState::NOT_SIGNALED); diff --git a/media/capture/video/chromeos/mock_camera_module.h b/media/capture/video/chromeos/mock_camera_module.h index cc482f5232d5f8..2063b4c17f7c22 100644 --- a/media/capture/video/chromeos/mock_camera_module.h +++ b/media/capture/video/chromeos/mock_camera_module.h @@ -57,6 +57,12 @@ class MockCameraModule : public cros::mojom::CameraModule { bool enabled, SetTorchModeCallback& callback)); + void GetVendorTagOps(cros::mojom::VendorTagOpsRequest vendor_tag_ops_request, + GetVendorTagOpsCallback callback) override; + MOCK_METHOD2(DoGetVendorTagOps, + void(cros::mojom::VendorTagOpsRequest& vendor_tag_ops_request, + GetVendorTagOpsCallback& callback)); + cros::mojom::CameraModulePtrInfo GetInterfacePtrInfo(); private: diff --git a/media/capture/video/chromeos/mock_vendor_tag_ops.cc b/media/capture/video/chromeos/mock_vendor_tag_ops.cc new file mode 100644 index 00000000000000..d4799904d810b0 --- /dev/null +++ b/media/capture/video/chromeos/mock_vendor_tag_ops.cc @@ -0,0 +1,67 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// 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/mock_vendor_tag_ops.h" + +#include "base/bind.h" +#include "base/logging.h" +#include "base/synchronization/waitable_event.h" + +namespace media { +namespace unittest_internal { + +MockVendorTagOps::MockVendorTagOps() + : mock_vendor_tag_ops_thread_("MockVendorTagOpsThread"), binding_(this) { + CHECK(mock_vendor_tag_ops_thread_.Start()); +} + +MockVendorTagOps::~MockVendorTagOps() { + mock_vendor_tag_ops_thread_.task_runner()->PostTask( + FROM_HERE, base::BindOnce(&MockVendorTagOps::CloseBindingOnThread, + base::Unretained(this))); + mock_vendor_tag_ops_thread_.Stop(); +} + +void MockVendorTagOps::Bind(cros::mojom::VendorTagOpsRequest request) { + base::WaitableEvent done(base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED); + cros::mojom::CameraModulePtrInfo ptr_info; + mock_vendor_tag_ops_thread_.task_runner()->PostTask( + FROM_HERE, + base::BindOnce(&MockVendorTagOps::BindOnThread, base::Unretained(this), + base::Unretained(&done), std::move(request))); + done.Wait(); +} + +void MockVendorTagOps::GetTagCount(GetTagCountCallback callback) { + std::move(callback).Run(DoGetTagCount()); +} + +void MockVendorTagOps::GetAllTags(GetAllTagsCallback callback) { + std::move(callback).Run(DoGetAllTags()); +} + +void MockVendorTagOps::GetSectionName(uint32_t tag, + GetSectionNameCallback callback) { + std::move(callback).Run(DoGetSectionName(tag)); +} + +void MockVendorTagOps::GetTagName(uint32_t tag, GetTagNameCallback callback) { + std::move(callback).Run(DoGetTagName(tag)); +} + +void MockVendorTagOps::CloseBindingOnThread() { + if (binding_.is_bound()) { + binding_.Close(); + } +} + +void MockVendorTagOps::BindOnThread(base::WaitableEvent* done, + cros::mojom::VendorTagOpsRequest request) { + binding_.Bind(std::move(request)); + done->Signal(); +} + +} // namespace unittest_internal +} // namespace media diff --git a/media/capture/video/chromeos/mock_vendor_tag_ops.h b/media/capture/video/chromeos/mock_vendor_tag_ops.h new file mode 100644 index 00000000000000..b39a9384a8c4d7 --- /dev/null +++ b/media/capture/video/chromeos/mock_vendor_tag_ops.h @@ -0,0 +1,57 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MEDIA_CAPTURE_VIDEO_CHROMEOS_MOCK_VENDOR_TAG_OPS_H_ +#define MEDIA_CAPTURE_VIDEO_CHROMEOS_MOCK_VENDOR_TAG_OPS_H_ + +#include +#include +#include + +#include "base/threading/thread.h" +#include "media/capture/video/chromeos/mojo/camera_common.mojom.h" +#include "mojo/public/cpp/bindings/binding.h" +#include "testing/gmock/include/gmock/gmock.h" + +namespace media { +namespace unittest_internal { + +class MockVendorTagOps : public cros::mojom::VendorTagOps { + public: + MockVendorTagOps(); + ~MockVendorTagOps(); + + void Bind(cros::mojom::VendorTagOpsRequest request); + + MOCK_METHOD0(DoGetTagCount, int32_t()); + void GetTagCount(GetTagCountCallback callback); + + MOCK_METHOD0(DoGetAllTags, std::vector()); + void GetAllTags(GetAllTagsCallback callback); + + MOCK_METHOD1(DoGetSectionName, base::Optional(uint32_t tag)); + void GetSectionName(uint32_t tag, GetSectionNameCallback callback); + + MOCK_METHOD1(DoGetTagName, base::Optional(uint32_t tag)); + void GetTagName(uint32_t tag, GetTagNameCallback callback); + + MOCK_METHOD1(DoGetTagType, int32_t(uint32_t tag)); + void GetTagType(uint32_t tag, GetTagTypeCallback callback) { + std::move(callback).Run(DoGetTagType(tag)); + } + + private: + void CloseBindingOnThread(); + + void BindOnThread(base::WaitableEvent* done, + cros::mojom::VendorTagOpsRequest request); + + base::Thread mock_vendor_tag_ops_thread_; + mojo::Binding binding_; +}; + +} // namespace unittest_internal +} // namespace media + +#endif // MEDIA_CAPTURE_VIDEO_CHROMEOS_MOCK_VENDOR_TAG_OPS_H_ diff --git a/media/capture/video/chromeos/mojo/camera_common.mojom b/media/capture/video/chromeos/mojo/camera_common.mojom index 5e7f1c4330fddc..65689d61c0ffb0 100644 --- a/media/capture/video/chromeos/mojo/camera_common.mojom +++ b/media/capture/video/chromeos/mojo/camera_common.mojom @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Next min version: 2 +// Next min version: 3 module cros.mojom; @@ -57,11 +57,37 @@ interface CameraModuleCallbacks { TorchModeStatusChange@1(int32 camera_id, TorchModeStatus new_status); }; +// VendorTagOps is a translation of the vendor_tag_ops_t API +// (https://goo.gl/3aLWv3). This structure contains basic functions for +// enumerating an immutable set of vendor-defined camera metadata tags, and +// querying static information about their structure/type. +// +// Next method ID: 5 +// TODO(hywu): evaluate passing an array of vendor tags along with their +// section names, tag names, and types +interface VendorTagOps { + // Get the number of vendor tags supported on this platform. Return -1 on + // error. + GetTagCount@0() => (int32 result); + + // Fill an array with all of the supported vendor tags on this platform. + GetAllTags@1() => (array tag_array); + + // Get the vendor section name for a vendor-specified entry tag. + GetSectionName@2(uint32 tag) => (string? name); + + // Get the tag name for a vendor-specified entry tag. + GetTagName@3(uint32 tag) => (string? name); + + // Get tag type for a vendor-specified entry tag. Return -1 on error. + GetTagType@4(uint32 tag) => (int32 type); +}; + // CameraModule is a translation of the camera_module_t API // (https://goo.gl/8Hf8S8). CameraModule is the interface to interact with a // camera HAL to query device info and open camera devices. // -// Next method ID: 6 +// Next method ID: 7 interface CameraModule { // Opens the camera device specified by |camera_id|. On success, the camera // device is accessible through the |device_ops| returned. @@ -87,4 +113,10 @@ interface CameraModule { // one-time operations. [MinVersion=1] Init@5() => (int32 result); + + // Get methods to query for vendor extension metadata tag information. The HAL + // should fill in all the vendor tag operation methods, or leave ops unchanged + // if no vendor tags are defined. + [MinVersion=2] + GetVendorTagOps@6(VendorTagOps& vendor_tag_ops_request) => (); }; diff --git a/media/capture/video/chromeos/reprocess_manager.h b/media/capture/video/chromeos/reprocess_manager.h index 436379fdd93411..a9e2050b2ba044 100644 --- a/media/capture/video/chromeos/reprocess_manager.h +++ b/media/capture/video/chromeos/reprocess_manager.h @@ -33,6 +33,7 @@ struct ReprocessTask { using ReprocessTaskQueue = base::queue; +// TODO(shik): Get the keys from VendorTagOps by names instead (b/130774415). constexpr uint32_t kPortraitModeVendorKey = 0x80000000; constexpr uint32_t kPortraitModeSegmentationResultVendorKey = 0x80000001; constexpr int32_t kReprocessSuccess = 0; diff --git a/media/capture/video/chromeos/vendor_tag_ops_delegate.cc b/media/capture/video/chromeos/vendor_tag_ops_delegate.cc new file mode 100644 index 00000000000000..24f47f1208785e --- /dev/null +++ b/media/capture/video/chromeos/vendor_tag_ops_delegate.cc @@ -0,0 +1,154 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// 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/vendor_tag_ops_delegate.h" + +#include + +#include "base/bind.h" +#include "base/strings/strcat.h" + +namespace media { + +VendorTagOpsDelegate::VendorTagOpsDelegate( + scoped_refptr ipc_task_runner) + : ipc_task_runner_(ipc_task_runner) {} + +VendorTagOpsDelegate::~VendorTagOpsDelegate() = default; + +cros::mojom::VendorTagOpsRequest VendorTagOpsDelegate::MakeRequest() { + DCHECK(ipc_task_runner_->RunsTasksInCurrentSequence()); + auto request = mojo::MakeRequest(&vendor_tag_ops_); + vendor_tag_ops_.set_connection_error_handler( + base::BindOnce(&VendorTagOpsDelegate::Reset, base::Unretained(this))); + return request; +} + +void VendorTagOpsDelegate::Initialize() { + DCHECK(ipc_task_runner_->RunsTasksInCurrentSequence()); + vendor_tag_ops_->GetTagCount(base::BindOnce( + &VendorTagOpsDelegate::OnGotTagCount, base::Unretained(this))); +} + +void VendorTagOpsDelegate::Reset() { + DCHECK(ipc_task_runner_->RunsTasksInCurrentSequence()); + vendor_tag_ops_.reset(); + pending_info_.clear(); + name_map_.clear(); + tag_map_.clear(); + initialized_.Reset(); +} + +void VendorTagOpsDelegate::RemovePending(uint32_t tag) { + DCHECK(ipc_task_runner_->RunsTasksInCurrentSequence()); + size_t removed = pending_info_.erase(tag); + DCHECK_EQ(removed, 1u); + if (pending_info_.empty()) { + DVLOG(1) << "VendorTagOpsDelegate initialized"; + initialized_.Signal(); + } +} + +void VendorTagOpsDelegate::OnGotTagCount(int32_t tag_count) { + DCHECK(ipc_task_runner_->RunsTasksInCurrentSequence()); + if (tag_count == -1) { + LOG(ERROR) << "Failed to get tag count"; + initialized_.Signal(); + return; + } + + if (tag_count == 0) { + // There is no vendor tag, we are done here. + initialized_.Signal(); + return; + } + + vendor_tag_ops_->GetAllTags(base::BindOnce( + &VendorTagOpsDelegate::OnGotAllTags, base::Unretained(this), tag_count)); +} + +void VendorTagOpsDelegate::OnGotAllTags(size_t tag_count, + const std::vector& tags) { + DCHECK(ipc_task_runner_->RunsTasksInCurrentSequence()); + DCHECK_EQ(tags.size(), tag_count); + + for (uint32_t tag : tags) { + pending_info_[tag].tag = static_cast(tag); + vendor_tag_ops_->GetSectionName( + tag, base::BindOnce(&VendorTagOpsDelegate::OnGotSectionName, + base::Unretained(this), tag)); + } +} + +void VendorTagOpsDelegate::OnGotSectionName( + uint32_t tag, + const base::Optional& section_name) { + DCHECK(ipc_task_runner_->RunsTasksInCurrentSequence()); + if (!section_name.has_value()) { + LOG(ERROR) << "Failed to get section name of tag " << std::hex + << std::showbase << tag; + RemovePending(tag); + return; + } + + pending_info_[tag].section_name = *section_name; + vendor_tag_ops_->GetTagName( + tag, base::BindOnce(&VendorTagOpsDelegate::OnGotTagName, + base::Unretained(this), tag)); +} + +void VendorTagOpsDelegate::OnGotTagName( + uint32_t tag, + const base::Optional& tag_name) { + DCHECK(ipc_task_runner_->RunsTasksInCurrentSequence()); + if (!tag_name.has_value()) { + LOG(ERROR) << "Failed to get tag name of tag " << std::hex << std::showbase + << tag; + RemovePending(tag); + return; + } + + pending_info_[tag].tag_name = *tag_name; + vendor_tag_ops_->GetTagType( + tag, base::BindOnce(&VendorTagOpsDelegate::OnGotTagType, + base::Unretained(this), tag)); +} + +void VendorTagOpsDelegate::OnGotTagType(uint32_t tag, int32_t type) { + DCHECK(ipc_task_runner_->RunsTasksInCurrentSequence()); + if (type == -1) { + LOG(ERROR) << "Failed to get tag type of tag " << std::hex << std::showbase + << tag; + RemovePending(tag); + return; + } + + VendorTagInfo& info = pending_info_[tag]; + info.type = static_cast(type); + std::string full_name = base::StrCat({info.section_name, ".", info.tag_name}); + name_map_[full_name] = info; + RemovePending(tag); +} + +const VendorTagInfo* VendorTagOpsDelegate::GetInfoByName( + const std::string& full_name) { + initialized_.Wait(); + auto it = name_map_.find(full_name); + if (it == name_map_.end()) { + return nullptr; + } + return &it->second; +} + +const VendorTagInfo* VendorTagOpsDelegate::GetInfoByTag( + cros::mojom::CameraMetadataTag tag) { + initialized_.Wait(); + auto it = tag_map_.find(tag); + if (it == tag_map_.end()) { + return nullptr; + } + return &it->second; +} + +} // namespace media diff --git a/media/capture/video/chromeos/vendor_tag_ops_delegate.h b/media/capture/video/chromeos/vendor_tag_ops_delegate.h new file mode 100644 index 00000000000000..c343b6c656c6f5 --- /dev/null +++ b/media/capture/video/chromeos/vendor_tag_ops_delegate.h @@ -0,0 +1,68 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MEDIA_CAPTURE_VIDEO_CHROMEOS_VENDOR_TAG_OPS_DELEGATE_H_ +#define MEDIA_CAPTURE_VIDEO_CHROMEOS_VENDOR_TAG_OPS_DELEGATE_H_ + +#include +#include +#include + +#include "media/capture/video/chromeos/mojo/camera_common.mojom.h" + +namespace media { + +struct VendorTagInfo { + cros::mojom::CameraMetadataTag tag; + std::string section_name; + std::string tag_name; + cros::mojom::EntryType type; +}; + +class VendorTagOpsDelegate { + public: + VendorTagOpsDelegate( + scoped_refptr ipc_task_runner); + ~VendorTagOpsDelegate(); + + // Setups/Teardowns the VendorTagOpsDelegate instance. All methods here should + // be called on |ipc_task_runner_|. + cros::mojom::VendorTagOpsRequest MakeRequest(); + void Initialize(); + void Reset(); + + // Gets the info by name or tag after |inited_|. The returned pointer is still + // owned by VendorTagOpsDelegate. Returns nullptr if not found. These + // functions can be called concurrently on different threads. + const VendorTagInfo* GetInfoByName(const std::string& full_name); + const VendorTagInfo* GetInfoByTag(cros::mojom::CameraMetadataTag tag); + + private: + void RemovePending(uint32_t tag); + + void OnGotTagCount(int32_t tag_count); + void OnGotAllTags(size_t tag_count, const std::vector& tags); + void OnGotSectionName(uint32_t tag, + const base::Optional& section_name); + void OnGotTagName(uint32_t tag, const base::Optional& tag_name); + void OnGotTagType(uint32_t tag, int32_t type); + + scoped_refptr ipc_task_runner_; + cros::mojom::VendorTagOpsPtr vendor_tag_ops_; + + // The paritally initialized tags. A tag with its info would be moved to + // |name_map_| and |tag_map_| once it's fully initialized. The |inited_| event + // would be signaled when |pending_info_| is empty. + std::map pending_info_; + + // These maps are read-only after |inited_|. + std::map name_map_; + std::map tag_map_; + + base::WaitableEvent initialized_; +}; + +} // namespace media + +#endif // MEDIA_CAPTURE_VIDEO_CHROMEOS_VENDOR_TAG_OPS_DELEGATE_H_