Message ID | 20241206160747.97176-4-jacopo.mondi@ideasonboard.com |
---|---|
State | New |
Headers | show |
Series |
|
Related | show |
Hi Jacopo, Thank you for the patch. On Fri, Dec 6, 2024 at 5:07 PM Jacopo Mondi <jacopo.mondi@ideasonboard.com> wrote: > > 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 two overloads, one that accepts a ControlList and merges it into > Request::metadata_ and one that allows to set a single metadata result > there without going through an intermediate copy. > > The newly provided helpers trigger the Camera::availableMetadata signal > from where applications can retrieve the list of ControlIds that have > just been made available by the pipeline handler. > > Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com> > --- > include/libcamera/internal/pipeline_handler.h | 41 ++++++++++ > src/libcamera/pipeline_handler.cpp | 74 +++++++++++++++++++ > 2 files changed, 115 insertions(+) > > diff --git a/include/libcamera/internal/pipeline_handler.h b/include/libcamera/internal/pipeline_handler.h > index fb28a18d0f46..3ca6a0290b2b 100644 > --- a/include/libcamera/internal/pipeline_handler.h > +++ b/include/libcamera/internal/pipeline_handler.h > @@ -11,13 +11,17 @@ > #include <queue> > #include <string> > #include <sys/types.h> > +#include <unordered_set> > #include <vector> > > #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 +62,43 @@ 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 T &value) > + { > + if (request->metadata().contains(ctrl.id())) > + return; > + > + std::unordered_set<const ControlId *> ids; > + ids.insert(&ctrl); > + > + request->metadata().set<T, T>(ctrl, value); > + > + Camera *camera = request->_d()->camera(); > + camera->metadataAvailable.emit(request, ids); > + } One question: Have you considered wrapping `ctrls` and `value` into a ControlList, and reuse `void metadataAvailable(Request *request, const ControlList &metadata)` above? I think this function doesn't check `request->metadata()->idMap()` while the above function does. Same for the function below. BR, Harvey > + > +#ifndef __DOXYGEN__ > + template<typename T, std::size_t Size> > + void metadataAvailable(Request *request, > + const Control<Span<const T, Size>> &ctrl, > + const Span<const T, Size> &value) > + { > + if (request->metadata().contains(ctrl.id())) > + return; > + > + std::unordered_set<const ControlId *> ids; > + ids.insert(&ctrl); > + > + request->metadata().set(ctrl, value); > + > + Camera *camera = request->_d()->camera(); > + camera->metadataAvailable.emit(request, ids); > + } > +#endif > + > 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 caa5c20e7483..a69d789116ad 100644 > --- a/src/libcamera/pipeline_handler.cpp > +++ b/src/libcamera/pipeline_handler.cpp > @@ -507,6 +507,80 @@ void PipelineHandler::doQueueRequests() > * \return 0 on success or a negative error code otherwise > */ > > +/** > + * \brief Notify the availability of a list of metadata for \a request > + * \param[in] request The request the metadata belongs to > + * \param[in] metadata The metadata list > + * > + * This function should be called multiple times by pipeline handlers to signal > + * the availability of a list of metadata results. It notifies applications > + * by triggering the Camera::availableMetadata signal and accumulates the > + * metadata results in Request::metadata(). > + * > + * 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(). > + * > + * A metadata key is expected to be notified at most once. Metadata keys > + * notified multiple times are ignored. > + * > + * This overload allows to signal the availability of a list of metadata and > + * merges them in the Request::metadata() list. This operations is expensive > + * as controls are copied from \a metadata to Request::metadata(). > + * > + * \context This function shall be called from the CameraManager thread. > + */ > +void PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata) > +{ > + std::unordered_set<const ControlId *> ids; > + const ControlIdMap *idmap = request->metadata().idMap(); > + > + for (const auto &ctrl : metadata) { > + if (request->metadata().contains(ctrl.first)) > + continue; > + > + ASSERT(idmap->count(ctrl.first)); > + > + ids.insert(idmap->at(ctrl.first)); > + } > + > + if (ids.empty()) > + return; > + > + request->metadata().merge(metadata); > + > + Camera *camera = request->_d()->camera(); > + camera->metadataAvailable.emit(request, ids); > +} > + > +/** > + * \fn void PipelineHandler::metadataAvailable(Request *request, const Control<T> &ctrl, const T &value) > + * \brief Notify the availability of a metadata result for \a request > + * \param[in] request The request the metadata belongs to > + * \param[in] ctrl The control id to notify > + * \param[in] value the control value > + * > + * This function should be called multiple times by pipeline handlers to signal > + * the availability of a metadata result. It notifies applications > + * by triggering the Camera::availableMetadata signal and accumulates the > + * metadata result in Request::metadata(). > + * > + * 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(). > + * > + * A metadata key is expected to be notified at most once. Metadata keys > + * notified multiple times are ignored. > + * > + * This overload allows to signal the availability of a single metadata and > + * merge \a value in the Request::metadata() list. This operations copies \a > + * value in the Request::metadata() list without creating intermediate copies. > + * > + * \context This function shall be called from the CameraManager thread. > + */ > + > /** > * \brief Complete a buffer for a request > * \param[in] request The request the buffer belongs to > -- > 2.47.1 >
Hi Harvey On Thu, Jan 02, 2025 at 05:13:36PM +0100, Cheng-Hao Yang wrote: > Hi Jacopo, > > Thank you for the patch. > > On Fri, Dec 6, 2024 at 5:07 PM Jacopo Mondi > <jacopo.mondi@ideasonboard.com> wrote: > > > > 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 two overloads, one that accepts a ControlList and merges it into > > Request::metadata_ and one that allows to set a single metadata result > > there without going through an intermediate copy. > > > > The newly provided helpers trigger the Camera::availableMetadata signal > > from where applications can retrieve the list of ControlIds that have > > just been made available by the pipeline handler. > > > > Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com> > > --- > > include/libcamera/internal/pipeline_handler.h | 41 ++++++++++ > > src/libcamera/pipeline_handler.cpp | 74 +++++++++++++++++++ > > 2 files changed, 115 insertions(+) > > > > diff --git a/include/libcamera/internal/pipeline_handler.h b/include/libcamera/internal/pipeline_handler.h > > index fb28a18d0f46..3ca6a0290b2b 100644 > > --- a/include/libcamera/internal/pipeline_handler.h > > +++ b/include/libcamera/internal/pipeline_handler.h > > @@ -11,13 +11,17 @@ > > #include <queue> > > #include <string> > > #include <sys/types.h> > > +#include <unordered_set> > > #include <vector> > > > > #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 +62,43 @@ 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 T &value) > > + { > > + if (request->metadata().contains(ctrl.id())) > > + return; > > + > > + std::unordered_set<const ControlId *> ids; > > + ids.insert(&ctrl); > > + > > + request->metadata().set<T, T>(ctrl, value); > > + > > + Camera *camera = request->_d()->camera(); > > + camera->metadataAvailable.emit(request, ids); > > + } > > One question: Have you considered wrapping `ctrls` and `value` into a > ControlList, and reuse `void metadataAvailable(Request *request, const > ControlList &metadata)` above? If memory doesn't fail me, to wrap them I should create a ControlList and set(), going through a copy, doesn't I ? > I think this function doesn't check `request->metadata()->idMap()` > while the above function does. I think it's fine. In the templated versions ctrl is a Control<T>, while in void PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata) ctrl is an int, that's why I need to go through an id map. Do you agree ? Thanks j > > Same for the function below. > > BR, > Harvey > > > > + > > +#ifndef __DOXYGEN__ > > + template<typename T, std::size_t Size> > > + void metadataAvailable(Request *request, > > + const Control<Span<const T, Size>> &ctrl, > > + const Span<const T, Size> &value) > > + { > > + if (request->metadata().contains(ctrl.id())) > > + return; > > + > > + std::unordered_set<const ControlId *> ids; > > + ids.insert(&ctrl); > > + > > + request->metadata().set(ctrl, value); > > + > > + Camera *camera = request->_d()->camera(); > > + camera->metadataAvailable.emit(request, ids); > > + } > > +#endif > > + > > 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 caa5c20e7483..a69d789116ad 100644 > > --- a/src/libcamera/pipeline_handler.cpp > > +++ b/src/libcamera/pipeline_handler.cpp > > @@ -507,6 +507,80 @@ void PipelineHandler::doQueueRequests() > > * \return 0 on success or a negative error code otherwise > > */ > > > > +/** > > + * \brief Notify the availability of a list of metadata for \a request > > + * \param[in] request The request the metadata belongs to > > + * \param[in] metadata The metadata list > > + * > > + * This function should be called multiple times by pipeline handlers to signal > > + * the availability of a list of metadata results. It notifies applications > > + * by triggering the Camera::availableMetadata signal and accumulates the > > + * metadata results in Request::metadata(). > > + * > > + * 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(). > > + * > > + * A metadata key is expected to be notified at most once. Metadata keys > > + * notified multiple times are ignored. > > + * > > + * This overload allows to signal the availability of a list of metadata and > > + * merges them in the Request::metadata() list. This operations is expensive > > + * as controls are copied from \a metadata to Request::metadata(). > > + * > > + * \context This function shall be called from the CameraManager thread. > > + */ > > +void PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata) > > +{ > > + std::unordered_set<const ControlId *> ids; > > + const ControlIdMap *idmap = request->metadata().idMap(); > > + > > + for (const auto &ctrl : metadata) { > > + if (request->metadata().contains(ctrl.first)) > > + continue; > > + > > + ASSERT(idmap->count(ctrl.first)); > > + > > + ids.insert(idmap->at(ctrl.first)); > > + } > > + > > + if (ids.empty()) > > + return; > > + > > + request->metadata().merge(metadata); > > + > > + Camera *camera = request->_d()->camera(); > > + camera->metadataAvailable.emit(request, ids); > > +} > > + > > +/** > > + * \fn void PipelineHandler::metadataAvailable(Request *request, const Control<T> &ctrl, const T &value) > > + * \brief Notify the availability of a metadata result for \a request > > + * \param[in] request The request the metadata belongs to > > + * \param[in] ctrl The control id to notify > > + * \param[in] value the control value > > + * > > + * This function should be called multiple times by pipeline handlers to signal > > + * the availability of a metadata result. It notifies applications > > + * by triggering the Camera::availableMetadata signal and accumulates the > > + * metadata result in Request::metadata(). > > + * > > + * 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(). > > + * > > + * A metadata key is expected to be notified at most once. Metadata keys > > + * notified multiple times are ignored. > > + * > > + * This overload allows to signal the availability of a single metadata and > > + * merge \a value in the Request::metadata() list. This operations copies \a > > + * value in the Request::metadata() list without creating intermediate copies. > > + * > > + * \context This function shall be called from the CameraManager thread. > > + */ > > + > > /** > > * \brief Complete a buffer for a request > > * \param[in] request The request the buffer belongs to > > -- > > 2.47.1 > >
Hi Jacopo, On Fri, Jan 3, 2025 at 6:08 PM Jacopo Mondi <jacopo.mondi@ideasonboard.com> wrote: > > Hi Harvey > > On Thu, Jan 02, 2025 at 05:13:36PM +0100, Cheng-Hao Yang wrote: > > Hi Jacopo, > > > > Thank you for the patch. > > > > On Fri, Dec 6, 2024 at 5:07 PM Jacopo Mondi > > <jacopo.mondi@ideasonboard.com> wrote: > > > > > > 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 two overloads, one that accepts a ControlList and merges it into > > > Request::metadata_ and one that allows to set a single metadata result > > > there without going through an intermediate copy. > > > > > > The newly provided helpers trigger the Camera::availableMetadata signal > > > from where applications can retrieve the list of ControlIds that have > > > just been made available by the pipeline handler. > > > > > > Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com> > > > --- > > > include/libcamera/internal/pipeline_handler.h | 41 ++++++++++ > > > src/libcamera/pipeline_handler.cpp | 74 +++++++++++++++++++ > > > 2 files changed, 115 insertions(+) > > > > > > diff --git a/include/libcamera/internal/pipeline_handler.h b/include/libcamera/internal/pipeline_handler.h > > > index fb28a18d0f46..3ca6a0290b2b 100644 > > > --- a/include/libcamera/internal/pipeline_handler.h > > > +++ b/include/libcamera/internal/pipeline_handler.h > > > @@ -11,13 +11,17 @@ > > > #include <queue> > > > #include <string> > > > #include <sys/types.h> > > > +#include <unordered_set> > > > #include <vector> > > > > > > #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 +62,43 @@ 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 T &value) > > > + { > > > + if (request->metadata().contains(ctrl.id())) > > > + return; > > > + > > > + std::unordered_set<const ControlId *> ids; > > > + ids.insert(&ctrl); > > > + > > > + request->metadata().set<T, T>(ctrl, value); > > > + > > > + Camera *camera = request->_d()->camera(); > > > + camera->metadataAvailable.emit(request, ids); > > > + } > > > > One question: Have you considered wrapping `ctrls` and `value` into a > > ControlList, and reuse `void metadataAvailable(Request *request, const > > ControlList &metadata)` above? > > If memory doesn't fail me, to wrap them I should create a ControlList > and set(), going through a copy, doesn't I ? Ah got it, thanks for the explanation. I guess using rvalue reference here (Control<T> &&ctrl) and expecting move semantics of users is an overkill? Fine with the current way though. > > > I think this function doesn't check `request->metadata()->idMap()` > > while the above function does. > > I think it's fine. In the templated versions ctrl is a Control<T>, > while in > > void PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata) > > ctrl is an int, that's why I need to go through an id map. > > Do you agree ? Hmm, Control classes in libcamera have always been a headache to me, while I thought that ControlList is just a list of `pair<Control<T>, T>`...? (Observed as `void ControlList::set(const Control<T> &ctrl, const V &value)`) > > Thanks > j > > > > > Same for the function below. > > > > BR, > > Harvey > > > > > > > + > > > +#ifndef __DOXYGEN__ > > > + template<typename T, std::size_t Size> > > > + void metadataAvailable(Request *request, > > > + const Control<Span<const T, Size>> &ctrl, > > > + const Span<const T, Size> &value) > > > + { > > > + if (request->metadata().contains(ctrl.id())) > > > + return; > > > + > > > + std::unordered_set<const ControlId *> ids; > > > + ids.insert(&ctrl); > > > + > > > + request->metadata().set(ctrl, value); > > > + > > > + Camera *camera = request->_d()->camera(); > > > + camera->metadataAvailable.emit(request, ids); > > > + } > > > +#endif > > > + > > > 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 caa5c20e7483..a69d789116ad 100644 > > > --- a/src/libcamera/pipeline_handler.cpp > > > +++ b/src/libcamera/pipeline_handler.cpp > > > @@ -507,6 +507,80 @@ void PipelineHandler::doQueueRequests() > > > * \return 0 on success or a negative error code otherwise > > > */ > > > > > > +/** > > > + * \brief Notify the availability of a list of metadata for \a request > > > + * \param[in] request The request the metadata belongs to > > > + * \param[in] metadata The metadata list > > > + * > > > + * This function should be called multiple times by pipeline handlers to signal nit: I think `should` is a relatively strong term. Some pipeline handlers might still be calling it once at the end of a Request? > > > + * the availability of a list of metadata results. It notifies applications > > > + * by triggering the Camera::availableMetadata signal and accumulates the > > > + * metadata results in Request::metadata(). > > > + * > > > + * 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(). > > > + * > > > + * A metadata key is expected to be notified at most once. Metadata keys > > > + * notified multiple times are ignored. > > > + * > > > + * This overload allows to signal the availability of a list of metadata and > > > + * merges them in the Request::metadata() list. This operations is expensive nit: s/operations/operation > > > + * as controls are copied from \a metadata to Request::metadata(). > > > + * > > > + * \context This function shall be called from the CameraManager thread. > > > + */ > > > +void PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata) > > > +{ > > > + std::unordered_set<const ControlId *> ids; > > > + const ControlIdMap *idmap = request->metadata().idMap(); > > > + > > > + for (const auto &ctrl : metadata) { > > > + if (request->metadata().contains(ctrl.first)) > > > + continue; > > > + > > > + ASSERT(idmap->count(ctrl.first)); > > > + > > > + ids.insert(idmap->at(ctrl.first)); > > > + } > > > + > > > + if (ids.empty()) > > > + return; > > > + > > > + request->metadata().merge(metadata); If we're ignoring the whole `metadata` above when `ids.empty() == true`, why do we still want to merge the ids that are not listed in `idmap`? I suggest setting the valid id & value pairs in the for loop instead. WDYT? BR, Harvey > > > + > > > + Camera *camera = request->_d()->camera(); > > > + camera->metadataAvailable.emit(request, ids); > > > +} > > > + > > > +/** > > > + * \fn void PipelineHandler::metadataAvailable(Request *request, const Control<T> &ctrl, const T &value) > > > + * \brief Notify the availability of a metadata result for \a request > > > + * \param[in] request The request the metadata belongs to > > > + * \param[in] ctrl The control id to notify > > > + * \param[in] value the control value > > > + * > > > + * This function should be called multiple times by pipeline handlers to signal > > > + * the availability of a metadata result. It notifies applications > > > + * by triggering the Camera::availableMetadata signal and accumulates the > > > + * metadata result in Request::metadata(). > > > + * > > > + * 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(). > > > + * > > > + * A metadata key is expected to be notified at most once. Metadata keys > > > + * notified multiple times are ignored. > > > + * > > > + * This overload allows to signal the availability of a single metadata and > > > + * merge \a value in the Request::metadata() list. This operations copies \a > > > + * value in the Request::metadata() list without creating intermediate copies. > > > + * > > > + * \context This function shall be called from the CameraManager thread. > > > + */ > > > + > > > /** > > > * \brief Complete a buffer for a request > > > * \param[in] request The request the buffer belongs to > > > -- > > > 2.47.1 > > >
diff --git a/include/libcamera/internal/pipeline_handler.h b/include/libcamera/internal/pipeline_handler.h index fb28a18d0f46..3ca6a0290b2b 100644 --- a/include/libcamera/internal/pipeline_handler.h +++ b/include/libcamera/internal/pipeline_handler.h @@ -11,13 +11,17 @@ #include <queue> #include <string> #include <sys/types.h> +#include <unordered_set> #include <vector> #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 +62,43 @@ 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 T &value) + { + if (request->metadata().contains(ctrl.id())) + return; + + std::unordered_set<const ControlId *> ids; + ids.insert(&ctrl); + + request->metadata().set<T, T>(ctrl, value); + + Camera *camera = request->_d()->camera(); + camera->metadataAvailable.emit(request, ids); + } + +#ifndef __DOXYGEN__ + template<typename T, std::size_t Size> + void metadataAvailable(Request *request, + const Control<Span<const T, Size>> &ctrl, + const Span<const T, Size> &value) + { + if (request->metadata().contains(ctrl.id())) + return; + + std::unordered_set<const ControlId *> ids; + ids.insert(&ctrl); + + request->metadata().set(ctrl, value); + + Camera *camera = request->_d()->camera(); + camera->metadataAvailable.emit(request, ids); + } +#endif + 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 caa5c20e7483..a69d789116ad 100644 --- a/src/libcamera/pipeline_handler.cpp +++ b/src/libcamera/pipeline_handler.cpp @@ -507,6 +507,80 @@ void PipelineHandler::doQueueRequests() * \return 0 on success or a negative error code otherwise */ +/** + * \brief Notify the availability of a list of metadata for \a request + * \param[in] request The request the metadata belongs to + * \param[in] metadata The metadata list + * + * This function should be called multiple times by pipeline handlers to signal + * the availability of a list of metadata results. It notifies applications + * by triggering the Camera::availableMetadata signal and accumulates the + * metadata results in Request::metadata(). + * + * 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(). + * + * A metadata key is expected to be notified at most once. Metadata keys + * notified multiple times are ignored. + * + * This overload allows to signal the availability of a list of metadata and + * merges them in the Request::metadata() list. This operations is expensive + * as controls are copied from \a metadata to Request::metadata(). + * + * \context This function shall be called from the CameraManager thread. + */ +void PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata) +{ + std::unordered_set<const ControlId *> ids; + const ControlIdMap *idmap = request->metadata().idMap(); + + for (const auto &ctrl : metadata) { + if (request->metadata().contains(ctrl.first)) + continue; + + ASSERT(idmap->count(ctrl.first)); + + ids.insert(idmap->at(ctrl.first)); + } + + if (ids.empty()) + return; + + request->metadata().merge(metadata); + + Camera *camera = request->_d()->camera(); + camera->metadataAvailable.emit(request, ids); +} + +/** + * \fn void PipelineHandler::metadataAvailable(Request *request, const Control<T> &ctrl, const T &value) + * \brief Notify the availability of a metadata result for \a request + * \param[in] request The request the metadata belongs to + * \param[in] ctrl The control id to notify + * \param[in] value the control value + * + * This function should be called multiple times by pipeline handlers to signal + * the availability of a metadata result. It notifies applications + * by triggering the Camera::availableMetadata signal and accumulates the + * metadata result in Request::metadata(). + * + * 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(). + * + * A metadata key is expected to be notified at most once. Metadata keys + * notified multiple times are ignored. + * + * This overload allows to signal the availability of a single metadata and + * merge \a value in the Request::metadata() list. This operations copies \a + * value in the Request::metadata() list without creating intermediate copies. + * + * \context This function shall be called from the CameraManager thread. + */ + /** * \brief Complete a buffer for a request * \param[in] request The request the buffer belongs to
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 two overloads, one that accepts a ControlList and merges it into Request::metadata_ and one that allows to set a single metadata result there without going through an intermediate copy. The newly provided helpers trigger the Camera::availableMetadata signal from where applications can retrieve the list of ControlIds that have just been made available by the pipeline handler. Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com> --- include/libcamera/internal/pipeline_handler.h | 41 ++++++++++ src/libcamera/pipeline_handler.cpp | 74 +++++++++++++++++++ 2 files changed, 115 insertions(+)