Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(125)

Side by Side Diff: media/capture/video/fake_video_capture_device_factory.cc

Issue 2715513008: Make FakeVideoCaptureDeviceFactory configurable to arbitrary fake device configurations (Closed)
Patch Set: Fix compiler warning. Fix WebRtcDepthCaptureBrowserTest. Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "media/capture/video/fake_video_capture_device_factory.h" 5 #include "media/capture/video/fake_video_capture_device_factory.h"
6 6
7 #include "base/command_line.h" 7 #include <array>
8 #include <vector>
9
8 #include "base/strings/string_number_conversions.h" 10 #include "base/strings/string_number_conversions.h"
9 #include "base/strings/string_split.h" 11 #include "base/strings/string_split.h"
10 #include "base/strings/string_tokenizer.h" 12 #include "base/strings/string_tokenizer.h"
11 #include "base/strings/string_util.h" 13 #include "base/strings/string_util.h"
12 #include "base/strings/stringprintf.h" 14 #include "base/strings/stringprintf.h"
13 #include "build/build_config.h"
14 #include "media/base/media_switches.h" 15 #include "media/base/media_switches.h"
15 16
16 namespace media {
17 namespace { 17 namespace {
18 18
19 static const size_t kDepthDeviceIndex = 1; 19 static const size_t kDepthDeviceIndex = 1;
20 20
21 // Cap the frame rate command line input to reasonable values. 21 // Cap the frame rate command line input to reasonable values.
22 static const float kFakeCaptureMinFrameRate = 5.0f; 22 static const float kFakeCaptureMinFrameRate = 5.0f;
23 static const float kFakeCaptureMaxFrameRate = 60.0f; 23 static const float kFakeCaptureMaxFrameRate = 60.0f;
24 // Default rate if none is specified as part of the command line. 24
25 static const float kFakeCaptureDefaultFrameRate = 20.0f;
26 // Cap the device count command line input to reasonable values. 25 // Cap the device count command line input to reasonable values.
27 static const int kFakeCaptureMinDeviceCount = 1; 26 static const int kFakeCaptureMinDeviceCount = 0;
28 static const int kFakeCaptureMaxDeviceCount = 10; 27 static const int kFakeCaptureMaxDeviceCount = 10;
28 static const int kDefaultDeviceCount = 1;
29 29
30 FakeVideoCaptureDeviceMaker::PixelFormat GetPixelFormatFromDeviceId( 30 static const char* kDefaultDeviceIdMask = "/dev/video%d";
31 const std::string& device_id) { 31 static const media::FakeVideoCaptureDevice::DeliveryMode kDefaultDeliveryMode =
32 if (device_id == "/dev/video1") 32 media::FakeVideoCaptureDevice::DeliveryMode::USE_DEVICE_INTERNAL_BUFFERS;
33 return FakeVideoCaptureDeviceMaker::PixelFormat::Y16; 33 static constexpr std::array<gfx::Size, 5> kDefaultResolutions{
34 if (device_id == "/dev/video2") 34 {gfx::Size(96, 96), gfx::Size(320, 240), gfx::Size(640, 480),
35 return FakeVideoCaptureDeviceMaker::PixelFormat::MJPEG; 35 gfx::Size(1280, 720), gfx::Size(1920, 1080)}};
36 return FakeVideoCaptureDeviceMaker::PixelFormat::I420; 36 static constexpr std::array<float, 1> kDefaultFrameRates{{20.0f}};
37
38 static const double kInitialZoom = 100.0;
39
40 static const media::VideoPixelFormat kSupportedPixelFormats[] = {
41 media::PIXEL_FORMAT_I420, media::PIXEL_FORMAT_Y16,
42 media::PIXEL_FORMAT_MJPEG};
43
44 template <typename TElement, size_t TSize>
45 std::vector<TElement> ArrayToVector(const std::array<TElement, TSize>& arr) {
46 return std::vector<TElement>(arr.begin(), arr.end());
37 } 47 }
38 48
49 media::VideoPixelFormat GetPixelFormatFromDeviceIndex(int device_index) {
50 if (device_index == 1)
51 return media::PIXEL_FORMAT_Y16;
52 if (device_index == 2)
53 return media::PIXEL_FORMAT_MJPEG;
54 return media::PIXEL_FORMAT_I420;
55 }
56
57 void AppendAllCombinationsToFormatsContainer(
58 const std::vector<media::VideoPixelFormat>& pixel_formats,
59 const std::vector<gfx::Size>& resolutions,
60 const std::vector<float>& frame_rates,
61 media::VideoCaptureFormats* output) {
62 for (const auto& pixel_format : pixel_formats) {
63 for (const auto& resolution : resolutions) {
64 for (const auto& frame_rate : frame_rates)
65 output->emplace_back(resolution, frame_rate, pixel_format);
66 }
67 }
68 }
69
70 class ErrorFakeDevice : public media::VideoCaptureDevice {
71 public:
72 // VideoCaptureDevice implementation.
73 void AllocateAndStart(const media::VideoCaptureParams& params,
74 std::unique_ptr<Client> client) override {
75 client->OnError(FROM_HERE, "Device has no supported formats.");
76 }
77
78 void StopAndDeAllocate() override {}
79 void GetPhotoCapabilities(GetPhotoCapabilitiesCallback callback) override {}
80 void SetPhotoOptions(media::mojom::PhotoSettingsPtr settings,
81 SetPhotoOptionsCallback callback) override {}
82 void TakePhoto(TakePhotoCallback callback) override {}
83 };
84
39 } // anonymous namespace 85 } // anonymous namespace
40 86
41 FakeVideoCaptureDeviceFactory::FakeVideoCaptureDeviceFactory() 87 namespace media {
42 : number_of_devices_(1), 88
43 delivery_mode_(FakeVideoCaptureDeviceMaker::DeliveryMode:: 89 FakeVideoCaptureDeviceSettings::FakeVideoCaptureDeviceSettings() = default;
44 USE_DEVICE_INTERNAL_BUFFERS), 90
45 frame_rate_(kFakeCaptureDefaultFrameRate) {} 91 FakeVideoCaptureDeviceSettings::~FakeVideoCaptureDeviceSettings() = default;
92
93 FakeVideoCaptureDeviceSettings::FakeVideoCaptureDeviceSettings(
94 const FakeVideoCaptureDeviceSettings& other) = default;
95
96 FakeVideoCaptureDeviceFactory::FakeVideoCaptureDeviceFactory() {
97 // The default |devices_config_| is the one obtained from an empty options
98 // string.
99 ParseFakeDevicesConfigFromOptionsString("", &devices_config_);
100 }
101
102 FakeVideoCaptureDeviceFactory::~FakeVideoCaptureDeviceFactory() = default;
103
104 // static
105 std::unique_ptr<VideoCaptureDevice>
106 FakeVideoCaptureDeviceFactory::CreateDeviceWithSupportedFormats(
107 FakeVideoCaptureDevice::DeliveryMode delivery_mode,
108 const VideoCaptureFormats& formats) {
109 if (formats.empty())
110 return CreateErrorDevice();
111
112 for (const auto& entry : formats) {
113 bool pixel_format_supported = false;
114 for (const auto& supported_pixel_format : kSupportedPixelFormats) {
115 if (entry.pixel_format == supported_pixel_format) {
116 pixel_format_supported = true;
117 break;
118 }
119 }
120 if (!pixel_format_supported) {
121 DLOG(ERROR) << "Requested an unsupported pixel format "
122 << VideoPixelFormatToString(entry.pixel_format);
123 return nullptr;
124 }
125 }
126
127 const VideoCaptureFormat& initial_format = formats.front();
128 auto device_state = base::MakeUnique<FakeDeviceState>(
129 kInitialZoom, initial_format.frame_rate, initial_format.pixel_format);
130
131 auto photo_frame_painter = base::MakeUnique<PacmanFramePainter>(
132 PacmanFramePainter::Format::SK_N32, device_state.get());
133 auto photo_device = base::MakeUnique<FakePhotoDevice>(
134 std::move(photo_frame_painter), device_state.get());
135
136 return base::MakeUnique<FakeVideoCaptureDevice>(
137 formats,
138 base::MakeUnique<FrameDelivererFactory>(delivery_mode,
139 device_state.get()),
140 std::move(photo_device), std::move(device_state));
141 }
142
143 // static
144 std::unique_ptr<VideoCaptureDevice>
145 FakeVideoCaptureDeviceFactory::CreateDeviceWithDefaultResolutions(
146 VideoPixelFormat pixel_format,
147 FakeVideoCaptureDevice::DeliveryMode delivery_mode,
148 float frame_rate) {
149 VideoCaptureFormats formats;
150 for (const gfx::Size& resolution : kDefaultResolutions)
151 formats.emplace_back(resolution, frame_rate, pixel_format);
152 return CreateDeviceWithSupportedFormats(delivery_mode, formats);
153 }
154
155 // static
156 std::unique_ptr<VideoCaptureDevice>
157 FakeVideoCaptureDeviceFactory::CreateErrorDevice() {
158 return base::MakeUnique<ErrorFakeDevice>();
159 }
160
161 void FakeVideoCaptureDeviceFactory::SetToDefaultDevicesConfig(
162 int device_count) {
163 devices_config_.clear();
164 ParseFakeDevicesConfigFromOptionsString(
165 base::StringPrintf("device-count=%d", device_count), &devices_config_);
166 }
167
168 void FakeVideoCaptureDeviceFactory::SetToCustomDevicesConfig(
169 const std::vector<FakeVideoCaptureDeviceSettings>& config) {
170 devices_config_ = config;
171 }
46 172
47 std::unique_ptr<VideoCaptureDevice> FakeVideoCaptureDeviceFactory::CreateDevice( 173 std::unique_ptr<VideoCaptureDevice> FakeVideoCaptureDeviceFactory::CreateDevice(
48 const VideoCaptureDeviceDescriptor& device_descriptor) { 174 const VideoCaptureDeviceDescriptor& device_descriptor) {
49 DCHECK(thread_checker_.CalledOnValidThread()); 175 DCHECK(thread_checker_.CalledOnValidThread());
50 176
51 ParseCommandLine(); 177 for (const auto& entry : devices_config_) {
52 178 if (device_descriptor.device_id != entry.device_id)
53 for (int n = 0; n < number_of_devices_; ++n) { 179 continue;
54 std::string possible_id = base::StringPrintf("/dev/video%d", n); 180 return CreateDeviceWithSupportedFormats(entry.delivery_mode,
55 if (device_descriptor.device_id.compare(possible_id) == 0) { 181 entry.supported_formats);
56 FakeVideoCaptureDeviceMaker::PixelFormat pixel_format =
57 GetPixelFormatFromDeviceId(possible_id);
58 FakeVideoCaptureDeviceMaker::DeliveryMode delivery_mode = delivery_mode_;
59 if (delivery_mode ==
60 FakeVideoCaptureDeviceMaker::DeliveryMode::
61 USE_CLIENT_PROVIDED_BUFFERS &&
62 pixel_format == FakeVideoCaptureDeviceMaker::PixelFormat::MJPEG) {
63 // Incompatible options. Fall back to using internal buffers.
64 delivery_mode = FakeVideoCaptureDeviceMaker::DeliveryMode::
65 USE_DEVICE_INTERNAL_BUFFERS;
66 }
67 return FakeVideoCaptureDeviceMaker::MakeInstance(
68 pixel_format, delivery_mode, frame_rate_);
69 }
70 } 182 }
71 return std::unique_ptr<VideoCaptureDevice>(); 183 return nullptr;
72 } 184 }
73 185
74 void FakeVideoCaptureDeviceFactory::GetDeviceDescriptors( 186 void FakeVideoCaptureDeviceFactory::GetDeviceDescriptors(
75 VideoCaptureDeviceDescriptors* device_descriptors) { 187 VideoCaptureDeviceDescriptors* device_descriptors) {
76 DCHECK(thread_checker_.CalledOnValidThread()); 188 DCHECK(thread_checker_.CalledOnValidThread());
77 DCHECK(device_descriptors->empty()); 189 DCHECK(device_descriptors->empty());
78 190
79 ParseCommandLine(); 191 int entry_index = 0;
80 192 for (const auto& entry : devices_config_) {
81 for (int n = 0; n < number_of_devices_; ++n) { 193 device_descriptors->emplace_back(
82 device_descriptors->emplace_back(base::StringPrintf("fake_device_%d", n), 194 base::StringPrintf("fake_device_%d", entry_index), entry.device_id,
83 base::StringPrintf("/dev/video%d", n),
84 #if defined(OS_LINUX) 195 #if defined(OS_LINUX)
85 VideoCaptureApi::LINUX_V4L2_SINGLE_PLANE 196 VideoCaptureApi::LINUX_V4L2_SINGLE_PLANE
86 #elif defined(OS_MACOSX) 197 #elif defined(OS_MACOSX)
87 VideoCaptureApi::MACOSX_AVFOUNDATION 198 VideoCaptureApi::MACOSX_AVFOUNDATION
88 #elif defined(OS_WIN) 199 #elif defined(OS_WIN)
89 VideoCaptureApi::WIN_DIRECT_SHOW 200 VideoCaptureApi::WIN_DIRECT_SHOW
90 #elif defined(OS_ANDROID) 201 #elif defined(OS_ANDROID)
91 VideoCaptureApi::ANDROID_API2_LEGACY 202 VideoCaptureApi::ANDROID_API2_LEGACY
92 #endif 203 #endif
93 ); 204 );
205 entry_index++;
94 } 206 }
95 207
96 // Video device on index 1 (kDepthDeviceIndex) is depth video capture device. 208 // Video device on index |kDepthDeviceIndex| is depth video capture device.
97 // Fill the camera calibration information only for it. 209 // Fill the camera calibration information only for it.
98 if (device_descriptors->size() <= kDepthDeviceIndex) 210 if (device_descriptors->size() <= kDepthDeviceIndex)
99 return; 211 return;
100 VideoCaptureDeviceDescriptor& depth_device( 212 VideoCaptureDeviceDescriptor& depth_device(
101 (*device_descriptors)[kDepthDeviceIndex]); 213 (*device_descriptors)[kDepthDeviceIndex]);
102 depth_device.camera_calibration.emplace(); 214 depth_device.camera_calibration.emplace();
103 depth_device.camera_calibration->focal_length_x = 135.0; 215 depth_device.camera_calibration->focal_length_x = 135.0;
104 depth_device.camera_calibration->focal_length_y = 135.6; 216 depth_device.camera_calibration->focal_length_y = 135.6;
105 depth_device.camera_calibration->depth_near = 0.0; 217 depth_device.camera_calibration->depth_near = 0.0;
106 depth_device.camera_calibration->depth_far = 65.535; 218 depth_device.camera_calibration->depth_far = 65.535;
107 } 219 }
108 220
109 void FakeVideoCaptureDeviceFactory::GetSupportedFormats( 221 void FakeVideoCaptureDeviceFactory::GetSupportedFormats(
110 const VideoCaptureDeviceDescriptor& device_descriptor, 222 const VideoCaptureDeviceDescriptor& device_descriptor,
111 VideoCaptureFormats* supported_formats) { 223 VideoCaptureFormats* supported_formats) {
112 DCHECK(thread_checker_.CalledOnValidThread()); 224 DCHECK(thread_checker_.CalledOnValidThread());
113 225
114 ParseCommandLine(); 226 for (const auto& entry : devices_config_) {
115 227 if (device_descriptor.device_id != entry.device_id)
116 const VideoPixelFormat pixel_format = static_cast<VideoPixelFormat>( 228 continue;
117 GetPixelFormatFromDeviceId(device_descriptor.device_id)); 229 supported_formats->insert(supported_formats->end(),
118 const VideoPixelStorage pixel_storage = PIXEL_STORAGE_CPU; 230 entry.supported_formats.begin(),
119 std::vector<gfx::Size> supported_sizes; 231 entry.supported_formats.end());
120 FakeVideoCaptureDeviceMaker::GetSupportedSizes(&supported_sizes);
121 for (const auto& supported_size : supported_sizes) {
122 supported_formats->emplace_back(supported_size, frame_rate_, pixel_format,
123 pixel_storage);
124 } 232 }
125 } 233 }
126 234
127 // Optional comma delimited parameters to the command line can specify buffer 235 // static
128 // ownership, device count, and the fake video devices FPS. 236 void FakeVideoCaptureDeviceFactory::ParseFakeDevicesConfigFromOptionsString(
129 // Examples: "ownership=client, device-count=2, fps=60" "fps=30" 237 const std::string options_string,
130 void FakeVideoCaptureDeviceFactory::ParseCommandLine() { 238 std::vector<FakeVideoCaptureDeviceSettings>* config) {
131 if (command_line_parsed_) 239 base::StringTokenizer option_tokenizer(options_string, ", ");
132 return; 240 option_tokenizer.set_quote_chars("\"");
133 command_line_parsed_ = true;
134 241
135 const std::string option = 242 FakeVideoCaptureDevice::DeliveryMode delivery_mode = kDefaultDeliveryMode;
136 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( 243 std::vector<gfx::Size> resolutions = ArrayToVector(kDefaultResolutions);
emircan 2017/03/01 18:58:59 Is it necessary to copy them into vector? AFAICT Y
chfremer 2017/03/01 21:55:48 It is true that |resolutions| is currently never m
137 switches::kUseFakeDeviceForMediaStream); 244 std::vector<float> frame_rates = ArrayToVector(kDefaultFrameRates);
138 base::StringTokenizer option_tokenizer(option, ", "); 245 int device_count = kDefaultDeviceCount;
139 option_tokenizer.set_quote_chars("\"");
140 246
141 while (option_tokenizer.GetNext()) { 247 while (option_tokenizer.GetNext()) {
142 std::vector<std::string> param = 248 std::vector<std::string> param =
143 base::SplitString(option_tokenizer.token(), "=", base::TRIM_WHITESPACE, 249 base::SplitString(option_tokenizer.token(), "=", base::TRIM_WHITESPACE,
144 base::SPLIT_WANT_NONEMPTY); 250 base::SPLIT_WANT_NONEMPTY);
145 251
146 if (param.size() != 2u) { 252 if (param.size() != 2u) {
147 LOG(WARNING) << "Forget a value '" << option << "'? Use name=value for " 253 LOG(WARNING) << "Forget a value '" << options_string
254 << "'? Use name=value for "
148 << switches::kUseFakeDeviceForMediaStream << "."; 255 << switches::kUseFakeDeviceForMediaStream << ".";
149 return; 256 return;
150 } 257 }
151 258
152 if (base::EqualsCaseInsensitiveASCII(param.front(), "ownership") && 259 if (base::EqualsCaseInsensitiveASCII(param.front(), "ownership") &&
153 base::EqualsCaseInsensitiveASCII(param.back(), "client")) { 260 base::EqualsCaseInsensitiveASCII(param.back(), "client")) {
154 delivery_mode_ = FakeVideoCaptureDeviceMaker::DeliveryMode:: 261 delivery_mode =
155 USE_CLIENT_PROVIDED_BUFFERS; 262 FakeVideoCaptureDevice::DeliveryMode::USE_CLIENT_PROVIDED_BUFFERS;
156 } else if (base::EqualsCaseInsensitiveASCII(param.front(), "fps")) { 263 } else if (base::EqualsCaseInsensitiveASCII(param.front(), "fps")) {
157 double fps = 0; 264 double parsed_fps = 0;
158 if (base::StringToDouble(param.back(), &fps)) { 265 if (base::StringToDouble(param.back(), &parsed_fps)) {
159 frame_rate_ = 266 float capped_frame_rate =
160 std::max(kFakeCaptureMinFrameRate, static_cast<float>(fps)); 267 std::max(kFakeCaptureMinFrameRate, static_cast<float>(parsed_fps));
161 frame_rate_ = std::min(kFakeCaptureMaxFrameRate, frame_rate_); 268 capped_frame_rate =
269 std::min(kFakeCaptureMaxFrameRate, capped_frame_rate);
270 frame_rates.clear();
271 frame_rates.push_back(capped_frame_rate);
162 } 272 }
163 } else if (base::EqualsCaseInsensitiveASCII(param.front(), 273 } else if (base::EqualsCaseInsensitiveASCII(param.front(),
164 "device-count")) { 274 "device-count")) {
165 unsigned int count = 0; 275 unsigned int count = 0;
166 if (base::StringToUint(param.back(), &count)) { 276 if (base::StringToUint(param.back(), &count)) {
167 number_of_devices_ = std::min( 277 device_count = std::min(
168 kFakeCaptureMaxDeviceCount, 278 kFakeCaptureMaxDeviceCount,
169 std::max(kFakeCaptureMinDeviceCount, static_cast<int>(count))); 279 std::max(kFakeCaptureMinDeviceCount, static_cast<int>(count)));
170 } 280 }
171 } 281 }
172 } 282 }
283
284 for (int device_index = 0; device_index < device_count; device_index++) {
285 std::vector<VideoPixelFormat> pixel_formats;
286 pixel_formats.push_back(GetPixelFormatFromDeviceIndex(device_index));
287 FakeVideoCaptureDeviceSettings settings;
288 settings.delivery_mode = delivery_mode;
289 settings.device_id = base::StringPrintf(kDefaultDeviceIdMask, device_index);
290 AppendAllCombinationsToFormatsContainer(
291 pixel_formats, resolutions, frame_rates, &settings.supported_formats);
292 config->push_back(settings);
293 }
173 } 294 }
174 295
175 } // namespace media 296 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698