{"id":21715,"url":"https://patchwork.libcamera.org/api/1.1/patches/21715/?format=json","web_url":"https://patchwork.libcamera.org/patch/21715/","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":"<20241021094955.26991-5-jacopo.mondi@ideasonboard.com>","date":"2024-10-21T09:49:52","name":"[RFC,v3,4/4] libcamera: pipeline_handler: Use YamlEmitter","commit_ref":null,"pull_url":null,"state":"superseded","archived":false,"hash":"da895d31fb5afc44878344ca5ce799373b90309a","submitter":{"id":143,"url":"https://patchwork.libcamera.org/api/1.1/people/143/?format=json","name":"Jacopo Mondi","email":"jacopo.mondi@ideasonboard.com"},"delegate":null,"mbox":"https://patchwork.libcamera.org/patch/21715/mbox/","series":[{"id":4730,"url":"https://patchwork.libcamera.org/api/1.1/series/4730/?format=json","web_url":"https://patchwork.libcamera.org/project/libcamera/list/?series=4730","date":"2024-10-21T09:49:49","name":"[RFC,v3,1/4] pipeline: Add support for dumping capture script and metadata","version":3,"mbox":"https://patchwork.libcamera.org/series/4730/mbox/"}],"comments":"https://patchwork.libcamera.org/api/patches/21715/comments/","check":"pending","checks":"https://patchwork.libcamera.org/api/patches/21715/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 BA129C3304\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon, 21 Oct 2024 09:50:24 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id CAC7E65395;\n\tMon, 21 Oct 2024 11:50:23 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 0A48265395\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 21 Oct 2024 11:50:14 +0200 (CEST)","from ideasonboard.com (mob-5-90-62-78.net.vodafone.it [5.90.62.78])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 0611319F8;\n\tMon, 21 Oct 2024 11:48:28 +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=\"Da0oR1Fc\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1729504109;\n\tbh=YnaqdHf4COiwyOo9ZyS6UvZnQLokg1OBDK6AnEZiopo=;\n\th=From:To:Cc:Subject:Date:In-Reply-To:References:From;\n\tb=Da0oR1FcRRFj4UhGgSl/bpTJCkiWZEF2GrNF0LI6PcnZ/Lbq6CH6oRcWBUUtzUE12\n\t2dFaZfWqUV8szqDxaJyE4T+spl4JrxWAum7x3V36xi4kKC9x7cfcpNqNOm3dJoPAM7\n\tjsrX02y/RjbraUMdWVQkqTHXkBdN75ZBFwpi6lDA=","From":"Jacopo Mondi <jacopo.mondi@ideasonboard.com>","To":"libcamera-devel@lists.libcamera.org","Cc":"Jacopo Mondi <jacopo.mondi@ideasonboard.com>","Subject":"[RFC v3 4/4] libcamera: pipeline_handler: Use YamlEmitter","Date":"Mon, 21 Oct 2024 11:49:52 +0200","Message-ID":"<20241021094955.26991-5-jacopo.mondi@ideasonboard.com>","X-Mailer":"git-send-email 2.47.0","In-Reply-To":"<20241021094955.26991-1-jacopo.mondi@ideasonboard.com>","References":"<20241021094955.26991-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":"Replace raw output usage with YamlEmitter.\n\nSigned-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>\n---\n include/libcamera/internal/pipeline_handler.h | 11 ++-\n src/libcamera/pipeline_handler.cpp            | 99 +++++++++----------\n 2 files changed, 58 insertions(+), 52 deletions(-)","diff":"diff --git a/include/libcamera/internal/pipeline_handler.h b/include/libcamera/internal/pipeline_handler.h\nindex fb3914185a01..89d10b373cfa 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+\tYamlRoot controlsEmitter_;\n+\tYamlDict controlsDict_;\n+\tYamlList controlsList_;\n+\n+\tYamlRoot metadataEmitter_;\n+\tYamlDict metadataDict_;\n+\tYamlList metadataList_;\n \n \tfriend class PipelineHandlerFactoryBase;\n };\ndiff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp\nindex 7002b4323bdd..b5d613f630a2 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@@ -785,68 +780,72 @@ void PipelineHandler::disconnect()\n  * \\return The CameraManager for this pipeline handler\n  */\n \n+/**\n+ * \\brief todo\n+ */\n void PipelineHandler::dumpConfiguration(const std::set<const Stream *> &streams,\n \t\t\t\t\tconst Orientation &orientation)\n {\n-\tif (!dumpCaptureScript_)\n+\tif (!controlsEmitter_.initialized())\n \t\treturn;\n \n-\tstd::stringstream ss;\n-\tss << \"configuration:\" << std::endl;\n-\tss << \"  orientation: \" << orientation << std::endl;\n+\tYamlDict configurationDict = controlsDict_.dict(\"configuration\");\n+\n+\tstd::stringstream o;\n+\to << orientation;\n+\tconfigurationDict[\"orientation\"] = o.str();\n \n \t/* TODO Dump Sensor configuration */\n \n-\tss << \"  streams:\" << std::endl;\n+\tYamlList 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\tif (streamConfig.colorSpace)\n-\t\t\tss << \"      colorSpace: \" << streamConfig.colorSpace->toString() << std::endl;\n-\t}\n+\t\tYamlDict yamlStream = streamsList.dict();\n \n-\tdumpCaptureScript_->write(ss.str().c_str(), ss.str().size());\n+\t\tyamlStream[\"pixelformat\"] = streamConfig.pixelFormat.toString();\n+\t\tyamlStream[\"size\"] = streamConfig.size.toString();\n+\t\tyamlStream[\"stride\"] = std::to_string(streamConfig.stride);\n+\t\tyamlStream[\"frameSize\"] = std::to_string(streamConfig.frameSize);\n+\t\tyamlStream[\"bufferCount\"] = std::to_string(streamConfig.bufferCount);\n \n-\tstd::string str = \"frames:\\n\";\n-\tdumpCaptureScript_->write(str.c_str(), str.size());\n-\tdumpCaptureScript_->flush();\n+\t\tif (streamConfig.colorSpace)\n+\t\t\tyamlStream[\"colorSpace\"] =\n+\t\t\t\tstreamConfig.colorSpace->toString();\n+\t}\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+\tif (!controlsEmitter_.initialized())\n \t\treturn;\n \n-\tstd::stringstream ss;\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+\tYamlDict yamlFrame;\n+\tif (mode == DumpMode::Controls) {\n+\t\tif (!controlsList_.initialized())\n+\t\t\tcontrolsList_ = controlsDict_.list(\"frames\");\n+\n+\t\tyamlFrame = controlsList_.dict();\n+\t} else {\n+\t\tyamlFrame = metadataList_.dict();\n+\t}\n+\n+\tYamlDict 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\tyamlCtrls[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","v3","4/4"]}