[{"id":35187,"web_url":"https://patchwork.libcamera.org/comment/35187/","msgid":"<suwldvkf2xtacjvg3lw4gejhtrxlyarxdz2itakhc3jj3dpcxr@ncme4c5zybq4>","date":"2025-07-28T10:08:19","subject":"Re: [RFC PATCH v2 16/22] libcamera: pipeline_handler: Add\n\tmetadataAvailable() function","submitter":{"id":143,"url":"https://patchwork.libcamera.org/api/people/143/","name":"Jacopo Mondi","email":"jacopo.mondi@ideasonboard.com"},"content":"Hi Barnabás\n\nOn Mon, Jul 21, 2025 at 12:46:16PM +0200, Barnabás Pőcze wrote:\n> From: Jacopo Mondi <jacopo.mondi@ideasonboard.com>\n>\n> Currently the way pipeline handlers have to store metadata results\n> for a Request is to access the Request::metadata_ list directly and\n> either merge a ControlList or set a single control value there.\n>\n> Direct access to Request::metadata_ is however problematic as even if\n> metadata would be available earlier, pipeline handlers can only\n> accumulate the results in Request::metadata_ and they're only available\n> for applications at Request complete time.\n>\n> Instead of letting pipeline handlers access Request::metadata_ directly\n> provide two helper functions, similar in spirit to\n> PipelineHandler::completeBuffer() and\n> PipelineHandler::completeRequest(), to allow pipeline handlers to\n> notify early availability of metadata.\n>\n> Provide three overloads, one that accepts a ControlList and merges it into\n> Request::metadata_, one that allows to set a single metadata result there\n> without going through an intermediate copy, and one that runs a callback\n> for conditional metadata reporting without intermediate an ControlList.\n>\n> The newly provided helpers trigger the Camera::availableMetadata signal\n> from where applications can retrieve the list of controls that have\n> just been made available by the pipeline handler.\n>\n> Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>\n> [Fill both lists, use `type_identity`, new overload, adjust commit message.]\n> Signed-off-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com>\n> ---\n> Original: https://patchwork.libcamera.org/patch/22229/\n>\n> changes in v2:\n>   * add new overload that takes an invocable object for more flexibility\n> ---\n>  include/libcamera/internal/pipeline_handler.h | 49 +++++++++++\n>  src/libcamera/pipeline_handler.cpp            | 84 +++++++++++++++++++\n>  2 files changed, 133 insertions(+)\n>\n> diff --git a/include/libcamera/internal/pipeline_handler.h b/include/libcamera/internal/pipeline_handler.h\n> index e89d6a33e..49c907178 100644\n> --- a/include/libcamera/internal/pipeline_handler.h\n> +++ b/include/libcamera/internal/pipeline_handler.h\n> @@ -7,16 +7,21 @@\n>\n>  #pragma once\n>\n> +#include <functional>\n>  #include <memory>\n>  #include <string>\n>  #include <sys/types.h>\n>  #include <vector>\n>\n> +#include <libcamera/base/details/cxx20.h>\n>  #include <libcamera/base/object.h>\n>\n> +#include <libcamera/camera.h>\n>  #include <libcamera/controls.h>\n>  #include <libcamera/stream.h>\n>\n> +#include \"libcamera/internal/request.h\"\n> +\n>  namespace libcamera {\n>\n>  class Camera;\n> @@ -58,6 +63,50 @@ public:\n>  \tvoid registerRequest(Request *request);\n>  \tvoid queueRequest(Request *request);\n>\n> +\tvoid metadataAvailable(Request *request, const ControlList &metadata);\n> +\n> +\ttemplate<typename T>\n> +\tvoid metadataAvailable(Request *request, const Control<T> &ctrl,\n> +\t\t\t       const details::cxx20::type_identity_t<T> &value)\n\nI presume the usage of type_identity_t<T> is a safety measure to avoid\na deduction failure. However I presume T is fully specified  and the\ntype of the last argument should match the Control<T> one.\n\nHowver I presume this doesn't hurt, and might save some deduction\nfailure ?\n\n> +\t{\n> +\t\tauto &m = request->metadata2();\n> +\t\tconst auto c = m.checkpoint();\n> +\n> +\t\tm.set(ctrl, value);\n> +\t\trequest->metadata().set(ctrl, value);\n> +\n> +\t\tconst auto d = c.diffSince();\n> +\t\tif (d)\n> +\t\t\trequest->_d()->camera()->metadataAvailable.emit(request, d);\n> +\t}\n> +\n> +#ifndef __DOXYGEN__\n> +\tstruct MetadataSetter {\n> +\t\tRequest *request;\n> +\n> +\t\ttemplate<typename T>\n> +\t\tvoid operator()(const Control<T> &ctrl,\n> +\t\t\t        const details::cxx20::type_identity_t<T> &value) const\n> +\t\t{\n> +\t\t\trequest->metadata().set(ctrl, value);\n> +\t\t\trequest->metadata2().set(ctrl, value);\n> +\t\t}\n> +\t};\n> +\n> +\ttemplate<typename Func, std::enable_if_t<std::is_invocable_v<Func&, MetadataSetter>> * = nullptr>\n> +#else\n> +\ttemplate<typename Func>\n> +#endif\n> +\tvoid metadataAvailable(Request *request, Func func)\n> +\t{\n> +\t\tconst auto c = request->metadata2().checkpoint();\n> +\n> +\t\tstd::invoke(func, MetadataSetter{ request });\n> +\n> +\t\tif (const auto d = c.diffSince())\n> +\t\t\trequest->_d()->camera()->metadataAvailable.emit(request, d);\n> +\t}\n> +\n>  \tbool completeBuffer(Request *request, FrameBuffer *buffer);\n>  \tvoid completeRequest(Request *request);\n>  \tvoid cancelRequest(Request *request);\n> diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp\n> index e5f9e55c9..edfa9cf58 100644\n> --- a/src/libcamera/pipeline_handler.cpp\n> +++ b/src/libcamera/pipeline_handler.cpp\n> @@ -532,6 +532,90 @@ void PipelineHandler::doQueueRequests(Camera *camera)\n>   * \\return 0 on success or a negative error code otherwise\n>   */\n>\n> +/**\n> + * \\brief Signal the availability of metadata for \\a request\n> + * \\param[in] request The request the metadata belongs to\n> + * \\param[in] metadata The collection of metadata items\n> + *\n> + * This function copies metadata items from \\a metadata to the cumulative metadata\n> + * collection of \\a request. This function may be called multiple times, but metadata\n> + * items already present in Request::metadata() are ignored. Afterwards the function\n> + * notifies the application by triggering the Camera::availableMetadata signal with\n> + * the just added metadata items.\n> + *\n> + * Early metadata completion allows pipeline handlers to fast track delivery of\n> + * metadata results as soon as they are available before the completion of \\a\n> + * request. The full list of metadata results of a Request is available at\n> + * Request completion time in Request::metadata().\n> + *\n> + * \\context This function shall be called from the CameraManager thread.\n> + *\n> + * \\sa PipelineHandler::metadataAvailable(Request *request, Func func)\n> + * \\sa PipelineHandler::metadataAvailable(Request *request,\n> + *                                        const Control<T> &ctrl,\n> + *                                        const details::cxx20::type_identity_t<T> &value)\n> + */\n> +void PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata)\n> +{\n> +\trequest->metadata().merge(metadata);\n> +\n> +\tconst auto d = request->metadata2().merge(metadata);\n> +\tif (d)\n> +\t\trequest->_d()->camera()->metadataAvailable.emit(request, d);\n> +}\n> +\n> +/**\n> + * \\fn void PipelineHandler::metadataAvailable(Request *request, const Control<T> &ctrl,\n> + *\t\t\t\t\t       const details::cxx20::type_identity_t<T> &value)\n> + * \\copybrief PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata)\n> + * \\param[in] request The request the metadata belongs to\n> + * \\param[in] ctrl The control id of the metadata item\n> + * \\param[in] value The value of the metadata item\n> + *\n> + * This function servers the same purpose as PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata)\n\nyou can break the line as\n\n * This function servers the same purpose as\n * PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata)\n\n\n> + * but it allows a single metadata item to be reported directly,\n> + * without creating a ControlList.\n> + *\n> + * \\context This function shall be called from the CameraManager thread.\n> + * \\sa PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata)\n> + */\n> +\n> +/**\n> + * \\fn void PipelineHandler::metadataAvailable(Request *request, Func func)\n> + * \\copybrief PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata)\n> + * \\param[in] request The request the metadata belongs to\n> + * \\param[in] func The callback to invoke\n> + *\n> + * This function serves the same purpose as PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata)\n\nditto\n\n> + * but it provides more flexibility for pipeline handlers. This function invokes\n> + * \\a func, which receives as its sole argument an object of unspecified type whose\n> + * operator() can be used to add metadata items.\n> + *\n> + * For example, a PipelineHandler might use this function to conditionally report two\n> + * metadata items without creating an intermediate ControlList:\n> + *\n> + * \\code\n> +\tmetadataAvailable(request, [&](auto set) {\n> +\t\tif (x)\n> +\t\t\tset(controls::X, x);\n> +\t\tif (y)\n> +\t\t\tset(controls::Y, y);\n> +\t\t// ...\n> +\t});\n> + * \\endcode\n\nSorry I might be missing the use case here.\n\nThe call receives a MetadataSetter as 'set' (again auto requires a few\nlevels of indirection just to save a few characters), but I don't get\nhow the pipeline handler should call this, in particular what\n\n        if (x)\n\n        if (y)\n\nmight refer to...\n\nWhat I mean is that pipeline handlers call metadataAvailable in\nresponse to events, and they should provide a callback where they\ninspect 'x' and 'y' which are conditions related to the event that\njust happened ?\n\n> + *\n> + * 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)\n\nagain line breaks\n\n> + * is that the application is only notified once, after \\a func has returned.\n> + *\n> + * \\note Calling any overload of metadataAvailable() inside \\a func is not allowed.\n> + * \\note The object passed to \\a func is only usable while \\a func runs, it must not\n> + *       be saved or reused.\n> + *\n> + * \\context This function shall be called from the CameraManager thread.\n> + *\n> + * \\sa PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata)\n> + */\n> +\n>  /**\n>   * \\brief Complete a buffer for a request\n>   * \\param[in] request The request the buffer belongs to\n> --\n> 2.50.1\n>","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 67627C3237\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon, 28 Jul 2025 10:08:30 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 35FB269149;\n\tMon, 28 Jul 2025 12:08:29 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 4886D6904C\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 28 Jul 2025 12:08:27 +0200 (CEST)","from ideasonboard.com (mob-5-90-139-29.net.vodafone.it\n\t[5.90.139.29])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 3C0A23A4;\n\tMon, 28 Jul 2025 12:07:43 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"QLTm8JSH\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1753697265;\n\tbh=SbdGqCFDPJTqo5pbCwt5PKiiaSrtWbkwC580YPF+YLA=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=QLTm8JSHnYqmApkbGe9Ct899mYsBJgm1CUDyBkeod+Lym/qnqEWtplX3VmxtofSyO\n\tx5bMMftMGTlj6oyMC61Hi9Eqg/UGjUgBaYUvyEFD4s0JbTKCPTsr3SDWviFUK+bNQZ\n\thG8fOIHJJoDXKp1ih6HbG0Ccsekb8rsWuj7fDElg=","Date":"Mon, 28 Jul 2025 12:08:19 +0200","From":"Jacopo Mondi <jacopo.mondi@ideasonboard.com>","To":"=?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= <barnabas.pocze@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org, \n\tJacopo Mondi <jacopo.mondi@ideasonboard.com>","Subject":"Re: [RFC PATCH v2 16/22] libcamera: pipeline_handler: Add\n\tmetadataAvailable() function","Message-ID":"<suwldvkf2xtacjvg3lw4gejhtrxlyarxdz2itakhc3jj3dpcxr@ncme4c5zybq4>","References":"<20250721104622.1550908-1-barnabas.pocze@ideasonboard.com>\n\t<20250721104622.1550908-17-barnabas.pocze@ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","Content-Transfer-Encoding":"8bit","In-Reply-To":"<20250721104622.1550908-17-barnabas.pocze@ideasonboard.com>","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":35196,"web_url":"https://patchwork.libcamera.org/comment/35196/","msgid":"<fb991d2f-cfc4-4531-b38a-209d101160ba@ideasonboard.com>","date":"2025-07-28T12:11:27","subject":"Re: [RFC PATCH v2 16/22] libcamera: pipeline_handler: Add\n\tmetadataAvailable() function","submitter":{"id":216,"url":"https://patchwork.libcamera.org/api/people/216/","name":"Barnabás Pőcze","email":"barnabas.pocze@ideasonboard.com"},"content":"Hi\n\n2025. 07. 28. 12:08 keltezéssel, Jacopo Mondi írta:\n> Hi Barnabás\n> \n> On Mon, Jul 21, 2025 at 12:46:16PM +0200, Barnabás Pőcze wrote:\n>> From: Jacopo Mondi <jacopo.mondi@ideasonboard.com>\n>>\n>> Currently the way pipeline handlers have to store metadata results\n>> for a Request is to access the Request::metadata_ list directly and\n>> either merge a ControlList or set a single control value there.\n>>\n>> Direct access to Request::metadata_ is however problematic as even if\n>> metadata would be available earlier, pipeline handlers can only\n>> accumulate the results in Request::metadata_ and they're only available\n>> for applications at Request complete time.\n>>\n>> Instead of letting pipeline handlers access Request::metadata_ directly\n>> provide two helper functions, similar in spirit to\n>> PipelineHandler::completeBuffer() and\n>> PipelineHandler::completeRequest(), to allow pipeline handlers to\n>> notify early availability of metadata.\n>>\n>> Provide three overloads, one that accepts a ControlList and merges it into\n>> Request::metadata_, one that allows to set a single metadata result there\n>> without going through an intermediate copy, and one that runs a callback\n>> for conditional metadata reporting without intermediate an ControlList.\n>>\n>> The newly provided helpers trigger the Camera::availableMetadata signal\n>> from where applications can retrieve the list of controls that have\n>> just been made available by the pipeline handler.\n>>\n>> Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>\n>> [Fill both lists, use `type_identity`, new overload, adjust commit message.]\n>> Signed-off-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com>\n>> ---\n>> Original: https://patchwork.libcamera.org/patch/22229/\n>>\n>> changes in v2:\n>>    * add new overload that takes an invocable object for more flexibility\n>> ---\n>>   include/libcamera/internal/pipeline_handler.h | 49 +++++++++++\n>>   src/libcamera/pipeline_handler.cpp            | 84 +++++++++++++++++++\n>>   2 files changed, 133 insertions(+)\n>>\n>> diff --git a/include/libcamera/internal/pipeline_handler.h b/include/libcamera/internal/pipeline_handler.h\n>> index e89d6a33e..49c907178 100644\n>> --- a/include/libcamera/internal/pipeline_handler.h\n>> +++ b/include/libcamera/internal/pipeline_handler.h\n>> @@ -7,16 +7,21 @@\n>>\n>>   #pragma once\n>>\n>> +#include <functional>\n>>   #include <memory>\n>>   #include <string>\n>>   #include <sys/types.h>\n>>   #include <vector>\n>>\n>> +#include <libcamera/base/details/cxx20.h>\n>>   #include <libcamera/base/object.h>\n>>\n>> +#include <libcamera/camera.h>\n>>   #include <libcamera/controls.h>\n>>   #include <libcamera/stream.h>\n>>\n>> +#include \"libcamera/internal/request.h\"\n>> +\n>>   namespace libcamera {\n>>\n>>   class Camera;\n>> @@ -58,6 +63,50 @@ public:\n>>   \tvoid registerRequest(Request *request);\n>>   \tvoid queueRequest(Request *request);\n>>\n>> +\tvoid metadataAvailable(Request *request, const ControlList &metadata);\n>> +\n>> +\ttemplate<typename T>\n>> +\tvoid metadataAvailable(Request *request, const Control<T> &ctrl,\n>> +\t\t\t       const details::cxx20::type_identity_t<T> &value)\n> \n> I presume the usage of type_identity_t<T> is a safety measure to avoid\n> a deduction failure. However I presume T is fully specified  and the\n> type of the last argument should match the Control<T> one.\n> \n> Howver I presume this doesn't hurt, and might save some deduction\n> failure ?\n\nI think it's more of a convenience feature, it allows you to use\ne.g. initializer lists for the value, e.g.\n\n    Rectangle *ptr; size_t count;\n    metadataAvailable(controls::rpi::ScalerScrops, { ptr, count });\n\n    Rectangle item1, item2, item3;\n    metadataAvailable(controls::rpi::ScalerScrops, {{ item1, item2, item3  }});\n\nIt can be dropped if it seems unsuitable for some reason.\n\n\n> \n>> +\t{\n>> +\t\tauto &m = request->metadata2();\n>> +\t\tconst auto c = m.checkpoint();\n>> +\n>> +\t\tm.set(ctrl, value);\n>> +\t\trequest->metadata().set(ctrl, value);\n>> +\n>> +\t\tconst auto d = c.diffSince();\n>> +\t\tif (d)\n>> +\t\t\trequest->_d()->camera()->metadataAvailable.emit(request, d);\n>> +\t}\n>> +\n>> +#ifndef __DOXYGEN__\n>> +\tstruct MetadataSetter {\n>> +\t\tRequest *request;\n>> +\n>> +\t\ttemplate<typename T>\n>> +\t\tvoid operator()(const Control<T> &ctrl,\n>> +\t\t\t        const details::cxx20::type_identity_t<T> &value) const\n>> +\t\t{\n>> +\t\t\trequest->metadata().set(ctrl, value);\n>> +\t\t\trequest->metadata2().set(ctrl, value);\n>> +\t\t}\n>> +\t};\n>> +\n>> +\ttemplate<typename Func, std::enable_if_t<std::is_invocable_v<Func&, MetadataSetter>> * = nullptr>\n>> +#else\n>> +\ttemplate<typename Func>\n>> +#endif\n>> +\tvoid metadataAvailable(Request *request, Func func)\n>> +\t{\n>> +\t\tconst auto c = request->metadata2().checkpoint();\n>> +\n>> +\t\tstd::invoke(func, MetadataSetter{ request });\n>> +\n>> +\t\tif (const auto d = c.diffSince())\n>> +\t\t\trequest->_d()->camera()->metadataAvailable.emit(request, d);\n>> +\t}\n>> +\n>>   \tbool completeBuffer(Request *request, FrameBuffer *buffer);\n>>   \tvoid completeRequest(Request *request);\n>>   \tvoid cancelRequest(Request *request);\n>> diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp\n>> index e5f9e55c9..edfa9cf58 100644\n>> --- a/src/libcamera/pipeline_handler.cpp\n>> +++ b/src/libcamera/pipeline_handler.cpp\n>> @@ -532,6 +532,90 @@ void PipelineHandler::doQueueRequests(Camera *camera)\n>>    * \\return 0 on success or a negative error code otherwise\n>>    */\n>>\n>> +/**\n>> + * \\brief Signal the availability of metadata for \\a request\n>> + * \\param[in] request The request the metadata belongs to\n>> + * \\param[in] metadata The collection of metadata items\n>> + *\n>> + * This function copies metadata items from \\a metadata to the cumulative metadata\n>> + * collection of \\a request. This function may be called multiple times, but metadata\n>> + * items already present in Request::metadata() are ignored. Afterwards the function\n>> + * notifies the application by triggering the Camera::availableMetadata signal with\n>> + * the just added metadata items.\n>> + *\n>> + * Early metadata completion allows pipeline handlers to fast track delivery of\n>> + * metadata results as soon as they are available before the completion of \\a\n>> + * request. The full list of metadata results of a Request is available at\n>> + * Request completion time in Request::metadata().\n>> + *\n>> + * \\context This function shall be called from the CameraManager thread.\n>> + *\n>> + * \\sa PipelineHandler::metadataAvailable(Request *request, Func func)\n>> + * \\sa PipelineHandler::metadataAvailable(Request *request,\n>> + *                                        const Control<T> &ctrl,\n>> + *                                        const details::cxx20::type_identity_t<T> &value)\n>> + */\n>> +void PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata)\n>> +{\n>> +\trequest->metadata().merge(metadata);\n>> +\n>> +\tconst auto d = request->metadata2().merge(metadata);\n>> +\tif (d)\n>> +\t\trequest->_d()->camera()->metadataAvailable.emit(request, d);\n>> +}\n>> +\n>> +/**\n>> + * \\fn void PipelineHandler::metadataAvailable(Request *request, const Control<T> &ctrl,\n>> + *\t\t\t\t\t       const details::cxx20::type_identity_t<T> &value)\n>> + * \\copybrief PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata)\n>> + * \\param[in] request The request the metadata belongs to\n>> + * \\param[in] ctrl The control id of the metadata item\n>> + * \\param[in] value The value of the metadata item\n>> + *\n>> + * This function servers the same purpose as PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata)\n> \n> you can break the line as\n> \n>   * This function servers the same purpose as\n>   * PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata)\n\nok\n\n\n> \n> \n>> + * but it allows a single metadata item to be reported directly,\n>> + * without creating a ControlList.\n>> + *\n>> + * \\context This function shall be called from the CameraManager thread.\n>> + * \\sa PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata)\n>> + */\n>> +\n>> +/**\n>> + * \\fn void PipelineHandler::metadataAvailable(Request *request, Func func)\n>> + * \\copybrief PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata)\n>> + * \\param[in] request The request the metadata belongs to\n>> + * \\param[in] func The callback to invoke\n>> + *\n>> + * This function serves the same purpose as PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata)\n> \n> ditto\n\nok\n\n\n> \n>> + * but it provides more flexibility for pipeline handlers. This function invokes\n>> + * \\a func, which receives as its sole argument an object of unspecified type whose\n>> + * operator() can be used to add metadata items.\n>> + *\n>> + * For example, a PipelineHandler might use this function to conditionally report two\n>> + * metadata items without creating an intermediate ControlList:\n>> + *\n>> + * \\code\n>> +\tmetadataAvailable(request, [&](auto set) {\n>> +\t\tif (x)\n>> +\t\t\tset(controls::X, x);\n>> +\t\tif (y)\n>> +\t\t\tset(controls::Y, y);\n>> +\t\t// ...\n>> +\t});\n>> + * \\endcode\n> \n> Sorry I might be missing the use case here.\n> \n> The call receives a MetadataSetter as 'set' (again auto requires a few\n> levels of indirection just to save a few characters), but I don't get\n> how the pipeline handler should call this, in particular what\n> \n>          if (x)\n> \n>          if (y)\n> \n> might refer to...\n> \n> What I mean is that pipeline handlers call metadataAvailable in\n> response to events, and they should provide a callback where they\n> inspect 'x' and 'y' which are conditions related to the event that\n> just happened ?\n\nI hope that the use case in one of the later patches makes things clearer.\nI will try to make the example clearer in any case.\n\n\n> \n>> + *\n>> + * 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)\n> \n> again line breaks\n\nok\n\n\nRegards,\nBarnabás Pőcze\n\n> \n>> + * is that the application is only notified once, after \\a func has returned.\n>> + *\n>> + * \\note Calling any overload of metadataAvailable() inside \\a func is not allowed.\n>> + * \\note The object passed to \\a func is only usable while \\a func runs, it must not\n>> + *       be saved or reused.\n>> + *\n>> + * \\context This function shall be called from the CameraManager thread.\n>> + *\n>> + * \\sa PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata)\n>> + */\n>> +\n>>   /**\n>>    * \\brief Complete a buffer for a request\n>>    * \\param[in] request The request the buffer belongs to\n>> --\n>> 2.50.1\n>>","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 7569BC3237\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon, 28 Jul 2025 12:11:34 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 15A466916C;\n\tMon, 28 Jul 2025 14:11:33 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id DA50B69158\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 28 Jul 2025 14:11:31 +0200 (CEST)","from [192.168.33.18] (185.221.140.39.nat.pool.zt.hu\n\t[185.221.140.39])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id AFE0D446;\n\tMon, 28 Jul 2025 14:10:49 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"eVfwQiwQ\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1753704649;\n\tbh=Ggc743qetKcyq44ATTo/kJKjb8knO47EjYp/WDPQkV4=;\n\th=Date:Subject:To:Cc:References:From:In-Reply-To:From;\n\tb=eVfwQiwQ+z/M+u5BID5slcVRCkR479zrRAA2UsKe9uOubmutbH09D2egn3nBj/RHm\n\t4kcyRT+fnwQz4O1vJ3aQD6VJVq4CX4MfPeJIWZrmAmnWoiFzgfb0Iq90J2UpWcQGXs\n\tedRpARUTcF51ODlWGmSJ27M7tagiVz61fpwSwoTQ=","Message-ID":"<fb991d2f-cfc4-4531-b38a-209d101160ba@ideasonboard.com>","Date":"Mon, 28 Jul 2025 14:11:27 +0200","MIME-Version":"1.0","User-Agent":"Mozilla Thunderbird","Subject":"Re: [RFC PATCH v2 16/22] libcamera: pipeline_handler: Add\n\tmetadataAvailable() function","To":"Jacopo Mondi <jacopo.mondi@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","References":"<20250721104622.1550908-1-barnabas.pocze@ideasonboard.com>\n\t<20250721104622.1550908-17-barnabas.pocze@ideasonboard.com>\n\t<suwldvkf2xtacjvg3lw4gejhtrxlyarxdz2itakhc3jj3dpcxr@ncme4c5zybq4>","From":"=?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= <barnabas.pocze@ideasonboard.com>","Content-Language":"en-US, hu-HU","In-Reply-To":"<suwldvkf2xtacjvg3lw4gejhtrxlyarxdz2itakhc3jj3dpcxr@ncme4c5zybq4>","Content-Type":"text/plain; charset=UTF-8; format=flowed","Content-Transfer-Encoding":"8bit","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":35198,"web_url":"https://patchwork.libcamera.org/comment/35198/","msgid":"<2e4t6sxocrdppsvl6l5icezakpnhotfn2flhitqhqtctrgvuuy@c4rpdwacioir>","date":"2025-07-28T12:34:39","subject":"Re: [RFC PATCH v2 16/22] libcamera: pipeline_handler: Add\n\tmetadataAvailable() function","submitter":{"id":143,"url":"https://patchwork.libcamera.org/api/people/143/","name":"Jacopo Mondi","email":"jacopo.mondi@ideasonboard.com"},"content":"Hi Barnabás\n\nOn Mon, Jul 28, 2025 at 02:11:27PM +0200, Barnabás Pőcze wrote:\n> Hi\n>\n> 2025. 07. 28. 12:08 keltezéssel, Jacopo Mondi írta:\n> > Hi Barnabás\n> >\n> > On Mon, Jul 21, 2025 at 12:46:16PM +0200, Barnabás Pőcze wrote:\n> > > From: Jacopo Mondi <jacopo.mondi@ideasonboard.com>\n> > >\n> > > Currently the way pipeline handlers have to store metadata results\n> > > for a Request is to access the Request::metadata_ list directly and\n> > > either merge a ControlList or set a single control value there.\n> > >\n> > > Direct access to Request::metadata_ is however problematic as even if\n> > > metadata would be available earlier, pipeline handlers can only\n> > > accumulate the results in Request::metadata_ and they're only available\n> > > for applications at Request complete time.\n> > >\n> > > Instead of letting pipeline handlers access Request::metadata_ directly\n> > > provide two helper functions, similar in spirit to\n> > > PipelineHandler::completeBuffer() and\n> > > PipelineHandler::completeRequest(), to allow pipeline handlers to\n> > > notify early availability of metadata.\n> > >\n> > > Provide three overloads, one that accepts a ControlList and merges it into\n> > > Request::metadata_, one that allows to set a single metadata result there\n> > > without going through an intermediate copy, and one that runs a callback\n> > > for conditional metadata reporting without intermediate an ControlList.\n> > >\n> > > The newly provided helpers trigger the Camera::availableMetadata signal\n> > > from where applications can retrieve the list of controls that have\n> > > just been made available by the pipeline handler.\n> > >\n> > > Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>\n> > > [Fill both lists, use `type_identity`, new overload, adjust commit message.]\n> > > Signed-off-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com>\n> > > ---\n> > > Original: https://patchwork.libcamera.org/patch/22229/\n> > >\n> > > changes in v2:\n> > >    * add new overload that takes an invocable object for more flexibility\n> > > ---\n> > >   include/libcamera/internal/pipeline_handler.h | 49 +++++++++++\n> > >   src/libcamera/pipeline_handler.cpp            | 84 +++++++++++++++++++\n> > >   2 files changed, 133 insertions(+)\n> > >\n> > > diff --git a/include/libcamera/internal/pipeline_handler.h b/include/libcamera/internal/pipeline_handler.h\n> > > index e89d6a33e..49c907178 100644\n> > > --- a/include/libcamera/internal/pipeline_handler.h\n> > > +++ b/include/libcamera/internal/pipeline_handler.h\n> > > @@ -7,16 +7,21 @@\n> > >\n> > >   #pragma once\n> > >\n> > > +#include <functional>\n> > >   #include <memory>\n> > >   #include <string>\n> > >   #include <sys/types.h>\n> > >   #include <vector>\n> > >\n> > > +#include <libcamera/base/details/cxx20.h>\n> > >   #include <libcamera/base/object.h>\n> > >\n> > > +#include <libcamera/camera.h>\n> > >   #include <libcamera/controls.h>\n> > >   #include <libcamera/stream.h>\n> > >\n> > > +#include \"libcamera/internal/request.h\"\n> > > +\n> > >   namespace libcamera {\n> > >\n> > >   class Camera;\n> > > @@ -58,6 +63,50 @@ public:\n> > >   \tvoid registerRequest(Request *request);\n> > >   \tvoid queueRequest(Request *request);\n> > >\n> > > +\tvoid metadataAvailable(Request *request, const ControlList &metadata);\n> > > +\n> > > +\ttemplate<typename T>\n> > > +\tvoid metadataAvailable(Request *request, const Control<T> &ctrl,\n> > > +\t\t\t       const details::cxx20::type_identity_t<T> &value)\n> >\n> > I presume the usage of type_identity_t<T> is a safety measure to avoid\n> > a deduction failure. However I presume T is fully specified  and the\n> > type of the last argument should match the Control<T> one.\n> >\n> > Howver I presume this doesn't hurt, and might save some deduction\n> > failure ?\n>\n> I think it's more of a convenience feature, it allows you to use\n> e.g. initializer lists for the value, e.g.\n>\n>    Rectangle *ptr; size_t count;\n>    metadataAvailable(controls::rpi::ScalerScrops, { ptr, count });\n>\n>    Rectangle item1, item2, item3;\n>    metadataAvailable(controls::rpi::ScalerScrops, {{ item1, item2, item3  }});\n>\n> It can be dropped if it seems unsuitable for some reason.\n>\n\nNo no, I think initializer_lists are a a valid case of non-deduced\ncontext where type_identity_t might help.\n\nAs said it's certainly doesn't hurt, even more if it allows usage of\nuseful features\n\n>\n> >\n> > > +\t{\n> > > +\t\tauto &m = request->metadata2();\n> > > +\t\tconst auto c = m.checkpoint();\n> > > +\n> > > +\t\tm.set(ctrl, value);\n> > > +\t\trequest->metadata().set(ctrl, value);\n> > > +\n> > > +\t\tconst auto d = c.diffSince();\n> > > +\t\tif (d)\n> > > +\t\t\trequest->_d()->camera()->metadataAvailable.emit(request, d);\n> > > +\t}\n> > > +\n> > > +#ifndef __DOXYGEN__\n> > > +\tstruct MetadataSetter {\n> > > +\t\tRequest *request;\n> > > +\n> > > +\t\ttemplate<typename T>\n> > > +\t\tvoid operator()(const Control<T> &ctrl,\n> > > +\t\t\t        const details::cxx20::type_identity_t<T> &value) const\n> > > +\t\t{\n> > > +\t\t\trequest->metadata().set(ctrl, value);\n> > > +\t\t\trequest->metadata2().set(ctrl, value);\n> > > +\t\t}\n> > > +\t};\n> > > +\n> > > +\ttemplate<typename Func, std::enable_if_t<std::is_invocable_v<Func&, MetadataSetter>> * = nullptr>\n> > > +#else\n> > > +\ttemplate<typename Func>\n> > > +#endif\n> > > +\tvoid metadataAvailable(Request *request, Func func)\n> > > +\t{\n> > > +\t\tconst auto c = request->metadata2().checkpoint();\n> > > +\n> > > +\t\tstd::invoke(func, MetadataSetter{ request });\n> > > +\n> > > +\t\tif (const auto d = c.diffSince())\n> > > +\t\t\trequest->_d()->camera()->metadataAvailable.emit(request, d);\n> > > +\t}\n> > > +\n> > >   \tbool completeBuffer(Request *request, FrameBuffer *buffer);\n> > >   \tvoid completeRequest(Request *request);\n> > >   \tvoid cancelRequest(Request *request);\n> > > diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp\n> > > index e5f9e55c9..edfa9cf58 100644\n> > > --- a/src/libcamera/pipeline_handler.cpp\n> > > +++ b/src/libcamera/pipeline_handler.cpp\n> > > @@ -532,6 +532,90 @@ void PipelineHandler::doQueueRequests(Camera *camera)\n> > >    * \\return 0 on success or a negative error code otherwise\n> > >    */\n> > >\n> > > +/**\n> > > + * \\brief Signal the availability of metadata for \\a request\n> > > + * \\param[in] request The request the metadata belongs to\n> > > + * \\param[in] metadata The collection of metadata items\n> > > + *\n> > > + * This function copies metadata items from \\a metadata to the cumulative metadata\n> > > + * collection of \\a request. This function may be called multiple times, but metadata\n> > > + * items already present in Request::metadata() are ignored. Afterwards the function\n> > > + * notifies the application by triggering the Camera::availableMetadata signal with\n> > > + * the just added metadata items.\n> > > + *\n> > > + * Early metadata completion allows pipeline handlers to fast track delivery of\n> > > + * metadata results as soon as they are available before the completion of \\a\n> > > + * request. The full list of metadata results of a Request is available at\n> > > + * Request completion time in Request::metadata().\n> > > + *\n> > > + * \\context This function shall be called from the CameraManager thread.\n> > > + *\n> > > + * \\sa PipelineHandler::metadataAvailable(Request *request, Func func)\n> > > + * \\sa PipelineHandler::metadataAvailable(Request *request,\n> > > + *                                        const Control<T> &ctrl,\n> > > + *                                        const details::cxx20::type_identity_t<T> &value)\n> > > + */\n> > > +void PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata)\n> > > +{\n> > > +\trequest->metadata().merge(metadata);\n> > > +\n> > > +\tconst auto d = request->metadata2().merge(metadata);\n> > > +\tif (d)\n> > > +\t\trequest->_d()->camera()->metadataAvailable.emit(request, d);\n> > > +}\n> > > +\n> > > +/**\n> > > + * \\fn void PipelineHandler::metadataAvailable(Request *request, const Control<T> &ctrl,\n> > > + *\t\t\t\t\t       const details::cxx20::type_identity_t<T> &value)\n> > > + * \\copybrief PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata)\n> > > + * \\param[in] request The request the metadata belongs to\n> > > + * \\param[in] ctrl The control id of the metadata item\n> > > + * \\param[in] value The value of the metadata item\n> > > + *\n> > > + * This function servers the same purpose as PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata)\n> >\n> > you can break the line as\n> >\n> >   * This function servers the same purpose as\n> >   * PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata)\n>\n> ok\n>\n>\n> >\n> >\n> > > + * but it allows a single metadata item to be reported directly,\n> > > + * without creating a ControlList.\n> > > + *\n> > > + * \\context This function shall be called from the CameraManager thread.\n> > > + * \\sa PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata)\n> > > + */\n> > > +\n> > > +/**\n> > > + * \\fn void PipelineHandler::metadataAvailable(Request *request, Func func)\n> > > + * \\copybrief PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata)\n> > > + * \\param[in] request The request the metadata belongs to\n> > > + * \\param[in] func The callback to invoke\n> > > + *\n> > > + * This function serves the same purpose as PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata)\n> >\n> > ditto\n>\n> ok\n>\n>\n> >\n> > > + * but it provides more flexibility for pipeline handlers. This function invokes\n> > > + * \\a func, which receives as its sole argument an object of unspecified type whose\n> > > + * operator() can be used to add metadata items.\n> > > + *\n> > > + * For example, a PipelineHandler might use this function to conditionally report two\n> > > + * metadata items without creating an intermediate ControlList:\n> > > + *\n> > > + * \\code\n> > > +\tmetadataAvailable(request, [&](auto set) {\n> > > +\t\tif (x)\n> > > +\t\t\tset(controls::X, x);\n> > > +\t\tif (y)\n> > > +\t\t\tset(controls::Y, y);\n> > > +\t\t// ...\n> > > +\t});\n> > > + * \\endcode\n> >\n> > Sorry I might be missing the use case here.\n> >\n> > The call receives a MetadataSetter as 'set' (again auto requires a few\n> > levels of indirection just to save a few characters), but I don't get\n> > how the pipeline handler should call this, in particular what\n> >\n> >          if (x)\n> >\n> >          if (y)\n> >\n> > might refer to...\n> >\n> > What I mean is that pipeline handlers call metadataAvailable in\n> > response to events, and they should provide a callback where they\n> > inspect 'x' and 'y' which are conditions related to the event that\n> > just happened ?\n>\n> I hope that the use case in one of the later patches makes things clearer.\n\nYes sure, let's continue the discussion there\n\nThanks\n  j\n\n> I will try to make the example clearer in any case.\n>\n>\n> >\n> > > + *\n> > > + * 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)\n> >\n> > again line breaks\n>\n> ok\n>\n>\n> Regards,\n> Barnabás Pőcze\n>\n> >\n> > > + * is that the application is only notified once, after \\a func has returned.\n> > > + *\n> > > + * \\note Calling any overload of metadataAvailable() inside \\a func is not allowed.\n> > > + * \\note The object passed to \\a func is only usable while \\a func runs, it must not\n> > > + *       be saved or reused.\n> > > + *\n> > > + * \\context This function shall be called from the CameraManager thread.\n> > > + *\n> > > + * \\sa PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata)\n> > > + */\n> > > +\n> > >   /**\n> > >    * \\brief Complete a buffer for a request\n> > >    * \\param[in] request The request the buffer belongs to\n> > > --\n> > > 2.50.1\n> > >\n>","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 3F8C2C3237\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon, 28 Jul 2025 12:34:47 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 7F1BB69164;\n\tMon, 28 Jul 2025 14:34:46 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id E935669158\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 28 Jul 2025 14:34:44 +0200 (CEST)","from ideasonboard.com (mob-5-90-139-29.net.vodafone.it\n\t[5.90.139.29])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 164C44A4;\n\tMon, 28 Jul 2025 14:34:01 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"V8zSHv8E\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1753706042;\n\tbh=DxE4lmEUR4bRygSxwCeZ8HlHQPSR7r+bPP6g+CQbe+s=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=V8zSHv8EJOhbSfj0XiOigMPppckfMIQc5TQSdEEXzxvX2h5C/no/lgaW61oVtll81\n\tQipmcd3CLCsyI8PeaXGL6FyKCzmRcQ3c2WoCDx3BtQUF3PpC+JAlEmKtv8YplPmkpE\n\tQIlaTDZnY+a7CXEg/1JmMUiilmHIZ4dmQngyZP08=","Date":"Mon, 28 Jul 2025 14:34:39 +0200","From":"Jacopo Mondi <jacopo.mondi@ideasonboard.com>","To":"=?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= <barnabas.pocze@ideasonboard.com>","Cc":"Jacopo Mondi <jacopo.mondi@ideasonboard.com>, \n\tlibcamera-devel@lists.libcamera.org","Subject":"Re: [RFC PATCH v2 16/22] libcamera: pipeline_handler: Add\n\tmetadataAvailable() function","Message-ID":"<2e4t6sxocrdppsvl6l5icezakpnhotfn2flhitqhqtctrgvuuy@c4rpdwacioir>","References":"<20250721104622.1550908-1-barnabas.pocze@ideasonboard.com>\n\t<20250721104622.1550908-17-barnabas.pocze@ideasonboard.com>\n\t<suwldvkf2xtacjvg3lw4gejhtrxlyarxdz2itakhc3jj3dpcxr@ncme4c5zybq4>\n\t<fb991d2f-cfc4-4531-b38a-209d101160ba@ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","Content-Transfer-Encoding":"8bit","In-Reply-To":"<fb991d2f-cfc4-4531-b38a-209d101160ba@ideasonboard.com>","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":35885,"web_url":"https://patchwork.libcamera.org/comment/35885/","msgid":"<175819452207.2127323.9197093205682745730@neptunite.rasen.tech>","date":"2025-09-18T11:22:02","subject":"Re: [RFC PATCH v2 16/22] libcamera: pipeline_handler: Add\n\tmetadataAvailable() function","submitter":{"id":17,"url":"https://patchwork.libcamera.org/api/people/17/","name":"Paul Elder","email":"paul.elder@ideasonboard.com"},"content":"Quoting Barnabás Pőcze (2025-07-21 19:46:16)\n> From: Jacopo Mondi <jacopo.mondi@ideasonboard.com>\n> \n> Currently the way pipeline handlers have to store metadata results\n> for a Request is to access the Request::metadata_ list directly and\n\nThis is a bit difficult to parse... s/way/method/ would make it easier.\ns/way/only method/ might be be better even.\n\n> either merge a ControlList or set a single control value there.\n> \n> Direct access to Request::metadata_ is however problematic as even if\n> metadata would be available earlier, pipeline handlers can only\n> accumulate the results in Request::metadata_ and they're only available\n> for applications at Request complete time.\n> \n> Instead of letting pipeline handlers access Request::metadata_ directly\n> provide two helper functions, similar in spirit to\n> PipelineHandler::completeBuffer() and\n> PipelineHandler::completeRequest(), to allow pipeline handlers to\n> notify early availability of metadata.\n> \n> Provide three overloads, one that accepts a ControlList and merges it into\n> Request::metadata_, one that allows to set a single metadata result there\n> without going through an intermediate copy, and one that runs a callback\n> for conditional metadata reporting without intermediate an ControlList.\n\nswap(intermediate, an)\n\n> \n> The newly provided helpers trigger the Camera::availableMetadata signal\n> from where applications can retrieve the list of controls that have\n> just been made available by the pipeline handler.\n\nOoh that's cool.\n\n> \n> Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>\n> [Fill both lists, use `type_identity`, new overload, adjust commit message.]\n> Signed-off-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com>\n\nLooks good to me.\n\nReviewed-by: Paul Elder <paul.elder@ideasonboard.com>\n\n> ---\n> Original: https://patchwork.libcamera.org/patch/22229/\n> \n> changes in v2:\n>   * add new overload that takes an invocable object for more flexibility\n> ---\n>  include/libcamera/internal/pipeline_handler.h | 49 +++++++++++\n>  src/libcamera/pipeline_handler.cpp            | 84 +++++++++++++++++++\n>  2 files changed, 133 insertions(+)\n> \n> diff --git a/include/libcamera/internal/pipeline_handler.h b/include/libcamera/internal/pipeline_handler.h\n> index e89d6a33e..49c907178 100644\n> --- a/include/libcamera/internal/pipeline_handler.h\n> +++ b/include/libcamera/internal/pipeline_handler.h\n> @@ -7,16 +7,21 @@\n>  \n>  #pragma once\n>  \n> +#include <functional>\n>  #include <memory>\n>  #include <string>\n>  #include <sys/types.h>\n>  #include <vector>\n>  \n> +#include <libcamera/base/details/cxx20.h>\n>  #include <libcamera/base/object.h>\n>  \n> +#include <libcamera/camera.h>\n>  #include <libcamera/controls.h>\n>  #include <libcamera/stream.h>\n>  \n> +#include \"libcamera/internal/request.h\"\n> +\n>  namespace libcamera {\n>  \n>  class Camera;\n> @@ -58,6 +63,50 @@ public:\n>         void registerRequest(Request *request);\n>         void queueRequest(Request *request);\n>  \n> +       void metadataAvailable(Request *request, const ControlList &metadata);\n> +\n> +       template<typename T>\n> +       void metadataAvailable(Request *request, const Control<T> &ctrl,\n> +                              const details::cxx20::type_identity_t<T> &value)\n> +       {\n> +               auto &m = request->metadata2();\n> +               const auto c = m.checkpoint();\n> +\n> +               m.set(ctrl, value);\n> +               request->metadata().set(ctrl, value);\n> +\n> +               const auto d = c.diffSince();\n> +               if (d)\n> +                       request->_d()->camera()->metadataAvailable.emit(request, d);\n> +       }\n> +\n> +#ifndef __DOXYGEN__\n> +       struct MetadataSetter {\n> +               Request *request;\n> +\n> +               template<typename T>\n> +               void operator()(const Control<T> &ctrl,\n> +                               const details::cxx20::type_identity_t<T> &value) const\n> +               {\n> +                       request->metadata().set(ctrl, value);\n> +                       request->metadata2().set(ctrl, value);\n> +               }\n> +       };\n> +\n> +       template<typename Func, std::enable_if_t<std::is_invocable_v<Func&, MetadataSetter>> * = nullptr>\n> +#else\n> +       template<typename Func>\n> +#endif\n> +       void metadataAvailable(Request *request, Func func)\n> +       {\n> +               const auto c = request->metadata2().checkpoint();\n> +\n> +               std::invoke(func, MetadataSetter{ request });\n> +\n> +               if (const auto d = c.diffSince())\n> +                       request->_d()->camera()->metadataAvailable.emit(request, d);\n> +       }\n> +\n>         bool completeBuffer(Request *request, FrameBuffer *buffer);\n>         void completeRequest(Request *request);\n>         void cancelRequest(Request *request);\n> diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp\n> index e5f9e55c9..edfa9cf58 100644\n> --- a/src/libcamera/pipeline_handler.cpp\n> +++ b/src/libcamera/pipeline_handler.cpp\n> @@ -532,6 +532,90 @@ void PipelineHandler::doQueueRequests(Camera *camera)\n>   * \\return 0 on success or a negative error code otherwise\n>   */\n>  \n> +/**\n> + * \\brief Signal the availability of metadata for \\a request\n> + * \\param[in] request The request the metadata belongs to\n> + * \\param[in] metadata The collection of metadata items\n> + *\n> + * This function copies metadata items from \\a metadata to the cumulative metadata\n> + * collection of \\a request. This function may be called multiple times, but metadata\n> + * items already present in Request::metadata() are ignored. Afterwards the function\n> + * notifies the application by triggering the Camera::availableMetadata signal with\n> + * the just added metadata items.\n> + *\n> + * Early metadata completion allows pipeline handlers to fast track delivery of\n> + * metadata results as soon as they are available before the completion of \\a\n> + * request. The full list of metadata results of a Request is available at\n> + * Request completion time in Request::metadata().\n> + *\n> + * \\context This function shall be called from the CameraManager thread.\n> + *\n> + * \\sa PipelineHandler::metadataAvailable(Request *request, Func func)\n> + * \\sa PipelineHandler::metadataAvailable(Request *request,\n> + *                                        const Control<T> &ctrl,\n> + *                                        const details::cxx20::type_identity_t<T> &value)\n> + */\n> +void PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata)\n> +{\n> +       request->metadata().merge(metadata);\n> +\n> +       const auto d = request->metadata2().merge(metadata);\n> +       if (d)\n> +               request->_d()->camera()->metadataAvailable.emit(request, d);\n> +}\n> +\n> +/**\n> + * \\fn void PipelineHandler::metadataAvailable(Request *request, const Control<T> &ctrl,\n> + *                                            const details::cxx20::type_identity_t<T> &value)\n> + * \\copybrief PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata)\n> + * \\param[in] request The request the metadata belongs to\n> + * \\param[in] ctrl The control id of the metadata item\n> + * \\param[in] value The value of the metadata item\n> + *\n> + * This function servers the same purpose as PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata)\n> + * but it allows a single metadata item to be reported directly,\n> + * without creating a ControlList.\n> + *\n> + * \\context This function shall be called from the CameraManager thread.\n> + * \\sa PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata)\n> + */\n> +\n> +/**\n> + * \\fn void PipelineHandler::metadataAvailable(Request *request, Func func)\n> + * \\copybrief PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata)\n> + * \\param[in] request The request the metadata belongs to\n> + * \\param[in] func The callback to invoke\n> + *\n> + * This function serves the same purpose as PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata)\n> + * but it provides more flexibility for pipeline handlers. This function invokes\n> + * \\a func, which receives as its sole argument an object of unspecified type whose\n> + * operator() can be used to add metadata items.\n> + *\n> + * For example, a PipelineHandler might use this function to conditionally report two\n> + * metadata items without creating an intermediate ControlList:\n> + *\n> + * \\code\n> +       metadataAvailable(request, [&](auto set) {\n> +               if (x)\n> +                       set(controls::X, x);\n> +               if (y)\n> +                       set(controls::Y, y);\n> +               // ...\n> +       });\n> + * \\endcode\n> + *\n> + * 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)\n> + * is that the application is only notified once, after \\a func has returned.\n> + *\n> + * \\note Calling any overload of metadataAvailable() inside \\a func is not allowed.\n> + * \\note The object passed to \\a func is only usable while \\a func runs, it must not\n> + *       be saved or reused.\n> + *\n> + * \\context This function shall be called from the CameraManager thread.\n> + *\n> + * \\sa PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata)\n> + */\n> +\n>  /**\n>   * \\brief Complete a buffer for a request\n>   * \\param[in] request The request the buffer belongs to\n> -- \n> 2.50.1\n>","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id A6245BE173\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu, 18 Sep 2025 11:22:10 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 94CA16936F;\n\tThu, 18 Sep 2025 13:22:09 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 9A7D262C3B\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 18 Sep 2025 13:22:08 +0200 (CEST)","from neptunite.rasen.tech (unknown\n\t[IPv6:2404:7a81:160:2100:7cf2:5f58:dd2a:9ec1])\n\tby perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 7A014C6E;\n\tThu, 18 Sep 2025 13:20:48 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"SBYyp25g\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1758194449;\n\tbh=kkIFsQzL/aD/HLhNPZHqonxhPFMZGOIbw+KYeS9ouhY=;\n\th=In-Reply-To:References:Subject:From:Cc:To:Date:From;\n\tb=SBYyp25gydAn6DCNAhZzC8m9gCIHFNAYgjifPG6qVIme/dgsqXgyOM6ZtjARrlmjH\n\thKRfGyRAxY5Y0+LHPWEYRBEP6lM5UKyIGqrGtXvdiD98ZahT8FWgiuUFnq3rRi+GRW\n\tZpafbyzKvwYIZ/HLw4JhaG/ItzQ1zfJJGwBgME/E=","Content-Type":"text/plain; charset=\"utf-8\"","MIME-Version":"1.0","Content-Transfer-Encoding":"quoted-printable","In-Reply-To":"<20250721104622.1550908-17-barnabas.pocze@ideasonboard.com>","References":"<20250721104622.1550908-1-barnabas.pocze@ideasonboard.com>\n\t<20250721104622.1550908-17-barnabas.pocze@ideasonboard.com>","Subject":"Re: [RFC PATCH v2 16/22] libcamera: pipeline_handler: Add\n\tmetadataAvailable() function","From":"Paul Elder <paul.elder@ideasonboard.com>","Cc":"Jacopo Mondi <jacopo.mondi@ideasonboard.com>","To":"=?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= <barnabas.pocze@ideasonboard.com>,\n\tlibcamera-devel@lists.libcamera.org","Date":"Thu, 18 Sep 2025 20:22:02 +0900","Message-ID":"<175819452207.2127323.9197093205682745730@neptunite.rasen.tech>","User-Agent":"alot/0.0.0","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":35950,"web_url":"https://patchwork.libcamera.org/comment/35950/","msgid":"<457f8734-ea14-4207-b453-1c27f23558a8@ideasonboard.com>","date":"2025-09-22T12:07:03","subject":"Re: [RFC PATCH v2 16/22] libcamera: pipeline_handler: Add\n\tmetadataAvailable() function","submitter":{"id":216,"url":"https://patchwork.libcamera.org/api/people/216/","name":"Barnabás Pőcze","email":"barnabas.pocze@ideasonboard.com"},"content":"Hi\n\n2025. 09. 18. 13:22 keltezéssel, Paul Elder írta:\n> Quoting Barnabás Pőcze (2025-07-21 19:46:16)\n>> From: Jacopo Mondi <jacopo.mondi@ideasonboard.com>\n>>\n>> Currently the way pipeline handlers have to store metadata results\n>> for a Request is to access the Request::metadata_ list directly and\n> \n> This is a bit difficult to parse... s/way/method/ would make it easier.\n> s/way/only method/ might be be better even.\n> \n>> either merge a ControlList or set a single control value there.\n\nMaybe:\n\n   Currently pipeline handlers access `Request::metadata_` directly, and\n   consequently they also store metadata results directly by setting single\n   values or merging other control lists.\n\n?\n\n\nRegards,\nBarnabás Pőcze\n\n>>\n>> Direct access to Request::metadata_ is however problematic as even if\n>> metadata would be available earlier, pipeline handlers can only\n>> accumulate the results in Request::metadata_ and they're only available\n>> for applications at Request complete time.\n>>\n>> Instead of letting pipeline handlers access Request::metadata_ directly\n>> provide two helper functions, similar in spirit to\n>> PipelineHandler::completeBuffer() and\n>> PipelineHandler::completeRequest(), to allow pipeline handlers to\n>> notify early availability of metadata.\n>>\n>> Provide three overloads, one that accepts a ControlList and merges it into\n>> Request::metadata_, one that allows to set a single metadata result there\n>> without going through an intermediate copy, and one that runs a callback\n>> for conditional metadata reporting without intermediate an ControlList.\n> \n> swap(intermediate, an)\n> \n>>\n>> The newly provided helpers trigger the Camera::availableMetadata signal\n>> from where applications can retrieve the list of controls that have\n>> just been made available by the pipeline handler.\n> \n> Ooh that's cool.\n> \n>>\n>> Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>\n>> [Fill both lists, use `type_identity`, new overload, adjust commit message.]\n>> Signed-off-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com>\n> \n> Looks good to me.\n> \n> Reviewed-by: Paul Elder <paul.elder@ideasonboard.com>\n> \n>> ---\n>> Original: https://patchwork.libcamera.org/patch/22229/\n>>\n>> changes in v2:\n>>    * add new overload that takes an invocable object for more flexibility\n>> ---\n>>   include/libcamera/internal/pipeline_handler.h | 49 +++++++++++\n>>   src/libcamera/pipeline_handler.cpp            | 84 +++++++++++++++++++\n>>   2 files changed, 133 insertions(+)\n>>\n>> diff --git a/include/libcamera/internal/pipeline_handler.h b/include/libcamera/internal/pipeline_handler.h\n>> index e89d6a33e..49c907178 100644\n>> --- a/include/libcamera/internal/pipeline_handler.h\n>> +++ b/include/libcamera/internal/pipeline_handler.h\n>> @@ -7,16 +7,21 @@\n>>   \n>>   #pragma once\n>>   \n>> +#include <functional>\n>>   #include <memory>\n>>   #include <string>\n>>   #include <sys/types.h>\n>>   #include <vector>\n>>   \n>> +#include <libcamera/base/details/cxx20.h>\n>>   #include <libcamera/base/object.h>\n>>   \n>> +#include <libcamera/camera.h>\n>>   #include <libcamera/controls.h>\n>>   #include <libcamera/stream.h>\n>>   \n>> +#include \"libcamera/internal/request.h\"\n>> +\n>>   namespace libcamera {\n>>   \n>>   class Camera;\n>> @@ -58,6 +63,50 @@ public:\n>>          void registerRequest(Request *request);\n>>          void queueRequest(Request *request);\n>>   \n>> +       void metadataAvailable(Request *request, const ControlList &metadata);\n>> +\n>> +       template<typename T>\n>> +       void metadataAvailable(Request *request, const Control<T> &ctrl,\n>> +                              const details::cxx20::type_identity_t<T> &value)\n>> +       {\n>> +               auto &m = request->metadata2();\n>> +               const auto c = m.checkpoint();\n>> +\n>> +               m.set(ctrl, value);\n>> +               request->metadata().set(ctrl, value);\n>> +\n>> +               const auto d = c.diffSince();\n>> +               if (d)\n>> +                       request->_d()->camera()->metadataAvailable.emit(request, d);\n>> +       }\n>> +\n>> +#ifndef __DOXYGEN__\n>> +       struct MetadataSetter {\n>> +               Request *request;\n>> +\n>> +               template<typename T>\n>> +               void operator()(const Control<T> &ctrl,\n>> +                               const details::cxx20::type_identity_t<T> &value) const\n>> +               {\n>> +                       request->metadata().set(ctrl, value);\n>> +                       request->metadata2().set(ctrl, value);\n>> +               }\n>> +       };\n>> +\n>> +       template<typename Func, std::enable_if_t<std::is_invocable_v<Func&, MetadataSetter>> * = nullptr>\n>> +#else\n>> +       template<typename Func>\n>> +#endif\n>> +       void metadataAvailable(Request *request, Func func)\n>> +       {\n>> +               const auto c = request->metadata2().checkpoint();\n>> +\n>> +               std::invoke(func, MetadataSetter{ request });\n>> +\n>> +               if (const auto d = c.diffSince())\n>> +                       request->_d()->camera()->metadataAvailable.emit(request, d);\n>> +       }\n>> +\n>>          bool completeBuffer(Request *request, FrameBuffer *buffer);\n>>          void completeRequest(Request *request);\n>>          void cancelRequest(Request *request);\n>> diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp\n>> index e5f9e55c9..edfa9cf58 100644\n>> --- a/src/libcamera/pipeline_handler.cpp\n>> +++ b/src/libcamera/pipeline_handler.cpp\n>> @@ -532,6 +532,90 @@ void PipelineHandler::doQueueRequests(Camera *camera)\n>>    * \\return 0 on success or a negative error code otherwise\n>>    */\n>>   \n>> +/**\n>> + * \\brief Signal the availability of metadata for \\a request\n>> + * \\param[in] request The request the metadata belongs to\n>> + * \\param[in] metadata The collection of metadata items\n>> + *\n>> + * This function copies metadata items from \\a metadata to the cumulative metadata\n>> + * collection of \\a request. This function may be called multiple times, but metadata\n>> + * items already present in Request::metadata() are ignored. Afterwards the function\n>> + * notifies the application by triggering the Camera::availableMetadata signal with\n>> + * the just added metadata items.\n>> + *\n>> + * Early metadata completion allows pipeline handlers to fast track delivery of\n>> + * metadata results as soon as they are available before the completion of \\a\n>> + * request. The full list of metadata results of a Request is available at\n>> + * Request completion time in Request::metadata().\n>> + *\n>> + * \\context This function shall be called from the CameraManager thread.\n>> + *\n>> + * \\sa PipelineHandler::metadataAvailable(Request *request, Func func)\n>> + * \\sa PipelineHandler::metadataAvailable(Request *request,\n>> + *                                        const Control<T> &ctrl,\n>> + *                                        const details::cxx20::type_identity_t<T> &value)\n>> + */\n>> +void PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata)\n>> +{\n>> +       request->metadata().merge(metadata);\n>> +\n>> +       const auto d = request->metadata2().merge(metadata);\n>> +       if (d)\n>> +               request->_d()->camera()->metadataAvailable.emit(request, d);\n>> +}\n>> +\n>> +/**\n>> + * \\fn void PipelineHandler::metadataAvailable(Request *request, const Control<T> &ctrl,\n>> + *                                            const details::cxx20::type_identity_t<T> &value)\n>> + * \\copybrief PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata)\n>> + * \\param[in] request The request the metadata belongs to\n>> + * \\param[in] ctrl The control id of the metadata item\n>> + * \\param[in] value The value of the metadata item\n>> + *\n>> + * This function servers the same purpose as PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata)\n>> + * but it allows a single metadata item to be reported directly,\n>> + * without creating a ControlList.\n>> + *\n>> + * \\context This function shall be called from the CameraManager thread.\n>> + * \\sa PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata)\n>> + */\n>> +\n>> +/**\n>> + * \\fn void PipelineHandler::metadataAvailable(Request *request, Func func)\n>> + * \\copybrief PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata)\n>> + * \\param[in] request The request the metadata belongs to\n>> + * \\param[in] func The callback to invoke\n>> + *\n>> + * This function serves the same purpose as PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata)\n>> + * but it provides more flexibility for pipeline handlers. This function invokes\n>> + * \\a func, which receives as its sole argument an object of unspecified type whose\n>> + * operator() can be used to add metadata items.\n>> + *\n>> + * For example, a PipelineHandler might use this function to conditionally report two\n>> + * metadata items without creating an intermediate ControlList:\n>> + *\n>> + * \\code\n>> +       metadataAvailable(request, [&](auto set) {\n>> +               if (x)\n>> +                       set(controls::X, x);\n>> +               if (y)\n>> +                       set(controls::Y, y);\n>> +               // ...\n>> +       });\n>> + * \\endcode\n>> + *\n>> + * 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)\n>> + * is that the application is only notified once, after \\a func has returned.\n>> + *\n>> + * \\note Calling any overload of metadataAvailable() inside \\a func is not allowed.\n>> + * \\note The object passed to \\a func is only usable while \\a func runs, it must not\n>> + *       be saved or reused.\n>> + *\n>> + * \\context This function shall be called from the CameraManager thread.\n>> + *\n>> + * \\sa PipelineHandler::metadataAvailable(Request *request, const ControlList &metadata)\n>> + */\n>> +\n>>   /**\n>>    * \\brief Complete a buffer for a request\n>>    * \\param[in] request The request the buffer belongs to\n>> -- \n>> 2.50.1\n>>","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 837ECC328C\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon, 22 Sep 2025 12:07:10 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 609F46B5F3;\n\tMon, 22 Sep 2025 14:07:09 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 408FF62C35\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 22 Sep 2025 14:07:08 +0200 (CEST)","from [192.168.33.12] (185.221.142.115.nat.pool.zt.hu\n\t[185.221.142.115])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 10B44669;\n\tMon, 22 Sep 2025 14:05:44 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"LYjA7tsW\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1758542745;\n\tbh=gHsZKwDXWfu7hLAVJFNt+h0HeBJvcajLjlJtiO8MqK8=;\n\th=Date:Subject:To:Cc:References:From:In-Reply-To:From;\n\tb=LYjA7tsWtxHfmNFGR9VDzuOyvsie0iOmWqmsK8mxWyZzMiCVP6mise9jWsW8Lkixj\n\tGts1mt+o9Y6VN75DclgWh57bygpdnP1xl1HVQQKqBjSjnhhc66iZyguxajZx/D9esj\n\tZnxB10tozX2CPQzXhjxmW+CEA1n147NjrgZt98Ic=","Message-ID":"<457f8734-ea14-4207-b453-1c27f23558a8@ideasonboard.com>","Date":"Mon, 22 Sep 2025 14:07:03 +0200","MIME-Version":"1.0","User-Agent":"Mozilla Thunderbird","Subject":"Re: [RFC PATCH v2 16/22] libcamera: pipeline_handler: Add\n\tmetadataAvailable() function","To":"Paul Elder <paul.elder@ideasonboard.com>,\n\tlibcamera-devel@lists.libcamera.org","Cc":"Jacopo Mondi <jacopo.mondi@ideasonboard.com>","References":"<20250721104622.1550908-1-barnabas.pocze@ideasonboard.com>\n\t<20250721104622.1550908-17-barnabas.pocze@ideasonboard.com>\n\t<175819452207.2127323.9197093205682745730@neptunite.rasen.tech>","From":"=?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= <barnabas.pocze@ideasonboard.com>","Content-Language":"en-US, hu-HU","In-Reply-To":"<175819452207.2127323.9197093205682745730@neptunite.rasen.tech>","Content-Type":"text/plain; charset=UTF-8; format=flowed","Content-Transfer-Encoding":"8bit","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}}]