[{"id":25447,"web_url":"https://patchwork.libcamera.org/comment/25447/","msgid":"<Y05qkb04DhcD3ccl@pendragon.ideasonboard.com>","date":"2022-10-18T08:57:53","subject":"Re: [libcamera-devel] [PATCH v2 2/3] cam: file_sink: Add support\n\tfor DNG output","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi Paul,\n\nThank you for the patch.\n\nOn Tue, Oct 18, 2022 at 05:09:07PM +0900, Paul Elder via libcamera-devel wrote:\n> Add support for outputting buffers in DNG format. It reuses the DNG\n> writer that we had previously in qcam.\n> \n> Signed-off-by: Paul Elder <paul.elder@ideasonboard.com>\n> \n> ---\n> Changes in v2:\n> - update help test to mention the dng output feature\n> - pass camera as first argument to FileSink constructor\n> ---\n>  src/cam/camera_session.cpp |  4 ++--\n>  src/cam/file_sink.cpp      | 32 ++++++++++++++++++++++++++------\n>  src/cam/file_sink.h        |  7 +++++--\n>  src/cam/main.cpp           |  2 ++\n>  src/cam/meson.build        |  8 ++++++++\n>  5 files changed, 43 insertions(+), 10 deletions(-)\n> \n> diff --git a/src/cam/camera_session.cpp b/src/cam/camera_session.cpp\n> index 238186a3..6b409c98 100644\n> --- a/src/cam/camera_session.cpp\n> +++ b/src/cam/camera_session.cpp\n> @@ -207,10 +207,10 @@ int CameraSession::start()\n>  \n>  \tif (options_.isSet(OptFile)) {\n>  \t\tif (!options_[OptFile].toString().empty())\n> -\t\t\tsink_ = std::make_unique<FileSink>(streamNames_,\n> +\t\t\tsink_ = std::make_unique<FileSink>(camera_.get(), streamNames_,\n>  \t\t\t\t\t\t\t   options_[OptFile]);\n>  \t\telse\n> -\t\t\tsink_ = std::make_unique<FileSink>(streamNames_);\n> +\t\t\tsink_ = std::make_unique<FileSink>(camera_.get(), streamNames_);\n>  \t}\n>  \n>  \tif (sink_) {\n> diff --git a/src/cam/file_sink.cpp b/src/cam/file_sink.cpp\n> index 45213d4a..8bba4e7f 100644\n> --- a/src/cam/file_sink.cpp\n> +++ b/src/cam/file_sink.cpp\n> @@ -15,14 +15,16 @@\n>  \n>  #include <libcamera/camera.h>\n>  \n> +#include \"dng_writer.h\"\n>  #include \"file_sink.h\"\n>  #include \"image.h\"\n>  \n>  using namespace libcamera;\n>  \n> -FileSink::FileSink(const std::map<const libcamera::Stream *, std::string> &streamNames,\n> +FileSink::FileSink(const libcamera::Camera *camera,\n> +\t\t   const std::map<const libcamera::Stream *, std::string> &streamNames,\n>  \t\t   const std::string &pattern)\n> -\t: streamNames_(streamNames), pattern_(pattern)\n> +\t: camera_(camera), streamNames_(streamNames), pattern_(pattern)\n>  {\n>  }\n>  \n> @@ -51,12 +53,13 @@ void FileSink::mapBuffer(FrameBuffer *buffer)\n>  bool FileSink::processRequest(Request *request)\n>  {\n>  \tfor (auto [stream, buffer] : request->buffers())\n> -\t\twriteBuffer(stream, buffer);\n> +\t\twriteBuffer(stream, buffer, request->metadata());\n>  \n>  \treturn true;\n>  }\n>  \n> -void FileSink::writeBuffer(const Stream *stream, FrameBuffer *buffer)\n> +void FileSink::writeBuffer(const Stream *stream, FrameBuffer *buffer,\n> +\t\t\t   [[maybe_unused]] const ControlList &metadata)\n>  {\n>  \tstd::string filename;\n>  \tsize_t pos;\n> @@ -65,6 +68,10 @@ void FileSink::writeBuffer(const Stream *stream, FrameBuffer *buffer)\n>  \tif (!pattern_.empty())\n>  \t\tfilename = pattern_;\n>  \n> +#ifdef HAVE_TIFF\n> +\tbool dng = filename.find(\".dng\", filename.size() - 4) != std::string::npos;\n> +#endif /* HAVE_TIFF */\n> +\n>  \tif (filename.empty() || filename.back() == '/')\n>  \t\tfilename += \"frame-#.bin\";\n>  \n> @@ -76,6 +83,21 @@ void FileSink::writeBuffer(const Stream *stream, FrameBuffer *buffer)\n>  \t\tfilename.replace(pos, 1, ss.str());\n>  \t}\n>  \n> +\tImage *image = mappedBuffers_[buffer].get();\n> +\n> +#ifdef HAVE_TIFF\n> +\tif (dng) {\n> +\t\tret = DNGWriter::write(filename.c_str(), camera_,\n> +\t\t\t\t       stream->configuration(), metadata,\n> +\t\t\t\t       buffer, image->data(0).data());\n> +\t\tif (ret < 0)\n> +\t\t\tstd::cerr << \"failed to write DNG \" << filename\n> +\t\t\t\t  << std::endl;\n\nIt's nice to quote file names to avoid ambiguities:\n\n\t\t\tstd::cerr << \"failed to write DNG file `\" << filename\n\t\t\t\t  << \"'\" << std::endl;\n\nReviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n\n> +\n> +\t\treturn;\n> +\t}\n> +#endif /* HAVE_TIFF */\n> +\n>  \tfd = open(filename.c_str(), O_CREAT | O_WRONLY |\n>  \t\t  (pos == std::string::npos ? O_APPEND : O_TRUNC),\n>  \t\t  S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);\n> @@ -86,8 +108,6 @@ void FileSink::writeBuffer(const Stream *stream, FrameBuffer *buffer)\n>  \t\treturn;\n>  \t}\n>  \n> -\tImage *image = mappedBuffers_[buffer].get();\n> -\n>  \tfor (unsigned int i = 0; i < buffer->planes().size(); ++i) {\n>  \t\tconst FrameMetadata::Plane &meta = buffer->metadata().planes()[i];\n>  \n> diff --git a/src/cam/file_sink.h b/src/cam/file_sink.h\n> index 067736f5..9ce8b619 100644\n> --- a/src/cam/file_sink.h\n> +++ b/src/cam/file_sink.h\n> @@ -20,7 +20,8 @@ class Image;\n>  class FileSink : public FrameSink\n>  {\n>  public:\n> -\tFileSink(const std::map<const libcamera::Stream *, std::string> &streamNames,\n> +\tFileSink(const libcamera::Camera *camera,\n> +\t\t const std::map<const libcamera::Stream *, std::string> &streamNames,\n>  \t\t const std::string &pattern = \"\");\n>  \t~FileSink();\n>  \n> @@ -32,8 +33,10 @@ public:\n>  \n>  private:\n>  \tvoid writeBuffer(const libcamera::Stream *stream,\n> -\t\t\t libcamera::FrameBuffer *buffer);\n> +\t\t\t libcamera::FrameBuffer *buffer,\n> +\t\t\t const libcamera::ControlList &metadata);\n>  \n> +\tconst libcamera::Camera *camera_;\n>  \tstd::map<const libcamera::Stream *, std::string> streamNames_;\n>  \tstd::string pattern_;\n>  \tstd::map<libcamera::FrameBuffer *, std::unique_ptr<Image>> mappedBuffers_;\n> diff --git a/src/cam/main.cpp b/src/cam/main.cpp\n> index 53c2ffde..c4e18a13 100644\n> --- a/src/cam/main.cpp\n> +++ b/src/cam/main.cpp\n> @@ -144,6 +144,8 @@ int CamApp::parseOptions(int argc, char *argv[])\n>  \t\t\t \"to write files, using the default file name. Otherwise it sets the\\n\"\n>  \t\t\t \"full file path and name. The first '#' character in the file name\\n\"\n>  \t\t\t \"is expanded to the camera index, stream name and frame sequence number.\\n\"\n> +\t\t\t \"If the file name ends with '.dng', then the frame will be written to\\n\"\n> +\t\t\t \"the output file(s) in DNG format.\\n\"\n>  \t\t\t \"The default file name is 'frame-#.bin'.\",\n>  \t\t\t \"file\", ArgumentOptional, \"filename\", false,\n>  \t\t\t OptCamera);\n> diff --git a/src/cam/meson.build b/src/cam/meson.build\n> index 9c766221..06dbea06 100644\n> --- a/src/cam/meson.build\n> +++ b/src/cam/meson.build\n> @@ -52,6 +52,13 @@ if libsdl2.found()\n>      endif\n>  endif\n>  \n> +if libtiff.found()\n> +    cam_cpp_args += ['-DHAVE_TIFF']\n> +    cam_sources += files([\n> +        'dng_writer.cpp',\n> +    ])\n> +endif\n> +\n>  cam  = executable('cam', cam_sources,\n>                    dependencies : [\n>                        libatomic,\n> @@ -60,6 +67,7 @@ cam  = executable('cam', cam_sources,\n>                        libevent,\n>                        libjpeg,\n>                        libsdl2,\n> +                      libtiff,\n>                        libyaml,\n>                    ],\n>                    cpp_args : cam_cpp_args,","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 057E8C0DA4\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue, 18 Oct 2022 08:58:21 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 3C29F62E15;\n\tTue, 18 Oct 2022 10:58:20 +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 2DA5962DD1\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 18 Oct 2022 10:58:19 +0200 (CEST)","from pendragon.ideasonboard.com (62-78-145-57.bb.dnainternet.fi\n\t[62.78.145.57])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 2677E32A;\n\tTue, 18 Oct 2022 10:58:17 +0200 (CEST)"],"DKIM-Signature":["v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1666083500;\n\tbh=ICCu8/58h61p/WN5/8UBNO+Rcju9OXTsFh+XqtgcM6Y=;\n\th=Date:To:References:In-Reply-To:Subject:List-Id:List-Unsubscribe:\n\tList-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc:\n\tFrom;\n\tb=zQET16FCwNm4tD8P1nU8T8KBnP1/WzZw//ZebtPPNNfLyUgZ/kxID6O3BhvkIwFPf\n\t9OPhOOe5MoG69hT8rm6UAlaTC97M41L+MtrBte73eVsve5tyN+gmKuARV8xOxKHk3x\n\tRMJjyq21eIKrNSpjXuA/BmQusNT4m9BvITKcErWOu0YXAlPgYJ73lt6q4qCzPJ9rrc\n\tZZsjqVZoUJ2dydCVwRSTaRIyUGFyLztE0uujepmvJVWQQLXgS8k064AeENSHU6HBze\n\tMCfU5sH89LdYyn5t7802dCXa0kZ8zlZ7krg6dAYFvSjKquZpOh4FMfRGliQZGoFYqo\n\thhUWDEtj3748A==","v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1666083498;\n\tbh=ICCu8/58h61p/WN5/8UBNO+Rcju9OXTsFh+XqtgcM6Y=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=NcG4mUgaczKczGNWCj6cDW8RIRA8ce2gA7AupGVuQ/zMBw8jbESO73PQDQ3BD7UGi\n\tGlY9Q3lv7IAN6JcvCCYzt6Ko52EO3x9RAWK0/wXwuZu1PH+8uv8XZ7E8DlZAhXzTHS\n\tS8RtBN5b7sSppGfPB/YmukUFap+qwGd8WobQSXPQ="],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key; \n\tunprotected) header.d=ideasonboard.com\n\theader.i=@ideasonboard.com\n\theader.b=\"NcG4mUga\"; dkim-atps=neutral","Date":"Tue, 18 Oct 2022 11:57:53 +0300","To":"Paul Elder <paul.elder@ideasonboard.com>","Message-ID":"<Y05qkb04DhcD3ccl@pendragon.ideasonboard.com>","References":"<20221018080908.2841339-1-paul.elder@ideasonboard.com>\n\t<20221018080908.2841339-3-paul.elder@ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<20221018080908.2841339-3-paul.elder@ideasonboard.com>","Subject":"Re: [libcamera-devel] [PATCH v2 2/3] cam: file_sink: Add support\n\tfor DNG output","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":"Laurent Pinchart via libcamera-devel\n\t<libcamera-devel@lists.libcamera.org>","Reply-To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":25452,"web_url":"https://patchwork.libcamera.org/comment/25452/","msgid":"<20221019083432.47ocg3gnuc3fkbzn@uno.localdomain>","date":"2022-10-19T08:34:32","subject":"Re: [libcamera-devel] [PATCH v2 2/3] cam: file_sink: Add support\n\tfor DNG output","submitter":{"id":3,"url":"https://patchwork.libcamera.org/api/people/3/","name":"Jacopo Mondi","email":"jacopo@jmondi.org"},"content":"Hi Paul\n\nOn Tue, Oct 18, 2022 at 05:09:07PM +0900, Paul Elder via libcamera-devel wrote:\n> Add support for outputting buffers in DNG format. It reuses the DNG\n> writer that we had previously in qcam.\n>\n> Signed-off-by: Paul Elder <paul.elder@ideasonboard.com>\n>\n> ---\n> Changes in v2:\n> - update help test to mention the dng output feature\n> - pass camera as first argument to FileSink constructor\n> ---\n>  src/cam/camera_session.cpp |  4 ++--\n>  src/cam/file_sink.cpp      | 32 ++++++++++++++++++++++++++------\n>  src/cam/file_sink.h        |  7 +++++--\n>  src/cam/main.cpp           |  2 ++\n>  src/cam/meson.build        |  8 ++++++++\n>  5 files changed, 43 insertions(+), 10 deletions(-)\n>\n> diff --git a/src/cam/camera_session.cpp b/src/cam/camera_session.cpp\n> index 238186a3..6b409c98 100644\n> --- a/src/cam/camera_session.cpp\n> +++ b/src/cam/camera_session.cpp\n> @@ -207,10 +207,10 @@ int CameraSession::start()\n>\n>  \tif (options_.isSet(OptFile)) {\n>  \t\tif (!options_[OptFile].toString().empty())\n> -\t\t\tsink_ = std::make_unique<FileSink>(streamNames_,\n> +\t\t\tsink_ = std::make_unique<FileSink>(camera_.get(), streamNames_,\n>  \t\t\t\t\t\t\t   options_[OptFile]);\n>  \t\telse\n> -\t\t\tsink_ = std::make_unique<FileSink>(streamNames_);\n> +\t\t\tsink_ = std::make_unique<FileSink>(camera_.get(), streamNames_);\n>  \t}\n>\n>  \tif (sink_) {\n> diff --git a/src/cam/file_sink.cpp b/src/cam/file_sink.cpp\n> index 45213d4a..8bba4e7f 100644\n> --- a/src/cam/file_sink.cpp\n> +++ b/src/cam/file_sink.cpp\n> @@ -15,14 +15,16 @@\n>\n>  #include <libcamera/camera.h>\n>\n> +#include \"dng_writer.h\"\n>  #include \"file_sink.h\"\n>  #include \"image.h\"\n>\n>  using namespace libcamera;\n>\n> -FileSink::FileSink(const std::map<const libcamera::Stream *, std::string> &streamNames,\n> +FileSink::FileSink(const libcamera::Camera *camera,\n> +\t\t   const std::map<const libcamera::Stream *, std::string> &streamNames,\n>  \t\t   const std::string &pattern)\n> -\t: streamNames_(streamNames), pattern_(pattern)\n> +\t: camera_(camera), streamNames_(streamNames), pattern_(pattern)\n>  {\n>  }\n>\n> @@ -51,12 +53,13 @@ void FileSink::mapBuffer(FrameBuffer *buffer)\n>  bool FileSink::processRequest(Request *request)\n>  {\n>  \tfor (auto [stream, buffer] : request->buffers())\n> -\t\twriteBuffer(stream, buffer);\n> +\t\twriteBuffer(stream, buffer, request->metadata());\n>\n>  \treturn true;\n>  }\n>\n> -void FileSink::writeBuffer(const Stream *stream, FrameBuffer *buffer)\n> +void FileSink::writeBuffer(const Stream *stream, FrameBuffer *buffer,\n> +\t\t\t   [[maybe_unused]] const ControlList &metadata)\n>  {\n>  \tstd::string filename;\n\n        bool dng = false;\n\n>  \tsize_t pos;\n> @@ -65,6 +68,10 @@ void FileSink::writeBuffer(const Stream *stream, FrameBuffer *buffer)\n>  \tif (!pattern_.empty())\n>  \t\tfilename = pattern_;\n>\n> +#ifdef HAVE_TIFF\n> +\tbool dng = filename.find(\".dng\", filename.size() - 4) != std::string::npos;\n\n\tdng = filename.find(\".dng\", filename.size() - 4) != std::string::npos;\n\n> +#endif /* HAVE_TIFF */\n> +\n>  \tif (filename.empty() || filename.back() == '/')\n>  \t\tfilename += \"frame-#.bin\";\n>\n> @@ -76,6 +83,21 @@ void FileSink::writeBuffer(const Stream *stream, FrameBuffer *buffer)\n>  \t\tfilename.replace(pos, 1, ss.str());\n>  \t}\n>\n> +\tImage *image = mappedBuffers_[buffer].get();\n> +\n> +#ifdef HAVE_TIFF\n\nAnd you can here remove  the #ifdef and the [[maybe_unused]] attribute from the\nmetadata argument\n\n> +\tif (dng) {\n> +\t\tret = DNGWriter::write(filename.c_str(), camera_,\n> +\t\t\t\t       stream->configuration(), metadata,\n> +\t\t\t\t       buffer, image->data(0).data());\n> +\t\tif (ret < 0)\n> +\t\t\tstd::cerr << \"failed to write DNG \" << filename\n> +\t\t\t\t  << std::endl;\n> +\n> +\t\treturn;\n> +\t}\n> +#endif /* HAVE_TIFF */\n> +\n>  \tfd = open(filename.c_str(), O_CREAT | O_WRONLY |\n>  \t\t  (pos == std::string::npos ? O_APPEND : O_TRUNC),\n>  \t\t  S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);\n> @@ -86,8 +108,6 @@ void FileSink::writeBuffer(const Stream *stream, FrameBuffer *buffer)\n>  \t\treturn;\n>  \t}\n>\n> -\tImage *image = mappedBuffers_[buffer].get();\n> -\n>  \tfor (unsigned int i = 0; i < buffer->planes().size(); ++i) {\n>  \t\tconst FrameMetadata::Plane &meta = buffer->metadata().planes()[i];\n>\n> diff --git a/src/cam/file_sink.h b/src/cam/file_sink.h\n> index 067736f5..9ce8b619 100644\n> --- a/src/cam/file_sink.h\n> +++ b/src/cam/file_sink.h\n> @@ -20,7 +20,8 @@ class Image;\n>  class FileSink : public FrameSink\n>  {\n>  public:\n> -\tFileSink(const std::map<const libcamera::Stream *, std::string> &streamNames,\n> +\tFileSink(const libcamera::Camera *camera,\n> +\t\t const std::map<const libcamera::Stream *, std::string> &streamNames,\n>  \t\t const std::string &pattern = \"\");\n>  \t~FileSink();\n>\n> @@ -32,8 +33,10 @@ public:\n>\n>  private:\n>  \tvoid writeBuffer(const libcamera::Stream *stream,\n\nIf only we could get the Camera * back from the request, you could\navoid storing camera_ as class member as you could do\n\n        bool FileSink::processRequest(Request *request)\n        {\n                for (auto [stream, buffer] : request->buffers())\n                        writeBuffer(request->camera(), stream, buffer, request->metadata());\n\n                return true;\n        }\n\nI recall we discussed that in the past and if it's not there there\nmight be reasons (likely the fact that a Request can outlive the\nCamera it has been created ?)\n\n\n> -\t\t\t libcamera::FrameBuffer *buffer);\n> +\t\t\t libcamera::FrameBuffer *buffer,\n> +\t\t\t const libcamera::ControlList &metadata);\n>\n> +\tconst libcamera::Camera *camera_;\n>  \tstd::map<const libcamera::Stream *, std::string> streamNames_;\n>  \tstd::string pattern_;\n>  \tstd::map<libcamera::FrameBuffer *, std::unique_ptr<Image>> mappedBuffers_;\n> diff --git a/src/cam/main.cpp b/src/cam/main.cpp\n> index 53c2ffde..c4e18a13 100644\n> --- a/src/cam/main.cpp\n> +++ b/src/cam/main.cpp\n> @@ -144,6 +144,8 @@ int CamApp::parseOptions(int argc, char *argv[])\n>  \t\t\t \"to write files, using the default file name. Otherwise it sets the\\n\"\n>  \t\t\t \"full file path and name. The first '#' character in the file name\\n\"\n>  \t\t\t \"is expanded to the camera index, stream name and frame sequence number.\\n\"\n> +\t\t\t \"If the file name ends with '.dng', then the frame will be written to\\n\"\n> +\t\t\t \"the output file(s) in DNG format.\\n\"\n>  \t\t\t \"The default file name is 'frame-#.bin'.\",\n>  \t\t\t \"file\", ArgumentOptional, \"filename\", false,\n>  \t\t\t OptCamera);\n> diff --git a/src/cam/meson.build b/src/cam/meson.build\n> index 9c766221..06dbea06 100644\n> --- a/src/cam/meson.build\n> +++ b/src/cam/meson.build\n> @@ -52,6 +52,13 @@ if libsdl2.found()\n>      endif\n>  endif\n>\n> +if libtiff.found()\n> +    cam_cpp_args += ['-DHAVE_TIFF']\n> +    cam_sources += files([\n> +        'dng_writer.cpp',\n> +    ])\n> +endif\n> +\n>  cam  = executable('cam', cam_sources,\n>                    dependencies : [\n>                        libatomic,\n> @@ -60,6 +67,7 @@ cam  = executable('cam', cam_sources,\n>                        libevent,\n>                        libjpeg,\n>                        libsdl2,\n> +                      libtiff,\n>                        libyaml,\n>                    ],\n>                    cpp_args : cam_cpp_args,\n> --\n> 2.30.2\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 5546ABD16B\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed, 19 Oct 2022 08:34:42 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 7D53262E37;\n\tWed, 19 Oct 2022 10:34:37 +0200 (CEST)","from relay2-d.mail.gandi.net (relay2-d.mail.gandi.net\n\t[IPv6:2001:4b98:dc4:8::222])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 42B8D62DD7\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 19 Oct 2022 10:34:36 +0200 (CEST)","(Authenticated sender: jacopo@jmondi.org)\n\tby mail.gandi.net (Postfix) with ESMTPSA id 4E08540009;\n\tWed, 19 Oct 2022 08:34:35 +0000 (UTC)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1666168477;\n\tbh=aGtTS6oiC3TSERWGvwi/Y7Zbm3atIG5E4hhhHR6a3UU=;\n\th=Date:To:References:In-Reply-To:Subject:List-Id:List-Unsubscribe:\n\tList-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc:\n\tFrom;\n\tb=YSnbe6BJr2CHxqo+c//MCPKgc7L0L6kelq6n1HdrUIugnCkJKP9jCWmuxuzJMTkd4\n\tPsPBQki8xOXx/lhOFwteoTctc01dCMcAbI+OMdzQSjvdE289qSW0FXHaqrqQBGePhY\n\t8fkzqGcFnnNzKZcxBIMhgG4anzKf2Ae8Hy+qPxoyPgoVWruLA7HI5ckx73Eqygs9cl\n\t/kq+Z3wixJ7qlLYhn0Yu+LYOoZ+jWNlpFJgRHcAR3riBfsVujvqB1QKxI2cZ6FI29C\n\tdFvYFv6Dd7Tp0eIABDCufvAzWqFpoZ6MO6666/J6WVXnsosSorPHOujVxFYQYNQoxT\n\t7Ff87E46vMHkA==","Date":"Wed, 19 Oct 2022 10:34:32 +0200","To":"Paul Elder <paul.elder@ideasonboard.com>","Message-ID":"<20221019083432.47ocg3gnuc3fkbzn@uno.localdomain>","References":"<20221018080908.2841339-1-paul.elder@ideasonboard.com>\n\t<20221018080908.2841339-3-paul.elder@ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<20221018080908.2841339-3-paul.elder@ideasonboard.com>","Subject":"Re: [libcamera-devel] [PATCH v2 2/3] cam: file_sink: Add support\n\tfor DNG output","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>","Cc":"libcamera-devel@lists.libcamera.org","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":25460,"web_url":"https://patchwork.libcamera.org/comment/25460/","msgid":"<Y0/F8rzFo9qTgIug@pendragon.ideasonboard.com>","date":"2022-10-19T09:40:02","subject":"Re: [libcamera-devel] [PATCH v2 2/3] cam: file_sink: Add support\n\tfor DNG output","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"On Wed, Oct 19, 2022 at 10:34:32AM +0200, Jacopo Mondi via libcamera-devel wrote:\n> On Tue, Oct 18, 2022 at 05:09:07PM +0900, Paul Elder via libcamera-devel wrote:\n> > Add support for outputting buffers in DNG format. It reuses the DNG\n> > writer that we had previously in qcam.\n> >\n> > Signed-off-by: Paul Elder <paul.elder@ideasonboard.com>\n> >\n> > ---\n> > Changes in v2:\n> > - update help test to mention the dng output feature\n> > - pass camera as first argument to FileSink constructor\n> > ---\n> >  src/cam/camera_session.cpp |  4 ++--\n> >  src/cam/file_sink.cpp      | 32 ++++++++++++++++++++++++++------\n> >  src/cam/file_sink.h        |  7 +++++--\n> >  src/cam/main.cpp           |  2 ++\n> >  src/cam/meson.build        |  8 ++++++++\n> >  5 files changed, 43 insertions(+), 10 deletions(-)\n> >\n> > diff --git a/src/cam/camera_session.cpp b/src/cam/camera_session.cpp\n> > index 238186a3..6b409c98 100644\n> > --- a/src/cam/camera_session.cpp\n> > +++ b/src/cam/camera_session.cpp\n> > @@ -207,10 +207,10 @@ int CameraSession::start()\n> >\n> >  \tif (options_.isSet(OptFile)) {\n> >  \t\tif (!options_[OptFile].toString().empty())\n> > -\t\t\tsink_ = std::make_unique<FileSink>(streamNames_,\n> > +\t\t\tsink_ = std::make_unique<FileSink>(camera_.get(), streamNames_,\n> >  \t\t\t\t\t\t\t   options_[OptFile]);\n> >  \t\telse\n> > -\t\t\tsink_ = std::make_unique<FileSink>(streamNames_);\n> > +\t\t\tsink_ = std::make_unique<FileSink>(camera_.get(), streamNames_);\n> >  \t}\n> >\n> >  \tif (sink_) {\n> > diff --git a/src/cam/file_sink.cpp b/src/cam/file_sink.cpp\n> > index 45213d4a..8bba4e7f 100644\n> > --- a/src/cam/file_sink.cpp\n> > +++ b/src/cam/file_sink.cpp\n> > @@ -15,14 +15,16 @@\n> >\n> >  #include <libcamera/camera.h>\n> >\n> > +#include \"dng_writer.h\"\n> >  #include \"file_sink.h\"\n> >  #include \"image.h\"\n> >\n> >  using namespace libcamera;\n> >\n> > -FileSink::FileSink(const std::map<const libcamera::Stream *, std::string> &streamNames,\n> > +FileSink::FileSink(const libcamera::Camera *camera,\n> > +\t\t   const std::map<const libcamera::Stream *, std::string> &streamNames,\n> >  \t\t   const std::string &pattern)\n> > -\t: streamNames_(streamNames), pattern_(pattern)\n> > +\t: camera_(camera), streamNames_(streamNames), pattern_(pattern)\n> >  {\n> >  }\n> >\n> > @@ -51,12 +53,13 @@ void FileSink::mapBuffer(FrameBuffer *buffer)\n> >  bool FileSink::processRequest(Request *request)\n> >  {\n> >  \tfor (auto [stream, buffer] : request->buffers())\n> > -\t\twriteBuffer(stream, buffer);\n> > +\t\twriteBuffer(stream, buffer, request->metadata());\n> >\n> >  \treturn true;\n> >  }\n> >\n> > -void FileSink::writeBuffer(const Stream *stream, FrameBuffer *buffer)\n> > +void FileSink::writeBuffer(const Stream *stream, FrameBuffer *buffer,\n> > +\t\t\t   [[maybe_unused]] const ControlList &metadata)\n> >  {\n> >  \tstd::string filename;\n> \n>         bool dng = false;\n> \n> >  \tsize_t pos;\n> > @@ -65,6 +68,10 @@ void FileSink::writeBuffer(const Stream *stream, FrameBuffer *buffer)\n> >  \tif (!pattern_.empty())\n> >  \t\tfilename = pattern_;\n> >\n> > +#ifdef HAVE_TIFF\n> > +\tbool dng = filename.find(\".dng\", filename.size() - 4) != std::string::npos;\n> \n> \tdng = filename.find(\".dng\", filename.size() - 4) != std::string::npos;\n> \n> > +#endif /* HAVE_TIFF */\n> > +\n> >  \tif (filename.empty() || filename.back() == '/')\n> >  \t\tfilename += \"frame-#.bin\";\n> >\n> > @@ -76,6 +83,21 @@ void FileSink::writeBuffer(const Stream *stream, FrameBuffer *buffer)\n> >  \t\tfilename.replace(pos, 1, ss.str());\n> >  \t}\n> >\n> > +\tImage *image = mappedBuffers_[buffer].get();\n> > +\n> > +#ifdef HAVE_TIFF\n> \n> And you can here remove  the #ifdef and the [[maybe_unused]] attribute from the\n> metadata argument\n\nWhen !HAVE_TIFF, the DNGWriter class isn't declared by dng_writer.h. The\ncode below would thus not compile.\n\n> > +\tif (dng) {\n> > +\t\tret = DNGWriter::write(filename.c_str(), camera_,\n> > +\t\t\t\t       stream->configuration(), metadata,\n> > +\t\t\t\t       buffer, image->data(0).data());\n> > +\t\tif (ret < 0)\n> > +\t\t\tstd::cerr << \"failed to write DNG \" << filename\n> > +\t\t\t\t  << std::endl;\n> > +\n> > +\t\treturn;\n> > +\t}\n> > +#endif /* HAVE_TIFF */\n> > +\n> >  \tfd = open(filename.c_str(), O_CREAT | O_WRONLY |\n> >  \t\t  (pos == std::string::npos ? O_APPEND : O_TRUNC),\n> >  \t\t  S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);\n> > @@ -86,8 +108,6 @@ void FileSink::writeBuffer(const Stream *stream, FrameBuffer *buffer)\n> >  \t\treturn;\n> >  \t}\n> >\n> > -\tImage *image = mappedBuffers_[buffer].get();\n> > -\n> >  \tfor (unsigned int i = 0; i < buffer->planes().size(); ++i) {\n> >  \t\tconst FrameMetadata::Plane &meta = buffer->metadata().planes()[i];\n> >\n> > diff --git a/src/cam/file_sink.h b/src/cam/file_sink.h\n> > index 067736f5..9ce8b619 100644\n> > --- a/src/cam/file_sink.h\n> > +++ b/src/cam/file_sink.h\n> > @@ -20,7 +20,8 @@ class Image;\n> >  class FileSink : public FrameSink\n> >  {\n> >  public:\n> > -\tFileSink(const std::map<const libcamera::Stream *, std::string> &streamNames,\n> > +\tFileSink(const libcamera::Camera *camera,\n> > +\t\t const std::map<const libcamera::Stream *, std::string> &streamNames,\n> >  \t\t const std::string &pattern = \"\");\n> >  \t~FileSink();\n> >\n> > @@ -32,8 +33,10 @@ public:\n> >\n> >  private:\n> >  \tvoid writeBuffer(const libcamera::Stream *stream,\n> \n> If only we could get the Camera * back from the request, you could\n> avoid storing camera_ as class member as you could do\n> \n>         bool FileSink::processRequest(Request *request)\n>         {\n>                 for (auto [stream, buffer] : request->buffers())\n>                         writeBuffer(request->camera(), stream, buffer, request->metadata());\n> \n>                 return true;\n>         }\n> \n> I recall we discussed that in the past and if it's not there there\n> might be reasons (likely the fact that a Request can outlive the\n> Camera it has been created ?)\n> \n> > -\t\t\t libcamera::FrameBuffer *buffer);\n> > +\t\t\t libcamera::FrameBuffer *buffer,\n> > +\t\t\t const libcamera::ControlList &metadata);\n> >\n> > +\tconst libcamera::Camera *camera_;\n> >  \tstd::map<const libcamera::Stream *, std::string> streamNames_;\n> >  \tstd::string pattern_;\n> >  \tstd::map<libcamera::FrameBuffer *, std::unique_ptr<Image>> mappedBuffers_;\n> > diff --git a/src/cam/main.cpp b/src/cam/main.cpp\n> > index 53c2ffde..c4e18a13 100644\n> > --- a/src/cam/main.cpp\n> > +++ b/src/cam/main.cpp\n> > @@ -144,6 +144,8 @@ int CamApp::parseOptions(int argc, char *argv[])\n> >  \t\t\t \"to write files, using the default file name. Otherwise it sets the\\n\"\n> >  \t\t\t \"full file path and name. The first '#' character in the file name\\n\"\n> >  \t\t\t \"is expanded to the camera index, stream name and frame sequence number.\\n\"\n> > +\t\t\t \"If the file name ends with '.dng', then the frame will be written to\\n\"\n> > +\t\t\t \"the output file(s) in DNG format.\\n\"\n> >  \t\t\t \"The default file name is 'frame-#.bin'.\",\n> >  \t\t\t \"file\", ArgumentOptional, \"filename\", false,\n> >  \t\t\t OptCamera);\n> > diff --git a/src/cam/meson.build b/src/cam/meson.build\n> > index 9c766221..06dbea06 100644\n> > --- a/src/cam/meson.build\n> > +++ b/src/cam/meson.build\n> > @@ -52,6 +52,13 @@ if libsdl2.found()\n> >      endif\n> >  endif\n> >\n> > +if libtiff.found()\n> > +    cam_cpp_args += ['-DHAVE_TIFF']\n> > +    cam_sources += files([\n> > +        'dng_writer.cpp',\n> > +    ])\n> > +endif\n> > +\n> >  cam  = executable('cam', cam_sources,\n> >                    dependencies : [\n> >                        libatomic,\n> > @@ -60,6 +67,7 @@ cam  = executable('cam', cam_sources,\n> >                        libevent,\n> >                        libjpeg,\n> >                        libsdl2,\n> > +                      libtiff,\n> >                        libyaml,\n> >                    ],\n> >                    cpp_args : cam_cpp_args,","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 5B150BD16B\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed, 19 Oct 2022 09:40:29 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 1A8E262E48;\n\tWed, 19 Oct 2022 11:40:29 +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 0F2D562E37\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 19 Oct 2022 11:40:27 +0200 (CEST)","from pendragon.ideasonboard.com (62-78-145-57.bb.dnainternet.fi\n\t[62.78.145.57])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 96DB15A4;\n\tWed, 19 Oct 2022 11:40:26 +0200 (CEST)"],"DKIM-Signature":["v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1666172429;\n\tbh=hNoUF7lveX9BkhLYCFvUIf8/niK7uQK2aDOnjRvQfC4=;\n\th=Date:To:References:In-Reply-To:Subject:List-Id:List-Unsubscribe:\n\tList-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc:\n\tFrom;\n\tb=yrne0KC4xIjPgYvVfrlcJgOOvh9LIhYghWChIbWO0V9prEAgsnk85azdnZV8WNAO6\n\t7MmDFAHH7s1cyldcZYVhQpxfnTru8r5h0ACl9SaUWY+FoFjtHMIxtcLvCCUximLqNM\n\t3wd1krJCSuQEr88PsIna4a9BBEUONOFWzyZKbofSt090lvZVa6L3WNYSkiRBi3aIza\n\tKxCcPx3mlq+DI31lRQvLTI7FbNyyQKO19X/qyFZHjanVjVt8jZk9bpDXqqyKSn4J/j\n\tG/gzvpSEf6kE2wnanhpKen29hV93O1X9QUHL0o0zREjvsytS8Zj6DwkU56DQupT518\n\tQWpIM6k/+OOHg==","v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1666172426;\n\tbh=hNoUF7lveX9BkhLYCFvUIf8/niK7uQK2aDOnjRvQfC4=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=JulooliLFrOURJRI/T7dksiZxNCmiStnT4UdgF1onniRdgcebZmPAVUkukP0xU/VQ\n\taTh/2l+iR1tAeTeN4oP4i81GhV2mmEx6KMqd4mue4RI0buH8MxEcOZAG7fE1vQpZSF\n\tLvWzK6881lpkEv7urykL0hEOh7bpQsb7Xl8fT/Ns="],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key; \n\tunprotected) header.d=ideasonboard.com\n\theader.i=@ideasonboard.com\n\theader.b=\"JulooliL\"; dkim-atps=neutral","Date":"Wed, 19 Oct 2022 12:40:02 +0300","To":"Jacopo Mondi <jacopo@jmondi.org>","Message-ID":"<Y0/F8rzFo9qTgIug@pendragon.ideasonboard.com>","References":"<20221018080908.2841339-1-paul.elder@ideasonboard.com>\n\t<20221018080908.2841339-3-paul.elder@ideasonboard.com>\n\t<20221019083432.47ocg3gnuc3fkbzn@uno.localdomain>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<20221019083432.47ocg3gnuc3fkbzn@uno.localdomain>","Subject":"Re: [libcamera-devel] [PATCH v2 2/3] cam: file_sink: Add support\n\tfor DNG output","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":"Laurent Pinchart via libcamera-devel\n\t<libcamera-devel@lists.libcamera.org>","Reply-To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":25465,"web_url":"https://patchwork.libcamera.org/comment/25465/","msgid":"<20221019101931.o5q6ywxyygieal7o@uno.localdomain>","date":"2022-10-19T10:19:31","subject":"Re: [libcamera-devel] [PATCH v2 2/3] cam: file_sink: Add support\n\tfor DNG output","submitter":{"id":3,"url":"https://patchwork.libcamera.org/api/people/3/","name":"Jacopo Mondi","email":"jacopo@jmondi.org"},"content":"Hi Laurent\n\nOn Wed, Oct 19, 2022 at 12:40:02PM +0300, Laurent Pinchart wrote:\n> On Wed, Oct 19, 2022 at 10:34:32AM +0200, Jacopo Mondi via libcamera-devel wrote:\n> > On Tue, Oct 18, 2022 at 05:09:07PM +0900, Paul Elder via libcamera-devel wrote:\n> > > Add support for outputting buffers in DNG format. It reuses the DNG\n> > > writer that we had previously in qcam.\n> > >\n> > > Signed-off-by: Paul Elder <paul.elder@ideasonboard.com>\n> > >\n> > > ---\n> > > Changes in v2:\n> > > - update help test to mention the dng output feature\n> > > - pass camera as first argument to FileSink constructor\n> > > ---\n> > >  src/cam/camera_session.cpp |  4 ++--\n> > >  src/cam/file_sink.cpp      | 32 ++++++++++++++++++++++++++------\n> > >  src/cam/file_sink.h        |  7 +++++--\n> > >  src/cam/main.cpp           |  2 ++\n> > >  src/cam/meson.build        |  8 ++++++++\n> > >  5 files changed, 43 insertions(+), 10 deletions(-)\n> > >\n> > > diff --git a/src/cam/camera_session.cpp b/src/cam/camera_session.cpp\n> > > index 238186a3..6b409c98 100644\n> > > --- a/src/cam/camera_session.cpp\n> > > +++ b/src/cam/camera_session.cpp\n> > > @@ -207,10 +207,10 @@ int CameraSession::start()\n> > >\n> > >  \tif (options_.isSet(OptFile)) {\n> > >  \t\tif (!options_[OptFile].toString().empty())\n> > > -\t\t\tsink_ = std::make_unique<FileSink>(streamNames_,\n> > > +\t\t\tsink_ = std::make_unique<FileSink>(camera_.get(), streamNames_,\n> > >  \t\t\t\t\t\t\t   options_[OptFile]);\n> > >  \t\telse\n> > > -\t\t\tsink_ = std::make_unique<FileSink>(streamNames_);\n> > > +\t\t\tsink_ = std::make_unique<FileSink>(camera_.get(), streamNames_);\n> > >  \t}\n> > >\n> > >  \tif (sink_) {\n> > > diff --git a/src/cam/file_sink.cpp b/src/cam/file_sink.cpp\n> > > index 45213d4a..8bba4e7f 100644\n> > > --- a/src/cam/file_sink.cpp\n> > > +++ b/src/cam/file_sink.cpp\n> > > @@ -15,14 +15,16 @@\n> > >\n> > >  #include <libcamera/camera.h>\n> > >\n> > > +#include \"dng_writer.h\"\n> > >  #include \"file_sink.h\"\n> > >  #include \"image.h\"\n> > >\n> > >  using namespace libcamera;\n> > >\n> > > -FileSink::FileSink(const std::map<const libcamera::Stream *, std::string> &streamNames,\n> > > +FileSink::FileSink(const libcamera::Camera *camera,\n> > > +\t\t   const std::map<const libcamera::Stream *, std::string> &streamNames,\n> > >  \t\t   const std::string &pattern)\n> > > -\t: streamNames_(streamNames), pattern_(pattern)\n> > > +\t: camera_(camera), streamNames_(streamNames), pattern_(pattern)\n> > >  {\n> > >  }\n> > >\n> > > @@ -51,12 +53,13 @@ void FileSink::mapBuffer(FrameBuffer *buffer)\n> > >  bool FileSink::processRequest(Request *request)\n> > >  {\n> > >  \tfor (auto [stream, buffer] : request->buffers())\n> > > -\t\twriteBuffer(stream, buffer);\n> > > +\t\twriteBuffer(stream, buffer, request->metadata());\n> > >\n> > >  \treturn true;\n> > >  }\n> > >\n> > > -void FileSink::writeBuffer(const Stream *stream, FrameBuffer *buffer)\n> > > +void FileSink::writeBuffer(const Stream *stream, FrameBuffer *buffer,\n> > > +\t\t\t   [[maybe_unused]] const ControlList &metadata)\n> > >  {\n> > >  \tstd::string filename;\n> >\n> >         bool dng = false;\n> >\n> > >  \tsize_t pos;\n> > > @@ -65,6 +68,10 @@ void FileSink::writeBuffer(const Stream *stream, FrameBuffer *buffer)\n> > >  \tif (!pattern_.empty())\n> > >  \t\tfilename = pattern_;\n> > >\n> > > +#ifdef HAVE_TIFF\n> > > +\tbool dng = filename.find(\".dng\", filename.size() - 4) != std::string::npos;\n> >\n> > \tdng = filename.find(\".dng\", filename.size() - 4) != std::string::npos;\n> >\n> > > +#endif /* HAVE_TIFF */\n> > > +\n> > >  \tif (filename.empty() || filename.back() == '/')\n> > >  \t\tfilename += \"frame-#.bin\";\n> > >\n> > > @@ -76,6 +83,21 @@ void FileSink::writeBuffer(const Stream *stream, FrameBuffer *buffer)\n> > >  \t\tfilename.replace(pos, 1, ss.str());\n> > >  \t}\n> > >\n> > > +\tImage *image = mappedBuffers_[buffer].get();\n> > > +\n> > > +#ifdef HAVE_TIFF\n> >\n> > And you can here remove  the #ifdef and the [[maybe_unused]] attribute from the\n> > metadata argument\n>\n> When !HAVE_TIFF, the DNGWriter class isn't declared by dng_writer.h. The\n> code below would thus not compile.\n>\n\nAt a first look I don't seen anything that depends on libtiff in\ndng_writer.h\n\nBut as it would require an additional change on top which is clearly\nnot for this series\n\nReviewed-by: Jacopo Mondi <jacopo@jmondi.org>\n\nThanks\n  j\n\n> > > +\tif (dng) {\n> > > +\t\tret = DNGWriter::write(filename.c_str(), camera_,\n> > > +\t\t\t\t       stream->configuration(), metadata,\n> > > +\t\t\t\t       buffer, image->data(0).data());\n> > > +\t\tif (ret < 0)\n> > > +\t\t\tstd::cerr << \"failed to write DNG \" << filename\n> > > +\t\t\t\t  << std::endl;\n> > > +\n> > > +\t\treturn;\n> > > +\t}\n> > > +#endif /* HAVE_TIFF */\n> > > +\n> > >  \tfd = open(filename.c_str(), O_CREAT | O_WRONLY |\n> > >  \t\t  (pos == std::string::npos ? O_APPEND : O_TRUNC),\n> > >  \t\t  S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);\n> > > @@ -86,8 +108,6 @@ void FileSink::writeBuffer(const Stream *stream, FrameBuffer *buffer)\n> > >  \t\treturn;\n> > >  \t}\n> > >\n> > > -\tImage *image = mappedBuffers_[buffer].get();\n> > > -\n> > >  \tfor (unsigned int i = 0; i < buffer->planes().size(); ++i) {\n> > >  \t\tconst FrameMetadata::Plane &meta = buffer->metadata().planes()[i];\n> > >\n> > > diff --git a/src/cam/file_sink.h b/src/cam/file_sink.h\n> > > index 067736f5..9ce8b619 100644\n> > > --- a/src/cam/file_sink.h\n> > > +++ b/src/cam/file_sink.h\n> > > @@ -20,7 +20,8 @@ class Image;\n> > >  class FileSink : public FrameSink\n> > >  {\n> > >  public:\n> > > -\tFileSink(const std::map<const libcamera::Stream *, std::string> &streamNames,\n> > > +\tFileSink(const libcamera::Camera *camera,\n> > > +\t\t const std::map<const libcamera::Stream *, std::string> &streamNames,\n> > >  \t\t const std::string &pattern = \"\");\n> > >  \t~FileSink();\n> > >\n> > > @@ -32,8 +33,10 @@ public:\n> > >\n> > >  private:\n> > >  \tvoid writeBuffer(const libcamera::Stream *stream,\n> >\n> > If only we could get the Camera * back from the request, you could\n> > avoid storing camera_ as class member as you could do\n> >\n> >         bool FileSink::processRequest(Request *request)\n> >         {\n> >                 for (auto [stream, buffer] : request->buffers())\n> >                         writeBuffer(request->camera(), stream, buffer, request->metadata());\n> >\n> >                 return true;\n> >         }\n> >\n> > I recall we discussed that in the past and if it's not there there\n> > might be reasons (likely the fact that a Request can outlive the\n> > Camera it has been created ?)\n> >\n> > > -\t\t\t libcamera::FrameBuffer *buffer);\n> > > +\t\t\t libcamera::FrameBuffer *buffer,\n> > > +\t\t\t const libcamera::ControlList &metadata);\n> > >\n> > > +\tconst libcamera::Camera *camera_;\n> > >  \tstd::map<const libcamera::Stream *, std::string> streamNames_;\n> > >  \tstd::string pattern_;\n> > >  \tstd::map<libcamera::FrameBuffer *, std::unique_ptr<Image>> mappedBuffers_;\n> > > diff --git a/src/cam/main.cpp b/src/cam/main.cpp\n> > > index 53c2ffde..c4e18a13 100644\n> > > --- a/src/cam/main.cpp\n> > > +++ b/src/cam/main.cpp\n> > > @@ -144,6 +144,8 @@ int CamApp::parseOptions(int argc, char *argv[])\n> > >  \t\t\t \"to write files, using the default file name. Otherwise it sets the\\n\"\n> > >  \t\t\t \"full file path and name. The first '#' character in the file name\\n\"\n> > >  \t\t\t \"is expanded to the camera index, stream name and frame sequence number.\\n\"\n> > > +\t\t\t \"If the file name ends with '.dng', then the frame will be written to\\n\"\n> > > +\t\t\t \"the output file(s) in DNG format.\\n\"\n> > >  \t\t\t \"The default file name is 'frame-#.bin'.\",\n> > >  \t\t\t \"file\", ArgumentOptional, \"filename\", false,\n> > >  \t\t\t OptCamera);\n> > > diff --git a/src/cam/meson.build b/src/cam/meson.build\n> > > index 9c766221..06dbea06 100644\n> > > --- a/src/cam/meson.build\n> > > +++ b/src/cam/meson.build\n> > > @@ -52,6 +52,13 @@ if libsdl2.found()\n> > >      endif\n> > >  endif\n> > >\n> > > +if libtiff.found()\n> > > +    cam_cpp_args += ['-DHAVE_TIFF']\n> > > +    cam_sources += files([\n> > > +        'dng_writer.cpp',\n> > > +    ])\n> > > +endif\n> > > +\n> > >  cam  = executable('cam', cam_sources,\n> > >                    dependencies : [\n> > >                        libatomic,\n> > > @@ -60,6 +67,7 @@ cam  = executable('cam', cam_sources,\n> > >                        libevent,\n> > >                        libjpeg,\n> > >                        libsdl2,\n> > > +                      libtiff,\n> > >                        libyaml,\n> > >                    ],\n> > >                    cpp_args : cam_cpp_args,\n>\n> --\n> Regards,\n>\n> Laurent Pinchart","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 1EB0CC0DA4\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed, 19 Oct 2022 10:19:37 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 4712662E4E;\n\tWed, 19 Oct 2022 12:19:36 +0200 (CEST)","from relay7-d.mail.gandi.net (relay7-d.mail.gandi.net\n\t[217.70.183.200])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 3025062DFA\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 19 Oct 2022 12:19:34 +0200 (CEST)","(Authenticated sender: jacopo@jmondi.org)\n\tby mail.gandi.net (Postfix) with ESMTPSA id 68B5720012;\n\tWed, 19 Oct 2022 10:19:33 +0000 (UTC)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1666174776;\n\tbh=PncN4g805h4hyeExYAfnfDE8pT8Y9IzxZcXkJbp+1tw=;\n\th=Date:To:References:In-Reply-To:Subject:List-Id:List-Unsubscribe:\n\tList-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc:\n\tFrom;\n\tb=fIyTAhQnqeO3aZ7fO+EQ8PNX2Bmd4YqLZ7edlrM0gaxEynhNjBciVWiizwTELzgla\n\tLP9LZ/CHjg22jfDF6IcsBKSgNdRaw2FPTXfspqgRZBr05ZAEEN6yHRGTPpU6VKb5kH\n\t0dL9U995RWdBsO5vZWv+BLvmcgQAYE4GHpyY2pVBLrbhQFA0jRl2uI7+GQNhTsUsGF\n\tHaodtZd1lpd6DagNkIdRJ2DIJS7/WVYKtxtIunRtfHSLswhhVWUn5luvbnGpRPwfzR\n\tOOKUuHkrnNmwKrXRCbT85EIxm1OvBns4TwADzlHXGZt36qHTBADSDxWIL9nsoUg+E5\n\tzuDN9Ar4foFzA==","Date":"Wed, 19 Oct 2022 12:19:31 +0200","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Message-ID":"<20221019101931.o5q6ywxyygieal7o@uno.localdomain>","References":"<20221018080908.2841339-1-paul.elder@ideasonboard.com>\n\t<20221018080908.2841339-3-paul.elder@ideasonboard.com>\n\t<20221019083432.47ocg3gnuc3fkbzn@uno.localdomain>\n\t<Y0/F8rzFo9qTgIug@pendragon.ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<Y0/F8rzFo9qTgIug@pendragon.ideasonboard.com>","Subject":"Re: [libcamera-devel] [PATCH v2 2/3] cam: file_sink: Add support\n\tfor DNG output","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>","Cc":"libcamera-devel@lists.libcamera.org","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}}]