@@ -30,6 +30,7 @@
#include <libcamera/control_ids.h>
#include <libcamera/geometry.h>
#include <libcamera/pixel_format.h>
+#include <libcamera/property_ids.h>
#include <libcamera/stream.h>
#include "libcamera/internal/camera.h"
@@ -44,6 +45,7 @@
#include "libcamera/internal/media_device.h"
#include "libcamera/internal/pipeline_handler.h"
#include "libcamera/internal/request.h"
+#include "libcamera/internal/software_isp/debayer_geometry.h"
#include "libcamera/internal/software_isp/software_isp.h"
#include "libcamera/internal/v4l2_subdevice.h"
#include "libcamera/internal/v4l2_videodevice.h"
@@ -292,6 +294,7 @@ public:
Transform transform = Transform::Identity);
void imageBufferReady(FrameBuffer *buffer);
void clearIncompleteRequests();
+ void updateScalerCrop(const Size &inputSize, Transform transform);
unsigned int streamIndex(const Stream *stream) const
{
@@ -983,6 +986,48 @@ void SimpleCameraData::clearIncompleteRequests()
}
}
+void SimpleCameraData::updateScalerCrop(const Size &inputSize, Transform transform)
+{
+ IPACameraSensorInfo sensorInfo;
+ if (sensor_->sensorInfo(&sensorInfo))
+ return;
+
+ /*
+ * The buffer-to-sensor mapping requires a capture path that preserves
+ * the sensor output. Intermediate cropping or scaling needs a separate
+ * mapping; do not report the analogue crop as if it included that work.
+ */
+ if (sensorInfo.outputSize != inputSize)
+ return;
+
+ for (const Entity &entity : entities_) {
+ if (!entity.sink || !entity.source)
+ continue;
+
+ V4L2Subdevice *subdev = pipe()->subdev(entity.entity);
+ for (const MediaPad *pad : { entity.sink, entity.source }) {
+ V4L2SubdeviceFormat format{};
+ if (subdev->getFormat(pad->index(), &format) ||
+ format.size != inputSize)
+ return;
+
+ for (unsigned int target : { V4L2_SEL_TGT_CROP, V4L2_SEL_TGT_COMPOSE }) {
+ Rectangle selection;
+ int ret = subdev->getSelection(pad->index(), target, &selection, true);
+ if (!ret && selection != Rectangle(inputSize))
+ return;
+ if (ret && ret != -ENOTTY && ret != -EINVAL)
+ return;
+ }
+ }
+ }
+
+ Rectangle crop = debayerCropToSensor(swIsp_->inputCrop(), inputSize,
+ sensorInfo.analogCrop, sensorInfo.activeArea,
+ transform);
+ properties_.set(properties::ScalerCropMaximum, crop);
+}
+
void SimpleCameraData::tryCompleteRequest(Request *request)
{
if (request->hasPendingBuffers())
@@ -1505,6 +1550,8 @@ int SimplePipelineHandler::configure(Camera *camera, CameraConfiguration *c)
V4L2VideoDevice *video = data->video_;
int ret;
+ data->properties_ = data->sensor_->properties();
+
/*
* Configure links on the pipeline and propagate formats from the
* sensor to the video node.
@@ -1605,7 +1652,12 @@ int SimplePipelineHandler::configure(Camera *camera, CameraConfiguration *c)
} else {
ipa::softisp::IPAConfigInfo configInfo;
configInfo.sensorControls = data->sensor_->controls();
- return data->swIsp_->configure(inputCfg, outputCfgs, configInfo, &data->controlInfo_);
+ ret = data->swIsp_->configure(inputCfg, outputCfgs, configInfo, &data->controlInfo_);
+ if (ret)
+ return ret;
+
+ data->updateScalerCrop(inputCfg.size, config->combinedTransform());
+ return 0;
}
}