Show a patch.

GET /api/1.1/patches/1441/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 1441,
    "url": "https://patchwork.libcamera.org/api/1.1/patches/1441/?format=api",
    "web_url": "https://patchwork.libcamera.org/patch/1441/",
    "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": "<20190616133402.21934-11-niklas.soderlund@ragnatech.se>",
    "date": "2019-06-16T13:33:56",
    "name": "[libcamera-devel,v3,10/16] libcamera: stream: Add StreamFormats",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": false,
    "hash": "c07a88c2a22e4d6b91215ccd5f6408946ec21aeb",
    "submitter": {
        "id": 5,
        "url": "https://patchwork.libcamera.org/api/1.1/people/5/?format=api",
        "name": "Niklas Söderlund",
        "email": "niklas.soderlund@ragnatech.se"
    },
    "delegate": null,
    "mbox": "https://patchwork.libcamera.org/patch/1441/mbox/",
    "series": [
        {
            "id": 358,
            "url": "https://patchwork.libcamera.org/api/1.1/series/358/?format=api",
            "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=358",
            "date": "2019-06-16T13:33:46",
            "name": "libcamera: Add support for format information and validation",
            "version": 3,
            "mbox": "https://patchwork.libcamera.org/series/358/mbox/"
        }
    ],
    "comments": "https://patchwork.libcamera.org/api/patches/1441/comments/",
    "check": "pending",
    "checks": "https://patchwork.libcamera.org/api/patches/1441/checks/",
    "tags": {},
    "headers": {
        "Return-Path": "<niklas.soderlund@ragnatech.se>",
        "Received": [
            "from bin-mail-out-06.binero.net (bin-mail-out-06.binero.net\n\t[195.74.38.229])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 80C9D6475A\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tSun, 16 Jun 2019 15:35:39 +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 995bc1cf-903b-11e9-8ab4-005056917a89;\n\tSun, 16 Jun 2019 15:35:26 +0200 (CEST)"
        ],
        "X-Halon-ID": "995bc1cf-903b-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": "Sun, 16 Jun 2019 15:33:56 +0200",
        "Message-Id": "<20190616133402.21934-11-niklas.soderlund@ragnatech.se>",
        "X-Mailer": "git-send-email 2.21.0",
        "In-Reply-To": "<20190616133402.21934-1-niklas.soderlund@ragnatech.se>",
        "References": "<20190616133402.21934-1-niklas.soderlund@ragnatech.se>",
        "MIME-Version": "1.0",
        "Content-Type": "text/plain; charset=UTF-8",
        "Content-Transfer-Encoding": "8bit",
        "Subject": "[libcamera-devel] [PATCH v3 10/16] libcamera: stream: Add\n\tStreamFormats",
        "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": "Sun, 16 Jun 2019 13:35:39 -0000"
    },
    "content": "Add a StreamFormats class which describes all the formats supported by a\nstream. The object does not collect any information  itself but can\nsimplify user interactions 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>\nReviewed-by: Jacopo Mondi <jacopo@jmondi.org>\n---\n include/libcamera/stream.h |  16 +++\n src/libcamera/stream.cpp   | 226 +++++++++++++++++++++++++++++++++++++\n 2 files changed, 242 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 0c59a31a3a0501d3..27fde5fe29eeb340 100644\n--- a/src/libcamera/stream.cpp\n+++ b/src/libcamera/stream.cpp\n@@ -7,9 +7,13 @@\n \n #include <libcamera/stream.h>\n \n+#include <algorithm>\n+#include <climits>\n #include <iomanip>\n #include <sstream>\n \n+#include \"log.h\"\n+\n /**\n  * \\file stream.h\n  * \\brief Video stream for a Camera\n@@ -32,6 +36,228 @@\n \n 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 the pixel formats and frame\n+ * sizes a stream supports. The class groups size information by the pixel\n+ * format which can produce it.\n+ *\n+ * There are two ways to examine the size information, as a range or as a list\n+ * of discrete sizes. When sizes are viewed as a range it describes the minimum\n+ * and maximum width and height values. There is a possibility to supplement the\n+ * range description with a horizontal and vertical step. The step describes the\n+ * size in pixels starting from the minimum with/height.\n+ *\n+ * When sizes are viewed as a list of discrete sizes they describe the exact\n+ * dimensions 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 translate between the two different ways to view them. The translations\n+ * are performed as:\n+ *\n+ *  - If the StreamFormat is constructed using a list of discrete image sizes\n+ *    and a range is requested, it gets created by taking the minimum and\n+ *    maximum width/height in the list. The step information is not recreated\n+ *    and is set to 0 to indicate the range is generated.\n+ *\n+ *  - If the image sizes used to construct a StreamFormat are expressed as a\n+ *    range and a list of discrete sizes is requested, one which fits inside\n+ *    that range are selected from a list of common sizes. The step information\n+ *    is taken into consideration when generating the sizes.\n+ *\n+ * Applications examining sizes as a range with step values of 0 shall be\n+ * aware that the range are generated from a list of discrete sizes and there\n+ * could be a large quantity of possible Size combinations which may not\n+ * be supported by the Stream.\n+ *\n+ * All sizes retrieved from StreamFormats shall be treated as advisory and no\n+ * size shall be considered to be supported until its been verified using\n+ * CameraConfiguration::validate().\n+ */\n+\n+StreamFormats::StreamFormats()\n+{\n+}\n+\n+/**\n+ * \\brief Construct a StreamFormats object with a map of image formats\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 supported pixel formats\n+ * \\return The list of supported 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 supported by \\a pixelformat\n+ * \\param[in] pixelformat Pixel format to retrieve sizes for\n+ *\n+ * If the sizes described for \\a pixelformat are discrete they are returned\n+ * directly. If the size described is a range a list of discrete sizes are\n+ * computed from a set list of common resolutions which fits inside the\n+ * described range. When computing the discrete list step values are considered\n+ * but there are no guarantees that all sizes computed are supported.\n+ *\n+ * \\return A list of frame sizes or an empty list on error\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 creating a 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);\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 (limit.contains(size))\n+\t\t\t\tsizes.push_back(size);\n+\t}\n+\n+\tstd::sort(sizes.begin(), sizes.end());\n+\n+\treturn sizes;\n+}\n+\n+/**\n+ * \\brief Retrieve the range of minimum and maximu sizes\n+ * \\param[in] pixelformat Pixel format to retrieve range for\n+ *\n+ * If the size described for \\a pixelformat is a range that range is returned\n+ * directly. If the sizes described are a list of discrete sizes a range is\n+ * computed from the minimum and maxim sizes in the list. The step values of\n+ * a computed range is set to 0 to indicate that the range is generated and\n+ * that not all image sizes contained in the range might be supported.\n+ *\n+ * \\return A range of valid image sizes or an empty range on error\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 std::vector<SizeRange> &ranges = it->second;\n+\tif (ranges.size() == 1)\n+\t\treturn ranges[0];\n+\n+\tLOG(Stream, Debug) << \"Building range from discrete\";\n+\tSizeRange range(UINT_MAX, UINT_MAX, 0, 0);\n+\tfor (const SizeRange &limit : ranges) {\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+\trange.hStep = 0;\n+\trange.vStep = 0;\n+\n+\treturn range;\n+}\n+\n /**\n  * \\struct StreamConfiguration\n  * \\brief Configuration parameters for a stream\n",
    "prefixes": [
        "libcamera-devel",
        "v3",
        "10/16"
    ]
}