| Index: media/capture/video/fake_video_capture_device_factory.cc
|
| diff --git a/media/capture/video/fake_video_capture_device_factory.cc b/media/capture/video/fake_video_capture_device_factory.cc
|
| index cbe2fa9912c8b9ab9a1cc619708ba6f68a8d3b18..cba70d49f8226e0cf76abd9b60ff2976e228fc22 100644
|
| --- a/media/capture/video/fake_video_capture_device_factory.cc
|
| +++ b/media/capture/video/fake_video_capture_device_factory.cc
|
| @@ -4,16 +4,16 @@
|
|
|
| #include "media/capture/video/fake_video_capture_device_factory.h"
|
|
|
| -#include "base/command_line.h"
|
| +#include <array>
|
| +#include <vector>
|
| +
|
| #include "base/strings/string_number_conversions.h"
|
| #include "base/strings/string_split.h"
|
| #include "base/strings/string_tokenizer.h"
|
| #include "base/strings/string_util.h"
|
| #include "base/strings/stringprintf.h"
|
| -#include "build/build_config.h"
|
| #include "media/base/media_switches.h"
|
|
|
| -namespace media {
|
| namespace {
|
|
|
| static const size_t kDepthDeviceIndex = 1;
|
| @@ -21,53 +21,166 @@ static const size_t kDepthDeviceIndex = 1;
|
| // Cap the frame rate command line input to reasonable values.
|
| static const float kFakeCaptureMinFrameRate = 5.0f;
|
| static const float kFakeCaptureMaxFrameRate = 60.0f;
|
| -// Default rate if none is specified as part of the command line.
|
| -static const float kFakeCaptureDefaultFrameRate = 20.0f;
|
| +
|
| // Cap the device count command line input to reasonable values.
|
| -static const int kFakeCaptureMinDeviceCount = 1;
|
| +static const int kFakeCaptureMinDeviceCount = 0;
|
| static const int kFakeCaptureMaxDeviceCount = 10;
|
| +static const int kDefaultDeviceCount = 1;
|
| +
|
| +static const char* kDefaultDeviceIdMask = "/dev/video%d";
|
| +static const media::FakeVideoCaptureDevice::DeliveryMode kDefaultDeliveryMode =
|
| + media::FakeVideoCaptureDevice::DeliveryMode::USE_DEVICE_INTERNAL_BUFFERS;
|
| +static constexpr std::array<gfx::Size, 5> kDefaultResolutions{
|
| + {gfx::Size(96, 96), gfx::Size(320, 240), gfx::Size(640, 480),
|
| + gfx::Size(1280, 720), gfx::Size(1920, 1080)}};
|
| +static constexpr std::array<float, 1> kDefaultFrameRates{{20.0f}};
|
|
|
| -FakeVideoCaptureDeviceMaker::PixelFormat GetPixelFormatFromDeviceId(
|
| - const std::string& device_id) {
|
| - if (device_id == "/dev/video1")
|
| - return FakeVideoCaptureDeviceMaker::PixelFormat::Y16;
|
| - if (device_id == "/dev/video2")
|
| - return FakeVideoCaptureDeviceMaker::PixelFormat::MJPEG;
|
| - return FakeVideoCaptureDeviceMaker::PixelFormat::I420;
|
| +static const double kInitialZoom = 100.0;
|
| +
|
| +static const media::VideoPixelFormat kSupportedPixelFormats[] = {
|
| + media::PIXEL_FORMAT_I420, media::PIXEL_FORMAT_Y16,
|
| + media::PIXEL_FORMAT_MJPEG};
|
| +
|
| +template <typename TElement, size_t TSize>
|
| +std::vector<TElement> ArrayToVector(const std::array<TElement, TSize>& arr) {
|
| + return std::vector<TElement>(arr.begin(), arr.end());
|
| }
|
|
|
| +media::VideoPixelFormat GetPixelFormatFromDeviceIndex(int device_index) {
|
| + if (device_index == 1)
|
| + return media::PIXEL_FORMAT_Y16;
|
| + if (device_index == 2)
|
| + return media::PIXEL_FORMAT_MJPEG;
|
| + return media::PIXEL_FORMAT_I420;
|
| +}
|
| +
|
| +void AppendAllCombinationsToFormatsContainer(
|
| + const std::vector<media::VideoPixelFormat>& pixel_formats,
|
| + const std::vector<gfx::Size>& resolutions,
|
| + const std::vector<float>& frame_rates,
|
| + media::VideoCaptureFormats* output) {
|
| + for (const auto& pixel_format : pixel_formats) {
|
| + for (const auto& resolution : resolutions) {
|
| + for (const auto& frame_rate : frame_rates)
|
| + output->emplace_back(resolution, frame_rate, pixel_format);
|
| + }
|
| + }
|
| +}
|
| +
|
| +class ErrorFakeDevice : public media::VideoCaptureDevice {
|
| + public:
|
| + // VideoCaptureDevice implementation.
|
| + void AllocateAndStart(const media::VideoCaptureParams& params,
|
| + std::unique_ptr<Client> client) override {
|
| + client->OnError(FROM_HERE, "Device has no supported formats.");
|
| + }
|
| +
|
| + void StopAndDeAllocate() override {}
|
| + void GetPhotoCapabilities(GetPhotoCapabilitiesCallback callback) override {}
|
| + void SetPhotoOptions(media::mojom::PhotoSettingsPtr settings,
|
| + SetPhotoOptionsCallback callback) override {}
|
| + void TakePhoto(TakePhotoCallback callback) override {}
|
| +};
|
| +
|
| } // anonymous namespace
|
|
|
| -FakeVideoCaptureDeviceFactory::FakeVideoCaptureDeviceFactory()
|
| - : number_of_devices_(1),
|
| - delivery_mode_(FakeVideoCaptureDeviceMaker::DeliveryMode::
|
| - USE_DEVICE_INTERNAL_BUFFERS),
|
| - frame_rate_(kFakeCaptureDefaultFrameRate) {}
|
| +namespace media {
|
| +
|
| +FakeVideoCaptureDeviceSettings::FakeVideoCaptureDeviceSettings() = default;
|
| +
|
| +FakeVideoCaptureDeviceSettings::~FakeVideoCaptureDeviceSettings() = default;
|
| +
|
| +FakeVideoCaptureDeviceSettings::FakeVideoCaptureDeviceSettings(
|
| + const FakeVideoCaptureDeviceSettings& other) = default;
|
| +
|
| +FakeVideoCaptureDeviceFactory::FakeVideoCaptureDeviceFactory() {
|
| + // The default |devices_config_| is the one obtained from an empty options
|
| + // string.
|
| + ParseFakeDevicesConfigFromOptionsString("", &devices_config_);
|
| +}
|
| +
|
| +FakeVideoCaptureDeviceFactory::~FakeVideoCaptureDeviceFactory() = default;
|
| +
|
| +// static
|
| +std::unique_ptr<VideoCaptureDevice>
|
| +FakeVideoCaptureDeviceFactory::CreateDeviceWithSupportedFormats(
|
| + FakeVideoCaptureDevice::DeliveryMode delivery_mode,
|
| + const VideoCaptureFormats& formats) {
|
| + if (formats.empty())
|
| + return CreateErrorDevice();
|
| +
|
| + for (const auto& entry : formats) {
|
| + bool pixel_format_supported = false;
|
| + for (const auto& supported_pixel_format : kSupportedPixelFormats) {
|
| + if (entry.pixel_format == supported_pixel_format) {
|
| + pixel_format_supported = true;
|
| + break;
|
| + }
|
| + }
|
| + if (!pixel_format_supported) {
|
| + DLOG(ERROR) << "Requested an unsupported pixel format "
|
| + << VideoPixelFormatToString(entry.pixel_format);
|
| + return nullptr;
|
| + }
|
| + }
|
| +
|
| + const VideoCaptureFormat& initial_format = formats.front();
|
| + auto device_state = base::MakeUnique<FakeDeviceState>(
|
| + kInitialZoom, initial_format.frame_rate, initial_format.pixel_format);
|
| +
|
| + auto photo_frame_painter = base::MakeUnique<PacmanFramePainter>(
|
| + PacmanFramePainter::Format::SK_N32, device_state.get());
|
| + auto photo_device = base::MakeUnique<FakePhotoDevice>(
|
| + std::move(photo_frame_painter), device_state.get());
|
| +
|
| + return base::MakeUnique<FakeVideoCaptureDevice>(
|
| + formats,
|
| + base::MakeUnique<FrameDelivererFactory>(delivery_mode,
|
| + device_state.get()),
|
| + std::move(photo_device), std::move(device_state));
|
| +}
|
| +
|
| +// static
|
| +std::unique_ptr<VideoCaptureDevice>
|
| +FakeVideoCaptureDeviceFactory::CreateDeviceWithDefaultResolutions(
|
| + VideoPixelFormat pixel_format,
|
| + FakeVideoCaptureDevice::DeliveryMode delivery_mode,
|
| + float frame_rate) {
|
| + VideoCaptureFormats formats;
|
| + for (const gfx::Size& resolution : kDefaultResolutions)
|
| + formats.emplace_back(resolution, frame_rate, pixel_format);
|
| + return CreateDeviceWithSupportedFormats(delivery_mode, formats);
|
| +}
|
| +
|
| +// static
|
| +std::unique_ptr<VideoCaptureDevice>
|
| +FakeVideoCaptureDeviceFactory::CreateErrorDevice() {
|
| + return base::MakeUnique<ErrorFakeDevice>();
|
| +}
|
| +
|
| +void FakeVideoCaptureDeviceFactory::SetToDefaultDevicesConfig(
|
| + int device_count) {
|
| + devices_config_.clear();
|
| + ParseFakeDevicesConfigFromOptionsString(
|
| + base::StringPrintf("device-count=%d", device_count), &devices_config_);
|
| +}
|
| +
|
| +void FakeVideoCaptureDeviceFactory::SetToCustomDevicesConfig(
|
| + const std::vector<FakeVideoCaptureDeviceSettings>& config) {
|
| + devices_config_ = config;
|
| +}
|
|
|
| std::unique_ptr<VideoCaptureDevice> FakeVideoCaptureDeviceFactory::CreateDevice(
|
| const VideoCaptureDeviceDescriptor& device_descriptor) {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
|
|
| - ParseCommandLine();
|
| -
|
| - for (int n = 0; n < number_of_devices_; ++n) {
|
| - std::string possible_id = base::StringPrintf("/dev/video%d", n);
|
| - if (device_descriptor.device_id.compare(possible_id) == 0) {
|
| - FakeVideoCaptureDeviceMaker::PixelFormat pixel_format =
|
| - GetPixelFormatFromDeviceId(possible_id);
|
| - FakeVideoCaptureDeviceMaker::DeliveryMode delivery_mode = delivery_mode_;
|
| - if (delivery_mode == FakeVideoCaptureDeviceMaker::DeliveryMode::
|
| - USE_CLIENT_PROVIDED_BUFFERS &&
|
| - pixel_format == FakeVideoCaptureDeviceMaker::PixelFormat::MJPEG) {
|
| - // Incompatible options. Fall back to using internal buffers.
|
| - delivery_mode = FakeVideoCaptureDeviceMaker::DeliveryMode::
|
| - USE_DEVICE_INTERNAL_BUFFERS;
|
| - }
|
| - return FakeVideoCaptureDeviceMaker::MakeInstance(
|
| - pixel_format, delivery_mode, frame_rate_);
|
| - }
|
| + for (const auto& entry : devices_config_) {
|
| + if (device_descriptor.device_id != entry.device_id)
|
| + continue;
|
| + return CreateDeviceWithSupportedFormats(entry.delivery_mode,
|
| + entry.supported_formats);
|
| }
|
| - return std::unique_ptr<VideoCaptureDevice>();
|
| + return nullptr;
|
| }
|
|
|
| void FakeVideoCaptureDeviceFactory::GetDeviceDescriptors(
|
| @@ -75,24 +188,24 @@ void FakeVideoCaptureDeviceFactory::GetDeviceDescriptors(
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
| DCHECK(device_descriptors->empty());
|
|
|
| - ParseCommandLine();
|
| -
|
| - for (int n = 0; n < number_of_devices_; ++n) {
|
| - device_descriptors->emplace_back(base::StringPrintf("fake_device_%d", n),
|
| - base::StringPrintf("/dev/video%d", n),
|
| + int entry_index = 0;
|
| + for (const auto& entry : devices_config_) {
|
| + device_descriptors->emplace_back(
|
| + base::StringPrintf("fake_device_%d", entry_index), entry.device_id,
|
| #if defined(OS_LINUX)
|
| - VideoCaptureApi::LINUX_V4L2_SINGLE_PLANE
|
| + VideoCaptureApi::LINUX_V4L2_SINGLE_PLANE
|
| #elif defined(OS_MACOSX)
|
| - VideoCaptureApi::MACOSX_AVFOUNDATION
|
| + VideoCaptureApi::MACOSX_AVFOUNDATION
|
| #elif defined(OS_WIN)
|
| - VideoCaptureApi::WIN_DIRECT_SHOW
|
| + VideoCaptureApi::WIN_DIRECT_SHOW
|
| #elif defined(OS_ANDROID)
|
| - VideoCaptureApi::ANDROID_API2_LEGACY
|
| + VideoCaptureApi::ANDROID_API2_LEGACY
|
| #endif
|
| - );
|
| + );
|
| + entry_index++;
|
| }
|
|
|
| - // Video device on index 1 (kDepthDeviceIndex) is depth video capture device.
|
| + // Video device on index |kDepthDeviceIndex| is depth video capture device.
|
| // Fill the camera calibration information only for it.
|
| if (device_descriptors->size() <= kDepthDeviceIndex)
|
| return;
|
| @@ -110,65 +223,74 @@ void FakeVideoCaptureDeviceFactory::GetSupportedFormats(
|
| VideoCaptureFormats* supported_formats) {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
|
|
| - ParseCommandLine();
|
| -
|
| - const VideoPixelFormat pixel_format = static_cast<VideoPixelFormat>(
|
| - GetPixelFormatFromDeviceId(device_descriptor.device_id));
|
| - const VideoPixelStorage pixel_storage = PIXEL_STORAGE_CPU;
|
| - std::vector<gfx::Size> supported_sizes;
|
| - FakeVideoCaptureDeviceMaker::GetSupportedSizes(&supported_sizes);
|
| - for (const auto& supported_size : supported_sizes) {
|
| - supported_formats->emplace_back(supported_size, frame_rate_, pixel_format,
|
| - pixel_storage);
|
| + for (const auto& entry : devices_config_) {
|
| + if (device_descriptor.device_id != entry.device_id)
|
| + continue;
|
| + supported_formats->insert(supported_formats->end(),
|
| + entry.supported_formats.begin(),
|
| + entry.supported_formats.end());
|
| }
|
| }
|
|
|
| -// Optional comma delimited parameters to the command line can specify buffer
|
| -// ownership, device count, and the fake video devices FPS.
|
| -// Examples: "ownership=client, device-count=2, fps=60" "fps=30"
|
| -void FakeVideoCaptureDeviceFactory::ParseCommandLine() {
|
| - if (command_line_parsed_)
|
| - return;
|
| - command_line_parsed_ = true;
|
| -
|
| - const std::string option =
|
| - base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
|
| - switches::kUseFakeDeviceForMediaStream);
|
| - base::StringTokenizer option_tokenizer(option, ", ");
|
| +// static
|
| +void FakeVideoCaptureDeviceFactory::ParseFakeDevicesConfigFromOptionsString(
|
| + const std::string options_string,
|
| + std::vector<FakeVideoCaptureDeviceSettings>* config) {
|
| + base::StringTokenizer option_tokenizer(options_string, ", ");
|
| option_tokenizer.set_quote_chars("\"");
|
|
|
| + FakeVideoCaptureDevice::DeliveryMode delivery_mode = kDefaultDeliveryMode;
|
| + std::vector<gfx::Size> resolutions = ArrayToVector(kDefaultResolutions);
|
| + std::vector<float> frame_rates = ArrayToVector(kDefaultFrameRates);
|
| + int device_count = kDefaultDeviceCount;
|
| +
|
| while (option_tokenizer.GetNext()) {
|
| std::vector<std::string> param =
|
| base::SplitString(option_tokenizer.token(), "=", base::TRIM_WHITESPACE,
|
| base::SPLIT_WANT_NONEMPTY);
|
|
|
| if (param.size() != 2u) {
|
| - LOG(WARNING) << "Forget a value '" << option << "'? Use name=value for "
|
| + LOG(WARNING) << "Forget a value '" << options_string
|
| + << "'? Use name=value for "
|
| << switches::kUseFakeDeviceForMediaStream << ".";
|
| return;
|
| }
|
|
|
| if (base::EqualsCaseInsensitiveASCII(param.front(), "ownership") &&
|
| base::EqualsCaseInsensitiveASCII(param.back(), "client")) {
|
| - delivery_mode_ = FakeVideoCaptureDeviceMaker::DeliveryMode::
|
| - USE_CLIENT_PROVIDED_BUFFERS;
|
| + delivery_mode =
|
| + FakeVideoCaptureDevice::DeliveryMode::USE_CLIENT_PROVIDED_BUFFERS;
|
| } else if (base::EqualsCaseInsensitiveASCII(param.front(), "fps")) {
|
| - double fps = 0;
|
| - if (base::StringToDouble(param.back(), &fps)) {
|
| - frame_rate_ =
|
| - std::max(kFakeCaptureMinFrameRate, static_cast<float>(fps));
|
| - frame_rate_ = std::min(kFakeCaptureMaxFrameRate, frame_rate_);
|
| + double parsed_fps = 0;
|
| + if (base::StringToDouble(param.back(), &parsed_fps)) {
|
| + float capped_frame_rate =
|
| + std::max(kFakeCaptureMinFrameRate, static_cast<float>(parsed_fps));
|
| + capped_frame_rate =
|
| + std::min(kFakeCaptureMaxFrameRate, capped_frame_rate);
|
| + frame_rates.clear();
|
| + frame_rates.push_back(capped_frame_rate);
|
| }
|
| } else if (base::EqualsCaseInsensitiveASCII(param.front(),
|
| "device-count")) {
|
| unsigned int count = 0;
|
| if (base::StringToUint(param.back(), &count)) {
|
| - number_of_devices_ = std::min(
|
| + device_count = std::min(
|
| kFakeCaptureMaxDeviceCount,
|
| std::max(kFakeCaptureMinDeviceCount, static_cast<int>(count)));
|
| }
|
| }
|
| }
|
| +
|
| + for (int device_index = 0; device_index < device_count; device_index++) {
|
| + std::vector<VideoPixelFormat> pixel_formats;
|
| + pixel_formats.push_back(GetPixelFormatFromDeviceIndex(device_index));
|
| + FakeVideoCaptureDeviceSettings settings;
|
| + settings.delivery_mode = delivery_mode;
|
| + settings.device_id = base::StringPrintf(kDefaultDeviceIdMask, device_index);
|
| + AppendAllCombinationsToFormatsContainer(
|
| + pixel_formats, resolutions, frame_rates, &settings.supported_formats);
|
| + config->push_back(settings);
|
| + }
|
| }
|
|
|
| } // namespace media
|
|
|