[{"id":34577,"web_url":"https://patchwork.libcamera.org/comment/34577/","msgid":"<d6tatuwy34wpyil6yvbzcq4jac2tmkyjwipnqwhz4apryeodcu@bd6pelmrwxgj>","date":"2025-06-19T13:57:00","subject":"Re: [RFC PATCH v1 20/23] libcamera: pipeline: rpi: Queue metadata\n\tuntil completion","submitter":{"id":143,"url":"https://patchwork.libcamera.org/api/people/143/","name":"Jacopo Mondi","email":"jacopo.mondi@ideasonboard.com"},"content":"Hi Barnabás\n\nif I'm not mistaken this patch can now be dropped, right ?\n\nOn Fri, Jun 06, 2025 at 06:41:53PM +0200, Barnabás Pőcze wrote:\n> The rpi pipeline drops a certain number of initial frames. It uses\n> `ControlList::clear()` to remove the metadata items of a request that\n> was populated while processing a frame that is ultimately dropped.\n> Since the decision to drop a frame only occurs at the very end of the\n> processing, this stop-gap measure is introduced to delay metadata\n> completion until the request is actually completed.\n>\n> Obsoleted by https://patchwork.libcamera.org/cover/23474/.\n>\n> Signed-off-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com>\n> ---\n>  .../pipeline/rpi/common/pipeline_base.cpp     | 29 +++++++++++--------\n>  .../pipeline/rpi/common/pipeline_base.h       |  4 +--\n>  src/libcamera/pipeline/rpi/pisp/pisp.cpp      |  8 ++---\n>  src/libcamera/pipeline/rpi/vc4/vc4.cpp        |  8 ++---\n>  4 files changed, 27 insertions(+), 22 deletions(-)\n>\n> diff --git a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp\n> index 98507a152..d432cfb51 100644\n> --- a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp\n> +++ b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp\n> @@ -780,7 +780,7 @@ int PipelineHandlerBase::queueRequestDevice(Camera *camera, Request *request)\n>  \t}\n>\n>  \t/* Push the request to the back of the queue. */\n> -\tdata->requestQueue_.push(request);\n> +\tdata->requestQueue_.push({ request, {} });\n>  \tdata->handleState();\n>\n>  \treturn 0;\n> @@ -1232,8 +1232,8 @@ void CameraData::metadataReady(const ControlList &metadata)\n>\n>  \t/* Add to the Request metadata buffer what the IPA has provided. */\n>  \t/* Last thing to do is to fill up the request metadata. */\n> -\tRequest *request = requestQueue_.front();\n> -\trequest->metadata().merge(metadata);\n> +\tControlList &requestMetadata = requestQueue_.front().second;\n> +\trequestMetadata.merge(metadata);\n>\n>  \t/*\n>  \t * Inform the sensor of the latest colour gains if it has the\n> @@ -1392,7 +1392,7 @@ void CameraData::clearIncompleteRequests()\n>  \t * back to the application.\n>  \t */\n>  \twhile (!requestQueue_.empty()) {\n> -\t\tRequest *request = requestQueue_.front();\n> +\t\tauto &[request, metadata] = requestQueue_.front();\n>\n>  \t\tfor (auto &b : request->buffers()) {\n>  \t\t\tFrameBuffer *buffer = b.second;\n> @@ -1406,6 +1406,9 @@ void CameraData::clearIncompleteRequests()\n>  \t\t\t}\n>  \t\t}\n>\n> +\t\t// TODO: need this when cancelled?\n> +\t\trequest->metadata().merge(metadata);\n> +\n>  \t\tpipe()->completeRequest(request);\n>  \t\trequestQueue_.pop();\n>  \t}\n> @@ -1418,7 +1421,7 @@ void CameraData::handleStreamBuffer(FrameBuffer *buffer, RPi::Stream *stream)\n>  \t * that we actually have one to action, otherwise we just return\n>  \t * buffer back to the stream.\n>  \t */\n> -\tRequest *request = requestQueue_.empty() ? nullptr : requestQueue_.front();\n> +\tRequest *request = requestQueue_.empty() ? nullptr : requestQueue_.front().first;\n>  \tif (!dropFrameCount_ && request && request->findBuffer(stream) == buffer) {\n>  \t\t/*\n>  \t\t * Tag the buffer as completed, returning it to the\n> @@ -1471,7 +1474,7 @@ void CameraData::checkRequestCompleted()\n>  \t * change the state to IDLE when ready.\n>  \t */\n>  \tif (!dropFrameCount_) {\n> -\t\tRequest *request = requestQueue_.front();\n> +\t\tauto &[request, metadata] = requestQueue_.front();\n>  \t\tif (request->hasPendingBuffers())\n>  \t\t\treturn;\n>\n> @@ -1482,6 +1485,8 @@ void CameraData::checkRequestCompleted()\n>  \t\tLOG(RPI, Debug) << \"Completing request sequence: \"\n>  \t\t\t\t<< request->sequence();\n>\n> +\t\trequest->metadata().merge(metadata);\n> +\n>  \t\tpipe()->completeRequest(request);\n>  \t\trequestQueue_.pop();\n>  \t\trequestCompleted = true;\n> @@ -1504,10 +1509,10 @@ void CameraData::checkRequestCompleted()\n>  \t}\n>  }\n>\n> -void CameraData::fillRequestMetadata(const ControlList &bufferControls, Request *request)\n> +void CameraData::fillRequestMetadata(const ControlList &bufferControls, ControlList &metadata)\n>  {\n> -\trequest->metadata().set(controls::SensorTimestamp,\n> -\t\t\t\tbufferControls.get(controls::SensorTimestamp).value_or(0));\n> +\tmetadata.set(controls::SensorTimestamp,\n> +\t\t     bufferControls.get(controls::SensorTimestamp).value_or(0));\n>\n>  \tif (cropParams_.size()) {\n>  \t\tstd::vector<Rectangle> crops;\n> @@ -1515,10 +1520,10 @@ void CameraData::fillRequestMetadata(const ControlList &bufferControls, Request\n>  \t\tfor (auto const &[k, v] : cropParams_)\n>  \t\t\tcrops.push_back(scaleIspCrop(v.ispCrop));\n>\n> -\t\trequest->metadata().set(controls::ScalerCrop, crops[0]);\n> +\t\tmetadata.set(controls::ScalerCrop, crops[0]);\n>  \t\tif (crops.size() > 1) {\n> -\t\t\trequest->metadata().set(controls::rpi::ScalerCrops,\n> -\t\t\t\t\t\tSpan<const Rectangle>(crops.data(), crops.size()));\n> +\t\t\tmetadata.set(controls::rpi::ScalerCrops,\n> +\t\t\t\t     Span<const Rectangle>(crops.data(), crops.size()));\n>  \t\t}\n>  \t}\n>  }\n> diff --git a/src/libcamera/pipeline/rpi/common/pipeline_base.h b/src/libcamera/pipeline/rpi/common/pipeline_base.h\n> index aae0c2f35..d3a1bd216 100644\n> --- a/src/libcamera/pipeline/rpi/common/pipeline_base.h\n> +++ b/src/libcamera/pipeline/rpi/common/pipeline_base.h\n> @@ -129,7 +129,7 @@ public:\n>  \t\treturn state_ != State::Stopped && state_ != State::Error;\n>  \t}\n>\n> -\tstd::queue<Request *> requestQueue_;\n> +\tstd::queue<std::pair<Request *, ControlList>> requestQueue_;\n>\n>  \t/* For handling digital zoom. */\n>  \tIPACameraSensorInfo sensorInfo_;\n> @@ -179,7 +179,7 @@ public:\n>\n>  protected:\n>  \tvoid fillRequestMetadata(const ControlList &bufferControls,\n> -\t\t\t\t Request *request);\n> +\t\t\t\t ControlList &metadata);\n>\n>  \tvirtual void tryRunPipeline() = 0;\n>\n> diff --git a/src/libcamera/pipeline/rpi/pisp/pisp.cpp b/src/libcamera/pipeline/rpi/pisp/pisp.cpp\n> index 91e7f4c94..8436cb4fa 100644\n> --- a/src/libcamera/pipeline/rpi/pisp/pisp.cpp\n> +++ b/src/libcamera/pipeline/rpi/pisp/pisp.cpp\n> @@ -2318,7 +2318,7 @@ void PiSPCameraData::tryRunPipeline()\n>  \tCfeJob &job = cfeJobQueue_.front();\n>\n>  \t/* Take the first request from the queue and action the IPA. */\n> -\tRequest *request = requestQueue_.front();\n> +\tauto &[request, metadata] = requestQueue_.front();\n>\n>  \t/* See if a new ScalerCrop value needs to be applied. */\n>  \tapplyScalerCrop(request->controls());\n> @@ -2328,8 +2328,8 @@ void PiSPCameraData::tryRunPipeline()\n>  \t * related controls. We clear it first because the request metadata\n>  \t * may have been populated if we have dropped the previous frame.\n>  \t */\n> -\trequest->metadata().clear();\n> -\tfillRequestMetadata(job.sensorControls, request);\n> +\tmetadata.clear();\n> +\tfillRequestMetadata(job.sensorControls, metadata);\n>\n>  \t/* Set our state to say the pipeline is active. */\n>  \tstate_ = State::Busy;\n> @@ -2347,7 +2347,7 @@ void PiSPCameraData::tryRunPipeline()\n>  \tparams.buffers.bayer = RPi::MaskBayerData | bayerId;\n>  \tparams.buffers.stats = RPi::MaskStats | statsId;\n>  \tparams.buffers.embedded = 0;\n> -\tparams.ipaContext = requestQueue_.front()->sequence();\n> +\tparams.ipaContext = requestQueue_.front().first->sequence();\n>  \tparams.delayContext = job.delayContext;\n>  \tparams.sensorControls = std::move(job.sensorControls);\n>  \tparams.requestControls = request->controls();\n> diff --git a/src/libcamera/pipeline/rpi/vc4/vc4.cpp b/src/libcamera/pipeline/rpi/vc4/vc4.cpp\n> index fe910bdf2..a311f43a4 100644\n> --- a/src/libcamera/pipeline/rpi/vc4/vc4.cpp\n> +++ b/src/libcamera/pipeline/rpi/vc4/vc4.cpp\n> @@ -836,7 +836,7 @@ void Vc4CameraData::ispOutputDequeue(FrameBuffer *buffer)\n>  \tif (stream == &isp_[Isp::Stats]) {\n>  \t\tipa::RPi::ProcessParams params;\n>  \t\tparams.buffers.stats = index | RPi::MaskStats;\n> -\t\tparams.ipaContext = requestQueue_.front()->sequence();\n> +\t\tparams.ipaContext = requestQueue_.front().first->sequence();\n>  \t\tipa_->processStats(params);\n>  \t} else {\n>  \t\t/* Any other ISP output can be handed back to the application now. */\n> @@ -935,7 +935,7 @@ void Vc4CameraData::tryRunPipeline()\n>  \t\treturn;\n>\n>  \t/* Take the first request from the queue and action the IPA. */\n> -\tRequest *request = requestQueue_.front();\n> +\tauto &[request, metadata] = requestQueue_.front();\n>\n>  \t/* See if a new ScalerCrop value needs to be applied. */\n>  \tapplyScalerCrop(request->controls());\n> @@ -945,8 +945,8 @@ void Vc4CameraData::tryRunPipeline()\n>  \t * related controls. We clear it first because the request metadata\n>  \t * may have been populated if we have dropped the previous frame.\n>  \t */\n> -\trequest->metadata().clear();\n> -\tfillRequestMetadata(bayerFrame.controls, request);\n> +\tmetadata.clear();\n> +\tfillRequestMetadata(bayerFrame.controls, metadata);\n>\n>  \t/* Set our state to say the pipeline is active. */\n>  \tstate_ = State::Busy;\n> --\n> 2.49.0\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 79466C3237\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu, 19 Jun 2025 13:57:05 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 2E32668DE3;\n\tThu, 19 Jun 2025 15:57:05 +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 71D0768DDB\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 19 Jun 2025 15:57:03 +0200 (CEST)","from ideasonboard.com (93-61-96-190.ip145.fastwebnet.it\n\t[93.61.96.190])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id AACA42EC;\n\tThu, 19 Jun 2025 15:56: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=\"LDnxnHNY\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1750341409;\n\tbh=taXjWPhJo/uJ3Lg/7egiz7RBuXs0QRPKBrqnKQa/7Fk=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=LDnxnHNYy7fEOeIVIKZTP6Ua1JKjuH2X9ydZ1STiiQXDUUOqKJ+r9t8DEBF0EG3HQ\n\tS1MT8oe0R9BoQHOJOXy62JE6NoSr0qb+U41x5AGvLqfedrNMx+SxKLeClF2yiM/moe\n\tO0QJdQkO1MekTZrXE0kEqMWOkdxPjSmPiISRdqBI=","Date":"Thu, 19 Jun 2025 15:57:00 +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","Subject":"Re: [RFC PATCH v1 20/23] libcamera: pipeline: rpi: Queue metadata\n\tuntil completion","Message-ID":"<d6tatuwy34wpyil6yvbzcq4jac2tmkyjwipnqwhz4apryeodcu@bd6pelmrwxgj>","References":"<20250606164156.1442682-1-barnabas.pocze@ideasonboard.com>\n\t<20250606164156.1442682-21-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":"<20250606164156.1442682-21-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":34578,"web_url":"https://patchwork.libcamera.org/comment/34578/","msgid":"<1c2e8fce-c468-405e-8896-fd9df93d24b9@ideasonboard.com>","date":"2025-06-19T13:57:49","subject":"Re: [RFC PATCH v1 20/23] libcamera: pipeline: rpi: Queue metadata\n\tuntil completion","submitter":{"id":216,"url":"https://patchwork.libcamera.org/api/people/216/","name":"Barnabás Pőcze","email":"barnabas.pocze@ideasonboard.com"},"content":"2025. 06. 19. 15:57 keltezéssel, Jacopo Mondi írta:\n> Hi Barnabás\n> \n> if I'm not mistaken this patch can now be dropped, right ?\n\nYes.\n\n\n> \n> On Fri, Jun 06, 2025 at 06:41:53PM +0200, Barnabás Pőcze wrote:\n>> The rpi pipeline drops a certain number of initial frames. It uses\n>> `ControlList::clear()` to remove the metadata items of a request that\n>> was populated while processing a frame that is ultimately dropped.\n>> Since the decision to drop a frame only occurs at the very end of the\n>> processing, this stop-gap measure is introduced to delay metadata\n>> completion until the request is actually completed.\n>>\n>> Obsoleted by https://patchwork.libcamera.org/cover/23474/.\n>>\n>> Signed-off-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com>\n>> ---\n>>   .../pipeline/rpi/common/pipeline_base.cpp     | 29 +++++++++++--------\n>>   .../pipeline/rpi/common/pipeline_base.h       |  4 +--\n>>   src/libcamera/pipeline/rpi/pisp/pisp.cpp      |  8 ++---\n>>   src/libcamera/pipeline/rpi/vc4/vc4.cpp        |  8 ++---\n>>   4 files changed, 27 insertions(+), 22 deletions(-)\n>>\n>> diff --git a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp\n>> index 98507a152..d432cfb51 100644\n>> --- a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp\n>> +++ b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp\n>> @@ -780,7 +780,7 @@ int PipelineHandlerBase::queueRequestDevice(Camera *camera, Request *request)\n>>   \t}\n>>\n>>   \t/* Push the request to the back of the queue. */\n>> -\tdata->requestQueue_.push(request);\n>> +\tdata->requestQueue_.push({ request, {} });\n>>   \tdata->handleState();\n>>\n>>   \treturn 0;\n>> @@ -1232,8 +1232,8 @@ void CameraData::metadataReady(const ControlList &metadata)\n>>\n>>   \t/* Add to the Request metadata buffer what the IPA has provided. */\n>>   \t/* Last thing to do is to fill up the request metadata. */\n>> -\tRequest *request = requestQueue_.front();\n>> -\trequest->metadata().merge(metadata);\n>> +\tControlList &requestMetadata = requestQueue_.front().second;\n>> +\trequestMetadata.merge(metadata);\n>>\n>>   \t/*\n>>   \t * Inform the sensor of the latest colour gains if it has the\n>> @@ -1392,7 +1392,7 @@ void CameraData::clearIncompleteRequests()\n>>   \t * back to the application.\n>>   \t */\n>>   \twhile (!requestQueue_.empty()) {\n>> -\t\tRequest *request = requestQueue_.front();\n>> +\t\tauto &[request, metadata] = requestQueue_.front();\n>>\n>>   \t\tfor (auto &b : request->buffers()) {\n>>   \t\t\tFrameBuffer *buffer = b.second;\n>> @@ -1406,6 +1406,9 @@ void CameraData::clearIncompleteRequests()\n>>   \t\t\t}\n>>   \t\t}\n>>\n>> +\t\t// TODO: need this when cancelled?\n>> +\t\trequest->metadata().merge(metadata);\n>> +\n>>   \t\tpipe()->completeRequest(request);\n>>   \t\trequestQueue_.pop();\n>>   \t}\n>> @@ -1418,7 +1421,7 @@ void CameraData::handleStreamBuffer(FrameBuffer *buffer, RPi::Stream *stream)\n>>   \t * that we actually have one to action, otherwise we just return\n>>   \t * buffer back to the stream.\n>>   \t */\n>> -\tRequest *request = requestQueue_.empty() ? nullptr : requestQueue_.front();\n>> +\tRequest *request = requestQueue_.empty() ? nullptr : requestQueue_.front().first;\n>>   \tif (!dropFrameCount_ && request && request->findBuffer(stream) == buffer) {\n>>   \t\t/*\n>>   \t\t * Tag the buffer as completed, returning it to the\n>> @@ -1471,7 +1474,7 @@ void CameraData::checkRequestCompleted()\n>>   \t * change the state to IDLE when ready.\n>>   \t */\n>>   \tif (!dropFrameCount_) {\n>> -\t\tRequest *request = requestQueue_.front();\n>> +\t\tauto &[request, metadata] = requestQueue_.front();\n>>   \t\tif (request->hasPendingBuffers())\n>>   \t\t\treturn;\n>>\n>> @@ -1482,6 +1485,8 @@ void CameraData::checkRequestCompleted()\n>>   \t\tLOG(RPI, Debug) << \"Completing request sequence: \"\n>>   \t\t\t\t<< request->sequence();\n>>\n>> +\t\trequest->metadata().merge(metadata);\n>> +\n>>   \t\tpipe()->completeRequest(request);\n>>   \t\trequestQueue_.pop();\n>>   \t\trequestCompleted = true;\n>> @@ -1504,10 +1509,10 @@ void CameraData::checkRequestCompleted()\n>>   \t}\n>>   }\n>>\n>> -void CameraData::fillRequestMetadata(const ControlList &bufferControls, Request *request)\n>> +void CameraData::fillRequestMetadata(const ControlList &bufferControls, ControlList &metadata)\n>>   {\n>> -\trequest->metadata().set(controls::SensorTimestamp,\n>> -\t\t\t\tbufferControls.get(controls::SensorTimestamp).value_or(0));\n>> +\tmetadata.set(controls::SensorTimestamp,\n>> +\t\t     bufferControls.get(controls::SensorTimestamp).value_or(0));\n>>\n>>   \tif (cropParams_.size()) {\n>>   \t\tstd::vector<Rectangle> crops;\n>> @@ -1515,10 +1520,10 @@ void CameraData::fillRequestMetadata(const ControlList &bufferControls, Request\n>>   \t\tfor (auto const &[k, v] : cropParams_)\n>>   \t\t\tcrops.push_back(scaleIspCrop(v.ispCrop));\n>>\n>> -\t\trequest->metadata().set(controls::ScalerCrop, crops[0]);\n>> +\t\tmetadata.set(controls::ScalerCrop, crops[0]);\n>>   \t\tif (crops.size() > 1) {\n>> -\t\t\trequest->metadata().set(controls::rpi::ScalerCrops,\n>> -\t\t\t\t\t\tSpan<const Rectangle>(crops.data(), crops.size()));\n>> +\t\t\tmetadata.set(controls::rpi::ScalerCrops,\n>> +\t\t\t\t     Span<const Rectangle>(crops.data(), crops.size()));\n>>   \t\t}\n>>   \t}\n>>   }\n>> diff --git a/src/libcamera/pipeline/rpi/common/pipeline_base.h b/src/libcamera/pipeline/rpi/common/pipeline_base.h\n>> index aae0c2f35..d3a1bd216 100644\n>> --- a/src/libcamera/pipeline/rpi/common/pipeline_base.h\n>> +++ b/src/libcamera/pipeline/rpi/common/pipeline_base.h\n>> @@ -129,7 +129,7 @@ public:\n>>   \t\treturn state_ != State::Stopped && state_ != State::Error;\n>>   \t}\n>>\n>> -\tstd::queue<Request *> requestQueue_;\n>> +\tstd::queue<std::pair<Request *, ControlList>> requestQueue_;\n>>\n>>   \t/* For handling digital zoom. */\n>>   \tIPACameraSensorInfo sensorInfo_;\n>> @@ -179,7 +179,7 @@ public:\n>>\n>>   protected:\n>>   \tvoid fillRequestMetadata(const ControlList &bufferControls,\n>> -\t\t\t\t Request *request);\n>> +\t\t\t\t ControlList &metadata);\n>>\n>>   \tvirtual void tryRunPipeline() = 0;\n>>\n>> diff --git a/src/libcamera/pipeline/rpi/pisp/pisp.cpp b/src/libcamera/pipeline/rpi/pisp/pisp.cpp\n>> index 91e7f4c94..8436cb4fa 100644\n>> --- a/src/libcamera/pipeline/rpi/pisp/pisp.cpp\n>> +++ b/src/libcamera/pipeline/rpi/pisp/pisp.cpp\n>> @@ -2318,7 +2318,7 @@ void PiSPCameraData::tryRunPipeline()\n>>   \tCfeJob &job = cfeJobQueue_.front();\n>>\n>>   \t/* Take the first request from the queue and action the IPA. */\n>> -\tRequest *request = requestQueue_.front();\n>> +\tauto &[request, metadata] = requestQueue_.front();\n>>\n>>   \t/* See if a new ScalerCrop value needs to be applied. */\n>>   \tapplyScalerCrop(request->controls());\n>> @@ -2328,8 +2328,8 @@ void PiSPCameraData::tryRunPipeline()\n>>   \t * related controls. We clear it first because the request metadata\n>>   \t * may have been populated if we have dropped the previous frame.\n>>   \t */\n>> -\trequest->metadata().clear();\n>> -\tfillRequestMetadata(job.sensorControls, request);\n>> +\tmetadata.clear();\n>> +\tfillRequestMetadata(job.sensorControls, metadata);\n>>\n>>   \t/* Set our state to say the pipeline is active. */\n>>   \tstate_ = State::Busy;\n>> @@ -2347,7 +2347,7 @@ void PiSPCameraData::tryRunPipeline()\n>>   \tparams.buffers.bayer = RPi::MaskBayerData | bayerId;\n>>   \tparams.buffers.stats = RPi::MaskStats | statsId;\n>>   \tparams.buffers.embedded = 0;\n>> -\tparams.ipaContext = requestQueue_.front()->sequence();\n>> +\tparams.ipaContext = requestQueue_.front().first->sequence();\n>>   \tparams.delayContext = job.delayContext;\n>>   \tparams.sensorControls = std::move(job.sensorControls);\n>>   \tparams.requestControls = request->controls();\n>> diff --git a/src/libcamera/pipeline/rpi/vc4/vc4.cpp b/src/libcamera/pipeline/rpi/vc4/vc4.cpp\n>> index fe910bdf2..a311f43a4 100644\n>> --- a/src/libcamera/pipeline/rpi/vc4/vc4.cpp\n>> +++ b/src/libcamera/pipeline/rpi/vc4/vc4.cpp\n>> @@ -836,7 +836,7 @@ void Vc4CameraData::ispOutputDequeue(FrameBuffer *buffer)\n>>   \tif (stream == &isp_[Isp::Stats]) {\n>>   \t\tipa::RPi::ProcessParams params;\n>>   \t\tparams.buffers.stats = index | RPi::MaskStats;\n>> -\t\tparams.ipaContext = requestQueue_.front()->sequence();\n>> +\t\tparams.ipaContext = requestQueue_.front().first->sequence();\n>>   \t\tipa_->processStats(params);\n>>   \t} else {\n>>   \t\t/* Any other ISP output can be handed back to the application now. */\n>> @@ -935,7 +935,7 @@ void Vc4CameraData::tryRunPipeline()\n>>   \t\treturn;\n>>\n>>   \t/* Take the first request from the queue and action the IPA. */\n>> -\tRequest *request = requestQueue_.front();\n>> +\tauto &[request, metadata] = requestQueue_.front();\n>>\n>>   \t/* See if a new ScalerCrop value needs to be applied. */\n>>   \tapplyScalerCrop(request->controls());\n>> @@ -945,8 +945,8 @@ void Vc4CameraData::tryRunPipeline()\n>>   \t * related controls. We clear it first because the request metadata\n>>   \t * may have been populated if we have dropped the previous frame.\n>>   \t */\n>> -\trequest->metadata().clear();\n>> -\tfillRequestMetadata(bayerFrame.controls, request);\n>> +\tmetadata.clear();\n>> +\tfillRequestMetadata(bayerFrame.controls, metadata);\n>>\n>>   \t/* Set our state to say the pipeline is active. */\n>>   \tstate_ = State::Busy;\n>> --\n>> 2.49.0\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 763E0C3237\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu, 19 Jun 2025 13:57:54 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 3328D68DE3;\n\tThu, 19 Jun 2025 15:57:54 +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 C613C68DDB\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 19 Jun 2025 15:57:52 +0200 (CEST)","from [192.168.33.22] (185.221.143.107.nat.pool.zt.hu\n\t[185.221.143.107])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id E586999F;\n\tThu, 19 Jun 2025 15:57:38 +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=\"WOXO1u/+\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1750341459;\n\tbh=bzwFM68crwrLwiAUPms8VOVx8Qt4L/bpTOUEjeVWn5o=;\n\th=Date:Subject:To:Cc:References:From:In-Reply-To:From;\n\tb=WOXO1u/+P905hGbpR+oNRNXNMRoaIGyGE6MEpclfVJxukZaIQ59486duTJXF6MtvK\n\tQcpt9Xij22KnoP8nd07CM1dxcvf9Xkn177mU8vY5vqeZI58Dt+klxEI6XSUoMqacdv\n\tQ0jj2f6/bv5Q1Lvt8YVyRCcYp/GSrgJjMmb/hMGY=","Message-ID":"<1c2e8fce-c468-405e-8896-fd9df93d24b9@ideasonboard.com>","Date":"Thu, 19 Jun 2025 15:57:49 +0200","MIME-Version":"1.0","User-Agent":"Mozilla Thunderbird","Subject":"Re: [RFC PATCH v1 20/23] libcamera: pipeline: rpi: Queue metadata\n\tuntil completion","To":"Jacopo Mondi <jacopo.mondi@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","References":"<20250606164156.1442682-1-barnabas.pocze@ideasonboard.com>\n\t<20250606164156.1442682-21-barnabas.pocze@ideasonboard.com>\n\t<d6tatuwy34wpyil6yvbzcq4jac2tmkyjwipnqwhz4apryeodcu@bd6pelmrwxgj>","From":"=?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= <barnabas.pocze@ideasonboard.com>","Content-Language":"en-US, hu-HU","In-Reply-To":"<d6tatuwy34wpyil6yvbzcq4jac2tmkyjwipnqwhz4apryeodcu@bd6pelmrwxgj>","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>"}}]