Patch Detail
Show a patch.
GET /api/1.1/patches/1765/?format=api
{ "id": 1765, "url": "https://patchwork.libcamera.org/api/1.1/patches/1765/?format=api", "web_url": "https://patchwork.libcamera.org/patch/1765/", "project": { "id": 1, "url": "https://patchwork.libcamera.org/api/1.1/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": "<20190809150459.14421-4-kieran.bingham@ideasonboard.com>", "date": "2019-08-09T15:04:56", "name": "[libcamera-devel,v2,3/6] libcamera: v4l2_videodevice: Support M2M devices", "commit_ref": null, "pull_url": null, "state": "superseded", "archived": false, "hash": "9df0366b817cd5b883216989752d9ff3704c8bd1", "submitter": { "id": 4, "url": "https://patchwork.libcamera.org/api/1.1/people/4/?format=api", "name": "Kieran Bingham", "email": "kieran.bingham@ideasonboard.com" }, "delegate": null, "mbox": "https://patchwork.libcamera.org/patch/1765/mbox/", "series": [ { "id": 451, "url": "https://patchwork.libcamera.org/api/1.1/series/451/?format=api", "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=451", "date": "2019-08-09T15:04:53", "name": "V4L2 M2M Support (+RPi PoC)", "version": 2, "mbox": "https://patchwork.libcamera.org/series/451/mbox/" } ], "comments": "https://patchwork.libcamera.org/api/patches/1765/comments/", "check": "pending", "checks": "https://patchwork.libcamera.org/api/patches/1765/checks/", "tags": {}, "headers": { "Return-Path": "<kieran.bingham@ideasonboard.com>", "Received": [ "from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 133F36162B\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 9 Aug 2019 17:05:05 +0200 (CEST)", "from localhost.localdomain\n\t(cpc89242-aztw30-2-0-cust488.18-1.cable.virginm.net [86.31.129.233])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id A89739EA;\n\tFri, 9 Aug 2019 17:05:04 +0200 (CEST)" ], "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1565363104;\n\tbh=2tgVJJhFc22yT/5yO48NjZg10KfUjZ+pPaRbEKkHips=;\n\th=From:To:Cc:Subject:Date:In-Reply-To:References:From;\n\tb=bAogxhYVoeeTHsGdEDOZ6kDaL77SRN6+IEEjia8V9mLgCxjwTgkITfEUGLue3IDD3\n\tO5+lrY3ylbV5kPyaYtEZn5J7GkGiRh5o5nrl8S1b1G7ouj+KdX++mRTphKILEIr1xN\n\tnq8o1q5qaAuO3OmboLZ6AqRxYw00gw/3/x6ciZZU=", "From": "Kieran Bingham <kieran.bingham@ideasonboard.com>", "To": "LibCamera Devel <libcamera-devel@lists.libcamera.org>", "Date": "Fri, 9 Aug 2019 16:04:56 +0100", "Message-Id": "<20190809150459.14421-4-kieran.bingham@ideasonboard.com>", "X-Mailer": "git-send-email 2.20.1", "In-Reply-To": "<20190809150459.14421-1-kieran.bingham@ideasonboard.com>", "References": "<20190809150459.14421-1-kieran.bingham@ideasonboard.com>", "MIME-Version": "1.0", "Content-Transfer-Encoding": "8bit", "Subject": "[libcamera-devel] [PATCH v2 3/6] libcamera: v4l2_videodevice:\n\tSupport M2M devices", "X-BeenThere": "libcamera-devel@lists.libcamera.org", "X-Mailman-Version": "2.1.23", "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": "Fri, 09 Aug 2019 15:05:06 -0000" }, "content": "V4L2 M2M devices represent a V4L2Device with two queues: One output, and\none capture on a single device node.\n\nRepresent this by instantiating a V4L2VideoDevice for each queue type,\nand preparing each device for its queue.\n\nSigned-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n---\n src/libcamera/include/v4l2_videodevice.h | 28 ++++\n src/libcamera/v4l2_videodevice.cpp | 186 +++++++++++++++++++++++\n 2 files changed, 214 insertions(+)", "diff": "diff --git a/src/libcamera/include/v4l2_videodevice.h b/src/libcamera/include/v4l2_videodevice.h\nindex f5c8da93fcb5..72dc8c63e4bb 100644\n--- a/src/libcamera/include/v4l2_videodevice.h\n+++ b/src/libcamera/include/v4l2_videodevice.h\n@@ -71,6 +71,11 @@ struct V4L2Capability final : v4l2_capability {\n \t\t\t\t\tV4L2_CAP_VIDEO_OUTPUT |\n \t\t\t\t\tV4L2_CAP_VIDEO_OUTPUT_MPLANE);\n \t}\n+\tbool isM2M() const\n+\t{\n+\t\treturn device_caps() & (V4L2_CAP_VIDEO_M2M |\n+\t\t\t\t\tV4L2_CAP_VIDEO_M2M_MPLANE);\n+\t}\n \tbool isMeta() const\n \t{\n \t\treturn device_caps() & (V4L2_CAP_META_CAPTURE |\n@@ -124,6 +129,7 @@ public:\n \tV4L2VideoDevice &operator=(const V4L2VideoDevice &) = delete;\n \n \tint open();\n+\tint open(int handle, enum v4l2_buf_type type);\n \tvoid close();\n \n \tconst char *driverName() const { return caps_.driver(); }\n@@ -152,6 +158,9 @@ protected:\n \tstd::string logPrefix() const;\n \n private:\n+\tint queryBufferType();\n+\tint queryBufferType(enum v4l2_buf_type type);\n+\n \tint getFormatMeta(V4L2DeviceFormat *format);\n \tint setFormatMeta(V4L2DeviceFormat *format);\n \n@@ -182,6 +191,25 @@ private:\n \tEventNotifier *fdEvent_;\n };\n \n+class V4L2M2MDevice\n+{\n+public:\n+\tV4L2M2MDevice(const std::string &deviceNode);\n+\t~V4L2M2MDevice();\n+\n+\tint open();\n+\tvoid close();\n+\n+\tV4L2VideoDevice *output() { return output_; }\n+\tV4L2VideoDevice *capture() { return capture_; }\n+\n+private:\n+\tstd::string deviceNode_;\n+\n+\tV4L2VideoDevice *output_;\n+\tV4L2VideoDevice *capture_;\n+};\n+\n } /* namespace libcamera */\n \n #endif /* __LIBCAMERA_V4L2_VIDEODEVICE_H__ */\ndiff --git a/src/libcamera/v4l2_videodevice.cpp b/src/libcamera/v4l2_videodevice.cpp\nindex 81098dd70190..9c5638995577 100644\n--- a/src/libcamera/v4l2_videodevice.cpp\n+++ b/src/libcamera/v4l2_videodevice.cpp\n@@ -89,6 +89,12 @@ LOG_DECLARE_CATEGORY(V4L2)\n * \\return True if the video device can capture or output images\n */\n \n+/**\n+ * \\fn V4L2Capability::isM2M()\n+ * \\brief Identify if the device is an M2M device\n+ * \\return True if the device can capture and output images using the M2M API\n+ */\n+\n /**\n * \\fn V4L2Capability::isMeta()\n * \\brief Identify if the video device captures or outputs image meta-data\n@@ -296,6 +302,10 @@ V4L2VideoDevice::~V4L2VideoDevice()\n \n /**\n * \\brief Open a V4L2 video device and query its capabilities\n+ *\n+ * Opens a video device, then queries the capabilities of the device and\n+ * establishes the buffer types and device events accordingly.\n+ *\n * \\return 0 on success or a negative error code otherwise\n */\n int V4L2VideoDevice::open()\n@@ -355,6 +365,83 @@ int V4L2VideoDevice::open()\n \treturn 0;\n }\n \n+/**\n+ * \\brief Open a V4L2 video device and query its capabilities\n+ *\n+ * \\param[in] handle The file descriptor to set\n+ * \\param[in] type The device type to operate on\n+ *\n+ * Sets the file descriptor for the device and then queries the capabilities of\n+ * the device and establishes the buffer types and device events accordingly.\n+ *\n+ * \\return 0 on success or a negative error code otherwise\n+ */\n+int V4L2VideoDevice::open(int handle, enum v4l2_buf_type type)\n+{\n+\tint ret;\n+\tint newFd;\n+\n+\tnewFd = dup(handle);\n+\tif (newFd < 0) {\n+\t\tret = -errno;\n+\t\tLOG(V4L2, Error) << \"Failed to duplicate file handle: \"\n+\t\t\t\t << strerror(-ret);\n+\t\treturn ret;\n+\t}\n+\n+\tret = V4L2Device::setFd(newFd);\n+\tif (ret < 0) {\n+\t\tLOG(V4L2, Error) << \"Failed to set file handle: \"\n+\t\t\t\t << strerror(-ret);\n+\t\treturn ret;\n+\t}\n+\n+\tret = ioctl(VIDIOC_QUERYCAP, &caps_);\n+\tif (ret < 0) {\n+\t\tLOG(V4L2, Error)\n+\t\t\t<< \"Failed to query device capabilities: \"\n+\t\t\t<< strerror(-ret);\n+\t\treturn ret;\n+\t}\n+\n+\tif (!caps_.hasStreaming()) {\n+\t\tLOG(V4L2, Error) << \"Device does not support streaming I/O\";\n+\t\treturn -EINVAL;\n+\t}\n+\n+\t/*\n+\t * Set buffer type and wait for read notifications on CAPTURE video\n+\t * devices (POLLIN), and write notifications for OUTPUT video devices\n+\t * (POLLOUT).\n+\t */\n+\tswitch (type) {\n+\tcase V4L2_BUF_TYPE_VIDEO_OUTPUT:\n+\t\tfdEvent_ = new EventNotifier(fd(), EventNotifier::Write);\n+\t\tbufferType_ = caps_.isMultiplanar()\n+\t\t\t ? V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE\n+\t\t\t : V4L2_BUF_TYPE_VIDEO_OUTPUT;\n+\t\tbreak;\n+\tcase V4L2_BUF_TYPE_VIDEO_CAPTURE:\n+\t\tfdEvent_ = new EventNotifier(fd(), EventNotifier::Read);\n+\t\tbufferType_ = caps_.isMultiplanar()\n+\t\t\t ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE\n+\t\t\t : V4L2_BUF_TYPE_VIDEO_CAPTURE;\n+\t\tbreak;\n+\tdefault:\n+\t\tLOG(V4L2, Error) << \"Unsupported buffer type\";\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tfdEvent_->activated.connect(this, &V4L2VideoDevice::bufferAvailable);\n+\tfdEvent_->setEnabled(false);\n+\n+\tLOG(V4L2, Debug)\n+\t\t<< \"Opened device \" << caps_.bus_info() << \": \"\n+\t\t<< caps_.driver() << \": \" << caps_.card();\n+\n+\treturn 0;\n+}\n+\n /**\n * \\brief Close the video device, releasing any resources acquired by open()\n */\n@@ -1143,4 +1230,103 @@ V4L2VideoDevice *V4L2VideoDevice::fromEntityName(const MediaDevice *media,\n \treturn new V4L2VideoDevice(mediaEntity);\n }\n \n+/**\n+ * \\class V4L2M2MDevice\n+ * \\brief Memory2Memory video device\n+ *\n+ * The V4L2M2MDevice manages two V4L2VideoDevice instances on the same\n+ * deviceNode which operate together using two queues to implement the V4L2\n+ * Memory to Memory API.\n+ *\n+ * The two devices should be opened by calling open() on the V4L2M2MDevice, and\n+ * can be closed by calling close on the V4L2M2MDevice.\n+ *\n+ * Calling V4L2VideoDevice::open() and V4L2VideoDevice::close() on the capture\n+ * or output V4L2VideoDevice is not permitted.\n+ */\n+\n+/**\n+ * \\fn V4L2M2MDevice::output\n+ * \\brief Provide access to the output V4L2VideoDevice instance\n+ * \\return The output V4L2Device instance\n+ */\n+\n+/**\n+ * \\fn V4L2M2MDevice::capture\n+ * \\brief Provide access to the capture V4L2VideoDevice instance\n+ * \\return The capture V4L2Device instance\n+ */\n+\n+/**\n+ * \\brief Create a new V4L2M2MDevice from the \\a deviceNode\n+ */\n+V4L2M2MDevice::V4L2M2MDevice(const std::string &deviceNode)\n+\t: deviceNode_(deviceNode)\n+{\n+\toutput_ = new V4L2VideoDevice(deviceNode);\n+\tcapture_ = new V4L2VideoDevice(deviceNode);\n+}\n+\n+V4L2M2MDevice::~V4L2M2MDevice()\n+{\n+\tdelete capture_;\n+\tdelete output_;\n+}\n+\n+/**\n+ * \\brief Open a V4L2 Memory to Memory device\n+ *\n+ * Open the device node and prepare the two V4L2VideoDevice instances to handle\n+ * their respective buffer queues.\n+ *\n+ * \\return 0 on success or a negative error code otherwise\n+ */\n+int V4L2M2MDevice::open()\n+{\n+\tint fd;\n+\tint ret;\n+\n+\t/*\n+\t * The output and capture V4L2VideoDevice instances use the same file\n+\t * handle for the same device node. The local file handle can be closed\n+\t * as the V4L2VideoDevice::open() retains a handle by duplicating the\n+\t * fd passed in.\n+\t */\n+\tfd = ::open(deviceNode_.c_str(), O_RDWR | O_NONBLOCK);\n+\tif (fd < 0) {\n+\t\tret = -errno;\n+\t\tLOG(V4L2, Error)\n+\t\t\t<< \"Failed to open V4L2 M2M device: \" << strerror(-ret);\n+\t\treturn ret;\n+\t}\n+\n+\tret = output_->open(fd, V4L2_BUF_TYPE_VIDEO_OUTPUT);\n+\tif (ret)\n+\t\tgoto err;\n+\n+\tret = capture_->open(fd, V4L2_BUF_TYPE_VIDEO_CAPTURE);\n+\tif (ret)\n+\t\tgoto err;\n+\n+\t::close(fd);\n+\n+\treturn 0;\n+\n+err:\n+\tclose();\n+\t::close(fd);\n+\n+\treturn ret;\n+}\n+\n+/**\n+ * \\brief Close the memory-to-memory device, releasing any resources acquired by\n+ * open()\n+ */\n+void V4L2M2MDevice::close()\n+{\n+\tcapture_->close();\n+\toutput_->close();\n+}\n+\n } /* namespace libcamera */\n", "prefixes": [ "libcamera-devel", "v2", "3/6" ] }