@@ -57,6 +57,7 @@ static const ControlInfoMap RPiControls = {
{ &controls::Saturation, ControlInfo(0.0f, 32.0f) },
{ &controls::Sharpness, ControlInfo(0.0f, 16.0f, 1.0f) },
{ &controls::ColourCorrectionMatrix, ControlInfo(-16.0f, 16.0f) },
+ { &controls::SensorCrop, ControlInfo(Rectangle(0, 0, 0, 0), Rectangle(65535, 65535, 65535, 65535), Rectangle(0, 0, 0, 0)) },
};
} /* namespace libcamera */
@@ -687,6 +687,13 @@ void IPARPi::queueRequest(const ControlList &controls)
break;
}
+ case controls::SENSOR_CROP: {
+ /* Just copy the information back. */
+ Rectangle crop = ctrl.second.get<Rectangle>();
+ libcameraMetadata_.set(controls::SensorCrop, crop);
+ break;
+ }
+
default:
LOG(IPARPI, Warning)
<< "Ctrl " << controls::controls.at(ctrl.first)->name()
@@ -335,6 +335,11 @@ public:
std::queue<FrameBuffer *> embeddedQueue_;
std::deque<Request *> requestQueue_;
+ /* For handling digital zoom. */
+ Size ispMinSize_;
+ Size sensorOutputSize_;
+ Rectangle lastSensorCrop_;
+
private:
void checkRequestCompleted();
void tryRunPipeline();
@@ -737,6 +742,16 @@ int PipelineHandlerRPi::configure(Camera *camera, CameraConfiguration *config)
return ret;
}
+ /*
+ * Figure out the smallest selection the ISP will allow. We also store
+ * the output image size, in pixels, from the sensor. These will be
+ * used for digital zoom.
+ */
+ Rectangle testCrop(0, 0, 1, 1);
+ data->isp_[Isp::Input].dev()->setSelection(V4L2_SEL_TGT_CROP, &testCrop);
+ data->ispMinSize_ = testCrop.size();
+ data->sensorOutputSize_ = sensorFormat.size;
+
/* Adjust aspect ratio by providing crops on the input image. */
Rectangle crop{ 0, 0, sensorFormat.size };
@@ -753,6 +768,8 @@ int PipelineHandlerRPi::configure(Camera *camera, CameraConfiguration *config)
crop.y = (sensorFormat.size.height - crop.height) >> 1;
data->isp_[Isp::Input].dev()->setSelection(V4L2_SEL_TGT_CROP, &crop);
+ data->lastSensorCrop_ = crop;
+
ret = data->configureIPA();
if (ret)
LOG(RPI, Error) << "Failed to configure the IPA: " << ret;
@@ -1545,6 +1562,28 @@ void RPiCameraData::tryRunPipeline()
*/
Request *request = requestQueue_.front();
+ if (request->controls().contains(controls::SensorCrop)) {
+ Rectangle crop = request->controls().get<Rectangle>(controls::SensorCrop);
+ if (crop.width && crop.height) {
+ /*
+ * The crop that we set must be:
+ * 1. At least as big as ispMinSize_, 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.
+ */
+ Size minSize = ispMinSize_.aspectRatioUp(crop.size());
+ Size size = crop.size().expandedTo(minSize);
+ crop = size.centre(crop).clamp(Rectangle(sensorOutputSize_));
+
+ if (crop != lastSensorCrop_)
+ isp_[Isp::Input].dev()->setSelection(V4L2_SEL_TGT_CROP, &crop);
+ lastSensorCrop_ = crop;
+ }
+
+ request->controls().set(controls::SensorCrop, lastSensorCrop_);
+ }
+
/*
* Process all the user controls by the IPA. Once this is complete, we
* queue the ISP output buffer listed in the request to start the HW