{"id":1305,"url":"https://patchwork.libcamera.org/api/1.1/patches/1305/?format=json","web_url":"https://patchwork.libcamera.org/patch/1305/","project":{"id":1,"url":"https://patchwork.libcamera.org/api/1.1/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":"<20190527001543.13593-12-niklas.soderlund@ragnatech.se>","date":"2019-05-27T00:15:37","name":"[libcamera-devel,11/17] libcamera: stream: Add StreamFormats","commit_ref":null,"pull_url":null,"state":"superseded","archived":false,"hash":"d9adec30205d16d2b672bedeac0c63293b3ca4e0","submitter":{"id":5,"url":"https://patchwork.libcamera.org/api/1.1/people/5/?format=json","name":"Niklas Söderlund","email":"niklas.soderlund@ragnatech.se"},"delegate":null,"mbox":"https://patchwork.libcamera.org/patch/1305/mbox/","series":[{"id":328,"url":"https://patchwork.libcamera.org/api/1.1/series/328/?format=json","web_url":"https://patchwork.libcamera.org/project/libcamera/list/?series=328","date":"2019-05-27T00:15:28","name":"libcamera: Add support for format information and validation","version":1,"mbox":"https://patchwork.libcamera.org/series/328/mbox/"}],"comments":"https://patchwork.libcamera.org/api/patches/1305/comments/","check":"pending","checks":"https://patchwork.libcamera.org/api/patches/1305/checks/","tags":{},"headers":{"Return-Path":"<niklas.soderlund@ragnatech.se>","Received":["from vsp-unauthed02.binero.net (vsp-unauthed02.binero.net\n\t[195.74.38.227])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 28FFA618F9\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 27 May 2019 02:16:12 +0200 (CEST)","from bismarck.berto.se (unknown [89.233.230.99])\n\tby bin-vsp-out-01.atm.binero.net (Halon) with ESMTPA\n\tid 9f6e729b-8014-11e9-8ab4-005056917a89;\n\tMon, 27 May 2019 02:16:07 +0200 (CEST)"],"X-Halon-ID":"9f6e729b-8014-11e9-8ab4-005056917a89","Authorized-sender":"niklas@soderlund.pp.se","From":"=?utf-8?q?Niklas_S=C3=B6derlund?= <niklas.soderlund@ragnatech.se>","To":"libcamera-devel@lists.libcamera.org","Date":"Mon, 27 May 2019 02:15:37 +0200","Message-Id":"<20190527001543.13593-12-niklas.soderlund@ragnatech.se>","X-Mailer":"git-send-email 2.21.0","In-Reply-To":"<20190527001543.13593-1-niklas.soderlund@ragnatech.se>","References":"<20190527001543.13593-1-niklas.soderlund@ragnatech.se>","MIME-Version":"1.0","Content-Type":"text/plain; charset=UTF-8","Content-Transfer-Encoding":"8bit","Subject":"[libcamera-devel] [PATCH 11/17] libcamera: stream: Add StreamFormats","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":"Mon, 27 May 2019 00:16:14 -0000"},"content":"Add a StreamFormats which describes all the formats a stream can\nsupport. The object does not collect any formation itself but can\nsimplify users interaction with formats as it's able to translate a\nstream format range into discrete list and a discrete list to a range.\n\nSigned-off-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>\n---\n include/libcamera/stream.h |  16 +++\n src/libcamera/stream.cpp   | 216 +++++++++++++++++++++++++++++++++++++\n 2 files changed, 232 insertions(+)","diff":"diff --git a/include/libcamera/stream.h b/include/libcamera/stream.h\nindex e38c0e7e827d5888..48daf5ac23f55d85 100644\n--- a/include/libcamera/stream.h\n+++ b/include/libcamera/stream.h\n@@ -7,6 +7,7 @@\n #ifndef __LIBCAMERA_STREAM_H__\n #define __LIBCAMERA_STREAM_H__\n \n+#include <map>\n #include <string>\n #include <vector>\n \n@@ -18,6 +19,21 @@ namespace libcamera {\n class Camera;\n class Stream;\n \n+class StreamFormats\n+{\n+public:\n+\tStreamFormats();\n+\tStreamFormats(const std::map<unsigned int, std::vector<SizeRange>> &formats);\n+\n+\tstd::vector<unsigned int> pixelformats() const;\n+\tstd::vector<Size> sizes(unsigned int pixelformat) const;\n+\n+\tSizeRange range(unsigned int pixelformat) const;\n+\n+private:\n+\tstd::map<unsigned int, std::vector<SizeRange>> formats_;\n+};\n+\n struct StreamConfiguration {\n \tStreamConfiguration()\n \t\t: stream_(nullptr)\ndiff --git a/src/libcamera/stream.cpp b/src/libcamera/stream.cpp\nindex eecd37160150d55c..a2931902fda2baa5 100644\n--- a/src/libcamera/stream.cpp\n+++ b/src/libcamera/stream.cpp\n@@ -7,6 +7,7 @@\n \n #include <libcamera/stream.h>\n \n+#include <algorithm>\n #include <iomanip>\n #include <sstream>\n \n@@ -36,6 +37,221 @@ namespace libcamera {\n \n LOG_DEFINE_CATEGORY(Stream)\n \n+/**\n+ * \\class StreamFormats\n+ * \\brief Hold information about supported stream formats\n+ *\n+ * The StreamFormats class holds information about pixel formats and frame\n+ * sizes a stream supports. The class groups size information by the pixel\n+ * format which can produce it. There are two ways to examine the size\n+ * information, as a range or as a list of discrete sizes.\n+ *\n+ * When sizes are viewed as a range it describes the minimum and maximum width\n+ * and height values. There is a possibility to supplement the range description\n+ * with a horizontal och vertical stepping size. The stepping size describes the\n+ * step size in pixel from the minimum with/height.\n+ *\n+ * When sizes is viewed as a list of discrete sizes it describes exact dimensions\n+ * which can be selected and used.\n+ *\n+ * Pipeline handlers can create StreamFormats describing each pixel format using\n+ * either a range or a list of  discrete sizes. The StreamFormats class attempts\n+ * to translates between the two different ways to view them. The translations\n+ * are performed as:\n+ *\n+ *  - If a pixel format is described as a list of discrete sizes a range is\n+ *    created by taking the minim and maximum width/height in the list.\n+ *    The stepping information is not recreated and set to 1.\n+ *\n+ *  - If a pixel format is described as a range a list of discrete sizes which\n+ *    fits inside that range are selected from a list of common sizes. The\n+ *    stepping information is taken into consideration when generating the\n+ *    sizes.\n+ *\n+ * Applications examining sizes as a range with stepping values of 1 should be\n+ * aware that the range could be generated form a list of discrete sizes and\n+ * there could be big gaps in the range to what the stream can support.\n+ *\n+ * All sizes retrieved from StreamFormats should be treated as advisory and no\n+ * size should be considered to be supported until its been verified using\n+ * CameraConfiguration::validate().\n+ */\n+\n+/**\n+ * \\brief Construct a empty StreamFormats object\n+ */\n+StreamFormats::StreamFormats()\n+{\n+}\n+\n+/**\n+ * \\brief Construct a StreamFormats object\n+ * \\param[in] formats A map of pixel formats to a sizes description\n+ */\n+StreamFormats::StreamFormats(const std::map<unsigned int, std::vector<SizeRange>> &formats)\n+\t: formats_(formats)\n+{\n+}\n+\n+/**\n+ * \\brief Retrieve the list of pixel formats supported\n+ * \\returns List of pixel formats\n+ */\n+std::vector<unsigned int> StreamFormats::pixelformats() const\n+{\n+\tstd::vector<unsigned int> formats;\n+\n+\tfor (auto const &it : formats_)\n+\t\tformats.push_back(it.first);\n+\n+\treturn formats;\n+}\n+\n+/**\n+ * \\brief Retrieve the list of frame sizes\n+ * \\param[in] pixelformat Pixel format to retrieve sizes for\n+ * \\returns List description of frame sizes\n+ */\n+std::vector<Size> StreamFormats::sizes(unsigned int pixelformat) const\n+{\n+\t/*\n+\t * Sizes to try and extract from ranges.\n+\t * \\todo Verify list of resolutions are good, current list compiled\n+\t * from v4l2 documentation and source code as well as lists of\n+\t * common frame sizes.\n+\t */\n+\tstatic const std::vector<Size> rangeDiscreteSizes = {\n+\t\tSize(160, 120),\n+\t\tSize(240, 160),\n+\t\tSize(320, 240),\n+\t\tSize(400, 240),\n+\t\tSize(480, 320),\n+\t\tSize(640, 360),\n+\t\tSize(640, 480),\n+\t\tSize(720, 480),\n+\t\tSize(720, 576),\n+\t\tSize(768, 480),\n+\t\tSize(800, 600),\n+\t\tSize(854, 480),\n+\t\tSize(960, 540),\n+\t\tSize(960, 640),\n+\t\tSize(1024, 576),\n+\t\tSize(1024, 600),\n+\t\tSize(1024, 768),\n+\t\tSize(1152, 864),\n+\t\tSize(1280, 1024),\n+\t\tSize(1280, 1080),\n+\t\tSize(1280, 720),\n+\t\tSize(1280, 800),\n+\t\tSize(1360, 768),\n+\t\tSize(1366, 768),\n+\t\tSize(1400, 1050),\n+\t\tSize(1440, 900),\n+\t\tSize(1536, 864),\n+\t\tSize(1600, 1200),\n+\t\tSize(1600, 900),\n+\t\tSize(1680, 1050),\n+\t\tSize(1920, 1080),\n+\t\tSize(1920, 1200),\n+\t\tSize(2048, 1080),\n+\t\tSize(2048, 1152),\n+\t\tSize(2048, 1536),\n+\t\tSize(2160, 1080),\n+\t\tSize(2560, 1080),\n+\t\tSize(2560, 1440),\n+\t\tSize(2560, 1600),\n+\t\tSize(2560, 2048),\n+\t\tSize(2960, 1440),\n+\t\tSize(3200, 1800),\n+\t\tSize(3200, 2048),\n+\t\tSize(3200, 2400),\n+\t\tSize(3440, 1440),\n+\t\tSize(3840, 1080),\n+\t\tSize(3840, 1600),\n+\t\tSize(3840, 2160),\n+\t\tSize(3840, 2400),\n+\t\tSize(4096, 2160),\n+\t\tSize(5120, 2160),\n+\t\tSize(5120, 2880),\n+\t\tSize(7680, 4320),\n+\t};\n+\tstd::vector<Size> sizes;\n+\n+\t/* Make sure pixel format exists. */\n+\tauto const &it = formats_.find(pixelformat);\n+\tif (it == formats_.end())\n+\t\treturn {};\n+\n+\t/* Try create list of discrete sizes. */\n+\tconst std::vector<SizeRange> &ranges = it->second;\n+\tbool discrete = true;\n+\tfor (const SizeRange &range : ranges) {\n+\t\tif (range.min != range.max) {\n+\t\t\tdiscrete = false;\n+\t\t\tbreak;\n+\t\t}\n+\t\tsizes.emplace_back(range.min.width, range.min.height);\n+\t}\n+\n+\t/* If discrete not possible generate from range. */\n+\tif (!discrete) {\n+\t\tif (ranges.size() != 1) {\n+\t\t\tLOG(Stream, Error) << \"Range format is ambiguous\";\n+\t\t\treturn {};\n+\t\t}\n+\n+\t\tconst SizeRange &limit = ranges.front();\n+\t\tsizes.clear();\n+\n+\t\tfor (const Size &size : rangeDiscreteSizes) {\n+\t\t\tif (size.width < limit.min.width ||\n+\t\t\t    size.width > limit.max.width ||\n+\t\t\t    size.height < limit.min.height ||\n+\t\t\t    size.height > limit.max.height ||\n+\t\t\t    (size.width - limit.min.width) % limit.vStep ||\n+\t\t\t    (size.height - limit.min.height) % limit.hStep)\n+\t\t\t\tcontinue;\n+\n+\t\t\tsizes.push_back(size);\n+\t\t}\n+\t}\n+\n+\tstd::sort(sizes.begin(), sizes.end());\n+\n+\treturn sizes;\n+}\n+\n+/**\n+ * \\brief Retrieve a frame size range\n+ * \\param[in] pixelformat Pixel format to retrieve range for\n+ * \\returns Range description of frame size\n+ */\n+SizeRange StreamFormats::range(unsigned int pixelformat) const\n+{\n+\tauto const it = formats_.find(pixelformat);\n+\tif (it == formats_.end())\n+\t\treturn {};\n+\n+\tconst SizeRange &first = it->second.front();\n+\tif (it->second.size() == 1)\n+\t\treturn first;\n+\n+\tLOG(Stream, Debug) << \"Building range from discret\";\n+\n+\tSizeRange range(first.min.width, first.min.height,\n+\t\t\tfirst.max.width, first.max.height);\n+\n+\tfor (const SizeRange &limit : it->second) {\n+\t\tif (limit.min < range.min)\n+\t\t\trange.min = limit.min;\n+\n+\t\tif (limit.max > range.max)\n+\t\t\trange.max = limit.max;\n+\t}\n+\n+\treturn range;\n+}\n+\n /**\n  * \\struct StreamConfiguration\n  * \\brief Configuration parameters for a stream\n","prefixes":["libcamera-devel","11/17"]}