[{"id":35303,"web_url":"https://patchwork.libcamera.org/comment/35303/","msgid":"<kmncz4cqwc2y2vnq2oqo3yvcabnvpz4elwhgk4f2tc4752fdzc@6mn5mowwheks>","date":"2025-08-08T04:36:36","subject":"Re: [PATCH v12 8/8] libcamera: simple: Make raw streams working","submitter":{"id":232,"url":"https://patchwork.libcamera.org/api/people/232/","name":"Umang Jain","email":"uajain@igalia.com"},"content":"On Mon, Aug 04, 2025 at 06:38:11PM +0200, Milan Zamazal wrote:\n> When a raw stream is requested, whether alone or together with a\n> processed stream, its buffers must be handled outside the software ISP\n> machinery.  They serve as output buffers, even when a processed stream\n> is produced.\n> \n> At most one raw stream and at most one processed stream are supported\n> and can be combined.  An example of producing both raw and processed\n> files using `cam' application:\n> \n>   cam -c1 -C100 -Ffile# \\\n>     -s role=viewfinder,width=1920,height=1080,pixelformat=RGB888 \\\n>     -s role=raw,width=3280,height=2464,pixelformat=SRGGB8 \\\n> \n> Note the difference in viewfinder and raw stream sizes due to the fact\n> that debayering requires enlarging the image width, which enforces\n> selecting a larger sensor resolution in this case.\n> \n> In order to track whether a raw stream is requested and which one it is,\n> SimpleCameraData::rawStream_ member variable is introduced.\n> \n> This is the final step to make raw streams working.\n> \n> Signed-off-by: Milan Zamazal <mzamazal@redhat.com>\n> ---\n>  src/libcamera/pipeline/simple/simple.cpp | 55 ++++++++++++++++++------\n>  1 file changed, 41 insertions(+), 14 deletions(-)\n> \n> diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp\n> index e5449cd2e..d854d6a72 100644\n> --- a/src/libcamera/pipeline/simple/simple.cpp\n> +++ b/src/libcamera/pipeline/simple/simple.cpp\n> @@ -330,6 +330,7 @@ public:\n>  \t};\n>  \n>  \tstd::vector<Stream> streams_;\n> +\tStream *rawStream_;\n>  \n>  \t/*\n>  \t * All entities in the pipeline, from the camera sensor to the video\n> @@ -368,6 +369,11 @@ private:\n>  \tvoid ispStatsReady(uint32_t frame, uint32_t bufferId);\n>  \tvoid metadataReady(uint32_t frame, const ControlList &metadata);\n>  \tvoid setSensorControls(const ControlList &sensorControls);\n> +\n> +\tbool processedRequested() const\n> +\t{\n> +\t\treturn streams_.size() - (rawStream_ ? 1 : 0) > 0;\n> +\t}\n>  };\n>  \n>  class SimpleCameraConfiguration : public CameraConfiguration\n> @@ -460,7 +466,7 @@ private:\n>  SimpleCameraData::SimpleCameraData(SimplePipelineHandler *pipe,\n>  \t\t\t\t   unsigned int numStreams,\n>  \t\t\t\t   MediaEntity *sensor)\n> -\t: Camera::Private(pipe), streams_(numStreams)\n> +\t: Camera::Private(pipe), streams_(numStreams), rawStream_(nullptr)\n>  {\n>  \t/*\n>  \t * Find the shortest path from the camera sensor to a video capture\n> @@ -871,10 +877,13 @@ void SimpleCameraData::imageBufferReady(FrameBuffer *buffer)\n>  \t * point converting an erroneous buffer.\n>  \t */\n>  \tif (buffer->metadata().status != FrameMetadata::FrameSuccess) {\n> -\t\tif (!useConversion_) {\n> +\t\tif (rawStream_) {\n>  \t\t\t/* No conversion, just complete the request. */\n>  \t\t\tRequest *request = buffer->request();\n>  \t\t\tpipe->completeBuffer(request, buffer);\n> +\t\t\tSimpleFrameInfo *info = frameInfo_.find(request->sequence());\n> +\t\t\tif (info)\n> +\t\t\t\tinfo->metadataRequired = false;\n>  \t\t\ttryCompleteRequest(request);\n>  \t\t\treturn;\n>  \t\t}\n> @@ -884,7 +893,8 @@ void SimpleCameraData::imageBufferReady(FrameBuffer *buffer)\n>  \t\t * buffer for capture (unless the stream is being stopped), and\n>  \t\t * complete the request with all the user-facing buffers.\n>  \t\t */\n> -\t\tif (buffer->metadata().status != FrameMetadata::FrameCancelled)\n> +\t\tif (buffer->metadata().status != FrameMetadata::FrameCancelled &&\n> +\t\t    !rawStream_)\n>  \t\t\tvideo_->queueBuffer(buffer);\n>  \n>  \t\tif (conversionQueue_.empty())\n> @@ -933,13 +943,14 @@ void SimpleCameraData::imageBufferReady(FrameBuffer *buffer)\n>  \t */\n>  \tif (useConversion_) {\n>  \t\tif (conversionQueue_.empty()) {\n> -\t\t\tvideo_->queueBuffer(buffer);\n> +\t\t\tif (!rawStream_)\n> +\t\t\t\tvideo_->queueBuffer(buffer);\n>  \t\t\treturn;\n>  \t\t}\n>  \n>  \t\tif (converter_)\n>  \t\t\tconverter_->queueBuffers(buffer, conversionQueue_.front().outputs);\n> -\t\telse\n> +\t\telse if (processedRequested())\n>  \t\t\t/*\n>  \t\t\t * request->sequence() cannot be retrieved from `buffer' inside\n>  \t\t\t * queueBuffers because unique_ptr's make buffer->request() invalid\n> @@ -949,6 +960,8 @@ void SimpleCameraData::imageBufferReady(FrameBuffer *buffer)\n>  \t\t\t\t\t     conversionQueue_.front().outputs);\n>  \n>  \t\tconversionQueue_.pop();\n> +\t\tif (rawStream_)\n> +\t\t\tpipe->completeBuffer(request, buffer);\n>  \t\treturn;\n>  \t}\n>  \n> @@ -986,7 +999,8 @@ void SimpleCameraData::tryCompleteRequest(Request *request)\n>  void SimpleCameraData::conversionInputDone(FrameBuffer *buffer)\n>  {\n>  \t/* Queue the input buffer back for capture. */\n> -\tvideo_->queueBuffer(buffer);\n> +\tif (!rawStream_)\n> +\t\tvideo_->queueBuffer(buffer);\n>  }\n>  \n>  void SimpleCameraData::conversionOutputDone(FrameBuffer *buffer)\n> @@ -1499,11 +1513,20 @@ int SimplePipelineHandler::configure(Camera *camera, CameraConfiguration *c)\n>  \n>  \tfor (unsigned int i = 0; i < config->size(); ++i) {\n>  \t\tStreamConfiguration &cfg = config->at(i);\n> +\t\tbool rawStream = isRaw(cfg);\n>  \n>  \t\tcfg.setStream(&data->streams_[i]);\n>  \n> -\t\tif (data->useConversion_ && !isRaw(cfg))\n> +\t\tif (data->useConversion_ && !rawStream)\n>  \t\t\toutputCfgs.push_back(cfg);\n> +\n> +\t\tif (rawStream) {\n> +\t\t\tif (data->rawStream_) {\n> +\t\t\t\tLOG(SimplePipeline, Error) << \"Multiple raw streams not supported\";\n> +\t\t\t\treturn -EINVAL;\n> +\t\t\t}\n\nThere are 3 places you try to do this validation:\n\n- generateConfiguration 3/8\n- in validate() 4/8\n\nand now here in configure(). Please refer to the following doc from\nPipelineHandler::configure()\n\n * The configuration is guaranteed to have been validated with\n * CameraConfiguration::validate(). The pipeline handler implementation shall\n * not perform further validation and may rely on any custom field stored in its\n * custom CameraConfiguration derived class.\n\nMy question here is why? Is it something I am not understanding with this\nseries? There are more comments, the ones I have already comments in\nprevious iterations - which you might have chose to ignore (and that's\nfine), but still I think the series can be simplied that will gain a\nvery straight-forward review relatively quickly.\n\n\n> +\t\t\tdata->rawStream_ = &data->streams_[i];\n> +\t\t}\n>  \t}\n>  \n>  \tif (outputCfgs.empty())\n> @@ -1534,7 +1557,7 @@ int SimplePipelineHandler::exportFrameBuffers(Camera *camera, Stream *stream,\n>  \t * Export buffers on the converter or capture video node, depending on\n>  \t * whether the converter is used or not.\n>  \t */\n> -\tif (data->useConversion_)\n> +\tif (data->useConversion_ && stream != data->rawStream_)\n>  \t\treturn data->converter_\n>  \t\t\t       ? data->converter_->exportBuffers(stream, count, buffers)\n>  \t\t\t       : data->swIsp_->exportBuffers(stream, count, buffers);\n> @@ -1557,7 +1580,7 @@ int SimplePipelineHandler::start(Camera *camera, [[maybe_unused]] const ControlL\n>  \t\treturn -EBUSY;\n>  \t}\n>  \n> -\tif (data->useConversion_) {\n> +\tif (data->useConversion_ && !data->rawStream_) {\n>  \t\t/*\n>  \t\t * When using the converter allocate a fixed number of internal\n>  \t\t * buffers.\n> @@ -1565,8 +1588,11 @@ int SimplePipelineHandler::start(Camera *camera, [[maybe_unused]] const ControlL\n>  \t\tret = video->allocateBuffers(kNumInternalBuffers,\n>  \t\t\t\t\t     &data->conversionBuffers_);\n>  \t} else {\n> -\t\t/* Otherwise, prepare for using buffers from the only stream. */\n> -\t\tStream *stream = &data->streams_[0];\n> +\t\t/*\n> +\t\t * Otherwise, prepare for using buffers from either the raw stream, if\n> +\t\t * requested, or the only stream configured.\n> +\t\t */\n> +\t\tStream *stream = (data->rawStream_ ? data->rawStream_ : &data->streams_[0]);\n>  \t\tret = video->importBuffers(stream->configuration().bufferCount);\n>  \t}\n>  \tif (ret < 0) {\n> @@ -1607,8 +1633,9 @@ int SimplePipelineHandler::start(Camera *camera, [[maybe_unused]] const ControlL\n>  \t\t}\n>  \n>  \t\t/* Queue all internal buffers for capture. */\n> -\t\tfor (std::unique_ptr<FrameBuffer> &buffer : data->conversionBuffers_)\n> -\t\t\tvideo->queueBuffer(buffer.get());\n> +\t\tif (!data->rawStream_)\n> +\t\t\tfor (std::unique_ptr<FrameBuffer> &buffer : data->conversionBuffers_)\n> +\t\t\t\tvideo->queueBuffer(buffer.get());\n>  \t}\n>  \n>  \treturn 0;\n> @@ -1659,7 +1686,7 @@ int SimplePipelineHandler::queueRequestDevice(Camera *camera, Request *request)\n>  \t\t * queue, it will be handed to the converter in the capture\n>  \t\t * completion handler.\n>  \t\t */\n> -\t\tif (data->useConversion_) {\n> +\t\tif (data->useConversion_ && stream != data->rawStream_) {\n>  \t\t\tbuffers.emplace(stream, buffer);\n>  \t\t\tmetadataRequired = !!data->swIsp_;\n>  \t\t} else {\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 D624EBE086\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri,  8 Aug 2025 04:36:31 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 0A72C6921A;\n\tFri,  8 Aug 2025 06:36:31 +0200 (CEST)","from fanzine2.igalia.com (fanzine2.igalia.com [213.97.179.56])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 85D6961460\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri,  8 Aug 2025 06:36:28 +0200 (CEST)","from [49.36.71.143] (helo=uajain)\n\tby fanzine2.igalia.com with esmtpsa \n\t(Cipher TLS1.3:ECDHE_SECP256R1__RSA_PSS_RSAE_SHA256__AES_256_GCM:256)\n\t(Exim) id 1ukEqA-00BLce-Ef; Fri, 08 Aug 2025 06:36:26 +0200"],"Authentication-Results":"lancelot.ideasonboard.com;\n\tdkim=fail reason=\"signature verification failed\" (2048-bit key;\n\tunprotected) header.d=igalia.com header.i=@igalia.com\n\theader.b=\"N2/MeGnc\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=igalia.com;\n\ts=20170329;\n\th=In-Reply-To:Content-Type:MIME-Version:References:Message-ID:\n\tSubject:Cc:From:Date:Sender:Reply-To:To:Content-Transfer-Encoding:Content-ID:\n\tContent-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc\n\t:Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe:\n\tList-Post:List-Owner:List-Archive;\n\tbh=sr/c8LP2qf37xKvnFXicNH1WVGqc4tnbj9Yz1skToOE=;\n\tb=N2/MeGncz9o5DfTRQ3P0Cf8heT\n\tirYqZ9harKF3ztDaVwwc3wWfZpCy983EWlcyLyc0HffBRnpx3+rhXdOrS/YEZBmHH2ycYMAGXQfvv\n\t3wpyOMOaT4vCf9PMMmCnqflGybQ78m2cb7KhuH/GBl3MJkbdcU+r6ud5JgjDVdRVMDRZrWz5ReHXq\n\tduIisxMlG+O+SJkQFJCjBa4lVv6MbmJve76MfjBWn/uzvUZ43W2BrkuwCvpRnmW0i1OJT6I4gzKQr\n\tLEuUrKLXmbFmAmX6pGadDsPRviYDrt7Qj1HStOcGPTBkCHQOFZFnWJ9wZDOa6iLkhgM5jI5QZyesA\n\tYSwNJkFg==;","Date":"Fri, 8 Aug 2025 10:06:36 +0530","From":"Umang Jain <uajain@igalia.com>","Cc":"libcamera-devel@lists.libcamera.org, Laurent Pinchart\n\t<laurent.pinchart@ideasonboard.com>, Kieran Bingham\n\t<kieran.bingham@ideasonboard.com>, =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?=\n\t<barnabas.pocze@ideasonboard.com>, Paul Elder\n\t<paul.elder@ideasonboard.com>","Subject":"Re: [PATCH v12 8/8] libcamera: simple: Make raw streams working","Message-ID":"<kmncz4cqwc2y2vnq2oqo3yvcabnvpz4elwhgk4f2tc4752fdzc@6mn5mowwheks>","References":"<20250804163812.126022-1-mzamazal@redhat.com>\n\t<20250804163812.126022-9-mzamazal@redhat.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=us-ascii","Content-Disposition":"inline","In-Reply-To":"<20250804163812.126022-9-mzamazal@redhat.com>","User-Agent":"NeoMutt/20250510-dirty","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":35370,"web_url":"https://patchwork.libcamera.org/comment/35370/","msgid":"<85a543zf37.fsf@mzamazal-thinkpadp1gen7.tpbc.csb>","date":"2025-08-13T10:33:00","subject":"Re: [PATCH v12 8/8] libcamera: simple: Make raw streams working","submitter":{"id":177,"url":"https://patchwork.libcamera.org/api/people/177/","name":"Milan Zamazal","email":"mzamazal@redhat.com"},"content":"Hi Umang,\n\nUmang Jain <uajain@igalia.com> writes:\n\n> On Mon, Aug 04, 2025 at 06:38:11PM +0200, Milan Zamazal wrote:\n>> When a raw stream is requested, whether alone or together with a\n>> processed stream, its buffers must be handled outside the software ISP\n>\n>> machinery.  They serve as output buffers, even when a processed stream\n>> is produced.\n>> \n>> At most one raw stream and at most one processed stream are supported\n>> and can be combined.  An example of producing both raw and processed\n>> files using `cam' application:\n>> \n>>   cam -c1 -C100 -Ffile# \\\n>>     -s role=viewfinder,width=1920,height=1080,pixelformat=RGB888 \\\n>>     -s role=raw,width=3280,height=2464,pixelformat=SRGGB8 \\\n>> \n>> Note the difference in viewfinder and raw stream sizes due to the fact\n>> that debayering requires enlarging the image width, which enforces\n>> selecting a larger sensor resolution in this case.\n>> \n>> In order to track whether a raw stream is requested and which one it is,\n>> SimpleCameraData::rawStream_ member variable is introduced.\n>> \n>> This is the final step to make raw streams working.\n>> \n>> Signed-off-by: Milan Zamazal <mzamazal@redhat.com>\n>> ---\n>>  src/libcamera/pipeline/simple/simple.cpp | 55 ++++++++++++++++++------\n>>  1 file changed, 41 insertions(+), 14 deletions(-)\n>> \n>> diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp\n>> index e5449cd2e..d854d6a72 100644\n>> --- a/src/libcamera/pipeline/simple/simple.cpp\n>> +++ b/src/libcamera/pipeline/simple/simple.cpp\n>> @@ -330,6 +330,7 @@ public:\n>>  \t};\n>>  \n>>  \tstd::vector<Stream> streams_;\n>> +\tStream *rawStream_;\n>>  \n>>  \t/*\n>>  \t * All entities in the pipeline, from the camera sensor to the video\n>> @@ -368,6 +369,11 @@ private:\n>>  \tvoid ispStatsReady(uint32_t frame, uint32_t bufferId);\n>>  \tvoid metadataReady(uint32_t frame, const ControlList &metadata);\n>>  \tvoid setSensorControls(const ControlList &sensorControls);\n>> +\n>> +\tbool processedRequested() const\n>> +\t{\n>> +\t\treturn streams_.size() - (rawStream_ ? 1 : 0) > 0;\n>> +\t}\n>>  };\n>>  \n>>  class SimpleCameraConfiguration : public CameraConfiguration\n>> @@ -460,7 +466,7 @@ private:\n>>  SimpleCameraData::SimpleCameraData(SimplePipelineHandler *pipe,\n>>  \t\t\t\t   unsigned int numStreams,\n>>  \t\t\t\t   MediaEntity *sensor)\n>> -\t: Camera::Private(pipe), streams_(numStreams)\n>> +\t: Camera::Private(pipe), streams_(numStreams), rawStream_(nullptr)\n>>  {\n>>  \t/*\n>>  \t * Find the shortest path from the camera sensor to a video capture\n>> @@ -871,10 +877,13 @@ void SimpleCameraData::imageBufferReady(FrameBuffer *buffer)\n>>  \t * point converting an erroneous buffer.\n>>  \t */\n>>  \tif (buffer->metadata().status != FrameMetadata::FrameSuccess) {\n>> -\t\tif (!useConversion_) {\n>> +\t\tif (rawStream_) {\n>>  \t\t\t/* No conversion, just complete the request. */\n>>  \t\t\tRequest *request = buffer->request();\n>>  \t\t\tpipe->completeBuffer(request, buffer);\n>> +\t\t\tSimpleFrameInfo *info = frameInfo_.find(request->sequence());\n>> +\t\t\tif (info)\n>> +\t\t\t\tinfo->metadataRequired = false;\n>>  \t\t\ttryCompleteRequest(request);\n>>  \t\t\treturn;\n>>  \t\t}\n>> @@ -884,7 +893,8 @@ void SimpleCameraData::imageBufferReady(FrameBuffer *buffer)\n>>  \t\t * buffer for capture (unless the stream is being stopped), and\n>>  \t\t * complete the request with all the user-facing buffers.\n>>  \t\t */\n>> -\t\tif (buffer->metadata().status != FrameMetadata::FrameCancelled)\n>> +\t\tif (buffer->metadata().status != FrameMetadata::FrameCancelled &&\n>> +\t\t    !rawStream_)\n>>  \t\t\tvideo_->queueBuffer(buffer);\n>>  \n>>  \t\tif (conversionQueue_.empty())\n>> @@ -933,13 +943,14 @@ void SimpleCameraData::imageBufferReady(FrameBuffer *buffer)\n>>  \t */\n>>  \tif (useConversion_) {\n>>  \t\tif (conversionQueue_.empty()) {\n>> -\t\t\tvideo_->queueBuffer(buffer);\n>> +\t\t\tif (!rawStream_)\n>> +\t\t\t\tvideo_->queueBuffer(buffer);\n>>  \t\t\treturn;\n>>  \t\t}\n>>  \n>>  \t\tif (converter_)\n>>  \t\t\tconverter_->queueBuffers(buffer, conversionQueue_.front().outputs);\n>> -\t\telse\n>> +\t\telse if (processedRequested())\n>>  \t\t\t/*\n>>  \t\t\t * request->sequence() cannot be retrieved from `buffer' inside\n>>  \t\t\t * queueBuffers because unique_ptr's make buffer->request() invalid\n>> @@ -949,6 +960,8 @@ void SimpleCameraData::imageBufferReady(FrameBuffer *buffer)\n>>  \t\t\t\t\t     conversionQueue_.front().outputs);\n>>  \n>>  \t\tconversionQueue_.pop();\n>> +\t\tif (rawStream_)\n>> +\t\t\tpipe->completeBuffer(request, buffer);\n>>  \t\treturn;\n>>  \t}\n>>  \n>> @@ -986,7 +999,8 @@ void SimpleCameraData::tryCompleteRequest(Request *request)\n>>  void SimpleCameraData::conversionInputDone(FrameBuffer *buffer)\n>>  {\n>>  \t/* Queue the input buffer back for capture. */\n>> -\tvideo_->queueBuffer(buffer);\n>> +\tif (!rawStream_)\n>> +\t\tvideo_->queueBuffer(buffer);\n>>  }\n>>  \n>>  void SimpleCameraData::conversionOutputDone(FrameBuffer *buffer)\n>> @@ -1499,11 +1513,20 @@ int SimplePipelineHandler::configure(Camera *camera, CameraConfiguration *c)\n>>  \n>>  \tfor (unsigned int i = 0; i < config->size(); ++i) {\n>>  \t\tStreamConfiguration &cfg = config->at(i);\n>> +\t\tbool rawStream = isRaw(cfg);\n>>  \n>>  \t\tcfg.setStream(&data->streams_[i]);\n>>  \n>> -\t\tif (data->useConversion_ && !isRaw(cfg))\n>> +\t\tif (data->useConversion_ && !rawStream)\n>>  \t\t\toutputCfgs.push_back(cfg);\n>> +\n>> +\t\tif (rawStream) {\n>> +\t\t\tif (data->rawStream_) {\n>> +\t\t\t\tLOG(SimplePipeline, Error) << \"Multiple raw streams not supported\";\n>> +\t\t\t\treturn -EINVAL;\n>> +\t\t\t}\n>\n> There are 3 places you try to do this validation:\n>\n> - generateConfiguration 3/8\n> - in validate() 4/8\n>\n> and now here in configure(). Please refer to the following doc from\n> PipelineHandler::configure()\n>\n>  * The configuration is guaranteed to have been validated with\n>  * CameraConfiguration::validate(). The pipeline handler implementation shall\n>  * not perform further validation and may rely on any custom field stored in its\n>  * custom CameraConfiguration derived class.\n>\n> My question here is why? Is it something I am not understanding with this\n> series? \n\nNo, I'll remove this one check in v13.\n\n> There are more comments, the ones I have already comments in previous\n> iterations - which you might have chose to ignore (and that's fine),\n> but still I think the series can be simplied that will gain a very\n> straight-forward review relatively quickly.\n\nI'm sorry, I got in trouble to track all the stuff in the review.  I\ntried to consolidate the patches based on your comments and patches to\nmake a base for further discussion, but I most likely haven't addressed\neverything.  Could you please remind me about the unresolved comments?\n\n>> +\t\t\tdata->rawStream_ = &data->streams_[i];\n>> +\t\t}\n>>  \t}\n>>  \n>>  \tif (outputCfgs.empty())\n>> @@ -1534,7 +1557,7 @@ int SimplePipelineHandler::exportFrameBuffers(Camera *camera, Stream *stream,\n>>  \t * Export buffers on the converter or capture video node, depending on\n>>  \t * whether the converter is used or not.\n>>  \t */\n>> -\tif (data->useConversion_)\n>> +\tif (data->useConversion_ && stream != data->rawStream_)\n>>  \t\treturn data->converter_\n>>  \t\t\t       ? data->converter_->exportBuffers(stream, count, buffers)\n>>  \t\t\t       : data->swIsp_->exportBuffers(stream, count, buffers);\n>> @@ -1557,7 +1580,7 @@ int SimplePipelineHandler::start(Camera *camera, [[maybe_unused]] const ControlL\n>>  \t\treturn -EBUSY;\n>>  \t}\n>>  \n>> -\tif (data->useConversion_) {\n>> +\tif (data->useConversion_ && !data->rawStream_) {\n>>  \t\t/*\n>>  \t\t * When using the converter allocate a fixed number of internal\n>>  \t\t * buffers.\n>> @@ -1565,8 +1588,11 @@ int SimplePipelineHandler::start(Camera *camera, [[maybe_unused]] const ControlL\n>>  \t\tret = video->allocateBuffers(kNumInternalBuffers,\n>>  \t\t\t\t\t     &data->conversionBuffers_);\n>>  \t} else {\n>> -\t\t/* Otherwise, prepare for using buffers from the only stream. */\n>> -\t\tStream *stream = &data->streams_[0];\n>> +\t\t/*\n>> +\t\t * Otherwise, prepare for using buffers from either the raw stream, if\n>> +\t\t * requested, or the only stream configured.\n>> +\t\t */\n>> +\t\tStream *stream = (data->rawStream_ ? data->rawStream_ : &data->streams_[0]);\n>>  \t\tret = video->importBuffers(stream->configuration().bufferCount);\n>>  \t}\n>>  \tif (ret < 0) {\n>> @@ -1607,8 +1633,9 @@ int SimplePipelineHandler::start(Camera *camera, [[maybe_unused]] const ControlL\n>>  \t\t}\n>>  \n>>  \t\t/* Queue all internal buffers for capture. */\n>> -\t\tfor (std::unique_ptr<FrameBuffer> &buffer : data->conversionBuffers_)\n>> -\t\t\tvideo->queueBuffer(buffer.get());\n>> +\t\tif (!data->rawStream_)\n>> +\t\t\tfor (std::unique_ptr<FrameBuffer> &buffer : data->conversionBuffers_)\n>> +\t\t\t\tvideo->queueBuffer(buffer.get());\n>>  \t}\n>>  \n>>  \treturn 0;\n>> @@ -1659,7 +1686,7 @@ int SimplePipelineHandler::queueRequestDevice(Camera *camera, Request *request)\n>>  \t\t * queue, it will be handed to the converter in the capture\n>>  \t\t * completion handler.\n>>  \t\t */\n>> -\t\tif (data->useConversion_) {\n>> +\t\tif (data->useConversion_ && stream != data->rawStream_) {\n>>  \t\t\tbuffers.emplace(stream, buffer);\n>>  \t\t\tmetadataRequired = !!data->swIsp_;\n>>  \t\t} else {\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 031B1BDCC1\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed, 13 Aug 2025 10:33:13 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id A2F7B69251;\n\tWed, 13 Aug 2025 12:33:13 +0200 (CEST)","from us-smtp-delivery-124.mimecast.com\n\t(us-smtp-delivery-124.mimecast.com [170.10.133.124])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id C3DF76924A\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 13 Aug 2025 12:33:11 +0200 (CEST)","from mail-wr1-f70.google.com (mail-wr1-f70.google.com\n\t[209.85.221.70]) by relay.mimecast.com with ESMTP with STARTTLS\n\t(version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id\n\tus-mta-646-PXwY0k8vM22sElCOncLT8w-1; Wed, 13 Aug 2025 06:33:05 -0400","by mail-wr1-f70.google.com with SMTP id\n\tffacd0b85a97d-3b79ad7b8a5so4212088f8f.3\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 13 Aug 2025 03:33:03 -0700 (PDT)","from mzamazal-thinkpadp1gen7.tpbc.csb\n\t(ip-77-48-47-2.net.vodafone.cz. [77.48.47.2])\n\tby smtp.gmail.com with ESMTPSA id\n\tffacd0b85a97d-3b914e70596sm4192437f8f.61.2025.08.13.03.33.00\n\t(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n\tWed, 13 Aug 2025 03:33:01 -0700 (PDT)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=redhat.com header.i=@redhat.com\n\theader.b=\"Jsf17oRt\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n\ts=mimecast20190719; t=1755081187;\n\th=from:from:reply-to:subject:subject:date:date:message-id:message-id:\n\tto:to:cc:cc:mime-version:mime-version:content-type:content-type:\n\tin-reply-to:in-reply-to:references:references;\n\tbh=GPCNyXlbw/QUMCYL/oK6mbGnPccWUHiTFWRpBpjKvUY=;\n\tb=Jsf17oRtIYE4rhbi98bSQTWW5UQRPW9NasDjwuf4wvcnyJiANjnXCaIiTEm/9D2Dy6vRdS\n\tgH3G0BpPDGyu4/sa76JdKW6N+OHTuc4q4nObboBpBFp/6L6se/81PF3U8+1mvV/AHkOGaz\n\trq0mutQYDfumPC3XDvoFtFeN0hS0WOo=","X-MC-Unique":"PXwY0k8vM22sElCOncLT8w-1","X-Mimecast-MFC-AGG-ID":"PXwY0k8vM22sElCOncLT8w_1755081182","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20230601; t=1755081182; x=1755685982;\n\th=mime-version:message-id:date:user-agent:references:in-reply-to\n\t:subject:cc:to:from:x-gm-message-state:from:to:cc:subject:date\n\t:message-id:reply-to;\n\tbh=GPCNyXlbw/QUMCYL/oK6mbGnPccWUHiTFWRpBpjKvUY=;\n\tb=ggiap2So3ZbvKsokjZdM3dR9Rzzr4Q1N0hc6JZrwdWPndDK2AQqu8GS/LaiPWU02OY\n\tzHml5UEvaRFyOIrArS02n7EkypXXHUkJDmLxWRVg66tZug7Hd4Vc5EjH/gsfDxsmJy1X\n\t7fqUlIiExp7fW66WfcldfNe5gAV9NBDK+4k6bCx7q48Z9eFNXts717K9/er3hJrJ6E4Q\n\tShicTK+ReSxIUuQ2zUYNYcOFEJm7oX2wim7oGKT4l2BYV9WLiHGqf1Qv1ONJOjfNvnYu\n\tldl09g0uwC0NDAxvy6zFXlVOg2LXSYsg1IHIiIdD5YEBFsfk4BmoNuk1glZJBMgTwFBW\n\tNJ+w==","X-Gm-Message-State":"AOJu0YzD2pTLzLqTYU8Qb346egGNPAZ7saJt9kcZDxcXgDOfjDePuya6\n\t28xr2vAWI6RqVcpMXhEzR9nhx0WBsRrygvMVCtN2eNTfcs7VElP0TZi8MwZ5TdqtVtHU0a55+0m\n\tBBsR1osvT/Tk4pgQm7LabwcZQjgDF4BifgtJ3sbvCxRjizttDoKzbs5eXkGI3IZgZjSv4mel4oC\n\ts=","X-Gm-Gg":"ASbGncvCZY4tmr4eT2E3ldsFiZC5XNawufEtynikxn+rcY/II46pB9VBsKzQ/Rd1mqK\n\t7o4VHOInWQG80vN9FZGKu5nwOtY5Pu4KCLZY8eRMn911VXOaBiNL9n7K6DC0rRqOjcBpmMXde8b\n\tJwnWxscSvLYAvoqXo993rBH901jvQt4VDAXZX0RucVzp2wCoqS+ZF2FtHB8kJep+oWyTI3Cyown\n\tnrP4GgjJxBKDwtW5m7VIcxzn4bKXOULX79lpjtfSw49IZc/l1L1vTXpyQJZyfCWThe9psl1/YuI\n\tSSb5msUwldsJpKKXVQ5czx+vKqs3RvqjKfvWTWQtFg0eJlmxl2mvixsso8FSKMMn17+OGreSSM2\n\tdhZbQ2Di8FoScmk/b","X-Received":["by 2002:a05:6000:110a:b0:3b9:1d32:cf2c with SMTP id\n\tffacd0b85a97d-3b91d32dd68mr102365f8f.2.1755081182342; \n\tWed, 13 Aug 2025 03:33:02 -0700 (PDT)","by 2002:a05:6000:110a:b0:3b9:1d32:cf2c with SMTP id\n\tffacd0b85a97d-3b91d32dd68mr102335f8f.2.1755081181777; \n\tWed, 13 Aug 2025 03:33:01 -0700 (PDT)"],"X-Google-Smtp-Source":"AGHT+IE5OBYfJMUnjYk70k2lZWq5M1FeA6zHKqNcWSY5nhkE+gzQG3tlpqxu97kLajTM4msIY/Lypg==","From":"Milan Zamazal <mzamazal@redhat.com>","To":"Umang Jain <uajain@igalia.com>","Cc":"libcamera-devel@lists.libcamera.org,  Laurent Pinchart\n\t<laurent.pinchart@ideasonboard.com>,\n\tKieran Bingham <kieran.bingham@ideasonboard.com>, =?utf-8?q?Barnab?=\n\t=?utf-8?b?w6FzIFDFkWN6ZQ==?=\n\t<barnabas.pocze@ideasonboard.com>, Paul Elder\n\t<paul.elder@ideasonboard.com>","Subject":"Re: [PATCH v12 8/8] libcamera: simple: Make raw streams working","In-Reply-To":"<kmncz4cqwc2y2vnq2oqo3yvcabnvpz4elwhgk4f2tc4752fdzc@6mn5mowwheks>\n\t(Umang Jain's message of \"Fri, 8 Aug 2025 10:06:36 +0530\")","References":"<20250804163812.126022-1-mzamazal@redhat.com>\n\t<20250804163812.126022-9-mzamazal@redhat.com>\n\t<kmncz4cqwc2y2vnq2oqo3yvcabnvpz4elwhgk4f2tc4752fdzc@6mn5mowwheks>","User-Agent":"Gnus/5.13 (Gnus v5.13)","Date":"Wed, 13 Aug 2025 12:33:00 +0200","Message-ID":"<85a543zf37.fsf@mzamazal-thinkpadp1gen7.tpbc.csb>","MIME-Version":"1.0","X-Mimecast-Spam-Score":"0","X-Mimecast-MFC-PROC-ID":"iXKkwkqKuKVkJ4u-jsoP_LL9Gj_xRP4k9HY85E30fMs_1755081182","X-Mimecast-Originator":"redhat.com","Content-Type":"text/plain","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":35591,"web_url":"https://patchwork.libcamera.org/comment/35591/","msgid":"<fomuqs3jo4x65wm6hdtvy3av6cgprybyatnhl2ncptkrj2veaw@uuflrqw5jztr>","date":"2025-08-27T14:47:15","subject":"Re: [PATCH v12 8/8] libcamera: simple: Make raw streams working","submitter":{"id":232,"url":"https://patchwork.libcamera.org/api/people/232/","name":"Umang Jain","email":"uajain@igalia.com"},"content":"On Wed, Aug 13, 2025 at 12:33:00PM +0200, Milan Zamazal wrote:\n> Hi Umang,\n> \n> Umang Jain <uajain@igalia.com> writes:\n> \n> > On Mon, Aug 04, 2025 at 06:38:11PM +0200, Milan Zamazal wrote:\n> >> When a raw stream is requested, whether alone or together with a\n> >> processed stream, its buffers must be handled outside the software ISP\n> >\n> >> machinery.  They serve as output buffers, even when a processed stream\n> >> is produced.\n> >> \n> >> At most one raw stream and at most one processed stream are supported\n> >> and can be combined.  An example of producing both raw and processed\n> >> files using `cam' application:\n> >> \n> >>   cam -c1 -C100 -Ffile# \\\n> >>     -s role=viewfinder,width=1920,height=1080,pixelformat=RGB888 \\\n> >>     -s role=raw,width=3280,height=2464,pixelformat=SRGGB8 \\\n> >> \n> >> Note the difference in viewfinder and raw stream sizes due to the fact\n> >> that debayering requires enlarging the image width, which enforces\n> >> selecting a larger sensor resolution in this case.\n> >> \n> >> In order to track whether a raw stream is requested and which one it is,\n> >> SimpleCameraData::rawStream_ member variable is introduced.\n> >> \n> >> This is the final step to make raw streams working.\n> >> \n> >> Signed-off-by: Milan Zamazal <mzamazal@redhat.com>\n> >> ---\n> >>  src/libcamera/pipeline/simple/simple.cpp | 55 ++++++++++++++++++------\n> >>  1 file changed, 41 insertions(+), 14 deletions(-)\n> >> \n> >> diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp\n> >> index e5449cd2e..d854d6a72 100644\n> >> --- a/src/libcamera/pipeline/simple/simple.cpp\n> >> +++ b/src/libcamera/pipeline/simple/simple.cpp\n> >> @@ -330,6 +330,7 @@ public:\n> >>  \t};\n> >>  \n> >>  \tstd::vector<Stream> streams_;\n> >> +\tStream *rawStream_;\n> >>  \n> >>  \t/*\n> >>  \t * All entities in the pipeline, from the camera sensor to the video\n> >> @@ -368,6 +369,11 @@ private:\n> >>  \tvoid ispStatsReady(uint32_t frame, uint32_t bufferId);\n> >>  \tvoid metadataReady(uint32_t frame, const ControlList &metadata);\n> >>  \tvoid setSensorControls(const ControlList &sensorControls);\n> >> +\n> >> +\tbool processedRequested() const\n> >> +\t{\n> >> +\t\treturn streams_.size() - (rawStream_ ? 1 : 0) > 0;\n> >> +\t}\n> >>  };\n> >>  \n> >>  class SimpleCameraConfiguration : public CameraConfiguration\n> >> @@ -460,7 +466,7 @@ private:\n> >>  SimpleCameraData::SimpleCameraData(SimplePipelineHandler *pipe,\n> >>  \t\t\t\t   unsigned int numStreams,\n> >>  \t\t\t\t   MediaEntity *sensor)\n> >> -\t: Camera::Private(pipe), streams_(numStreams)\n> >> +\t: Camera::Private(pipe), streams_(numStreams), rawStream_(nullptr)\n> >>  {\n> >>  \t/*\n> >>  \t * Find the shortest path from the camera sensor to a video capture\n> >> @@ -871,10 +877,13 @@ void SimpleCameraData::imageBufferReady(FrameBuffer *buffer)\n> >>  \t * point converting an erroneous buffer.\n> >>  \t */\n> >>  \tif (buffer->metadata().status != FrameMetadata::FrameSuccess) {\n> >> -\t\tif (!useConversion_) {\n> >> +\t\tif (rawStream_) {\n> >>  \t\t\t/* No conversion, just complete the request. */\n> >>  \t\t\tRequest *request = buffer->request();\n> >>  \t\t\tpipe->completeBuffer(request, buffer);\n> >> +\t\t\tSimpleFrameInfo *info = frameInfo_.find(request->sequence());\n> >> +\t\t\tif (info)\n> >> +\t\t\t\tinfo->metadataRequired = false;\n> >>  \t\t\ttryCompleteRequest(request);\n> >>  \t\t\treturn;\n> >>  \t\t}\n> >> @@ -884,7 +893,8 @@ void SimpleCameraData::imageBufferReady(FrameBuffer *buffer)\n> >>  \t\t * buffer for capture (unless the stream is being stopped), and\n> >>  \t\t * complete the request with all the user-facing buffers.\n> >>  \t\t */\n> >> -\t\tif (buffer->metadata().status != FrameMetadata::FrameCancelled)\n> >> +\t\tif (buffer->metadata().status != FrameMetadata::FrameCancelled &&\n> >> +\t\t    !rawStream_)\n> >>  \t\t\tvideo_->queueBuffer(buffer);\n> >>  \n> >>  \t\tif (conversionQueue_.empty())\n> >> @@ -933,13 +943,14 @@ void SimpleCameraData::imageBufferReady(FrameBuffer *buffer)\n> >>  \t */\n> >>  \tif (useConversion_) {\n> >>  \t\tif (conversionQueue_.empty()) {\n> >> -\t\t\tvideo_->queueBuffer(buffer);\n> >> +\t\t\tif (!rawStream_)\n> >> +\t\t\t\tvideo_->queueBuffer(buffer);\n> >>  \t\t\treturn;\n> >>  \t\t}\n> >>  \n> >>  \t\tif (converter_)\n> >>  \t\t\tconverter_->queueBuffers(buffer, conversionQueue_.front().outputs);\n> >> -\t\telse\n> >> +\t\telse if (processedRequested())\n> >>  \t\t\t/*\n> >>  \t\t\t * request->sequence() cannot be retrieved from `buffer' inside\n> >>  \t\t\t * queueBuffers because unique_ptr's make buffer->request() invalid\n> >> @@ -949,6 +960,8 @@ void SimpleCameraData::imageBufferReady(FrameBuffer *buffer)\n> >>  \t\t\t\t\t     conversionQueue_.front().outputs);\n> >>  \n> >>  \t\tconversionQueue_.pop();\n> >> +\t\tif (rawStream_)\n> >> +\t\t\tpipe->completeBuffer(request, buffer);\n> >>  \t\treturn;\n> >>  \t}\n> >>  \n> >> @@ -986,7 +999,8 @@ void SimpleCameraData::tryCompleteRequest(Request *request)\n> >>  void SimpleCameraData::conversionInputDone(FrameBuffer *buffer)\n> >>  {\n> >>  \t/* Queue the input buffer back for capture. */\n> >> -\tvideo_->queueBuffer(buffer);\n> >> +\tif (!rawStream_)\n> >> +\t\tvideo_->queueBuffer(buffer);\n> >>  }\n> >>  \n> >>  void SimpleCameraData::conversionOutputDone(FrameBuffer *buffer)\n> >> @@ -1499,11 +1513,20 @@ int SimplePipelineHandler::configure(Camera *camera, CameraConfiguration *c)\n> >>  \n> >>  \tfor (unsigned int i = 0; i < config->size(); ++i) {\n> >>  \t\tStreamConfiguration &cfg = config->at(i);\n> >> +\t\tbool rawStream = isRaw(cfg);\n> >>  \n> >>  \t\tcfg.setStream(&data->streams_[i]);\n> >>  \n> >> -\t\tif (data->useConversion_ && !isRaw(cfg))\n> >> +\t\tif (data->useConversion_ && !rawStream)\n> >>  \t\t\toutputCfgs.push_back(cfg);\n> >> +\n> >> +\t\tif (rawStream) {\n> >> +\t\t\tif (data->rawStream_) {\n> >> +\t\t\t\tLOG(SimplePipeline, Error) << \"Multiple raw streams not supported\";\n> >> +\t\t\t\treturn -EINVAL;\n> >> +\t\t\t}\n> >\n> > There are 3 places you try to do this validation:\n> >\n> > - generateConfiguration 3/8\n> > - in validate() 4/8\n> >\n> > and now here in configure(). Please refer to the following doc from\n> > PipelineHandler::configure()\n> >\n> >  * The configuration is guaranteed to have been validated with\n> >  * CameraConfiguration::validate(). The pipeline handler implementation shall\n> >  * not perform further validation and may rely on any custom field stored in its\n> >  * custom CameraConfiguration derived class.\n> >\n> > My question here is why? Is it something I am not understanding with this\n> > series? \n> \n> No, I'll remove this one check in v13.\n> \n> > There are more comments, the ones I have already comments in previous\n> > iterations - which you might have chose to ignore (and that's fine),\n> > but still I think the series can be simplied that will gain a very\n> > straight-forward review relatively quickly.\n> \n> I'm sorry, I got in trouble to track all the stuff in the review.  I\n> tried to consolidate the patches based on your comments and patches to\n> make a base for further discussion, but I most likely haven't addressed\n> everything.  Could you please remind me about the unresolved comments?\n\nI cannot make out whether you forgot to address them or you chose\nnot to incorporate those review comments. So, it is not easy for me\nto tell here.\n\nfwiw, the implementation is here[1] and I would say it's built on top\nof comments I already had in mind, for this series from previous versions. You\nreported one issue during testing - which I resolved it fairly quickly.\nSo it's is a bit optimised in that sense and I find it better for readability\n/ understanding the flow. So it's really upto you. If you want, at best, I can\npost the patches for review bashing here or to brainstorming any\nconflicting ideas.\n\n[1]: https://gitlab.freedesktop.org/uajain/libcamera/-/commits/uajain/simple/raw\n\n> \n> >> +\t\t\tdata->rawStream_ = &data->streams_[i];\n> >> +\t\t}\n> >>  \t}\n> >>  \n> >>  \tif (outputCfgs.empty())\n> >> @@ -1534,7 +1557,7 @@ int SimplePipelineHandler::exportFrameBuffers(Camera *camera, Stream *stream,\n> >>  \t * Export buffers on the converter or capture video node, depending on\n> >>  \t * whether the converter is used or not.\n> >>  \t */\n> >> -\tif (data->useConversion_)\n> >> +\tif (data->useConversion_ && stream != data->rawStream_)\n> >>  \t\treturn data->converter_\n> >>  \t\t\t       ? data->converter_->exportBuffers(stream, count, buffers)\n> >>  \t\t\t       : data->swIsp_->exportBuffers(stream, count, buffers);\n> >> @@ -1557,7 +1580,7 @@ int SimplePipelineHandler::start(Camera *camera, [[maybe_unused]] const ControlL\n> >>  \t\treturn -EBUSY;\n> >>  \t}\n> >>  \n> >> -\tif (data->useConversion_) {\n> >> +\tif (data->useConversion_ && !data->rawStream_) {\n> >>  \t\t/*\n> >>  \t\t * When using the converter allocate a fixed number of internal\n> >>  \t\t * buffers.\n> >> @@ -1565,8 +1588,11 @@ int SimplePipelineHandler::start(Camera *camera, [[maybe_unused]] const ControlL\n> >>  \t\tret = video->allocateBuffers(kNumInternalBuffers,\n> >>  \t\t\t\t\t     &data->conversionBuffers_);\n> >>  \t} else {\n> >> -\t\t/* Otherwise, prepare for using buffers from the only stream. */\n> >> -\t\tStream *stream = &data->streams_[0];\n> >> +\t\t/*\n> >> +\t\t * Otherwise, prepare for using buffers from either the raw stream, if\n> >> +\t\t * requested, or the only stream configured.\n> >> +\t\t */\n> >> +\t\tStream *stream = (data->rawStream_ ? data->rawStream_ : &data->streams_[0]);\n> >>  \t\tret = video->importBuffers(stream->configuration().bufferCount);\n> >>  \t}\n> >>  \tif (ret < 0) {\n> >> @@ -1607,8 +1633,9 @@ int SimplePipelineHandler::start(Camera *camera, [[maybe_unused]] const ControlL\n> >>  \t\t}\n> >>  \n> >>  \t\t/* Queue all internal buffers for capture. */\n> >> -\t\tfor (std::unique_ptr<FrameBuffer> &buffer : data->conversionBuffers_)\n> >> -\t\t\tvideo->queueBuffer(buffer.get());\n> >> +\t\tif (!data->rawStream_)\n> >> +\t\t\tfor (std::unique_ptr<FrameBuffer> &buffer : data->conversionBuffers_)\n> >> +\t\t\t\tvideo->queueBuffer(buffer.get());\n> >>  \t}\n> >>  \n> >>  \treturn 0;\n> >> @@ -1659,7 +1686,7 @@ int SimplePipelineHandler::queueRequestDevice(Camera *camera, Request *request)\n> >>  \t\t * queue, it will be handed to the converter in the capture\n> >>  \t\t * completion handler.\n> >>  \t\t */\n> >> -\t\tif (data->useConversion_) {\n> >> +\t\tif (data->useConversion_ && stream != data->rawStream_) {\n> >>  \t\t\tbuffers.emplace(stream, buffer);\n> >>  \t\t\tmetadataRequired = !!data->swIsp_;\n> >>  \t\t} else {\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 6B4CFBD87C\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed, 27 Aug 2025 14:47:10 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 0A026692E7;\n\tWed, 27 Aug 2025 16:47:09 +0200 (CEST)","from fanzine2.igalia.com (fanzine2.igalia.com [213.97.179.56])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id D7695613BA\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 27 Aug 2025 16:47:05 +0200 (CEST)","from [49.36.69.233] (helo=uajain)\n\tby fanzine2.igalia.com with esmtpsa \n\t(Cipher TLS1.3:ECDHE_SECP256R1__RSA_PSS_RSAE_SHA256__AES_256_GCM:256)\n\t(Exim) id 1urHQW-002TiR-4m; Wed, 27 Aug 2025 16:47:04 +0200"],"Authentication-Results":"lancelot.ideasonboard.com;\n\tdkim=fail reason=\"signature verification failed\" (2048-bit key;\n\tunprotected) header.d=igalia.com header.i=@igalia.com\n\theader.b=\"WI327z8m\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=igalia.com;\n\ts=20170329;\n\th=In-Reply-To:Content-Type:MIME-Version:References:Message-ID:\n\tSubject:Cc:To:From:Date:Sender:Reply-To:Content-Transfer-Encoding:Content-ID:\n\tContent-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc\n\t:Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe:\n\tList-Post:List-Owner:List-Archive;\n\tbh=0UdJ7ahjwR4fZN+bROXJ+hOjPN3gLPSHbAeyTYfE3ws=;\n\tb=WI327z8mVSsEhIDfaHa9Rrj5C3\n\ts09vh7twlgVfpQUKQdHW93hSjH035gI1Dor+onF6Xv160IIGxAgO+TA58JdANj5Ydy8MTLfau/2LR\n\tC6ZOosiSkeShkFVJtv9hqy3eIpefWv1JEs+IhM9IHpv6wCViU5aj0tT6sXXlE+EIKuuYIHpI8djr7\n\taHBMVV6w7Lo4d20aQao379KkK0NVSxrt30vlGqD5IslU+/0gh6ge4/Jrw5d0RZUI3ZPhcYB2vkLHR\n\tlTvqSuH+ZBOO3l14zjqqn+kQtf/ecPqG2+QsPW0Hrw22Vc8MiXTswHc8a+V+qz5Krn1MWxvSZCp70\n\tkTnztxGg==;","Date":"Wed, 27 Aug 2025 20:17:15 +0530","From":"Umang Jain <uajain@igalia.com>","To":"Milan Zamazal <mzamazal@redhat.com>","Cc":"libcamera-devel@lists.libcamera.org, Laurent Pinchart\n\t<laurent.pinchart@ideasonboard.com>, Kieran Bingham\n\t<kieran.bingham@ideasonboard.com>, =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?=\n\t<barnabas.pocze@ideasonboard.com>, Paul Elder\n\t<paul.elder@ideasonboard.com>","Subject":"Re: [PATCH v12 8/8] libcamera: simple: Make raw streams working","Message-ID":"<fomuqs3jo4x65wm6hdtvy3av6cgprybyatnhl2ncptkrj2veaw@uuflrqw5jztr>","References":"<20250804163812.126022-1-mzamazal@redhat.com>\n\t<20250804163812.126022-9-mzamazal@redhat.com>\n\t<kmncz4cqwc2y2vnq2oqo3yvcabnvpz4elwhgk4f2tc4752fdzc@6mn5mowwheks>\n\t<85a543zf37.fsf@mzamazal-thinkpadp1gen7.tpbc.csb>","MIME-Version":"1.0","Content-Type":"text/plain; charset=us-ascii","Content-Disposition":"inline","In-Reply-To":"<85a543zf37.fsf@mzamazal-thinkpadp1gen7.tpbc.csb>","User-Agent":"NeoMutt/20250510-dirty","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":35593,"web_url":"https://patchwork.libcamera.org/comment/35593/","msgid":"<855xe8srqv.fsf@mzamazal-thinkpadp1gen7.tpbc.csb>","date":"2025-08-27T15:34:32","subject":"Re: [PATCH v12 8/8] libcamera: simple: Make raw streams working","submitter":{"id":177,"url":"https://patchwork.libcamera.org/api/people/177/","name":"Milan Zamazal","email":"mzamazal@redhat.com"},"content":"Hi Umang,\n\nUmang Jain <uajain@igalia.com> writes:\n\n> On Wed, Aug 13, 2025 at 12:33:00PM +0200, Milan Zamazal wrote:\n>> Hi Umang,\n>> \n>\n>> Umang Jain <uajain@igalia.com> writes:\n>> \n>> > On Mon, Aug 04, 2025 at 06:38:11PM +0200, Milan Zamazal wrote:\n>> >> When a raw stream is requested, whether alone or together with a\n>> >> processed stream, its buffers must be handled outside the software ISP\n>> >\n>> >> machinery.  They serve as output buffers, even when a processed stream\n>> >> is produced.\n>> >> \n>> >> At most one raw stream and at most one processed stream are supported\n>> >> and can be combined.  An example of producing both raw and processed\n>> >> files using `cam' application:\n>> >> \n>> >>   cam -c1 -C100 -Ffile# \\\n>> >>     -s role=viewfinder,width=1920,height=1080,pixelformat=RGB888 \\\n>> >>     -s role=raw,width=3280,height=2464,pixelformat=SRGGB8 \\\n>> >> \n>> >> Note the difference in viewfinder and raw stream sizes due to the fact\n>> >> that debayering requires enlarging the image width, which enforces\n>> >> selecting a larger sensor resolution in this case.\n>> >> \n>> >> In order to track whether a raw stream is requested and which one it is,\n>> >> SimpleCameraData::rawStream_ member variable is introduced.\n>> >> \n>> >> This is the final step to make raw streams working.\n>> >> \n>> >> Signed-off-by: Milan Zamazal <mzamazal@redhat.com>\n>> >> ---\n>> >>  src/libcamera/pipeline/simple/simple.cpp | 55 ++++++++++++++++++------\n>> >>  1 file changed, 41 insertions(+), 14 deletions(-)\n>> >> \n>> >> diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp\n>> >> index e5449cd2e..d854d6a72 100644\n>> >> --- a/src/libcamera/pipeline/simple/simple.cpp\n>> >> +++ b/src/libcamera/pipeline/simple/simple.cpp\n>> >> @@ -330,6 +330,7 @@ public:\n>> >>  \t};\n>> >>  \n>> >>  \tstd::vector<Stream> streams_;\n>> >> +\tStream *rawStream_;\n>> >>  \n>> >>  \t/*\n>> >>  \t * All entities in the pipeline, from the camera sensor to the video\n>> >> @@ -368,6 +369,11 @@ private:\n>> >>  \tvoid ispStatsReady(uint32_t frame, uint32_t bufferId);\n>> >>  \tvoid metadataReady(uint32_t frame, const ControlList &metadata);\n>> >>  \tvoid setSensorControls(const ControlList &sensorControls);\n>> >> +\n>> >> +\tbool processedRequested() const\n>> >> +\t{\n>> >> +\t\treturn streams_.size() - (rawStream_ ? 1 : 0) > 0;\n>> >> +\t}\n>> >>  };\n>> >>  \n>> >>  class SimpleCameraConfiguration : public CameraConfiguration\n>> >> @@ -460,7 +466,7 @@ private:\n>> >>  SimpleCameraData::SimpleCameraData(SimplePipelineHandler *pipe,\n>> >>  \t\t\t\t   unsigned int numStreams,\n>> >>  \t\t\t\t   MediaEntity *sensor)\n>> >> -\t: Camera::Private(pipe), streams_(numStreams)\n>> >> +\t: Camera::Private(pipe), streams_(numStreams), rawStream_(nullptr)\n>> >>  {\n>> >>  \t/*\n>> >>  \t * Find the shortest path from the camera sensor to a video capture\n>> >> @@ -871,10 +877,13 @@ void SimpleCameraData::imageBufferReady(FrameBuffer *buffer)\n>> >>  \t * point converting an erroneous buffer.\n>> >>  \t */\n>> >>  \tif (buffer->metadata().status != FrameMetadata::FrameSuccess) {\n>> >> -\t\tif (!useConversion_) {\n>> >> +\t\tif (rawStream_) {\n>> >>  \t\t\t/* No conversion, just complete the request. */\n>> >>  \t\t\tRequest *request = buffer->request();\n>> >>  \t\t\tpipe->completeBuffer(request, buffer);\n>> >> +\t\t\tSimpleFrameInfo *info = frameInfo_.find(request->sequence());\n>> >> +\t\t\tif (info)\n>> >> +\t\t\t\tinfo->metadataRequired = false;\n>> >>  \t\t\ttryCompleteRequest(request);\n>> >>  \t\t\treturn;\n>> >>  \t\t}\n>> >> @@ -884,7 +893,8 @@ void SimpleCameraData::imageBufferReady(FrameBuffer *buffer)\n>> >>  \t\t * buffer for capture (unless the stream is being stopped), and\n>> >>  \t\t * complete the request with all the user-facing buffers.\n>> >>  \t\t */\n>> >> -\t\tif (buffer->metadata().status != FrameMetadata::FrameCancelled)\n>> >> +\t\tif (buffer->metadata().status != FrameMetadata::FrameCancelled &&\n>> >> +\t\t    !rawStream_)\n>> >>  \t\t\tvideo_->queueBuffer(buffer);\n>> >>  \n>> >>  \t\tif (conversionQueue_.empty())\n>> >> @@ -933,13 +943,14 @@ void SimpleCameraData::imageBufferReady(FrameBuffer *buffer)\n>> >>  \t */\n>> >>  \tif (useConversion_) {\n>> >>  \t\tif (conversionQueue_.empty()) {\n>> >> -\t\t\tvideo_->queueBuffer(buffer);\n>> >> +\t\t\tif (!rawStream_)\n>> >> +\t\t\t\tvideo_->queueBuffer(buffer);\n>> >>  \t\t\treturn;\n>> >>  \t\t}\n>> >>  \n>> >>  \t\tif (converter_)\n>> >>  \t\t\tconverter_->queueBuffers(buffer, conversionQueue_.front().outputs);\n>> >> -\t\telse\n>> >> +\t\telse if (processedRequested())\n>> >>  \t\t\t/*\n>> >>  \t\t\t * request->sequence() cannot be retrieved from `buffer' inside\n>> >>  \t\t\t * queueBuffers because unique_ptr's make buffer->request() invalid\n>> >> @@ -949,6 +960,8 @@ void SimpleCameraData::imageBufferReady(FrameBuffer *buffer)\n>> >>  \t\t\t\t\t     conversionQueue_.front().outputs);\n>> >>  \n>> >>  \t\tconversionQueue_.pop();\n>> >> +\t\tif (rawStream_)\n>> >> +\t\t\tpipe->completeBuffer(request, buffer);\n>> >>  \t\treturn;\n>> >>  \t}\n>> >>  \n>> >> @@ -986,7 +999,8 @@ void SimpleCameraData::tryCompleteRequest(Request *request)\n>> >>  void SimpleCameraData::conversionInputDone(FrameBuffer *buffer)\n>> >>  {\n>> >>  \t/* Queue the input buffer back for capture. */\n>> >> -\tvideo_->queueBuffer(buffer);\n>> >> +\tif (!rawStream_)\n>> >> +\t\tvideo_->queueBuffer(buffer);\n>> >>  }\n>> >>  \n>> >>  void SimpleCameraData::conversionOutputDone(FrameBuffer *buffer)\n>> >> @@ -1499,11 +1513,20 @@ int SimplePipelineHandler::configure(Camera *camera, CameraConfiguration *c)\n>> >>  \n>> >>  \tfor (unsigned int i = 0; i < config->size(); ++i) {\n>> >>  \t\tStreamConfiguration &cfg = config->at(i);\n>> >> +\t\tbool rawStream = isRaw(cfg);\n>> >>  \n>> >>  \t\tcfg.setStream(&data->streams_[i]);\n>> >>  \n>> >> -\t\tif (data->useConversion_ && !isRaw(cfg))\n>> >> +\t\tif (data->useConversion_ && !rawStream)\n>> >>  \t\t\toutputCfgs.push_back(cfg);\n>> >> +\n>> >> +\t\tif (rawStream) {\n>> >> +\t\t\tif (data->rawStream_) {\n>> >> +\t\t\t\tLOG(SimplePipeline, Error) << \"Multiple raw streams not supported\";\n>> >> +\t\t\t\treturn -EINVAL;\n>> >> +\t\t\t}\n>> >\n>> > There are 3 places you try to do this validation:\n>> >\n>> > - generateConfiguration 3/8\n>> > - in validate() 4/8\n>> >\n>> > and now here in configure(). Please refer to the following doc from\n>> > PipelineHandler::configure()\n>> >\n>> >  * The configuration is guaranteed to have been validated with\n>> >  * CameraConfiguration::validate(). The pipeline handler implementation shall\n>> >  * not perform further validation and may rely on any custom field stored in its\n>> >  * custom CameraConfiguration derived class.\n>> >\n>> > My question here is why? Is it something I am not understanding with this\n>> > series? \n>> \n>> No, I'll remove this one check in v13.\n>> \n>> > There are more comments, the ones I have already comments in previous\n>> > iterations - which you might have chose to ignore (and that's fine),\n>> > but still I think the series can be simplied that will gain a very\n>> > straight-forward review relatively quickly.\n>> \n>> I'm sorry, I got in trouble to track all the stuff in the review.  I\n>> tried to consolidate the patches based on your comments and patches to\n>> make a base for further discussion, but I most likely haven't addressed\n>> everything.  Could you please remind me about the unresolved comments?\n>\n> I cannot make out whether you forgot to address them or you chose\n> not to incorporate those review comments. So, it is not easy for me\n> to tell here.\n\nIf I haven't responded and it's not mentioned in the changelog then it\ncan be raised.\n\n> fwiw, the implementation is here[1] and I would say it's built on top\n> of comments I already had in mind, for this series from previous versions. You\n> reported one issue during testing - which I resolved it fairly quickly.\n> So it's is a bit optimised in that sense and I find it better for readability\n> / understanding the flow. So it's really upto you. If you want, at best, I can\n> post the patches for review bashing here or to brainstorming any\n> conflicting ideas.\n\nI had thought working with two version could be possible, but it wasn't\nfor me.  I looked into your patches to understand what you mean and how\nit can be done but otherwise I lost track where we're in the review.\nI'd suggest let's pick one of the series and continue with proper review\nthere (which can include pointing to specific parts of different\npatches).\n\n> [1]: https://gitlab.freedesktop.org/uajain/libcamera/-/commits/uajain/simple/raw\n>\n>> \n>> >> +\t\t\tdata->rawStream_ = &data->streams_[i];\n>> >> +\t\t}\n>> >>  \t}\n>> >>  \n>> >>  \tif (outputCfgs.empty())\n>> >> @@ -1534,7 +1557,7 @@ int SimplePipelineHandler::exportFrameBuffers(Camera *camera, Stream *stream,\n>> >>  \t * Export buffers on the converter or capture video node, depending on\n>> >>  \t * whether the converter is used or not.\n>> >>  \t */\n>> >> -\tif (data->useConversion_)\n>> >> +\tif (data->useConversion_ && stream != data->rawStream_)\n>> >>  \t\treturn data->converter_\n>> >>  \t\t\t       ? data->converter_->exportBuffers(stream, count, buffers)\n>> >>  \t\t\t       : data->swIsp_->exportBuffers(stream, count, buffers);\n>> >> @@ -1557,7 +1580,7 @@ int SimplePipelineHandler::start(Camera *camera, [[maybe_unused]] const ControlL\n>> >>  \t\treturn -EBUSY;\n>> >>  \t}\n>> >>  \n>> >> -\tif (data->useConversion_) {\n>> >> +\tif (data->useConversion_ && !data->rawStream_) {\n>> >>  \t\t/*\n>> >>  \t\t * When using the converter allocate a fixed number of internal\n>> >>  \t\t * buffers.\n>> >> @@ -1565,8 +1588,11 @@ int SimplePipelineHandler::start(Camera *camera, [[maybe_unused]] const ControlL\n>> >>  \t\tret = video->allocateBuffers(kNumInternalBuffers,\n>> >>  \t\t\t\t\t     &data->conversionBuffers_);\n>> >>  \t} else {\n>> >> -\t\t/* Otherwise, prepare for using buffers from the only stream. */\n>> >> -\t\tStream *stream = &data->streams_[0];\n>> >> +\t\t/*\n>> >> +\t\t * Otherwise, prepare for using buffers from either the raw stream, if\n>> >> +\t\t * requested, or the only stream configured.\n>> >> +\t\t */\n>> >> +\t\tStream *stream = (data->rawStream_ ? data->rawStream_ : &data->streams_[0]);\n>> >>  \t\tret = video->importBuffers(stream->configuration().bufferCount);\n>> >>  \t}\n>> >>  \tif (ret < 0) {\n>> >> @@ -1607,8 +1633,9 @@ int SimplePipelineHandler::start(Camera *camera, [[maybe_unused]] const ControlL\n>> >>  \t\t}\n>> >>  \n>> >>  \t\t/* Queue all internal buffers for capture. */\n>> >> -\t\tfor (std::unique_ptr<FrameBuffer> &buffer : data->conversionBuffers_)\n>> >> -\t\t\tvideo->queueBuffer(buffer.get());\n>> >> +\t\tif (!data->rawStream_)\n>> >> +\t\t\tfor (std::unique_ptr<FrameBuffer> &buffer : data->conversionBuffers_)\n>> >> +\t\t\t\tvideo->queueBuffer(buffer.get());\n>> >>  \t}\n>> >>  \n>> >>  \treturn 0;\n>> >> @@ -1659,7 +1686,7 @@ int SimplePipelineHandler::queueRequestDevice(Camera *camera, Request *request)\n>> >>  \t\t * queue, it will be handed to the converter in the capture\n>> >>  \t\t * completion handler.\n>> >>  \t\t */\n>> >> -\t\tif (data->useConversion_) {\n>> >> +\t\tif (data->useConversion_ && stream != data->rawStream_) {\n>> >>  \t\t\tbuffers.emplace(stream, buffer);\n>> >>  \t\t\tmetadataRequired = !!data->swIsp_;\n>> >>  \t\t} else {\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 3CEA7BD87C\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed, 27 Aug 2025 15:34:42 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 0A11A692E7;\n\tWed, 27 Aug 2025 17:34:41 +0200 (CEST)","from us-smtp-delivery-124.mimecast.com\n\t(us-smtp-delivery-124.mimecast.com [170.10.133.124])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id CC55B613BA\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 27 Aug 2025 17:34:39 +0200 (CEST)","from mail-qk1-f199.google.com (mail-qk1-f199.google.com\n\t[209.85.222.199]) by relay.mimecast.com with ESMTP with STARTTLS\n\t(version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id\n\tus-mta-486-55Bbyi2yMxqbeh1B62NrpA-1; Wed, 27 Aug 2025 11:34:37 -0400","by mail-qk1-f199.google.com with SMTP id\n\taf79cd13be357-7e8706abd44so7934185a.3\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 27 Aug 2025 08:34:37 -0700 (PDT)","from mzamazal-thinkpadp1gen7.tpbc.csb\n\t(ip-77-48-47-2.net.vodafone.cz. [77.48.47.2])\n\tby smtp.gmail.com with ESMTPSA id\n\taf79cd13be357-7ebf41792dcsm890915985a.71.2025.08.27.08.34.34\n\t(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n\tWed, 27 Aug 2025 08:34:35 -0700 (PDT)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=redhat.com header.i=@redhat.com\n\theader.b=\"LjPnjODL\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n\ts=mimecast20190719; t=1756308878;\n\th=from:from:reply-to:subject:subject:date:date:message-id:message-id:\n\tto:to:cc:cc:mime-version:mime-version:content-type:content-type:\n\tin-reply-to:in-reply-to:references:references;\n\tbh=9Li3aUHyauRVOfPWBpNyJzz3rjZw8uuQOWPj1PXIuhU=;\n\tb=LjPnjODLoau+s23su4EWRvO1lq10GAYizav703XrKZDIt9GrkBdMoNsAr5i/1h7CvmLSET\n\tD735ISjarvNqjBcMmpMvXgASR8FU5t1wLVWCRS3wThruJmf4Swoe1mbz0ww8C8gYcXb9Nd\n\t0/AyjrRkgx/73A+tq/bb2BxUxh80ZkY=","X-MC-Unique":"55Bbyi2yMxqbeh1B62NrpA-1","X-Mimecast-MFC-AGG-ID":"55Bbyi2yMxqbeh1B62NrpA_1756308876","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20230601; t=1756308876; x=1756913676;\n\th=mime-version:user-agent:message-id:date:references:in-reply-to\n\t:subject:cc:to:from:x-gm-message-state:from:to:cc:subject:date\n\t:message-id:reply-to;\n\tbh=9Li3aUHyauRVOfPWBpNyJzz3rjZw8uuQOWPj1PXIuhU=;\n\tb=q1zuuyyEJ3voF+MONzC3rtzHG9gXsEV8peXnFyqsXOat0hoiYKdQ1h4Nc3WK+hX5XA\n\tmuXD8B+PKBIR2pMHgIUgCqq/J7U6BHZ/+o+BkXCtMK5n+7P5USFqCCCi6VjE+khEW4va\n\tjBpMR75y7RNls8brfi8cXp6kk3mj3BhQhAq7kq3S57f8Kww6vVXd7/JJ3wxIe89Sxzz+\n\ttuMHs0McmSTHzZ/MLDzOGMP+YjPpQ009SHnwKCFTQdV/PiWWPLh7r8PffBf+Ai8bJDBd\n\twDgjuj8SjAHt3bMNbGNuU6sQPFccl5PlGgQ2tHkDopPwe2hGvw/79wzez+9taeq5be4p\n\tNCxw==","X-Gm-Message-State":"AOJu0Yw6Ji6k4luhcssG13SBy8qzlLueQWpvVh/tJb1mqT/pTjh/6fGJ\n\tl1hbV9DxrknTpFj+oaAlgK/8phTd/ckQ8cp1mtSNBQOyRwCzYttNowzUM5mMilIesESsb2c8Iqt\n\tpt7IBgzn0zvqTXGKJkw85E4fmJVeumLSWRVQx1b/yU+rAh3mV/l7Da9YfK7f4Yy4E44lyI0e80I\n\tc=","X-Gm-Gg":"ASbGncuW1jIN6S+bEDzsbPj7whDO9bdZbUNK5jAlkpg+kbpLaH8Iwu/GPso5QppP0S6\n\tKDoRIfHmKeWLLzacpbRvSbxdYIV6fUURNtCquXovXLmGA31gdGP6E+TbGGuIPFL6RNOvQJrs4UV\n\tltwRPbFPNPY3rjztP+LQFzt8R+cuVEtlBIkCBrcr8yLobk123mW6Gzl7OiqsihVh9ZV0/TFV8th\n\tQBQquwW6b45lPEzaQjmAztHhcngl4ZLjb+m+SYxfu2SRsSKJ358SnXLnQ5YqCo/cyycm9dD1LWS\n\tSgq3o4dFhHThzT0l6XpjcjYYDkpclBW+cCBmvjUUQ0AM13QXkJO7J8P4hwQALQn552ajZjcHVOG\n\trYRijSQ1JljjmtSqb","X-Received":["by 2002:a05:620a:2914:b0:7e8:39da:9735 with SMTP id\n\taf79cd13be357-7ea10f86ed1mr2637915885a.14.1756308876232; \n\tWed, 27 Aug 2025 08:34:36 -0700 (PDT)","by 2002:a05:620a:2914:b0:7e8:39da:9735 with SMTP id\n\taf79cd13be357-7ea10f86ed1mr2637910585a.14.1756308875620; \n\tWed, 27 Aug 2025 08:34:35 -0700 (PDT)"],"X-Google-Smtp-Source":"AGHT+IEzN0ZVByuyUwL+0By+BXxjYvSTYJYWZtOhqiAmCJX76QYGnXZ84Vgz3lzSUE00uvoLA4Eb5Q==","From":"Milan Zamazal <mzamazal@redhat.com>","To":"Umang Jain <uajain@igalia.com>","Cc":"libcamera-devel@lists.libcamera.org,  Laurent Pinchart\n\t<laurent.pinchart@ideasonboard.com>,\n\tKieran Bingham <kieran.bingham@ideasonboard.com>, =?utf-8?q?Barnab?=\n\t=?utf-8?b?w6FzIFDFkWN6ZQ==?=\n\t<barnabas.pocze@ideasonboard.com>, Paul Elder\n\t<paul.elder@ideasonboard.com>","Subject":"Re: [PATCH v12 8/8] libcamera: simple: Make raw streams working","In-Reply-To":"<fomuqs3jo4x65wm6hdtvy3av6cgprybyatnhl2ncptkrj2veaw@uuflrqw5jztr>\n\t(Umang Jain's message of \"Wed, 27 Aug 2025 20:17:15 +0530\")","References":"<20250804163812.126022-1-mzamazal@redhat.com>\n\t<20250804163812.126022-9-mzamazal@redhat.com>\n\t<kmncz4cqwc2y2vnq2oqo3yvcabnvpz4elwhgk4f2tc4752fdzc@6mn5mowwheks>\n\t<85a543zf37.fsf@mzamazal-thinkpadp1gen7.tpbc.csb>\n\t<fomuqs3jo4x65wm6hdtvy3av6cgprybyatnhl2ncptkrj2veaw@uuflrqw5jztr>","Date":"Wed, 27 Aug 2025 17:34:32 +0200","Message-ID":"<855xe8srqv.fsf@mzamazal-thinkpadp1gen7.tpbc.csb>","User-Agent":"Gnus/5.13 (Gnus v5.13)","MIME-Version":"1.0","X-Mimecast-Spam-Score":"0","X-Mimecast-MFC-PROC-ID":"KkcOTN8NfKrVCXhZ-g0yt03uM8XVZNAdzRynkqgem8k_1756308876","X-Mimecast-Originator":"redhat.com","Content-Type":"text/plain","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>"}}]