[libcamera-devel] [PATCH v3 3/5] libcamera: control_serializer: Use the right idmap
Jacopo Mondi
jacopo at jmondi.org
Mon Sep 27 14:35:34 CEST 2021
Hi Laurent,
On Sun, Sep 26, 2021 at 10:56:52PM +0300, Laurent Pinchart wrote:
> Hi Jacopo,
>
> Thank you for the patch.
>
> On Fri, Sep 24, 2021 at 07:25:23PM +0200, Jacopo Mondi wrote:
> > When a ControlList is deserialized, the code searches for a valid
> > ControlInfoMap in the local cache and use its id map to initialize the
> > list. If no valid ControlInfoMap is found, as it's usually the case
> > for lists transporting libcamera controls and properties, the globally
> > defined controls::controls id map is used unconditionally.
> >
> > This breaks the deserialization of libcamera properties, for which a
> > wrong idmap is used at construction time.
> >
> > As the serialization header now transports an id_map_type field, store
> > the idmap type at serialization time, and re-use it at
> > deserialization time to identify the correct id map.
> >
> > Also make the validation stricter by imposing to list of V4L2 controls to
> > have an associated ControlInfoMap available, as there is no globally
> > defined idmap for such controls.
> >
> > To be able to retrieve the idmap associated with a ControlList, add an
> > accessor function to the ControlList class.
> >
> > It might be worth in future using a ControlInfoMap to initialize the
> > deserialized ControlList to implement controls validation against their
> > limit. As such validation is not implemented at the moment, maintain the
> > current behaviour and initialize the control list with an idmap.
> >
> > Signed-off-by: Jacopo Mondi <jacopo at jmondi.org>
> > Reviewed-by: Paul Elder <paul.elder at ideasonboard.com>
> > Reviewed-by: Kieran Bingham <kieran.bingham at ideasonboard.com>
> > ---
> > include/libcamera/controls.h | 1 +
> > src/libcamera/control_serializer.cpp | 51 +++++++++++++++++++++++-----
> > src/libcamera/controls.cpp | 8 +++++
> > 3 files changed, 51 insertions(+), 9 deletions(-)
> >
> > diff --git a/include/libcamera/controls.h b/include/libcamera/controls.h
> > index b3590fdb93ec..af851b4661c8 100644
> > --- a/include/libcamera/controls.h
> > +++ b/include/libcamera/controls.h
> > @@ -407,6 +407,7 @@ public:
> > void set(unsigned int id, const ControlValue &value);
> >
> > const ControlInfoMap *infoMap() const { return infoMap_; }
> > + const ControlIdMap *idMap() const { return idmap_; }
> >
> > private:
> > const ControlValue *find(unsigned int id) const;
> > diff --git a/src/libcamera/control_serializer.cpp b/src/libcamera/control_serializer.cpp
> > index 27360526f9eb..d42840cddecb 100644
> > --- a/src/libcamera/control_serializer.cpp
> > +++ b/src/libcamera/control_serializer.cpp
> > @@ -275,6 +275,15 @@ int ControlSerializer::serialize(const ControlList &list,
> > infoMapHandle = 0;
> > }
> >
> > + const ControlIdMap *idmap = list.idMap();
> > + enum ipa_controls_id_map_type idMapType;
> > + if (idmap == &controls::controls)
> > + idMapType = IPA_CONTROL_ID_MAP_CONTROLS;
> > + else if (idmap == &properties::properties)
> > + idMapType = IPA_CONTROL_ID_MAP_PROPERTIES;
> > + else
> > + idMapType = IPA_CONTROL_ID_MAP_V4L2;
> > +
> > size_t entriesSize = list.size() * sizeof(struct ipa_control_value_entry);
> > size_t valuesSize = 0;
> > for (const auto &ctrl : list)
> > @@ -287,6 +296,7 @@ int ControlSerializer::serialize(const ControlList &list,
> > hdr.entries = list.size();
> > hdr.size = sizeof(hdr) + entriesSize + valuesSize;
> > hdr.data_offset = sizeof(hdr) + entriesSize;
> > + hdr.id_map_type = idMapType;
> >
> > buffer.write(&hdr);
> >
> > @@ -496,13 +506,15 @@ ControlList ControlSerializer::deserialize<ControlList>(ByteStreamBuffer &buffer
> > }
> >
> > /*
> > - * Retrieve the ControlInfoMap associated with the ControlList based on
> > - * its ID. The mapping between infoMap and ID is set up when serializing
> > - * or deserializing ControlInfoMap. If no mapping is found (which is
> > - * currently the case for ControlList related to libcamera controls),
> > - * use the global control::control idmap.
> > + * Retrieve the ControlIdMap associated with the ControlList.
> > + *
> > + * The idmap is either retrieved from the list's ControlInfoMap when
> > + * a valid handle has been initialized at serialization time, or by
> > + * using the header's id_map_type field for lists that refer to the
> > + * globally defined libcamera controls and properties, for which no
> > + * ControlInfoMap is available.
> > */
> > - const ControlInfoMap *infoMap;
> > + const ControlIdMap *idMap;
> > if (hdr->handle) {
> > auto iter = std::find_if(infoMapHandles_.begin(), infoMapHandles_.end(),
> > [&](decltype(infoMapHandles_)::value_type &entry) {
> > @@ -514,12 +526,33 @@ ControlList ControlSerializer::deserialize<ControlList>(ByteStreamBuffer &buffer
> > return {};
> > }
> >
> > - infoMap = iter->first;
> > + const ControlInfoMap *infoMap = iter->first;
> > + idMap = &infoMap->idmap();
> > + ASSERT(idMap);
>
> A reference can't be null, that would be an undefined behaviour. The
Ah, right, we return a reference by dereferencing the idmap_ pointer
unconditionally in ControlInfoMap
const ControlIdMap &idmap() const { return *idmap_; }
If idmap_ happens to be nullptr we'll have issues and the above ASSERT
clearly can't help. I'll drop it, thanks for spotting!
> compiler can skip the assert here. If you're concerned that
> ControlInfoMap::idmap_ may be null when ControlInfoMap::idmap() is
> called, the assert should go to ControlInfoMap::idmap().
>
> > } else {
> > - infoMap = nullptr;
> > + switch (hdr->id_map_type) {
> > + case IPA_CONTROL_ID_MAP_CONTROLS:
> > + idMap = &controls::controls;
> > + break;
> > +
> > + case IPA_CONTROL_ID_MAP_PROPERTIES:
> > + idMap = &properties::properties;
> > + break;
> > +
> > + case IPA_CONTROL_ID_MAP_V4L2:
> > + LOG(Serializer, Fatal)
> > + << "A list of V4L2 controls requires an ControlInfoMap";
> > + return {};
> > + }
> > }
> >
> > - ControlList ctrls(infoMap ? infoMap->idmap() : controls::controls);
> > + /*
> > + * \todo When available, initialize the list with the ControlInfoMap
> > + * so that controls can be validated against their limits.
> > + * Currently no validation is performed, so it's fine relying on the
> > + * idmap only.
> > + */
> > + ControlList ctrls(*idMap);
> >
> > for (unsigned int i = 0; i < hdr->entries; ++i) {
> > const struct ipa_control_value_entry *entry =
> > diff --git a/src/libcamera/controls.cpp b/src/libcamera/controls.cpp
> > index 55eec71ffe35..d23eff9e2728 100644
> > --- a/src/libcamera/controls.cpp
> > +++ b/src/libcamera/controls.cpp
> > @@ -1040,6 +1040,14 @@ void ControlList::set(unsigned int id, const ControlValue &value)
> > * associated ControlInfoMap, nullptr is returned in that case.
> > */
> >
> > +/**
> > + * \fn ControlList::idMap()
> > + * \brief Retrieve the ControlId map used to construct the ControlList
> > + * \return The ControlId map used to construct the ControlList. ControlsList
>
> s/ControlsList/ControlList/
>
> > + * instances constructed with ControlList() have no associated idmap, nullptr is
>
> s/ControlList()/the default constructor/
>
> Reviewed-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
>
> > + * returned in that case.
> > + */
> > +
> > const ControlValue *ControlList::find(unsigned int id) const
> > {
> > const auto iter = controls_.find(id);
>
> --
> Regards,
>
> Laurent Pinchart
More information about the libcamera-devel
mailing list