[libcamera-devel] [PATCH v2] cam: kms_sink: Remove limitation that camera and display must match

Eric Curtin ecurtin at redhat.com
Mon Feb 7 16:00:59 CET 2022


There is a limitation that requires input and output to be pixel
for pixel identical in terms of height and width. Remove this
limitation to enable more hardware that doesn't match exactly in
terms of pixels. Centralize the image. This works for the case
where camera output has more pixels than the display and
vice-versa. In the case where there are too many pixels for the
display, we take the most central part of the image cropping out
the border.

Signed-off-by: Eric Curtin <ecurtin at redhat.com>
---

Changes in v2:
- Tested and support drawing from negative pixel range
  kernel parameter (video=960x540 at 60) was useful here

 src/cam/kms_sink.cpp | 32 ++++++++++++++------------------
 src/cam/kms_sink.h   |  2 ++
 2 files changed, 16 insertions(+), 18 deletions(-)

diff --git a/src/cam/kms_sink.cpp b/src/cam/kms_sink.cpp
index 973cd370..8eb51454 100644
--- a/src/cam/kms_sink.cpp
+++ b/src/cam/kms_sink.cpp
@@ -113,24 +113,20 @@ int KMSSink::configure(const libcamera::CameraConfiguration &config)
 	const libcamera::StreamConfiguration &cfg = config.at(0);
 
 	const std::vector<DRM::Mode> &modes = connector_->modes();
-	const auto iter = std::find_if(modes.begin(), modes.end(),
-				       [&](const DRM::Mode &mode) {
-					       return mode.hdisplay == cfg.size.width &&
-						      mode.vdisplay == cfg.size.height;
-				       });
-	if (iter == modes.end()) {
-		std::cerr
-			<< "No mode matching " << cfg.size.toString()
-			<< std::endl;
-		return -EINVAL;
-	}
 
 	int ret = configurePipeline(cfg.pixelFormat);
 	if (ret < 0)
 		return ret;
 
-	mode_ = &*iter;
+	mode_ = &modes[0];
 	size_ = cfg.size;
+
+	// We need to cast for the case where the camera output has more
+	// pixels than the display, in this case we start drawing from a
+	// negative pixel point to crop out the content to display just
+	// the middle part.
+	x_ = (mode_->hdisplay - static_cast<int>(size_.width)) / 2;
+	y_ = (mode_->vdisplay - static_cast<int>(size_.height)) / 2;
 	stride_ = cfg.stride;
 
 	return 0;
@@ -297,12 +293,12 @@ bool KMSSink::processRequest(libcamera::Request *camRequest)
 		drmRequest->addProperty(plane_, "CRTC_ID", crtc_->id());
 		drmRequest->addProperty(plane_, "SRC_X", 0 << 16);
 		drmRequest->addProperty(plane_, "SRC_Y", 0 << 16);
-		drmRequest->addProperty(plane_, "SRC_W", mode_->hdisplay << 16);
-		drmRequest->addProperty(plane_, "SRC_H", mode_->vdisplay << 16);
-		drmRequest->addProperty(plane_, "CRTC_X", 0);
-		drmRequest->addProperty(plane_, "CRTC_Y", 0);
-		drmRequest->addProperty(plane_, "CRTC_W", mode_->hdisplay);
-		drmRequest->addProperty(plane_, "CRTC_H", mode_->vdisplay);
+		drmRequest->addProperty(plane_, "SRC_W", size_.width << 16);
+		drmRequest->addProperty(plane_, "SRC_H", size_.height << 16);
+		drmRequest->addProperty(plane_, "CRTC_X", x_);
+		drmRequest->addProperty(plane_, "CRTC_Y", y_);
+		drmRequest->addProperty(plane_, "CRTC_W", size_.width);
+		drmRequest->addProperty(plane_, "CRTC_H", size_.height);
 
 		flags |= DRM::AtomicRequest::FlagAllowModeset;
 	}
diff --git a/src/cam/kms_sink.h b/src/cam/kms_sink.h
index 4a0a872c..2c16182c 100644
--- a/src/cam/kms_sink.h
+++ b/src/cam/kms_sink.h
@@ -61,6 +61,8 @@ private:
 	libcamera::PixelFormat format_;
 	libcamera::Size size_;
 	unsigned int stride_;
+	int x_;  // Where to start drawing camera output
+	int y_;  // Where to start drawing camera output
 
 	std::map<libcamera::FrameBuffer *, std::unique_ptr<DRM::FrameBuffer>> buffers_;
 
-- 
2.34.1



More information about the libcamera-devel mailing list