mirror of
https://github.com/andreili/camera-streamer.git
synced 2025-08-23 19:34:07 +02:00
libcamera: parse arrays for options (#180)
This does that by trying to parse value, and then advancing pointer. It checks if the string ends or is split by comma. With collaboration from @arekm. Take a look at: - https://github.com/ayufan/camera-streamer/pull/170 - https://github.com/ayufan/camera-streamer/pull/172 - https://github.com/ayufan/camera-streamer/pull/176
This commit is contained in:
parent
5e689449d4
commit
9379ffde78
@ -73,6 +73,13 @@ static std::set<const libcamera::ControlId *> ignored_controls =
|
|||||||
|
|
||||||
static auto control_type_values = control_enum_values<libcamera::ControlType>("ControlType");
|
static auto control_type_values = control_enum_values<libcamera::ControlType>("ControlType");
|
||||||
|
|
||||||
|
#if LIBCAMERA_VERSION_MAJOR == 0 && LIBCAMERA_VERSION_MINOR < 4
|
||||||
|
// Not supported before 0.4.0
|
||||||
|
#define CONTROL_ID_IS_ARRAY(ctrl) (false)
|
||||||
|
#else
|
||||||
|
#define CONTROL_ID_IS_ARRAY(ctrl) (ctrl)->isArray()
|
||||||
|
#endif
|
||||||
|
|
||||||
static const std::map<unsigned, std::string> *libcamera_find_control_ids(unsigned control_id)
|
static const std::map<unsigned, std::string> *libcamera_find_control_ids(unsigned control_id)
|
||||||
{
|
{
|
||||||
auto iter = libcamera_control_ids.find(control_id);
|
auto iter = libcamera_control_ids.find(control_id);
|
||||||
@ -82,17 +89,20 @@ static const std::map<unsigned, std::string> *libcamera_find_control_ids(unsigne
|
|||||||
return &iter->second.enum_values;
|
return &iter->second.enum_values;
|
||||||
}
|
}
|
||||||
|
|
||||||
static long long libcamera_find_control_id_named_value(unsigned control_id, const char *name)
|
static std::pair<long long, const char*> libcamera_find_control_id_named_value(unsigned control_id, const char *value)
|
||||||
{
|
{
|
||||||
auto named_values = libcamera_find_control_ids(control_id);
|
auto named_values = libcamera_find_control_ids(control_id);
|
||||||
if (named_values) {
|
if (named_values) {
|
||||||
for (const auto & named_value : *named_values) {
|
for (const auto & named_value : *named_values) {
|
||||||
if (device_option_is_equal(named_value.second.c_str(), name))
|
if (device_option_is_equal(named_value.second.c_str(), value)) {
|
||||||
return named_value.first;
|
return std::make_pair(named_value.first, value + named_value.second.length());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return strtoll(name, NULL, 10);
|
char *endptr = NULL;
|
||||||
|
auto res = strtoll(value, &endptr, 10);
|
||||||
|
return std::make_pair(res, endptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static libcamera::ControlInfoMap::Map libcamera_control_list(device_t *dev)
|
static libcamera::ControlInfoMap::Map libcamera_control_list(device_t *dev)
|
||||||
@ -140,9 +150,10 @@ void libcamera_device_dump_options(device_t *dev, FILE *stream)
|
|||||||
auto control_key = libcamera_device_option_normalize(control_id->name());
|
auto control_key = libcamera_device_option_normalize(control_id->name());
|
||||||
auto control_info = control.second;
|
auto control_info = control.second;
|
||||||
|
|
||||||
fprintf(stream, "- available option: %s (%08x, type=%s): %s\n",
|
fprintf(stream, "- available option: %s (%08x, type=%s%s): %s\n",
|
||||||
control_id->name().c_str(), control_id->id(),
|
control_id->name().c_str(), control_id->id(),
|
||||||
control_type_values[control_id->type()].c_str(),
|
control_type_values[control_id->type()].c_str(),
|
||||||
|
CONTROL_ID_IS_ARRAY(control_id) ? " Array" : "",
|
||||||
control_info.toString().c_str());
|
control_info.toString().c_str());
|
||||||
|
|
||||||
auto named_values = libcamera_find_control_ids(control_id->id());
|
auto named_values = libcamera_find_control_ids(control_id->id());
|
||||||
@ -321,46 +332,55 @@ int libcamera_device_dump_options2(device_t *dev, device_option_fn fn, void *opa
|
|||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
static libcamera::Rectangle libcamera_parse_rectangle(const char *value)
|
static std::pair<float, const char*> libcamera_parse_float(const char *value)
|
||||||
|
{
|
||||||
|
char *endptr = NULL;
|
||||||
|
auto res = strtof(value, &endptr);
|
||||||
|
return std::make_pair(res, endptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::pair<libcamera::Rectangle, const char*> libcamera_parse_rectangle(const char *value)
|
||||||
{
|
{
|
||||||
static const char *RECTANGLE_PATTERNS[] =
|
static const char *RECTANGLE_PATTERNS[] =
|
||||||
{
|
{
|
||||||
"(%d,%d)/%ux%u",
|
"(%d,%d)/%ux%u%n",
|
||||||
"%d,%d,%u,%u",
|
"%d,%d,%u,%u%n",
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
for (int i = 0; RECTANGLE_PATTERNS[i]; i++) {
|
for (int i = 0; RECTANGLE_PATTERNS[i]; i++) {
|
||||||
libcamera::Rectangle rectangle;
|
libcamera::Rectangle rectangle;
|
||||||
|
int read = 0;
|
||||||
|
|
||||||
if (4 == sscanf(value, RECTANGLE_PATTERNS[i],
|
if (4 == sscanf(value, RECTANGLE_PATTERNS[i],
|
||||||
&rectangle.x, &rectangle.y,
|
&rectangle.x, &rectangle.y,
|
||||||
&rectangle.width, &rectangle.height)) {
|
&rectangle.width, &rectangle.height, &read)) {
|
||||||
return rectangle;
|
return std::make_pair(rectangle, value + read);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return libcamera::Rectangle();
|
return std::make_pair(libcamera::Rectangle(), (const char*)NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static libcamera::Size libcamera_parse_size(const char *value)
|
static std::pair<libcamera::Size, const char*> libcamera_parse_size(const char *value)
|
||||||
{
|
{
|
||||||
static const char *SIZE_PATTERNS[] =
|
static const char *SIZE_PATTERNS[] =
|
||||||
{
|
{
|
||||||
"%ux%u",
|
"%ux%u%n",
|
||||||
"%u,%u",
|
"%u,%u%n",
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
for (int i = 0; SIZE_PATTERNS[i]; i++) {
|
for (int i = 0; SIZE_PATTERNS[i]; i++) {
|
||||||
libcamera::Size size;
|
libcamera::Size size;
|
||||||
|
int read = 0;
|
||||||
|
|
||||||
if (2 == sscanf(value, SIZE_PATTERNS[i], &size.width, &size.height)) {
|
if (2 == sscanf(value, SIZE_PATTERNS[i], &size.width, &size.height, &read)) {
|
||||||
return size;
|
return std::make_pair(size, value + read);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return libcamera::Size();
|
return std::make_pair(libcamera::Size(), (const char*)NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if LIBCAMERA_VERSION_MAJOR == 0 && LIBCAMERA_VERSION_MINOR > 3 && LIBCAMERA_VERSION_PATCH >= 2 // Support for older libcamera versions
|
#if LIBCAMERA_VERSION_MAJOR == 0 && LIBCAMERA_VERSION_MINOR > 3 && LIBCAMERA_VERSION_PATCH >= 2 // Support for older libcamera versions
|
||||||
@ -368,54 +388,49 @@ static libcamera::Point libcamera_parse_point(const char *value)
|
|||||||
{
|
{
|
||||||
static const char *POINT_PATTERNS[] =
|
static const char *POINT_PATTERNS[] =
|
||||||
{
|
{
|
||||||
"(%d,%d)",
|
"(%d,%d)%n",
|
||||||
"%d,%d",
|
"%d,%d%n",
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
for (int i = 0; POINT_PATTERNS[i]; i++) {
|
for (int i = 0; POINT_PATTERNS[i]; i++) {
|
||||||
libcamera::Point point;
|
libcamera::Point point;
|
||||||
|
int read = 0;
|
||||||
|
|
||||||
if (2 == sscanf(value, POINT_PATTERNS[i],
|
if (2 == sscanf(value, POINT_PATTERNS[i],
|
||||||
&point.x, &point.y)) {
|
&point.x, &point.y, &read)) {
|
||||||
return point;
|
return std::make_pair(point, value + read);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return libcamera::Point();
|
return std::make_pair(libcamera::Point(), NULL);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
template<typename T, typename F>
|
template<typename T, typename F>
|
||||||
static bool libcamera_parse_control_value(libcamera::ControlValue &control_value, const char *value, const F &fn)
|
static bool libcamera_parse_control_value(libcamera::ControlValue &control_value, bool control_array, const char *value, const F& fn)
|
||||||
{
|
{
|
||||||
std::vector<T> parsed;
|
std::vector<T> items;
|
||||||
|
|
||||||
while (value && *value) {
|
while (value && *value) {
|
||||||
std::string current_value;
|
auto [item, next] = fn(value);
|
||||||
|
if (!next)
|
||||||
|
return false; // failed to parse
|
||||||
|
items.push_back(item);
|
||||||
|
|
||||||
if (const char *next = strchr(value, ',')) {
|
if (!*next)
|
||||||
current_value.assign(value, next);
|
break; // reached end of elements
|
||||||
value = &next[1];
|
if (*next != ',')
|
||||||
} else {
|
return false; // expected comma to split items
|
||||||
current_value.assign(value);
|
value = ++next;
|
||||||
value = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (current_value.empty())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
parsed.push_back(fn(current_value.c_str()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parsed.empty()) {
|
if (items.empty()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
} else if (control_array) {
|
||||||
|
control_value.set<libcamera::Span<T> >(items);
|
||||||
if (parsed.size() > 1) {
|
|
||||||
control_value.set<libcamera::Span<T> >(parsed);
|
|
||||||
} else {
|
} else {
|
||||||
control_value.set<T>(parsed[0]);
|
control_value.set<T>(items[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -433,42 +448,46 @@ int libcamera_device_set_option(device_t *dev, const char *keyp, const char *val
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
libcamera::ControlValue control_value;
|
libcamera::ControlValue control_value;
|
||||||
|
bool control_array = CONTROL_ID_IS_ARRAY(control_id);
|
||||||
|
|
||||||
switch (control_id->type()) {
|
switch (control_id->type()) {
|
||||||
case libcamera::ControlTypeNone:
|
case libcamera::ControlTypeNone:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case libcamera::ControlTypeBool:
|
case libcamera::ControlTypeBool:
|
||||||
|
if (control_array) {
|
||||||
|
throw std::runtime_error("Array ControlType for boolean is not supported");
|
||||||
|
}
|
||||||
control_value.set<bool>(atoi(value));
|
control_value.set<bool>(atoi(value));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case libcamera::ControlTypeByte:
|
case libcamera::ControlTypeByte:
|
||||||
libcamera_parse_control_value<unsigned char>(control_value, value,
|
libcamera_parse_control_value<unsigned char>(control_value, control_array, value,
|
||||||
[control_id](const char *value) { return libcamera_find_control_id_named_value(control_id->id(), value); });
|
[control_id](const char *value) { return libcamera_find_control_id_named_value(control_id->id(), value); });
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case libcamera::ControlTypeInteger32:
|
case libcamera::ControlTypeInteger32:
|
||||||
libcamera_parse_control_value<int32_t>(control_value, value,
|
libcamera_parse_control_value<int32_t>(control_value, control_array, value,
|
||||||
[control_id](const char *value) { return libcamera_find_control_id_named_value(control_id->id(), value); });
|
[control_id](const char *value) { return libcamera_find_control_id_named_value(control_id->id(), value); });
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case libcamera::ControlTypeInteger64:
|
case libcamera::ControlTypeInteger64:
|
||||||
libcamera_parse_control_value<int64_t>(control_value, value,
|
libcamera_parse_control_value<int64_t>(control_value, control_array, value,
|
||||||
[control_id](const char *value) { return libcamera_find_control_id_named_value(control_id->id(), value); });
|
[control_id](const char *value) { return libcamera_find_control_id_named_value(control_id->id(), value); });
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case libcamera::ControlTypeFloat:
|
case libcamera::ControlTypeFloat:
|
||||||
libcamera_parse_control_value<float>(control_value, value, atof);
|
libcamera_parse_control_value<float>(control_value, control_array, value, libcamera_parse_float);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case libcamera::ControlTypeRectangle:
|
case libcamera::ControlTypeRectangle:
|
||||||
libcamera_parse_control_value<libcamera::Rectangle>(
|
libcamera_parse_control_value<libcamera::Rectangle>(
|
||||||
control_value, value, libcamera_parse_rectangle);
|
control_value, control_array, value, libcamera_parse_rectangle);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case libcamera::ControlTypeSize:
|
case libcamera::ControlTypeSize:
|
||||||
libcamera_parse_control_value<libcamera::Size>(
|
libcamera_parse_control_value<libcamera::Size>(
|
||||||
control_value, value, libcamera_parse_size);
|
control_value, control_array, value, libcamera_parse_size);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case libcamera::ControlTypeString:
|
case libcamera::ControlTypeString:
|
||||||
@ -477,7 +496,7 @@ int libcamera_device_set_option(device_t *dev, const char *keyp, const char *val
|
|||||||
#if LIBCAMERA_VERSION_MAJOR == 0 && LIBCAMERA_VERSION_MINOR > 3 && LIBCAMERA_VERSION_PATCH >= 2 // Support for older libcamera versions
|
#if LIBCAMERA_VERSION_MAJOR == 0 && LIBCAMERA_VERSION_MINOR > 3 && LIBCAMERA_VERSION_PATCH >= 2 // Support for older libcamera versions
|
||||||
case libcamera::ControlTypePoint:
|
case libcamera::ControlTypePoint:
|
||||||
libcamera_parse_control_value<libcamera::Point>(
|
libcamera_parse_control_value<libcamera::Point>(
|
||||||
control_value, value, libcamera_parse_point);
|
control_value, control_array, value, libcamera_parse_point);
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user