mirror of
https://git.libcamera.org/libcamera/libcamera.git
synced 2025-07-13 15:29:45 +03:00
libcamera: v4l2_device: Workaround faulty control menus
Some UVC cameras have been identified that can provide V4L2 menu controls without any menu items. This leads to a segfault where we try to construct a ControlInfo(Span<>,default) with an empty span. Convert the v4l2ControlInfo and v4l2MenuControlInfo helper functions to return std::optional<ControlInfo> to be able to account in the caller if the control is valid, and only add acceptable controls to the supported control list. Menu controls without a list of menu items are no longer added as a valid control and a warning is logged. This also fixes a potential crash that would have occured in the unlikely event that a ctrl.minimum was set to less than 0. Bug: https://bugs.libcamera.org/show_bug.cgi?id=167 Reported-by: Marian Buschsieweke <marian.buschsieweke@ovgu.de> Reviewed-by: Jacopo Mondi <jacopo@jmondi.org> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
This commit is contained in:
parent
1cd7646f97
commit
96ed45b971
2 changed files with 25 additions and 7 deletions
|
@ -70,8 +70,8 @@ protected:
|
||||||
private:
|
private:
|
||||||
static ControlType v4l2CtrlType(uint32_t ctrlType);
|
static ControlType v4l2CtrlType(uint32_t ctrlType);
|
||||||
static std::unique_ptr<ControlId> v4l2ControlId(const v4l2_query_ext_ctrl &ctrl);
|
static std::unique_ptr<ControlId> v4l2ControlId(const v4l2_query_ext_ctrl &ctrl);
|
||||||
ControlInfo v4l2ControlInfo(const v4l2_query_ext_ctrl &ctrl);
|
std::optional<ControlInfo> v4l2ControlInfo(const v4l2_query_ext_ctrl &ctrl);
|
||||||
ControlInfo v4l2MenuControlInfo(const v4l2_query_ext_ctrl &ctrl);
|
std::optional<ControlInfo> v4l2MenuControlInfo(const v4l2_query_ext_ctrl &ctrl);
|
||||||
|
|
||||||
void listControls();
|
void listControls();
|
||||||
void updateControls(ControlList *ctrls,
|
void updateControls(ControlList *ctrls,
|
||||||
|
|
|
@ -529,7 +529,7 @@ std::unique_ptr<ControlId> V4L2Device::v4l2ControlId(const v4l2_query_ext_ctrl &
|
||||||
* \param[in] ctrl The v4l2_query_ext_ctrl that represents a V4L2 control
|
* \param[in] ctrl The v4l2_query_ext_ctrl that represents a V4L2 control
|
||||||
* \return A ControlInfo that represents \a ctrl
|
* \return A ControlInfo that represents \a ctrl
|
||||||
*/
|
*/
|
||||||
ControlInfo V4L2Device::v4l2ControlInfo(const v4l2_query_ext_ctrl &ctrl)
|
std::optional<ControlInfo> V4L2Device::v4l2ControlInfo(const v4l2_query_ext_ctrl &ctrl)
|
||||||
{
|
{
|
||||||
switch (ctrl.type) {
|
switch (ctrl.type) {
|
||||||
case V4L2_CTRL_TYPE_U8:
|
case V4L2_CTRL_TYPE_U8:
|
||||||
|
@ -566,14 +566,14 @@ ControlInfo V4L2Device::v4l2ControlInfo(const v4l2_query_ext_ctrl &ctrl)
|
||||||
*
|
*
|
||||||
* \return A ControlInfo that represents \a ctrl
|
* \return A ControlInfo that represents \a ctrl
|
||||||
*/
|
*/
|
||||||
ControlInfo V4L2Device::v4l2MenuControlInfo(const struct v4l2_query_ext_ctrl &ctrl)
|
std::optional<ControlInfo> V4L2Device::v4l2MenuControlInfo(const struct v4l2_query_ext_ctrl &ctrl)
|
||||||
{
|
{
|
||||||
std::vector<ControlValue> indices;
|
std::vector<ControlValue> indices;
|
||||||
struct v4l2_querymenu menu = {};
|
struct v4l2_querymenu menu = {};
|
||||||
menu.id = ctrl.id;
|
menu.id = ctrl.id;
|
||||||
|
|
||||||
if (ctrl.minimum < 0)
|
if (ctrl.minimum < 0)
|
||||||
return ControlInfo();
|
return std::nullopt;
|
||||||
|
|
||||||
for (int32_t index = ctrl.minimum; index <= ctrl.maximum; ++index) {
|
for (int32_t index = ctrl.minimum; index <= ctrl.maximum; ++index) {
|
||||||
menu.index = index;
|
menu.index = index;
|
||||||
|
@ -583,6 +583,14 @@ ControlInfo V4L2Device::v4l2MenuControlInfo(const struct v4l2_query_ext_ctrl &ct
|
||||||
indices.push_back(index);
|
indices.push_back(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Some faulty UVC devices are known to return an empty menu control.
|
||||||
|
* Controls without a menu option can not be set, or read, so they are
|
||||||
|
* not exposed.
|
||||||
|
*/
|
||||||
|
if (indices.size() == 0)
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
return ControlInfo(indices,
|
return ControlInfo(indices,
|
||||||
ControlValue(static_cast<int32_t>(ctrl.default_value)));
|
ControlValue(static_cast<int32_t>(ctrl.default_value)));
|
||||||
}
|
}
|
||||||
|
@ -631,7 +639,17 @@ void V4L2Device::listControls()
|
||||||
controlIdMap_[ctrl.id] = controlIds_.back().get();
|
controlIdMap_[ctrl.id] = controlIds_.back().get();
|
||||||
controlInfo_.emplace(ctrl.id, ctrl);
|
controlInfo_.emplace(ctrl.id, ctrl);
|
||||||
|
|
||||||
ctrls.emplace(controlIds_.back().get(), v4l2ControlInfo(ctrl));
|
std::optional<ControlInfo> info = v4l2ControlInfo(ctrl);
|
||||||
|
|
||||||
|
if (!info) {
|
||||||
|
LOG(V4L2, Error)
|
||||||
|
<< "Control " << ctrl.name
|
||||||
|
<< " cannot be registered";
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctrls.emplace(controlIds_.back().get(), *info);
|
||||||
}
|
}
|
||||||
|
|
||||||
controls_ = ControlInfoMap(std::move(ctrls), controlIdMap_);
|
controls_ = ControlInfoMap(std::move(ctrls), controlIdMap_);
|
||||||
|
@ -670,7 +688,7 @@ void V4L2Device::updateControlInfo()
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
info = v4l2ControlInfo(ctrl);
|
info = *v4l2ControlInfo(ctrl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue