Skip to content

Commit 321002f

Browse files
committed
libcamera: parse arrays for options
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: - #170 - #172 - #176
1 parent 5e68944 commit 321002f

File tree

1 file changed

+70
-51
lines changed

1 file changed

+70
-51
lines changed

device/libcamera/options.cc

Lines changed: 70 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,13 @@ static std::set<const libcamera::ControlId *> ignored_controls =
7373

7474
static auto control_type_values = control_enum_values<libcamera::ControlType>("ControlType");
7575

76+
#if LIBCAMERA_VERSION_MAJOR == 0 && LIBCAMERA_VERSION_MINOR < 4
77+
// Not supported before 0.4.0
78+
#define CONTROL_ID_IS_ARRAY(ctrl) (false)
79+
#else
80+
#define CONTROL_ID_IS_ARRAY(ctrl) (ctrl)->isArray()
81+
#endif
82+
7683
static const std::map<unsigned, std::string> *libcamera_find_control_ids(unsigned control_id)
7784
{
7885
auto iter = libcamera_control_ids.find(control_id);
@@ -82,17 +89,20 @@ static const std::map<unsigned, std::string> *libcamera_find_control_ids(unsigne
8289
return &iter->second.enum_values;
8390
}
8491

85-
static long long libcamera_find_control_id_named_value(unsigned control_id, const char *name)
92+
static std::pair<long long, const char*> libcamera_find_control_id_named_value(unsigned control_id, const char *value)
8693
{
8794
auto named_values = libcamera_find_control_ids(control_id);
8895
if (named_values) {
8996
for (const auto & named_value : *named_values) {
90-
if (device_option_is_equal(named_value.second.c_str(), name))
91-
return named_value.first;
97+
if (device_option_is_equal(named_value.second.c_str(), value)) {
98+
return std::make_pair(named_value.first, value + named_value.second.length());
99+
}
92100
}
93101
}
94102

95-
return strtoll(name, NULL, 10);
103+
char *endptr = NULL;
104+
auto res = strtoll(value, &endptr, 10);
105+
return std::make_pair(res, endptr);
96106
}
97107

98108
static libcamera::ControlInfoMap::Map libcamera_control_list(device_t *dev)
@@ -140,9 +150,10 @@ void libcamera_device_dump_options(device_t *dev, FILE *stream)
140150
auto control_key = libcamera_device_option_normalize(control_id->name());
141151
auto control_info = control.second;
142152

143-
fprintf(stream, "- available option: %s (%08x, type=%s): %s\n",
153+
fprintf(stream, "- available option: %s (%08x, type=%s%s): %s\n",
144154
control_id->name().c_str(), control_id->id(),
145155
control_type_values[control_id->type()].c_str(),
156+
CONTROL_ID_IS_ARRAY(control_id) ? " Array" : "",
146157
control_info.toString().c_str());
147158

148159
auto named_values = libcamera_find_control_ids(control_id->id());
@@ -321,101 +332,105 @@ int libcamera_device_dump_options2(device_t *dev, device_option_fn fn, void *opa
321332
return n;
322333
}
323334

324-
static libcamera::Rectangle libcamera_parse_rectangle(const char *value)
335+
static std::pair<float, const char*> libcamera_parse_float(const char *value)
336+
{
337+
char *endptr = NULL;
338+
auto res = strtof(value, &endptr);
339+
return std::make_pair(res, endptr);
340+
}
341+
342+
static std::pair<libcamera::Rectangle, const char*> libcamera_parse_rectangle(const char *value)
325343
{
326344
static const char *RECTANGLE_PATTERNS[] =
327345
{
328-
"(%d,%d)/%ux%u",
329-
"%d,%d,%u,%u",
346+
"(%d,%d)/%ux%u%n",
347+
"%d,%d,%u,%u%n",
330348
NULL
331349
};
332350

333351
for (int i = 0; RECTANGLE_PATTERNS[i]; i++) {
334352
libcamera::Rectangle rectangle;
353+
int read = 0;
335354

336355
if (4 == sscanf(value, RECTANGLE_PATTERNS[i],
337356
&rectangle.x, &rectangle.y,
338-
&rectangle.width, &rectangle.height)) {
339-
return rectangle;
357+
&rectangle.width, &rectangle.height, &read)) {
358+
return std::make_pair(rectangle, value + read);
340359
}
341360
}
342361

343-
return libcamera::Rectangle();
362+
return std::make_pair(libcamera::Rectangle(), (const char*)NULL);
344363
}
345364

346-
static libcamera::Size libcamera_parse_size(const char *value)
365+
static std::pair<libcamera::Size, const char*> libcamera_parse_size(const char *value)
347366
{
348367
static const char *SIZE_PATTERNS[] =
349368
{
350-
"%ux%u",
351-
"%u,%u",
369+
"%ux%u%n",
370+
"%u,%u%n",
352371
NULL
353372
};
354373

355374
for (int i = 0; SIZE_PATTERNS[i]; i++) {
356375
libcamera::Size size;
376+
int read = 0;
357377

358-
if (2 == sscanf(value, SIZE_PATTERNS[i], &size.width, &size.height)) {
359-
return size;
378+
if (2 == sscanf(value, SIZE_PATTERNS[i], &size.width, &size.height, &read)) {
379+
return std::make_pair(size, value + read);
360380
}
361381
}
362382

363-
return libcamera::Size();
383+
return std::make_pair(libcamera::Size(), (const char*)NULL);
364384
}
365385

366386
#if LIBCAMERA_VERSION_MAJOR == 0 && LIBCAMERA_VERSION_MINOR > 3 && LIBCAMERA_VERSION_PATCH >= 2 // Support for older libcamera versions
367387
static libcamera::Point libcamera_parse_point(const char *value)
368388
{
369389
static const char *POINT_PATTERNS[] =
370390
{
371-
"(%d,%d)",
372-
"%d,%d",
391+
"(%d,%d)%n",
392+
"%d,%d%n",
373393
NULL
374394
};
375395

376396
for (int i = 0; POINT_PATTERNS[i]; i++) {
377397
libcamera::Point point;
398+
int read = 0;
378399

379400
if (2 == sscanf(value, POINT_PATTERNS[i],
380-
&point.x, &point.y)) {
381-
return point;
401+
&point.x, &point.y, &read)) {
402+
return std::make_pair(point, value + read);
382403
}
383404
}
384405

385-
return libcamera::Point();
406+
return std::make_pair(libcamera::Point(), NULL);
386407
}
387408
#endif
388409

389410
template<typename T, typename F>
390-
static bool libcamera_parse_control_value(libcamera::ControlValue &control_value, const char *value, const F &fn)
411+
static bool libcamera_parse_control_value(libcamera::ControlValue &control_value, bool control_array, const char *value, const F& fn)
391412
{
392-
std::vector<T> parsed;
413+
std::vector<T> items;
393414

394415
while (value && *value) {
395-
std::string current_value;
396-
397-
if (const char *next = strchr(value, ',')) {
398-
current_value.assign(value, next);
399-
value = &next[1];
400-
} else {
401-
current_value.assign(value);
402-
value = NULL;
403-
}
404-
405-
if (current_value.empty())
406-
continue;
407-
408-
parsed.push_back(fn(current_value.c_str()));
416+
auto [item, next] = fn(value);
417+
if (!next)
418+
return false; // failed to parse
419+
items.push_back(item);
420+
421+
if (!*next)
422+
break; // reached end of elements
423+
if (*next != ',')
424+
return false; // expected comma to split items
425+
value = ++next;
409426
}
410427

411-
if (parsed.empty()) {
428+
if (items.empty()) {
412429
return false;
413-
}
414-
415-
if (parsed.size() > 1) {
416-
control_value.set<libcamera::Span<T> >(parsed);
430+
} else if (control_array) {
431+
control_value.set<libcamera::Span<T> >(items);
417432
} else {
418-
control_value.set<T>(parsed[0]);
433+
control_value.set<T>(items[0]);
419434
}
420435

421436
return true;
@@ -433,42 +448,46 @@ int libcamera_device_set_option(device_t *dev, const char *keyp, const char *val
433448
continue;
434449

435450
libcamera::ControlValue control_value;
451+
bool control_array = CONTROL_ID_IS_ARRAY(control_id);
436452

437453
switch (control_id->type()) {
438454
case libcamera::ControlTypeNone:
439455
break;
440456

441457
case libcamera::ControlTypeBool:
458+
if (control_array) {
459+
throw std::runtime_error("Array ControlType for boolean is not supported");
460+
}
442461
control_value.set<bool>(atoi(value));
443462
break;
444463

445464
case libcamera::ControlTypeByte:
446-
libcamera_parse_control_value<unsigned char>(control_value, value,
465+
libcamera_parse_control_value<unsigned char>(control_value, control_array, value,
447466
[control_id](const char *value) { return libcamera_find_control_id_named_value(control_id->id(), value); });
448467
break;
449468

450469
case libcamera::ControlTypeInteger32:
451-
libcamera_parse_control_value<int32_t>(control_value, value,
470+
libcamera_parse_control_value<int32_t>(control_value, control_array, value,
452471
[control_id](const char *value) { return libcamera_find_control_id_named_value(control_id->id(), value); });
453472
break;
454473

455474
case libcamera::ControlTypeInteger64:
456-
libcamera_parse_control_value<int64_t>(control_value, value,
475+
libcamera_parse_control_value<int64_t>(control_value, control_array, value,
457476
[control_id](const char *value) { return libcamera_find_control_id_named_value(control_id->id(), value); });
458477
break;
459478

460479
case libcamera::ControlTypeFloat:
461-
libcamera_parse_control_value<float>(control_value, value, atof);
480+
libcamera_parse_control_value<float>(control_value, control_array, value, libcamera_parse_float);
462481
break;
463482

464483
case libcamera::ControlTypeRectangle:
465484
libcamera_parse_control_value<libcamera::Rectangle>(
466-
control_value, value, libcamera_parse_rectangle);
485+
control_value, control_array, value, libcamera_parse_rectangle);
467486
break;
468487

469488
case libcamera::ControlTypeSize:
470489
libcamera_parse_control_value<libcamera::Size>(
471-
control_value, value, libcamera_parse_size);
490+
control_value, control_array, value, libcamera_parse_size);
472491
break;
473492

474493
case libcamera::ControlTypeString:
@@ -477,7 +496,7 @@ int libcamera_device_set_option(device_t *dev, const char *keyp, const char *val
477496
#if LIBCAMERA_VERSION_MAJOR == 0 && LIBCAMERA_VERSION_MINOR > 3 && LIBCAMERA_VERSION_PATCH >= 2 // Support for older libcamera versions
478497
case libcamera::ControlTypePoint:
479498
libcamera_parse_control_value<libcamera::Point>(
480-
control_value, value, libcamera_parse_point);
499+
control_value, control_array, value, libcamera_parse_point);
481500
break;
482501
#endif
483502

0 commit comments

Comments
 (0)