[libcamera-devel,v4,2/2] libcamera: pipeline: simple: converter: Use generic converter interface
diff mbox series

Message ID 20221214103443.236973-2-xavier.roumegue@oss.nxp.com
State Accepted
Headers show
Series
  • [libcamera-devel,v4,1/2] libcamera: Declare generic converter interface
Related show

Commit Message

Xavier Roumegue Dec. 14, 2022, 10:34 a.m. UTC
Move the simple converter implementation to a generic V4L2 M2M class
derived from the converter interface. This latter could be used by
other pipeline implementations and as base class for customized V4L2 M2M
converters.

Signed-off-by: Xavier Roumegue <xavier.roumegue@oss.nxp.com>
Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
---
 .../internal/converter/converter_v4l2_m2m.h   |  18 +-
 .../libcamera/internal/converter/meson.build  |   5 +
 include/libcamera/internal/meson.build        |   2 +
 .../converter_v4l2_m2m.cpp}                   | 157 ++++++++++++------
 src/libcamera/converter/meson.build           |   5 +
 src/libcamera/meson.build                     |   1 +
 src/libcamera/pipeline/simple/meson.build     |   1 -
 src/libcamera/pipeline/simple/simple.cpp      |   6 +-
 8 files changed, 127 insertions(+), 68 deletions(-)
 rename src/libcamera/pipeline/simple/converter.h => include/libcamera/internal/converter/converter_v4l2_m2m.h (83%)
 create mode 100644 include/libcamera/internal/converter/meson.build
 rename src/libcamera/{pipeline/simple/converter.cpp => converter/converter_v4l2_m2m.cpp} (67%)
 create mode 100644 src/libcamera/converter/meson.build

Patch
diff mbox series

diff --git a/src/libcamera/pipeline/simple/converter.h b/include/libcamera/internal/converter/converter_v4l2_m2m.h
similarity index 83%
rename from src/libcamera/pipeline/simple/converter.h
rename to include/libcamera/internal/converter/converter_v4l2_m2m.h
index f0ebe2e0..ef31eeba 100644
--- a/src/libcamera/pipeline/simple/converter.h
+++ b/include/libcamera/internal/converter/converter_v4l2_m2m.h
@@ -1,8 +1,9 @@ 
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 /*
  * Copyright (C) 2020, Laurent Pinchart
+ * Copyright 2022 NXP
  *
- * converter.h - Format converter for simple pipeline handler
+ * converter_v4l2_m2m.h - V4l2 M2M Format converter interface
  */
 
 #pragma once
@@ -19,6 +20,8 @@ 
 #include <libcamera/base/log.h>
 #include <libcamera/base/signal.h>
 
+#include "libcamera/internal/converter.h"
+
 namespace libcamera {
 
 class FrameBuffer;
@@ -28,11 +31,12 @@  class SizeRange;
 struct StreamConfiguration;
 class V4L2M2MDevice;
 
-class SimpleConverter
+class V4L2M2MConverter : public Converter
 {
 public:
-	SimpleConverter(MediaDevice *media);
+	V4L2M2MConverter(MediaDevice *media);
 
+	int loadConfiguration([[maybe_unused]] const std::string &filename) { return 0; }
 	bool isValid() const { return m2m_ != nullptr; }
 
 	std::vector<PixelFormat> formats(PixelFormat input);
@@ -52,14 +56,11 @@  public:
 	int queueBuffers(FrameBuffer *input,
 			 const std::map<unsigned int, FrameBuffer *> &outputs);
 
-	Signal<FrameBuffer *> inputBufferReady;
-	Signal<FrameBuffer *> outputBufferReady;
-
 private:
 	class Stream : protected Loggable
 	{
 	public:
-		Stream(SimpleConverter *converter, unsigned int index);
+		Stream(V4L2M2MConverter *converter, unsigned int index);
 
 		bool isValid() const { return m2m_ != nullptr; }
 
@@ -80,7 +81,7 @@  private:
 		void captureBufferReady(FrameBuffer *buffer);
 		void outputBufferReady(FrameBuffer *buffer);
 
-		SimpleConverter *converter_;
+		V4L2M2MConverter *converter_;
 		unsigned int index_;
 		std::unique_ptr<V4L2M2MDevice> m2m_;
 
@@ -88,7 +89,6 @@  private:
 		unsigned int outputBufferCount_;
 	};
 
-	std::string deviceNode_;
 	std::unique_ptr<V4L2M2MDevice> m2m_;
 
 	std::vector<Stream> streams_;
diff --git a/include/libcamera/internal/converter/meson.build b/include/libcamera/internal/converter/meson.build
new file mode 100644
index 00000000..891e79e7
--- /dev/null
+++ b/include/libcamera/internal/converter/meson.build
@@ -0,0 +1,5 @@ 
+# SPDX-License-Identifier: CC0-1.0
+
+libcamera_internal_headers += files([
+    'converter_v4l2_m2m.h',
+])
diff --git a/include/libcamera/internal/meson.build b/include/libcamera/internal/meson.build
index 341af8a2..d7508805 100644
--- a/include/libcamera/internal/meson.build
+++ b/include/libcamera/internal/meson.build
@@ -45,3 +45,5 @@  libcamera_internal_headers = files([
     'v4l2_videodevice.h',
     'yaml_parser.h',
 ])
+
+subdir('converter')
diff --git a/src/libcamera/pipeline/simple/converter.cpp b/src/libcamera/converter/converter_v4l2_m2m.cpp
similarity index 67%
rename from src/libcamera/pipeline/simple/converter.cpp
rename to src/libcamera/converter/converter_v4l2_m2m.cpp
index acaaa64c..5995d406 100644
--- a/src/libcamera/pipeline/simple/converter.cpp
+++ b/src/libcamera/converter/converter_v4l2_m2m.cpp
@@ -1,12 +1,11 @@ 
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 /*
  * Copyright (C) 2020, Laurent Pinchart
+ * Copyright 2022 NXP
  *
- * converter.cpp - Format converter for simple pipeline handler
+ * converter_v4l2_m2m.cpp - V4L2 M2M Format converter
  */
 
-#include "converter.h"
-
 #include <algorithm>
 #include <limits.h>
 
@@ -20,19 +19,25 @@ 
 
 #include "libcamera/internal/media_device.h"
 #include "libcamera/internal/v4l2_videodevice.h"
+#include "libcamera/internal/converter/converter_v4l2_m2m.h"
+
+/**
+ * \file internal/converter/converter_v4l2_m2m.h
+ * \brief V4L2 M2M based converter
+ */
 
 namespace libcamera {
 
-LOG_DECLARE_CATEGORY(SimplePipeline)
+LOG_DECLARE_CATEGORY(Converter)
 
 /* -----------------------------------------------------------------------------
- * SimpleConverter::Stream
+ * V4L2M2MConverter::Stream
  */
 
-SimpleConverter::Stream::Stream(SimpleConverter *converter, unsigned int index)
+V4L2M2MConverter::Stream::Stream(V4L2M2MConverter *converter, unsigned int index)
 	: converter_(converter), index_(index)
 {
-	m2m_ = std::make_unique<V4L2M2MDevice>(converter->deviceNode_);
+	m2m_ = std::make_unique<V4L2M2MDevice>(converter->deviceNode());
 
 	m2m_->output()->bufferReady.connect(this, &Stream::outputBufferReady);
 	m2m_->capture()->bufferReady.connect(this, &Stream::captureBufferReady);
@@ -42,8 +47,8 @@  SimpleConverter::Stream::Stream(SimpleConverter *converter, unsigned int index)
 		m2m_.reset();
 }
 
-int SimpleConverter::Stream::configure(const StreamConfiguration &inputCfg,
-				       const StreamConfiguration &outputCfg)
+int V4L2M2MConverter::Stream::configure(const StreamConfiguration &inputCfg,
+					const StreamConfiguration &outputCfg)
 {
 	V4L2PixelFormat videoFormat =
 		m2m_->output()->toV4L2PixelFormat(inputCfg.pixelFormat);
@@ -56,14 +61,14 @@  int SimpleConverter::Stream::configure(const StreamConfiguration &inputCfg,
 
 	int ret = m2m_->output()->setFormat(&format);
 	if (ret < 0) {
-		LOG(SimplePipeline, Error)
+		LOG(Converter, Error)
 			<< "Failed to set input format: " << strerror(-ret);
 		return ret;
 	}
 
 	if (format.fourcc != videoFormat || format.size != inputCfg.size ||
 	    format.planes[0].bpl != inputCfg.stride) {
-		LOG(SimplePipeline, Error)
+		LOG(Converter, Error)
 			<< "Input format not supported (requested "
 			<< inputCfg.size << "-" << videoFormat
 			<< ", got " << format << ")";
@@ -78,13 +83,13 @@  int SimpleConverter::Stream::configure(const StreamConfiguration &inputCfg,
 
 	ret = m2m_->capture()->setFormat(&format);
 	if (ret < 0) {
-		LOG(SimplePipeline, Error)
+		LOG(Converter, Error)
 			<< "Failed to set output format: " << strerror(-ret);
 		return ret;
 	}
 
 	if (format.fourcc != videoFormat || format.size != outputCfg.size) {
-		LOG(SimplePipeline, Error)
+		LOG(Converter, Error)
 			<< "Output format not supported";
 		return -EINVAL;
 	}
@@ -95,13 +100,13 @@  int SimpleConverter::Stream::configure(const StreamConfiguration &inputCfg,
 	return 0;
 }
 
-int SimpleConverter::Stream::exportBuffers(unsigned int count,
-					   std::vector<std::unique_ptr<FrameBuffer>> *buffers)
+int V4L2M2MConverter::Stream::exportBuffers(unsigned int count,
+					    std::vector<std::unique_ptr<FrameBuffer>> *buffers)
 {
 	return m2m_->capture()->exportBuffers(count, buffers);
 }
 
-int SimpleConverter::Stream::start()
+int V4L2M2MConverter::Stream::start()
 {
 	int ret = m2m_->output()->importBuffers(inputBufferCount_);
 	if (ret < 0)
@@ -128,7 +133,7 @@  int SimpleConverter::Stream::start()
 	return 0;
 }
 
-void SimpleConverter::Stream::stop()
+void V4L2M2MConverter::Stream::stop()
 {
 	m2m_->capture()->streamOff();
 	m2m_->output()->streamOff();
@@ -136,8 +141,7 @@  void SimpleConverter::Stream::stop()
 	m2m_->output()->releaseBuffers();
 }
 
-int SimpleConverter::Stream::queueBuffers(FrameBuffer *input,
-					  FrameBuffer *output)
+int V4L2M2MConverter::Stream::queueBuffers(FrameBuffer *input, FrameBuffer *output)
 {
 	int ret = m2m_->output()->queueBuffer(input);
 	if (ret < 0)
@@ -150,12 +154,12 @@  int SimpleConverter::Stream::queueBuffers(FrameBuffer *input,
 	return 0;
 }
 
-std::string SimpleConverter::Stream::logPrefix() const
+std::string V4L2M2MConverter::Stream::logPrefix() const
 {
 	return "stream" + std::to_string(index_);
 }
 
-void SimpleConverter::Stream::outputBufferReady(FrameBuffer *buffer)
+void V4L2M2MConverter::Stream::outputBufferReady(FrameBuffer *buffer)
 {
 	auto it = converter_->queue_.find(buffer);
 	if (it == converter_->queue_.end())
@@ -167,32 +171,34 @@  void SimpleConverter::Stream::outputBufferReady(FrameBuffer *buffer)
 	}
 }
 
-void SimpleConverter::Stream::captureBufferReady(FrameBuffer *buffer)
+void V4L2M2MConverter::Stream::captureBufferReady(FrameBuffer *buffer)
 {
 	converter_->outputBufferReady.emit(buffer);
 }
 
 /* -----------------------------------------------------------------------------
- * SimpleConverter
+ * V4L2M2MConverter
+ */
+
+/**
+ * \class libcamera::V4L2M2MConverter
+ * \brief The V4L2 M2M converter implements the converter interface based on
+ * V4L2 M2M device.
+*/
+
+/**
+ * \fn V4L2M2MConverter::V4L2M2MConverter
+ * \brief Construct a V4L2M2MConverter instance
+ * \param[in] media The media device implementing the converter
  */
 
-SimpleConverter::SimpleConverter(MediaDevice *media)
+V4L2M2MConverter::V4L2M2MConverter(MediaDevice *media)
+	: Converter(media)
 {
-	/*
-	 * Locate the video node. There's no need to validate the pipeline
-	 * further, the caller guarantees that this is a V4L2 mem2mem device.
-	 */
-	const std::vector<MediaEntity *> &entities = media->entities();
-	auto it = std::find_if(entities.begin(), entities.end(),
-			       [](MediaEntity *entity) {
-				       return entity->function() == MEDIA_ENT_F_IO_V4L;
-			       });
-	if (it == entities.end())
+	if (deviceNode().empty())
 		return;
 
-	deviceNode_ = (*it)->deviceNode();
-
-	m2m_ = std::make_unique<V4L2M2MDevice>(deviceNode_);
+	m2m_ = std::make_unique<V4L2M2MDevice>(deviceNode());
 	int ret = m2m_->open();
 	if (ret < 0) {
 		m2m_.reset();
@@ -200,7 +206,21 @@  SimpleConverter::SimpleConverter(MediaDevice *media)
 	}
 }
 
-std::vector<PixelFormat> SimpleConverter::formats(PixelFormat input)
+/**
+ * \fn libcamera::V4L2M2MConverter::loadConfiguration
+ * \details \copydetails libcamera::Converter::loadConfiguration
+ */
+
+/**
+ * \fn libcamera::V4L2M2MConverter::isValid
+ * \details \copydetails libcamera::Converter::isValid
+ */
+
+/**
+ * \fn libcamera::V4L2M2MConverter::formats
+ * \details \copydetails libcamera::Converter::formats
+ */
+std::vector<PixelFormat> V4L2M2MConverter::formats(PixelFormat input)
 {
 	if (!m2m_)
 		return {};
@@ -215,13 +235,13 @@  std::vector<PixelFormat> SimpleConverter::formats(PixelFormat input)
 
 	int ret = m2m_->output()->setFormat(&v4l2Format);
 	if (ret < 0) {
-		LOG(SimplePipeline, Error)
+		LOG(Converter, Error)
 			<< "Failed to set format: " << strerror(-ret);
 		return {};
 	}
 
 	if (v4l2Format.fourcc != m2m_->output()->toV4L2PixelFormat(input)) {
-		LOG(SimplePipeline, Debug)
+		LOG(Converter, Debug)
 			<< "Input format " << input << " not supported.";
 		return {};
 	}
@@ -237,7 +257,10 @@  std::vector<PixelFormat> SimpleConverter::formats(PixelFormat input)
 	return pixelFormats;
 }
 
-SizeRange SimpleConverter::sizes(const Size &input)
+/**
+ * \copydoc libcamera::Converter::sizes
+ */
+SizeRange V4L2M2MConverter::sizes(const Size &input)
 {
 	if (!m2m_)
 		return {};
@@ -252,7 +275,7 @@  SizeRange SimpleConverter::sizes(const Size &input)
 
 	int ret = m2m_->output()->setFormat(&format);
 	if (ret < 0) {
-		LOG(SimplePipeline, Error)
+		LOG(Converter, Error)
 			<< "Failed to set format: " << strerror(-ret);
 		return {};
 	}
@@ -262,7 +285,7 @@  SizeRange SimpleConverter::sizes(const Size &input)
 	format.size = { 1, 1 };
 	ret = m2m_->capture()->setFormat(&format);
 	if (ret < 0) {
-		LOG(SimplePipeline, Error)
+		LOG(Converter, Error)
 			<< "Failed to set format: " << strerror(-ret);
 		return {};
 	}
@@ -272,7 +295,7 @@  SizeRange SimpleConverter::sizes(const Size &input)
 	format.size = { UINT_MAX, UINT_MAX };
 	ret = m2m_->capture()->setFormat(&format);
 	if (ret < 0) {
-		LOG(SimplePipeline, Error)
+		LOG(Converter, Error)
 			<< "Failed to set format: " << strerror(-ret);
 		return {};
 	}
@@ -282,9 +305,12 @@  SizeRange SimpleConverter::sizes(const Size &input)
 	return sizes;
 }
 
+/**
+ * \copydoc libcamera::Converter::strideAndFrameSize
+ */
 std::tuple<unsigned int, unsigned int>
-SimpleConverter::strideAndFrameSize(const PixelFormat &pixelFormat,
-				    const Size &size)
+V4L2M2MConverter::strideAndFrameSize(const PixelFormat &pixelFormat,
+				     const Size &size)
 {
 	V4L2DeviceFormat format;
 	format.fourcc = m2m_->capture()->toV4L2PixelFormat(pixelFormat);
@@ -297,8 +323,11 @@  SimpleConverter::strideAndFrameSize(const PixelFormat &pixelFormat,
 	return std::make_tuple(format.planes[0].bpl, format.planes[0].size);
 }
 
-int SimpleConverter::configure(const StreamConfiguration &inputCfg,
-			       const std::vector<std::reference_wrapper<StreamConfiguration>> &outputCfgs)
+/**
+ * \copydoc libcamera::Converter::configure
+ */
+int V4L2M2MConverter::configure(const StreamConfiguration &inputCfg,
+				const std::vector<std::reference_wrapper<StreamConfiguration>> &outputCfgs)
 {
 	int ret = 0;
 
@@ -309,7 +338,7 @@  int SimpleConverter::configure(const StreamConfiguration &inputCfg,
 		Stream &stream = streams_.emplace_back(this, i);
 
 		if (!stream.isValid()) {
-			LOG(SimplePipeline, Error)
+			LOG(Converter, Error)
 				<< "Failed to create stream " << i;
 			ret = -EINVAL;
 			break;
@@ -328,8 +357,11 @@  int SimpleConverter::configure(const StreamConfiguration &inputCfg,
 	return 0;
 }
 
-int SimpleConverter::exportBuffers(unsigned int output, unsigned int count,
-				   std::vector<std::unique_ptr<FrameBuffer>> *buffers)
+/**
+ * \copydoc libcamera::Converter::exportBuffers
+ */
+int V4L2M2MConverter::exportBuffers(unsigned int output, unsigned int count,
+				    std::vector<std::unique_ptr<FrameBuffer>> *buffers)
 {
 	if (output >= streams_.size())
 		return -EINVAL;
@@ -337,7 +369,10 @@  int SimpleConverter::exportBuffers(unsigned int output, unsigned int count,
 	return streams_[output].exportBuffers(count, buffers);
 }
 
-int SimpleConverter::start()
+/**
+ * \copydoc libcamera::Converter::start
+ */
+int V4L2M2MConverter::start()
 {
 	int ret;
 
@@ -352,14 +387,20 @@  int SimpleConverter::start()
 	return 0;
 }
 
-void SimpleConverter::stop()
+/**
+ * \copydoc libcamera::Converter::stop
+ */
+void V4L2M2MConverter::stop()
 {
 	for (Stream &stream : utils::reverse(streams_))
 		stream.stop();
 }
 
-int SimpleConverter::queueBuffers(FrameBuffer *input,
-				  const std::map<unsigned int, FrameBuffer *> &outputs)
+/**
+ * \copydoc libcamera::Converter::queueBuffers
+ */
+int V4L2M2MConverter::queueBuffers(FrameBuffer *input,
+				   const std::map<unsigned int, FrameBuffer *> &outputs)
 {
 	unsigned int mask = 0;
 	int ret;
@@ -402,4 +443,10 @@  int SimpleConverter::queueBuffers(FrameBuffer *input,
 	return 0;
 }
 
+static std::initializer_list<std::string> compatibles = {
+	"pxp",
+};
+
+REGISTER_CONVERTER("v4l2_m2m", V4L2M2MConverter, compatibles)
+
 } /* namespace libcamera */
diff --git a/src/libcamera/converter/meson.build b/src/libcamera/converter/meson.build
new file mode 100644
index 00000000..2aa72fe4
--- /dev/null
+++ b/src/libcamera/converter/meson.build
@@ -0,0 +1,5 @@ 
+# SPDX-License-Identifier: CC0-1.0
+
+libcamera_sources += files([
+        'converter_v4l2_m2m.cpp'
+])
diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build
index e9d0324e..ffc294f3 100644
--- a/src/libcamera/meson.build
+++ b/src/libcamera/meson.build
@@ -62,6 +62,7 @@  libatomic = cc.find_library('atomic', required : false)
 libthreads = dependency('threads')
 
 subdir('base')
+subdir('converter')
 subdir('ipa')
 subdir('pipeline')
 subdir('proxy')
diff --git a/src/libcamera/pipeline/simple/meson.build b/src/libcamera/pipeline/simple/meson.build
index 9c99b32f..42b0896d 100644
--- a/src/libcamera/pipeline/simple/meson.build
+++ b/src/libcamera/pipeline/simple/meson.build
@@ -1,6 +1,5 @@ 
 # SPDX-License-Identifier: CC0-1.0
 
 libcamera_sources += files([
-    'converter.cpp',
     'simple.cpp',
 ])
diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp
index a32de7f3..24ded4db 100644
--- a/src/libcamera/pipeline/simple/simple.cpp
+++ b/src/libcamera/pipeline/simple/simple.cpp
@@ -30,13 +30,13 @@ 
 
 #include "libcamera/internal/camera.h"
 #include "libcamera/internal/camera_sensor.h"
+#include "libcamera/internal/converter.h"
 #include "libcamera/internal/device_enumerator.h"
 #include "libcamera/internal/media_device.h"
 #include "libcamera/internal/pipeline_handler.h"
 #include "libcamera/internal/v4l2_subdevice.h"
 #include "libcamera/internal/v4l2_videodevice.h"
 
-#include "converter.h"
 
 namespace libcamera {
 
@@ -266,7 +266,7 @@  public:
 	std::vector<Configuration> configs_;
 	std::map<PixelFormat, std::vector<const Configuration *>> formats_;
 
-	std::unique_ptr<SimpleConverter> converter_;
+	std::unique_ptr<Converter> converter_;
 	std::vector<std::unique_ptr<FrameBuffer>> converterBuffers_;
 	bool useConverter_;
 	std::queue<std::map<unsigned int, FrameBuffer *>> converterQueue_;
@@ -492,7 +492,7 @@  int SimpleCameraData::init()
 	/* Open the converter, if any. */
 	MediaDevice *converter = pipe->converter();
 	if (converter) {
-		converter_ = std::make_unique<SimpleConverter>(converter);
+		converter_ = ConverterFactoryBase::create(converter);
 		if (!converter_->isValid()) {
 			LOG(SimplePipeline, Warning)
 				<< "Failed to create converter, disabling format conversion";