blob: 23e222bca4488da2db0ce82fd85ad399e6d310ef [file] [log] [blame]
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "media/capture/video/video_capture_metrics.h"
#include "base/containers/fixed_flat_map.h"
#include "base/containers/flat_set.h"
#include "base/containers/span.h"
#include "base/logging.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "ui/gfx/geometry/size.h"
namespace {
// These resolutions are ones supported on a test webcam. Names given
// where possible, from https://en.wikipedia.org/wiki/List_of_common_resolutions
enum class VideoResolutionDesignation {
kUnknown = 0, // Catch-all for resolutions not understood.
// Video Graphics Array resolutions
kQQVGA = 1, // 160x120
kHQVGA = 2, // 240x160
kQVGA = 3, // 320x240
kWQVGA = 4, // 432x240
kHVGA = 5, // 480x320
kVGA = 6, // 640x480
kWVGA = 7, // 720x480
kWSVGA = 8, // 1024x576
kSVGA = 9, // 800x600
// Extended Graphics Array resolutions
kSXGA_MINUS = 10, // 1280x960
kUXGA = 11, // 1600x1200
kQXGA = 12, // 2048x1536
// Common Intermediate Format resolutions
kQCIF = 13, // 176x144
kCIF = 14, // 352x288
// High-definition resolutions.
kNHD = 15, // 640x360
kQHD = 16, // 960x540
kHD_FULLSCREEN = 17, // 960x720
kHD = 18, // 1280x720
kHD_PLUS = 19, // 1600x900
kFHD = 20, // 1920x1080
kWQHD = 21, // 2560x1440
kQHD_PLUS = 22, // 3200x1800
k4K_UHD = 23, // 3840x2160
kDCI_4K = 24, // 4096x2160
k5K = 25, // 5120x2880
k8K_UHD = 26, // 7680x4320
// Odd resolutions with no name
k160x90 = 27,
k320x176 = 28,
k320x180 = 29,
k480x270 = 30,
k544x288 = 31,
k752x416 = 32,
k864x480 = 33,
k800x448 = 34,
k960x544 = 35,
k1184x656 = 36,
k1392x768 = 37,
k1504x832 = 38,
k1600x896 = 39,
k1712x960 = 40,
k1792x1008 = 41,
k2592x1944 = 42,
kMaxValue = k2592x1944,
};
struct FrameSizeCompare {
// Return true iff lhs < rhs.
constexpr bool operator()(const gfx::Size& lhs, const gfx::Size& rhs) const {
return (lhs.height() < rhs.height() ||
(lhs.height() == rhs.height() && lhs.width() < rhs.width()));
}
};
constexpr auto kResolutions =
base::MakeFixedFlatMap<gfx::Size, VideoResolutionDesignation>(
{
{{160, 120}, VideoResolutionDesignation::kQQVGA},
{{240, 160}, VideoResolutionDesignation::kHQVGA},
{{320, 240}, VideoResolutionDesignation::kQVGA},
{{432, 240}, VideoResolutionDesignation::kWQVGA},
{{480, 320}, VideoResolutionDesignation::kHVGA},
{{640, 480}, VideoResolutionDesignation::kVGA},
{{720, 480}, VideoResolutionDesignation::kWVGA},
{{1024, 576}, VideoResolutionDesignation::kWSVGA},
{{800, 600}, VideoResolutionDesignation::kSVGA},
{{1280, 960}, VideoResolutionDesignation::kSXGA_MINUS},
{{1600, 1200}, VideoResolutionDesignation::kUXGA},
{{2048, 1536}, VideoResolutionDesignation::kQXGA},
{{176, 144}, VideoResolutionDesignation::kQCIF},
{{352, 288}, VideoResolutionDesignation::kCIF},
{{640, 360}, VideoResolutionDesignation::kNHD},
{{960, 540}, VideoResolutionDesignation::kQHD},
{{960, 720}, VideoResolutionDesignation::kHD_FULLSCREEN},
{{1280, 720}, VideoResolutionDesignation::kHD},
{{1600, 900}, VideoResolutionDesignation::kHD_PLUS},
{{1920, 1080}, VideoResolutionDesignation::kFHD},
{{2560, 1440}, VideoResolutionDesignation::kWQHD},
{{3200, 1800}, VideoResolutionDesignation::kQHD_PLUS},
{{3840, 2160}, VideoResolutionDesignation::k4K_UHD},
{{4096, 2160}, VideoResolutionDesignation::kDCI_4K},
{{5120, 2880}, VideoResolutionDesignation::k5K},
{{7680, 4320}, VideoResolutionDesignation::k8K_UHD},
{{160, 90}, VideoResolutionDesignation::k160x90},
{{320, 176}, VideoResolutionDesignation::k320x176},
{{320, 180}, VideoResolutionDesignation::k320x180},
{{480, 270}, VideoResolutionDesignation::k480x270},
{{544, 288}, VideoResolutionDesignation::k544x288},
{{752, 416}, VideoResolutionDesignation::k752x416},
{{864, 480}, VideoResolutionDesignation::k864x480},
{{800, 448}, VideoResolutionDesignation::k800x448},
{{960, 544}, VideoResolutionDesignation::k960x544},
{{1184, 656}, VideoResolutionDesignation::k1184x656},
{{1392, 768}, VideoResolutionDesignation::k1392x768},
{{1504, 832}, VideoResolutionDesignation::k1504x832},
{{1600, 896}, VideoResolutionDesignation::k1600x896},
{{1712, 960}, VideoResolutionDesignation::k1712x960},
{{1792, 1008}, VideoResolutionDesignation::k1792x1008},
{{2592, 1944}, VideoResolutionDesignation::k2592x1944},
},
FrameSizeCompare());
static_assert(kResolutions.size() ==
static_cast<size_t>(VideoResolutionDesignation::kMaxValue),
"Each resolution must have one entry in kResolutions.");
VideoResolutionDesignation ResolutionNameFromSize(gfx::Size frame_size) {
// Rotate such that we are always in landscape.
if (frame_size.width() < frame_size.height()) {
int tmp = frame_size.width();
frame_size.set_width(frame_size.height());
frame_size.set_width(tmp);
}
auto* it = kResolutions.find(frame_size);
return it != kResolutions.end() ? it->second
: VideoResolutionDesignation::kUnknown;
}
} // namespace
namespace media {
void LogCaptureDeviceMetrics(
base::span<const media::VideoCaptureDeviceInfo> devices_info) {
for (const auto& device : devices_info) {
base::flat_set<media::VideoPixelFormat> supported_pixel_formats;
base::flat_set<gfx::Size, FrameSizeCompare> resolutions;
for (const auto& format : device.supported_formats) {
VLOG(2) << "Device supports "
<< media::VideoPixelFormatToString(format.pixel_format) << " at "
<< format.frame_size.ToString() << " ("
<< static_cast<int>(ResolutionNameFromSize(format.frame_size))
<< ")";
media::VideoPixelFormat pixel_format = format.pixel_format;
bool inserted = supported_pixel_formats.insert(pixel_format).second;
if (inserted) {
base::UmaHistogramEnumeration(
"Media.VideoCapture.Device.SupportedPixelFormat", pixel_format,
media::VideoPixelFormat::PIXEL_FORMAT_MAX);
}
if (!resolutions.contains(format.frame_size)) {
resolutions.insert(format.frame_size);
base::UmaHistogramEnumeration(
"Media.VideoCapture.Device.SupportedResolution",
ResolutionNameFromSize(format.frame_size));
}
}
}
}
} // namespace media