[PATCH 2/2] apps: cam: Print an error when outputting DNG and DNG support is missing

Milan Zamazal mzamazal at redhat.com
Thu Sep 26 11:21:06 CEST 2024


Hi Laurent,

thank you for the patch, nice improvement.

Laurent Pinchart <laurent.pinchart at ideasonboard.com> writes:

> When DNG support is missing, the cam application ignores the .dng suffix
> of the file pattern and writes raw binary data instead, without
> notifying the user. This leads to confusion. Fix it by printing an error
> message.
>
> Signed-off-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>

Reviewed-by: Milan Zamazal <mzamazal at redhat.com>

> ---
>  src/apps/cam/camera_session.cpp | 15 ++++++---
>  src/apps/cam/file_sink.cpp      | 60 +++++++++++++++++++++++----------
>  src/apps/cam/file_sink.h        | 18 ++++++++--
>  3 files changed, 68 insertions(+), 25 deletions(-)
>
> diff --git a/src/apps/cam/camera_session.cpp b/src/apps/cam/camera_session.cpp
> index 097dc479241a..227df9e922ea 100644
> --- a/src/apps/cam/camera_session.cpp
> +++ b/src/apps/cam/camera_session.cpp
> @@ -230,11 +230,16 @@ int CameraSession::start()
>  #endif
>  
>  	if (options_.isSet(OptFile)) {
> -		if (!options_[OptFile].toString().empty())
> -			sink_ = std::make_unique<FileSink>(camera_.get(), streamNames_,
> -							   options_[OptFile]);
> -		else
> -			sink_ = std::make_unique<FileSink>(camera_.get(), streamNames_);
> +		std::unique_ptr<FileSink> sink =
> +			std::make_unique<FileSink>(camera_.get(), streamNames_);
> +
> +		if (!options_[OptFile].toString().empty()) {
> +			ret = sink->setFilePattern(options_[OptFile]);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		sink_ = std::move(sink);
>  	}
>  
>  	if (sink_) {
> diff --git a/src/apps/cam/file_sink.cpp b/src/apps/cam/file_sink.cpp
> index 3e000d2fd9c6..76e21db9bf9a 100644
> --- a/src/apps/cam/file_sink.cpp
> +++ b/src/apps/cam/file_sink.cpp
> @@ -5,6 +5,7 @@
>   * File Sink
>   */
>  
> +#include <array>
>  #include <assert.h>
>  #include <fcntl.h>
>  #include <iomanip>
> @@ -12,6 +13,7 @@
>  #include <sstream>
>  #include <string.h>
>  #include <unistd.h>
> +#include <utility>
>  
>  #include <libcamera/camera.h>
>  
> @@ -24,13 +26,13 @@
>  using namespace libcamera;
>  
>  FileSink::FileSink([[maybe_unused]] const libcamera::Camera *camera,
> -		   const std::map<const libcamera::Stream *, std::string> &streamNames,
> -		   const std::string &pattern)
> +		   const std::map<const libcamera::Stream *, std::string> &streamNames)
>  	:
>  #ifdef HAVE_TIFF
>  	  camera_(camera),
>  #endif
> -	  streamNames_(streamNames), pattern_(pattern)
> +	  pattern_(kDefaultFilePattern), fileType_(FileType::Binary),
> +	  streamNames_(streamNames)
>  {
>  }
>  
> @@ -38,6 +40,41 @@ FileSink::~FileSink()
>  {
>  }
>  
> +int FileSink::setFilePattern(const std::string &pattern)
> +{
> +	static const std::array<std::pair<std::string, FileType>, 2> types{{
> +		{ ".dng", FileType::Dng },
> +		{ ".ppm", FileType::Ppm },
> +	}};
> +
> +	pattern_ = pattern;
> +
> +	if (pattern_.empty() || pattern_.back() == '/')
> +		pattern_ += kDefaultFilePattern;
> +
> +	fileType_ = FileType::Binary;
> +
> +	for (const auto &type : types) {
> +		if (pattern_.size() < type.first.size())
> +			continue;
> +
> +		if (pattern_.find(type.first, pattern_.size() - type.first.size()) !=
> +		    std::string::npos) {
> +			fileType_ = type.second;
> +			break;
> +		}
> +	}
> +
> +#ifndef HAVE_TIFF
> +	if (fileType_ == FileType::Dng) {
> +		std::cerr << "DNG support not available" << std::endl;
> +		return -EINVAL;
> +	}
> +#endif /* HAVE_TIFF */
> +
> +	return 0;
> +}
> +
>  int FileSink::configure(const libcamera::CameraConfiguration &config)
>  {
>  	int ret = FrameSink::configure(config);
> @@ -67,21 +104,10 @@ bool FileSink::processRequest(Request *request)
>  void FileSink::writeBuffer(const Stream *stream, FrameBuffer *buffer,
>  			   [[maybe_unused]] const ControlList &metadata)
>  {
> -	std::string filename;
> +	std::string filename = pattern_;
>  	size_t pos;
>  	int fd, ret = 0;
>  
> -	if (!pattern_.empty())
> -		filename = pattern_;
> -
> -#ifdef HAVE_TIFF
> -	bool dng = filename.find(".dng", filename.size() - 4) != std::string::npos;
> -#endif /* HAVE_TIFF */
> -	bool ppm = filename.find(".ppm", filename.size() - 4) != std::string::npos;
> -
> -	if (filename.empty() || filename.back() == '/')
> -		filename += "frame-#.bin";
> -
>  	pos = filename.find_first_of('#');
>  	if (pos != std::string::npos) {
>  		std::stringstream ss;
> @@ -93,7 +119,7 @@ void FileSink::writeBuffer(const Stream *stream, FrameBuffer *buffer,
>  	Image *image = mappedBuffers_[buffer].get();
>  
>  #ifdef HAVE_TIFF
> -	if (dng) {
> +	if (fileType_ == FileType::Dng) {
>  		ret = DNGWriter::write(filename.c_str(), camera_,
>  				       stream->configuration(), metadata,
>  				       buffer, image->data(0).data());
> @@ -104,7 +130,7 @@ void FileSink::writeBuffer(const Stream *stream, FrameBuffer *buffer,
>  		return;
>  	}
>  #endif /* HAVE_TIFF */
> -	if (ppm) {
> +	if (fileType_ == FileType::Ppm) {
>  		ret = PPMWriter::write(filename.c_str(), stream->configuration(),
>  				       image->data(0));
>  		if (ret < 0)
> diff --git a/src/apps/cam/file_sink.h b/src/apps/cam/file_sink.h
> index 9d560783af09..71b7fe0feab5 100644
> --- a/src/apps/cam/file_sink.h
> +++ b/src/apps/cam/file_sink.h
> @@ -21,10 +21,11 @@ class FileSink : public FrameSink
>  {
>  public:
>  	FileSink(const libcamera::Camera *camera,
> -		 const std::map<const libcamera::Stream *, std::string> &streamNames,
> -		 const std::string &pattern = "");
> +		 const std::map<const libcamera::Stream *, std::string> &streamNames);
>  	~FileSink();
>  
> +	int setFilePattern(const std::string &pattern);
> +
>  	int configure(const libcamera::CameraConfiguration &config) override;
>  
>  	void mapBuffer(libcamera::FrameBuffer *buffer) override;
> @@ -32,6 +33,14 @@ public:
>  	bool processRequest(libcamera::Request *request) override;
>  
>  private:
> +	static constexpr const char *kDefaultFilePattern = "frame-#.bin";
> +
> +	enum class FileType {
> +		Binary,
> +		Dng,
> +		Ppm,
> +	};
> +
>  	void writeBuffer(const libcamera::Stream *stream,
>  			 libcamera::FrameBuffer *buffer,
>  			 const libcamera::ControlList &metadata);
> @@ -39,7 +48,10 @@ private:
>  #ifdef HAVE_TIFF
>  	const libcamera::Camera *camera_;
>  #endif
> -	std::map<const libcamera::Stream *, std::string> streamNames_;
> +
>  	std::string pattern_;
> +	FileType fileType_;
> +
> +	std::map<const libcamera::Stream *, std::string> streamNames_;
>  	std::map<libcamera::FrameBuffer *, std::unique_ptr<Image>> mappedBuffers_;
>  };



More information about the libcamera-devel mailing list