6#include <QtMultimedia/private/qcameradevice_p.h>
7#include <QtMultimedia/private/qmultimedia_ranges_p.h>
8#include <QtMultimedia/private/qpipewire_spa_pod_parser_support_p.h>
9#include <QtMultimedia/private/qpipewire_videoformat_support_p.h>
11#include <spa/pod/pod.h>
21namespace ranges = QtMultimediaPrivate::ranges;
23qreal fpsFromFraction(spa_fraction fraction)
25 if (fraction.denom == 0)
27 return qreal(fraction.num) / qreal(fraction.denom);
30QSize toSize(spa_rectangle rectangle)
32 return QSize(
int(rectangle.width),
int(rectangle.height));
35void appendUnique(std::vector<QSize> &list, QSize value)
37 if (!value.isEmpty() && !ranges::contains(list, value))
38 list.push_back(value);
41void appendUnique(std::vector<QVideoFrameFormat::PixelFormat> &list,
42 QVideoFrameFormat::PixelFormat value)
44 if (value != QVideoFrameFormat::Format_Invalid && !ranges::contains(list, value))
45 list.push_back(value);
48std::vector<QVideoFrameFormat::PixelFormat> parsePixelFormats(
const spa_pod &pod)
50 std::vector<QVideoFrameFormat::PixelFormat> result;
52 if (
auto format = spaParsePodPropertyScalar<spa_video_format>(pod, SPA_TYPE_OBJECT_Format,
53 SPA_FORMAT_VIDEO_format)) {
54 const QVideoFrameFormat::PixelFormat pixelFormat = toQtPixelFormat(*format);
55 if (pixelFormat != QVideoFrameFormat::Format_Invalid)
56 result.push_back(pixelFormat);
60 if (
auto choice = spaParsePodPropertyChoice<spa_video_format, SPA_CHOICE_Enum>(
61 pod, SPA_TYPE_OBJECT_Format, SPA_FORMAT_VIDEO_format)) {
62 appendUnique(result, toQtPixelFormat(choice->defaultValue()));
63 if (choice->size() > 1) {
64 for (spa_video_format format : choice->alternativeValues())
65 appendUnique(result, toQtPixelFormat(format));
72SpaObjectVideoFormat::ResolutionSet parseResolutions(SpaEnum<spa_rectangle> values)
74 std::vector<QSize> result;
75 appendUnique(result, toSize(values.defaultValue()));
76 if (values.size() > 1) {
77 for (spa_rectangle size : values.alternativeValues())
78 appendUnique(result, toSize(size));
82SpaObjectVideoFormat::ResolutionSet parseResolutions(SpaRange<spa_rectangle> range)
85 .preferred = toSize(range.defaultValue),
86 .min = toSize(range.minValue),
87 .max = toSize(range.maxValue),
90SpaObjectVideoFormat::ResolutionSet parseResolutions(
const spa_pod &pod)
92 if (
auto size = spaParsePodPropertyScalar<spa_rectangle>(pod, SPA_TYPE_OBJECT_Format,
93 SPA_FORMAT_VIDEO_size)) {
94 const QSize resolution = toSize(*size);
95 if (resolution.isEmpty())
96 return std::vector<QSize>{};
97 return std::vector{ resolution };
100 auto choice = spaParsePodPropertyChoice<spa_rectangle, SPA_CHOICE_Enum, SPA_CHOICE_Range>(
101 pod, SPA_TYPE_OBJECT_Format, SPA_FORMAT_VIDEO_size);
103 return std::vector<QSize>{};
105 return std::visit([](
const auto &arg) {
106 return parseResolutions(arg);
113std::vector<QSize> expandResolutions(
const SizeRange &range)
115 std::vector<QSize> result;
116 appendUnique(result, range.preferred);
117 appendUnique(result, range.min);
118 appendUnique(result, range.max);
121std::vector<QSize> expandResolutions(
const std::vector<QSize> &list)
125std::vector<QSize> expandResolutions(
const SpaObjectVideoFormat::ResolutionSet &resolutions)
127 return std::visit([](
const auto &arg) {
128 return expandResolutions(arg);
132bool isEmpty(
const std::vector<QSize> &list)
140bool isEmpty(
const SpaObjectVideoFormat::ResolutionSet &resolutions)
142 using namespace QtMultimediaPrivate;
143 return std::visit([](
const auto &arg) {
150std::pair<qreal, qreal> parseFrameRateRange(
const SpaEnum<spa_fraction> &values)
152 std::vector<qreal> fpsValues{ fpsFromFraction(values.defaultValue()) };
153 if (values.size() > 1)
154 ranges::transform(values.alternativeValues(), std::back_inserter(fpsValues), fpsFromFraction);
156 return { ranges::min(fpsValues), ranges::max(fpsValues) };
158std::pair<qreal, qreal> parseFrameRateRange(
const SpaRange<spa_fraction> &range)
160 return { fpsFromFraction(range.minValue), fpsFromFraction(range.maxValue) };
163std::pair<qreal, qreal> parseFrameRateRange(
const spa_pod &pod,
unsigned property)
166 spaParsePodPropertyScalar<spa_fraction>(pod, SPA_TYPE_OBJECT_Format, property)) {
167 const qreal fps = fpsFromFraction(*rate);
171 auto choice = spaParsePodPropertyChoice<spa_fraction, SPA_CHOICE_Enum, SPA_CHOICE_Range>(
172 pod, SPA_TYPE_OBJECT_Format, property);
176 return std::visit([](
const auto &arg) {
177 return parseFrameRateRange(arg);
242 QList<QCameraFormat> result;
244 for (
const SpaObjectVideoFormat &format : formats) {
245 for (QVideoFrameFormat::PixelFormat pixelFormat : format.pixelFormats) {
246 for (QSize resolution : expandResolutions(format.resolutions)) {
247 auto entry = std::make_unique<QCameraFormatPrivate>();
248 entry->pixelFormat = pixelFormat;
249 entry->resolution = resolution;
250 entry->minFrameRate = format.minFrameRate;
251 entry->maxFrameRate = format.maxFrameRate;
253 QCameraFormat cameraFormat = QCameraFormatPrivate::create(std::move(entry));
254 if (!result.contains(cameraFormat))
255 result.push_back(cameraFormat);
QList< QCameraFormat > toCameraFormats(QSpan< const SpaObjectVideoFormat > formats)