[{"id":31949,"web_url":"https://patchwork.libcamera.org/comment/31949/","msgid":"<20241028223529.GC22600@pendragon.ideasonboard.com>","date":"2024-10-28T22:35:29","subject":"Re: [PATCH v3 7/7] pipeline: rpi: Handler controls::rpi::ScalerCrops","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi Naush,\n\nThank you for the patch.\n\nOn Thu, Oct 03, 2024 at 08:47:20AM +0100, Naushir Patuck wrote:\n> Handle multiple scaler crops being set through the rpi::ScalerCrops\n> control. We now populate the cropParams_ map in the loop where we handle\n> the output stream configuration items. The key of this map is the index\n> of the stream configuration structure set by the application. This will\n> also be the same index used to specify the crop rectangles through the\n> ScalerCrops control.\n> \n> CameraData::applyScalerCrop() has been adapted to look at either\n> controls::ScalerCrop or controls::rpi::ScalerCrops. The former takes\n> priority over the latter, and if present, will apply the same scaler\n> crop to all output streams.\n\nThat contradicts patch 1/7 that states\n\n        If both rpi::ScalerCrops and ScalerCrop controls are present in a\n        ControlList, the latter is discarded, and crops are obtained from this\n        control.\n\nand also contradicts the code below.\n\n> \n> Finally return all crops through the same ScalerCrops control via\n> request metadata. The first configure stream's crop rectangle is also\n> returned via the ScalerCrop control in the request metadata.\n> \n> Signed-off-by: Naushir Patuck <naush@raspberrypi.com>\n> Reviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>\n> ---\n>  .../pipeline/rpi/common/pipeline_base.cpp     | 76 ++++++++++++++-----\n>  1 file changed, 59 insertions(+), 17 deletions(-)\n> \n> diff --git a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp\n> index 267e6bd9cd70..eba4dad6d212 100644\n> --- a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp\n> +++ b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp\n> @@ -181,12 +181,14 @@ CameraConfiguration::Status RPiCameraConfiguration::validate()\n>  \n>  \trawStreams_.clear();\n>  \toutStreams_.clear();\n> +\tunsigned int rawStreamIndex = 0;\n> +\tunsigned int outStreamIndex = 0;\n>  \n> -\tfor (const auto &[index, cfg] : utils::enumerate(config_)) {\n> +\tfor (auto &cfg : config_) {\n>  \t\tif (PipelineHandlerBase::isRaw(cfg.pixelFormat))\n> -\t\t\trawStreams_.emplace_back(index, &cfg);\n> +\t\t\trawStreams_.emplace_back(rawStreamIndex++, &cfg);\n>  \t\telse\n> -\t\t\toutStreams_.emplace_back(index, &cfg);\n> +\t\t\toutStreams_.emplace_back(outStreamIndex++, &cfg);\n\nThis changes the indices, but as far as I can tell, they're currently\nunused, so that should be fine. Do I assume correctly the will be used\nin the Pi 5 platformConfigure() implementation to populate cropParams_\nin the right order ?\n\n>  \t}\n>  \n>  \t/* Sort the streams so the highest resolution is first. */\n> @@ -565,10 +567,24 @@ int PipelineHandlerBase::configure(Camera *camera, CameraConfiguration *config)\n>  \tconst auto cropParamsIt = data->cropParams_.find(0);\n>  \tif (cropParamsIt != data->cropParams_.end()) {\n>  \t\tconst CameraData::CropParams &cropParams = cropParamsIt->second;\n> -\t\t/* Add the ScalerCrop control limits based on the current mode. */\n> +\t\t/*\n> +\t\t * Add the ScalerCrop control limits based on the current mode and\n> +\t\t * the first configured stream.\n> +\t\t */\n>  \t\tRectangle ispMinCrop = data->scaleIspCrop(Rectangle(cropParams.ispMinCropSize));\n>  \t\tctrlMap[&controls::ScalerCrop] = ControlInfo(ispMinCrop, data->sensorInfo_.analogCrop,\n>  \t\t\t\t\t\t\t     data->scaleIspCrop(cropParams.ispCrop));\n> +\t\tif (data->cropParams_.size() == 2) {\n> +\t\t\t/*\n> +\t\t\t * The control map for rpi::ScalerCrops has the min value\n> +\t\t\t * as the default crop for stream 0, max value as the default\n> +\t\t\t * value for stream 1.\n\nThat sounds like a real hack. I'm fine with it for now, but should it be\ndocumented in 1/7 ? Or would you rather not have anyone depending on\nthis ?\n\n> +\t\t\t */\n> +\t\t\tctrlMap[&controls::rpi::ScalerCrops] =\n> +\t\t\t\tControlInfo(data->scaleIspCrop(data->cropParams_.at(0).ispCrop),\n> +\t\t\t\t\t    data->scaleIspCrop(data->cropParams_.at(1).ispCrop),\n> +\t\t\t\t\t    ctrlMap[&controls::ScalerCrop].def());\n> +\t\t}\n>  \t}\n>  \n>  \tdata->controlInfo_ = ControlInfoMap(std::move(ctrlMap), result.controlInfo.idmap());\n> @@ -1295,11 +1311,29 @@ Rectangle CameraData::scaleIspCrop(const Rectangle &ispCrop) const\n>  \n>  void CameraData::applyScalerCrop(const ControlList &controls)\n>  {\n> -\tconst auto &scalerCrop = controls.get<Rectangle>(controls::ScalerCrop);\n> -\tconst auto cropParamsIt = cropParams_.find(0);\n> -\tif (scalerCrop && cropParamsIt != cropParams_.end()) {\n> -\t\tRectangle nativeCrop = *scalerCrop;\n> -\t\tCropParams &cropParams = cropParamsIt->second;\n> +\tconst auto &scalerCropRPi = controls.get<Span<const Rectangle>>(controls::rpi::ScalerCrops);\n> +\tconst auto &scalerCropCore = controls.get<Rectangle>(controls::ScalerCrop);\n> +\tstd::vector<Rectangle> scalerCrops;\n> +\n> +\t/*\n> +\t * First thing to do is create a vector of crops to apply to each ISP output\n> +\t * based on either controls::ScalerCrop or controls::rpi::ScalerCrops if\n> +\t * present.\n> +\t *\n> +\t * If controls::ScalerCrop is present, apply the same crop to all ISP output\n> +\t * streams. Otherwise if controls::rpi::ScalerCrops, apply the given crops\n> +\t * to the ISP output streams, indexed by the same order in which they had\n> +\t * been configured. This is not the same as the ISP output index.\n\nThis also contradicts the code below. You can pick the begaviour you\nwant, but let's make documentation, comments, commit messages and code\nconsistent.\n\n> +\t */\n> +\tfor (unsigned int i = 0; i < cropParams_.size(); i++) {\n> +\t\tif (scalerCropRPi && i < scalerCropRPi->size())\n> +\t\t\tscalerCrops.push_back(scalerCropRPi->data()[i]);\n> +\t\telse if (scalerCropCore)\n> +\t\t\tscalerCrops.push_back(*scalerCropCore);\n> +\t}\n> +\n> +\tfor (auto const &[i, scalerCrop] : utils::enumerate(scalerCrops)) {\n> +\t\tRectangle nativeCrop = scalerCrop;\n>  \n>  \t\tif (!nativeCrop.width || !nativeCrop.height)\n>  \t\t\tnativeCrop = { 0, 0, 1, 1 };\n> @@ -1315,13 +1349,13 @@ void CameraData::applyScalerCrop(const ControlList &controls)\n>  \t\t * 2. With the same mid-point, if possible.\n>  \t\t * 3. But it can't go outside the sensor area.\n>  \t\t */\n> -\t\tSize minSize = cropParams.ispMinCropSize.expandedToAspectRatio(nativeCrop.size());\n> +\t\tSize minSize = cropParams_.at(i).ispMinCropSize.expandedToAspectRatio(nativeCrop.size());\n>  \t\tSize size = ispCrop.size().expandedTo(minSize);\n>  \t\tispCrop = size.centeredTo(ispCrop.center()).enclosedIn(Rectangle(sensorInfo_.outputSize));\n>  \n> -\t\tif (ispCrop != cropParams.ispCrop) {\n> -\t\t\tcropParams.ispCrop = ispCrop;\n> -\t\t\tplatformSetIspCrop(cropParams.ispIndex, ispCrop);\n> +\t\tif (ispCrop != cropParams_.at(i).ispCrop) {\n> +\t\t\tcropParams_.at(i).ispCrop = ispCrop;\n> +\t\t\tplatformSetIspCrop(cropParams_.at(i).ispIndex, ispCrop);\n>  \t\t}\n>  \t}\n>  }\n> @@ -1478,10 +1512,18 @@ void CameraData::fillRequestMetadata(const ControlList &bufferControls, Request\n>  \trequest->metadata().set(controls::SensorTimestamp,\n>  \t\t\t\tbufferControls.get(controls::SensorTimestamp).value_or(0));\n>  \n> -\tconst auto cropParamsIt = cropParams_.find(0);\n> -\tif (cropParamsIt != cropParams_.end())\n> -\t\trequest->metadata().set(controls::ScalerCrop,\n> -\t\t\t\t\tscaleIspCrop(cropParamsIt->second.ispCrop));\n> +\tif (cropParams_.size()) {\n> +\t\tstd::vector<Rectangle> crops;\n> +\n> +\t\tfor (auto const &[k, v] : cropParams_)\n> +\t\t\tcrops.push_back(scaleIspCrop(v.ispCrop));\n> +\n> +\t\trequest->metadata().set(controls::ScalerCrop, crops[0]);\n> +\t\tif (crops.size() > 1) {\n> +\t\t\trequest->metadata().set(controls::rpi::ScalerCrops,\n> +\t\t\t\t\t\tSpan<const Rectangle>(crops.data(), crops.size()));\n> +\t\t}\n> +\t}\n>  }\n>  \n>  } /* namespace libcamera */","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 AF914C3220\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon, 28 Oct 2024 22:35:42 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id BA5C36539E;\n\tMon, 28 Oct 2024 23:35:41 +0100 (CET)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 42B2860367\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 28 Oct 2024 23:35:40 +0100 (CET)","from pendragon.ideasonboard.com (81-175-209-231.bb.dnainternet.fi\n\t[81.175.209.231])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id C1A836B5;\n\tMon, 28 Oct 2024 23:35:34 +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=\"kCfosy4b\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1730154936;\n\tbh=fGYxsDZ4uX6wkpwhESULE2KKvgKaHfebujPVYXbnbeA=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=kCfosy4bqFE1NlonbFo++xj/Fof2oRSAzP4rfXnPtQYFk9zd0bWkLz13szBmtxjpJ\n\tRoiqW1hMqAHESclhKdU7mfIjtd650aNPG62IJJVMEqBQ26MhJ2+ff7cmrsEbDWuBQe\n\t94m7kFgTk3UZx1QaEfuGvf++OAkv5tLCtdkgVf3w=","Date":"Tue, 29 Oct 2024 00:35:29 +0200","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Naushir Patuck <naush@raspberrypi.com>","Cc":"libcamera-devel@lists.libcamera.org,\n\tJacopo Mondi <jacopo.mondi@ideasonboard.com>","Subject":"Re: [PATCH v3 7/7] pipeline: rpi: Handler controls::rpi::ScalerCrops","Message-ID":"<20241028223529.GC22600@pendragon.ideasonboard.com>","References":"<20241003074720.18882-1-naush@raspberrypi.com>\n\t<20241003074720.18882-8-naush@raspberrypi.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<20241003074720.18882-8-naush@raspberrypi.com>","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":31953,"web_url":"https://patchwork.libcamera.org/comment/31953/","msgid":"<CAEmqJPpRKoAu6FRkpguUJ3yFTE2VnxemnGp2V8W14GR7A7q8Ew@mail.gmail.com>","date":"2024-10-29T08:58:46","subject":"Re: [PATCH v3 7/7] pipeline: rpi: Handler controls::rpi::ScalerCrops","submitter":{"id":34,"url":"https://patchwork.libcamera.org/api/people/34/","name":"Naushir Patuck","email":"naush@raspberrypi.com"},"content":"Hi Laurent,\n\nOn Mon, 28 Oct 2024 at 22:35, Laurent Pinchart\n<laurent.pinchart@ideasonboard.com> wrote:\n>\n> Hi Naush,\n>\n> Thank you for the patch.\n>\n> On Thu, Oct 03, 2024 at 08:47:20AM +0100, Naushir Patuck wrote:\n> > Handle multiple scaler crops being set through the rpi::ScalerCrops\n> > control. We now populate the cropParams_ map in the loop where we handle\n> > the output stream configuration items. The key of this map is the index\n> > of the stream configuration structure set by the application. This will\n> > also be the same index used to specify the crop rectangles through the\n> > ScalerCrops control.\n> >\n> > CameraData::applyScalerCrop() has been adapted to look at either\n> > controls::ScalerCrop or controls::rpi::ScalerCrops. The former takes\n> > priority over the latter, and if present, will apply the same scaler\n> > crop to all output streams.\n>\n> That contradicts patch 1/7 that states\n>\n>         If both rpi::ScalerCrops and ScalerCrop controls are present in a\n>         ControlList, the latter is discarded, and crops are obtained from this\n>         control.\n>\n> and also contradicts the code below.\n\nYes, this is an error in the commit message.  I'll update this to\nreflect that rpi::ScalerCrops take precedence.\n\n>\n> >\n> > Finally return all crops through the same ScalerCrops control via\n> > request metadata. The first configure stream's crop rectangle is also\n> > returned via the ScalerCrop control in the request metadata.\n> >\n> > Signed-off-by: Naushir Patuck <naush@raspberrypi.com>\n> > Reviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>\n> > ---\n> >  .../pipeline/rpi/common/pipeline_base.cpp     | 76 ++++++++++++++-----\n> >  1 file changed, 59 insertions(+), 17 deletions(-)\n> >\n> > diff --git a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp\n> > index 267e6bd9cd70..eba4dad6d212 100644\n> > --- a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp\n> > +++ b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp\n> > @@ -181,12 +181,14 @@ CameraConfiguration::Status RPiCameraConfiguration::validate()\n> >\n> >       rawStreams_.clear();\n> >       outStreams_.clear();\n> > +     unsigned int rawStreamIndex = 0;\n> > +     unsigned int outStreamIndex = 0;\n> >\n> > -     for (const auto &[index, cfg] : utils::enumerate(config_)) {\n> > +     for (auto &cfg : config_) {\n> >               if (PipelineHandlerBase::isRaw(cfg.pixelFormat))\n> > -                     rawStreams_.emplace_back(index, &cfg);\n> > +                     rawStreams_.emplace_back(rawStreamIndex++, &cfg);\n> >               else\n> > -                     outStreams_.emplace_back(index, &cfg);\n> > +                     outStreams_.emplace_back(outStreamIndex++, &cfg);\n>\n> This changes the indices, but as far as I can tell, they're currently\n> unused, so that should be fine. Do I assume correctly the will be used\n> in the Pi 5 platformConfigure() implementation to populate cropParams_\n> in the right order ?\n\nThat's correct, the VC4 pipeline handler doesn't use this index, it's\nonly for PISP where the control is used.\n\n>\n> >       }\n> >\n> >       /* Sort the streams so the highest resolution is first. */\n> > @@ -565,10 +567,24 @@ int PipelineHandlerBase::configure(Camera *camera, CameraConfiguration *config)\n> >       const auto cropParamsIt = data->cropParams_.find(0);\n> >       if (cropParamsIt != data->cropParams_.end()) {\n> >               const CameraData::CropParams &cropParams = cropParamsIt->second;\n> > -             /* Add the ScalerCrop control limits based on the current mode. */\n> > +             /*\n> > +              * Add the ScalerCrop control limits based on the current mode and\n> > +              * the first configured stream.\n> > +              */\n> >               Rectangle ispMinCrop = data->scaleIspCrop(Rectangle(cropParams.ispMinCropSize));\n> >               ctrlMap[&controls::ScalerCrop] = ControlInfo(ispMinCrop, data->sensorInfo_.analogCrop,\n> >                                                            data->scaleIspCrop(cropParams.ispCrop));\n> > +             if (data->cropParams_.size() == 2) {\n> > +                     /*\n> > +                      * The control map for rpi::ScalerCrops has the min value\n> > +                      * as the default crop for stream 0, max value as the default\n> > +                      * value for stream 1.\n>\n> That sounds like a real hack. I'm fine with it for now, but should it be\n> documented in 1/7 ? Or would you rather not have anyone depending on\n> this ?\n\n100% a hack.  I'd be happy to see us get rid of this asap when we have\nreal per-stream controls.  I intend on working on this next...\n\n>\n> > +                      */\n> > +                     ctrlMap[&controls::rpi::ScalerCrops] =\n> > +                             ControlInfo(data->scaleIspCrop(data->cropParams_.at(0).ispCrop),\n> > +                                         data->scaleIspCrop(data->cropParams_.at(1).ispCrop),\n> > +                                         ctrlMap[&controls::ScalerCrop].def());\n> > +             }\n> >       }\n> >\n> >       data->controlInfo_ = ControlInfoMap(std::move(ctrlMap), result.controlInfo.idmap());\n> > @@ -1295,11 +1311,29 @@ Rectangle CameraData::scaleIspCrop(const Rectangle &ispCrop) const\n> >\n> >  void CameraData::applyScalerCrop(const ControlList &controls)\n> >  {\n> > -     const auto &scalerCrop = controls.get<Rectangle>(controls::ScalerCrop);\n> > -     const auto cropParamsIt = cropParams_.find(0);\n> > -     if (scalerCrop && cropParamsIt != cropParams_.end()) {\n> > -             Rectangle nativeCrop = *scalerCrop;\n> > -             CropParams &cropParams = cropParamsIt->second;\n> > +     const auto &scalerCropRPi = controls.get<Span<const Rectangle>>(controls::rpi::ScalerCrops);\n> > +     const auto &scalerCropCore = controls.get<Rectangle>(controls::ScalerCrop);\n> > +     std::vector<Rectangle> scalerCrops;\n> > +\n> > +     /*\n> > +      * First thing to do is create a vector of crops to apply to each ISP output\n> > +      * based on either controls::ScalerCrop or controls::rpi::ScalerCrops if\n> > +      * present.\n> > +      *\n> > +      * If controls::ScalerCrop is present, apply the same crop to all ISP output\n> > +      * streams. Otherwise if controls::rpi::ScalerCrops, apply the given crops\n> > +      * to the ISP output streams, indexed by the same order in which they had\n> > +      * been configured. This is not the same as the ISP output index.\n>\n> This also contradicts the code below. You can pick the begaviour you\n> want, but let's make documentation, comments, commit messages and code\n> consistent.\n\nAs above, I'll fix up the comment here as well.\n\nRegards,\nNaush\n\n>\n> > +      */\n> > +     for (unsigned int i = 0; i < cropParams_.size(); i++) {\n> > +             if (scalerCropRPi && i < scalerCropRPi->size())\n> > +                     scalerCrops.push_back(scalerCropRPi->data()[i]);\n> > +             else if (scalerCropCore)\n> > +                     scalerCrops.push_back(*scalerCropCore);\n> > +     }\n> > +\n> > +     for (auto const &[i, scalerCrop] : utils::enumerate(scalerCrops)) {\n> > +             Rectangle nativeCrop = scalerCrop;\n> >\n> >               if (!nativeCrop.width || !nativeCrop.height)\n> >                       nativeCrop = { 0, 0, 1, 1 };\n> > @@ -1315,13 +1349,13 @@ void CameraData::applyScalerCrop(const ControlList &controls)\n> >                * 2. With the same mid-point, if possible.\n> >                * 3. But it can't go outside the sensor area.\n> >                */\n> > -             Size minSize = cropParams.ispMinCropSize.expandedToAspectRatio(nativeCrop.size());\n> > +             Size minSize = cropParams_.at(i).ispMinCropSize.expandedToAspectRatio(nativeCrop.size());\n> >               Size size = ispCrop.size().expandedTo(minSize);\n> >               ispCrop = size.centeredTo(ispCrop.center()).enclosedIn(Rectangle(sensorInfo_.outputSize));\n> >\n> > -             if (ispCrop != cropParams.ispCrop) {\n> > -                     cropParams.ispCrop = ispCrop;\n> > -                     platformSetIspCrop(cropParams.ispIndex, ispCrop);\n> > +             if (ispCrop != cropParams_.at(i).ispCrop) {\n> > +                     cropParams_.at(i).ispCrop = ispCrop;\n> > +                     platformSetIspCrop(cropParams_.at(i).ispIndex, ispCrop);\n> >               }\n> >       }\n> >  }\n> > @@ -1478,10 +1512,18 @@ void CameraData::fillRequestMetadata(const ControlList &bufferControls, Request\n> >       request->metadata().set(controls::SensorTimestamp,\n> >                               bufferControls.get(controls::SensorTimestamp).value_or(0));\n> >\n> > -     const auto cropParamsIt = cropParams_.find(0);\n> > -     if (cropParamsIt != cropParams_.end())\n> > -             request->metadata().set(controls::ScalerCrop,\n> > -                                     scaleIspCrop(cropParamsIt->second.ispCrop));\n> > +     if (cropParams_.size()) {\n> > +             std::vector<Rectangle> crops;\n> > +\n> > +             for (auto const &[k, v] : cropParams_)\n> > +                     crops.push_back(scaleIspCrop(v.ispCrop));\n> > +\n> > +             request->metadata().set(controls::ScalerCrop, crops[0]);\n> > +             if (crops.size() > 1) {\n> > +                     request->metadata().set(controls::rpi::ScalerCrops,\n> > +                                             Span<const Rectangle>(crops.data(), crops.size()));\n> > +             }\n> > +     }\n> >  }\n> >\n> >  } /* namespace libcamera */\n>\n> --\n> Regards,\n>\n> Laurent Pinchart","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 2FDD5C3220\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue, 29 Oct 2024 08:59:26 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id CDD14653A8;\n\tTue, 29 Oct 2024 09:59:25 +0100 (CET)","from mail-yw1-x112c.google.com (mail-yw1-x112c.google.com\n\t[IPv6:2607:f8b0:4864:20::112c])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 56C9665399\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 29 Oct 2024 09:59:23 +0100 (CET)","by mail-yw1-x112c.google.com with SMTP id\n\t00721157ae682-6e353f1e877so3742447b3.1\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 29 Oct 2024 01:59:23 -0700 (PDT)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (2048-bit key;\n\tunprotected) header.d=raspberrypi.com header.i=@raspberrypi.com\n\theader.b=\"SM2XoDhd\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=raspberrypi.com; s=google; t=1730192362; x=1730797162;\n\tdarn=lists.libcamera.org; \n\th=cc:to:subject:message-id:date:from:in-reply-to:references\n\t:mime-version:from:to:cc:subject:date:message-id:reply-to;\n\tbh=QXNN6aZPxPc7WBCvuP4rwsI+y7kT26DlhpOL0yQde9A=;\n\tb=SM2XoDhdYIgRdo5JJfItXwrJcGsTFEu0mo+QTKHjMuHWRKbj5Eqfx9dYPlCRmrR5i7\n\tADrukdfzGWpsnMKqnzhO+5fRGiq1Dd0wxayu5kOhBYYiWZX7OrH1OoZldOlUdn2Pnu7g\n\tMfFnBboZlaTvDN4+bRRQCQ4h20U/Owb0iWK4H52ly8Wuro/aBDXkgra6KfDJE6o8dyB5\n\t6diTvQKgTDzRpyuHDEtBV2eLjepNL/mfvveQd0Ppz+7P6J+3KjOySCLmmzHKtH74PRu7\n\tG5DCMC/+18iVSkSW+NYRg7S6ZULpcnEG25uR3a/0BlRmJ48KD9pF3Pbe62qyYgJtuGzD\n\taq/g==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20230601; t=1730192362; x=1730797162;\n\th=cc:to:subject:message-id:date:from:in-reply-to:references\n\t:mime-version:x-gm-message-state:from:to:cc:subject:date:message-id\n\t:reply-to;\n\tbh=QXNN6aZPxPc7WBCvuP4rwsI+y7kT26DlhpOL0yQde9A=;\n\tb=sOrYpAmfkxEaFqDMOHkEBI86766KVfhuEF+tfb9Zj54nYGtNZPpyHpUDiYCeAd2my6\n\tmWUnMqZWJIJFknj8OrUx6T8gmCxSL6A3RnFDHE9ao6GfHvo2re7Cm1bFRwEHJfnBUhX3\n\tHcMvVLd/fK2CXGgC8HQET1DH6JSb4Ak09Mn+hhnVzZYNZLo+9YILRysW/wmgO9Fcde5+\n\tCkpl+iVjJI+xVKxIDO1FHEO2a/CR0RH/l7mxRHuFwO22cmdbca+Yo0BDRxFc6t3Mu1se\n\t/k9NMU7miBLzKOp7TMu2V7x9LmTzaP/RbXuMznKvStXKVAM1V7JBkUhyImQq44pJPiEZ\n\tFuPw==","X-Gm-Message-State":"AOJu0Yw5BQe82sEoWNsp6vtN20GjzKBRd816sBxPW5GaNr+UNDCpnxA1\n\tkmd0R6hcT/IoaoOXgcWhemEBUwXzl9S30P+Bh/2Opl6ujBWxUkP2NQW29IKlVss+s/+dX2IM3Gy\n\ttD7ala7RR3pnG5YvaiSwnbpQ+yvEw3999HY033l1yJ1hpo1oC","X-Google-Smtp-Source":"AGHT+IEm6oaxweXRIwSjKVRtxXsQLQJX7mvzMpIoHao2FISpWw7IMABeVWKV+hZHRydhQnQh53541TYZeEN8OCoQrfs=","X-Received":"by 2002:a05:690c:7a1:b0:6dd:c828:485a with SMTP id\n\t00721157ae682-6e9d8b33118mr46699307b3.8.1730192362106;\n\tTue, 29 Oct 2024 01:59:22 -0700 (PDT)","MIME-Version":"1.0","References":"<20241003074720.18882-1-naush@raspberrypi.com>\n\t<20241003074720.18882-8-naush@raspberrypi.com>\n\t<20241028223529.GC22600@pendragon.ideasonboard.com>","In-Reply-To":"<20241028223529.GC22600@pendragon.ideasonboard.com>","From":"Naushir Patuck <naush@raspberrypi.com>","Date":"Tue, 29 Oct 2024 08:58:46 +0000","Message-ID":"<CAEmqJPpRKoAu6FRkpguUJ3yFTE2VnxemnGp2V8W14GR7A7q8Ew@mail.gmail.com>","Subject":"Re: [PATCH v3 7/7] pipeline: rpi: Handler controls::rpi::ScalerCrops","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org, \n\tJacopo Mondi <jacopo.mondi@ideasonboard.com>","Content-Type":"text/plain; charset=\"UTF-8\"","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>"}}]