Show a patch.

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

{
    "id": 21616,
    "url": "https://patchwork.libcamera.org/api/1.1/patches/21616/?format=api",
    "web_url": "https://patchwork.libcamera.org/patch/21616/",
    "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": "<20241014095937.24924-5-jacopo.mondi@ideasonboard.com>",
    "date": "2024-10-14T09:59:36",
    "name": "[RFC,4/4] libcamera: pipeline_handler: Use YamlEmitter",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": false,
    "hash": "ba4f848fdc21d18d01d58e4c8f52bc323b947a7c",
    "submitter": {
        "id": 143,
        "url": "https://patchwork.libcamera.org/api/1.1/people/143/?format=api",
        "name": "Jacopo Mondi",
        "email": "jacopo.mondi@ideasonboard.com"
    },
    "delegate": null,
    "mbox": "https://patchwork.libcamera.org/patch/21616/mbox/",
    "series": [
        {
            "id": 4695,
            "url": "https://patchwork.libcamera.org/api/1.1/series/4695/?format=api",
            "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=4695",
            "date": "2024-10-14T09:59:32",
            "name": "libcamera: Implement YamlEmitter",
            "version": 1,
            "mbox": "https://patchwork.libcamera.org/series/4695/mbox/"
        }
    ],
    "comments": "https://patchwork.libcamera.org/api/patches/21616/comments/",
    "check": "pending",
    "checks": "https://patchwork.libcamera.org/api/patches/21616/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 8D4D8C32F8\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon, 14 Oct 2024 10:00:10 +0000 (UTC)",
            "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 4F6736538E;\n\tMon, 14 Oct 2024 12:00:06 +0200 (CEST)",
            "from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 3ED316537B\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 14 Oct 2024 12:00:00 +0200 (CEST)",
            "from ideasonboard.com (unknown [5.77.95.224])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 849828BE;\n\tMon, 14 Oct 2024 11:58:18 +0200 (CEST)"
        ],
        "Authentication-Results": "lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"ob6HMijX\"; dkim-atps=neutral",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1728899899;\n\tbh=oXrkN3on37pRu2/oNtO4qLlJzaW8X6MHVA/ZT7ap/KA=;\n\th=From:To:Cc:Subject:Date:In-Reply-To:References:From;\n\tb=ob6HMijXxQ/xuQcQawIjayCr466GvGB5aCZhLimfLOMbSMnOr3LCI28koPfA0Iavr\n\txSQteQfwgyXjVyUFhQzDWLGyIIddOZVA0sMmSfw9yZwds2o71F4k5tTMz2WGYnFxuO\n\tp8pT7qMbQkWqjNk/R+gwEAAw04M3udexZcjlCuf0=",
        "From": "Jacopo Mondi <jacopo.mondi@ideasonboard.com>",
        "To": "libcamera-devel@lists.libcamera.org",
        "Cc": "Jacopo Mondi <jacopo.mondi@ideasonboard.com>",
        "Subject": "[RFC 4/4] libcamera: pipeline_handler: Use YamlEmitter",
        "Date": "Mon, 14 Oct 2024 11:59:36 +0200",
        "Message-ID": "<20241014095937.24924-5-jacopo.mondi@ideasonboard.com>",
        "X-Mailer": "git-send-email 2.46.2",
        "In-Reply-To": "<20241014095937.24924-1-jacopo.mondi@ideasonboard.com>",
        "References": "<20241014095937.24924-1-jacopo.mondi@ideasonboard.com>",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "8bit",
        "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>",
        "Errors-To": "libcamera-devel-bounces@lists.libcamera.org",
        "Sender": "\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"
    },
    "content": "Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>\n---\n include/libcamera/internal/pipeline_handler.h | 11 ++-\n src/libcamera/pipeline_handler.cpp            | 94 +++++++++----------\n 2 files changed, 54 insertions(+), 51 deletions(-)",
    "diff": "diff --git a/include/libcamera/internal/pipeline_handler.h b/include/libcamera/internal/pipeline_handler.h\nindex fb3914185a01..a10d7b1fab8c 100644\n--- a/include/libcamera/internal/pipeline_handler.h\n+++ b/include/libcamera/internal/pipeline_handler.h\n@@ -19,6 +19,8 @@\n #include <libcamera/controls.h>\n #include <libcamera/stream.h>\n \n+#include \"libcamera/internal/yaml_emitter.h\"\n+\n namespace libcamera {\n \n enum class Orientation;\n@@ -110,8 +112,13 @@ private:\n \tconst char *name_;\n \tunsigned int useCount_;\n \n-\tstd::ostream *dumpCaptureScript_;\n-\tstd::ostream *dumpMetadata_;\n+\tstd::unique_ptr<YamlRoot> controlsEmitter_;\n+\tstd::unique_ptr<YamlDict> controlsDict_;\n+\tstd::unique_ptr<YamlList> controlsList_;\n+\n+\tstd::unique_ptr<YamlRoot> metadataEmitter_;\n+\tstd::unique_ptr<YamlDict> metadataDict_;\n+\tstd::unique_ptr<YamlList> metadataList_;\n \n \tfriend class PipelineHandlerFactoryBase;\n };\ndiff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp\nindex 7002b4323bdd..82868a8122ce 100644\n--- a/src/libcamera/pipeline_handler.cpp\n+++ b/src/libcamera/pipeline_handler.cpp\n@@ -69,36 +69,31 @@ LOG_DEFINE_CATEGORY(Pipeline)\n  * through the PipelineHandlerFactoryBase::create() function.\n  */\n PipelineHandler::PipelineHandler(CameraManager *manager)\n-\t: manager_(manager), useCount_(0),\n-\t  dumpCaptureScript_(nullptr), dumpMetadata_(nullptr)\n+\t: manager_(manager), useCount_(0)\n {\n \t/* TODO Print notification that we're dumping capture script */\n \tconst char *file = utils::secure_getenv(\"LIBCAMERA_DUMP_CAPTURE_SCRIPT\");\n \tif (!file)\n \t\treturn;\n \n-\tdumpCaptureScript_ = new std::ofstream(file);\n+\tstd::string filePath(file);\n+\tcontrolsEmitter_ = YamlEmitter::root(filePath);\n+\tcontrolsDict_ = controlsEmitter_->dict();\n \n \t/*\n \t * Metadata needs to go into a separate file because otherwise it'll\n \t * flood the capture script\n \t */\n-\tdumpMetadata_ = new std::ofstream(std::string(file) + \".metadata\");\n-\tstd::string str = \"frames:\\n\";\n-\tdumpMetadata_->write(str.c_str(), str.size());\n-\tdumpMetadata_->flush();\n+\tstd::string metadataFilePath = filePath + \".metadata\";\n+\tmetadataEmitter_ = YamlEmitter::root(metadataFilePath);\n+\tmetadataDict_ = metadataEmitter_->dict();\n+\tmetadataList_ = metadataDict_->list(\"frames\");\n }\n \n PipelineHandler::~PipelineHandler()\n {\n \tfor (std::shared_ptr<MediaDevice> media : mediaDevices_)\n \t\tmedia->release();\n-\n-\tif (dumpCaptureScript_)\n-\t\tdelete dumpCaptureScript_;\n-\n-\tif (dumpMetadata_)\n-\t\tdelete dumpMetadata_;\n }\n \n /**\n@@ -788,65 +783,66 @@ void PipelineHandler::disconnect()\n void PipelineHandler::dumpConfiguration(const std::set<const Stream *> &streams,\n \t\t\t\t\tconst Orientation &orientation)\n {\n-\tif (!dumpCaptureScript_)\n-\t\treturn;\n+\tauto configurationDict = controlsDict_->dict(\"configuration\");\n \n-\tstd::stringstream ss;\n-\tss << \"configuration:\" << std::endl;\n-\tss << \"  orientation: \" << orientation << std::endl;\n+\t(*configurationDict)[\"orientation\"] = orientation;\n \n \t/* TODO Dump Sensor configuration */\n \n-\tss << \"  streams:\" << std::endl;\n+\tauto streamsList = configurationDict->list(\"streams\");\n+\n \tfor (const auto &stream : streams) {\n \t\tconst StreamConfiguration &streamConfig = stream->configuration();\n-\t\tss << \"    - pixelFormat: \" << streamConfig.pixelFormat << std::endl;\n-\t\tss << \"      size: \" << streamConfig.size << std::endl;\n-\t\tss << \"      stride: \" << streamConfig.stride << std::endl;\n-\t\tss << \"      frameSize: \" << streamConfig.frameSize << std::endl;\n-\t\tss << \"      bufferCount: \" << streamConfig.bufferCount << std::endl;\n+\t\tauto yamlStream = streamsList->dict();\n+\n+\t\t(*yamlStream)[\"pixelformat\"] = streamConfig.pixelFormat.toString();\n+\t\t(*yamlStream)[\"size\"] = streamConfig.size.toString();\n+\t\t(*yamlStream)[\"stride\"] = std::to_string(streamConfig.stride);\n+\t\t(*yamlStream)[\"frameSize\"] = std::to_string(streamConfig.frameSize);\n+\t\t(*yamlStream)[\"bufferCount\"] = std::to_string(streamConfig.bufferCount);\n+\n \t\tif (streamConfig.colorSpace)\n-\t\t\tss << \"      colorSpace: \" << streamConfig.colorSpace->toString() << std::endl;\n+\t\t\t(*yamlStream)[\"colorSpace\"] =\n+\t\t\t\tstreamConfig.colorSpace->toString();\n \t}\n \n-\tdumpCaptureScript_->write(ss.str().c_str(), ss.str().size());\n+\tstreamsList->close();\n+\tconfigurationDict->close();\n \n-\tstd::string str = \"frames:\\n\";\n-\tdumpCaptureScript_->write(str.c_str(), str.size());\n-\tdumpCaptureScript_->flush();\n+\tcontrolsList_ = controlsDict_->list(\"frames\");\n }\n \n void PipelineHandler::dumpRequest(Request *request, DumpMode mode)\n {\n-\tControlList &controls =\n-\t\tmode == DumpMode::Controls ? request->controls()\n-\t\t\t\t\t   : request->metadata();\n-\tstd::ostream *output =\n-\t\tmode == DumpMode::Controls ? dumpCaptureScript_\n-\t\t\t\t\t   : dumpMetadata_;\n-\n-\tif (!output || controls.empty())\n+\tControlList &controls = mode == DumpMode::Controls ? request->controls()\n+\t\t\t\t\t\t\t   : request->metadata();\n+\tif (controls.empty())\n \t\treturn;\n \n-\tstd::stringstream ss;\n+\tstd::unique_ptr<YamlDict> yamlFrame;\n+\tif (mode == DumpMode::Controls) {\n+\t\tif (!controlsEmitter_)\n+\t\t\treturn;\n+\n+\t\tyamlFrame = controlsList_->dict();\n+\t} else {\n+\t\tif (!metadataEmitter_)\n+\t\t\treturn;\n+\n+\t\tyamlFrame = metadataList_->dict();\n+\t}\n+\n+\tauto yamlCtrls = yamlFrame->dict(std::to_string(request->sequence()));\n+\n \t/* TODO Figure out PFC */\n-\tss << \"  - \" << request->sequence() << \":\" << std::endl;\n \n \tconst ControlIdMap *idMap = controls.idMap();\n \tfor (const auto &pair : controls) {\n \t\tconst ControlId *ctrlId = idMap->at(pair.first);\n+\n \t\t/* TODO Prettify enums (probably by upgrading ControlValue::toString()) */\n-\t\tss << \"      \" << ctrlId->name() << \": \" << pair.second.toString() << std::endl;\n+\t\t(*yamlCtrls)[ctrlId->name()] = pair.second.toString();\n \t}\n-\n-\t/*\n-\t * TODO Investigate the overhead of flushing this frequently\n-\t * Controls aren't going to be queued too frequently so it should be\n-\t * fine to dump controls every frame. Metadata on the other hand needs\n-\t * to be investigated.\n-\t */\n-\toutput->write(ss.str().c_str(), ss.str().size());\n-\toutput->flush();\n }\n \n /**\n",
    "prefixes": [
        "RFC",
        "4/4"
    ]
}