[libcamera-devel] [RFC/PATCH 5/5] qcam: Add RAW capture support
Niklas Söderlund
niklas.soderlund at ragnatech.se
Thu Apr 30 02:36:04 CEST 2020
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 at ragnatech.se>
---
src/qcam/assets/feathericons/feathericons.qrc | 1 +
src/qcam/main_window.cpp | 94 ++++++++++++++++++-
src/qcam/main_window.h | 4 +
3 files changed, 98 insertions(+), 1 deletion(-)
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 f57aaf4a27e5f4ca..535fa53d6705a1a9 100644
--- a/src/qcam/main_window.cpp
+++ b/src/qcam/main_window.cpp
@@ -7,10 +7,13 @@
#include "main_window.h"
+#include <fcntl.h>
#include <iomanip>
#include <sstream>
#include <string>
#include <sys/mman.h>
+#include <sys/stat.h>
+#include <unistd.h>
#include <QComboBox>
#include <QCoreApplication>
@@ -49,7 +52,8 @@ public:
};
MainWindow::MainWindow(CameraManager *cm, const OptionsParser::Options &options)
- : options_(options), cm_(cm), allocator_(nullptr), isCapturing_(false)
+ : options_(options), cm_(cm), allocator_(nullptr), isCapturing_(false),
+ captureRaw_(false)
{
int ret;
@@ -149,6 +153,14 @@ int MainWindow::createToolbars()
"Save As...");
connect(action, &QAction::triggered, this, &MainWindow::saveViewfinder);
+ /* Save Raw action. */
+ action = toolbar_->addAction(QIcon::fromTheme("document-save-as",
+ QIcon(":aperture.svg")),
+ "Save Raw");
+ action->setEnabled(false);
+ connect(action, &QAction::triggered, this, &MainWindow::saveRaw);
+ saveRaw_ = action;
+
return 0;
}
@@ -369,6 +381,9 @@ int MainWindow::startCapture()
adjustSize();
+ /* Configure the raw capture button. */
+ saveRaw_->setEnabled(config_->size() == 2);
+
/* Allocate and map buffers. */
allocator_ = new FrameBufferAllocator(camera_);
for (StreamConfiguration &config : *config_) {
@@ -474,6 +489,7 @@ void MainWindow::stopCapture()
return;
viewfinder_->stop();
+ saveRaw_->setEnabled(false);
int ret = camera_->stop();
if (ret)
@@ -514,6 +530,11 @@ void MainWindow::saveViewfinder()
saveViewfinder_ = true;
}
+void MainWindow::saveRaw()
+{
+ captureRaw_ = true;
+}
+
/* -----------------------------------------------------------------------------
* Request Completion Handling
*/
@@ -558,6 +579,9 @@ void MainWindow::processCapture()
if (buffers.count(vfStream_))
processViewfinder(buffers[vfStream_]);
+ if (buffers.count(rawStream_))
+ processRaw(buffers[rawStream_]);
+
/*
* Return buffers so they can be reused. No processing involving
* a buffer can happen after they are returned to the free list.
@@ -618,6 +642,61 @@ void MainWindow::processViewfinder(FrameBuffer *buffer)
}
}
+void MainWindow::processRaw(FrameBuffer *raw)
+{
+ /* TODO: Should write a DNG file instead of a .raw and .jpeg file. */
+
+ unsigned int seq = raw->metadata().sequence;
+ std::string filename;
+ int fd, ret = 0;
+ size_t pos;
+
+ /* Write .raw */
+ filename = defaultPath_.toStdString() + "/raw-#.raw";
+ pos = filename.find_first_of('#');
+ if (pos != std::string::npos) {
+ std::stringstream ss;
+ ss << std::setw(6) << std::setfill('0') << seq;
+ filename.replace(pos, 1, ss.str());
+ }
+ qInfo() << "Saving" << filename.c_str();
+
+ 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);
+ if (fd == -1) {
+ qWarning() << "Failed to open raw output file";
+ return;
+ }
+
+ const MappedBuffer &info = mappedBuffers_[raw];
+ ret = ::write(fd, info.memory, info.size);
+ if (ret < 0) {
+ ret = -errno;
+ qWarning() << "write error: " << strerror(-ret);
+ } else if (ret != (int)info.size) {
+ qWarning() << "write error: only " << ret
+ << " bytes written instead of " << info.size;
+ }
+
+ ::close(fd);
+
+ /* Write scaled thumbnail .jpeg */
+ filename = defaultPath_.toStdString() + "/raw-#.jpeg";
+ pos = filename.find_first_of('#');
+ if (pos != std::string::npos) {
+ std::stringstream ss;
+ ss << std::setw(6) << std::setfill('0') << seq;
+ filename.replace(pos, 1, ss.str());
+ }
+ qInfo() << "Saving" << filename.c_str();
+
+ QImage image = viewfinder_->getCurrentImage().scaledToHeight(640);
+ QImageWriter writer(QString::fromUtf8(filename.c_str()));
+ writer.setQuality(95);
+ writer.write(image);
+}
+
void MainWindow::queueRequest(FrameBuffer *buffer)
{
Request *request = camera_->createRequest();
@@ -628,5 +707,18 @@ void MainWindow::queueRequest(FrameBuffer *buffer)
request->addBuffer(vfStream_, buffer);
+ if (captureRaw_) {
+ QMutexLocker locker(&mutex_);
+
+ if (freeBuffers_[rawStream_].isEmpty()) {
+ qWarning() << "Raw stream buffer empty";
+ return;
+ }
+
+ request->addBuffer(rawStream_,
+ freeBuffers_[rawStream_].dequeue());
+ captureRaw_ = false;
+ }
+
camera_->queueRequest(request);
}
diff --git a/src/qcam/main_window.h b/src/qcam/main_window.h
index 580bcac146fabe07..37a1d95351e144e0 100644
--- a/src/qcam/main_window.h
+++ b/src/qcam/main_window.h
@@ -55,6 +55,7 @@ private Q_SLOTS:
void toggleCapture(bool start);
void saveViewfinder();
+ void saveRaw();
void queueRequest(FrameBuffer *buffer);
@@ -70,10 +71,12 @@ private:
void requestComplete(Request *request);
void processCapture();
void processViewfinder(FrameBuffer *buffer);
+ void processRaw(FrameBuffer *raw);
/* UI elements */
QToolBar *toolbar_;
QAction *startStopAction_;
+ QAction *saveRaw_;
ViewFinder *viewfinder_;
QIcon iconPlay_;
@@ -97,6 +100,7 @@ private:
/* Capture state, buffers queue and statistics */
bool isCapturing_;
bool saveViewfinder_;
+ bool captureRaw_;
Stream *vfStream_;
Stream *rawStream_;
std::map<Stream *, QQueue<FrameBuffer *>> freeBuffers_;
--
2.26.0
More information about the libcamera-devel
mailing list