[libcamera-devel,v4,3/3] qcam: Add RAW capture support

Message ID 20200502121356.1045727-4-niklas.soderlund@ragnatech.se
State Accepted
Headers show
Series
  • qcam: Add RAW capture support
Related show

Commit Message

Niklas Söderlund May 2, 2020, 12:13 p.m. UTC
Add a toolbar button that captures RAW data to disk. The button is only
enabled if the camera is configured to provide a raw stream to the
application.

Only when the capture action is triggered will a request with a raw
buffer be queued to the camera.

Signed-off-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
* Changes since v2
- Use a file dialog
- Make DNG optional depending on libtiff

* Changes since v3
- Use HAVE_DNG
- Rework MainWindow::queueRequest() to reduce code cover by lock.
---
 src/qcam/assets/feathericons/feathericons.qrc |  1 +
 src/qcam/main_window.cpp                      | 68 ++++++++++++++++++-
 src/qcam/main_window.h                        |  4 ++
 3 files changed, 72 insertions(+), 1 deletion(-)

Patch

diff --git a/src/qcam/assets/feathericons/feathericons.qrc b/src/qcam/assets/feathericons/feathericons.qrc
index c4eb7a0be6884373..fc8213928ece70ea 100644
--- a/src/qcam/assets/feathericons/feathericons.qrc
+++ b/src/qcam/assets/feathericons/feathericons.qrc
@@ -1,5 +1,6 @@ 
 <!DOCTYPE RCC><RCC version="1.0">
 <qresource>
+<file>./aperture.svg</file>
 <file>./camera-off.svg</file>
 <file>./play-circle.svg</file>
 <file>./save.svg</file>
diff --git a/src/qcam/main_window.cpp b/src/qcam/main_window.cpp
index 0bd9f3583ea4f6d4..8720c6c61f401c14 100644
--- a/src/qcam/main_window.cpp
+++ b/src/qcam/main_window.cpp
@@ -27,6 +27,8 @@ 
 #include <libcamera/camera_manager.h>
 #include <libcamera/version.h>
 
+#include "dng_writer.h"
+
 using namespace libcamera;
 
 /**
@@ -48,7 +50,8 @@  public:
 };
 
 MainWindow::MainWindow(CameraManager *cm, const OptionsParser::Options &options)
-	: options_(options), cm_(cm), allocator_(nullptr), isCapturing_(false)
+	: saveRaw_(nullptr), options_(options), cm_(cm), allocator_(nullptr),
+	  isCapturing_(false), captureRaw_(false)
 {
 	int ret;
 
@@ -144,6 +147,16 @@  int MainWindow::createToolbars()
 	action->setShortcut(QKeySequence::SaveAs);
 	connect(action, &QAction::triggered, this, &MainWindow::saveImageAs);
 
+#ifdef HAVE_DNG
+	/* Save Raw action. */
+	action = toolbar_->addAction(QIcon::fromTheme("camera-photo",
+						      QIcon(":aperture.svg")),
+				     "Save Raw");
+	action->setEnabled(false);
+	connect(action, &QAction::triggered, this, &MainWindow::captureRaw);
+	saveRaw_ = action;
+#endif
+
 	return 0;
 }
 
@@ -369,6 +382,10 @@  int MainWindow::startCapture()
 
 	adjustSize();
 
+	/* Configure the raw capture button. */
+	if (saveRaw_)
+		saveRaw_->setEnabled(config_->size() == 2);
+
 	/* Allocate and map buffers. */
 	allocator_ = new FrameBufferAllocator(camera_);
 	for (StreamConfiguration &config : *config_) {
@@ -474,6 +491,9 @@  void MainWindow::stopCapture()
 		return;
 
 	viewfinder_->stop();
+	if (saveRaw_)
+		saveRaw_->setEnabled(false);
+	captureRaw_ = false;
 
 	int ret = camera_->stop();
 	if (ret)
@@ -524,6 +544,32 @@  void MainWindow::saveImageAs()
 	writer.write(image);
 }
 
+void MainWindow::captureRaw()
+{
+	captureRaw_ = true;
+}
+
+void MainWindow::processRaw(FrameBuffer *buffer)
+{
+#ifdef HAVE_DNG
+	QString defaultPath = QStandardPaths::writableLocation(QStandardPaths::PicturesLocation);
+	QString filename = QFileDialog::getSaveFileName(this, "Save DNG", defaultPath,
+							"DNG Files (*.dng)");
+
+	if (!filename.isEmpty()) {
+		const MappedBuffer &mapped = mappedBuffers_[buffer];
+		DNGWriter::write(filename.toStdString().c_str(), camera_.get(),
+				 rawStream_->configuration(), buffer,
+				 mapped.memory);
+	}
+#endif
+
+	{
+		QMutexLocker locker(&mutex_);
+		freeBuffers_[rawStream_].enqueue(buffer);
+	}
+}
+
 /* -----------------------------------------------------------------------------
  * Request Completion Handling
  */
@@ -566,6 +612,9 @@  void MainWindow::processCapture()
 	/* Process buffers. */
 	if (buffers.count(vfStream_))
 		processViewfinder(buffers[vfStream_]);
+
+	if (buffers.count(rawStream_))
+		processRaw(buffers[rawStream_]);
 }
 
 void MainWindow::processViewfinder(FrameBuffer *buffer)
@@ -598,5 +647,22 @@  void MainWindow::queueRequest(FrameBuffer *buffer)
 
 	request->addBuffer(vfStream_, buffer);
 
+	if (captureRaw_) {
+		FrameBuffer *buffer = nullptr;
+
+		{
+			QMutexLocker locker(&mutex_);
+			if (!freeBuffers_[rawStream_].isEmpty())
+				buffer = freeBuffers_[rawStream_].dequeue();
+		}
+
+		if (buffer) {
+			request->addBuffer(rawStream_, buffer);
+			captureRaw_ = false;
+		} else {
+			qWarning() << "No free buffer available for RAW capture";
+		}
+	}
+
 	camera_->queueRequest(request);
 }
diff --git a/src/qcam/main_window.h b/src/qcam/main_window.h
index 4856ecc10729159c..295ecc537e9d45bf 100644
--- a/src/qcam/main_window.h
+++ b/src/qcam/main_window.h
@@ -55,6 +55,8 @@  private Q_SLOTS:
 	void toggleCapture(bool start);
 
 	void saveImageAs();
+	void captureRaw();
+	void processRaw(FrameBuffer *buffer);
 
 	void queueRequest(FrameBuffer *buffer);
 
@@ -75,6 +77,7 @@  private:
 	QToolBar *toolbar_;
 	QAction *startStopAction_;
 	QComboBox *cameraCombo_;
+	QAction *saveRaw_;
 	ViewFinder *viewfinder_;
 
 	QIcon iconPlay_;
@@ -96,6 +99,7 @@  private:
 
 	/* Capture state, buffers queue and statistics */
 	bool isCapturing_;
+	bool captureRaw_;
 	Stream *vfStream_;
 	Stream *rawStream_;
 	std::map<Stream *, QQueue<FrameBuffer *>> freeBuffers_;