[PATCH 3/7] mali-c55: implement support for ScalerCrop
Kieran Bingham
kieran.bingham at ideasonboard.com
Thu Jun 13 21:33:11 CEST 2024
Quoting Daniel Scally (2024-06-13 16:59:45)
> From: Jacopo Mondi <jacopo.mondi at ideasonboard.com>
>
> Implement support for the ScalerCrop control that allows to apply a
> digital zoom to the captured streams.
>
> Initialize the camera controls at camera registration time and update
> them at configure time as the sensor's analogue crop size might change
> depending on the desired Camera configuration.
>
> Signed-off-by: Jacopo Mondi <jacopo.mondi at ideasonboard.com>
> ---
> src/libcamera/pipeline/mali-c55/mali-c55.cpp | 138 ++++++++++++++++++-
> 1 file changed, 137 insertions(+), 1 deletion(-)
>
> diff --git a/src/libcamera/pipeline/mali-c55/mali-c55.cpp b/src/libcamera/pipeline/mali-c55/mali-c55.cpp
> index c4f1afbc..2c34f3e9 100644
> --- a/src/libcamera/pipeline/mali-c55/mali-c55.cpp
> +++ b/src/libcamera/pipeline/mali-c55/mali-c55.cpp
> @@ -100,6 +100,8 @@ public:
>
> PixelFormat bestRawFormat() const;
>
> + void updateControls();
> +
> PixelFormat adjustRawFormat(const PixelFormat &pixFmt) const;
> Size adjustRawSizes(const PixelFormat &pixFmt, const Size &rawSize) const;
>
> @@ -245,6 +247,27 @@ PixelFormat MaliC55CameraData::bestRawFormat() const
> return rawFormat;
> }
>
> +void MaliC55CameraData::updateControls()
> +{
> + if (!sensor_)
> + return;
> +
> + IPACameraSensorInfo sensorInfo;
> + int ret = sensor_->sensorInfo(&sensorInfo);
> + if (ret) {
> + LOG(MaliC55, Error) << "Failed to retrieve sensor info";
> + return;
> + }
> +
> + ControlInfoMap::Map controls;
> + Rectangle ispMinCrop{ 0, 0, 640, 480 };
This looks like it should be a constant somewhere outside of here?
Perhaps class constant or just a constant at the top of the file.
> + controls[&controls::ScalerCrop] =
> + ControlInfo(ispMinCrop, sensorInfo.analogCrop,
> + sensorInfo.analogCrop);
> +
> + controlInfo_ = ControlInfoMap(std::move(controls), controls::controls);
> +}
> +
> /*
> * Make sure the provided raw pixel format is supported and adjust it to
> * one of the supported ones if it's not.
> @@ -515,6 +538,8 @@ private:
> const StreamConfiguration &config,
> V4L2SubdeviceFormat &subdevFormat);
>
> + void applyScalerCrop(Camera *camera, const ControlList &controls);
> +
> void registerMaliCamera(std::unique_ptr<MaliC55CameraData> data,
> const std::string &name);
> bool registerTPGCamera(MediaLink *link);
> @@ -828,6 +853,8 @@ int PipelineHandlerMaliC55::configure(Camera *camera,
> pipe->stream = stream;
> }
>
> + data->updateControls();
> +
> return 0;
> }
>
> @@ -875,6 +902,104 @@ void PipelineHandlerMaliC55::stopDevice([[maybe_unused]] Camera *camera)
> }
> }
>
> +void PipelineHandlerMaliC55::applyScalerCrop(Camera *camera,
> + const ControlList &controls)
> +{
> + MaliC55CameraData *data = cameraData(camera);
> +
> + const auto &scalerCrop = controls.get<Rectangle>(controls::ScalerCrop);
> + if (!scalerCrop)
> + return;
> +
> + if (!data->sensor_) {
> + LOG(MaliC55, Error) << "ScalerCrop not supported for TPG";
> + return;
> + }
> +
> + Rectangle nativeCrop = *scalerCrop;
> +
> + IPACameraSensorInfo sensorInfo;
> + int ret = data->sensor_->sensorInfo(&sensorInfo);
> + if (ret) {
> + LOG(MaliC55, Error) << "Failed to retrieve sensor info";
> + return;
> + }
> +
> + /*
> + * The ScalerCrop rectangle re-scaling in the ISP crop rectangle
> + * comes straight from the RPi pipeline handler.
> + *
> + * Create a version of the crop rectangle aligned to the analogue crop
> + * rectangle top-left coordinates and scaled in the [analogue crop to
> + * output frame] ratio to take into account binning/skipping on the
> + * sensor.
> + */
> + Rectangle ispCrop = nativeCrop.translatedBy(-sensorInfo.analogCrop
> + .topLeft());
> + ispCrop.scaleBy(sensorInfo.outputSize, sensorInfo.analogCrop.size());
> +
> + /*
> + * The crop rectangle should be:
> + * 1. At least as big as ispMinCropSize_, once that's been
> + * enlarged to the same aspect ratio.
> + * 2. With the same mid-point, if possible.
> + * 3. But it can't go outside the sensor area.
> + */
> + Rectangle ispMinCrop{ 0, 0, 640, 480 };
Especially if it's used multiple times.
> + Size minSize = ispMinCrop.size().expandedToAspectRatio(nativeCrop.size());
> + Size size = ispCrop.size().expandedTo(minSize);
> + ispCrop = size.centeredTo(ispCrop.center())
> + .enclosedIn(Rectangle(sensorInfo.outputSize));
> +
> + /*
> + * As the resizer can't upscale, the crop rectangle has to be larger
> + * than the larger stream output size.
> + */
> + Size maxYuvSize;
> + for (MaliC55Pipe &pipe : pipes_) {
> +
Probably delete that blank line.
> + if (!pipe.stream)
> + continue;
> +
> + const StreamConfiguration &config = pipe.stream->configuration();
> + if (isFormatRaw(config.pixelFormat)) {
> + LOG(MaliC55, Debug) << "Cannot crop with a RAW stream";
> + return;
> + }
> +
> + Size streamSize = config.size;
> + if (streamSize.width > maxYuvSize.width)
> + maxYuvSize.width = streamSize.width;
> + if (streamSize.height > maxYuvSize.height)
> + maxYuvSize.height = streamSize.height;
> + }
> +
> + ispCrop.size().expandTo(maxYuvSize);
> +
> + /*
> + * Now apply the scaler crop to each enabled output. This overrides the
> + * crop configuration performed at configure() time and can cause
> + * square pixels if the crop rectangle and scaler output FOV ratio are
Can cause 'non square' pixels perhaps?
> + * different.
> + */
> + for (MaliC55Pipe &pipe : pipes_) {
> +
> + if (!pipe.stream)
> + continue;
> +
> + /* Create a copy to avoid setSelection() to modify ispCrop. */
'to prevent setSelection() from modifying ispCrop'
> + Rectangle pipeCrop = ispCrop;
> + ret = pipe.resizer->setSelection(0, V4L2_SEL_TGT_CROP, &pipeCrop);
> + if (ret) {
> + LOG(MaliC55, Error)
> + << "Failed to apply crop to "
> + << (pipe.stream == &data->frStream_ ?
> + "FR" : "DS") << " pipe";
> + return;
> + }
> + }
> +}
> +
> int PipelineHandlerMaliC55::queueRequestDevice(Camera *camera, Request *request)
> {
> int ret;
> @@ -887,6 +1012,15 @@ int PipelineHandlerMaliC55::queueRequestDevice(Camera *camera, Request *request)
> return ret;
> }
>
> + /*
> + * Some controls need to be applied immediately, as in example,
> + * the ScalerCrop one.
> + *
> + * \todo Move it buffer queue time (likely after the IPA has filled in
> + * the parameters buffer) once we have plumbed the IPA loop in.
> + */
> + applyScalerCrop(camera, request->controls());
> +
> return 0;
> }
>
> @@ -965,7 +1099,9 @@ bool PipelineHandlerMaliC55::registerSensorCamera(MediaLink *ispLink)
> if (data->init())
> return false;
>
> - /* \todo: Init properties and controls. */
> + /* \todo: Init properties. */
> +
> + data->updateControls();
>
> registerMaliCamera(std::move(data), sensor->name());
> }
> --
> 2.30.2
>
More information about the libcamera-devel
mailing list