1 // Copyright 2017 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "media/capture/video/video_capture_system_impl.h"
9 #include "base/functional/bind.h"
10 #include "base/functional/callback_helpers.h"
11 #include "base/ranges/algorithm.h"
12 #include "base/trace_event/trace_event.h"
13 #include "build/build_config.h"
14 #include "media/base/scoped_async_trace.h"
15 #include "media/capture/video/video_capture_device_factory.h"
16 #include "media/capture/video/video_capture_metrics.h"
18 using ScopedCaptureTrace =
19 media::TypedScopedAsyncTrace<media::TraceCategory::kVideoAndImageCapture>;
23 // Compares two VideoCaptureFormat by checking smallest frame_size area, then
24 // by width, and then by _largest_ frame_rate. Used to order a
25 // VideoCaptureFormats vector so that the first entry for a given resolution has
26 // the largest frame rate.
27 bool IsCaptureFormatSmaller(const media::VideoCaptureFormat& format1,
28 const media::VideoCaptureFormat& format2) {
29 DCHECK(format1.frame_size.GetCheckedArea().IsValid());
30 DCHECK(format2.frame_size.GetCheckedArea().IsValid());
31 if (format1.frame_size.GetCheckedArea().ValueOrDefault(0) ==
32 format2.frame_size.GetCheckedArea().ValueOrDefault(0)) {
33 if (format1.frame_size.width() == format2.frame_size.width()) {
34 return format1.frame_rate > format2.frame_rate;
36 return format1.frame_size.width() > format2.frame_size.width();
38 return format1.frame_size.GetCheckedArea().ValueOrDefault(0) <
39 format2.frame_size.GetCheckedArea().ValueOrDefault(0);
42 bool IsCaptureFormatEqual(const media::VideoCaptureFormat& format1,
43 const media::VideoCaptureFormat& format2) {
44 return format1.frame_size == format2.frame_size &&
45 format1.frame_rate == format2.frame_rate &&
46 format1.pixel_format == format2.pixel_format;
49 // This function receives a list of capture formats, sets all of them to I420
50 // (while keeping Y16 as is), and then removes duplicates.
51 void ConsolidateCaptureFormats(media::VideoCaptureFormats* formats) {
54 // Mark all formats as I420, since this is what the renderer side will get
55 // anyhow: the actual pixel format is decided at the device level.
56 // Don't do this for the Y16 or NV12 formats as they are handled separately.
57 for (auto& format : *formats) {
58 if (format.pixel_format != media::PIXEL_FORMAT_Y16 &&
59 format.pixel_format != media::PIXEL_FORMAT_NV12)
60 format.pixel_format = media::PIXEL_FORMAT_I420;
62 std::sort(formats->begin(), formats->end(), IsCaptureFormatSmaller);
65 std::unique(formats->begin(), formats->end(), IsCaptureFormatEqual);
66 formats->erase(last, formats->end());
69 void DeviceInfosCallbackTrampoline(
70 media::VideoCaptureSystem::DeviceInfoCallback callback,
71 std::unique_ptr<ScopedCaptureTrace> trace,
72 const std::vector<media::VideoCaptureDeviceInfo>& infos) {
73 std::move(callback).Run(infos);
76 } // anonymous namespace
80 VideoCaptureSystemImpl::VideoCaptureSystemImpl(
81 std::unique_ptr<VideoCaptureDeviceFactory> factory)
82 : factory_(std::move(factory)) {
83 thread_checker_.DetachFromThread();
86 VideoCaptureSystemImpl::~VideoCaptureSystemImpl() = default;
88 void VideoCaptureSystemImpl::GetDeviceInfosAsync(
89 DeviceInfoCallback result_callback) {
90 DCHECK(thread_checker_.CalledOnValidThread());
91 device_enum_request_queue_.push_back(base::BindOnce(
92 &DeviceInfosCallbackTrampoline, std::move(result_callback),
93 ScopedCaptureTrace::CreateIfEnabled("GetDeviceInfosAsync")));
94 if (device_enum_request_queue_.size() == 1) {
95 // base::Unretained() is safe because |factory_| is owned and it guarantees
96 // not to call the callback after destruction.
97 factory_->GetDevicesInfo(base::BindOnce(
98 &VideoCaptureSystemImpl::DevicesInfoReady, base::Unretained(this)));
102 VideoCaptureErrorOrDevice VideoCaptureSystemImpl::CreateDevice(
103 const std::string& device_id) {
104 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("video_and_image_capture"),
105 "VideoCaptureSystemImpl::CreateDevice");
106 DCHECK(thread_checker_.CalledOnValidThread());
107 const VideoCaptureDeviceInfo* device_info = LookupDeviceInfoFromId(device_id);
109 return VideoCaptureErrorOrDevice(
110 VideoCaptureError::kVideoCaptureSystemDeviceIdNotFound);
112 return factory_->CreateDevice(device_info->descriptor);
115 const VideoCaptureDeviceInfo* VideoCaptureSystemImpl::LookupDeviceInfoFromId(
116 const std::string& device_id) {
117 DCHECK(thread_checker_.CalledOnValidThread());
118 auto iter = base::ranges::find(devices_info_cache_, device_id,
119 [](const VideoCaptureDeviceInfo& device_info) {
120 return device_info.descriptor.device_id;
122 if (iter == devices_info_cache_.end())
127 void VideoCaptureSystemImpl::DevicesInfoReady(
128 std::vector<VideoCaptureDeviceInfo> devices_info) {
129 DCHECK(thread_checker_.CalledOnValidThread());
130 DCHECK(!device_enum_request_queue_.empty());
132 // Only save metrics the first time device infos are populated.
133 if (devices_info_cache_.empty()) {
134 LogCaptureDeviceMetrics(devices_info);
137 for (auto& device_info : devices_info) {
138 ConsolidateCaptureFormats(&device_info.supported_formats);
141 devices_info_cache_ = std::move(devices_info);
143 DeviceEnumQueue requests;
144 std::swap(requests, device_enum_request_queue_);
146 auto weak_this = weak_factory_.GetWeakPtr();
147 for (auto& request : requests) {
148 std::move(request).Run(devices_info_cache_);
150 // Callbacks may destroy |this|.
156 VideoCaptureDeviceFactory* VideoCaptureSystemImpl::GetFactory() {
157 return factory_.get();