{"id":21371,"url":"https://patchwork.libcamera.org/api/1.1/patches/21371/?format=json","web_url":"https://patchwork.libcamera.org/patch/21371/","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":"<20240925152134.20284-3-laurent.pinchart@ideasonboard.com>","date":"2024-09-25T15:21:34","name":"[2/2] apps: cam: Print an error when outputting DNG and DNG support is missing","commit_ref":"b2538c80b96df937ff6fa823a489bf4710cee0e2","pull_url":null,"state":"accepted","archived":false,"hash":"292e96c906c20b6b2df1365ea8d5f29704b73012","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/1.1/people/2/?format=json","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"delegate":null,"mbox":"https://patchwork.libcamera.org/patch/21371/mbox/","series":[{"id":4624,"url":"https://patchwork.libcamera.org/api/1.1/series/4624/?format=json","web_url":"https://patchwork.libcamera.org/project/libcamera/list/?series=4624","date":"2024-09-25T15:21:32","name":"apps: cam: Improve user experience with DNG capture","version":1,"mbox":"https://patchwork.libcamera.org/series/4624/mbox/"}],"comments":"https://patchwork.libcamera.org/api/patches/21371/comments/","check":"pending","checks":"https://patchwork.libcamera.org/api/patches/21371/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 4FB54C3257\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed, 25 Sep 2024 15:21:47 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 638476350E;\n\tWed, 25 Sep 2024 17:21:46 +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 4E3C2634F4\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 25 Sep 2024 17:21:42 +0200 (CEST)","from pendragon.ideasonboard.com (81-175-209-231.bb.dnainternet.fi\n\t[81.175.209.231])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id B5BDDA30;\n\tWed, 25 Sep 2024 17:20:14 +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=\"oFehNpSU\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1727277614;\n\tbh=ledoTUZWaXxhS0X5PpcpvRb5w95v4/FSCzoj14RHPJE=;\n\th=From:To:Cc:Subject:Date:In-Reply-To:References:From;\n\tb=oFehNpSURpc/u2dRkuXMLWLWyf64hUa+4ACNYda13/QEYSSIgKRAOwDgqLFyC6Y5T\n\t6RDGEMMP74EUaFn2dEwUKzL/DqusULd7KeFpjn5fOAQHlQNxmkRMGPZbIg54GRHQGS\n\tPEfksbWcI9bHL4orW0+dzq77gMQ2CwBbDS3tyDIU=","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"libcamera-devel@lists.libcamera.org","Cc":"Arne Caspari <arne.caspari@theimagingsource.com>","Subject":"[PATCH 2/2] apps: cam: Print an error when outputting DNG and DNG\n\tsupport is missing","Date":"Wed, 25 Sep 2024 18:21:34 +0300","Message-ID":"<20240925152134.20284-3-laurent.pinchart@ideasonboard.com>","X-Mailer":"git-send-email 2.45.2","In-Reply-To":"<20240925152134.20284-1-laurent.pinchart@ideasonboard.com>","References":"<20240925152134.20284-1-laurent.pinchart@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":"When DNG support is missing, the cam application ignores the .dng suffix\nof the file pattern and writes raw binary data instead, without\nnotifying the user. This leads to confusion. Fix it by printing an error\nmessage.\n\nSigned-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n---\n src/apps/cam/camera_session.cpp | 15 ++++++---\n src/apps/cam/file_sink.cpp      | 60 +++++++++++++++++++++++----------\n src/apps/cam/file_sink.h        | 18 ++++++++--\n 3 files changed, 68 insertions(+), 25 deletions(-)","diff":"diff --git a/src/apps/cam/camera_session.cpp b/src/apps/cam/camera_session.cpp\nindex 097dc479241a..227df9e922ea 100644\n--- a/src/apps/cam/camera_session.cpp\n+++ b/src/apps/cam/camera_session.cpp\n@@ -230,11 +230,16 @@ int CameraSession::start()\n #endif\n \n \tif (options_.isSet(OptFile)) {\n-\t\tif (!options_[OptFile].toString().empty())\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>(camera_.get(), streamNames_);\n+\t\tstd::unique_ptr<FileSink> sink =\n+\t\t\tstd::make_unique<FileSink>(camera_.get(), streamNames_);\n+\n+\t\tif (!options_[OptFile].toString().empty()) {\n+\t\t\tret = sink->setFilePattern(options_[OptFile]);\n+\t\t\tif (ret)\n+\t\t\t\treturn ret;\n+\t\t}\n+\n+\t\tsink_ = std::move(sink);\n \t}\n \n \tif (sink_) {\ndiff --git a/src/apps/cam/file_sink.cpp b/src/apps/cam/file_sink.cpp\nindex 3e000d2fd9c6..76e21db9bf9a 100644\n--- a/src/apps/cam/file_sink.cpp\n+++ b/src/apps/cam/file_sink.cpp\n@@ -5,6 +5,7 @@\n  * File Sink\n  */\n \n+#include <array>\n #include <assert.h>\n #include <fcntl.h>\n #include <iomanip>\n@@ -12,6 +13,7 @@\n #include <sstream>\n #include <string.h>\n #include <unistd.h>\n+#include <utility>\n \n #include <libcamera/camera.h>\n \n@@ -24,13 +26,13 @@\n using namespace libcamera;\n \n FileSink::FileSink([[maybe_unused]] 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\t   const std::map<const libcamera::Stream *, std::string> &streamNames)\n \t:\n #ifdef HAVE_TIFF\n \t  camera_(camera),\n #endif\n-\t  streamNames_(streamNames), pattern_(pattern)\n+\t  pattern_(kDefaultFilePattern), fileType_(FileType::Binary),\n+\t  streamNames_(streamNames)\n {\n }\n \n@@ -38,6 +40,41 @@ FileSink::~FileSink()\n {\n }\n \n+int FileSink::setFilePattern(const std::string &pattern)\n+{\n+\tstatic const std::array<std::pair<std::string, FileType>, 2> types{{\n+\t\t{ \".dng\", FileType::Dng },\n+\t\t{ \".ppm\", FileType::Ppm },\n+\t}};\n+\n+\tpattern_ = pattern;\n+\n+\tif (pattern_.empty() || pattern_.back() == '/')\n+\t\tpattern_ += kDefaultFilePattern;\n+\n+\tfileType_ = FileType::Binary;\n+\n+\tfor (const auto &type : types) {\n+\t\tif (pattern_.size() < type.first.size())\n+\t\t\tcontinue;\n+\n+\t\tif (pattern_.find(type.first, pattern_.size() - type.first.size()) !=\n+\t\t    std::string::npos) {\n+\t\t\tfileType_ = type.second;\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\n+#ifndef HAVE_TIFF\n+\tif (fileType_ == FileType::Dng) {\n+\t\tstd::cerr << \"DNG support not available\" << std::endl;\n+\t\treturn -EINVAL;\n+\t}\n+#endif /* HAVE_TIFF */\n+\n+\treturn 0;\n+}\n+\n int FileSink::configure(const libcamera::CameraConfiguration &config)\n {\n \tint ret = FrameSink::configure(config);\n@@ -67,21 +104,10 @@ bool FileSink::processRequest(Request *request)\n void FileSink::writeBuffer(const Stream *stream, FrameBuffer *buffer,\n \t\t\t   [[maybe_unused]] const ControlList &metadata)\n {\n-\tstd::string filename;\n+\tstd::string filename = pattern_;\n \tsize_t pos;\n \tint fd, ret = 0;\n \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-\tbool ppm = filename.find(\".ppm\", filename.size() - 4) != std::string::npos;\n-\n-\tif (filename.empty() || filename.back() == '/')\n-\t\tfilename += \"frame-#.bin\";\n-\n \tpos = filename.find_first_of('#');\n \tif (pos != std::string::npos) {\n \t\tstd::stringstream ss;\n@@ -93,7 +119,7 @@ void FileSink::writeBuffer(const Stream *stream, FrameBuffer *buffer,\n \tImage *image = mappedBuffers_[buffer].get();\n \n #ifdef HAVE_TIFF\n-\tif (dng) {\n+\tif (fileType_ == FileType::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@@ -104,7 +130,7 @@ void FileSink::writeBuffer(const Stream *stream, FrameBuffer *buffer,\n \t\treturn;\n \t}\n #endif /* HAVE_TIFF */\n-\tif (ppm) {\n+\tif (fileType_ == FileType::Ppm) {\n \t\tret = PPMWriter::write(filename.c_str(), stream->configuration(),\n \t\t\t\t       image->data(0));\n \t\tif (ret < 0)\ndiff --git a/src/apps/cam/file_sink.h b/src/apps/cam/file_sink.h\nindex 9d560783af09..71b7fe0feab5 100644\n--- a/src/apps/cam/file_sink.h\n+++ b/src/apps/cam/file_sink.h\n@@ -21,10 +21,11 @@ class FileSink : public FrameSink\n {\n public:\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\t const std::map<const libcamera::Stream *, std::string> &streamNames);\n \t~FileSink();\n \n+\tint setFilePattern(const std::string &pattern);\n+\n \tint configure(const libcamera::CameraConfiguration &config) override;\n \n \tvoid mapBuffer(libcamera::FrameBuffer *buffer) override;\n@@ -32,6 +33,14 @@ public:\n \tbool processRequest(libcamera::Request *request) override;\n \n private:\n+\tstatic constexpr const char *kDefaultFilePattern = \"frame-#.bin\";\n+\n+\tenum class FileType {\n+\t\tBinary,\n+\t\tDng,\n+\t\tPpm,\n+\t};\n+\n \tvoid writeBuffer(const libcamera::Stream *stream,\n \t\t\t libcamera::FrameBuffer *buffer,\n \t\t\t const libcamera::ControlList &metadata);\n@@ -39,7 +48,10 @@ private:\n #ifdef HAVE_TIFF\n \tconst libcamera::Camera *camera_;\n #endif\n-\tstd::map<const libcamera::Stream *, std::string> streamNames_;\n+\n \tstd::string pattern_;\n+\tFileType fileType_;\n+\n+\tstd::map<const libcamera::Stream *, std::string> streamNames_;\n \tstd::map<libcamera::FrameBuffer *, std::unique_ptr<Image>> mappedBuffers_;\n };\n","prefixes":["2/2"]}