diff options
author | Laurent Pinchart <laurent.pinchart@ideasonboard.com> | 2020-03-23 02:34:36 +0200 |
---|---|---|
committer | Laurent Pinchart <laurent.pinchart@ideasonboard.com> | 2020-03-24 10:34:08 +0200 |
commit | 5816c0c38e2a7dce1bcbf88f9fdcc330358eea8d (patch) | |
tree | adde4d8b21ea218f3d7e6500e8a9dc1fe6376600 /src/qcam/viewfinder.cpp | |
parent | ac828f937e5426d48f996a29e70ff1a6ab5c85e6 (diff) |
qcam: viewfinder: Avoid memory copy when conversion isn't needed
If the frame buffer format is identical to the display format, the
viewfinder still invokes the converter to perform what is essentially a
slow memcpy(). Make it possible to skip that operation by creating a
QImage referencing the buffer memory instead. A reference to the frame
buffer is kept internally, and released when the next buffer is queued,
pushing the current one out.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
Diffstat (limited to 'src/qcam/viewfinder.cpp')
-rw-r--r-- | src/qcam/viewfinder.cpp | 74 |
1 files changed, 57 insertions, 17 deletions
diff --git a/src/qcam/viewfinder.cpp b/src/qcam/viewfinder.cpp index 31b358da..3f984efb 100644 --- a/src/qcam/viewfinder.cpp +++ b/src/qcam/viewfinder.cpp @@ -7,6 +7,8 @@ #include "viewfinder.h" +#include <utility> + #include <QImage> #include <QImageWriter> #include <QMutexLocker> @@ -16,7 +18,7 @@ #include "format_converter.h" ViewFinder::ViewFinder(QWidget *parent) - : QWidget(parent) + : QWidget(parent), buffer_(nullptr) { } @@ -27,17 +29,23 @@ ViewFinder::~ViewFinder() int ViewFinder::setFormat(const libcamera::PixelFormat &format, const QSize &size) { - int ret; + image_ = QImage(); - ret = converter_.configure(format, size); - if (ret < 0) - return ret; + /* + * If format conversion is needed, configure the converter and allocate + * the destination image. + */ + if (format != DRM_FORMAT_ARGB8888) { + int ret = converter_.configure(format, size); + if (ret < 0) + return ret; + + image_ = QImage(size, QImage::Format_RGB32); + } format_ = format; size_ = size; - image_ = QImage(size_, QImage::Format_RGB32); - updateGeometry(); return 0; } @@ -49,19 +57,51 @@ void ViewFinder::render(libcamera::FrameBuffer *buffer, MappedBuffer *map) return; } - QMutexLocker locker(&mutex_); - - /* - * \todo We're not supposed to block the pipeline handler thread - * for long, implement a better way to save images without - * impacting performances. - */ + unsigned char *memory = static_cast<unsigned char *>(map->memory); + size_t size = buffer->metadata().planes[0].bytesused; + + { + QMutexLocker locker(&mutex_); + + if (format_ == DRM_FORMAT_ARGB8888) { + /* + * If the frame format is identical to the display + * format, create a QImage that references the frame + * and store a reference to the frame buffer. The + * previously stored frame buffer, if any, will be + * released. + * + * \todo Get the stride from the buffer instead of + * computing it naively + */ + image_ = QImage(memory, size_.width(), size_.height(), + size / size_.height(), QImage::Format_RGB32); + std::swap(buffer, buffer_); + } else { + /* + * Otherwise, convert the format and release the frame + * buffer immediately. + */ + converter_.convert(memory, size, &image_); + } + } - converter_.convert(static_cast<unsigned char *>(map->memory), - buffer->metadata().planes[0].bytesused, &image_); update(); - renderComplete(buffer); + if (buffer) + renderComplete(buffer); +} + +void ViewFinder::stop() +{ + image_ = QImage(); + + if (buffer_) { + renderComplete(buffer_); + buffer_ = nullptr; + } + + update(); } QImage ViewFinder::getCurrentImage() |