[libcamera-devel] [PATCH 2/3] cam: file_sink: Add support for DNG output
paul.elder at ideasonboard.com
paul.elder at ideasonboard.com
Tue Oct 18 08:46:52 CEST 2022
Hi Laurent,
On Tue, Oct 18, 2022 at 03:45:31AM +0300, Laurent Pinchart wrote:
> Hi Paul,
>
> Thank you for the patch.
>
> On Tue, Oct 18, 2022 at 02:17:40AM +0900, Paul Elder via libcamera-devel wrote:
> > 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>
> > ---
> > src/cam/camera_session.cpp | 3 ++-
> > src/cam/file_sink.cpp | 31 +++++++++++++++++++++++++------
> > src/cam/file_sink.h | 7 +++++--
> > 3 files changed, 32 insertions(+), 9 deletions(-)
>
> Should the help text of the --file option be updated in main.cpp to
> document this feature ?
Yeah.
>
> > diff --git a/src/cam/camera_session.cpp b/src/cam/camera_session.cpp
> > index 238186a3..2557f32d 100644
> > --- a/src/cam/camera_session.cpp
> > +++ b/src/cam/camera_session.cpp
> > @@ -208,7 +208,8 @@ int CameraSession::start()
> > if (options_.isSet(OptFile)) {
> > if (!options_[OptFile].toString().empty())
> > sink_ = std::make_unique<FileSink>(streamNames_,
> > - options_[OptFile]);
> > + options_[OptFile],
> > + camera_.get());
> > else
> > sink_ = std::make_unique<FileSink>(streamNames_);
> > }
> > diff --git a/src/cam/file_sink.cpp b/src/cam/file_sink.cpp
> > index 45213d4a..fabf163c 100644
> > --- a/src/cam/file_sink.cpp
> > +++ b/src/cam/file_sink.cpp
> > @@ -15,14 +15,15 @@
> >
> > #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,
> > - const std::string &pattern)
> > - : streamNames_(streamNames), pattern_(pattern)
> > + const std::string &pattern, const libcamera::Camera *camera)
> > + : streamNames_(streamNames), pattern_(pattern), camera_(camera)
> > {
> > }
> >
> > @@ -51,12 +52,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 +67,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;
>
> I wish C++ had std::string::ends_width().
>
> substr could also be used:
>
> bool dng = filename.substr(filename.size() - 4) == ".dng";
>
> but that will result in a copy. It think std::string_view would solve
> that:
>
> bool dng = std::string_view(filename).substr(filename.size() - 4) == ".dng";
>
> but I'm not sure that's better :-)
I'll keep the original :)
>
> > +#endif /* HAVE_TIFF */
> > +
> > if (filename.empty() || filename.back() == '/')
> > filename += "frame-#.bin";
> >
> > @@ -76,6 +82,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;
> > + }
>
> Hmmmm... You won't like this, but... what if the pipeline handler can
> capture both raw and processed streams, and the user wants to write raw
> frames in DNG and processed frames as .bin files ?
I don't like this.
qcam behaved like this, so I thought it was fine to just mimick it.
Eh, I guess I could expand it, shouldn't be *that* bad (famous last
words).
>
> > +#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 +107,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..e4838b37 100644
> > --- a/src/cam/file_sink.h
> > +++ b/src/cam/file_sink.h
> > @@ -21,7 +21,7 @@ class FileSink : public FrameSink
> > {
> > public:
> > FileSink(const std::map<const libcamera::Stream *, std::string> &streamNames,
> > - const std::string &pattern = "");
> > + const std::string &pattern = "", const libcamera::Camera *camera = nullptr);
>
> I'd pass the camera as the first argument, to avoid having to add a
> default value.
It's only needed for DNG writing, though. I guess it is good
future-proofing though :/
Paul
>
> > ~FileSink();
> >
> > int configure(const libcamera::CameraConfiguration &config) override;
> > @@ -32,9 +32,12 @@ public:
> >
> > private:
> > void writeBuffer(const libcamera::Stream *stream,
> > - libcamera::FrameBuffer *buffer);
> > + libcamera::FrameBuffer *buffer,
> > + const libcamera::ControlList &metadata);
> >
> > std::map<const libcamera::Stream *, std::string> streamNames_;
> > std::string pattern_;
> > std::map<libcamera::FrameBuffer *, std::unique_ptr<Image>> mappedBuffers_;
> > +
> > + const libcamera::Camera *camera_;
> > };
More information about the libcamera-devel
mailing list