summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorUmang Jain <umang.jain@ideasonboard.com>2024-09-26 15:06:21 +0530
committerUmang Jain <umang.jain@ideasonboard.com>2024-10-24 14:04:31 +0530
commit1b0b90a332e21fdc6b302740eeb414731c79fd3b (patch)
tree90ecdfd4508a28cbd5d24cabdd829b5e9b0ec19f /src
parent7fad22efae4e89374d1767642cdd0bb4d683df1f (diff)
libcamera: converter: Add interface to support cropping capability
If the converter has cropping capability on its input, the interface should support it by providing appropriate virtual functions. Provide Feature::InputCrop in Feature enumeration for the same. Provide virtual setInputCrop() and inputCropBounds() interfaces so that the converter can implement its own cropping functionality. The V4L2M2MConverter implements these interfaces of the Converter interface. Not all V4L2M2M converters will have cropping ability on its input, hence it needs to be discovered at construction time. If the capability to crop is identified successfully, the cropping bounds are determined during configure() time. Signed-off-by: Umang Jain <umang.jain@ideasonboard.com> Reviewed-by: Paul Elder <paul.elder@ideasonboard.com> Reviewed-by: Stefan Klug <stefan.klug@ideasonboard.com>
Diffstat (limited to 'src')
-rw-r--r--src/libcamera/converter.cpp37
-rw-r--r--src/libcamera/converter/converter_v4l2_m2m.cpp110
2 files changed, 147 insertions, 0 deletions
diff --git a/src/libcamera/converter.cpp b/src/libcamera/converter.cpp
index d7bb7273..945f2527 100644
--- a/src/libcamera/converter.cpp
+++ b/src/libcamera/converter.cpp
@@ -11,6 +11,8 @@
#include <libcamera/base/log.h>
+#include <libcamera/stream.h>
+
#include "libcamera/internal/media_device.h"
/**
@@ -39,6 +41,8 @@ LOG_DEFINE_CATEGORY(Converter)
* \brief Specify the features supported by the converter
* \var Converter::Feature::None
* \brief No extra features supported by the converter
+ * \var Converter::Feature::InputCrop
+ * \brief Cropping capability at input is supported by the converter
*/
/**
@@ -162,6 +166,39 @@ Converter::~Converter()
*/
/**
+ * \fn Converter::setInputCrop()
+ * \brief Set the crop rectangle \a rect for \a stream
+ * \param[in] stream The output stream
+ * \param[inout] rect The crop rectangle to apply and return the rectangle
+ * that is actually applied
+ *
+ * Set the crop rectangle \a rect for \a stream provided the converter supports
+ * cropping. The converter has the Feature::InputCrop flag in this case.
+ *
+ * The underlying hardware can adjust the rectangle supplied by the user
+ * due to hardware constraints. The caller can inspect \a rect to determine the
+ * actual rectangle that has been applied by the converter, after this function
+ * returns.
+ *
+ * \return 0 on success or a negative error code otherwise
+ */
+
+/**
+ * \fn Converter::inputCropBounds()
+ * \brief Retrieve the crop bounds for \a stream
+ * \param[in] stream The output stream
+ *
+ * Retrieve the minimum and maximum crop bounds for \a stream. The converter
+ * should support cropping (Feature::InputCrop).
+ *
+ * The crop bounds depend on the configuration of the output stream and hence
+ * this function should be called after the \a stream has been configured using
+ * configure().
+ *
+ * \return A pair containing the minimum and maximum crop bound in that order
+ */
+
+/**
* \var Converter::inputBufferReady
* \brief A signal emitted when the input frame buffer completes
*/
diff --git a/src/libcamera/converter/converter_v4l2_m2m.cpp b/src/libcamera/converter/converter_v4l2_m2m.cpp
index 4f3e8ce4..d63ef2f8 100644
--- a/src/libcamera/converter/converter_v4l2_m2m.cpp
+++ b/src/libcamera/converter/converter_v4l2_m2m.cpp
@@ -97,6 +97,44 @@ int V4L2M2MConverter::V4L2M2MStream::configure(const StreamConfiguration &inputC
inputBufferCount_ = inputCfg.bufferCount;
outputBufferCount_ = outputCfg.bufferCount;
+ if (converter_->features() & Feature::InputCrop) {
+ Rectangle minCrop;
+ Rectangle maxCrop;
+
+ /* Find crop bounds */
+ minCrop.width = 1;
+ minCrop.height = 1;
+ maxCrop.width = UINT_MAX;
+ maxCrop.height = UINT_MAX;
+
+ ret = setInputSelection(V4L2_SEL_TGT_CROP, &minCrop);
+ if (ret) {
+ LOG(Converter, Error)
+ << "Could not query minimum selection crop: "
+ << strerror(-ret);
+ return ret;
+ }
+
+ ret = getInputSelection(V4L2_SEL_TGT_CROP_BOUNDS, &maxCrop);
+ if (ret) {
+ LOG(Converter, Error)
+ << "Could not query maximum selection crop: "
+ << strerror(-ret);
+ return ret;
+ }
+
+ /* Reset the crop to its maximum */
+ ret = setInputSelection(V4L2_SEL_TGT_CROP, &maxCrop);
+ if (ret) {
+ LOG(Converter, Error)
+ << "Could not reset selection crop: "
+ << strerror(-ret);
+ return ret;
+ }
+
+ inputCropBounds_ = { minCrop, maxCrop };
+ }
+
return 0;
}
@@ -154,6 +192,21 @@ int V4L2M2MConverter::V4L2M2MStream::queueBuffers(FrameBuffer *input, FrameBuffe
return 0;
}
+int V4L2M2MConverter::V4L2M2MStream::getInputSelection(unsigned int target, Rectangle *rect)
+{
+ return m2m_->output()->getSelection(target, rect);
+}
+
+int V4L2M2MConverter::V4L2M2MStream::setInputSelection(unsigned int target, Rectangle *rect)
+{
+ return m2m_->output()->setSelection(target, rect);
+}
+
+std::pair<Rectangle, Rectangle> V4L2M2MConverter::V4L2M2MStream::inputCropBounds()
+{
+ return inputCropBounds_;
+}
+
std::string V4L2M2MConverter::V4L2M2MStream::logPrefix() const
{
return stream_->configuration().toString();
@@ -204,6 +257,33 @@ V4L2M2MConverter::V4L2M2MConverter(MediaDevice *media)
m2m_.reset();
return;
}
+
+ /* Discover Feature::InputCrop */
+ Rectangle maxCrop;
+ maxCrop.width = UINT_MAX;
+ maxCrop.height = UINT_MAX;
+
+ ret = m2m_->output()->setSelection(V4L2_SEL_TGT_CROP, &maxCrop);
+ if (ret)
+ return;
+
+ /*
+ * Rectangles for cropping targets are defined even if the device
+ * does not support cropping. Their sizes and positions will be
+ * fixed in such cases.
+ *
+ * Set and inspect a crop equivalent to half of the maximum crop
+ * returned earlier. Use this to determine whether the crop on
+ * input is really supported.
+ */
+ Rectangle halfCrop(maxCrop.size() / 2);
+ ret = m2m_->output()->setSelection(V4L2_SEL_TGT_CROP, &halfCrop);
+ if (!ret && halfCrop != maxCrop) {
+ features_ |= Feature::InputCrop;
+
+ LOG(Converter, Info)
+ << "Converter supports cropping on its input";
+ }
}
/**
@@ -374,6 +454,36 @@ int V4L2M2MConverter::exportBuffers(const Stream *stream, unsigned int count,
}
/**
+ * \copydoc libcamera::Converter::setInputCrop
+ */
+int V4L2M2MConverter::setInputCrop(const Stream *stream, Rectangle *rect)
+{
+ if (!(features_ & Feature::InputCrop))
+ return -ENOTSUP;
+
+ auto iter = streams_.find(stream);
+ if (iter == streams_.end()) {
+ LOG(Converter, Error) << "Invalid output stream";
+ return -EINVAL;
+ }
+
+ return iter->second->setInputSelection(V4L2_SEL_TGT_CROP, rect);
+}
+
+/**
+ * \copydoc libcamera::Converter::inputCropBounds
+ */
+std::pair<Rectangle, Rectangle>
+V4L2M2MConverter::inputCropBounds(const Stream *stream)
+{
+ auto iter = streams_.find(stream);
+ if (iter == streams_.end())
+ return {};
+
+ return iter->second->inputCropBounds();
+}
+
+/**
* \copydoc libcamera::Converter::start
*/
int V4L2M2MConverter::start()