[{"id":31819,"web_url":"https://patchwork.libcamera.org/comment/31819/","msgid":"<172937730579.2485972.15660754944359962829@ping.linuxembedded.co.uk>","date":"2024-10-19T22:35:05","subject":"Re: [RFC v2 4/4] libcamera: pipeline_handler: Use YamlEmitter","submitter":{"id":4,"url":"https://patchwork.libcamera.org/api/people/4/","name":"Kieran Bingham","email":"kieran.bingham@ideasonboard.com"},"content":"Quoting Jacopo Mondi (2024-10-17 13:52:19)\n> Replace raw output usage with YamlEmitter.\n> \n> Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>\n> ---\n>  include/libcamera/internal/pipeline_handler.h |  11 +-\n>  src/libcamera/pipeline_handler.cpp            | 102 +++++++++---------\n>  2 files changed, 61 insertions(+), 52 deletions(-)\n> \n> diff --git a/include/libcamera/internal/pipeline_handler.h b/include/libcamera/internal/pipeline_handler.h\n> index 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>         const char *name_;\n>         unsigned int useCount_;\n>  \n> -       std::ostream *dumpCaptureScript_;\n> -       std::ostream *dumpMetadata_;\n> +       std::unique_ptr<YamlRoot> controlsEmitter_;\n> +       std::unique_ptr<YamlDict> controlsDict_;\n> +       std::unique_ptr<YamlList> controlsList_;\n> +\n> +       std::unique_ptr<YamlRoot> metadataEmitter_;\n> +       std::unique_ptr<YamlDict> metadataDict_;\n> +       std::unique_ptr<YamlList> metadataList_;\n\nWill 'all' users of a YamlEmitter instance need each of a root/dict/list\n- or is this just specific to this usage?\n\nI don't think this series has taken on comments from Pauls' series,\nwhere I saw a lot of duplication between different 'output streams'\nwhich should be factored out.\n\nI can't tell if they should be factored out to a 'YamlEmitter' class\neach - or if ther eshould be some extra use-case specific class specific\nto the metadata here ...\n\n\n\n>  \n>         friend class PipelineHandlerFactoryBase;\n>  };\n> diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp\n> index 7002b4323bdd..533d0f8fc132 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> -       : manager_(manager), useCount_(0),\n> -         dumpCaptureScript_(nullptr), dumpMetadata_(nullptr)\n> +       : manager_(manager), useCount_(0)\n>  {\n>         /* TODO Print notification that we're dumping capture script */\n>         const char *file = utils::secure_getenv(\"LIBCAMERA_DUMP_CAPTURE_SCRIPT\");\n>         if (!file)\n>                 return;\n>  \n> -       dumpCaptureScript_ = new std::ofstream(file);\n> +       std::string filePath(file);\n> +       controlsEmitter_ = YamlEmitter::root(filePath);\n> +       controlsDict_ = controlsEmitter_->dict();\n>  \n>         /*\n>          * Metadata needs to go into a separate file because otherwise it'll\n>          * flood the capture script\n>          */\n> -       dumpMetadata_ = new std::ofstream(std::string(file) + \".metadata\");\n> -       std::string str = \"frames:\\n\";\n> -       dumpMetadata_->write(str.c_str(), str.size());\n> -       dumpMetadata_->flush();\n> +       std::string metadataFilePath = filePath + \".metadata\";\n> +       metadataEmitter_ = YamlEmitter::root(metadataFilePath);\n> +       metadataDict_ = metadataEmitter_->dict();\n> +       metadataList_ = metadataDict_->list(\"frames\");\n>  }\n>  \n>  PipelineHandler::~PipelineHandler()\n>  {\n>         for (std::shared_ptr<MediaDevice> media : mediaDevices_)\n>                 media->release();\n> -\n> -       if (dumpCaptureScript_)\n> -               delete dumpCaptureScript_;\n> -\n> -       if (dumpMetadata_)\n> -               delete dumpMetadata_;\n>  }\n>  \n>  /**\n> @@ -788,65 +783,72 @@ void PipelineHandler::disconnect()\n>  void PipelineHandler::dumpConfiguration(const std::set<const Stream *> &streams,\n>                                         const Orientation &orientation)\n>  {\n> -       if (!dumpCaptureScript_)\n> +       if (!controlsEmitter_)\n>                 return;\n>  \n> -       std::stringstream ss;\n> -       ss << \"configuration:\" << std::endl;\n> -       ss << \"  orientation: \" << orientation << std::endl;\n> +       auto configurationDict = controlsDict_->dict(\"configuration\");\n> +\n> +       std::stringstream o;\n> +       o << orientation;\n> +       (*configurationDict)[\"orientation\"] = o.str();\n>  \n>         /* TODO Dump Sensor configuration */\n>  \n> -       ss << \"  streams:\" << std::endl;\n> +       auto streamsList = configurationDict->list(\"streams\");\n> +\n>         for (const auto &stream : streams) {\n>                 const StreamConfiguration &streamConfig = stream->configuration();\n> -               ss << \"    - pixelFormat: \" << streamConfig.pixelFormat << std::endl;\n> -               ss << \"      size: \" << streamConfig.size << std::endl;\n> -               ss << \"      stride: \" << streamConfig.stride << std::endl;\n> -               ss << \"      frameSize: \" << streamConfig.frameSize << std::endl;\n> -               ss << \"      bufferCount: \" << streamConfig.bufferCount << std::endl;\n> -               if (streamConfig.colorSpace)\n> -                       ss << \"      colorSpace: \" << streamConfig.colorSpace->toString() << std::endl;\n> -       }\n> +               auto yamlStream = streamsList->dict();\n>  \n> -       dumpCaptureScript_->write(ss.str().c_str(), ss.str().size());\n> +               (*yamlStream)[\"pixelformat\"] = streamConfig.pixelFormat.toString();\n> +               (*yamlStream)[\"size\"] = streamConfig.size.toString();\n> +               (*yamlStream)[\"stride\"] = std::to_string(streamConfig.stride);\n> +               (*yamlStream)[\"frameSize\"] = std::to_string(streamConfig.frameSize);\n> +               (*yamlStream)[\"bufferCount\"] = std::to_string(streamConfig.bufferCount);\n>  \n> -       std::string str = \"frames:\\n\";\n> -       dumpCaptureScript_->write(str.c_str(), str.size());\n> -       dumpCaptureScript_->flush();\n> +               if (streamConfig.colorSpace)\n> +                       (*yamlStream)[\"colorSpace\"] =\n> +                               streamConfig.colorSpace->toString();\n> +       }\n>  }\n>  \n>  void PipelineHandler::dumpRequest(Request *request, DumpMode mode)\n>  {\n> -       ControlList &controls =\n> -               mode == DumpMode::Controls ? request->controls()\n> -                                          : request->metadata();\n> -       std::ostream *output =\n> -               mode == DumpMode::Controls ? dumpCaptureScript_\n> -                                          : dumpMetadata_;\n> -\n> -       if (!output || controls.empty())\n> +       if (!controlsEmitter_)\n>                 return;\n>  \n> -       std::stringstream ss;\n> +       ControlList &controls = mode == DumpMode::Controls ? request->controls()\n> +                                                          : request->metadata();\n> +       if (controls.empty())\n> +               return;\n> +\n> +       std::unique_ptr<YamlDict> yamlFrame;\n> +       if (mode == DumpMode::Controls) {\n> +               if (!controlsEmitter_)\n> +                       return;\n> +\n> +               if (!controlsList_)\n> +                       controlsList_ = controlsDict_->list(\"frames\");\n> +\n> +               yamlFrame = controlsList_->dict();\n> +       } else {\n> +               if (!metadataEmitter_)\n> +                       return;\n> +\n> +               yamlFrame = metadataList_->dict();\n> +       }\n> +\n> +       auto yamlCtrls = yamlFrame->dict(std::to_string(request->sequence()));\n> +\n>         /* TODO Figure out PFC */\n> -       ss << \"  - \" << request->sequence() << \":\" << std::endl;\n>  \n>         const ControlIdMap *idMap = controls.idMap();\n>         for (const auto &pair : controls) {\n>                 const ControlId *ctrlId = idMap->at(pair.first);\n> +\n>                 /* TODO Prettify enums (probably by upgrading ControlValue::toString()) */\n> -               ss << \"      \" << ctrlId->name() << \": \" << pair.second.toString() << std::endl;\n> +               (*yamlCtrls)[ctrlId->name()] = pair.second.toString();\n>         }\n> -\n> -       /*\n> -        * TODO Investigate the overhead of flushing this frequently\n> -        * Controls aren't going to be queued too frequently so it should be\n> -        * fine to dump controls every frame. Metadata on the other hand needs\n> -        * to be investigated.\n> -        */\n> -       output->write(ss.str().c_str(), ss.str().size());\n> -       output->flush();\n>  }\n>  \n>  /**\n> -- \n> 2.47.0\n>","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 81F1FBD1F1\n\tfor <parsemail@patchwork.libcamera.org>;\n\tSat, 19 Oct 2024 22:35:11 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 67FAC6538D;\n\tSun, 20 Oct 2024 00:35:10 +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 1531065382\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tSun, 20 Oct 2024 00:35:09 +0200 (CEST)","from pendragon.ideasonboard.com\n\t(cpc89244-aztw30-2-0-cust6594.18-1.cable.virginm.net [86.31.185.195])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id EC8B2502;\n\tSun, 20 Oct 2024 00:33:23 +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=\"rUYi0sAy\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1729377204;\n\tbh=fMKud4Uh2EWaK60PSWuUG5xUkp+Z9lzarwKqZdfXdNU=;\n\th=In-Reply-To:References:Subject:From:Cc:To:Date:From;\n\tb=rUYi0sAy0G8EZN8CRARlmABU7xPcrKU31e3WIQL9xaVOJFyKbsXfsDbV8qjtBFXor\n\t7dR6AjlxQsc65C/eUGfZ5mN4KpEW0MATPoEaJrTsEE/rKqYVLkcXo4QZsca9IIolK8\n\tBXK+DaYG8uQ3H9PXArNPwXd87HUI38p8l2UnMyNg=","Content-Type":"text/plain; charset=\"utf-8\"","MIME-Version":"1.0","Content-Transfer-Encoding":"quoted-printable","In-Reply-To":"<20241017125220.60567-5-jacopo.mondi@ideasonboard.com>","References":"<20241017125220.60567-1-jacopo.mondi@ideasonboard.com>\n\t<20241017125220.60567-5-jacopo.mondi@ideasonboard.com>","Subject":"Re: [RFC v2 4/4] libcamera: pipeline_handler: Use YamlEmitter","From":"Kieran Bingham <kieran.bingham@ideasonboard.com>","Cc":"Jacopo Mondi <jacopo.mondi@ideasonboard.com>","To":"Jacopo Mondi <jacopo.mondi@ideasonboard.com>,\n\tlibcamera-devel@lists.libcamera.org","Date":"Sat, 19 Oct 2024 23:35:05 +0100","Message-ID":"<172937730579.2485972.15660754944359962829@ping.linuxembedded.co.uk>","User-Agent":"alot/0.10","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>"}},{"id":31846,"web_url":"https://patchwork.libcamera.org/comment/31846/","msgid":"<pse6cds65vrziophstajb2kclniokhdeop5hcocfy7z7wyam54@kmrgd2evdkef>","date":"2024-10-21T09:33:51","subject":"Re: [RFC v2 4/4] libcamera: pipeline_handler: Use YamlEmitter","submitter":{"id":143,"url":"https://patchwork.libcamera.org/api/people/143/","name":"Jacopo Mondi","email":"jacopo.mondi@ideasonboard.com"},"content":"Hi Kieran\n\nOn Sat, Oct 19, 2024 at 11:35:05PM +0100, Kieran Bingham wrote:\n> Quoting Jacopo Mondi (2024-10-17 13:52:19)\n> > Replace raw output usage with YamlEmitter.\n> >\n> > Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>\n> > ---\n> >  include/libcamera/internal/pipeline_handler.h |  11 +-\n> >  src/libcamera/pipeline_handler.cpp            | 102 +++++++++---------\n> >  2 files changed, 61 insertions(+), 52 deletions(-)\n> >\n> > diff --git a/include/libcamera/internal/pipeline_handler.h b/include/libcamera/internal/pipeline_handler.h\n> > index 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> >         const char *name_;\n> >         unsigned int useCount_;\n> >\n> > -       std::ostream *dumpCaptureScript_;\n> > -       std::ostream *dumpMetadata_;\n> > +       std::unique_ptr<YamlRoot> controlsEmitter_;\n> > +       std::unique_ptr<YamlDict> controlsDict_;\n> > +       std::unique_ptr<YamlList> controlsList_;\n> > +\n> > +       std::unique_ptr<YamlRoot> metadataEmitter_;\n> > +       std::unique_ptr<YamlDict> metadataDict_;\n> > +       std::unique_ptr<YamlList> metadataList_;\n>\n> Will 'all' users of a YamlEmitter instance need each of a root/dict/list\n> - or is this just specific to this usage?\n\nIt depends what you have to do.\n\nIf a root/dict/list has to be kept open for the whole duration of the\nlibrary, like in this case as it needs to dump frames/metadata for the\nwhole library lifetime, then yes, you have to keep them in scope.\n\nI suspect that a root node has anyway to be kept around in most cases,\nas deleting it terminates the yaml stream and closes the output file.\n\nDeleting an object (that has been initialized by something valid) emit\nthe yaml end sequences associated to the obejct type, so if you delete\nan instance of a dict/list earlier you wont be able to add stuff to\nit. If you delete a Root earlier the yaml stream is closed as well as\nthe output file.\n\n>\n> I don't think this series has taken on comments from Pauls' series,\n> where I saw a lot of duplication between different 'output streams'\n> which should be factored out.\n>\n\nSorry, not what this series is about. I think once we reach a decent\nstatus on YamlEmitter the frame/metadata dumping should be\nreimplemented on top. At least this was my understanding, but I would\nlike to know what's Paul preference as well..\n\n> I can't tell if they should be factored out to a 'YamlEmitter' class\n> each - or if ther eshould be some extra use-case specific class specific\n> to the metadata here ...\n\nAccording to Laurent's comment of not adding anything specific to\nlibcamera's types to the YamlEmitter interface for the moment being, I\ndon't think we will subclass it for specific use cases (to be honest I\ncan't think of what would be made metadata-specific in a derived class)\n\n>\n>\n>\n> >\n> >         friend class PipelineHandlerFactoryBase;\n> >  };\n> > diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp\n> > index 7002b4323bdd..533d0f8fc132 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> > -       : manager_(manager), useCount_(0),\n> > -         dumpCaptureScript_(nullptr), dumpMetadata_(nullptr)\n> > +       : manager_(manager), useCount_(0)\n> >  {\n> >         /* TODO Print notification that we're dumping capture script */\n> >         const char *file = utils::secure_getenv(\"LIBCAMERA_DUMP_CAPTURE_SCRIPT\");\n> >         if (!file)\n> >                 return;\n> >\n> > -       dumpCaptureScript_ = new std::ofstream(file);\n> > +       std::string filePath(file);\n> > +       controlsEmitter_ = YamlEmitter::root(filePath);\n> > +       controlsDict_ = controlsEmitter_->dict();\n> >\n> >         /*\n> >          * Metadata needs to go into a separate file because otherwise it'll\n> >          * flood the capture script\n> >          */\n> > -       dumpMetadata_ = new std::ofstream(std::string(file) + \".metadata\");\n> > -       std::string str = \"frames:\\n\";\n> > -       dumpMetadata_->write(str.c_str(), str.size());\n> > -       dumpMetadata_->flush();\n> > +       std::string metadataFilePath = filePath + \".metadata\";\n> > +       metadataEmitter_ = YamlEmitter::root(metadataFilePath);\n> > +       metadataDict_ = metadataEmitter_->dict();\n> > +       metadataList_ = metadataDict_->list(\"frames\");\n> >  }\n> >\n> >  PipelineHandler::~PipelineHandler()\n> >  {\n> >         for (std::shared_ptr<MediaDevice> media : mediaDevices_)\n> >                 media->release();\n> > -\n> > -       if (dumpCaptureScript_)\n> > -               delete dumpCaptureScript_;\n> > -\n> > -       if (dumpMetadata_)\n> > -               delete dumpMetadata_;\n> >  }\n> >\n> >  /**\n> > @@ -788,65 +783,72 @@ void PipelineHandler::disconnect()\n> >  void PipelineHandler::dumpConfiguration(const std::set<const Stream *> &streams,\n> >                                         const Orientation &orientation)\n> >  {\n> > -       if (!dumpCaptureScript_)\n> > +       if (!controlsEmitter_)\n> >                 return;\n> >\n> > -       std::stringstream ss;\n> > -       ss << \"configuration:\" << std::endl;\n> > -       ss << \"  orientation: \" << orientation << std::endl;\n> > +       auto configurationDict = controlsDict_->dict(\"configuration\");\n> > +\n> > +       std::stringstream o;\n> > +       o << orientation;\n> > +       (*configurationDict)[\"orientation\"] = o.str();\n> >\n> >         /* TODO Dump Sensor configuration */\n> >\n> > -       ss << \"  streams:\" << std::endl;\n> > +       auto streamsList = configurationDict->list(\"streams\");\n> > +\n> >         for (const auto &stream : streams) {\n> >                 const StreamConfiguration &streamConfig = stream->configuration();\n> > -               ss << \"    - pixelFormat: \" << streamConfig.pixelFormat << std::endl;\n> > -               ss << \"      size: \" << streamConfig.size << std::endl;\n> > -               ss << \"      stride: \" << streamConfig.stride << std::endl;\n> > -               ss << \"      frameSize: \" << streamConfig.frameSize << std::endl;\n> > -               ss << \"      bufferCount: \" << streamConfig.bufferCount << std::endl;\n> > -               if (streamConfig.colorSpace)\n> > -                       ss << \"      colorSpace: \" << streamConfig.colorSpace->toString() << std::endl;\n> > -       }\n> > +               auto yamlStream = streamsList->dict();\n> >\n> > -       dumpCaptureScript_->write(ss.str().c_str(), ss.str().size());\n> > +               (*yamlStream)[\"pixelformat\"] = streamConfig.pixelFormat.toString();\n> > +               (*yamlStream)[\"size\"] = streamConfig.size.toString();\n> > +               (*yamlStream)[\"stride\"] = std::to_string(streamConfig.stride);\n> > +               (*yamlStream)[\"frameSize\"] = std::to_string(streamConfig.frameSize);\n> > +               (*yamlStream)[\"bufferCount\"] = std::to_string(streamConfig.bufferCount);\n> >\n> > -       std::string str = \"frames:\\n\";\n> > -       dumpCaptureScript_->write(str.c_str(), str.size());\n> > -       dumpCaptureScript_->flush();\n> > +               if (streamConfig.colorSpace)\n> > +                       (*yamlStream)[\"colorSpace\"] =\n> > +                               streamConfig.colorSpace->toString();\n> > +       }\n> >  }\n> >\n> >  void PipelineHandler::dumpRequest(Request *request, DumpMode mode)\n> >  {\n> > -       ControlList &controls =\n> > -               mode == DumpMode::Controls ? request->controls()\n> > -                                          : request->metadata();\n> > -       std::ostream *output =\n> > -               mode == DumpMode::Controls ? dumpCaptureScript_\n> > -                                          : dumpMetadata_;\n> > -\n> > -       if (!output || controls.empty())\n> > +       if (!controlsEmitter_)\n> >                 return;\n> >\n> > -       std::stringstream ss;\n> > +       ControlList &controls = mode == DumpMode::Controls ? request->controls()\n> > +                                                          : request->metadata();\n> > +       if (controls.empty())\n> > +               return;\n> > +\n> > +       std::unique_ptr<YamlDict> yamlFrame;\n> > +       if (mode == DumpMode::Controls) {\n> > +               if (!controlsEmitter_)\n> > +                       return;\n> > +\n> > +               if (!controlsList_)\n> > +                       controlsList_ = controlsDict_->list(\"frames\");\n> > +\n> > +               yamlFrame = controlsList_->dict();\n> > +       } else {\n> > +               if (!metadataEmitter_)\n> > +                       return;\n> > +\n> > +               yamlFrame = metadataList_->dict();\n> > +       }\n> > +\n> > +       auto yamlCtrls = yamlFrame->dict(std::to_string(request->sequence()));\n> > +\n> >         /* TODO Figure out PFC */\n> > -       ss << \"  - \" << request->sequence() << \":\" << std::endl;\n> >\n> >         const ControlIdMap *idMap = controls.idMap();\n> >         for (const auto &pair : controls) {\n> >                 const ControlId *ctrlId = idMap->at(pair.first);\n> > +\n> >                 /* TODO Prettify enums (probably by upgrading ControlValue::toString()) */\n> > -               ss << \"      \" << ctrlId->name() << \": \" << pair.second.toString() << std::endl;\n> > +               (*yamlCtrls)[ctrlId->name()] = pair.second.toString();\n> >         }\n> > -\n> > -       /*\n> > -        * TODO Investigate the overhead of flushing this frequently\n> > -        * Controls aren't going to be queued too frequently so it should be\n> > -        * fine to dump controls every frame. Metadata on the other hand needs\n> > -        * to be investigated.\n> > -        */\n> > -       output->write(ss.str().c_str(), ss.str().size());\n> > -       output->flush();\n> >  }\n> >\n> >  /**\n> > --\n> > 2.47.0\n> >","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 55054C32A3\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon, 21 Oct 2024 09:33:58 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 4A43E65391;\n\tMon, 21 Oct 2024 11:33:57 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id B82846537E\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 21 Oct 2024 11:33:55 +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 B68F6526;\n\tMon, 21 Oct 2024 11:32:09 +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=\"truGChdj\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1729503129;\n\tbh=ajIKxz4wuFgV0RPmnLnK1Dn/RO+9JczY9gKskrHlwK4=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=truGChdjEwpjjlXwoSPn5WRFj7G3rPJW9rJ2+cMY0vXBZC6wKRcZEnSwoDNij+j3e\n\tlx9LE3OEwwVfdpMC4aRBX8J1F9aYWk7qdiZrd+Dlk/l9lcY3sjQxTKMDolCI/kGt2D\n\tVGAaDaFmTsQC/TXD4ENaUZVuguRKgy4/QzKv5PLg=","Date":"Mon, 21 Oct 2024 11:33:51 +0200","From":"Jacopo Mondi <jacopo.mondi@ideasonboard.com>","To":"Kieran Bingham <kieran.bingham@ideasonboard.com>","Cc":"Jacopo Mondi <jacopo.mondi@ideasonboard.com>, \n\tlibcamera-devel@lists.libcamera.org","Subject":"Re: [RFC v2 4/4] libcamera: pipeline_handler: Use YamlEmitter","Message-ID":"<pse6cds65vrziophstajb2kclniokhdeop5hcocfy7z7wyam54@kmrgd2evdkef>","References":"<20241017125220.60567-1-jacopo.mondi@ideasonboard.com>\n\t<20241017125220.60567-5-jacopo.mondi@ideasonboard.com>\n\t<172937730579.2485972.15660754944359962829@ping.linuxembedded.co.uk>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<172937730579.2485972.15660754944359962829@ping.linuxembedded.co.uk>","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>"}}]