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