Message ID | 20250721104622.1550908-17-barnabas.pocze@ideasonboard.com |
---|---|
State | New |
Headers | show |
Series |
|
Related | show |
Hi Barnabás On Mon, Jul 21, 2025 at 12:46:16PM +0200, Barnabás Pőcze wrote: > From: Jacopo Mondi <jacopo.mondi@ideasonboard.com> > > Currently the way pipeline handlers have to store metadata results > for a Request is to access the Request::metadata_ list directly and > either merge a ControlList or set a single control value there. > > Direct access to Request::metadata_ is however problematic as even if > metadata would be available earlier, pipeline handlers can only > accumulate the results in Request::metadata_ and they're only available > for applications at Request complete time. > > Instead of letting pipeline handlers access Request::metadata_ directly > provide two helper functions, similar in spirit to > PipelineHandler::completeBuffer() and > PipelineHandler::completeRequest(), to allow pipeline handlers to > notify early availability of metadata. > > Provide three overloads, one that accepts a ControlList and merges it into > Request::metadata_, one that allows to set a single metadata result there > without going through an intermediate copy, and one that runs a callback > for conditional metadata reporting without intermediate an ControlList. > > The newly provided helpers trigger the Camera::availableMetadata signal > from where applications can retrieve the list of controls that have > just been made available by the pipeline handler. > > Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com> > [Fill both lists, use `type_identity`, new overload, adjust commit message.] > Signed-off-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com> > --- > Original: https://patchwork.libcamera.org/patch/22229/ > > changes in v2: > * add new overload that takes an invocable object for more flexibility > --- > include/libcamera/internal/pipeline_handler.h | 49 +++++++++++ > src/libcamera/pipeline_handler.cpp | 84 +++++++++++++++++++ > 2 files changed, 133 insertions(+) > > diff --git a/include/libcamera/internal/pipeline_handler.h b/include/libcamera/internal/pipeline_handler.h > index e89d6a33e..49c907178 100644 > --- a/include/libcamera/internal/pipeline_handler.h > +++ b/include/libcamera/internal/pipeline_handler.h > @@ -7,16 +7,21 @@ > > #pragma once > > +#include <functional> > #include <memory> > #include <string> > #include <sys/types.h> > #include <vector> > > +#include <libcamera/base/details/cxx20.h> > #include <libcamera/base/object.h> > > +#include <libcamera/camera.h> > #include <libcamera/controls.h> > #include <libcamera/stream.h> > > +#include "libcamera/internal/request.h" > + > namespace libcamera { > > class Camera; > @@ -58,6 +63,50 @@ public: > void registerRequest(Request *request); > void queueRequest(Request *request); > > + void metadataAvailable(Request *request, const ControlList &metadata); > + > + template<typename T> > + void metadataAvailable(Request *request, const Control<T> &ctrl, > + const details::cxx20::type_identity_t<T> &value) I presume the usage of type_identity_t<T> is a safety measure to avoid a deduction failure. However I presume T is fully specified and the type of the last argument should match the Control<T> one. Howver I presume this doesn't hurt, and might save some deduction failure ? > + { > + auto &m = request->metadata2(); > + const auto c = m.checkpoint(); > + > + m.set(ctrl, value); > + request->metadata().set(ctrl, value); > + > + const auto d = c.diffSince(); > + if (d) > + request->_d()->camera()->metadataAvailable.emit(request, d); > + } > + > +#ifndef __DOXYGEN__ > + struct MetadataSetter { > + Request *request; > + > + template<typename T> > + void operator()(const Control<T> &ctrl, > + const details::cxx20::type_identity_t<T> &value) const > + { > + request->metadata().set(ctrl, value); > + request->metadata2().set(ctrl, value); > + } > + }; > + > + template<typename Func, std::enable_if_t<std::is_invocable_v<Func&, MetadataSetter>> * = nullptr> > +#else > + template<typename Func> > +#endif > + void metadataAvailable(Request *request, Func func) > + { > + const auto c = request->metadata2().checkpoint(); > + > + std::invoke(func, MetadataSetter{ request }); > + > + if (const auto d = c.diffSince()) > + request->_d()->camera()->metadataAvailable.emit(request, d); > + } > + > bool completeBuffer(Request *request, FrameBuffer *buffer); > void completeRequest(Request *request); > void cancelRequest(Request *request); > diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp > index e5f9e55c9..edfa9cf58 100644 > --- a/src/libcamera/pipeline_handler.cpp > +++ b/src/libcamera/pipeline_handler.cpp > @@ -532,6 +532,90 @@ void PipelineHandler::doQueueRequests(Camera *camera) > * \return 0 on success or a negative error code otherwise > */ > > +/** > + * \brief Signal the availability of metadata for \a request > + * \param[in] request The request the metadata belongs to > + * \param[in] metadata The collection of metadata items > + * > + * This function copies metadata items from \a metadata to the cumulative metadata > + * collection of \a request. This function may be called multiple times, but metadata > + * items already present in Request::metadata() are ignored. Afterwards the function > + * notifies the application by triggering the Camera::availableMetadata signal with > + * the just added metadata items. > + * > + * Early metadata completion allows pipeline handlers to fast track delivery of > + * metadata results as soon as they are available before the completion of \a > + * request. The full list of metadata results of a Request is available at > + * Request completion time in Request::metadata(). > + * > + * \context This function shall be called from the CameraManager thread. > + * > + * \sa PipelineHandler::metadataAvailable(Request *request, Func func) > + * \sa PipelineHandler::metadataAvailable(Request *request, > + * const Control<T> &ctrl, > + * const details::cxx20::type_identity_t<T> &value) > + */ > +void PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata) > +{ > + request->metadata().merge(metadata); > + > + const auto d = request->metadata2().merge(metadata); > + if (d) > + request->_d()->camera()->metadataAvailable.emit(request, d); > +} > + > +/** > + * \fn void PipelineHandler::metadataAvailable(Request *request, const Control<T> &ctrl, > + * const details::cxx20::type_identity_t<T> &value) > + * \copybrief PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata) > + * \param[in] request The request the metadata belongs to > + * \param[in] ctrl The control id of the metadata item > + * \param[in] value The value of the metadata item > + * > + * This function servers the same purpose as PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata) you can break the line as * This function servers the same purpose as * PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata) > + * but it allows a single metadata item to be reported directly, > + * without creating a ControlList. > + * > + * \context This function shall be called from the CameraManager thread. > + * \sa PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata) > + */ > + > +/** > + * \fn void PipelineHandler::metadataAvailable(Request *request, Func func) > + * \copybrief PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata) > + * \param[in] request The request the metadata belongs to > + * \param[in] func The callback to invoke > + * > + * This function serves the same purpose as PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata) ditto > + * but it provides more flexibility for pipeline handlers. This function invokes > + * \a func, which receives as its sole argument an object of unspecified type whose > + * operator() can be used to add metadata items. > + * > + * For example, a PipelineHandler might use this function to conditionally report two > + * metadata items without creating an intermediate ControlList: > + * > + * \code > + metadataAvailable(request, [&](auto set) { > + if (x) > + set(controls::X, x); > + if (y) > + set(controls::Y, y); > + // ... > + }); > + * \endcode Sorry I might be missing the use case here. The call receives a MetadataSetter as 'set' (again auto requires a few levels of indirection just to save a few characters), but I don't get how the pipeline handler should call this, in particular what if (x) if (y) might refer to... What I mean is that pipeline handlers call metadataAvailable in response to events, and they should provide a callback where they inspect 'x' and 'y' which are conditions related to the event that just happened ? > + * > + * The advantage of the above over two calls to PipelineHandler::metadataAvailable(Request *request, const Control<T> &ctrl, const details::cxx20::type_identity_t<T> &value) again line breaks > + * is that the application is only notified once, after \a func has returned. > + * > + * \note Calling any overload of metadataAvailable() inside \a func is not allowed. > + * \note The object passed to \a func is only usable while \a func runs, it must not > + * be saved or reused. > + * > + * \context This function shall be called from the CameraManager thread. > + * > + * \sa PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata) > + */ > + > /** > * \brief Complete a buffer for a request > * \param[in] request The request the buffer belongs to > -- > 2.50.1 >
Hi 2025. 07. 28. 12:08 keltezéssel, Jacopo Mondi írta: > Hi Barnabás > > On Mon, Jul 21, 2025 at 12:46:16PM +0200, Barnabás Pőcze wrote: >> From: Jacopo Mondi <jacopo.mondi@ideasonboard.com> >> >> Currently the way pipeline handlers have to store metadata results >> for a Request is to access the Request::metadata_ list directly and >> either merge a ControlList or set a single control value there. >> >> Direct access to Request::metadata_ is however problematic as even if >> metadata would be available earlier, pipeline handlers can only >> accumulate the results in Request::metadata_ and they're only available >> for applications at Request complete time. >> >> Instead of letting pipeline handlers access Request::metadata_ directly >> provide two helper functions, similar in spirit to >> PipelineHandler::completeBuffer() and >> PipelineHandler::completeRequest(), to allow pipeline handlers to >> notify early availability of metadata. >> >> Provide three overloads, one that accepts a ControlList and merges it into >> Request::metadata_, one that allows to set a single metadata result there >> without going through an intermediate copy, and one that runs a callback >> for conditional metadata reporting without intermediate an ControlList. >> >> The newly provided helpers trigger the Camera::availableMetadata signal >> from where applications can retrieve the list of controls that have >> just been made available by the pipeline handler. >> >> Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com> >> [Fill both lists, use `type_identity`, new overload, adjust commit message.] >> Signed-off-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com> >> --- >> Original: https://patchwork.libcamera.org/patch/22229/ >> >> changes in v2: >> * add new overload that takes an invocable object for more flexibility >> --- >> include/libcamera/internal/pipeline_handler.h | 49 +++++++++++ >> src/libcamera/pipeline_handler.cpp | 84 +++++++++++++++++++ >> 2 files changed, 133 insertions(+) >> >> diff --git a/include/libcamera/internal/pipeline_handler.h b/include/libcamera/internal/pipeline_handler.h >> index e89d6a33e..49c907178 100644 >> --- a/include/libcamera/internal/pipeline_handler.h >> +++ b/include/libcamera/internal/pipeline_handler.h >> @@ -7,16 +7,21 @@ >> >> #pragma once >> >> +#include <functional> >> #include <memory> >> #include <string> >> #include <sys/types.h> >> #include <vector> >> >> +#include <libcamera/base/details/cxx20.h> >> #include <libcamera/base/object.h> >> >> +#include <libcamera/camera.h> >> #include <libcamera/controls.h> >> #include <libcamera/stream.h> >> >> +#include "libcamera/internal/request.h" >> + >> namespace libcamera { >> >> class Camera; >> @@ -58,6 +63,50 @@ public: >> void registerRequest(Request *request); >> void queueRequest(Request *request); >> >> + void metadataAvailable(Request *request, const ControlList &metadata); >> + >> + template<typename T> >> + void metadataAvailable(Request *request, const Control<T> &ctrl, >> + const details::cxx20::type_identity_t<T> &value) > > I presume the usage of type_identity_t<T> is a safety measure to avoid > a deduction failure. However I presume T is fully specified and the > type of the last argument should match the Control<T> one. > > Howver I presume this doesn't hurt, and might save some deduction > failure ? I think it's more of a convenience feature, it allows you to use e.g. initializer lists for the value, e.g. Rectangle *ptr; size_t count; metadataAvailable(controls::rpi::ScalerScrops, { ptr, count }); Rectangle item1, item2, item3; metadataAvailable(controls::rpi::ScalerScrops, {{ item1, item2, item3 }}); It can be dropped if it seems unsuitable for some reason. > >> + { >> + auto &m = request->metadata2(); >> + const auto c = m.checkpoint(); >> + >> + m.set(ctrl, value); >> + request->metadata().set(ctrl, value); >> + >> + const auto d = c.diffSince(); >> + if (d) >> + request->_d()->camera()->metadataAvailable.emit(request, d); >> + } >> + >> +#ifndef __DOXYGEN__ >> + struct MetadataSetter { >> + Request *request; >> + >> + template<typename T> >> + void operator()(const Control<T> &ctrl, >> + const details::cxx20::type_identity_t<T> &value) const >> + { >> + request->metadata().set(ctrl, value); >> + request->metadata2().set(ctrl, value); >> + } >> + }; >> + >> + template<typename Func, std::enable_if_t<std::is_invocable_v<Func&, MetadataSetter>> * = nullptr> >> +#else >> + template<typename Func> >> +#endif >> + void metadataAvailable(Request *request, Func func) >> + { >> + const auto c = request->metadata2().checkpoint(); >> + >> + std::invoke(func, MetadataSetter{ request }); >> + >> + if (const auto d = c.diffSince()) >> + request->_d()->camera()->metadataAvailable.emit(request, d); >> + } >> + >> bool completeBuffer(Request *request, FrameBuffer *buffer); >> void completeRequest(Request *request); >> void cancelRequest(Request *request); >> diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp >> index e5f9e55c9..edfa9cf58 100644 >> --- a/src/libcamera/pipeline_handler.cpp >> +++ b/src/libcamera/pipeline_handler.cpp >> @@ -532,6 +532,90 @@ void PipelineHandler::doQueueRequests(Camera *camera) >> * \return 0 on success or a negative error code otherwise >> */ >> >> +/** >> + * \brief Signal the availability of metadata for \a request >> + * \param[in] request The request the metadata belongs to >> + * \param[in] metadata The collection of metadata items >> + * >> + * This function copies metadata items from \a metadata to the cumulative metadata >> + * collection of \a request. This function may be called multiple times, but metadata >> + * items already present in Request::metadata() are ignored. Afterwards the function >> + * notifies the application by triggering the Camera::availableMetadata signal with >> + * the just added metadata items. >> + * >> + * Early metadata completion allows pipeline handlers to fast track delivery of >> + * metadata results as soon as they are available before the completion of \a >> + * request. The full list of metadata results of a Request is available at >> + * Request completion time in Request::metadata(). >> + * >> + * \context This function shall be called from the CameraManager thread. >> + * >> + * \sa PipelineHandler::metadataAvailable(Request *request, Func func) >> + * \sa PipelineHandler::metadataAvailable(Request *request, >> + * const Control<T> &ctrl, >> + * const details::cxx20::type_identity_t<T> &value) >> + */ >> +void PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata) >> +{ >> + request->metadata().merge(metadata); >> + >> + const auto d = request->metadata2().merge(metadata); >> + if (d) >> + request->_d()->camera()->metadataAvailable.emit(request, d); >> +} >> + >> +/** >> + * \fn void PipelineHandler::metadataAvailable(Request *request, const Control<T> &ctrl, >> + * const details::cxx20::type_identity_t<T> &value) >> + * \copybrief PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata) >> + * \param[in] request The request the metadata belongs to >> + * \param[in] ctrl The control id of the metadata item >> + * \param[in] value The value of the metadata item >> + * >> + * This function servers the same purpose as PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata) > > you can break the line as > > * This function servers the same purpose as > * PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata) ok > > >> + * but it allows a single metadata item to be reported directly, >> + * without creating a ControlList. >> + * >> + * \context This function shall be called from the CameraManager thread. >> + * \sa PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata) >> + */ >> + >> +/** >> + * \fn void PipelineHandler::metadataAvailable(Request *request, Func func) >> + * \copybrief PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata) >> + * \param[in] request The request the metadata belongs to >> + * \param[in] func The callback to invoke >> + * >> + * This function serves the same purpose as PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata) > > ditto ok > >> + * but it provides more flexibility for pipeline handlers. This function invokes >> + * \a func, which receives as its sole argument an object of unspecified type whose >> + * operator() can be used to add metadata items. >> + * >> + * For example, a PipelineHandler might use this function to conditionally report two >> + * metadata items without creating an intermediate ControlList: >> + * >> + * \code >> + metadataAvailable(request, [&](auto set) { >> + if (x) >> + set(controls::X, x); >> + if (y) >> + set(controls::Y, y); >> + // ... >> + }); >> + * \endcode > > Sorry I might be missing the use case here. > > The call receives a MetadataSetter as 'set' (again auto requires a few > levels of indirection just to save a few characters), but I don't get > how the pipeline handler should call this, in particular what > > if (x) > > if (y) > > might refer to... > > What I mean is that pipeline handlers call metadataAvailable in > response to events, and they should provide a callback where they > inspect 'x' and 'y' which are conditions related to the event that > just happened ? I hope that the use case in one of the later patches makes things clearer. I will try to make the example clearer in any case. > >> + * >> + * The advantage of the above over two calls to PipelineHandler::metadataAvailable(Request *request, const Control<T> &ctrl, const details::cxx20::type_identity_t<T> &value) > > again line breaks ok Regards, Barnabás Pőcze > >> + * is that the application is only notified once, after \a func has returned. >> + * >> + * \note Calling any overload of metadataAvailable() inside \a func is not allowed. >> + * \note The object passed to \a func is only usable while \a func runs, it must not >> + * be saved or reused. >> + * >> + * \context This function shall be called from the CameraManager thread. >> + * >> + * \sa PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata) >> + */ >> + >> /** >> * \brief Complete a buffer for a request >> * \param[in] request The request the buffer belongs to >> -- >> 2.50.1 >>
Hi Barnabás On Mon, Jul 28, 2025 at 02:11:27PM +0200, Barnabás Pőcze wrote: > Hi > > 2025. 07. 28. 12:08 keltezéssel, Jacopo Mondi írta: > > Hi Barnabás > > > > On Mon, Jul 21, 2025 at 12:46:16PM +0200, Barnabás Pőcze wrote: > > > From: Jacopo Mondi <jacopo.mondi@ideasonboard.com> > > > > > > Currently the way pipeline handlers have to store metadata results > > > for a Request is to access the Request::metadata_ list directly and > > > either merge a ControlList or set a single control value there. > > > > > > Direct access to Request::metadata_ is however problematic as even if > > > metadata would be available earlier, pipeline handlers can only > > > accumulate the results in Request::metadata_ and they're only available > > > for applications at Request complete time. > > > > > > Instead of letting pipeline handlers access Request::metadata_ directly > > > provide two helper functions, similar in spirit to > > > PipelineHandler::completeBuffer() and > > > PipelineHandler::completeRequest(), to allow pipeline handlers to > > > notify early availability of metadata. > > > > > > Provide three overloads, one that accepts a ControlList and merges it into > > > Request::metadata_, one that allows to set a single metadata result there > > > without going through an intermediate copy, and one that runs a callback > > > for conditional metadata reporting without intermediate an ControlList. > > > > > > The newly provided helpers trigger the Camera::availableMetadata signal > > > from where applications can retrieve the list of controls that have > > > just been made available by the pipeline handler. > > > > > > Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com> > > > [Fill both lists, use `type_identity`, new overload, adjust commit message.] > > > Signed-off-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com> > > > --- > > > Original: https://patchwork.libcamera.org/patch/22229/ > > > > > > changes in v2: > > > * add new overload that takes an invocable object for more flexibility > > > --- > > > include/libcamera/internal/pipeline_handler.h | 49 +++++++++++ > > > src/libcamera/pipeline_handler.cpp | 84 +++++++++++++++++++ > > > 2 files changed, 133 insertions(+) > > > > > > diff --git a/include/libcamera/internal/pipeline_handler.h b/include/libcamera/internal/pipeline_handler.h > > > index e89d6a33e..49c907178 100644 > > > --- a/include/libcamera/internal/pipeline_handler.h > > > +++ b/include/libcamera/internal/pipeline_handler.h > > > @@ -7,16 +7,21 @@ > > > > > > #pragma once > > > > > > +#include <functional> > > > #include <memory> > > > #include <string> > > > #include <sys/types.h> > > > #include <vector> > > > > > > +#include <libcamera/base/details/cxx20.h> > > > #include <libcamera/base/object.h> > > > > > > +#include <libcamera/camera.h> > > > #include <libcamera/controls.h> > > > #include <libcamera/stream.h> > > > > > > +#include "libcamera/internal/request.h" > > > + > > > namespace libcamera { > > > > > > class Camera; > > > @@ -58,6 +63,50 @@ public: > > > void registerRequest(Request *request); > > > void queueRequest(Request *request); > > > > > > + void metadataAvailable(Request *request, const ControlList &metadata); > > > + > > > + template<typename T> > > > + void metadataAvailable(Request *request, const Control<T> &ctrl, > > > + const details::cxx20::type_identity_t<T> &value) > > > > I presume the usage of type_identity_t<T> is a safety measure to avoid > > a deduction failure. However I presume T is fully specified and the > > type of the last argument should match the Control<T> one. > > > > Howver I presume this doesn't hurt, and might save some deduction > > failure ? > > I think it's more of a convenience feature, it allows you to use > e.g. initializer lists for the value, e.g. > > Rectangle *ptr; size_t count; > metadataAvailable(controls::rpi::ScalerScrops, { ptr, count }); > > Rectangle item1, item2, item3; > metadataAvailable(controls::rpi::ScalerScrops, {{ item1, item2, item3 }}); > > It can be dropped if it seems unsuitable for some reason. > No no, I think initializer_lists are a a valid case of non-deduced context where type_identity_t might help. As said it's certainly doesn't hurt, even more if it allows usage of useful features > > > > > > + { > > > + auto &m = request->metadata2(); > > > + const auto c = m.checkpoint(); > > > + > > > + m.set(ctrl, value); > > > + request->metadata().set(ctrl, value); > > > + > > > + const auto d = c.diffSince(); > > > + if (d) > > > + request->_d()->camera()->metadataAvailable.emit(request, d); > > > + } > > > + > > > +#ifndef __DOXYGEN__ > > > + struct MetadataSetter { > > > + Request *request; > > > + > > > + template<typename T> > > > + void operator()(const Control<T> &ctrl, > > > + const details::cxx20::type_identity_t<T> &value) const > > > + { > > > + request->metadata().set(ctrl, value); > > > + request->metadata2().set(ctrl, value); > > > + } > > > + }; > > > + > > > + template<typename Func, std::enable_if_t<std::is_invocable_v<Func&, MetadataSetter>> * = nullptr> > > > +#else > > > + template<typename Func> > > > +#endif > > > + void metadataAvailable(Request *request, Func func) > > > + { > > > + const auto c = request->metadata2().checkpoint(); > > > + > > > + std::invoke(func, MetadataSetter{ request }); > > > + > > > + if (const auto d = c.diffSince()) > > > + request->_d()->camera()->metadataAvailable.emit(request, d); > > > + } > > > + > > > bool completeBuffer(Request *request, FrameBuffer *buffer); > > > void completeRequest(Request *request); > > > void cancelRequest(Request *request); > > > diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp > > > index e5f9e55c9..edfa9cf58 100644 > > > --- a/src/libcamera/pipeline_handler.cpp > > > +++ b/src/libcamera/pipeline_handler.cpp > > > @@ -532,6 +532,90 @@ void PipelineHandler::doQueueRequests(Camera *camera) > > > * \return 0 on success or a negative error code otherwise > > > */ > > > > > > +/** > > > + * \brief Signal the availability of metadata for \a request > > > + * \param[in] request The request the metadata belongs to > > > + * \param[in] metadata The collection of metadata items > > > + * > > > + * This function copies metadata items from \a metadata to the cumulative metadata > > > + * collection of \a request. This function may be called multiple times, but metadata > > > + * items already present in Request::metadata() are ignored. Afterwards the function > > > + * notifies the application by triggering the Camera::availableMetadata signal with > > > + * the just added metadata items. > > > + * > > > + * Early metadata completion allows pipeline handlers to fast track delivery of > > > + * metadata results as soon as they are available before the completion of \a > > > + * request. The full list of metadata results of a Request is available at > > > + * Request completion time in Request::metadata(). > > > + * > > > + * \context This function shall be called from the CameraManager thread. > > > + * > > > + * \sa PipelineHandler::metadataAvailable(Request *request, Func func) > > > + * \sa PipelineHandler::metadataAvailable(Request *request, > > > + * const Control<T> &ctrl, > > > + * const details::cxx20::type_identity_t<T> &value) > > > + */ > > > +void PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata) > > > +{ > > > + request->metadata().merge(metadata); > > > + > > > + const auto d = request->metadata2().merge(metadata); > > > + if (d) > > > + request->_d()->camera()->metadataAvailable.emit(request, d); > > > +} > > > + > > > +/** > > > + * \fn void PipelineHandler::metadataAvailable(Request *request, const Control<T> &ctrl, > > > + * const details::cxx20::type_identity_t<T> &value) > > > + * \copybrief PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata) > > > + * \param[in] request The request the metadata belongs to > > > + * \param[in] ctrl The control id of the metadata item > > > + * \param[in] value The value of the metadata item > > > + * > > > + * This function servers the same purpose as PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata) > > > > you can break the line as > > > > * This function servers the same purpose as > > * PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata) > > ok > > > > > > > > > + * but it allows a single metadata item to be reported directly, > > > + * without creating a ControlList. > > > + * > > > + * \context This function shall be called from the CameraManager thread. > > > + * \sa PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata) > > > + */ > > > + > > > +/** > > > + * \fn void PipelineHandler::metadataAvailable(Request *request, Func func) > > > + * \copybrief PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata) > > > + * \param[in] request The request the metadata belongs to > > > + * \param[in] func The callback to invoke > > > + * > > > + * This function serves the same purpose as PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata) > > > > ditto > > ok > > > > > > > + * but it provides more flexibility for pipeline handlers. This function invokes > > > + * \a func, which receives as its sole argument an object of unspecified type whose > > > + * operator() can be used to add metadata items. > > > + * > > > + * For example, a PipelineHandler might use this function to conditionally report two > > > + * metadata items without creating an intermediate ControlList: > > > + * > > > + * \code > > > + metadataAvailable(request, [&](auto set) { > > > + if (x) > > > + set(controls::X, x); > > > + if (y) > > > + set(controls::Y, y); > > > + // ... > > > + }); > > > + * \endcode > > > > Sorry I might be missing the use case here. > > > > The call receives a MetadataSetter as 'set' (again auto requires a few > > levels of indirection just to save a few characters), but I don't get > > how the pipeline handler should call this, in particular what > > > > if (x) > > > > if (y) > > > > might refer to... > > > > What I mean is that pipeline handlers call metadataAvailable in > > response to events, and they should provide a callback where they > > inspect 'x' and 'y' which are conditions related to the event that > > just happened ? > > I hope that the use case in one of the later patches makes things clearer. Yes sure, let's continue the discussion there Thanks j > I will try to make the example clearer in any case. > > > > > > > + * > > > + * The advantage of the above over two calls to PipelineHandler::metadataAvailable(Request *request, const Control<T> &ctrl, const details::cxx20::type_identity_t<T> &value) > > > > again line breaks > > ok > > > Regards, > Barnabás Pőcze > > > > > > + * is that the application is only notified once, after \a func has returned. > > > + * > > > + * \note Calling any overload of metadataAvailable() inside \a func is not allowed. > > > + * \note The object passed to \a func is only usable while \a func runs, it must not > > > + * be saved or reused. > > > + * > > > + * \context This function shall be called from the CameraManager thread. > > > + * > > > + * \sa PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata) > > > + */ > > > + > > > /** > > > * \brief Complete a buffer for a request > > > * \param[in] request The request the buffer belongs to > > > -- > > > 2.50.1 > > > >
diff --git a/include/libcamera/internal/pipeline_handler.h b/include/libcamera/internal/pipeline_handler.h index e89d6a33e..49c907178 100644 --- a/include/libcamera/internal/pipeline_handler.h +++ b/include/libcamera/internal/pipeline_handler.h @@ -7,16 +7,21 @@ #pragma once +#include <functional> #include <memory> #include <string> #include <sys/types.h> #include <vector> +#include <libcamera/base/details/cxx20.h> #include <libcamera/base/object.h> +#include <libcamera/camera.h> #include <libcamera/controls.h> #include <libcamera/stream.h> +#include "libcamera/internal/request.h" + namespace libcamera { class Camera; @@ -58,6 +63,50 @@ public: void registerRequest(Request *request); void queueRequest(Request *request); + void metadataAvailable(Request *request, const ControlList &metadata); + + template<typename T> + void metadataAvailable(Request *request, const Control<T> &ctrl, + const details::cxx20::type_identity_t<T> &value) + { + auto &m = request->metadata2(); + const auto c = m.checkpoint(); + + m.set(ctrl, value); + request->metadata().set(ctrl, value); + + const auto d = c.diffSince(); + if (d) + request->_d()->camera()->metadataAvailable.emit(request, d); + } + +#ifndef __DOXYGEN__ + struct MetadataSetter { + Request *request; + + template<typename T> + void operator()(const Control<T> &ctrl, + const details::cxx20::type_identity_t<T> &value) const + { + request->metadata().set(ctrl, value); + request->metadata2().set(ctrl, value); + } + }; + + template<typename Func, std::enable_if_t<std::is_invocable_v<Func&, MetadataSetter>> * = nullptr> +#else + template<typename Func> +#endif + void metadataAvailable(Request *request, Func func) + { + const auto c = request->metadata2().checkpoint(); + + std::invoke(func, MetadataSetter{ request }); + + if (const auto d = c.diffSince()) + request->_d()->camera()->metadataAvailable.emit(request, d); + } + bool completeBuffer(Request *request, FrameBuffer *buffer); void completeRequest(Request *request); void cancelRequest(Request *request); diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp index e5f9e55c9..edfa9cf58 100644 --- a/src/libcamera/pipeline_handler.cpp +++ b/src/libcamera/pipeline_handler.cpp @@ -532,6 +532,90 @@ void PipelineHandler::doQueueRequests(Camera *camera) * \return 0 on success or a negative error code otherwise */ +/** + * \brief Signal the availability of metadata for \a request + * \param[in] request The request the metadata belongs to + * \param[in] metadata The collection of metadata items + * + * This function copies metadata items from \a metadata to the cumulative metadata + * collection of \a request. This function may be called multiple times, but metadata + * items already present in Request::metadata() are ignored. Afterwards the function + * notifies the application by triggering the Camera::availableMetadata signal with + * the just added metadata items. + * + * Early metadata completion allows pipeline handlers to fast track delivery of + * metadata results as soon as they are available before the completion of \a + * request. The full list of metadata results of a Request is available at + * Request completion time in Request::metadata(). + * + * \context This function shall be called from the CameraManager thread. + * + * \sa PipelineHandler::metadataAvailable(Request *request, Func func) + * \sa PipelineHandler::metadataAvailable(Request *request, + * const Control<T> &ctrl, + * const details::cxx20::type_identity_t<T> &value) + */ +void PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata) +{ + request->metadata().merge(metadata); + + const auto d = request->metadata2().merge(metadata); + if (d) + request->_d()->camera()->metadataAvailable.emit(request, d); +} + +/** + * \fn void PipelineHandler::metadataAvailable(Request *request, const Control<T> &ctrl, + * const details::cxx20::type_identity_t<T> &value) + * \copybrief PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata) + * \param[in] request The request the metadata belongs to + * \param[in] ctrl The control id of the metadata item + * \param[in] value The value of the metadata item + * + * This function servers the same purpose as PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata) + * but it allows a single metadata item to be reported directly, + * without creating a ControlList. + * + * \context This function shall be called from the CameraManager thread. + * \sa PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata) + */ + +/** + * \fn void PipelineHandler::metadataAvailable(Request *request, Func func) + * \copybrief PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata) + * \param[in] request The request the metadata belongs to + * \param[in] func The callback to invoke + * + * This function serves the same purpose as PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata) + * but it provides more flexibility for pipeline handlers. This function invokes + * \a func, which receives as its sole argument an object of unspecified type whose + * operator() can be used to add metadata items. + * + * For example, a PipelineHandler might use this function to conditionally report two + * metadata items without creating an intermediate ControlList: + * + * \code + metadataAvailable(request, [&](auto set) { + if (x) + set(controls::X, x); + if (y) + set(controls::Y, y); + // ... + }); + * \endcode + * + * The advantage of the above over two calls to PipelineHandler::metadataAvailable(Request *request, const Control<T> &ctrl, const details::cxx20::type_identity_t<T> &value) + * is that the application is only notified once, after \a func has returned. + * + * \note Calling any overload of metadataAvailable() inside \a func is not allowed. + * \note The object passed to \a func is only usable while \a func runs, it must not + * be saved or reused. + * + * \context This function shall be called from the CameraManager thread. + * + * \sa PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata) + */ + /** * \brief Complete a buffer for a request * \param[in] request The request the buffer belongs to