[libcamera-devel] [PATCH v4 10/11] libcamera: pipeline: simple: Add simple format converter
Niklas Söderlund
niklas.soderlund at ragnatech.se
Tue Apr 21 17:57:05 CEST 2020
Hi Laurent,
Thanks for your work.
On 2020-04-04 03:44:37 +0300, Laurent Pinchart wrote:
> The simple format converter supports V4L2 M2M devices that convert pixel
> formats.
>
> Signed-off-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
> Reviewed-by: Kieran Bingham <kieran.bingham at ideasonboard.com>
> ---
> Changes since v3:
>
> - Add a comment to explain format enumeration
>
> Changes since v2:
>
> - Rebase on top of V4L2PixelFormat
> ---
> src/libcamera/pipeline/simple/converter.cpp | 213 ++++++++++++++++++++
> src/libcamera/pipeline/simple/converter.h | 60 ++++++
> src/libcamera/pipeline/simple/meson.build | 1 +
> 3 files changed, 274 insertions(+)
> create mode 100644 src/libcamera/pipeline/simple/converter.cpp
> create mode 100644 src/libcamera/pipeline/simple/converter.h
>
> diff --git a/src/libcamera/pipeline/simple/converter.cpp b/src/libcamera/pipeline/simple/converter.cpp
> new file mode 100644
> index 000000000000..50e554147c5f
> --- /dev/null
> +++ b/src/libcamera/pipeline/simple/converter.cpp
> @@ -0,0 +1,213 @@
> +/* SPDX-License-Identifier: LGPL-2.1-or-later */
> +/*
> + * Copyright (C) 2020, Laurent Pinchart
> + *
> + * converter.cpp - Format converter for simple pipeline handler
> + */
> +
> +#include "converter.h"
> +
> +#include <algorithm>
> +
> +#include <libcamera/buffer.h>
> +#include <libcamera/geometry.h>
> +#include <libcamera/signal.h>
> +
> +#include "log.h"
> +#include "media_device.h"
> +#include "v4l2_videodevice.h"
> +
> +namespace libcamera {
> +
> +LOG_DECLARE_CATEGORY(SimplePipeline);
> +
> +SimpleConverter::SimpleConverter(MediaDevice *media)
> + : m2m_(nullptr)
> +{
> + /*
> + * 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())
> + return;
> +
> + m2m_ = new V4L2M2MDevice((*it)->deviceNode());
> +
> + m2m_->output()->bufferReady.connect(this, &SimpleConverter::outputBufferReady);
> + m2m_->capture()->bufferReady.connect(this, &SimpleConverter::captureBufferReady);
> +}
> +
> +SimpleConverter::~SimpleConverter()
> +{
> + delete m2m_;
> +}
> +
> +int SimpleConverter::open()
> +{
> + if (!m2m_)
> + return -ENODEV;
> +
> + return m2m_->open();
> +}
> +
> +void SimpleConverter::close()
> +{
> + if (m2m_)
> + m2m_->close();
> +}
> +
> +std::vector<PixelFormat> SimpleConverter::formats(PixelFormat input)
> +{
> + if (!m2m_)
> + return {};
> +
> + /*
> + * Set the format on the input side (V4L2 output) of the converter to
> + * enumerate the conversion capabilities on its output (V4L2 capture).
> + */
> + V4L2DeviceFormat format;
> + format.fourcc = m2m_->output()->toV4L2PixelFormat(input);
> + format.size = { 1, 1 };
> +
> + int ret = m2m_->output()->setFormat(&format);
> + if (ret < 0) {
> + LOG(SimplePipeline, Error)
> + << "Failed to set format: " << strerror(-ret);
> + return {};
> + }
> +
> + std::vector<PixelFormat> pixelFormats;
> +
> + for (const auto &format : m2m_->capture()->formats()) {
> + PixelFormat pixelFormat = m2m_->capture()->toPixelFormat(format.first);
> + if (pixelFormat)
> + pixelFormats.push_back(pixelFormat);
> + }
> +
> + return pixelFormats;
> +}
> +
> +int SimpleConverter::configure(PixelFormat inputFormat,
> + PixelFormat outputFormat, const Size &size)
> +{
> + V4L2DeviceFormat format;
> + int ret;
> +
> + V4L2PixelFormat videoFormat = m2m_->output()->toV4L2PixelFormat(inputFormat);
> + format.fourcc = videoFormat;
> + format.size = size;
> +
> + ret = m2m_->output()->setFormat(&format);
> + if (ret < 0) {
> + LOG(SimplePipeline, Error)
> + << "Failed to set input format: " << strerror(-ret);
> + return ret;
> + }
> +
> + if (format.fourcc != videoFormat || format.size != size) {
> + LOG(SimplePipeline, Error)
> + << "Input format not supported";
> + return -EINVAL;
> + }
> +
> + videoFormat = m2m_->capture()->toV4L2PixelFormat(outputFormat);
> + format.fourcc = videoFormat;
I wound set format.size here as well even if it's not strictly needed as
it adds to readability. With or without this fixed tho,
Reviewed-by: Niklas Söderlund <niklas.soderlund at ragnatech.se>
> +
> + ret = m2m_->capture()->setFormat(&format);
> + if (ret < 0) {
> + LOG(SimplePipeline, Error)
> + << "Failed to set output format: " << strerror(-ret);
> + return ret;
> + }
> +
> + if (format.fourcc != videoFormat || format.size != size) {
> + LOG(SimplePipeline, Error)
> + << "Output format not supported";
> + return -EINVAL;
> + }
> +
> + return 0;
> +}
> +
> +int SimpleConverter::exportBuffers(unsigned int count,
> + std::vector<std::unique_ptr<FrameBuffer>> *buffers)
> +{
> + return m2m_->capture()->exportBuffers(count, buffers);
> +}
> +
> +int SimpleConverter::start(unsigned int count)
> +{
> + int ret = m2m_->output()->importBuffers(count);
> + if (ret < 0)
> + return ret;
> +
> + ret = m2m_->capture()->importBuffers(count);
> + if (ret < 0) {
> + stop();
> + return ret;
> + }
> +
> + ret = m2m_->output()->streamOn();
> + if (ret < 0) {
> + stop();
> + return ret;
> + }
> +
> + ret = m2m_->capture()->streamOn();
> + if (ret < 0) {
> + stop();
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +void SimpleConverter::stop()
> +{
> + m2m_->capture()->streamOff();
> + m2m_->output()->streamOff();
> + m2m_->capture()->releaseBuffers();
> + m2m_->output()->releaseBuffers();
> +}
> +
> +int SimpleConverter::queueBuffers(FrameBuffer *input, FrameBuffer *output)
> +{
> + int ret = m2m_->output()->queueBuffer(input);
> + if (ret < 0)
> + return ret;
> +
> + ret = m2m_->capture()->queueBuffer(output);
> + if (ret < 0)
> + return ret;
> +
> + return 0;
> +}
> +
> +void SimpleConverter::captureBufferReady(FrameBuffer *buffer)
> +{
> + if (!outputDoneQueue_.empty()) {
> + FrameBuffer *other = outputDoneQueue_.front();
> + outputDoneQueue_.pop();
> + bufferReady.emit(other, buffer);
> + } else {
> + captureDoneQueue_.push(buffer);
> + }
> +}
> +
> +void SimpleConverter::outputBufferReady(FrameBuffer *buffer)
> +{
> + if (!captureDoneQueue_.empty()) {
> + FrameBuffer *other = captureDoneQueue_.front();
> + captureDoneQueue_.pop();
> + bufferReady.emit(buffer, other);
> + } else {
> + outputDoneQueue_.push(buffer);
> + }
> +}
> +
> +} /* namespace libcamera */
> diff --git a/src/libcamera/pipeline/simple/converter.h b/src/libcamera/pipeline/simple/converter.h
> new file mode 100644
> index 000000000000..a33071fa8578
> --- /dev/null
> +++ b/src/libcamera/pipeline/simple/converter.h
> @@ -0,0 +1,60 @@
> +/* SPDX-License-Identifier: LGPL-2.1-or-later */
> +/*
> + * Copyright (C) 2020, Laurent Pinchart
> + *
> + * converter.h - Format converter for simple pipeline handler
> + */
> +
> +#ifndef __LIBCAMERA_PIPELINE_SIMPLE_CONVERTER_H__
> +#define __LIBCAMERA_PIPELINE_SIMPLE_CONVERTER_H__
> +
> +#include <memory>
> +#include <queue>
> +#include <vector>
> +
> +#include <libcamera/pixelformats.h>
> +#include <libcamera/signal.h>
> +
> +namespace libcamera {
> +
> +class FrameBuffer;
> +class MediaDevice;
> +struct Size;
> +class V4L2M2MDevice;
> +
> +class SimpleConverter
> +{
> +public:
> + SimpleConverter(MediaDevice *media);
> + ~SimpleConverter();
> +
> + int open();
> + void close();
> +
> + std::vector<PixelFormat> formats(PixelFormat input);
> +
> + int configure(PixelFormat inputFormat, PixelFormat outputFormat,
> + const Size &size);
> + int exportBuffers(unsigned int count,
> + std::vector<std::unique_ptr<FrameBuffer>> *buffers);
> +
> + int start(unsigned int count);
> + void stop();
> +
> + int queueBuffers(FrameBuffer *input, FrameBuffer *output);
> +
> + Signal<FrameBuffer *, FrameBuffer *> bufferReady;
> +
> +private:
> + void captureBufferReady(FrameBuffer *buffer);
> + void outputBufferReady(FrameBuffer *buffer);
> +
> + V4L2M2MDevice *m2m_;
> +
> + std::queue<FrameBuffer *> captureDoneQueue_;
> + std::queue<FrameBuffer *> outputDoneQueue_;
> +};
> +
> +} /* namespace libcamera */
> +
> +#endif /* __LIBCAMERA_PIPELINE_SIMPLE_CONVERTER_H__ */
> diff --git a/src/libcamera/pipeline/simple/meson.build b/src/libcamera/pipeline/simple/meson.build
> index 4945a3e173cf..8372f24e3788 100644
> --- a/src/libcamera/pipeline/simple/meson.build
> +++ b/src/libcamera/pipeline/simple/meson.build
> @@ -1,3 +1,4 @@
> libcamera_sources += files([
> + 'converter.cpp',
> 'simple.cpp',
> ])
> --
> Regards,
>
> Laurent Pinchart
>
> _______________________________________________
> libcamera-devel mailing list
> libcamera-devel at lists.libcamera.org
> https://lists.libcamera.org/listinfo/libcamera-devel
--
Regards,
Niklas Söderlund
More information about the libcamera-devel
mailing list