Show a patch.

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

{
    "id": 17281,
    "url": "https://patchwork.libcamera.org/api/patches/17281/?format=api",
    "web_url": "https://patchwork.libcamera.org/patch/17281/",
    "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": "<20220902150031.31184-1-jacopo@jmondi.org>",
    "date": "2022-09-02T15:00:31",
    "name": "[libcamera-devel] cam: capture_script: Introduce 'loop' property",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": false,
    "hash": "50e9c3379caa2194dd8af32c95b53866fd748fa0",
    "submitter": {
        "id": 3,
        "url": "https://patchwork.libcamera.org/api/people/3/?format=api",
        "name": "Jacopo Mondi",
        "email": "jacopo@jmondi.org"
    },
    "delegate": null,
    "mbox": "https://patchwork.libcamera.org/patch/17281/mbox/",
    "series": [
        {
            "id": 3461,
            "url": "https://patchwork.libcamera.org/api/series/3461/?format=api",
            "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=3461",
            "date": "2022-09-02T15:00:31",
            "name": "[libcamera-devel] cam: capture_script: Introduce 'loop' property",
            "version": 1,
            "mbox": "https://patchwork.libcamera.org/series/3461/mbox/"
        }
    ],
    "comments": "https://patchwork.libcamera.org/api/patches/17281/comments/",
    "check": "pending",
    "checks": "https://patchwork.libcamera.org/api/patches/17281/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 3E76FC0DA4\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri,  2 Sep 2022 15:00:40 +0000 (UTC)",
            "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id B9EF461FF2;\n\tFri,  2 Sep 2022 17:00:39 +0200 (CEST)",
            "from relay2-d.mail.gandi.net (relay2-d.mail.gandi.net\n\t[217.70.183.194])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 83D7761F9D\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri,  2 Sep 2022 17:00:37 +0200 (CEST)",
            "(Authenticated sender: jacopo@jmondi.org)\n\tby mail.gandi.net (Postfix) with ESMTPSA id 056764000C;\n\tFri,  2 Sep 2022 15:00:36 +0000 (UTC)"
        ],
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1662130839;\n\tbh=YgBnDfr97uKlJZ/OtsIWYvU8FWEj79b6TVXzX7mXKGY=;\n\th=To:Date:Subject:List-Id:List-Unsubscribe:List-Archive:List-Post:\n\tList-Help:List-Subscribe:From:Reply-To:From;\n\tb=wFiw3KqL6nsYkkUNpE1gXd/KezMnUa+6YsE9+po5k3HFyQrCER0DKSfXp3tN9n0S2\n\tPDoGQtldjJw4nLm2d1RwJn9Z4vi/TF5uaQIgP0YFRe/h7yCQ75T+qdWUd4kfO9HUUM\n\tNeVL8y0vf0hm0Ld781n4ZEnzOxknR3p64j2lo14thASaGVnkHb2odI93xPCn7J1aV7\n\tcR3FAmRYCaZe1lJlDICdWehLauqFZL/QK9t+v9Dvh9B1V9ECcTpLk7+IgbljLMFVIi\n\t8VPUL45yV3eAKaytUxS9hwMkEFEGRcYLoWDe0ftt58jjQXmLUNNBxvsr97394nnm8Q\n\tErGsQ56/N0Rfg==",
        "To": "libcamera-devel@lists.libcamera.org",
        "Date": "Fri,  2 Sep 2022 17:00:31 +0200",
        "Message-Id": "<20220902150031.31184-1-jacopo@jmondi.org>",
        "X-Mailer": "git-send-email 2.37.2",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "8bit",
        "Subject": "[libcamera-devel] [PATCH] cam: capture_script: Introduce 'loop'\n\tproperty",
        "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": "Add to the capture script support for properties that control the script\nexecution. Script properties are specified in a 'properties' section\nbefore the actual list of controls specified in the 'frames' section.\n\nDefine a first 'loop' property that allows to repeat the frame list\nperiodically. All the frame ids in the 'frames' section shall be smaller\nthan the loop control.\n\nModify the capture script example to show usage of the 'loop' property\nand better document the frames list while at it.\n\nSigned-off-by: Jacopo Mondi <jacopo@jmondi.org>\n---\n src/cam/capture-script.yaml | 50 +++++++++++------------\n src/cam/capture_script.cpp  | 79 +++++++++++++++++++++++++++++++++++--\n src/cam/capture_script.h    |  3 ++\n 3 files changed, 102 insertions(+), 30 deletions(-)",
    "diff": "diff --git a/src/cam/capture-script.yaml b/src/cam/capture-script.yaml\nindex 6a749bc60cf7..dbea4a9f01a7 100644\n--- a/src/cam/capture-script.yaml\n+++ b/src/cam/capture-script.yaml\n@@ -5,6 +5,20 @@\n # A capture script allows to associate a list of controls and their values\n # to frame numbers.\n \n+# The script allows to define a list of frames associated with controls and\n+# an optional list of properties that controls the script behaviour\n+#\n+# properties:\n+#   - loop: idx\n+#     Repeat the controls every 'idx' frames.\n+#\n+#  frames:\n+#    - frameid:\n+#        Control1: value1\n+#        Control2: value2\n+#\n+#    List of frame ids with associated a list of controls to be applied\n+#\n # \\todo Formally define the capture script structure with a schema\n \n # Notes:\n@@ -12,35 +26,17 @@\n #   libcamera::controls:: enumeration\n # - Controls not supported by the camera currently operated are ignored\n # - Frame numbers shall be monotonically incrementing, gaps are allowed\n+# - If a loop limit is specified, frame numbers in the 'frames' list shall be\n+#   strictly minor than the loop control\n \n-# Example:\n-frames:\n-  - 1:\n-      Brightness: 0.0\n+# Example: Turn brightness up and down every 50 frames\n \n-  - 40:\n-      Brightness: 0.2\n+properties:\n+  - loop: 50\n \n-  - 80:\n-      Brightness: 0.4\n-\n-  - 120:\n-      Brightness: 0.8\n-\n-  - 160:\n-      Brightness: 0.4\n-\n-  - 200:\n-      Brightness: 0.2\n-\n-  - 240:\n+frames:\n+  - 0:\n       Brightness: 0.0\n \n-  - 280:\n-      Brightness: -0.2\n-\n-  - 300:\n-      Brightness: -0.4\n-\n-  - 340:\n-      Brightness: -0.8\n+  - 25:\n+      Brightness: 0.8\ndiff --git a/src/cam/capture_script.cpp b/src/cam/capture_script.cpp\nindex 5e85b3ca604c..52bf19961c17 100644\n--- a/src/cam/capture_script.cpp\n+++ b/src/cam/capture_script.cpp\n@@ -15,7 +15,7 @@ using namespace libcamera;\n \n CaptureScript::CaptureScript(std::shared_ptr<Camera> camera,\n \t\t\t     const std::string &fileName)\n-\t: camera_(camera), valid_(false)\n+\t: camera_(camera), loop_(0), valid_(false)\n {\n \tFILE *fh = fopen(fileName.c_str(), \"r\");\n \tif (!fh) {\n@@ -44,8 +44,13 @@ CaptureScript::CaptureScript(std::shared_ptr<Camera> camera,\n const ControlList &CaptureScript::frameControls(unsigned int frame)\n {\n \tstatic ControlList controls{};\n+\tunsigned int idx = frame;\n \n-\tauto it = frameControls_.find(frame);\n+\t/* If we loop, repeat the controls every 'loop_' frames. */\n+\tif (loop_)\n+\t\tidx = frame % loop_;\n+\n+\tauto it = frameControls_.find(idx);\n \tif (it == frameControls_.end())\n \t\treturn controls;\n \n@@ -149,7 +154,11 @@ int CaptureScript::parseScript(FILE *script)\n \n \t\tstd::string section = eventScalarValue(event);\n \n-\t\tif (section == \"frames\") {\n+\t\tif (section == \"properties\") {\n+\t\t\tret = parseProperties();\n+\t\t\tif (ret)\n+\t\t\t\treturn ret;\n+\t\t} else if (section == \"frames\") {\n \t\t\tret = parseFrames();\n \t\t\tif (ret)\n \t\t\t\treturn ret;\n@@ -161,6 +170,64 @@ int CaptureScript::parseScript(FILE *script)\n \t}\n }\n \n+int CaptureScript::parseProperty()\n+{\n+\tEventPtr event = nextEvent(YAML_MAPPING_START_EVENT);\n+\tif (!event)\n+\t\treturn -EINVAL;\n+\n+\tstd::string prop = parseScalar();\n+\tif (prop.empty())\n+\t\treturn -EINVAL;\n+\n+\tif (prop == \"loop\") {\n+\t\tevent = nextEvent();\n+\t\tif (!event)\n+\t\t\treturn -EINVAL;\n+\n+\t\tstd::string value = eventScalarValue(event);\n+\t\tif (value.empty())\n+\t\t\treturn -EINVAL;\n+\n+\t\tloop_ = atoi(value.c_str());\n+\t\tif (!loop_) {\n+\t\t\tstd::cerr << \"Invalid loop limit: \" << loop_ << std::endl;\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\t} else {\n+\t\tstd::cerr << \"Unsupported property: \" << prop << std::endl;\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tevent = nextEvent(YAML_MAPPING_END_EVENT);\n+\tif (!event)\n+\t\treturn -EINVAL;\n+\n+\treturn 0;\n+}\n+\n+int CaptureScript::parseProperties()\n+{\n+\tEventPtr event = nextEvent(YAML_SEQUENCE_START_EVENT);\n+\tif (!event)\n+\t\treturn -EINVAL;\n+\n+\twhile (1) {\n+\t\tif (event->type == YAML_SEQUENCE_END_EVENT)\n+\t\t\treturn 0;\n+\n+\t\tint ret = parseProperty();\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\n+\t\tevent = nextEvent();\n+\t\tif (!event)\n+\t\t\treturn -EINVAL;\n+\t}\n+\n+\treturn 0;\n+}\n+\n int CaptureScript::parseFrames()\n {\n \tEventPtr event = nextEvent(YAML_SEQUENCE_START_EVENT);\n@@ -191,6 +258,12 @@ int CaptureScript::parseFrame(EventPtr event)\n \t\treturn -EINVAL;\n \n \tunsigned int frameId = atoi(key.c_str());\n+\tif (loop_ && frameId >= loop_) {\n+\t\tstd::cerr\n+\t\t\t<< \"Frame id (\" << frameId << \") shall be smaller than\"\n+\t\t\t<< \"loop limit (\" << loop_ << \")\" << std::endl;\n+\t\treturn -EINVAL;\n+\t}\n \n \tevent = nextEvent(YAML_MAPPING_START_EVENT);\n \tif (!event)\ndiff --git a/src/cam/capture_script.h b/src/cam/capture_script.h\nindex fffe67e5a3df..7a0ddebb00b5 100644\n--- a/src/cam/capture_script.h\n+++ b/src/cam/capture_script.h\n@@ -40,6 +40,7 @@ private:\n \tstd::map<unsigned int, libcamera::ControlList> frameControls_;\n \tstd::shared_ptr<libcamera::Camera> camera_;\n \tyaml_parser_t parser_;\n+\tunsigned int loop_;\n \tbool valid_;\n \n \tEventPtr nextEvent(yaml_event_type_t expectedType = YAML_NO_EVENT);\n@@ -49,6 +50,8 @@ private:\n \n \tint parseScript(FILE *script);\n \n+\tint parseProperties();\n+\tint parseProperty();\n \tint parseFrames();\n \tint parseFrame(EventPtr event);\n \tint parseControl(EventPtr event, libcamera::ControlList &controls);\n",
    "prefixes": [
        "libcamera-devel"
    ]
}