[libcamera-devel] [PATCH v2 2/3] cam: file_sink: Add support for DNG output

Paul Elder paul.elder at ideasonboard.com
Tue Oct 18 10:09:07 CEST 2022


Add support for outputting buffers in DNG format. It reuses the DNG
writer that we had previously in qcam.

Signed-off-by: Paul Elder <paul.elder at ideasonboard.com>

---
Changes in v2:
- update help test to mention the dng output feature
- pass camera as first argument to FileSink constructor
---
 src/cam/camera_session.cpp |  4 ++--
 src/cam/file_sink.cpp      | 32 ++++++++++++++++++++++++++------
 src/cam/file_sink.h        |  7 +++++--
 src/cam/main.cpp           |  2 ++
 src/cam/meson.build        |  8 ++++++++
 5 files changed, 43 insertions(+), 10 deletions(-)

diff --git a/src/cam/camera_session.cpp b/src/cam/camera_session.cpp
index 238186a3..6b409c98 100644
--- a/src/cam/camera_session.cpp
+++ b/src/cam/camera_session.cpp
@@ -207,10 +207,10 @@ int CameraSession::start()
 
 	if (options_.isSet(OptFile)) {
 		if (!options_[OptFile].toString().empty())
-			sink_ = std::make_unique<FileSink>(streamNames_,
+			sink_ = std::make_unique<FileSink>(camera_.get(), streamNames_,
 							   options_[OptFile]);
 		else
-			sink_ = std::make_unique<FileSink>(streamNames_);
+			sink_ = std::make_unique<FileSink>(camera_.get(), streamNames_);
 	}
 
 	if (sink_) {
diff --git a/src/cam/file_sink.cpp b/src/cam/file_sink.cpp
index 45213d4a..8bba4e7f 100644
--- a/src/cam/file_sink.cpp
+++ b/src/cam/file_sink.cpp
@@ -15,14 +15,16 @@
 
 #include <libcamera/camera.h>
 
+#include "dng_writer.h"
 #include "file_sink.h"
 #include "image.h"
 
 using namespace libcamera;
 
-FileSink::FileSink(const std::map<const libcamera::Stream *, std::string> &streamNames,
+FileSink::FileSink(const libcamera::Camera *camera,
+		   const std::map<const libcamera::Stream *, std::string> &streamNames,
 		   const std::string &pattern)
-	: streamNames_(streamNames), pattern_(pattern)
+	: camera_(camera), streamNames_(streamNames), pattern_(pattern)
 {
 }
 
@@ -51,12 +53,13 @@ void FileSink::mapBuffer(FrameBuffer *buffer)
 bool FileSink::processRequest(Request *request)
 {
 	for (auto [stream, buffer] : request->buffers())
-		writeBuffer(stream, buffer);
+		writeBuffer(stream, buffer, request->metadata());
 
 	return true;
 }
 
-void FileSink::writeBuffer(const Stream *stream, FrameBuffer *buffer)
+void FileSink::writeBuffer(const Stream *stream, FrameBuffer *buffer,
+			   [[maybe_unused]] const ControlList &metadata)
 {
 	std::string filename;
 	size_t pos;
@@ -65,6 +68,10 @@ void FileSink::writeBuffer(const Stream *stream, FrameBuffer *buffer)
 	if (!pattern_.empty())
 		filename = pattern_;
 
+#ifdef HAVE_TIFF
+	bool dng = filename.find(".dng", filename.size() - 4) != std::string::npos;
+#endif /* HAVE_TIFF */
+
 	if (filename.empty() || filename.back() == '/')
 		filename += "frame-#.bin";
 
@@ -76,6 +83,21 @@ void FileSink::writeBuffer(const Stream *stream, FrameBuffer *buffer)
 		filename.replace(pos, 1, ss.str());
 	}
 
+	Image *image = mappedBuffers_[buffer].get();
+
+#ifdef HAVE_TIFF
+	if (dng) {
+		ret = DNGWriter::write(filename.c_str(), camera_,
+				       stream->configuration(), metadata,
+				       buffer, image->data(0).data());
+		if (ret < 0)
+			std::cerr << "failed to write DNG " << filename
+				  << std::endl;
+
+		return;
+	}
+#endif /* HAVE_TIFF */
+
 	fd = open(filename.c_str(), O_CREAT | O_WRONLY |
 		  (pos == std::string::npos ? O_APPEND : O_TRUNC),
 		  S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
@@ -86,8 +108,6 @@ void FileSink::writeBuffer(const Stream *stream, FrameBuffer *buffer)
 		return;
 	}
 
-	Image *image = mappedBuffers_[buffer].get();
-
 	for (unsigned int i = 0; i < buffer->planes().size(); ++i) {
 		const FrameMetadata::Plane &meta = buffer->metadata().planes()[i];
 
diff --git a/src/cam/file_sink.h b/src/cam/file_sink.h
index 067736f5..9ce8b619 100644
--- a/src/cam/file_sink.h
+++ b/src/cam/file_sink.h
@@ -20,7 +20,8 @@ class Image;
 class FileSink : public FrameSink
 {
 public:
-	FileSink(const std::map<const libcamera::Stream *, std::string> &streamNames,
+	FileSink(const libcamera::Camera *camera,
+		 const std::map<const libcamera::Stream *, std::string> &streamNames,
 		 const std::string &pattern = "");
 	~FileSink();
 
@@ -32,8 +33,10 @@ public:
 
 private:
 	void writeBuffer(const libcamera::Stream *stream,
-			 libcamera::FrameBuffer *buffer);
+			 libcamera::FrameBuffer *buffer,
+			 const libcamera::ControlList &metadata);
 
+	const libcamera::Camera *camera_;
 	std::map<const libcamera::Stream *, std::string> streamNames_;
 	std::string pattern_;
 	std::map<libcamera::FrameBuffer *, std::unique_ptr<Image>> mappedBuffers_;
diff --git a/src/cam/main.cpp b/src/cam/main.cpp
index 53c2ffde..c4e18a13 100644
--- a/src/cam/main.cpp
+++ b/src/cam/main.cpp
@@ -144,6 +144,8 @@ int CamApp::parseOptions(int argc, char *argv[])
 			 "to write files, using the default file name. Otherwise it sets the\n"
 			 "full file path and name. The first '#' character in the file name\n"
 			 "is expanded to the camera index, stream name and frame sequence number.\n"
+			 "If the file name ends with '.dng', then the frame will be written to\n"
+			 "the output file(s) in DNG format.\n"
 			 "The default file name is 'frame-#.bin'.",
 			 "file", ArgumentOptional, "filename", false,
 			 OptCamera);
diff --git a/src/cam/meson.build b/src/cam/meson.build
index 9c766221..06dbea06 100644
--- a/src/cam/meson.build
+++ b/src/cam/meson.build
@@ -52,6 +52,13 @@ if libsdl2.found()
     endif
 endif
 
+if libtiff.found()
+    cam_cpp_args += ['-DHAVE_TIFF']
+    cam_sources += files([
+        'dng_writer.cpp',
+    ])
+endif
+
 cam  = executable('cam', cam_sources,
                   dependencies : [
                       libatomic,
@@ -60,6 +67,7 @@ cam  = executable('cam', cam_sources,
                       libevent,
                       libjpeg,
                       libsdl2,
+                      libtiff,
                       libyaml,
                   ],
                   cpp_args : cam_cpp_args,
-- 
2.30.2



More information about the libcamera-devel mailing list