{"id":16932,"url":"https://patchwork.libcamera.org/api/patches/16932/?format=json","web_url":"https://patchwork.libcamera.org/patch/16932/","project":{"id":1,"url":"https://patchwork.libcamera.org/api/projects/1/?format=json","name":"libcamera","link_name":"libcamera","list_id":"libcamera_core","list_email":"libcamera-devel@lists.libcamera.org","web_url":"","scm_url":"","webscm_url":""},"msgid":"<20220803103849.26144-7-jacopo@jmondi.org>","date":"2022-08-03T10:38:48","name":"[libcamera-devel,v5,6/7] libcamera: v4l2_videodevice: Match formats supported by the device","commit_ref":null,"pull_url":null,"state":"accepted","archived":false,"hash":"2566763503d19a07ef798e4500ced8be1145dae6","submitter":{"id":3,"url":"https://patchwork.libcamera.org/api/people/3/?format=json","name":"Jacopo Mondi","email":"jacopo@jmondi.org"},"delegate":null,"mbox":"https://patchwork.libcamera.org/patch/16932/mbox/","series":[{"id":3365,"url":"https://patchwork.libcamera.org/api/series/3365/?format=json","web_url":"https://patchwork.libcamera.org/project/libcamera/list/?series=3365","date":"2022-08-03T10:38:42","name":"libcamera: Map multiple V4L2 formats to a single libcamera::format","version":5,"mbox":"https://patchwork.libcamera.org/series/3365/mbox/"}],"comments":"https://patchwork.libcamera.org/api/patches/16932/comments/","check":"pending","checks":"https://patchwork.libcamera.org/api/patches/16932/checks/","tags":{},"headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 8D7CBBE173\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed,  3 Aug 2022 10:39:08 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 3B1686330F;\n\tWed,  3 Aug 2022 12:39:08 +0200 (CEST)","from relay5-d.mail.gandi.net (relay5-d.mail.gandi.net\n\t[IPv6:2001:4b98:dc4:8::225])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id CF9B1603E6\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed,  3 Aug 2022 12:39:06 +0200 (CEST)","(Authenticated sender: jacopo@jmondi.org)\n\tby mail.gandi.net (Postfix) with ESMTPSA id CEAAD1C0003;\n\tWed,  3 Aug 2022 10:39:05 +0000 (UTC)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1659523148;\n\tbh=D6XKAXnIa/VwBMq1dd04f/WYFrR4x4QDrGG0TNgjoT0=;\n\th=To:Date:In-Reply-To:References:Subject:List-Id:List-Unsubscribe:\n\tList-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:\n\tFrom;\n\tb=znLXdFDx6C7lop4sZLbnwqrKWttoAxK3v+tAi/9SHnJWBGmDYrNNZO4hwWJQJ2jCs\n\tt0Vg6nKZXv1U8QiHhSRsBSBUJa7l5xW2XdlG889y//p1lhzgmWJP1SmM91FRyA9QuR\n\teKozJYyqN2YB/PENDi6qP4n5qDgTs7df6RTW7ae8zhuASbWKgUlYVI/YNHp5IdsOgg\n\tQ8wxEuumGswvwMAOylgpXf8tiou3nEV28zAXw2MBJWmulGJn7bN3uDiCeqPXvkpdga\n\tYo7hst3jY8KXQ/K+cUS9hikceCosUtWRuY4pxb+RHSedtFRHYvIadHeLeKsrZoWCcv\n\tIcCkWw0k8/oZw==","To":"libcamera-devel@lists.libcamera.org","Date":"Wed,  3 Aug 2022 12:38:48 +0200","Message-Id":"<20220803103849.26144-7-jacopo@jmondi.org>","X-Mailer":"git-send-email 2.37.1","In-Reply-To":"<20220803103849.26144-1-jacopo@jmondi.org>","References":"<20220803103849.26144-1-jacopo@jmondi.org>","MIME-Version":"1.0","Content-Transfer-Encoding":"8bit","Subject":"[libcamera-devel] [PATCH v5 6/7] libcamera: v4l2_videodevice: Match\n\tformats supported by the device","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>","From":"Jacopo Mondi via libcamera-devel <libcamera-devel@lists.libcamera.org>","Reply-To":"Jacopo Mondi <jacopo@jmondi.org>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"},"content":"Now that V4L2PixelFormat::fromPixelFormat() returns a list of formats\nto chose from, select the one supported by the video device by matching\nagainst the list of supported pixel formats.\n\nThe first format found to match one of the device supported ones is\nreturned.\n\nAs the list of pixel formats supported by the video device does not\nchange at run-time, cache it at device open() time. To maximize the\nlookup efficiency store the list of supported V4L2PixelFormat in an\nstd::unordered_set<> which requires a specialization of\nstd::hash<V4L2PixelFormat> to be injected in the std namespace.\n\nSigned-off-by: Jacopo Mondi <jacopo@jmondi.org>\nSigned-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\nReviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n---\n include/libcamera/internal/v4l2_pixelformat.h | 13 +++++\n include/libcamera/internal/v4l2_videodevice.h |  4 ++\n src/libcamera/v4l2_videodevice.cpp            | 57 +++++++++++++++----\n 3 files changed, 62 insertions(+), 12 deletions(-)","diff":"diff --git a/include/libcamera/internal/v4l2_pixelformat.h b/include/libcamera/internal/v4l2_pixelformat.h\nindex d5400f90a67e..34d283db44f4 100644\n--- a/include/libcamera/internal/v4l2_pixelformat.h\n+++ b/include/libcamera/internal/v4l2_pixelformat.h\n@@ -8,6 +8,7 @@\n \n #pragma once\n \n+#include <functional>\n #include <ostream>\n #include <stdint.h>\n #include <string>\n@@ -55,3 +56,15 @@ private:\n std::ostream &operator<<(std::ostream &out, const V4L2PixelFormat &f);\n \n } /* namespace libcamera */\n+\n+namespace std {\n+\n+template<>\n+struct hash<libcamera::V4L2PixelFormat> {\n+\tsize_t operator()(libcamera::V4L2PixelFormat const &format) const noexcept\n+\t{\n+\t\treturn format.fourcc();\n+\t}\n+};\n+\n+} /* namespace std */\ndiff --git a/include/libcamera/internal/v4l2_videodevice.h b/include/libcamera/internal/v4l2_videodevice.h\nindex 29fa0bbaf670..ed98a284de16 100644\n--- a/include/libcamera/internal/v4l2_videodevice.h\n+++ b/include/libcamera/internal/v4l2_videodevice.h\n@@ -14,6 +14,7 @@\n #include <ostream>\n #include <stdint.h>\n #include <string>\n+#include <unordered_set>\n #include <vector>\n \n #include <linux/videodev2.h>\n@@ -242,6 +243,8 @@ private:\n \t\tStopped,\n \t};\n \n+\tint initFormats();\n+\n \tint getFormatMeta(V4L2DeviceFormat *format);\n \tint trySetFormatMeta(V4L2DeviceFormat *format, bool set);\n \n@@ -268,6 +271,7 @@ private:\n \tV4L2Capability caps_;\n \tV4L2DeviceFormat format_;\n \tconst PixelFormatInfo *formatInfo_;\n+\tstd::unordered_set<V4L2PixelFormat> pixelFormats_;\n \n \tenum v4l2_buf_type bufferType_;\n \tenum v4l2_memory memoryType_;\ndiff --git a/src/libcamera/v4l2_videodevice.cpp b/src/libcamera/v4l2_videodevice.cpp\nindex 2ca22f485d45..b80ee1cdbcca 100644\n--- a/src/libcamera/v4l2_videodevice.cpp\n+++ b/src/libcamera/v4l2_videodevice.cpp\n@@ -633,13 +633,9 @@ int V4L2VideoDevice::open()\n \t\t<< \"Opened device \" << caps_.bus_info() << \": \"\n \t\t<< caps_.driver() << \": \" << caps_.card();\n \n-\tret = getFormat(&format_);\n-\tif (ret) {\n-\t\tLOG(V4L2, Error) << \"Failed to get format\";\n+\tret = initFormats();\n+\tif (ret)\n \t\treturn ret;\n-\t}\n-\n-\tformatInfo_ = &PixelFormatInfo::info(format_.fourcc);\n \n \treturn 0;\n }\n@@ -726,7 +722,24 @@ int V4L2VideoDevice::open(SharedFD handle, enum v4l2_buf_type type)\n \t\t<< \"Opened device \" << caps_.bus_info() << \": \"\n \t\t<< caps_.driver() << \": \" << caps_.card();\n \n-\tret = getFormat(&format_);\n+\tret = initFormats();\n+\tif (ret)\n+\t\treturn ret;\n+\n+\treturn 0;\n+}\n+\n+int V4L2VideoDevice::initFormats()\n+{\n+\tconst std::vector<V4L2PixelFormat> &deviceFormats = enumPixelformats(0);\n+\tif (deviceFormats.empty()) {\n+\t\tLOG(V4L2, Error) << \"Failed to initialize device formats\";\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tpixelFormats_ = { deviceFormats.begin(), deviceFormats.end() };\n+\n+\tint ret = getFormat(&format_);\n \tif (ret) {\n \t\tLOG(V4L2, Error) << \"Failed to get format\";\n \t\treturn ret;\n@@ -1990,17 +2003,37 @@ V4L2VideoDevice::fromEntityName(const MediaDevice *media,\n }\n \n /**\n- * \\brief Convert \\a PixelFormat to its corresponding V4L2 FourCC\n+ * \\brief Convert \\a PixelFormat to a V4L2PixelFormat supported by the device\n  * \\param[in] pixelFormat The PixelFormat to convert\n  *\n- * The V4L2 format variant the function returns the contiguous version\n- * unconditionally.\n+ * Convert \\a pixelformat to a V4L2 FourCC that is known to be supported by\n+ * the video device.\n  *\n- * \\return The V4L2_PIX_FMT_* pixel format code corresponding to \\a pixelFormat\n+ * A V4L2VideoDevice may support different V4L2 pixel formats that map the same\n+ * PixelFormat. This is the case of the contiguous and non-contiguous variants\n+ * of multiplanar formats, and with the V4L2 MJPEG and JPEG pixel formats.\n+ * Converting a PixelFormat to a V4L2PixelFormat may thus have multiple answers.\n+ *\n+ * This function converts the \\a pixelFormat using the list of V4L2 pixel\n+ * formats that the V4L2VideoDevice supports. This guarantees that the returned\n+ * V4L2PixelFormat will be valid for the device. If multiple matches are still\n+ * possible, contiguous variants are preferred. If the \\a pixelFormat is not\n+ * supported by the device, the function returns an invalid V4L2PixelFormat.\n+ *\n+ * \\return The V4L2PixelFormat corresponding to \\a pixelFormat if supported by\n+ * the device, or an invalid V4L2PixelFormat otherwise\n  */\n V4L2PixelFormat V4L2VideoDevice::toV4L2PixelFormat(const PixelFormat &pixelFormat) const\n {\n-\treturn V4L2PixelFormat::fromPixelFormat(pixelFormat)[0];\n+\tconst std::vector<V4L2PixelFormat> &v4l2PixelFormats =\n+\t\tV4L2PixelFormat::fromPixelFormat(pixelFormat);\n+\n+\tfor (const V4L2PixelFormat &v4l2Format : v4l2PixelFormats) {\n+\t\tif (pixelFormats_.count(v4l2Format))\n+\t\t\treturn v4l2Format;\n+\t}\n+\n+\treturn {};\n }\n \n /**\n","prefixes":["libcamera-devel","v5","6/7"]}