[{"id":4476,"web_url":"https://patchwork.libcamera.org/comment/4476/","msgid":"<20200421155705.GE2600980@oden.dyn.berto.se>","date":"2020-04-21T15:57:05","subject":"Re: [libcamera-devel] [PATCH v4 10/11] libcamera: pipeline: simple:\n\tAdd simple format converter","submitter":{"id":5,"url":"https://patchwork.libcamera.org/api/people/5/","name":"Niklas Söderlund","email":"niklas.soderlund@ragnatech.se"},"content":"Hi Laurent,\n\nThanks for your work.\n\nOn 2020-04-04 03:44:37 +0300, Laurent Pinchart wrote:\n> The simple format converter supports V4L2 M2M devices that convert pixel\n> formats.\n> \n> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n> ---\n> Changes since v3:\n> \n> - Add a comment to explain format enumeration\n> \n> Changes since v2:\n> \n> - Rebase on top of V4L2PixelFormat\n> ---\n>  src/libcamera/pipeline/simple/converter.cpp | 213 ++++++++++++++++++++\n>  src/libcamera/pipeline/simple/converter.h   |  60 ++++++\n>  src/libcamera/pipeline/simple/meson.build   |   1 +\n>  3 files changed, 274 insertions(+)\n>  create mode 100644 src/libcamera/pipeline/simple/converter.cpp\n>  create mode 100644 src/libcamera/pipeline/simple/converter.h\n> \n> diff --git a/src/libcamera/pipeline/simple/converter.cpp b/src/libcamera/pipeline/simple/converter.cpp\n> new file mode 100644\n> index 000000000000..50e554147c5f\n> --- /dev/null\n> +++ b/src/libcamera/pipeline/simple/converter.cpp\n> @@ -0,0 +1,213 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2020, Laurent Pinchart\n> + *\n> + * converter.cpp - Format converter for simple pipeline handler\n> + */\n> +\n> +#include \"converter.h\"\n> +\n> +#include <algorithm>\n> +\n> +#include <libcamera/buffer.h>\n> +#include <libcamera/geometry.h>\n> +#include <libcamera/signal.h>\n> +\n> +#include \"log.h\"\n> +#include \"media_device.h\"\n> +#include \"v4l2_videodevice.h\"\n> +\n> +namespace libcamera {\n> +\n> +LOG_DECLARE_CATEGORY(SimplePipeline);\n> +\n> +SimpleConverter::SimpleConverter(MediaDevice *media)\n> +\t: m2m_(nullptr)\n> +{\n> +\t/*\n> +\t * Locate the video node. There's no need to validate the pipeline\n> +\t * further, the caller guarantees that this is a V4L2 mem2mem device.\n> +\t */\n> +\tconst std::vector<MediaEntity *> &entities = media->entities();\n> +\tauto it = std::find_if(entities.begin(), entities.end(),\n> +\t\t\t       [](MediaEntity *entity) {\n> +\t\t\t\t       return entity->function() == MEDIA_ENT_F_IO_V4L;\n> +\t\t\t       });\n> +\tif (it == entities.end())\n> +\t\treturn;\n> +\n> +\tm2m_ = new V4L2M2MDevice((*it)->deviceNode());\n> +\n> +\tm2m_->output()->bufferReady.connect(this, &SimpleConverter::outputBufferReady);\n> +\tm2m_->capture()->bufferReady.connect(this, &SimpleConverter::captureBufferReady);\n> +}\n> +\n> +SimpleConverter::~SimpleConverter()\n> +{\n> +\tdelete m2m_;\n> +}\n> +\n> +int SimpleConverter::open()\n> +{\n> +\tif (!m2m_)\n> +\t\treturn -ENODEV;\n> +\n> +\treturn m2m_->open();\n> +}\n> +\n> +void SimpleConverter::close()\n> +{\n> +\tif (m2m_)\n> +\t\tm2m_->close();\n> +}\n> +\n> +std::vector<PixelFormat> SimpleConverter::formats(PixelFormat input)\n> +{\n> +\tif (!m2m_)\n> +\t\treturn {};\n> +\n> +\t/*\n> +\t * Set the format on the input side (V4L2 output) of the converter to\n> +\t * enumerate the conversion capabilities on its output (V4L2 capture).\n> +\t */\n> +\tV4L2DeviceFormat format;\n> +\tformat.fourcc = m2m_->output()->toV4L2PixelFormat(input);\n> +\tformat.size = { 1, 1 };\n> +\n> +\tint ret = m2m_->output()->setFormat(&format);\n> +\tif (ret < 0) {\n> +\t\tLOG(SimplePipeline, Error)\n> +\t\t\t<< \"Failed to set format: \" << strerror(-ret);\n> +\t\treturn {};\n> +\t}\n> +\n> +\tstd::vector<PixelFormat> pixelFormats;\n> +\n> +\tfor (const auto &format : m2m_->capture()->formats()) {\n> +\t\tPixelFormat pixelFormat = m2m_->capture()->toPixelFormat(format.first);\n> +\t\tif (pixelFormat)\n> +\t\t\tpixelFormats.push_back(pixelFormat);\n> +\t}\n> +\n> +\treturn pixelFormats;\n> +}\n> +\n> +int SimpleConverter::configure(PixelFormat inputFormat,\n> +\t\t\t       PixelFormat outputFormat, const Size &size)\n> +{\n> +\tV4L2DeviceFormat format;\n> +\tint ret;\n> +\n> +\tV4L2PixelFormat videoFormat = m2m_->output()->toV4L2PixelFormat(inputFormat);\n> +\tformat.fourcc = videoFormat;\n> +\tformat.size = size;\n> +\n> +\tret = m2m_->output()->setFormat(&format);\n> +\tif (ret < 0) {\n> +\t\tLOG(SimplePipeline, Error)\n> +\t\t\t<< \"Failed to set input format: \" << strerror(-ret);\n> +\t\treturn ret;\n> +\t}\n> +\n> +\tif (format.fourcc != videoFormat || format.size != size) {\n> +\t\tLOG(SimplePipeline, Error)\n> +\t\t\t<< \"Input format not supported\";\n> +\t\treturn -EINVAL;\n> +\t}\n> +\n> +\tvideoFormat = m2m_->capture()->toV4L2PixelFormat(outputFormat);\n> +\tformat.fourcc = videoFormat;\n\nI wound set format.size here as well even if it's not strictly needed as \nit adds to readability. With or without this fixed tho,\n\nReviewed-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>\n\n> +\n> +\tret = m2m_->capture()->setFormat(&format);\n> +\tif (ret < 0) {\n> +\t\tLOG(SimplePipeline, Error)\n> +\t\t\t<< \"Failed to set output format: \" << strerror(-ret);\n> +\t\treturn ret;\n> +\t}\n> +\n> +\tif (format.fourcc != videoFormat || format.size != size) {\n> +\t\tLOG(SimplePipeline, Error)\n> +\t\t\t<< \"Output format not supported\";\n> +\t\treturn -EINVAL;\n> +\t}\n> +\n> +\treturn 0;\n> +}\n> +\n> +int SimpleConverter::exportBuffers(unsigned int count,\n> +\t\t\t\t   std::vector<std::unique_ptr<FrameBuffer>> *buffers)\n> +{\n> +\treturn m2m_->capture()->exportBuffers(count, buffers);\n> +}\n> +\n> +int SimpleConverter::start(unsigned int count)\n> +{\n> +\tint ret = m2m_->output()->importBuffers(count);\n> +\tif (ret < 0)\n> +\t\treturn ret;\n> +\n> +\tret = m2m_->capture()->importBuffers(count);\n> +\tif (ret < 0) {\n> +\t\tstop();\n> +\t\treturn ret;\n> +\t}\n> +\n> +\tret = m2m_->output()->streamOn();\n> +\tif (ret < 0) {\n> +\t\tstop();\n> +\t\treturn ret;\n> +\t}\n> +\n> +\tret = m2m_->capture()->streamOn();\n> +\tif (ret < 0) {\n> +\t\tstop();\n> +\t\treturn ret;\n> +\t}\n> +\n> +\treturn 0;\n> +}\n> +\n> +void SimpleConverter::stop()\n> +{\n> +\tm2m_->capture()->streamOff();\n> +\tm2m_->output()->streamOff();\n> +\tm2m_->capture()->releaseBuffers();\n> +\tm2m_->output()->releaseBuffers();\n> +}\n> +\n> +int SimpleConverter::queueBuffers(FrameBuffer *input, FrameBuffer *output)\n> +{\n> +\tint ret = m2m_->output()->queueBuffer(input);\n> +\tif (ret < 0)\n> +\t\treturn ret;\n> +\n> +\tret = m2m_->capture()->queueBuffer(output);\n> +\tif (ret < 0)\n> +\t\treturn ret;\n> +\n> +\treturn 0;\n> +}\n> +\n> +void SimpleConverter::captureBufferReady(FrameBuffer *buffer)\n> +{\n> +\tif (!outputDoneQueue_.empty()) {\n> +\t\tFrameBuffer *other = outputDoneQueue_.front();\n> +\t\toutputDoneQueue_.pop();\n> +\t\tbufferReady.emit(other, buffer);\n> +\t} else {\n> +\t\tcaptureDoneQueue_.push(buffer);\n> +\t}\n> +}\n> +\n> +void SimpleConverter::outputBufferReady(FrameBuffer *buffer)\n> +{\n> +\tif (!captureDoneQueue_.empty()) {\n> +\t\tFrameBuffer *other = captureDoneQueue_.front();\n> +\t\tcaptureDoneQueue_.pop();\n> +\t\tbufferReady.emit(buffer, other);\n> +\t} else {\n> +\t\toutputDoneQueue_.push(buffer);\n> +\t}\n> +}\n> +\n> +} /* namespace libcamera */\n> diff --git a/src/libcamera/pipeline/simple/converter.h b/src/libcamera/pipeline/simple/converter.h\n> new file mode 100644\n> index 000000000000..a33071fa8578\n> --- /dev/null\n> +++ b/src/libcamera/pipeline/simple/converter.h\n> @@ -0,0 +1,60 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2020, Laurent Pinchart\n> + *\n> + * converter.h - Format converter for simple pipeline handler\n> + */\n> +\n> +#ifndef __LIBCAMERA_PIPELINE_SIMPLE_CONVERTER_H__\n> +#define __LIBCAMERA_PIPELINE_SIMPLE_CONVERTER_H__\n> +\n> +#include <memory>\n> +#include <queue>\n> +#include <vector>\n> +\n> +#include <libcamera/pixelformats.h>\n> +#include <libcamera/signal.h>\n> +\n> +namespace libcamera {\n> +\n> +class FrameBuffer;\n> +class MediaDevice;\n> +struct Size;\n> +class V4L2M2MDevice;\n> +\n> +class SimpleConverter\n> +{\n> +public:\n> +\tSimpleConverter(MediaDevice *media);\n> +\t~SimpleConverter();\n> +\n> +\tint open();\n> +\tvoid close();\n> +\n> +\tstd::vector<PixelFormat> formats(PixelFormat input);\n> +\n> +\tint configure(PixelFormat inputFormat, PixelFormat outputFormat,\n> +\t\t      const Size &size);\n> +\tint exportBuffers(unsigned int count,\n> +\t\t\t  std::vector<std::unique_ptr<FrameBuffer>> *buffers);\n> +\n> +\tint start(unsigned int count);\n> +\tvoid stop();\n> +\n> +\tint queueBuffers(FrameBuffer *input, FrameBuffer *output);\n> +\n> +\tSignal<FrameBuffer *, FrameBuffer *> bufferReady;\n> +\n> +private:\n> +\tvoid captureBufferReady(FrameBuffer *buffer);\n> +\tvoid outputBufferReady(FrameBuffer *buffer);\n> +\n> +\tV4L2M2MDevice *m2m_;\n> +\n> +\tstd::queue<FrameBuffer *> captureDoneQueue_;\n> +\tstd::queue<FrameBuffer *> outputDoneQueue_;\n> +};\n> +\n> +} /* namespace libcamera */\n> +\n> +#endif /* __LIBCAMERA_PIPELINE_SIMPLE_CONVERTER_H__ */\n> diff --git a/src/libcamera/pipeline/simple/meson.build b/src/libcamera/pipeline/simple/meson.build\n> index 4945a3e173cf..8372f24e3788 100644\n> --- a/src/libcamera/pipeline/simple/meson.build\n> +++ b/src/libcamera/pipeline/simple/meson.build\n> @@ -1,3 +1,4 @@\n>  libcamera_sources += files([\n> +    'converter.cpp',\n>      'simple.cpp',\n>  ])\n> -- \n> Regards,\n> \n> Laurent Pinchart\n> \n> _______________________________________________\n> libcamera-devel mailing list\n> libcamera-devel@lists.libcamera.org\n> https://lists.libcamera.org/listinfo/libcamera-devel","headers":{"Return-Path":"<niklas.soderlund@ragnatech.se>","Received":["from mail-lf1-x12a.google.com (mail-lf1-x12a.google.com\n\t[IPv6:2a00:1450:4864:20::12a])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 216C960406\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 21 Apr 2020 17:57:08 +0200 (CEST)","by mail-lf1-x12a.google.com with SMTP id u10so11510151lfo.8\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 21 Apr 2020 08:57:08 -0700 (PDT)","from localhost (h-209-203.A463.priv.bahnhof.se. [155.4.209.203])\n\tby smtp.gmail.com with ESMTPSA id\n\tr20sm2190366ljj.44.2020.04.21.08.57.06\n\t(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n\tTue, 21 Apr 2020 08:57:06 -0700 (PDT)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (2048-bit key; \n\tunprotected)\n\theader.d=ragnatech-se.20150623.gappssmtp.com\n\theader.i=@ragnatech-se.20150623.gappssmtp.com header.b=\"j9EQnUz1\"; \n\tdkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=ragnatech-se.20150623.gappssmtp.com; s=20150623;\n\th=date:from:to:cc:subject:message-id:references:mime-version\n\t:content-disposition:content-transfer-encoding:in-reply-to;\n\tbh=t8ZftcTO0ywC8FFLKZmL/l2Kcsc5IpX8zBFmuuvGBNY=;\n\tb=j9EQnUz1AUZVNHdu8pgKj8M8NpwraurPOsbLk5c3VarL61TuWz6QjPJ7QjfaMoBYYr\n\tBV/ssvO/nX4aWnfgqe7mhCgxPrhQP0aox2euErGuqLV9SC7EPy5ElYy1FiTSvQopDTpO\n\tk5AcWKDQrf4MkjgA+PJs4lDjDpgbWtvLwsZlf5G7XV6K4rfBi17Rwci9yQo1ze3alXJZ\n\tkl3aXV7CsbKEsAlQfmkkJYHD39L0mihF5FvTQBOcCO96ToWt6+LCCQPeBMy35W366LF9\n\tuCwK03GRe2by/qFD3oP1IzPK+OQKVDZlofNaROqPdNz/jlBapWwVeK/usPhxnqWliJKT\n\tBzYg==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20161025;\n\th=x-gm-message-state:date:from:to:cc:subject:message-id:references\n\t:mime-version:content-disposition:content-transfer-encoding\n\t:in-reply-to;\n\tbh=t8ZftcTO0ywC8FFLKZmL/l2Kcsc5IpX8zBFmuuvGBNY=;\n\tb=X8jb/+zbH6dzdi2WJ4Y+UTy4Pkmk5EQz+7No0tErGbYuzennC317HHUm+RVDYZ+XcZ\n\tlmp14VIGmQM8E9wFhMT/TnnqbemwkLmLD0MQ8J5Ff6Bi4yPavhIAuQfJgwy7ElMLu38q\n\tXBZTbNs9K8pO52g+i6Eac69U7OL+nLwAvLULLm4Z+Bph6JjGAy4/aQJtpTgsM/r+58Mo\n\t8HnulR35n6sCJzmksM06o2Wt9mqNtSsPfkGQ/L24KpLWmoMK0XV4TZo5j8BbWlLfFT0j\n\tjxsQ0+5VskH96thfauFv7p5c6Gwc6VgnTNOLgYMzGONs/WXeGgiYf+UEAepg7UE4odzo\n\tE9NQ==","X-Gm-Message-State":"AGi0PuZBn1ds26tStmrZg2Fmg9Zs6ebWjqdETDiR6Oj+CqlUyjQ2cAuZ\n\tWw8xJNJBSHyU7Qeba+uG9/Qxog==","X-Google-Smtp-Source":"APiQypLgK0V9mFClmGOr+n0n/dUxGpN4WnCUugPko9nDM1xb4wq/Csap9T2UBQApst9qj7omuXTCyw==","X-Received":"by 2002:a19:40d0:: with SMTP id\n\tn199mr14233493lfa.161.1587484627209; \n\tTue, 21 Apr 2020 08:57:07 -0700 (PDT)","Date":"Tue, 21 Apr 2020 17:57:05 +0200","From":"Niklas =?iso-8859-1?q?S=F6derlund?= <niklas.soderlund@ragnatech.se>","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org, Martijn Braam <martijn@brixit.nl>, \n\tBenjamin GAIGNARD <benjamin.gaignard@st.com>","Message-ID":"<20200421155705.GE2600980@oden.dyn.berto.se>","References":"<20200404004438.17992-1-laurent.pinchart@ideasonboard.com>\n\t<20200404004438.17992-11-laurent.pinchart@ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=iso-8859-1","Content-Disposition":"inline","Content-Transfer-Encoding":"8bit","In-Reply-To":"<20200404004438.17992-11-laurent.pinchart@ideasonboard.com>","Subject":"Re: [libcamera-devel] [PATCH v4 10/11] libcamera: pipeline: simple:\n\tAdd simple format converter","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","X-List-Received-Date":"Tue, 21 Apr 2020 15:57:08 -0000"}},{"id":4479,"web_url":"https://patchwork.libcamera.org/comment/4479/","msgid":"<20200421192749.GF5983@pendragon.ideasonboard.com>","date":"2020-04-21T19:27:49","subject":"Re: [libcamera-devel] [PATCH v4 10/11] libcamera: pipeline: simple:\n\tAdd simple format converter","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi Niklas,\n\nOn Tue, Apr 21, 2020 at 05:57:05PM +0200, Niklas Söderlund wrote:\n> On 2020-04-04 03:44:37 +0300, Laurent Pinchart wrote:\n> > The simple format converter supports V4L2 M2M devices that convert pixel\n> > formats.\n> > \n> > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> > Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n> > ---\n> > Changes since v3:\n> > \n> > - Add a comment to explain format enumeration\n> > \n> > Changes since v2:\n> > \n> > - Rebase on top of V4L2PixelFormat\n> > ---\n> >  src/libcamera/pipeline/simple/converter.cpp | 213 ++++++++++++++++++++\n> >  src/libcamera/pipeline/simple/converter.h   |  60 ++++++\n> >  src/libcamera/pipeline/simple/meson.build   |   1 +\n> >  3 files changed, 274 insertions(+)\n> >  create mode 100644 src/libcamera/pipeline/simple/converter.cpp\n> >  create mode 100644 src/libcamera/pipeline/simple/converter.h\n> > \n> > diff --git a/src/libcamera/pipeline/simple/converter.cpp b/src/libcamera/pipeline/simple/converter.cpp\n> > new file mode 100644\n> > index 000000000000..50e554147c5f\n> > --- /dev/null\n> > +++ b/src/libcamera/pipeline/simple/converter.cpp\n> > @@ -0,0 +1,213 @@\n> > +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> > +/*\n> > + * Copyright (C) 2020, Laurent Pinchart\n> > + *\n> > + * converter.cpp - Format converter for simple pipeline handler\n> > + */\n> > +\n> > +#include \"converter.h\"\n> > +\n> > +#include <algorithm>\n> > +\n> > +#include <libcamera/buffer.h>\n> > +#include <libcamera/geometry.h>\n> > +#include <libcamera/signal.h>\n> > +\n> > +#include \"log.h\"\n> > +#include \"media_device.h\"\n> > +#include \"v4l2_videodevice.h\"\n> > +\n> > +namespace libcamera {\n> > +\n> > +LOG_DECLARE_CATEGORY(SimplePipeline);\n> > +\n> > +SimpleConverter::SimpleConverter(MediaDevice *media)\n> > +\t: m2m_(nullptr)\n> > +{\n> > +\t/*\n> > +\t * Locate the video node. There's no need to validate the pipeline\n> > +\t * further, the caller guarantees that this is a V4L2 mem2mem device.\n> > +\t */\n> > +\tconst std::vector<MediaEntity *> &entities = media->entities();\n> > +\tauto it = std::find_if(entities.begin(), entities.end(),\n> > +\t\t\t       [](MediaEntity *entity) {\n> > +\t\t\t\t       return entity->function() == MEDIA_ENT_F_IO_V4L;\n> > +\t\t\t       });\n> > +\tif (it == entities.end())\n> > +\t\treturn;\n> > +\n> > +\tm2m_ = new V4L2M2MDevice((*it)->deviceNode());\n> > +\n> > +\tm2m_->output()->bufferReady.connect(this, &SimpleConverter::outputBufferReady);\n> > +\tm2m_->capture()->bufferReady.connect(this, &SimpleConverter::captureBufferReady);\n> > +}\n> > +\n> > +SimpleConverter::~SimpleConverter()\n> > +{\n> > +\tdelete m2m_;\n> > +}\n> > +\n> > +int SimpleConverter::open()\n> > +{\n> > +\tif (!m2m_)\n> > +\t\treturn -ENODEV;\n> > +\n> > +\treturn m2m_->open();\n> > +}\n> > +\n> > +void SimpleConverter::close()\n> > +{\n> > +\tif (m2m_)\n> > +\t\tm2m_->close();\n> > +}\n> > +\n> > +std::vector<PixelFormat> SimpleConverter::formats(PixelFormat input)\n> > +{\n> > +\tif (!m2m_)\n> > +\t\treturn {};\n> > +\n> > +\t/*\n> > +\t * Set the format on the input side (V4L2 output) of the converter to\n> > +\t * enumerate the conversion capabilities on its output (V4L2 capture).\n> > +\t */\n> > +\tV4L2DeviceFormat format;\n> > +\tformat.fourcc = m2m_->output()->toV4L2PixelFormat(input);\n> > +\tformat.size = { 1, 1 };\n> > +\n> > +\tint ret = m2m_->output()->setFormat(&format);\n> > +\tif (ret < 0) {\n> > +\t\tLOG(SimplePipeline, Error)\n> > +\t\t\t<< \"Failed to set format: \" << strerror(-ret);\n> > +\t\treturn {};\n> > +\t}\n> > +\n> > +\tstd::vector<PixelFormat> pixelFormats;\n> > +\n> > +\tfor (const auto &format : m2m_->capture()->formats()) {\n> > +\t\tPixelFormat pixelFormat = m2m_->capture()->toPixelFormat(format.first);\n> > +\t\tif (pixelFormat)\n> > +\t\t\tpixelFormats.push_back(pixelFormat);\n> > +\t}\n> > +\n> > +\treturn pixelFormats;\n> > +}\n> > +\n> > +int SimpleConverter::configure(PixelFormat inputFormat,\n> > +\t\t\t       PixelFormat outputFormat, const Size &size)\n> > +{\n> > +\tV4L2DeviceFormat format;\n> > +\tint ret;\n> > +\n> > +\tV4L2PixelFormat videoFormat = m2m_->output()->toV4L2PixelFormat(inputFormat);\n> > +\tformat.fourcc = videoFormat;\n> > +\tformat.size = size;\n> > +\n> > +\tret = m2m_->output()->setFormat(&format);\n> > +\tif (ret < 0) {\n> > +\t\tLOG(SimplePipeline, Error)\n> > +\t\t\t<< \"Failed to set input format: \" << strerror(-ret);\n> > +\t\treturn ret;\n> > +\t}\n> > +\n> > +\tif (format.fourcc != videoFormat || format.size != size) {\n> > +\t\tLOG(SimplePipeline, Error)\n> > +\t\t\t<< \"Input format not supported\";\n> > +\t\treturn -EINVAL;\n> > +\t}\n> > +\n> > +\tvideoFormat = m2m_->capture()->toV4L2PixelFormat(outputFormat);\n> > +\tformat.fourcc = videoFormat;\n> \n> I wound set format.size here as well even if it's not strictly needed as \n> it adds to readability. With or without this fixed tho,\n\nBoth gcc 9 and clang 10 fail to optimize that away though :-S It's not\nbig deal in this specific case, but do we generally want to do so ?\nMaybe a comment would be better ?\n\n> Reviewed-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>\n> \n> > +\n> > +\tret = m2m_->capture()->setFormat(&format);\n> > +\tif (ret < 0) {\n> > +\t\tLOG(SimplePipeline, Error)\n> > +\t\t\t<< \"Failed to set output format: \" << strerror(-ret);\n> > +\t\treturn ret;\n> > +\t}\n> > +\n> > +\tif (format.fourcc != videoFormat || format.size != size) {\n> > +\t\tLOG(SimplePipeline, Error)\n> > +\t\t\t<< \"Output format not supported\";\n> > +\t\treturn -EINVAL;\n> > +\t}\n> > +\n> > +\treturn 0;\n> > +}\n> > +\n> > +int SimpleConverter::exportBuffers(unsigned int count,\n> > +\t\t\t\t   std::vector<std::unique_ptr<FrameBuffer>> *buffers)\n> > +{\n> > +\treturn m2m_->capture()->exportBuffers(count, buffers);\n> > +}\n> > +\n> > +int SimpleConverter::start(unsigned int count)\n> > +{\n> > +\tint ret = m2m_->output()->importBuffers(count);\n> > +\tif (ret < 0)\n> > +\t\treturn ret;\n> > +\n> > +\tret = m2m_->capture()->importBuffers(count);\n> > +\tif (ret < 0) {\n> > +\t\tstop();\n> > +\t\treturn ret;\n> > +\t}\n> > +\n> > +\tret = m2m_->output()->streamOn();\n> > +\tif (ret < 0) {\n> > +\t\tstop();\n> > +\t\treturn ret;\n> > +\t}\n> > +\n> > +\tret = m2m_->capture()->streamOn();\n> > +\tif (ret < 0) {\n> > +\t\tstop();\n> > +\t\treturn ret;\n> > +\t}\n> > +\n> > +\treturn 0;\n> > +}\n> > +\n> > +void SimpleConverter::stop()\n> > +{\n> > +\tm2m_->capture()->streamOff();\n> > +\tm2m_->output()->streamOff();\n> > +\tm2m_->capture()->releaseBuffers();\n> > +\tm2m_->output()->releaseBuffers();\n> > +}\n> > +\n> > +int SimpleConverter::queueBuffers(FrameBuffer *input, FrameBuffer *output)\n> > +{\n> > +\tint ret = m2m_->output()->queueBuffer(input);\n> > +\tif (ret < 0)\n> > +\t\treturn ret;\n> > +\n> > +\tret = m2m_->capture()->queueBuffer(output);\n> > +\tif (ret < 0)\n> > +\t\treturn ret;\n> > +\n> > +\treturn 0;\n> > +}\n> > +\n> > +void SimpleConverter::captureBufferReady(FrameBuffer *buffer)\n> > +{\n> > +\tif (!outputDoneQueue_.empty()) {\n> > +\t\tFrameBuffer *other = outputDoneQueue_.front();\n> > +\t\toutputDoneQueue_.pop();\n> > +\t\tbufferReady.emit(other, buffer);\n> > +\t} else {\n> > +\t\tcaptureDoneQueue_.push(buffer);\n> > +\t}\n> > +}\n> > +\n> > +void SimpleConverter::outputBufferReady(FrameBuffer *buffer)\n> > +{\n> > +\tif (!captureDoneQueue_.empty()) {\n> > +\t\tFrameBuffer *other = captureDoneQueue_.front();\n> > +\t\tcaptureDoneQueue_.pop();\n> > +\t\tbufferReady.emit(buffer, other);\n> > +\t} else {\n> > +\t\toutputDoneQueue_.push(buffer);\n> > +\t}\n> > +}\n> > +\n> > +} /* namespace libcamera */\n> > diff --git a/src/libcamera/pipeline/simple/converter.h b/src/libcamera/pipeline/simple/converter.h\n> > new file mode 100644\n> > index 000000000000..a33071fa8578\n> > --- /dev/null\n> > +++ b/src/libcamera/pipeline/simple/converter.h\n> > @@ -0,0 +1,60 @@\n> > +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> > +/*\n> > + * Copyright (C) 2020, Laurent Pinchart\n> > + *\n> > + * converter.h - Format converter for simple pipeline handler\n> > + */\n> > +\n> > +#ifndef __LIBCAMERA_PIPELINE_SIMPLE_CONVERTER_H__\n> > +#define __LIBCAMERA_PIPELINE_SIMPLE_CONVERTER_H__\n> > +\n> > +#include <memory>\n> > +#include <queue>\n> > +#include <vector>\n> > +\n> > +#include <libcamera/pixelformats.h>\n> > +#include <libcamera/signal.h>\n> > +\n> > +namespace libcamera {\n> > +\n> > +class FrameBuffer;\n> > +class MediaDevice;\n> > +struct Size;\n> > +class V4L2M2MDevice;\n> > +\n> > +class SimpleConverter\n> > +{\n> > +public:\n> > +\tSimpleConverter(MediaDevice *media);\n> > +\t~SimpleConverter();\n> > +\n> > +\tint open();\n> > +\tvoid close();\n> > +\n> > +\tstd::vector<PixelFormat> formats(PixelFormat input);\n> > +\n> > +\tint configure(PixelFormat inputFormat, PixelFormat outputFormat,\n> > +\t\t      const Size &size);\n> > +\tint exportBuffers(unsigned int count,\n> > +\t\t\t  std::vector<std::unique_ptr<FrameBuffer>> *buffers);\n> > +\n> > +\tint start(unsigned int count);\n> > +\tvoid stop();\n> > +\n> > +\tint queueBuffers(FrameBuffer *input, FrameBuffer *output);\n> > +\n> > +\tSignal<FrameBuffer *, FrameBuffer *> bufferReady;\n> > +\n> > +private:\n> > +\tvoid captureBufferReady(FrameBuffer *buffer);\n> > +\tvoid outputBufferReady(FrameBuffer *buffer);\n> > +\n> > +\tV4L2M2MDevice *m2m_;\n> > +\n> > +\tstd::queue<FrameBuffer *> captureDoneQueue_;\n> > +\tstd::queue<FrameBuffer *> outputDoneQueue_;\n> > +};\n> > +\n> > +} /* namespace libcamera */\n> > +\n> > +#endif /* __LIBCAMERA_PIPELINE_SIMPLE_CONVERTER_H__ */\n> > diff --git a/src/libcamera/pipeline/simple/meson.build b/src/libcamera/pipeline/simple/meson.build\n> > index 4945a3e173cf..8372f24e3788 100644\n> > --- a/src/libcamera/pipeline/simple/meson.build\n> > +++ b/src/libcamera/pipeline/simple/meson.build\n> > @@ -1,3 +1,4 @@\n> >  libcamera_sources += files([\n> > +    'converter.cpp',\n> >      'simple.cpp',\n> >  ])","headers":{"Return-Path":"<laurent.pinchart@ideasonboard.com>","Received":["from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id DA38A60406\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 21 Apr 2020 21:28:03 +0200 (CEST)","from pendragon.ideasonboard.com (81-175-216-236.bb.dnainternet.fi\n\t[81.175.216.236])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 39A7A528;\n\tTue, 21 Apr 2020 21:28:03 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key; \n\tunprotected) header.d=ideasonboard.com\n\theader.i=@ideasonboard.com\n\theader.b=\"UMJ8tFKw\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1587497283;\n\tbh=zDioBj0b+wISMwl5gRNAu+Q+XJ9KDnlNYFRqDI1GqTQ=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=UMJ8tFKwtCA607gwzJYrT+qWFMK4lznAAXyWLgUcu0ZTUbXNyfbt8Jwr0Cs2D4u0p\n\t/+aBX281ft4wTiNTil6k9mqfHjssi4POzaklp6jh+6+yKfiHYvOb+PSg0AJXPx0km8\n\tZnKqbpLZYMZJ27yiERDPOxpAK/psGXzGps//SVCQ=","Date":"Tue, 21 Apr 2020 22:27:49 +0300","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Niklas =?utf-8?q?S=C3=B6derlund?= <niklas.soderlund@ragnatech.se>","Cc":"libcamera-devel@lists.libcamera.org, Martijn Braam <martijn@brixit.nl>, \n\tBenjamin GAIGNARD <benjamin.gaignard@st.com>","Message-ID":"<20200421192749.GF5983@pendragon.ideasonboard.com>","References":"<20200404004438.17992-1-laurent.pinchart@ideasonboard.com>\n\t<20200404004438.17992-11-laurent.pinchart@ideasonboard.com>\n\t<20200421155705.GE2600980@oden.dyn.berto.se>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","Content-Transfer-Encoding":"8bit","In-Reply-To":"<20200421155705.GE2600980@oden.dyn.berto.se>","Subject":"Re: [libcamera-devel] [PATCH v4 10/11] libcamera: pipeline: simple:\n\tAdd simple format converter","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","X-List-Received-Date":"Tue, 21 Apr 2020 19:28:04 -0000"}},{"id":4480,"web_url":"https://patchwork.libcamera.org/comment/4480/","msgid":"<20200421201745.GA3027532@oden.dyn.berto.se>","date":"2020-04-21T20:17:45","subject":"Re: [libcamera-devel] [PATCH v4 10/11] libcamera: pipeline: simple:\n\tAdd simple format converter","submitter":{"id":5,"url":"https://patchwork.libcamera.org/api/people/5/","name":"Niklas Söderlund","email":"niklas.soderlund@ragnatech.se"},"content":"Hi Laurent,\n\nOn 2020-04-21 22:27:49 +0300, Laurent Pinchart wrote:\n> Hi Niklas,\n> \n> On Tue, Apr 21, 2020 at 05:57:05PM +0200, Niklas Söderlund wrote:\n> > On 2020-04-04 03:44:37 +0300, Laurent Pinchart wrote:\n> > > The simple format converter supports V4L2 M2M devices that convert pixel\n> > > formats.\n> > > \n> > > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> > > Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n> > > ---\n> > > Changes since v3:\n> > > \n> > > - Add a comment to explain format enumeration\n> > > \n> > > Changes since v2:\n> > > \n> > > - Rebase on top of V4L2PixelFormat\n> > > ---\n> > >  src/libcamera/pipeline/simple/converter.cpp | 213 ++++++++++++++++++++\n> > >  src/libcamera/pipeline/simple/converter.h   |  60 ++++++\n> > >  src/libcamera/pipeline/simple/meson.build   |   1 +\n> > >  3 files changed, 274 insertions(+)\n> > >  create mode 100644 src/libcamera/pipeline/simple/converter.cpp\n> > >  create mode 100644 src/libcamera/pipeline/simple/converter.h\n> > > \n> > > diff --git a/src/libcamera/pipeline/simple/converter.cpp b/src/libcamera/pipeline/simple/converter.cpp\n> > > new file mode 100644\n> > > index 000000000000..50e554147c5f\n> > > --- /dev/null\n> > > +++ b/src/libcamera/pipeline/simple/converter.cpp\n> > > @@ -0,0 +1,213 @@\n> > > +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> > > +/*\n> > > + * Copyright (C) 2020, Laurent Pinchart\n> > > + *\n> > > + * converter.cpp - Format converter for simple pipeline handler\n> > > + */\n> > > +\n> > > +#include \"converter.h\"\n> > > +\n> > > +#include <algorithm>\n> > > +\n> > > +#include <libcamera/buffer.h>\n> > > +#include <libcamera/geometry.h>\n> > > +#include <libcamera/signal.h>\n> > > +\n> > > +#include \"log.h\"\n> > > +#include \"media_device.h\"\n> > > +#include \"v4l2_videodevice.h\"\n> > > +\n> > > +namespace libcamera {\n> > > +\n> > > +LOG_DECLARE_CATEGORY(SimplePipeline);\n> > > +\n> > > +SimpleConverter::SimpleConverter(MediaDevice *media)\n> > > +\t: m2m_(nullptr)\n> > > +{\n> > > +\t/*\n> > > +\t * Locate the video node. There's no need to validate the pipeline\n> > > +\t * further, the caller guarantees that this is a V4L2 mem2mem device.\n> > > +\t */\n> > > +\tconst std::vector<MediaEntity *> &entities = media->entities();\n> > > +\tauto it = std::find_if(entities.begin(), entities.end(),\n> > > +\t\t\t       [](MediaEntity *entity) {\n> > > +\t\t\t\t       return entity->function() == MEDIA_ENT_F_IO_V4L;\n> > > +\t\t\t       });\n> > > +\tif (it == entities.end())\n> > > +\t\treturn;\n> > > +\n> > > +\tm2m_ = new V4L2M2MDevice((*it)->deviceNode());\n> > > +\n> > > +\tm2m_->output()->bufferReady.connect(this, &SimpleConverter::outputBufferReady);\n> > > +\tm2m_->capture()->bufferReady.connect(this, &SimpleConverter::captureBufferReady);\n> > > +}\n> > > +\n> > > +SimpleConverter::~SimpleConverter()\n> > > +{\n> > > +\tdelete m2m_;\n> > > +}\n> > > +\n> > > +int SimpleConverter::open()\n> > > +{\n> > > +\tif (!m2m_)\n> > > +\t\treturn -ENODEV;\n> > > +\n> > > +\treturn m2m_->open();\n> > > +}\n> > > +\n> > > +void SimpleConverter::close()\n> > > +{\n> > > +\tif (m2m_)\n> > > +\t\tm2m_->close();\n> > > +}\n> > > +\n> > > +std::vector<PixelFormat> SimpleConverter::formats(PixelFormat input)\n> > > +{\n> > > +\tif (!m2m_)\n> > > +\t\treturn {};\n> > > +\n> > > +\t/*\n> > > +\t * Set the format on the input side (V4L2 output) of the converter to\n> > > +\t * enumerate the conversion capabilities on its output (V4L2 capture).\n> > > +\t */\n> > > +\tV4L2DeviceFormat format;\n> > > +\tformat.fourcc = m2m_->output()->toV4L2PixelFormat(input);\n> > > +\tformat.size = { 1, 1 };\n> > > +\n> > > +\tint ret = m2m_->output()->setFormat(&format);\n> > > +\tif (ret < 0) {\n> > > +\t\tLOG(SimplePipeline, Error)\n> > > +\t\t\t<< \"Failed to set format: \" << strerror(-ret);\n> > > +\t\treturn {};\n> > > +\t}\n> > > +\n> > > +\tstd::vector<PixelFormat> pixelFormats;\n> > > +\n> > > +\tfor (const auto &format : m2m_->capture()->formats()) {\n> > > +\t\tPixelFormat pixelFormat = m2m_->capture()->toPixelFormat(format.first);\n> > > +\t\tif (pixelFormat)\n> > > +\t\t\tpixelFormats.push_back(pixelFormat);\n> > > +\t}\n> > > +\n> > > +\treturn pixelFormats;\n> > > +}\n> > > +\n> > > +int SimpleConverter::configure(PixelFormat inputFormat,\n> > > +\t\t\t       PixelFormat outputFormat, const Size &size)\n> > > +{\n> > > +\tV4L2DeviceFormat format;\n> > > +\tint ret;\n> > > +\n> > > +\tV4L2PixelFormat videoFormat = m2m_->output()->toV4L2PixelFormat(inputFormat);\n> > > +\tformat.fourcc = videoFormat;\n> > > +\tformat.size = size;\n> > > +\n> > > +\tret = m2m_->output()->setFormat(&format);\n> > > +\tif (ret < 0) {\n> > > +\t\tLOG(SimplePipeline, Error)\n> > > +\t\t\t<< \"Failed to set input format: \" << strerror(-ret);\n> > > +\t\treturn ret;\n> > > +\t}\n> > > +\n> > > +\tif (format.fourcc != videoFormat || format.size != size) {\n> > > +\t\tLOG(SimplePipeline, Error)\n> > > +\t\t\t<< \"Input format not supported\";\n> > > +\t\treturn -EINVAL;\n> > > +\t}\n> > > +\n> > > +\tvideoFormat = m2m_->capture()->toV4L2PixelFormat(outputFormat);\n> > > +\tformat.fourcc = videoFormat;\n> > \n> > I wound set format.size here as well even if it's not strictly needed as \n> > it adds to readability. With or without this fixed tho,\n> \n> Both gcc 9 and clang 10 fail to optimize that away though :-S It's not\n> big deal in this specific case, but do we generally want to do so ?\n> Maybe a comment would be better ?\n\nI can live with a comment.\n\n> \n> > Reviewed-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>\n> > \n> > > +\n> > > +\tret = m2m_->capture()->setFormat(&format);\n> > > +\tif (ret < 0) {\n> > > +\t\tLOG(SimplePipeline, Error)\n> > > +\t\t\t<< \"Failed to set output format: \" << strerror(-ret);\n> > > +\t\treturn ret;\n> > > +\t}\n> > > +\n> > > +\tif (format.fourcc != videoFormat || format.size != size) {\n> > > +\t\tLOG(SimplePipeline, Error)\n> > > +\t\t\t<< \"Output format not supported\";\n> > > +\t\treturn -EINVAL;\n> > > +\t}\n> > > +\n> > > +\treturn 0;\n> > > +}\n> > > +\n> > > +int SimpleConverter::exportBuffers(unsigned int count,\n> > > +\t\t\t\t   std::vector<std::unique_ptr<FrameBuffer>> *buffers)\n> > > +{\n> > > +\treturn m2m_->capture()->exportBuffers(count, buffers);\n> > > +}\n> > > +\n> > > +int SimpleConverter::start(unsigned int count)\n> > > +{\n> > > +\tint ret = m2m_->output()->importBuffers(count);\n> > > +\tif (ret < 0)\n> > > +\t\treturn ret;\n> > > +\n> > > +\tret = m2m_->capture()->importBuffers(count);\n> > > +\tif (ret < 0) {\n> > > +\t\tstop();\n> > > +\t\treturn ret;\n> > > +\t}\n> > > +\n> > > +\tret = m2m_->output()->streamOn();\n> > > +\tif (ret < 0) {\n> > > +\t\tstop();\n> > > +\t\treturn ret;\n> > > +\t}\n> > > +\n> > > +\tret = m2m_->capture()->streamOn();\n> > > +\tif (ret < 0) {\n> > > +\t\tstop();\n> > > +\t\treturn ret;\n> > > +\t}\n> > > +\n> > > +\treturn 0;\n> > > +}\n> > > +\n> > > +void SimpleConverter::stop()\n> > > +{\n> > > +\tm2m_->capture()->streamOff();\n> > > +\tm2m_->output()->streamOff();\n> > > +\tm2m_->capture()->releaseBuffers();\n> > > +\tm2m_->output()->releaseBuffers();\n> > > +}\n> > > +\n> > > +int SimpleConverter::queueBuffers(FrameBuffer *input, FrameBuffer *output)\n> > > +{\n> > > +\tint ret = m2m_->output()->queueBuffer(input);\n> > > +\tif (ret < 0)\n> > > +\t\treturn ret;\n> > > +\n> > > +\tret = m2m_->capture()->queueBuffer(output);\n> > > +\tif (ret < 0)\n> > > +\t\treturn ret;\n> > > +\n> > > +\treturn 0;\n> > > +}\n> > > +\n> > > +void SimpleConverter::captureBufferReady(FrameBuffer *buffer)\n> > > +{\n> > > +\tif (!outputDoneQueue_.empty()) {\n> > > +\t\tFrameBuffer *other = outputDoneQueue_.front();\n> > > +\t\toutputDoneQueue_.pop();\n> > > +\t\tbufferReady.emit(other, buffer);\n> > > +\t} else {\n> > > +\t\tcaptureDoneQueue_.push(buffer);\n> > > +\t}\n> > > +}\n> > > +\n> > > +void SimpleConverter::outputBufferReady(FrameBuffer *buffer)\n> > > +{\n> > > +\tif (!captureDoneQueue_.empty()) {\n> > > +\t\tFrameBuffer *other = captureDoneQueue_.front();\n> > > +\t\tcaptureDoneQueue_.pop();\n> > > +\t\tbufferReady.emit(buffer, other);\n> > > +\t} else {\n> > > +\t\toutputDoneQueue_.push(buffer);\n> > > +\t}\n> > > +}\n> > > +\n> > > +} /* namespace libcamera */\n> > > diff --git a/src/libcamera/pipeline/simple/converter.h b/src/libcamera/pipeline/simple/converter.h\n> > > new file mode 100644\n> > > index 000000000000..a33071fa8578\n> > > --- /dev/null\n> > > +++ b/src/libcamera/pipeline/simple/converter.h\n> > > @@ -0,0 +1,60 @@\n> > > +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> > > +/*\n> > > + * Copyright (C) 2020, Laurent Pinchart\n> > > + *\n> > > + * converter.h - Format converter for simple pipeline handler\n> > > + */\n> > > +\n> > > +#ifndef __LIBCAMERA_PIPELINE_SIMPLE_CONVERTER_H__\n> > > +#define __LIBCAMERA_PIPELINE_SIMPLE_CONVERTER_H__\n> > > +\n> > > +#include <memory>\n> > > +#include <queue>\n> > > +#include <vector>\n> > > +\n> > > +#include <libcamera/pixelformats.h>\n> > > +#include <libcamera/signal.h>\n> > > +\n> > > +namespace libcamera {\n> > > +\n> > > +class FrameBuffer;\n> > > +class MediaDevice;\n> > > +struct Size;\n> > > +class V4L2M2MDevice;\n> > > +\n> > > +class SimpleConverter\n> > > +{\n> > > +public:\n> > > +\tSimpleConverter(MediaDevice *media);\n> > > +\t~SimpleConverter();\n> > > +\n> > > +\tint open();\n> > > +\tvoid close();\n> > > +\n> > > +\tstd::vector<PixelFormat> formats(PixelFormat input);\n> > > +\n> > > +\tint configure(PixelFormat inputFormat, PixelFormat outputFormat,\n> > > +\t\t      const Size &size);\n> > > +\tint exportBuffers(unsigned int count,\n> > > +\t\t\t  std::vector<std::unique_ptr<FrameBuffer>> *buffers);\n> > > +\n> > > +\tint start(unsigned int count);\n> > > +\tvoid stop();\n> > > +\n> > > +\tint queueBuffers(FrameBuffer *input, FrameBuffer *output);\n> > > +\n> > > +\tSignal<FrameBuffer *, FrameBuffer *> bufferReady;\n> > > +\n> > > +private:\n> > > +\tvoid captureBufferReady(FrameBuffer *buffer);\n> > > +\tvoid outputBufferReady(FrameBuffer *buffer);\n> > > +\n> > > +\tV4L2M2MDevice *m2m_;\n> > > +\n> > > +\tstd::queue<FrameBuffer *> captureDoneQueue_;\n> > > +\tstd::queue<FrameBuffer *> outputDoneQueue_;\n> > > +};\n> > > +\n> > > +} /* namespace libcamera */\n> > > +\n> > > +#endif /* __LIBCAMERA_PIPELINE_SIMPLE_CONVERTER_H__ */\n> > > diff --git a/src/libcamera/pipeline/simple/meson.build b/src/libcamera/pipeline/simple/meson.build\n> > > index 4945a3e173cf..8372f24e3788 100644\n> > > --- a/src/libcamera/pipeline/simple/meson.build\n> > > +++ b/src/libcamera/pipeline/simple/meson.build\n> > > @@ -1,3 +1,4 @@\n> > >  libcamera_sources += files([\n> > > +    'converter.cpp',\n> > >      'simple.cpp',\n> > >  ])\n> \n> -- \n> Regards,\n> \n> Laurent Pinchart","headers":{"Return-Path":"<niklas.soderlund@ragnatech.se>","Received":["from mail-lf1-x144.google.com (mail-lf1-x144.google.com\n\t[IPv6:2a00:1450:4864:20::144])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 0841E60406\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 21 Apr 2020 22:17:48 +0200 (CEST)","by mail-lf1-x144.google.com with SMTP id j14so12169276lfg.9\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 21 Apr 2020 13:17:47 -0700 (PDT)","from localhost (h-209-203.A463.priv.bahnhof.se. [155.4.209.203])\n\tby smtp.gmail.com with ESMTPSA id\n\tv12sm2584658ljh.6.2020.04.21.13.17.46\n\t(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n\tTue, 21 Apr 2020 13:17:46 -0700 (PDT)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (2048-bit key; \n\tunprotected)\n\theader.d=ragnatech-se.20150623.gappssmtp.com\n\theader.i=@ragnatech-se.20150623.gappssmtp.com header.b=\"UuekngFn\"; \n\tdkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=ragnatech-se.20150623.gappssmtp.com; s=20150623;\n\th=date:from:to:cc:subject:message-id:references:mime-version\n\t:content-disposition:content-transfer-encoding:in-reply-to;\n\tbh=D6jckPIFuj0Yt38qdT5J2Nqi3EDJcs5JUGL2jy1FUQ8=;\n\tb=UuekngFn9zQ9UTgN9uGfK1NmwaCpOM8Yp8iunKCe7s0tMbpG9j4x0jSAN7uAD/xX6t\n\tbwtHwau6m5t0/hiKTv0Bh9XtTQJTv1IgM8sGMP9usaeEE2iK6ZlkluVsGAadMWptFFrN\n\tBUd7kO8BQujdX8UqGLDT3RIV6MuPAFB0QutPql9OAC4Unaxf/lca7zWvjeWw3+pdBwR5\n\t9KK2QrfW15XBN5iDiS2zgwMcnQ2b3gq5SVz7cnDG1bm1re3fuzSTZmulbGDGdk1BaO5A\n\ttqlYHRoyw+6bY84Id278UnV42sc9sIEBe0W3Z8uF8gugaNPh4b79PbsJgpaWylRYrqSB\n\t61gQ==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20161025;\n\th=x-gm-message-state:date:from:to:cc:subject:message-id:references\n\t:mime-version:content-disposition:content-transfer-encoding\n\t:in-reply-to;\n\tbh=D6jckPIFuj0Yt38qdT5J2Nqi3EDJcs5JUGL2jy1FUQ8=;\n\tb=VC6V/bsCZIl1Z0cyAhp8CN517sbe35Ca0S5DDb4166m3kCqyNDCdd3Ao0Ek3Zdj34x\n\t2V8T7v+OKkYtojRTZvoJUIoLZJZ94S+7/th6Ef2uFlT0W5qgr7b11DwuGKrmHvzGMWjC\n\tcmloFW8UQO3d4cO6haC5i7APquuEf5qr9C6xnLnQ5/MJhbK7xAYErsAhuYH6f2KnUEt3\n\ti6NQvoOybg2My0eZ3MyJl+8v20StNsCQ+xKwWCWmGEdc5TUNTc4TkNnili/oLYfcfYD2\n\tdLXl5n1olu1kGrwpnqMBLRaHXBLlF+leWJtObMWA7yl585ldxBL5vrDyIHTzc/5Jv+Sl\n\twi5Q==","X-Gm-Message-State":"AGi0PuaeDpwJPOKUlfDZwWMiVx6OhJXZZbEEuNr27y8/eVibObuuUcHS\n\tBpugaAcYQ1MkWmuiAf9Fh4QoBw==","X-Google-Smtp-Source":"APiQypLHvGQuAd/CEQIrqJMuDUJQuH8WamjOBV8p+ldwutt1zAjg0HbOMkN0r47XARK+PYzM2dEHVA==","X-Received":"by 2002:ac2:4832:: with SMTP id\n\t18mr15212439lft.162.1587500267148; \n\tTue, 21 Apr 2020 13:17:47 -0700 (PDT)","Date":"Tue, 21 Apr 2020 22:17:45 +0200","From":"Niklas =?iso-8859-1?q?S=F6derlund?= <niklas.soderlund@ragnatech.se>","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org, Martijn Braam <martijn@brixit.nl>, \n\tBenjamin GAIGNARD <benjamin.gaignard@st.com>","Message-ID":"<20200421201745.GA3027532@oden.dyn.berto.se>","References":"<20200404004438.17992-1-laurent.pinchart@ideasonboard.com>\n\t<20200404004438.17992-11-laurent.pinchart@ideasonboard.com>\n\t<20200421155705.GE2600980@oden.dyn.berto.se>\n\t<20200421192749.GF5983@pendragon.ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=iso-8859-1","Content-Disposition":"inline","Content-Transfer-Encoding":"8bit","In-Reply-To":"<20200421192749.GF5983@pendragon.ideasonboard.com>","Subject":"Re: [libcamera-devel] [PATCH v4 10/11] libcamera: pipeline: simple:\n\tAdd simple format converter","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","X-List-Received-Date":"Tue, 21 Apr 2020 20:17:48 -0000"}}]