similarity index 83%
rename from src/libcamera/pipeline/simple/converter.h
rename to 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_;
new file mode 100644
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: CC0-1.0
+
+libcamera_internal_headers += files([
+ 'converter_v4l2_m2m.h',
+])
@@ -45,3 +45,5 @@ libcamera_internal_headers = files([
'v4l2_videodevice.h',
'yaml_parser.h',
])
+
+subdir('converter')
similarity index 67%
rename from src/libcamera/pipeline/simple/converter.cpp
rename to 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 */
new file mode 100644
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: CC0-1.0
+
+libcamera_sources += files([
+ 'converter_v4l2_m2m.cpp'
+])
@@ -62,6 +62,7 @@ libatomic = cc.find_library('atomic', required : false)
libthreads = dependency('threads')
subdir('base')
+subdir('converter')
subdir('ipa')
subdir('pipeline')
subdir('proxy')
@@ -1,6 +1,5 @@
# SPDX-License-Identifier: CC0-1.0
libcamera_sources += files([
- 'converter.cpp',
'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";