1 // Copyright 2014 The Chromium Authors. All rights reserved.
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/fake_video_capture_device_factory.h"
6
7 #include <array>
8
9 #include "base/strings/string_number_conversions.h"
10 #include "base/strings/string_split.h"
11 #include "base/strings/string_tokenizer.h"
12 #include "base/strings/string_util.h"
13 #include "base/strings/stringprintf.h"
14 #include "build/build_config.h"
15 #include "gpu/ipc/common/gpu_memory_buffer_support.h"
16 #include "media/base/media_switches.h"
17
18 namespace {
19
20 // Cap the frame rate command line input to reasonable values.
21 static const float kFakeCaptureMinFrameRate = 5.0f;
22 static const float kFakeCaptureMaxFrameRate = 60.0f;
23
24 // Cap the device count command line input to reasonable values.
25 static const int kFakeCaptureMinDeviceCount = 0;
26 static const int kFakeCaptureMaxDeviceCount = 10;
27 static const int kDefaultDeviceCount = 1;
28
29 static const char* kDefaultDeviceIdMask = "/dev/video%d";
30 static const media::FakeVideoCaptureDevice::DeliveryMode kDefaultDeliveryMode =
31 media::FakeVideoCaptureDevice::DeliveryMode::USE_DEVICE_INTERNAL_BUFFERS;
32 static constexpr std::array<gfx::Size, 6> kDefaultResolutions{
33 {gfx::Size(96, 96), gfx::Size(320, 240), gfx::Size(640, 480),
34 gfx::Size(1280, 720), gfx::Size(1920, 1080), gfx::Size(3840, 2160)}};
35 static constexpr std::array<float, 1> kDefaultFrameRates{{20.0f}};
36
37 static const double kInitialPan = 100.0;
38 static const double kInitialTilt = 100.0;
39 static const double kInitialZoom = 100.0;
40 static const double kInitialExposureTime = 50.0;
41 static const double kInitialFocusDistance = 50.0;
42
43 static const media::VideoPixelFormat kSupportedPixelFormats[] = {
44 media::PIXEL_FORMAT_I420, media::PIXEL_FORMAT_Y16,
45 media::PIXEL_FORMAT_MJPEG};
46
47 template <typename TElement, size_t TSize>
ArrayToVector(const std::array<TElement,TSize> & arr)48 std::vector<TElement> ArrayToVector(const std::array<TElement, TSize>& arr) {
49 return std::vector<TElement>(arr.begin(), arr.end());
50 }
51
GetPixelFormatFromDeviceIndex(int device_index)52 media::VideoPixelFormat GetPixelFormatFromDeviceIndex(int device_index) {
53 if (device_index == 1)
54 return media::PIXEL_FORMAT_Y16;
55 if (device_index == 2)
56 return media::PIXEL_FORMAT_MJPEG;
57 return media::PIXEL_FORMAT_I420;
58 }
59
AppendAllCombinationsToFormatsContainer(const std::vector<media::VideoPixelFormat> & pixel_formats,const std::vector<gfx::Size> & resolutions,const std::vector<float> & frame_rates,media::VideoCaptureFormats * output)60 void AppendAllCombinationsToFormatsContainer(
61 const std::vector<media::VideoPixelFormat>& pixel_formats,
62 const std::vector<gfx::Size>& resolutions,
63 const std::vector<float>& frame_rates,
64 media::VideoCaptureFormats* output) {
65 for (const auto& pixel_format : pixel_formats) {
66 for (const auto& resolution : resolutions) {
67 for (const auto& frame_rate : frame_rates)
68 output->emplace_back(resolution, frame_rate, pixel_format);
69 }
70 }
71 }
72
73 class ErrorFakeDevice : public media::VideoCaptureDevice {
74 public:
75 // VideoCaptureDevice implementation.
AllocateAndStart(const media::VideoCaptureParams & params,std::unique_ptr<Client> client)76 void AllocateAndStart(const media::VideoCaptureParams& params,
77 std::unique_ptr<Client> client) override {
78 client->OnError(media::VideoCaptureError::
79 kErrorFakeDeviceIntentionallyEmittingErrorEvent,
80 FROM_HERE, "Device has no supported formats.");
81 }
82
StopAndDeAllocate()83 void StopAndDeAllocate() override {}
GetPhotoState(GetPhotoStateCallback callback)84 void GetPhotoState(GetPhotoStateCallback callback) override {}
SetPhotoOptions(media::mojom::PhotoSettingsPtr settings,SetPhotoOptionsCallback callback)85 void SetPhotoOptions(media::mojom::PhotoSettingsPtr settings,
86 SetPhotoOptionsCallback callback) override {}
TakePhoto(TakePhotoCallback callback)87 void TakePhoto(TakePhotoCallback callback) override {}
88 };
89
90 } // anonymous namespace
91
92 namespace media {
93
94 FakeVideoCaptureDeviceSettings::FakeVideoCaptureDeviceSettings() = default;
95
96 FakeVideoCaptureDeviceSettings::~FakeVideoCaptureDeviceSettings() = default;
97
98 FakeVideoCaptureDeviceSettings::FakeVideoCaptureDeviceSettings(
99 const FakeVideoCaptureDeviceSettings& other) = default;
100
101 constexpr char
102 FakeVideoCaptureDeviceFactory::kDeviceConfigForGetPhotoStateFails[];
103 constexpr char
104 FakeVideoCaptureDeviceFactory::kDeviceConfigForSetPhotoOptionsFails[];
105 constexpr char FakeVideoCaptureDeviceFactory::kDeviceConfigForTakePhotoFails[];
106
FakeVideoCaptureDeviceFactory()107 FakeVideoCaptureDeviceFactory::FakeVideoCaptureDeviceFactory() {
108 // The default |devices_config_| is the one obtained from an empty options
109 // string.
110 ParseFakeDevicesConfigFromOptionsString("", &devices_config_);
111 }
112
113 FakeVideoCaptureDeviceFactory::~FakeVideoCaptureDeviceFactory() = default;
114
115 // static
116 std::unique_ptr<VideoCaptureDevice>
CreateDeviceWithSettings(const FakeVideoCaptureDeviceSettings & settings,std::unique_ptr<gpu::GpuMemoryBufferSupport> gmb_support)117 FakeVideoCaptureDeviceFactory::CreateDeviceWithSettings(
118 const FakeVideoCaptureDeviceSettings& settings,
119 std::unique_ptr<gpu::GpuMemoryBufferSupport> gmb_support) {
120 if (settings.supported_formats.empty())
121 return CreateErrorDevice();
122
123 for (const auto& entry : settings.supported_formats) {
124 bool pixel_format_supported = false;
125 for (const auto& supported_pixel_format : kSupportedPixelFormats) {
126 if (entry.pixel_format == supported_pixel_format) {
127 pixel_format_supported = true;
128 break;
129 }
130 }
131 if (!pixel_format_supported) {
132 DLOG(ERROR) << "Requested an unsupported pixel format "
133 << VideoPixelFormatToString(entry.pixel_format);
134 return nullptr;
135 }
136 }
137
138 const VideoCaptureFormat& initial_format = settings.supported_formats.front();
139 auto device_state = std::make_unique<FakeDeviceState>(
140 kInitialPan, kInitialTilt, kInitialZoom, kInitialExposureTime,
141 kInitialFocusDistance, initial_format.frame_rate,
142 initial_format.pixel_format);
143
144 auto photo_frame_painter = std::make_unique<PacmanFramePainter>(
145 PacmanFramePainter::Format::SK_N32, device_state.get());
146 auto photo_device = std::make_unique<FakePhotoDevice>(
147 std::move(photo_frame_painter), device_state.get(),
148 settings.photo_device_config);
149
150 return std::make_unique<FakeVideoCaptureDevice>(
151 settings.supported_formats,
152 std::make_unique<FrameDelivererFactory>(
153 settings.delivery_mode, device_state.get(), std::move(gmb_support)),
154 std::move(photo_device), std::move(device_state));
155 }
156
157 // static
158 std::unique_ptr<VideoCaptureDevice>
CreateDeviceWithDefaultResolutions(VideoPixelFormat pixel_format,FakeVideoCaptureDevice::DeliveryMode delivery_mode,float frame_rate,std::unique_ptr<gpu::GpuMemoryBufferSupport> gmb_support)159 FakeVideoCaptureDeviceFactory::CreateDeviceWithDefaultResolutions(
160 VideoPixelFormat pixel_format,
161 FakeVideoCaptureDevice::DeliveryMode delivery_mode,
162 float frame_rate,
163 std::unique_ptr<gpu::GpuMemoryBufferSupport> gmb_support) {
164 FakeVideoCaptureDeviceSettings settings;
165 settings.delivery_mode = delivery_mode;
166 for (const gfx::Size& resolution : kDefaultResolutions)
167 settings.supported_formats.emplace_back(resolution, frame_rate,
168 pixel_format);
169 return CreateDeviceWithSettings(settings, std::move(gmb_support));
170 }
171
172 // static
173 std::unique_ptr<VideoCaptureDevice>
CreateErrorDevice()174 FakeVideoCaptureDeviceFactory::CreateErrorDevice() {
175 return std::make_unique<ErrorFakeDevice>();
176 }
177
SetToDefaultDevicesConfig(int device_count)178 void FakeVideoCaptureDeviceFactory::SetToDefaultDevicesConfig(
179 int device_count) {
180 devices_config_.clear();
181 ParseFakeDevicesConfigFromOptionsString(
182 base::StringPrintf("device-count=%d", device_count), &devices_config_);
183 }
184
SetToCustomDevicesConfig(const std::vector<FakeVideoCaptureDeviceSettings> & config)185 void FakeVideoCaptureDeviceFactory::SetToCustomDevicesConfig(
186 const std::vector<FakeVideoCaptureDeviceSettings>& config) {
187 devices_config_ = config;
188 }
189
CreateDevice(const VideoCaptureDeviceDescriptor & device_descriptor)190 std::unique_ptr<VideoCaptureDevice> FakeVideoCaptureDeviceFactory::CreateDevice(
191 const VideoCaptureDeviceDescriptor& device_descriptor) {
192 DCHECK(thread_checker_.CalledOnValidThread());
193
194 for (const auto& entry : devices_config_) {
195 if (device_descriptor.device_id != entry.device_id)
196 continue;
197 return CreateDeviceWithSettings(entry);
198 }
199 return nullptr;
200 }
201
GetDevicesInfo(GetDevicesInfoCallback callback)202 void FakeVideoCaptureDeviceFactory::GetDevicesInfo(
203 GetDevicesInfoCallback callback) {
204 DCHECK(thread_checker_.CalledOnValidThread());
205
206 std::vector<VideoCaptureDeviceInfo> devices_info;
207
208 int entry_index = 0;
209 for (const auto& entry : devices_config_) {
210 VideoCaptureApi api =
211 #if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_BSD)
212 VideoCaptureApi::LINUX_V4L2_SINGLE_PLANE;
213 #elif defined(OS_MAC)
214 VideoCaptureApi::MACOSX_AVFOUNDATION;
215 #elif defined(OS_WIN)
216 VideoCaptureApi::WIN_DIRECT_SHOW;
217 #elif defined(OS_ANDROID)
218 VideoCaptureApi::ANDROID_API2_LEGACY;
219 #elif defined(OS_FUCHSIA)
220 VideoCaptureApi::FUCHSIA_CAMERA3;
221 #else
222 #error Unsupported platform
223 #endif
224
225 devices_info.emplace_back(VideoCaptureDeviceDescriptor(
226 base::StringPrintf("fake_device_%d", entry_index), entry.device_id, api,
227 entry.photo_device_config.control_support,
228 VideoCaptureTransportType::OTHER_TRANSPORT));
229
230 devices_info.back().supported_formats =
231 GetSupportedFormats(entry.device_id);
232 entry_index++;
233 }
234
235 std::move(callback).Run(std::move(devices_info));
236 }
237
GetSupportedFormats(const std::string & device_id)238 VideoCaptureFormats FakeVideoCaptureDeviceFactory::GetSupportedFormats(
239 const std::string& device_id) {
240 DCHECK(thread_checker_.CalledOnValidThread());
241
242 VideoCaptureFormats supported_formats;
243 for (const auto& entry : devices_config_) {
244 if (device_id != entry.device_id)
245 continue;
246 supported_formats.insert(supported_formats.end(),
247 entry.supported_formats.begin(),
248 entry.supported_formats.end());
249 }
250
251 return supported_formats;
252 }
253
254 // static
ParseFakeDevicesConfigFromOptionsString(const std::string options_string,std::vector<FakeVideoCaptureDeviceSettings> * config)255 void FakeVideoCaptureDeviceFactory::ParseFakeDevicesConfigFromOptionsString(
256 const std::string options_string,
257 std::vector<FakeVideoCaptureDeviceSettings>* config) {
258 base::StringTokenizer option_tokenizer(options_string, ", ");
259 option_tokenizer.set_quote_chars("\"");
260
261 FakeVideoCaptureDevice::DeliveryMode delivery_mode = kDefaultDeliveryMode;
262 std::vector<gfx::Size> resolutions = ArrayToVector(kDefaultResolutions);
263 std::vector<float> frame_rates = ArrayToVector(kDefaultFrameRates);
264 int device_count = kDefaultDeviceCount;
265 FakePhotoDeviceConfig photo_device_config;
266 FakeVideoCaptureDevice::DisplayMediaType display_media_type =
267 FakeVideoCaptureDevice::DisplayMediaType::ANY;
268
269 while (option_tokenizer.GetNext()) {
270 std::vector<std::string> param =
271 base::SplitString(option_tokenizer.token(), "=", base::TRIM_WHITESPACE,
272 base::SPLIT_WANT_NONEMPTY);
273
274 if (param.size() != 2u) {
275 LOG(WARNING) << "Forget a value '" << options_string
276 << "'? Use name=value for "
277 << switches::kUseFakeDeviceForMediaStream << ".";
278 return;
279 }
280
281 if (base::EqualsCaseInsensitiveASCII(param.front(), "ownership") &&
282 base::EqualsCaseInsensitiveASCII(param.back(), "client")) {
283 delivery_mode =
284 FakeVideoCaptureDevice::DeliveryMode::USE_CLIENT_PROVIDED_BUFFERS;
285 } else if (base::EqualsCaseInsensitiveASCII(param.front(), "fps")) {
286 double parsed_fps = 0;
287 if (base::StringToDouble(param.back(), &parsed_fps)) {
288 float capped_frame_rate =
289 std::max(kFakeCaptureMinFrameRate, static_cast<float>(parsed_fps));
290 capped_frame_rate =
291 std::min(kFakeCaptureMaxFrameRate, capped_frame_rate);
292 frame_rates.clear();
293 frame_rates.push_back(capped_frame_rate);
294 }
295 } else if (base::EqualsCaseInsensitiveASCII(param.front(),
296 "device-count")) {
297 unsigned int count = 0;
298 if (base::StringToUint(param.back(), &count)) {
299 device_count = std::min(
300 kFakeCaptureMaxDeviceCount,
301 std::max(kFakeCaptureMinDeviceCount, static_cast<int>(count)));
302 }
303 } else if (base::EqualsCaseInsensitiveASCII(param.front(), "config")) {
304 const int device_index = 0;
305 std::vector<VideoPixelFormat> pixel_formats;
306 pixel_formats.push_back(GetPixelFormatFromDeviceIndex(device_index));
307 FakeVideoCaptureDeviceSettings settings;
308 settings.delivery_mode = delivery_mode;
309 settings.device_id =
310 base::StringPrintf(kDefaultDeviceIdMask, device_index);
311 AppendAllCombinationsToFormatsContainer(
312 pixel_formats, resolutions, frame_rates, &settings.supported_formats);
313
314 if (param.back() == kDeviceConfigForGetPhotoStateFails) {
315 settings.photo_device_config.should_fail_get_photo_capabilities = true;
316 config->push_back(settings);
317 return;
318 }
319 if (param.back() == kDeviceConfigForSetPhotoOptionsFails) {
320 settings.photo_device_config.should_fail_set_photo_options = true;
321 config->push_back(settings);
322 return;
323 }
324 if (param.back() == kDeviceConfigForTakePhotoFails) {
325 settings.photo_device_config.should_fail_take_photo = true;
326 config->push_back(settings);
327 return;
328 }
329 LOG(WARNING) << "Unknown config " << param.back();
330 return;
331 } else if (base::EqualsCaseInsensitiveASCII(param.front(),
332 "display-media-type")) {
333 if (base::EqualsCaseInsensitiveASCII(param.back(), "any")) {
334 display_media_type = FakeVideoCaptureDevice::DisplayMediaType::ANY;
335 } else if (base::EqualsCaseInsensitiveASCII(param.back(), "monitor")) {
336 display_media_type = FakeVideoCaptureDevice::DisplayMediaType::MONITOR;
337 } else if (base::EqualsCaseInsensitiveASCII(param.back(), "window")) {
338 display_media_type = FakeVideoCaptureDevice::DisplayMediaType::WINDOW;
339 } else if (base::EqualsCaseInsensitiveASCII(param.back(), "browser")) {
340 display_media_type = FakeVideoCaptureDevice::DisplayMediaType::BROWSER;
341 }
342 } else if (base::EqualsCaseInsensitiveASCII(param.front(),
343 "hardware-support")) {
344 photo_device_config.control_support = VideoCaptureControlSupport();
345 if (!base::EqualsCaseInsensitiveASCII(param.back(), "none")) {
346 for (const std::string& support :
347 base::SplitString(param.back(), "-", base::KEEP_WHITESPACE,
348 base::SPLIT_WANT_NONEMPTY)) {
349 if (base::EqualsCaseInsensitiveASCII(support, "pan"))
350 photo_device_config.control_support.pan = true;
351 else if (base::EqualsCaseInsensitiveASCII(support, "tilt"))
352 photo_device_config.control_support.tilt = true;
353 else if (base::EqualsCaseInsensitiveASCII(support, "zoom"))
354 photo_device_config.control_support.zoom = true;
355 else
356 LOG(WARNING) << "Unsupported hardware support " << support;
357 }
358 }
359 }
360 }
361
362 for (int device_index = 0; device_index < device_count; device_index++) {
363 std::vector<VideoPixelFormat> pixel_formats;
364 pixel_formats.push_back(GetPixelFormatFromDeviceIndex(device_index));
365 FakeVideoCaptureDeviceSettings settings;
366 settings.delivery_mode = delivery_mode;
367 settings.device_id = base::StringPrintf(kDefaultDeviceIdMask, device_index);
368 AppendAllCombinationsToFormatsContainer(
369 pixel_formats, resolutions, frame_rates, &settings.supported_formats);
370 settings.photo_device_config = photo_device_config;
371 settings.display_media_type = display_media_type;
372 config->push_back(settings);
373 }
374 }
375
376 } // namespace media
377