Skip to content

Commit aca61e3

Browse files
committed
linux-pipewire: camera-portal: Support enumerated sizes
A node might choose to use an enumerated choice pod to report the set of supported sizes. Currently that is not supported. And what's worse, since `SPA_POD_OPT_Rectangle()` is used, if the node uses an enum choice, then `{,this_}resolution` stays uninitialized but `spa_pod_parse_object()` will not report errors because the field is considered optional. Fix this by using `spa_pod_get_values()`, which can be used for concrete values, and both `SPA_CHOICE_{None,Enum}`. Since the resolutions are parsed in two separate places, and since the frame rates require essentially the same treatment a new function is introduced to handle the common parts.
1 parent 1f76884 commit aca61e3

File tree

1 file changed

+57
-39
lines changed

1 file changed

+57
-39
lines changed

plugins/linux-pipewire/camera-portal.c

Lines changed: 57 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -535,6 +535,28 @@ static int compare_resolutions(gconstpointer a, gconstpointer b)
535535
return 0;
536536
}
537537

538+
static const void *get_values_from_pod(const struct spa_pod *p, uint32_t type, uint32_t *cnt)
539+
{
540+
uint32_t choice;
541+
const struct spa_pod *vals = spa_pod_get_values(p, cnt, &choice);
542+
if (!vals || vals->type != type || *cnt <= 0)
543+
return NULL;
544+
545+
const void *body = SPA_POD_BODY_CONST(vals);
546+
547+
switch (choice) {
548+
case SPA_CHOICE_Enum:
549+
/* skip the first one, the default value */
550+
*cnt -= 1;
551+
body = SPA_PTROFF(body, vals->size, const void);
552+
SPA_FALLTHROUGH;
553+
case SPA_CHOICE_None:
554+
return body;
555+
default:
556+
return NULL;
557+
}
558+
}
559+
538560
static void resolution_list(struct camera_device *dev, uint32_t pixelformat, obs_property_t *prop)
539561
{
540562
g_autoptr(GArray) resolutions = NULL;
@@ -546,7 +568,6 @@ static void resolution_list(struct camera_device *dev, uint32_t pixelformat, obs
546568
spa_list_for_each(p, &dev->param_list, link)
547569
{
548570
struct obs_pw_video_format obs_pw_video_format;
549-
struct spa_rectangle resolution;
550571
uint32_t media_type, media_subtype, format;
551572

552573
if (p->id != SPA_PARAM_EnumFormat || p->param == NULL)
@@ -570,11 +591,18 @@ static void resolution_list(struct camera_device *dev, uint32_t pixelformat, obs
570591
if (obs_pw_video_format.video_format != pixelformat)
571592
continue;
572593

573-
if (spa_pod_parse_object(p->param, SPA_TYPE_OBJECT_Format, NULL, SPA_FORMAT_VIDEO_size,
574-
SPA_POD_OPT_Rectangle(&resolution)) < 0)
594+
const struct spa_pod_prop *size_prop = spa_pod_find_prop(p->param, NULL, SPA_FORMAT_VIDEO_size);
595+
if (!size_prop)
596+
continue;
597+
598+
uint32_t n_sizes;
599+
const struct spa_rectangle *sizes =
600+
get_values_from_pod(&size_prop->value, SPA_TYPE_Rectangle, &n_sizes);
601+
if (!sizes)
575602
continue;
576603

577-
g_array_append_val(resolutions, resolution);
604+
for (size_t i = 0; i < n_sizes; i++)
605+
g_array_append_val(resolutions, sizes[i]);
578606
}
579607

580608
g_array_sort(resolutions, compare_resolutions);
@@ -644,15 +672,9 @@ static void framerate_list(struct camera_device *dev, uint32_t pixelformat, cons
644672

645673
spa_list_for_each(p, &dev->param_list, link)
646674
{
647-
const struct spa_fraction *framerate_values;
648675
struct obs_pw_video_format obs_pw_video_format;
649-
enum spa_choice_type choice;
650-
const struct spa_pod_prop *prop;
651-
struct spa_rectangle this_resolution;
652-
struct spa_pod *framerate_pod;
653676
uint32_t media_subtype;
654677
uint32_t media_type;
655-
uint32_t n_framerates;
656678
uint32_t format;
657679

658680
if (p->id != SPA_PARAM_EnumFormat || p->param == NULL)
@@ -676,43 +698,39 @@ static void framerate_list(struct camera_device *dev, uint32_t pixelformat, cons
676698
if (obs_pw_video_format.video_format != pixelformat)
677699
continue;
678700

679-
if (spa_pod_parse_object(p->param, SPA_TYPE_OBJECT_Format, NULL, SPA_FORMAT_VIDEO_size,
680-
SPA_POD_OPT_Rectangle(&this_resolution)) < 0)
701+
const struct spa_pod_prop *size_prop = spa_pod_find_prop(p->param, NULL, SPA_FORMAT_VIDEO_size);
702+
if (!size_prop)
681703
continue;
682704

683-
if (this_resolution.width != resolution->width || this_resolution.height != resolution->height)
705+
uint32_t n_sizes;
706+
const struct spa_rectangle *sizes =
707+
get_values_from_pod(&size_prop->value, SPA_TYPE_Rectangle, &n_sizes);
708+
if (!sizes)
709+
continue;
710+
711+
bool resolution_found = false;
712+
713+
for (size_t i = 0; i < n_sizes; i++) {
714+
resolution_found =
715+
(sizes[i].width == resolution->width && sizes[i].height == resolution->height);
716+
if (resolution_found)
717+
break;
718+
}
719+
720+
if (!resolution_found)
684721
continue;
685722

686-
prop = spa_pod_find_prop(p->param, NULL, SPA_FORMAT_VIDEO_framerate);
687-
if (!prop)
723+
const struct spa_pod_prop *fr_prop = spa_pod_find_prop(p->param, NULL, SPA_FORMAT_VIDEO_framerate);
724+
if (!fr_prop)
688725
continue;
689726

690-
framerate_pod = spa_pod_get_values(&prop->value, &n_framerates, &choice);
691-
if (framerate_pod->type != SPA_TYPE_Fraction) {
692-
blog(LOG_WARNING, "Framerate is not a fraction - something is wrong");
727+
uint32_t n_framerates;
728+
const struct spa_fraction *fr = get_values_from_pod(&fr_prop->value, SPA_TYPE_Fraction, &n_framerates);
729+
if (!fr)
693730
continue;
694-
}
695731

696-
framerate_values = SPA_POD_BODY(framerate_pod);
697-
698-
switch (choice) {
699-
case SPA_CHOICE_None:
700-
g_array_append_val(framerates, framerate_values[0]);
701-
break;
702-
case SPA_CHOICE_Range:
703-
blog(LOG_WARNING, "Ranged framerates not supported");
704-
break;
705-
case SPA_CHOICE_Step:
706-
blog(LOG_WARNING, "Stepped framerates not supported");
707-
break;
708-
case SPA_CHOICE_Enum:
709-
/* i=0 is the default framerate, skip it */
710-
for (uint32_t i = 1; i < n_framerates; i++)
711-
g_array_append_val(framerates, framerate_values[i]);
712-
break;
713-
default:
714-
break;
715-
}
732+
for (size_t i = 0; i < n_framerates; i++)
733+
g_array_append_val(framerates, fr[i]);
716734
}
717735

718736
g_array_sort(framerates, compare_framerates);

0 commit comments

Comments
 (0)