[libcamera-devel] [PATCH v3 2/4] libcamera: pipeline: vimc: Switch to using the RGB/YUV Capture video node

Niklas Söderlund niklas.soderlund at ragnatech.se
Thu Aug 8 02:04:02 CEST 2019


Linux commit 85ab1aa1fac17bcd ("media: vimc: deb: fix default sink bayer
format") which is part of v5.2 changes the default media bus format for
the debayer subdevices. This leads to a -EPIPE error when trying to use
the raw capture video device nodes.

Fix this by moving the vimc pipeline to use the RGB/YUV Capture capture
video node. As a consequence of this change the scaler in the vimc
pipeline is used and a hard coded upscale of 3 is present in the video
pipeline. This limits the sizes exposed and accepted by libcamera to
multiples of 3.

The raw capture video node still needs to be handled by the pipeline as
its format needs to be updated to allow the pipeline format validation
to pass.

Signed-off-by: Niklas Söderlund <niklas.soderlund at ragnatech.se>
---
 src/libcamera/pipeline/vimc.cpp | 112 ++++++++++++++++++++++++++++----
 test/camera/buffer_import.cpp   |   8 +--
 2 files changed, 104 insertions(+), 16 deletions(-)

diff --git a/src/libcamera/pipeline/vimc.cpp b/src/libcamera/pipeline/vimc.cpp
index 3d6808222a8a2c5d..55975cae066d71cd 100644
--- a/src/libcamera/pipeline/vimc.cpp
+++ b/src/libcamera/pipeline/vimc.cpp
@@ -10,6 +10,8 @@
 #include <iomanip>
 #include <tuple>
 
+#include <linux/media-bus-format.h>
+
 #include <libcamera/camera.h>
 #include <libcamera/controls.h>
 #include <libcamera/ipa/ipa_interface.h>
@@ -25,6 +27,7 @@
 #include "pipeline_handler.h"
 #include "utils.h"
 #include "v4l2_controls.h"
+#include "v4l2_subdevice.h"
 #include "v4l2_videodevice.h"
 
 namespace libcamera {
@@ -35,21 +38,28 @@ class VimcCameraData : public CameraData
 {
 public:
 	VimcCameraData(PipelineHandler *pipe)
-		: CameraData(pipe), video_(nullptr), sensor_(nullptr)
+		: CameraData(pipe), sensor_(nullptr), debayer_(nullptr),
+		  scaler_(nullptr), video_(nullptr), raw_(nullptr)
 	{
 	}
 
 	~VimcCameraData()
 	{
 		delete sensor_;
+		delete debayer_;
+		delete scaler_;
 		delete video_;
+		delete raw_;
 	}
 
 	int init(MediaDevice *media);
 	void bufferReady(Buffer *buffer);
 
-	V4L2VideoDevice *video_;
 	CameraSensor *sensor_;
+	V4L2Subdevice *debayer_;
+	V4L2Subdevice *scaler_;
+	V4L2VideoDevice *video_;
+	V4L2VideoDevice *raw_;
 	Stream stream_;
 };
 
@@ -80,6 +90,8 @@ public:
 
 	int queueRequest(Camera *camera, Request *request) override;
 
+	int initLinks(MediaDevice *media);
+
 	bool match(DeviceEnumerator *enumerator) override;
 
 private:
@@ -131,8 +143,11 @@ CameraConfiguration::Status VimcCameraConfiguration::validate()
 	/* Clamp the size based on the device limits. */
 	const Size size = cfg.size;
 
-	cfg.size.width = std::max(16U, std::min(4096U, cfg.size.width));
-	cfg.size.height = std::max(16U, std::min(2160U, cfg.size.height));
+	/* Dimensions need to be a multiple of 3 for the scaler to work. */
+	cfg.size.width = std::max(18U, std::min(4096U, cfg.size.width));
+	cfg.size.height = std::max(18U, std::min(2160U, cfg.size.height));
+	cfg.size.width -= cfg.size.width % 3;
+	cfg.size.height -= cfg.size.height % 3;
 
 	if (cfg.size != size) {
 		LOG(VIMC, Debug)
@@ -160,7 +175,7 @@ CameraConfiguration *PipelineHandlerVimc::generateConfiguration(Camera *camera,
 
 	StreamConfiguration cfg{};
 	cfg.pixelFormat = V4L2_PIX_FMT_RGB24;
-	cfg.size = { 640, 480 };
+	cfg.size = { 1920, 1080 };
 	cfg.bufferCount = 4;
 
 	config->addConfiguration(cfg);
@@ -176,6 +191,33 @@ int PipelineHandlerVimc::configure(Camera *camera, CameraConfiguration *config)
 	StreamConfiguration &cfg = config->at(0);
 	int ret;
 
+	/* The scaler hardcodes a x3 scale-up ratio. */
+	V4L2SubdeviceFormat subformat = {};
+	subformat.mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8;
+	subformat.size = { cfg.size.width / 3, cfg.size.height / 3 };
+
+	ret = data->sensor_->setFormat(&subformat);
+	if (ret)
+		return ret;
+
+	ret = data->debayer_->setFormat(0, &subformat);
+	if (ret)
+		return ret;
+
+	subformat.mbus_code = MEDIA_BUS_FMT_RGB888_1X24;
+	ret = data->debayer_->setFormat(1, &subformat);
+	if (ret)
+		return ret;
+
+	ret = data->scaler_->setFormat(0, &subformat);
+	if (ret)
+		return ret;
+
+	subformat.size = cfg.size;
+	ret = data->scaler_->setFormat(1, &subformat);
+	if (ret)
+		return ret;
+
 	V4L2DeviceFormat format = {};
 	format.fourcc = cfg.pixelFormat;
 	format.size = cfg.size;
@@ -188,6 +230,17 @@ int PipelineHandlerVimc::configure(Camera *camera, CameraConfiguration *config)
 	    format.fourcc != cfg.pixelFormat)
 		return -EINVAL;
 
+	/*
+	 * Format has to be set on the raw capture video node, otherwise the
+	 * vimc driver will fail pipeline validation.
+	 */
+	format.fourcc = V4L2_PIX_FMT_SGRBG8;
+	format.size = { cfg.size.width / 3, cfg.size.height / 3 };
+
+	ret = data->raw_->setFormat(&format);
+	if (ret)
+		return ret;
+
 	cfg.setStream(&data->stream_);
 
 	return 0;
@@ -292,6 +345,26 @@ int PipelineHandlerVimc::queueRequest(Camera *camera, Request *request)
 	return 0;
 }
 
+int PipelineHandlerVimc::initLinks(MediaDevice *media)
+{
+	MediaLink *link;
+	int ret;
+
+	ret = media->disableLinks();
+	if (ret < 0)
+		return ret;
+
+	link = media->link("Debayer B", 1, "Scaler", 0);
+	if (!link)
+		return -ENODEV;
+
+	ret = link->setEnabled(true);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
 bool PipelineHandlerVimc::match(DeviceEnumerator *enumerator)
 {
 	DeviceMatch dm("vimc");
@@ -318,6 +391,9 @@ bool PipelineHandlerVimc::match(DeviceEnumerator *enumerator)
 
 	std::unique_ptr<VimcCameraData> data = utils::make_unique<VimcCameraData>(this);
 
+	if (initLinks(media))
+		return false;
+
 	/* Locate and open the capture video node. */
 	if (data->init(media))
 		return false;
@@ -335,18 +411,30 @@ int VimcCameraData::init(MediaDevice *media)
 {
 	int ret;
 
-	/* Create and open the video device and the camera sensor. */
-	video_ = new V4L2VideoDevice(media->getEntityByName("Raw Capture 1"));
-	if (video_->open())
-		return -ENODEV;
-
-	video_->bufferReady.connect(this, &VimcCameraData::bufferReady);
-
+	/* Create and open the camera sensor, debayer, scaler and video device. */
 	sensor_ = new CameraSensor(media->getEntityByName("Sensor B"));
 	ret = sensor_->init();
 	if (ret)
 		return ret;
 
+	debayer_ = new V4L2Subdevice(media->getEntityByName("Debayer B"));
+	if (debayer_->open())
+		return -ENODEV;
+
+	scaler_ = new V4L2Subdevice(media->getEntityByName("Scaler"));
+	if (scaler_->open())
+		return -ENODEV;
+
+	video_ = new V4L2VideoDevice(media->getEntityByName("RGB/YUV Capture"));
+	if (video_->open())
+		return -ENODEV;
+
+	video_->bufferReady.connect(this, &VimcCameraData::bufferReady);
+
+	raw_ = new V4L2VideoDevice(media->getEntityByName("Raw Capture 1"));
+	if (raw_->open())
+		return -ENODEV;
+
 	/* Initialise the supported controls. */
 	const V4L2ControlInfoMap &controls = sensor_->controls();
 	for (const auto &ctrl : controls) {
diff --git a/test/camera/buffer_import.cpp b/test/camera/buffer_import.cpp
index 400d02b350c1aa8f..620ee66dee0570bc 100644
--- a/test/camera/buffer_import.cpp
+++ b/test/camera/buffer_import.cpp
@@ -72,12 +72,12 @@ public:
 			return ret;
 		}
 
-		format_.size.width = 640;
-		format_.size.height = 480;
+		format_.size.width = 1920;
+		format_.size.height = 1080;
 		format_.fourcc = V4L2_PIX_FMT_RGB24;
 		format_.planesCount = 1;
-		format_.planes[0].size = 640 * 480 * 3;
-		format_.planes[0].bpl = 640 * 3;
+		format_.planes[0].size = 1920 * 1080 * 3;
+		format_.planes[0].bpl = 1920 * 3;
 
 		if (video_->setFormat(&format_)) {
 			cleanup();
-- 
2.22.0



More information about the libcamera-devel mailing list