[Reland][Fuchsia] Implement camera device enumeration
Added camera device enumeration in VideoCaptureDeviceFactoryFuchsia using fuchsia.camera3 API. Also updated CMX files for runners to list fuchsia.camera3.DeviceWatcher service. Originally review https://chromium-review.googlesource.com/c/chromium/src/+/2157870 TBR=ddorwin@chromium.org, nasko@chromium.org, guidou@chromium.org Bug: 1064731 Change-Id: I884c0335ff10b2b4445d1037d8794590914facae Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2166342 Reviewed-by: Sergey Ulanov <sergeyu@chromium.org> Commit-Queue: Sergey Ulanov <sergeyu@chromium.org> Cr-Commit-Position: refs/heads/master@{#762560}
This commit is contained in:

committed by
Commit Bot

parent
a7cb0cf42e
commit
1901bee30d
build/config/fuchsia
content
fuchsia
media/capture
@ -13,6 +13,7 @@
|
||||
],
|
||||
"services": [
|
||||
"fuchsia.accessibility.semantics.SemanticsManager",
|
||||
"fuchsia.camera3.DeviceWatcher",
|
||||
"fuchsia.device.NameProvider",
|
||||
"fuchsia.fonts.Provider",
|
||||
"fuchsia.intl.PropertyProvider",
|
||||
|
@ -13,6 +13,7 @@
|
||||
],
|
||||
"services": [
|
||||
"fuchsia.accessibility.semantics.SemanticsManager",
|
||||
"fuchsia.camera3.DeviceWatcher",
|
||||
"fuchsia.device.NameProvider",
|
||||
"fuchsia.fonts.Provider",
|
||||
"fuchsia.intl.PropertyProvider",
|
||||
|
@ -559,10 +559,7 @@ void MediaInternals::UpdateVideoCaptureDeviceCapabilities(
|
||||
device_dict->SetString("id", descriptor.device_id);
|
||||
device_dict->SetString("name", descriptor.GetNameAndModel());
|
||||
device_dict->Set("formats", std::move(format_list));
|
||||
#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX) || \
|
||||
defined(OS_ANDROID)
|
||||
device_dict->SetString("captureApi", descriptor.GetCaptureApiTypeString());
|
||||
#endif
|
||||
video_capture_capabilities_cached_data_.Append(std::move(device_dict));
|
||||
}
|
||||
|
||||
|
@ -48,7 +48,7 @@ namespace content {
|
||||
|
||||
// Mainline routine for running as the utility process.
|
||||
int UtilityMain(const MainFunctionParams& parameters) {
|
||||
const base::MessagePumpType message_pump_type =
|
||||
base::MessagePumpType message_pump_type =
|
||||
parameters.command_line.HasSwitch(switches::kMessageLoopTypeUi)
|
||||
? base::MessagePumpType::UI
|
||||
: base::MessagePumpType::DEFAULT;
|
||||
@ -66,6 +66,12 @@ int UtilityMain(const MainFunctionParams& parameters) {
|
||||
});
|
||||
#endif
|
||||
|
||||
#if defined(OS_FUCHSIA)
|
||||
// On Fuchsia always use IO threads to allow FIDL calls.
|
||||
if (message_pump_type == base::MessagePumpType::DEFAULT)
|
||||
message_pump_type = base::MessagePumpType::IO;
|
||||
#endif // defined(OS_FUCHSIA)
|
||||
|
||||
// The main task executor of the utility process.
|
||||
base::SingleThreadTaskExecutor main_thread_task_executor(message_pump_type);
|
||||
base::PlatformThread::SetName("CrUtilityMain");
|
||||
|
@ -6,6 +6,7 @@
|
||||
],
|
||||
"services": [
|
||||
"fuchsia.accessibility.semantics.SemanticsManager",
|
||||
"fuchsia.camera3.DeviceWatcher",
|
||||
"fuchsia.device.NameProvider",
|
||||
"fuchsia.fonts.Provider",
|
||||
"fuchsia.intl.PropertyProvider",
|
||||
|
@ -6,6 +6,7 @@
|
||||
"services": [
|
||||
"chromium.cast.ApplicationConfigManager",
|
||||
"fuchsia.accessibility.semantics.SemanticsManager",
|
||||
"fuchsia.camera3.DeviceWatcher",
|
||||
"fuchsia.device.NameProvider",
|
||||
"fuchsia.fonts.Provider",
|
||||
"fuchsia.intl.PropertyProvider",
|
||||
|
@ -6,6 +6,7 @@
|
||||
"services": [
|
||||
"fuchsia.accessibility.semantics.SemanticsManager",
|
||||
"fuchsia.device.NameProvider",
|
||||
"fuchsia.camera3.DeviceWatcher",
|
||||
"fuchsia.fonts.Provider",
|
||||
"fuchsia.intl.PropertyProvider",
|
||||
"fuchsia.logger.LogSink",
|
||||
|
@ -310,6 +310,10 @@ jumbo_component("capture_lib") {
|
||||
"video/fuchsia/video_capture_device_factory_fuchsia.cc",
|
||||
"video/fuchsia/video_capture_device_factory_fuchsia.h",
|
||||
]
|
||||
deps += [
|
||||
"//third_party/fuchsia-sdk/sdk/fidl/fuchsia.camera3",
|
||||
"//third_party/fuchsia-sdk/sdk/pkg/sys_cpp",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -74,6 +74,7 @@ enum VideoCaptureApi {
|
||||
ANDROID_API2_LEGACY,
|
||||
ANDROID_API2_FULL,
|
||||
ANDROID_API2_LIMITED,
|
||||
FUCHSIA_CAMERA3,
|
||||
VIRTUAL_DEVICE,
|
||||
UNKNOWN
|
||||
};
|
||||
|
@ -1510,6 +1510,8 @@ EnumTraits<media::mojom::VideoCaptureApi, media::VideoCaptureApi>::ToMojom(
|
||||
return media::mojom::VideoCaptureApi::ANDROID_API2_FULL;
|
||||
case media::VideoCaptureApi::ANDROID_API2_LIMITED:
|
||||
return media::mojom::VideoCaptureApi::ANDROID_API2_LIMITED;
|
||||
case media::VideoCaptureApi::FUCHSIA_CAMERA3:
|
||||
return media::mojom::VideoCaptureApi::FUCHSIA_CAMERA3;
|
||||
case media::VideoCaptureApi::VIRTUAL_DEVICE:
|
||||
return media::mojom::VideoCaptureApi::VIRTUAL_DEVICE;
|
||||
case media::VideoCaptureApi::UNKNOWN:
|
||||
@ -1554,6 +1556,9 @@ bool EnumTraits<media::mojom::VideoCaptureApi, media::VideoCaptureApi>::
|
||||
case media::mojom::VideoCaptureApi::ANDROID_API2_LIMITED:
|
||||
*output = media::VideoCaptureApi::ANDROID_API2_LIMITED;
|
||||
return true;
|
||||
case media::mojom::VideoCaptureApi::FUCHSIA_CAMERA3:
|
||||
*output = media::VideoCaptureApi::FUCHSIA_CAMERA3;
|
||||
return true;
|
||||
case media::mojom::VideoCaptureApi::VIRTUAL_DEVICE:
|
||||
*output = media::VideoCaptureApi::VIRTUAL_DEVICE;
|
||||
return true;
|
||||
|
@ -4,13 +4,113 @@
|
||||
|
||||
#include "media/capture/video/fuchsia/video_capture_device_factory_fuchsia.h"
|
||||
|
||||
#include <lib/sys/cpp/component_context.h>
|
||||
|
||||
#include "base/check_op.h"
|
||||
#include "base/notreached.h"
|
||||
#include "base/fuchsia/default_context.h"
|
||||
#include "base/fuchsia/fuchsia_logging.h"
|
||||
#include "base/location.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
#include "base/threading/thread_task_runner_handle.h"
|
||||
#include "base/time/time.h"
|
||||
|
||||
namespace media {
|
||||
|
||||
VideoCaptureDeviceFactoryFuchsia::VideoCaptureDeviceFactoryFuchsia() = default;
|
||||
VideoCaptureDeviceFactoryFuchsia::~VideoCaptureDeviceFactoryFuchsia() = default;
|
||||
class VideoCaptureDeviceFactoryFuchsia::DeviceInfoFetcher {
|
||||
public:
|
||||
DeviceInfoFetcher(uint64_t device_id, fuchsia::camera3::DevicePtr device)
|
||||
: device_id_(device_id), device_(std::move(device)) {
|
||||
device_.set_error_handler(
|
||||
fit::bind_member(this, &DeviceInfoFetcher::OnError));
|
||||
device_->GetIdentifier(
|
||||
fit::bind_member(this, &DeviceInfoFetcher::OnDescription));
|
||||
device_->GetConfigurations(
|
||||
fit::bind_member(this, &DeviceInfoFetcher::OnConfigurations));
|
||||
}
|
||||
|
||||
~DeviceInfoFetcher() = default;
|
||||
|
||||
DeviceInfoFetcher(const DeviceInfoFetcher&) = delete;
|
||||
const DeviceInfoFetcher& operator=(const DeviceInfoFetcher&) = delete;
|
||||
|
||||
void WaitResults() {
|
||||
DCHECK(!wait_results_run_loop_);
|
||||
|
||||
if (have_results())
|
||||
return;
|
||||
|
||||
if (!device_)
|
||||
return;
|
||||
|
||||
wait_results_run_loop_.emplace();
|
||||
wait_results_run_loop_->Run();
|
||||
wait_results_run_loop_.reset();
|
||||
}
|
||||
|
||||
bool have_results() const { return description_ && formats_; }
|
||||
bool is_usable() const { return device_ || have_results(); }
|
||||
|
||||
uint64_t device_id() const { return device_id_; }
|
||||
const std::string& description() const { return description_.value(); }
|
||||
const VideoCaptureFormats& formats() const { return formats_.value(); }
|
||||
|
||||
private:
|
||||
void OnError(zx_status_t status) {
|
||||
ZX_LOG(ERROR, status) << "fuchsia.camera3.Device disconnected";
|
||||
|
||||
if (wait_results_run_loop_)
|
||||
wait_results_run_loop_->Quit();
|
||||
}
|
||||
|
||||
void OnDescription(fidl::StringPtr identifier) {
|
||||
description_ = identifier.value_or("");
|
||||
MaybeSignalDone();
|
||||
}
|
||||
|
||||
void OnConfigurations(std::vector<fuchsia::camera3::Configuration> configs) {
|
||||
VideoCaptureFormats formats;
|
||||
for (auto& config : configs) {
|
||||
for (auto& props : config.streams) {
|
||||
VideoCaptureFormat format;
|
||||
format.frame_size = gfx::Size(props.image_format.display_width,
|
||||
props.image_format.display_height);
|
||||
format.frame_rate = static_cast<float>(props.frame_rate.numerator) /
|
||||
props.frame_rate.denominator;
|
||||
// VideoFrameCapturerFuchsia converts all formats to I420.
|
||||
format.pixel_format = PIXEL_FORMAT_I420;
|
||||
formats.push_back(format);
|
||||
}
|
||||
}
|
||||
|
||||
formats_ = std::move(formats);
|
||||
MaybeSignalDone();
|
||||
}
|
||||
|
||||
void MaybeSignalDone() {
|
||||
if (!have_results())
|
||||
return;
|
||||
|
||||
device_.Unbind();
|
||||
|
||||
if (wait_results_run_loop_)
|
||||
wait_results_run_loop_->Quit();
|
||||
}
|
||||
|
||||
uint64_t device_id_;
|
||||
fuchsia::camera3::DevicePtr device_;
|
||||
base::Optional<std::string> description_;
|
||||
base::Optional<VideoCaptureFormats> formats_;
|
||||
base::Optional<base::RunLoop> wait_results_run_loop_;
|
||||
};
|
||||
|
||||
VideoCaptureDeviceFactoryFuchsia::VideoCaptureDeviceFactoryFuchsia() {
|
||||
DETACH_FROM_THREAD(thread_checker_);
|
||||
}
|
||||
|
||||
VideoCaptureDeviceFactoryFuchsia::~VideoCaptureDeviceFactoryFuchsia() {
|
||||
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
|
||||
}
|
||||
|
||||
std::unique_ptr<VideoCaptureDevice>
|
||||
VideoCaptureDeviceFactoryFuchsia::CreateDevice(
|
||||
@ -23,14 +123,125 @@ VideoCaptureDeviceFactoryFuchsia::CreateDevice(
|
||||
void VideoCaptureDeviceFactoryFuchsia::GetDeviceDescriptors(
|
||||
VideoCaptureDeviceDescriptors* device_descriptors) {
|
||||
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
|
||||
|
||||
device_descriptors->clear();
|
||||
|
||||
if (!device_watcher_) {
|
||||
DCHECK(!first_update_run_loop_);
|
||||
DCHECK(devices_.empty());
|
||||
|
||||
Initialize();
|
||||
|
||||
// The RunLoop will quit when either we've received the first WatchDevices()
|
||||
// response or DeviceWatcher fails. |devices_| will be empty in case of a
|
||||
// failure.
|
||||
first_update_run_loop_.emplace();
|
||||
first_update_run_loop_->Run();
|
||||
first_update_run_loop_.reset();
|
||||
}
|
||||
|
||||
for (auto& d : devices_) {
|
||||
d.second->WaitResults();
|
||||
if (d.second->is_usable()) {
|
||||
device_descriptors->push_back(VideoCaptureDeviceDescriptor(
|
||||
d.second->description(), base::NumberToString(d.first),
|
||||
VideoCaptureApi::FUCHSIA_CAMERA3));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VideoCaptureDeviceFactoryFuchsia::GetSupportedFormats(
|
||||
const VideoCaptureDeviceDescriptor& device,
|
||||
VideoCaptureFormats* capture_formats) {
|
||||
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
|
||||
capture_formats->clear();
|
||||
|
||||
uint64_t device_id;
|
||||
bool converted = base::StringToUint64(device.device_id, &device_id);
|
||||
DCHECK(converted);
|
||||
|
||||
auto it = devices_.find(device_id);
|
||||
if (it == devices_.end()) {
|
||||
capture_formats->clear();
|
||||
} else {
|
||||
it->second->WaitResults();
|
||||
*capture_formats = it->second->formats();
|
||||
}
|
||||
}
|
||||
|
||||
void VideoCaptureDeviceFactoryFuchsia::Initialize() {
|
||||
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
|
||||
DCHECK(!device_watcher_);
|
||||
DCHECK(devices_.empty());
|
||||
|
||||
base::fuchsia::ComponentContextForCurrentProcess()->svc()->Connect(
|
||||
device_watcher_.NewRequest());
|
||||
|
||||
device_watcher_.set_error_handler(fit::bind_member(
|
||||
this, &VideoCaptureDeviceFactoryFuchsia::OnDeviceWatcherDisconnected));
|
||||
|
||||
WatchDevices();
|
||||
}
|
||||
|
||||
void VideoCaptureDeviceFactoryFuchsia::OnDeviceWatcherDisconnected(
|
||||
zx_status_t status) {
|
||||
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
|
||||
|
||||
ZX_LOG(ERROR, status) << "fuchsia.camera3.DeviceWatcher disconnected.";
|
||||
devices_.clear();
|
||||
|
||||
if (first_update_run_loop_)
|
||||
first_update_run_loop_->Quit();
|
||||
}
|
||||
|
||||
void VideoCaptureDeviceFactoryFuchsia::WatchDevices() {
|
||||
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
|
||||
|
||||
device_watcher_->WatchDevices(fit::bind_member(
|
||||
this, &VideoCaptureDeviceFactoryFuchsia::OnWatchDevicesResult));
|
||||
}
|
||||
|
||||
void VideoCaptureDeviceFactoryFuchsia::OnWatchDevicesResult(
|
||||
std::vector<fuchsia::camera3::WatchDevicesEvent> events) {
|
||||
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
|
||||
|
||||
for (auto& e : events) {
|
||||
if (e.is_removed()) {
|
||||
int erased = devices_.erase(e.removed());
|
||||
if (!erased) {
|
||||
LOG(WARNING) << "Received device removed event for a device that "
|
||||
"wasn't previously registered.";
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
uint64_t id;
|
||||
if (e.is_added()) {
|
||||
id = e.added();
|
||||
if (devices_.find(id) != devices_.end()) {
|
||||
LOG(WARNING) << "Received device added event for a device that was "
|
||||
"previously registered.";
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
id = e.existing();
|
||||
if (devices_.find(id) != devices_.end()) {
|
||||
continue;
|
||||
}
|
||||
LOG(WARNING) << "Received device exists event for a device that wasn't "
|
||||
"previously registered.";
|
||||
}
|
||||
|
||||
fuchsia::camera3::DevicePtr device;
|
||||
device_watcher_->ConnectToDevice(id, device.NewRequest());
|
||||
devices_.emplace(
|
||||
id, std::make_unique<DeviceInfoFetcher>(id, std::move(device)));
|
||||
}
|
||||
|
||||
if (first_update_run_loop_)
|
||||
first_update_run_loop_->Quit();
|
||||
|
||||
// Watch for further updates.
|
||||
WatchDevices();
|
||||
}
|
||||
|
||||
} // namespace media
|
||||
|
@ -5,6 +5,13 @@
|
||||
#ifndef MEDIA_CAPTURE_VIDEO_FUCHSIA_VIDEO_CAPTURE_DEVICE_FACTORY_FUCHSIA_H_
|
||||
#define MEDIA_CAPTURE_VIDEO_FUCHSIA_VIDEO_CAPTURE_DEVICE_FACTORY_FUCHSIA_H_
|
||||
|
||||
#include <fuchsia/camera3/cpp/fidl.h>
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "base/containers/small_map.h"
|
||||
#include "base/optional.h"
|
||||
#include "base/run_loop.h"
|
||||
#include "media/capture/video/video_capture_device_factory.h"
|
||||
|
||||
namespace media {
|
||||
@ -15,6 +22,12 @@ class CAPTURE_EXPORT VideoCaptureDeviceFactoryFuchsia
|
||||
VideoCaptureDeviceFactoryFuchsia();
|
||||
~VideoCaptureDeviceFactoryFuchsia() override;
|
||||
|
||||
VideoCaptureDeviceFactoryFuchsia(const VideoCaptureDeviceFactoryFuchsia&) =
|
||||
delete;
|
||||
VideoCaptureDeviceFactoryFuchsia& operator=(
|
||||
const VideoCaptureDeviceFactoryFuchsia&) = delete;
|
||||
|
||||
// VideoCaptureDeviceFactory implementation.
|
||||
std::unique_ptr<VideoCaptureDevice> CreateDevice(
|
||||
const VideoCaptureDeviceDescriptor& device_descriptor) override;
|
||||
void GetDeviceDescriptors(
|
||||
@ -23,7 +36,26 @@ class CAPTURE_EXPORT VideoCaptureDeviceFactoryFuchsia
|
||||
VideoCaptureFormats* supported_formats) override;
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(VideoCaptureDeviceFactoryFuchsia);
|
||||
// Helper class used to fetch per-device information.
|
||||
class DeviceInfoFetcher;
|
||||
|
||||
void Initialize();
|
||||
|
||||
void OnDeviceWatcherDisconnected(zx_status_t status);
|
||||
|
||||
void WatchDevices();
|
||||
void OnWatchDevicesResult(
|
||||
std::vector<fuchsia::camera3::WatchDevicesEvent> events);
|
||||
|
||||
fuchsia::camera3::DeviceWatcherPtr device_watcher_;
|
||||
base::small_map<std::map<uint64_t, std::unique_ptr<DeviceInfoFetcher>>>
|
||||
devices_;
|
||||
|
||||
// RunLoop used to wait for the first WatchDevices() response. Currently
|
||||
// required because GetDeviceDescriptors() is synchronous.
|
||||
// TODO(crbug.com/1072932) Refactor interface to allow asynchronous
|
||||
// enumeration and remove this hack.
|
||||
base::Optional<base::RunLoop> first_update_run_loop_;
|
||||
};
|
||||
|
||||
} // namespace media
|
||||
|
@ -89,6 +89,8 @@ const char* VideoCaptureDeviceDescriptor::GetCaptureApiTypeString() const {
|
||||
return "Camera API2 Full";
|
||||
case VideoCaptureApi::ANDROID_API2_LIMITED:
|
||||
return "Camera API2 Limited";
|
||||
case VideoCaptureApi::FUCHSIA_CAMERA3:
|
||||
return "fuchsia.camera3 API";
|
||||
case VideoCaptureApi::VIRTUAL_DEVICE:
|
||||
return "Virtual Device";
|
||||
case VideoCaptureApi::UNKNOWN:
|
||||
|
@ -26,6 +26,7 @@ enum class VideoCaptureApi {
|
||||
ANDROID_API2_LEGACY,
|
||||
ANDROID_API2_FULL,
|
||||
ANDROID_API2_LIMITED,
|
||||
FUCHSIA_CAMERA3,
|
||||
VIRTUAL_DEVICE,
|
||||
UNKNOWN
|
||||
};
|
||||
|
Reference in New Issue
Block a user