[{"id":32547,"web_url":"https://patchwork.libcamera.org/comment/32547/","msgid":"<l3ptognwlicltmepqjeqxh6olcgh4oyd2rn6zw4j573svkwcwc@64f7onqnqzqb>","date":"2024-12-05T16:13:30","subject":"Re: [PATCH v3 3/7] android: Correctly support multiple Mapped\n\tstreams","submitter":{"id":143,"url":"https://patchwork.libcamera.org/api/people/143/","name":"Jacopo Mondi","email":"jacopo.mondi@ideasonboard.com"},"content":"Hi Harvey\n\nOn Wed, Dec 04, 2024 at 04:36:28PM +0000, Harvey Yang wrote:\n> The Android camera HAL supports creating streams for the Android\n> framework by post-processing streams produced by libcamera.\n>\n> However at the moment a single Mapped stream can be associated with a\n> Direct stream because, after the first post-processing, the data from\n> the internal stream are returned preventing further post-processing\n> passes.\n>\n> Fix this by storing the list of Direct stream buffers used as the\n\nHave I suggested this ? The streams in internalBuffers_ are not Direct\nbut Internal. So s/Direct/Internal/\n\n> post-processing source in an Camera3RequestDescriptor::internalBuffers_\n> map to replace the single internalBuffer_ pointer and return the\n> internal buffers when the capture request is deleted.\n>\n> Signed-off-by: Han-Lin Chen <hanlinchen@chromium.org>\n> Co-developed-by: Harvey Yang <chenghaoyang@chromium.org>\n> Signed-off-by: Harvey Yang <chenghaoyang@chromium.org>\n> ---\n>  src/android/camera_device.cpp  | 66 +++++++++++++++++++---------------\n>  src/android/camera_request.cpp | 11 +++---\n>  src/android/camera_request.h   |  3 +-\n>  3 files changed, 47 insertions(+), 33 deletions(-)\n>\n> diff --git a/src/android/camera_device.cpp b/src/android/camera_device.cpp\n> index f6dadaf22..f2dd8d4fd 100644\n> --- a/src/android/camera_device.cpp\n> +++ b/src/android/camera_device.cpp\n> @@ -966,9 +966,10 @@ int CameraDevice::processCaptureRequest(camera3_capture_request_t *camera3Reques\n>  \t * to a libcamera stream. Streams of type Mapped will be handled later.\n>  \t *\n>  \t * Collect the CameraStream associated to each requested capture stream.\n> -\t * Since requestedStreams is an std:map<>, no duplications can happen.\n> +\t * Since directBuffers is an std:map<>, no duplications can\n> +\t * happen.\n\nnit: fits on the previous line\n\n>  \t */\n> -\tstd::map<CameraStream *, libcamera::FrameBuffer *> requestedBuffers;\n> +\tstd::map<CameraStream *, libcamera::FrameBuffer *> directBuffers;\n>  \tfor (const auto &[i, buffer] : utils::enumerate(descriptor->buffers_)) {\n>  \t\tCameraStream *cameraStream = buffer.stream;\n>  \t\tcamera3_stream_t *camera3Stream = cameraStream->camera3Stream();\n> @@ -1007,6 +1008,8 @@ int CameraDevice::processCaptureRequest(camera3_capture_request_t *camera3Reques\n>  \t\t\t\t\t\t  cameraStream->configuration().size);\n>  \t\t\tframeBuffer = buffer.frameBuffer.get();\n>  \t\t\tacquireFence = std::move(buffer.fence);\n> +\n> +\t\t\tdirectBuffers[cameraStream] = frameBuffer;\n>  \t\t\tLOG(HAL, Debug) << ss.str() << \" (direct)\";\n>  \t\t\tbreak;\n>\n> @@ -1015,13 +1018,17 @@ int CameraDevice::processCaptureRequest(camera3_capture_request_t *camera3Reques\n>  \t\t\t * Get the frame buffer from the CameraStream internal\n>  \t\t\t * buffer pool.\n>  \t\t\t *\n> -\t\t\t * The buffer has to be returned to the CameraStream\n> -\t\t\t * once it has been processed.\n> +\t\t\t * The buffer will be returned to the CameraStream when\n> +\t\t\t * the request is destroyed.\n>  \t\t\t */\n>  \t\t\tframeBuffer = cameraStream->getBuffer();\n> -\t\t\tbuffer.internalBuffer = frameBuffer;\n>  \t\t\tbuffer.srcBuffer = frameBuffer;\n>\n> +\t\t\t/*\n> +\t\t\t * Track the allocated internal buffers, which will be\n> +\t\t\t * recycled when the descriptor destroyed.\n\nnit: \"is destroyed\"\n\n> +\t\t\t */\n> +\t\t\tdescriptor->internalBuffers_[cameraStream] = frameBuffer;\n>  \t\t\tLOG(HAL, Debug) << ss.str() << \" (internal)\";\n>\n>  \t\t\tdescriptor->pendingStreamsToProcess_.insert(\n> @@ -1037,8 +1044,6 @@ int CameraDevice::processCaptureRequest(camera3_capture_request_t *camera3Reques\n>  \t\tauto fence = std::make_unique<Fence>(std::move(acquireFence));\n>  \t\tdescriptor->request_->addBuffer(cameraStream->stream(),\n>  \t\t\t\t\t\tframeBuffer, std::move(fence));\n> -\n> -\t\trequestedBuffers[cameraStream] = frameBuffer;\n>  \t}\n>\n>  \t/*\n> @@ -1076,24 +1081,43 @@ int CameraDevice::processCaptureRequest(camera3_capture_request_t *camera3Reques\n>  \t\t * post-processing. No need to recycle the buffer since it's\n>  \t\t * owned by Android.\n>  \t\t */\n> -\t\tauto iterDirectBuffer = requestedBuffers.find(sourceStream);\n> -\t\tif (iterDirectBuffer != requestedBuffers.end()) {\n> +\t\tauto iterDirectBuffer = directBuffers.find(sourceStream);\n> +\t\tif (iterDirectBuffer != directBuffers.end()) {\n>  \t\t\tbuffer.srcBuffer = iterDirectBuffer->second;\n>  \t\t\tcontinue;\n>  \t\t}\n>\n>  \t\t/*\n> -\t\t * If that's not the case, we need to add a buffer to the request\n> -\t\t * for this stream.\n> +\t\t * If that's not the case, we use an internal buffer allocated\n> +\t\t * from the source stream.\n> +\t\t */\n> +\n> +\t\t/*\n> +\t\t * If an internal buffer has been requested for the source\n> +\t\t * stream before, we should reuse it.\n>  \t\t */\n> -\t\tFrameBuffer *frameBuffer = cameraStream->getBuffer();\n> -\t\tbuffer.internalBuffer = frameBuffer;\n> +\t\tauto iterInternalBuffer = descriptor->internalBuffers_.find(sourceStream);\n> +\t\tif (iterInternalBuffer != descriptor->internalBuffers_.end()) {\n> +\t\t\tbuffer.srcBuffer = iterInternalBuffer->second;\n> +\t\t\tcontinue;\n> +\t\t}\n> +\n> +\t\t/*\n> +\t\t * Otherwise, we need to create an internal buffer to the\n> +\t\t * request for the source stream. Get the frame buffer from the\n> +\t\t * source stream's internal buffer pool.\n> +\t\t *\n> +\t\t * The buffer will be returned to the CameraStream when the\n> +\t\t * request is destructed.\n> +\t\t */\n> +\t\tFrameBuffer *frameBuffer = sourceStream->getBuffer();\n>  \t\tbuffer.srcBuffer = frameBuffer;\n>\n>  \t\tdescriptor->request_->addBuffer(sourceStream->stream(),\n>  \t\t\t\t\t\tframeBuffer, nullptr);\n>\n> -\t\trequestedBuffers[sourceStream] = frameBuffer;\n> +\t\t/* Track the allocated internal buffer. */\n> +\t\tdescriptor->internalBuffers_[sourceStream] = frameBuffer;\n\nFine with me.\n\nI wonder if inverting the logic wouldn't make it more clear\n\n\n\t\t/*\n\t\t * If that's not the case, we use an internal buffer allocated\n\t\t * from the source stream.\n\t\t */\n\n\t\tauto iterInternalBuffer = descriptor->internalBuffers_.find(sourceStream);\n\t\tif (iterInternalBuffer == descriptor->internalBuffers_.end()) {\n\t\t\t/*\n\t\t\t * We need to create an internal buffer to the request\n\t\t\t * for the source stream. Get the frame buffer from the\n\t\t\t * source stream's internal buffer pool.\n\t\t\t *\n\t\t\t * The buffer will be returned to the CameraStream when\n\t\t\t * the request is destructed.\n\t\t\t */\n\t\t\tFrameBuffer *frameBuffer = sourceStream->getBuffer();\n\t\t\tbuffer.srcBuffer = frameBuffer;\n\n\t\t\tdescriptor->request_->addBuffer(sourceStream->stream(),\n\t\t\t\t\t\t\tframeBuffer, nullptr);\n\n\t\t\t/* Track the allocated internal buffer. */\n\t\t\tdescriptor->internalBuffers_[sourceStream] = frameBuffer;\n\n\t\t\tcontinue;\n\t\t}\n\n\t\t/*\n\t\t * Otherwise if an internal buffer has already been requested\n\t\t * for the source stream before, we should reuse it.\n\t\t */\n\t\tbuffer.srcBuffer = iterInternalBuffer->second;\n\nUp to you.\n\nWith the two nits fixed, and with or without the above change\nReviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>\n\nThanks\n  j\n\n>  \t}\n>\n>  \t/*\n> @@ -1253,13 +1277,6 @@ void CameraDevice::requestComplete(Request *request)\n>  \t\tif (ret) {\n>  \t\t\tsetBufferStatus(*buffer, StreamBuffer::Status::Error);\n>  \t\t\tdescriptor->pendingStreamsToProcess_.erase(stream);\n> -\n> -\t\t\t/*\n> -\t\t\t * If the framebuffer is internal to CameraStream return\n> -\t\t\t * it back now that we're done processing it.\n> -\t\t\t */\n> -\t\t\tif (buffer->internalBuffer)\n> -\t\t\t\tstream->putBuffer(buffer->internalBuffer);\n>  \t\t}\n>  \t}\n>\n> @@ -1378,13 +1395,6 @@ void CameraDevice::streamProcessingComplete(StreamBuffer *streamBuffer,\n>  {\n>  \tsetBufferStatus(*streamBuffer, status);\n>\n> -\t/*\n> -\t * If the framebuffer is internal to CameraStream return it back now\n> -\t * that we're done processing it.\n> -\t */\n> -\tif (streamBuffer->internalBuffer)\n> -\t\tstreamBuffer->stream->putBuffer(streamBuffer->internalBuffer);\n> -\n>  \tCamera3RequestDescriptor *request = streamBuffer->request;\n>\n>  \t{\n> diff --git a/src/android/camera_request.cpp b/src/android/camera_request.cpp\n> index 52a3ac1f7..92e74ab6a 100644\n> --- a/src/android/camera_request.cpp\n> +++ b/src/android/camera_request.cpp\n> @@ -10,6 +10,7 @@\n>  #include <libcamera/base/span.h>\n>\n>  #include \"camera_buffer.h\"\n> +#include \"camera_stream.h\"\n>\n>  using namespace libcamera;\n>\n> @@ -138,7 +139,12 @@ Camera3RequestDescriptor::Camera3RequestDescriptor(\n>  \trequest_ = camera->createRequest(reinterpret_cast<uint64_t>(this));\n>  }\n>\n> -Camera3RequestDescriptor::~Camera3RequestDescriptor() = default;\n> +Camera3RequestDescriptor::~Camera3RequestDescriptor()\n> +{\n> +\t/* Recycle the allocated internal buffer back to its source stream. */\n> +\tfor (auto &[sourceStream, frameBuffer] : internalBuffers_)\n> +\t\tsourceStream->putBuffer(frameBuffer);\n> +}\n>\n>  /**\n>   * \\class StreamBuffer\n> @@ -166,9 +172,6 @@ Camera3RequestDescriptor::~Camera3RequestDescriptor() = default;\n>   * \\var StreamBuffer::status\n>   * \\brief Track the status of the buffer\n>   *\n> - * \\var StreamBuffer::internalBuffer\n> - * \\brief Pointer to a buffer internally handled by CameraStream (if any)\n> - *\n>   * \\var StreamBuffer::srcBuffer\n>   * \\brief Pointer to the source frame buffer used for post-processing\n>   *\n> diff --git a/src/android/camera_request.h b/src/android/camera_request.h\n> index 335f1985d..6b2a00795 100644\n> --- a/src/android/camera_request.h\n> +++ b/src/android/camera_request.h\n> @@ -49,7 +49,6 @@ public:\n>  \tstd::unique_ptr<HALFrameBuffer> frameBuffer;\n>  \tlibcamera::UniqueFD fence;\n>  \tStatus status = Status::Success;\n> -\tlibcamera::FrameBuffer *internalBuffer = nullptr;\n>  \tconst libcamera::FrameBuffer *srcBuffer = nullptr;\n>  \tstd::unique_ptr<CameraBuffer> dstBuffer;\n>  \tCamera3RequestDescriptor *request;\n> @@ -85,6 +84,8 @@ public:\n>  \tstd::unique_ptr<libcamera::Request> request_;\n>  \tstd::unique_ptr<CameraMetadata> resultMetadata_;\n>\n> +\tstd::map<CameraStream *, libcamera::FrameBuffer *> internalBuffers_;\n> +\n>  \tbool complete_ = false;\n>  \tStatus status_ = Status::Success;\n>\n> --\n> 2.47.0.338.g60cca15819-goog\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 21CABBDB1C\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu,  5 Dec 2024 16:13:36 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id C141C66109;\n\tThu,  5 Dec 2024 17:13:34 +0100 (CET)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id C4A336608C\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu,  5 Dec 2024 17:13:33 +0100 (CET)","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 D0BD67E2;\n\tThu,  5 Dec 2024 17:13:04 +0100 (CET)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"SEHIyuVu\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1733415184;\n\tbh=T0HLejAPMbMnDnhZhWYuaU/BZTN4hax/QWdLDM1kc/8=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=SEHIyuVuZR4WBE3U3L2ZeVgmtZ6l+NMAgAm2f0d4YfXBS4eevY0+s4uLjmEK7XMHc\n\tjKhy2JlsTn0u/13D4FhqNTRRQsz9FZujSiNqxEEWmc8OZTDZ7fEREx8mcTe30p+60c\n\tRFYYtFE136S5CxmorBVPENnarwH5B526oQfl42m0=","Date":"Thu, 5 Dec 2024 17:13:30 +0100","From":"Jacopo Mondi <jacopo.mondi@ideasonboard.com>","To":"Harvey Yang <chenghaoyang@chromium.org>","Cc":"libcamera-devel@lists.libcamera.org, \n\tHan-Lin Chen <hanlinchen@chromium.org>","Subject":"Re: [PATCH v3 3/7] android: Correctly support multiple Mapped\n\tstreams","Message-ID":"<l3ptognwlicltmepqjeqxh6olcgh4oyd2rn6zw4j573svkwcwc@64f7onqnqzqb>","References":"<20241204164137.3938891-1-chenghaoyang@chromium.org>\n\t<20241204164137.3938891-4-chenghaoyang@chromium.org>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<20241204164137.3938891-4-chenghaoyang@chromium.org>","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":32620,"web_url":"https://patchwork.libcamera.org/comment/32620/","msgid":"<CAEB1ahsQVWE_cW1bsfcjMyZ=NLHzCxzu+GzKNMhX_3WCTTu_PQ@mail.gmail.com>","date":"2024-12-09T05:23:00","subject":"Re: [PATCH v3 3/7] android: Correctly support multiple Mapped\n\tstreams","submitter":{"id":117,"url":"https://patchwork.libcamera.org/api/people/117/","name":"Cheng-Hao Yang","email":"chenghaoyang@chromium.org"},"content":"Hi Jacopo,\n\nWill upload a new version later.\n\nOn Fri, Dec 6, 2024 at 12:13 AM Jacopo Mondi\n<jacopo.mondi@ideasonboard.com> wrote:\n>\n> Hi Harvey\n>\n> On Wed, Dec 04, 2024 at 04:36:28PM +0000, Harvey Yang wrote:\n> > The Android camera HAL supports creating streams for the Android\n> > framework by post-processing streams produced by libcamera.\n> >\n> > However at the moment a single Mapped stream can be associated with a\n> > Direct stream because, after the first post-processing, the data from\n> > the internal stream are returned preventing further post-processing\n> > passes.\n> >\n> > Fix this by storing the list of Direct stream buffers used as the\n>\n> Have I suggested this ? The streams in internalBuffers_ are not Direct\n> but Internal. So s/Direct/Internal/\n\nAh right, I should've fixed it. Thanks!\n\n>\n> > post-processing source in an Camera3RequestDescriptor::internalBuffers_\n> > map to replace the single internalBuffer_ pointer and return the\n> > internal buffers when the capture request is deleted.\n> >\n> > Signed-off-by: Han-Lin Chen <hanlinchen@chromium.org>\n> > Co-developed-by: Harvey Yang <chenghaoyang@chromium.org>\n> > Signed-off-by: Harvey Yang <chenghaoyang@chromium.org>\n> > ---\n> >  src/android/camera_device.cpp  | 66 +++++++++++++++++++---------------\n> >  src/android/camera_request.cpp | 11 +++---\n> >  src/android/camera_request.h   |  3 +-\n> >  3 files changed, 47 insertions(+), 33 deletions(-)\n> >\n> > diff --git a/src/android/camera_device.cpp b/src/android/camera_device.cpp\n> > index f6dadaf22..f2dd8d4fd 100644\n> > --- a/src/android/camera_device.cpp\n> > +++ b/src/android/camera_device.cpp\n> > @@ -966,9 +966,10 @@ int CameraDevice::processCaptureRequest(camera3_capture_request_t *camera3Reques\n> >        * to a libcamera stream. Streams of type Mapped will be handled later.\n> >        *\n> >        * Collect the CameraStream associated to each requested capture stream.\n> > -      * Since requestedStreams is an std:map<>, no duplications can happen.\n> > +      * Since directBuffers is an std:map<>, no duplications can\n> > +      * happen.\n>\n> nit: fits on the previous line\n\nDone\n\n>\n> >        */\n> > -     std::map<CameraStream *, libcamera::FrameBuffer *> requestedBuffers;\n> > +     std::map<CameraStream *, libcamera::FrameBuffer *> directBuffers;\n> >       for (const auto &[i, buffer] : utils::enumerate(descriptor->buffers_)) {\n> >               CameraStream *cameraStream = buffer.stream;\n> >               camera3_stream_t *camera3Stream = cameraStream->camera3Stream();\n> > @@ -1007,6 +1008,8 @@ int CameraDevice::processCaptureRequest(camera3_capture_request_t *camera3Reques\n> >                                                 cameraStream->configuration().size);\n> >                       frameBuffer = buffer.frameBuffer.get();\n> >                       acquireFence = std::move(buffer.fence);\n> > +\n> > +                     directBuffers[cameraStream] = frameBuffer;\n> >                       LOG(HAL, Debug) << ss.str() << \" (direct)\";\n> >                       break;\n> >\n> > @@ -1015,13 +1018,17 @@ int CameraDevice::processCaptureRequest(camera3_capture_request_t *camera3Reques\n> >                        * Get the frame buffer from the CameraStream internal\n> >                        * buffer pool.\n> >                        *\n> > -                      * The buffer has to be returned to the CameraStream\n> > -                      * once it has been processed.\n> > +                      * The buffer will be returned to the CameraStream when\n> > +                      * the request is destroyed.\n> >                        */\n> >                       frameBuffer = cameraStream->getBuffer();\n> > -                     buffer.internalBuffer = frameBuffer;\n> >                       buffer.srcBuffer = frameBuffer;\n> >\n> > +                     /*\n> > +                      * Track the allocated internal buffers, which will be\n> > +                      * recycled when the descriptor destroyed.\n>\n> nit: \"is destroyed\"\n\nDone\n\n>\n> > +                      */\n> > +                     descriptor->internalBuffers_[cameraStream] = frameBuffer;\n> >                       LOG(HAL, Debug) << ss.str() << \" (internal)\";\n> >\n> >                       descriptor->pendingStreamsToProcess_.insert(\n> > @@ -1037,8 +1044,6 @@ int CameraDevice::processCaptureRequest(camera3_capture_request_t *camera3Reques\n> >               auto fence = std::make_unique<Fence>(std::move(acquireFence));\n> >               descriptor->request_->addBuffer(cameraStream->stream(),\n> >                                               frameBuffer, std::move(fence));\n> > -\n> > -             requestedBuffers[cameraStream] = frameBuffer;\n> >       }\n> >\n> >       /*\n> > @@ -1076,24 +1081,43 @@ int CameraDevice::processCaptureRequest(camera3_capture_request_t *camera3Reques\n> >                * post-processing. No need to recycle the buffer since it's\n> >                * owned by Android.\n> >                */\n> > -             auto iterDirectBuffer = requestedBuffers.find(sourceStream);\n> > -             if (iterDirectBuffer != requestedBuffers.end()) {\n> > +             auto iterDirectBuffer = directBuffers.find(sourceStream);\n> > +             if (iterDirectBuffer != directBuffers.end()) {\n> >                       buffer.srcBuffer = iterDirectBuffer->second;\n> >                       continue;\n> >               }\n> >\n> >               /*\n> > -              * If that's not the case, we need to add a buffer to the request\n> > -              * for this stream.\n> > +              * If that's not the case, we use an internal buffer allocated\n> > +              * from the source stream.\n> > +              */\n> > +\n> > +             /*\n> > +              * If an internal buffer has been requested for the source\n> > +              * stream before, we should reuse it.\n> >                */\n> > -             FrameBuffer *frameBuffer = cameraStream->getBuffer();\n> > -             buffer.internalBuffer = frameBuffer;\n> > +             auto iterInternalBuffer = descriptor->internalBuffers_.find(sourceStream);\n> > +             if (iterInternalBuffer != descriptor->internalBuffers_.end()) {\n> > +                     buffer.srcBuffer = iterInternalBuffer->second;\n> > +                     continue;\n> > +             }\n> > +\n> > +             /*\n> > +              * Otherwise, we need to create an internal buffer to the\n> > +              * request for the source stream. Get the frame buffer from the\n> > +              * source stream's internal buffer pool.\n> > +              *\n> > +              * The buffer will be returned to the CameraStream when the\n> > +              * request is destructed.\n> > +              */\n> > +             FrameBuffer *frameBuffer = sourceStream->getBuffer();\n> >               buffer.srcBuffer = frameBuffer;\n> >\n> >               descriptor->request_->addBuffer(sourceStream->stream(),\n> >                                               frameBuffer, nullptr);\n> >\n> > -             requestedBuffers[sourceStream] = frameBuffer;\n> > +             /* Track the allocated internal buffer. */\n> > +             descriptor->internalBuffers_[sourceStream] = frameBuffer;\n>\n> Fine with me.\n>\n> I wonder if inverting the logic wouldn't make it more clear\n>\n>\n>                 /*\n>                  * If that's not the case, we use an internal buffer allocated\n>                  * from the source stream.\n>                  */\n>\n>                 auto iterInternalBuffer = descriptor->internalBuffers_.find(sourceStream);\n>                 if (iterInternalBuffer == descriptor->internalBuffers_.end()) {\n>                         /*\n>                          * We need to create an internal buffer to the request\n>                          * for the source stream. Get the frame buffer from the\n>                          * source stream's internal buffer pool.\n>                          *\n>                          * The buffer will be returned to the CameraStream when\n>                          * the request is destructed.\n>                          */\n>                         FrameBuffer *frameBuffer = sourceStream->getBuffer();\n>                         buffer.srcBuffer = frameBuffer;\n>\n>                         descriptor->request_->addBuffer(sourceStream->stream(),\n>                                                         frameBuffer, nullptr);\n>\n>                         /* Track the allocated internal buffer. */\n>                         descriptor->internalBuffers_[sourceStream] = frameBuffer;\n>\n>                         continue;\n>                 }\n>\n>                 /*\n>                  * Otherwise if an internal buffer has already been requested\n>                  * for the source stream before, we should reuse it.\n>                  */\n>                 buffer.srcBuffer = iterInternalBuffer->second;\n>\n> Up to you.\n\nAh, I understand that reverting the logic would make the comment\nclearer, while I still prefer the current order, which I believe also\ninvolves less line changes.\n\n\n>\n> With the two nits fixed, and with or without the above change\n> Reviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>\n\nThanks!\n\nBR,\nHarvey\n\n>\n> Thanks\n>   j\n>\n> >       }\n> >\n> >       /*\n> > @@ -1253,13 +1277,6 @@ void CameraDevice::requestComplete(Request *request)\n> >               if (ret) {\n> >                       setBufferStatus(*buffer, StreamBuffer::Status::Error);\n> >                       descriptor->pendingStreamsToProcess_.erase(stream);\n> > -\n> > -                     /*\n> > -                      * If the framebuffer is internal to CameraStream return\n> > -                      * it back now that we're done processing it.\n> > -                      */\n> > -                     if (buffer->internalBuffer)\n> > -                             stream->putBuffer(buffer->internalBuffer);\n> >               }\n> >       }\n> >\n> > @@ -1378,13 +1395,6 @@ void CameraDevice::streamProcessingComplete(StreamBuffer *streamBuffer,\n> >  {\n> >       setBufferStatus(*streamBuffer, status);\n> >\n> > -     /*\n> > -      * If the framebuffer is internal to CameraStream return it back now\n> > -      * that we're done processing it.\n> > -      */\n> > -     if (streamBuffer->internalBuffer)\n> > -             streamBuffer->stream->putBuffer(streamBuffer->internalBuffer);\n> > -\n> >       Camera3RequestDescriptor *request = streamBuffer->request;\n> >\n> >       {\n> > diff --git a/src/android/camera_request.cpp b/src/android/camera_request.cpp\n> > index 52a3ac1f7..92e74ab6a 100644\n> > --- a/src/android/camera_request.cpp\n> > +++ b/src/android/camera_request.cpp\n> > @@ -10,6 +10,7 @@\n> >  #include <libcamera/base/span.h>\n> >\n> >  #include \"camera_buffer.h\"\n> > +#include \"camera_stream.h\"\n> >\n> >  using namespace libcamera;\n> >\n> > @@ -138,7 +139,12 @@ Camera3RequestDescriptor::Camera3RequestDescriptor(\n> >       request_ = camera->createRequest(reinterpret_cast<uint64_t>(this));\n> >  }\n> >\n> > -Camera3RequestDescriptor::~Camera3RequestDescriptor() = default;\n> > +Camera3RequestDescriptor::~Camera3RequestDescriptor()\n> > +{\n> > +     /* Recycle the allocated internal buffer back to its source stream. */\n> > +     for (auto &[sourceStream, frameBuffer] : internalBuffers_)\n> > +             sourceStream->putBuffer(frameBuffer);\n> > +}\n> >\n> >  /**\n> >   * \\class StreamBuffer\n> > @@ -166,9 +172,6 @@ Camera3RequestDescriptor::~Camera3RequestDescriptor() = default;\n> >   * \\var StreamBuffer::status\n> >   * \\brief Track the status of the buffer\n> >   *\n> > - * \\var StreamBuffer::internalBuffer\n> > - * \\brief Pointer to a buffer internally handled by CameraStream (if any)\n> > - *\n> >   * \\var StreamBuffer::srcBuffer\n> >   * \\brief Pointer to the source frame buffer used for post-processing\n> >   *\n> > diff --git a/src/android/camera_request.h b/src/android/camera_request.h\n> > index 335f1985d..6b2a00795 100644\n> > --- a/src/android/camera_request.h\n> > +++ b/src/android/camera_request.h\n> > @@ -49,7 +49,6 @@ public:\n> >       std::unique_ptr<HALFrameBuffer> frameBuffer;\n> >       libcamera::UniqueFD fence;\n> >       Status status = Status::Success;\n> > -     libcamera::FrameBuffer *internalBuffer = nullptr;\n> >       const libcamera::FrameBuffer *srcBuffer = nullptr;\n> >       std::unique_ptr<CameraBuffer> dstBuffer;\n> >       Camera3RequestDescriptor *request;\n> > @@ -85,6 +84,8 @@ public:\n> >       std::unique_ptr<libcamera::Request> request_;\n> >       std::unique_ptr<CameraMetadata> resultMetadata_;\n> >\n> > +     std::map<CameraStream *, libcamera::FrameBuffer *> internalBuffers_;\n> > +\n> >       bool complete_ = false;\n> >       Status status_ = Status::Success;\n> >\n> > --\n> > 2.47.0.338.g60cca15819-goog\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 486A8BD80A\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon,  9 Dec 2024 05:23:15 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 58E3A67E4C;\n\tMon,  9 Dec 2024 06:23:14 +0100 (CET)","from mail-lj1-x231.google.com (mail-lj1-x231.google.com\n\t[IPv6:2a00:1450:4864:20::231])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 94186618AD\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon,  9 Dec 2024 06:23:12 +0100 (CET)","by mail-lj1-x231.google.com with SMTP id\n\t38308e7fff4ca-30227ccf803so1849811fa.2\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tSun, 08 Dec 2024 21:23:12 -0800 (PST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=chromium.org header.i=@chromium.org\n\theader.b=\"Y9kL3kKw\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=chromium.org; s=google; t=1733721792; x=1734326592;\n\tdarn=lists.libcamera.org; \n\th=content-transfer-encoding:cc:to:subject:message-id:date:from\n\t:in-reply-to:references:mime-version:from:to:cc:subject:date\n\t:message-id:reply-to;\n\tbh=6eF/UV5kJIMK4cACMhjvZXWG92iDKlN1Vlz+EXpUCvc=;\n\tb=Y9kL3kKw7BAUYZ4CTo/xG2JWzEAKj+ql7uf67mb6BpZNvFe96nCPE6TeV4iUANQJic\n\tnO+JxWNpdrX7zN00QQxMrGWiCg5/+yCCcvxzUCJGdaejrG44ET8P4N+nsSelLn9bC7lt\n\tdAlqOhiTl88qBp0w9S5pd3U6rWr/LIBXzIAfY=","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20230601; t=1733721792; x=1734326592;\n\th=content-transfer-encoding:cc:to:subject:message-id:date:from\n\t:in-reply-to:references:mime-version:x-gm-message-state:from:to:cc\n\t:subject:date:message-id:reply-to;\n\tbh=6eF/UV5kJIMK4cACMhjvZXWG92iDKlN1Vlz+EXpUCvc=;\n\tb=K1JsHoW5JNCS0e0nCMfqXHlmSVw7CKWaNTXLUv1flu2g7fOf/0BTSPMkog1Xbny00D\n\tazIFnTU4gFIk9G6s+6FHno/VfMsynVjXRWpGrcVaC62RPfp8cOY2SizrEcSdKSBei+Cm\n\t0w7zy/HUQfSu1+JXGXAVf+Au6EnsFweEc4ruVcUNyG3Q+b1cZcNe9dxP5B+8YcGij5L8\n\tl1y3E2OMqO7BPPoW/zsLo6bHnZGsh3Wsi5g0ebPjmsRI4Vy9qmeBbnr9O+LhnkhFlDEP\n\tYUAxlZOB1uBZah1vC16KAn0/G38aqKeqHEhY2pC3AGC6LoNrBQL3qqd4Ad4cLaJCW/96\n\tM8dw==","X-Gm-Message-State":"AOJu0YyBTl4mB0DCTNzFo62Et/LuRS8u4WTdRBeMya4EAZpnYc8tzFli\n\tBC5lzHszo7UCJLHveHaAxZ9qrCvFtso32TwnyQ447gv12sT0mPTNpvfp+vjCoq6ha5HXpoU6wuC\n\tSBGps7P9ft9MOMeDgHYdxfsCRelj8hZugMblrlUTrqEZKwd0=","X-Gm-Gg":"ASbGncu+ud+v9yFZanYghU7vln2d9HXnE5tH95oenUttInp6sJcldPI32Vqdx8xmR09\n\t2vXutQhZnRnGeieazRmzuX92QfCgUihjLOHjW5ySU+RrUkB9FH6THgfe1ud0=","X-Google-Smtp-Source":"AGHT+IE0pXsM+xULwkwU9epEiYYw97IECCVo1ZJPynYFcN/YtI4mPjeOXhNqqAOgcw6FVVzKOjlC9TIeHoAMRjwXUTM=","X-Received":"by 2002:a05:651c:b29:b0:300:2d54:c2c8 with SMTP id\n\t38308e7fff4ca-3002f8b588dmr49180931fa.8.1733721791068;\n\tSun, 08 Dec 2024 21:23:11 -0800 (PST)","MIME-Version":"1.0","References":"<20241204164137.3938891-1-chenghaoyang@chromium.org>\n\t<20241204164137.3938891-4-chenghaoyang@chromium.org>\n\t<l3ptognwlicltmepqjeqxh6olcgh4oyd2rn6zw4j573svkwcwc@64f7onqnqzqb>","In-Reply-To":"<l3ptognwlicltmepqjeqxh6olcgh4oyd2rn6zw4j573svkwcwc@64f7onqnqzqb>","From":"Cheng-Hao Yang <chenghaoyang@chromium.org>","Date":"Mon, 9 Dec 2024 13:23:00 +0800","Message-ID":"<CAEB1ahsQVWE_cW1bsfcjMyZ=NLHzCxzu+GzKNMhX_3WCTTu_PQ@mail.gmail.com>","Subject":"Re: [PATCH v3 3/7] android: Correctly support multiple Mapped\n\tstreams","To":"Jacopo Mondi <jacopo.mondi@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org, \n\tHan-Lin Chen <hanlinchen@chromium.org>","Content-Type":"text/plain; charset=\"UTF-8\"","Content-Transfer-Encoding":"quoted-printable","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>"}}]