[M120 Migration][MM][WebRTC] Add encoded video capture type support
[platform/framework/web/chromium-efl.git] / media / capture / video / video_capture_system_impl.cc
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.
4
5 #include "media/capture/video/video_capture_system_impl.h"
6
7 #include <utility>
8
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"
17
18 using ScopedCaptureTrace =
19     media::TypedScopedAsyncTrace<media::TraceCategory::kVideoAndImageCapture>;
20
21 namespace {
22
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;
35     }
36     return format1.frame_size.width() > format2.frame_size.width();
37   }
38   return format1.frame_size.GetCheckedArea().ValueOrDefault(0) <
39          format2.frame_size.GetCheckedArea().ValueOrDefault(0);
40 }
41
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;
47 }
48
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) {
52   if (formats->empty())
53     return;
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 #if BUILDFLAG(IS_TIZEN)
60         format.pixel_format != media::PIXEL_FORMAT_ENCODED &&
61 #endif
62 #if defined(TIZEN_MULTIMEDIA_MJPEG_SUPPORT)
63         format.pixel_format != media::PIXEL_FORMAT_MJPEG &&
64 #endif
65         format.pixel_format != media::PIXEL_FORMAT_NV12)
66       format.pixel_format = media::PIXEL_FORMAT_I420;
67   }
68   std::sort(formats->begin(), formats->end(), IsCaptureFormatSmaller);
69   // Remove duplicates
70   auto last =
71       std::unique(formats->begin(), formats->end(), IsCaptureFormatEqual);
72   formats->erase(last, formats->end());
73 }
74
75 void DeviceInfosCallbackTrampoline(
76     media::VideoCaptureSystem::DeviceInfoCallback callback,
77     std::unique_ptr<ScopedCaptureTrace> trace,
78     const std::vector<media::VideoCaptureDeviceInfo>& infos) {
79   std::move(callback).Run(infos);
80 }
81
82 }  // anonymous namespace
83
84 namespace media {
85
86 VideoCaptureSystemImpl::VideoCaptureSystemImpl(
87     std::unique_ptr<VideoCaptureDeviceFactory> factory)
88     : factory_(std::move(factory)) {
89   thread_checker_.DetachFromThread();
90 }
91
92 VideoCaptureSystemImpl::~VideoCaptureSystemImpl() = default;
93
94 void VideoCaptureSystemImpl::GetDeviceInfosAsync(
95     DeviceInfoCallback result_callback) {
96   DCHECK(thread_checker_.CalledOnValidThread());
97   device_enum_request_queue_.push_back(base::BindOnce(
98       &DeviceInfosCallbackTrampoline, std::move(result_callback),
99       ScopedCaptureTrace::CreateIfEnabled("GetDeviceInfosAsync")));
100   if (device_enum_request_queue_.size() == 1) {
101     // base::Unretained() is safe because |factory_| is owned and it guarantees
102     // not to call the callback after destruction.
103     factory_->GetDevicesInfo(base::BindOnce(
104         &VideoCaptureSystemImpl::DevicesInfoReady, base::Unretained(this)));
105   }
106 }
107
108 VideoCaptureErrorOrDevice VideoCaptureSystemImpl::CreateDevice(
109     const std::string& device_id) {
110   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("video_and_image_capture"),
111                "VideoCaptureSystemImpl::CreateDevice");
112   DCHECK(thread_checker_.CalledOnValidThread());
113   const VideoCaptureDeviceInfo* device_info = LookupDeviceInfoFromId(device_id);
114   if (!device_info) {
115     return VideoCaptureErrorOrDevice(
116         VideoCaptureError::kVideoCaptureSystemDeviceIdNotFound);
117   }
118   return factory_->CreateDevice(device_info->descriptor);
119 }
120
121 const VideoCaptureDeviceInfo* VideoCaptureSystemImpl::LookupDeviceInfoFromId(
122     const std::string& device_id) {
123   DCHECK(thread_checker_.CalledOnValidThread());
124   auto iter = base::ranges::find(devices_info_cache_, device_id,
125                                  [](const VideoCaptureDeviceInfo& device_info) {
126                                    return device_info.descriptor.device_id;
127                                  });
128   if (iter == devices_info_cache_.end())
129     return nullptr;
130   return &(*iter);
131 }
132
133 void VideoCaptureSystemImpl::DevicesInfoReady(
134     std::vector<VideoCaptureDeviceInfo> devices_info) {
135   DCHECK(thread_checker_.CalledOnValidThread());
136   DCHECK(!device_enum_request_queue_.empty());
137
138   // Only save metrics the first time device infos are populated.
139   if (devices_info_cache_.empty()) {
140     LogCaptureDeviceMetrics(devices_info);
141   }
142
143   for (auto& device_info : devices_info) {
144     ConsolidateCaptureFormats(&device_info.supported_formats);
145   }
146
147   devices_info_cache_ = std::move(devices_info);
148
149   DeviceEnumQueue requests;
150   std::swap(requests, device_enum_request_queue_);
151
152   auto weak_this = weak_factory_.GetWeakPtr();
153   for (auto& request : requests) {
154     std::move(request).Run(devices_info_cache_);
155
156     // Callbacks may destroy |this|.
157     if (!weak_this)
158       return;
159   }
160 }
161
162 VideoCaptureDeviceFactory* VideoCaptureSystemImpl::GetFactory() {
163   return factory_.get();
164 }
165
166 }  // namespace media