@@ -14,6 +14,7 @@
#include <memory>
#include <string>
#include <tuple>
+#include <utility>
#include <vector>
#include <libcamera/base/class.h>
@@ -35,6 +36,7 @@ class Converter
public:
enum class Feature {
None = 0,
+ Crop = (1 << 0),
};
using Features = Flags<Feature>;
@@ -63,6 +65,9 @@ public:
virtual int queueBuffers(FrameBuffer *input,
const std::map<const Stream *, FrameBuffer *> &outputs) = 0;
+ virtual int setCrop(const Stream *stream, Rectangle *rect);
+ virtual std::pair<Rectangle, Rectangle> getCropBounds(const Stream *stream);
+
Signal<FrameBuffer *> inputBufferReady;
Signal<FrameBuffer *> outputBufferReady;
@@ -30,6 +30,7 @@ class Size;
class SizeRange;
class Stream;
struct StreamConfiguration;
+class Rectangle;
class V4L2M2MDevice;
class V4L2M2MConverter : public Converter
@@ -57,6 +58,9 @@ public:
int queueBuffers(FrameBuffer *input,
const std::map<const Stream *, FrameBuffer *> &outputs);
+ int setCrop(const Stream *stream, Rectangle *rect);
+ std::pair<Rectangle, Rectangle> getCropBounds(const Stream *stream);
+
private:
class V4L2M2MStream : protected Loggable
{
@@ -75,6 +79,8 @@ private:
int queueBuffers(FrameBuffer *input, FrameBuffer *output);
+ int setSelection(unsigned int target, Rectangle *rect);
+
protected:
std::string logPrefix() const override;
@@ -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::Crop
+ * \brief Cropping capability is supported by the converter
*/
/**
@@ -161,6 +165,53 @@ Converter::~Converter()
* \return 0 on success or a negative error code otherwise
*/
+/**
+ * \brief Set the crop rectangle \a rect for \a stream
+ * \param[in] stream Pointer to output stream
+ * \param[inout] rect The crop rectangle to be applied
+ *
+ * Set the crop rectangle \a rect for \a stream provided the converter supports
+ * cropping. The converter should have the Feature::Crop flag in this case.
+ *
+ * \return 0 on success or a negative error code otherwise
+ */
+int Converter::setCrop([[maybe_unused]] const Stream *stream, [[maybe_unused]] Rectangle *rect)
+{
+ if (!(getFeatures() & Feature::Crop)) {
+ LOG(Converter, Error) << "Converter doesn't support cropping capabilities";
+ return -ENOTSUP;
+ }
+
+ return 0;
+}
+
+/**
+ * \brief Get the crop bounds \a stream
+ * \param[in] stream Pointer to output stream
+ *
+ * Get the minimum and maximum crop bounds for \a stream. The converter
+ * should supporting cropping (Feature::Crop).
+ *
+ * \return A std::pair<Rectangle, Rectangle> containining minimum and maximum
+ * crop bound respectively.
+ */
+std::pair<Rectangle, Rectangle> Converter::getCropBounds([[maybe_unused]] const Stream *stream)
+{
+ const StreamConfiguration &config = stream->configuration();
+ Rectangle rect;
+
+ if (!(getFeatures() & Feature::Crop))
+ LOG(Converter, Error) << "Converter doesn't support cropping capabilities";
+
+ /*
+ * This is base implementation for the Converter class, so just return
+ * the stream configured size as minimum and maximum crop bounds.
+ */
+ rect.size() = config.size;
+
+ return { rect, rect };
+}
+
/**
* \var Converter::inputBufferReady
* \brief A signal emitted when the input frame buffer completes
@@ -155,6 +155,15 @@ int V4L2M2MConverter::V4L2M2MStream::queueBuffers(FrameBuffer *input, FrameBuffe
return 0;
}
+int V4L2M2MConverter::V4L2M2MStream::setSelection(unsigned int target, Rectangle *rect)
+{
+ int ret = m2m_->output()->setSelection(target, rect);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
std::string V4L2M2MConverter::V4L2M2MStream::logPrefix() const
{
return stream_->configuration().toString();
@@ -375,6 +384,81 @@ int V4L2M2MConverter::exportBuffers(const Stream *stream, unsigned int count,
return iter->second->exportBuffers(count, buffers);
}
+/**
+ * \copydoc libcamera::Converter::setCrop
+ */
+int V4L2M2MConverter::setCrop(const Stream *stream, Rectangle *rect)
+{
+ if (!(getFeatures() & Feature::Crop))
+ return -ENOTSUP;
+
+ auto iter = streams_.find(stream);
+ if (iter == streams_.end())
+ return -EINVAL;
+
+ return iter->second->setSelection(V4L2_SEL_TGT_CROP, rect);
+}
+
+/**
+ * \copydoc libcamera::Converter::getCropBounds
+ */
+std::pair<Rectangle, Rectangle>
+V4L2M2MConverter::getCropBounds(const Stream *stream)
+{
+ Rectangle minCrop;
+ Rectangle maxCrop;
+ int ret;
+
+ minCrop.width = 1;
+ minCrop.height = 1;
+ maxCrop.width = UINT_MAX;
+ maxCrop.height = UINT_MAX;
+
+ if (!(getFeatures() & Feature::Crop)) {
+ LOG(Converter, Error) << "Crop functionality is not supported";
+ return {};
+ }
+
+ auto iter = streams_.find(stream);
+ if (iter == streams_.end()) {
+ /*
+ * No streams configured, return minimum and maximum crop
+ * bounds at initialization.
+ */
+ ret = m2m_->output()->setSelection(V4L2_SEL_TGT_CROP, &minCrop);
+ if (ret) {
+ LOG(Converter, Error) << "Failed to query minimum crop bound";
+ return {};
+ }
+
+ ret = m2m_->output()->setSelection(V4L2_SEL_TGT_CROP, &maxCrop);
+ if (ret) {
+ LOG(Converter, Error) << "Failed to query maximum crop bound";
+ return {};
+ }
+
+ return { minCrop, maxCrop };
+ }
+
+ /*
+ * If the streams are configured, return bounds from according to
+ * stream configuration.
+ */
+ ret = setCrop(stream, &minCrop);
+ if (ret) {
+ LOG(Converter, Error) << "Failed to query minimum crop bound";
+ return {};
+ }
+
+ ret = setCrop(stream, &maxCrop);
+ if (ret) {
+ LOG(Converter, Error) << "Failed to query maximum crop bound";
+ return {};
+ }
+
+ return { minCrop, maxCrop };
+}
+
/**
* \copydoc libcamera::Converter::start
*/
@@ -448,6 +532,10 @@ int V4L2M2MConverter::queueBuffers(FrameBuffer *input,
return 0;
}
+/*
+ * \todo: This should be extended to include Feature::Flag to denote
+ * what each converter supports feature-wise.
+ */
static std::initializer_list<std::string> compatibles = {
"mtk-mdp",
"pxp",