From e379267274364ceeef8c4f94cdc768e14dd03927 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Barnab=C3=A1s=20P=C5=91cze?= Date: Wed, 23 Jul 2025 14:32:56 +0200 Subject: [PATCH] spa: libcamera: source: handle enum controls better If the `libcamera::ControlInfo` object explicitly lists the values of a control, then use those values when adding `SPA_PROP_INFO_type` to construct an enumerated choice object. --- spa/plugins/libcamera/libcamera-source.cpp | 107 +++++++++++++++------ 1 file changed, 77 insertions(+), 30 deletions(-) diff --git a/spa/plugins/libcamera/libcamera-source.cpp b/spa/plugins/libcamera/libcamera-source.cpp index d36acaff6..a983a9de2 100644 --- a/spa/plugins/libcamera/libcamera-source.cpp +++ b/spa/plugins/libcamera/libcamera-source.cpp @@ -742,6 +742,32 @@ uint32_t prop_id_to_control(uint32_t prop_id) return SPA_ID_INVALID; } +[[nodiscard]] +bool control_value_to_pod(spa_pod_builder& b, const libcamera::ControlValue& cv) +{ + if (cv.isArray()) + return false; + + switch (cv.type()) { + case libcamera::ControlTypeBool: { + spa_pod_builder_bool(&b, cv.get()); + break; + } + case libcamera::ControlTypeInteger32: { + spa_pod_builder_int(&b, cv.get()); + break; + } + case libcamera::ControlTypeFloat: { + spa_pod_builder_float(&b, cv.get()); + break; + } + default: + return false; + } + + return true; +} + template [[nodiscard]] std::array control_info_to_range(const libcamera::ControlInfo& cinfo) @@ -775,41 +801,62 @@ spa_pod *control_details_to_pod(spa_pod_builder& b, SPA_PROP_INFO_description, SPA_POD_String(cid.name().c_str()), 0); - switch (cid.type()) { - case ControlTypeBool: { - auto min = cinfo.min().get(); - auto max = cinfo.max().get(); - auto def = !cinfo.def().isNone() - ? cinfo.def().get() - : min; + if (cinfo.values().empty()) { + switch (cid.type()) { + case ControlTypeBool: { + auto min = cinfo.min().get(); + auto max = cinfo.max().get(); + auto def = !cinfo.def().isNone() + ? cinfo.def().get() + : min; + spa_pod_frame f; + + spa_pod_builder_prop(&b, SPA_PROP_INFO_type, 0); + spa_pod_builder_push_choice(&b, &f, SPA_CHOICE_Enum, 0); + spa_pod_builder_bool(&b, def); + spa_pod_builder_bool(&b, min); + if (max != min) + spa_pod_builder_bool(&b, max); + spa_pod_builder_pop(&b, &f); + break; + } + case ControlTypeFloat: { + auto [ min, max, def ] = control_info_to_range(cinfo); + + spa_pod_builder_add(&b, + SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Float( + def, min, max), + 0); + break; + } + case ControlTypeInteger32: { + auto [ min, max, def ] = control_info_to_range(cinfo); + + spa_pod_builder_add(&b, + SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Int( + def, min, max), + 0); + break; + } + default: + return nullptr; + } + } + else { spa_pod_frame f; spa_pod_builder_prop(&b, SPA_PROP_INFO_type, 0); spa_pod_builder_push_choice(&b, &f, SPA_CHOICE_Enum, 0); - spa_pod_builder_bool(&b, def); - spa_pod_builder_bool(&b, min); - if (max != min) - spa_pod_builder_bool(&b, max); + + if (!control_value_to_pod(b, cinfo.def())) + return nullptr; + + for (const auto& cv : cinfo.values()) { + if (!control_value_to_pod(b, cv)) + return nullptr; + } + spa_pod_builder_pop(&b, &f); - } break; - case ControlTypeFloat: { - auto [ min, max, def ] = control_info_to_range(cinfo); - - spa_pod_builder_add(&b, - SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Float( - def, min, max), - 0); - } break; - case ControlTypeInteger32: { - auto [ min, max, def ] = control_info_to_range(cinfo); - - spa_pod_builder_add(&b, - SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Int( - def, min, max), - 0); - } break; - default: - return nullptr; } return reinterpret_cast(spa_pod_builder_pop(&b, &f));