Patch Detail
Show a patch.
GET /api/patches/3743/?format=api
{ "id": 3743, "url": "https://patchwork.libcamera.org/api/patches/3743/?format=api", "web_url": "https://patchwork.libcamera.org/patch/3743/", "project": { "id": 1, "url": "https://patchwork.libcamera.org/api/projects/1/?format=api", "name": "libcamera", "link_name": "libcamera", "list_id": "libcamera_core", "list_email": "libcamera-devel@lists.libcamera.org", "web_url": "", "scm_url": "", "webscm_url": "" }, "msgid": "<20200510115810.21938-5-laurent.pinchart@ideasonboard.com>", "date": "2020-05-10T11:58:08", "name": "[libcamera-devel,v5,4/6] libcamera: pipeline: simple: Add simple format converter", "commit_ref": null, "pull_url": null, "state": "accepted", "archived": false, "hash": "4abc83df2121f9a925c49d20f31cab7d40e54bdf", "submitter": { "id": 2, "url": "https://patchwork.libcamera.org/api/people/2/?format=api", "name": "Laurent Pinchart", "email": "laurent.pinchart@ideasonboard.com" }, "delegate": null, "mbox": "https://patchwork.libcamera.org/patch/3743/mbox/", "series": [ { "id": 890, "url": "https://patchwork.libcamera.org/api/series/890/?format=api", "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=890", "date": "2020-05-10T11:58:04", "name": "Simple pipeline handler", "version": 5, "mbox": "https://patchwork.libcamera.org/series/890/mbox/" } ], "comments": "https://patchwork.libcamera.org/api/patches/3743/comments/", "check": "pending", "checks": "https://patchwork.libcamera.org/api/patches/3743/checks/", "tags": {}, "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 EF09560BDC\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tSun, 10 May 2020 13:58:21 +0200 (CEST)", "from pendragon.bb.dnainternet.fi (81-175-216-236.bb.dnainternet.fi\n\t[81.175.216.236])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 7715A304;\n\tSun, 10 May 2020 13:58:21 +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=\"veGBnF4c\"; dkim-atps=neutral", "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1589111901;\n\tbh=N7CZkeb1u2lLdgBSpVXcglB+P3bYrGReq8lFxS8NaCY=;\n\th=From:To:Cc:Subject:Date:In-Reply-To:References:From;\n\tb=veGBnF4cIx5v3YooTn2e7MbRGOBf57yh1RH/rWosPMNC/4GCCNHw/1OqZfnqyRSSu\n\tRsbCWGL2NDPVrweDU0/l4H3ehUT8WyyOJXuElwbGUfARgh8W4pa/YKw1WkCZKmk887\n\tU5MJkwuMG9HehiSaOzWsl/v5MGRLR8Un5ZAoAbQ4=", "From": "Laurent Pinchart <laurent.pinchart@ideasonboard.com>", "To": "libcamera-devel@lists.libcamera.org", "Cc": "Martijn Braam <martijn@brixit.nl>", "Date": "Sun, 10 May 2020 14:58:08 +0300", "Message-Id": "<20200510115810.21938-5-laurent.pinchart@ideasonboard.com>", "X-Mailer": "git-send-email 2.26.2", "In-Reply-To": "<20200510115810.21938-1-laurent.pinchart@ideasonboard.com>", "References": "<20200510115810.21938-1-laurent.pinchart@ideasonboard.com>", "MIME-Version": "1.0", "Content-Type": "text/plain; charset=UTF-8", "Content-Transfer-Encoding": "8bit", "Subject": "[libcamera-devel] [PATCH v5 4/6] libcamera: pipeline: simple: Add\n\tsimple 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": "Sun, 10 May 2020 11:58:22 -0000" }, "content": "The simple format converter supports V4L2 M2M devices that convert pixel\nformats.\n\nSigned-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\nReviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\nReviewed-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>\n---\nChanges since v4:\n\n- Add comment\n- Rebase on top of V4L2PixelFormat changes\n\nChanges since v3:\n\n- Add a comment to explain format enumeration\n\nChanges since v2:\n\n- Rebase on top of V4L2PixelFormat\n---\n src/libcamera/pipeline/simple/converter.cpp | 217 ++++++++++++++++++++\n src/libcamera/pipeline/simple/converter.h | 60 ++++++\n src/libcamera/pipeline/simple/meson.build | 1 +\n 3 files changed, 278 insertions(+)\n create mode 100644 src/libcamera/pipeline/simple/converter.cpp\n create mode 100644 src/libcamera/pipeline/simple/converter.h", "diff": "diff --git a/src/libcamera/pipeline/simple/converter.cpp b/src/libcamera/pipeline/simple/converter.cpp\nnew file mode 100644\nindex 000000000000..6d88776dc2f0\n--- /dev/null\n+++ b/src/libcamera/pipeline/simple/converter.cpp\n@@ -0,0 +1,217 @@\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 = format.first.toPixelFormat();\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+\t/*\n+\t * Set the pixel format on the output, the size is identical to the\n+\t * input as we don't support scaling.\n+\t */\n+\tvideoFormat = m2m_->capture()->toV4L2PixelFormat(outputFormat);\n+\tformat.fourcc = videoFormat;\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 */\ndiff --git a/src/libcamera/pipeline/simple/converter.h b/src/libcamera/pipeline/simple/converter.h\nnew file mode 100644\nindex 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__ */\ndiff --git a/src/libcamera/pipeline/simple/meson.build b/src/libcamera/pipeline/simple/meson.build\nindex 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", "prefixes": [ "libcamera-devel", "v5", "4/6" ] }