mirror of
https://git.libcamera.org/libcamera/libcamera.git
synced 2025-07-21 11:25:08 +03:00
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>
This commit is contained in:
parent
ac828f937e
commit
5816c0c38e
3 changed files with 60 additions and 16 deletions
|
@ -416,6 +416,8 @@ void MainWindow::stopCapture()
|
||||||
if (!isCapturing_)
|
if (!isCapturing_)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
viewfinder_->stop();
|
||||||
|
|
||||||
int ret = camera_->stop();
|
int ret = camera_->stop();
|
||||||
if (ret)
|
if (ret)
|
||||||
qInfo() << "Failed to stop capture";
|
qInfo() << "Failed to stop capture";
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
|
|
||||||
#include "viewfinder.h"
|
#include "viewfinder.h"
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#include <QImage>
|
#include <QImage>
|
||||||
#include <QImageWriter>
|
#include <QImageWriter>
|
||||||
#include <QMutexLocker>
|
#include <QMutexLocker>
|
||||||
|
@ -16,7 +18,7 @@
|
||||||
#include "format_converter.h"
|
#include "format_converter.h"
|
||||||
|
|
||||||
ViewFinder::ViewFinder(QWidget *parent)
|
ViewFinder::ViewFinder(QWidget *parent)
|
||||||
: QWidget(parent)
|
: QWidget(parent), buffer_(nullptr)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,17 +29,23 @@ ViewFinder::~ViewFinder()
|
||||||
int ViewFinder::setFormat(const libcamera::PixelFormat &format,
|
int ViewFinder::setFormat(const libcamera::PixelFormat &format,
|
||||||
const QSize &size)
|
const QSize &size)
|
||||||
{
|
{
|
||||||
int ret;
|
image_ = QImage();
|
||||||
|
|
||||||
ret = converter_.configure(format, size);
|
/*
|
||||||
if (ret < 0)
|
* If format conversion is needed, configure the converter and allocate
|
||||||
return ret;
|
* 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;
|
format_ = format;
|
||||||
size_ = size;
|
size_ = size;
|
||||||
|
|
||||||
image_ = QImage(size_, QImage::Format_RGB32);
|
|
||||||
|
|
||||||
updateGeometry();
|
updateGeometry();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -49,19 +57,51 @@ void ViewFinder::render(libcamera::FrameBuffer *buffer, MappedBuffer *map)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QMutexLocker locker(&mutex_);
|
unsigned char *memory = static_cast<unsigned char *>(map->memory);
|
||||||
|
size_t size = buffer->metadata().planes[0].bytesused;
|
||||||
|
|
||||||
/*
|
{
|
||||||
* \todo We're not supposed to block the pipeline handler thread
|
QMutexLocker locker(&mutex_);
|
||||||
* for long, implement a better way to save images without
|
|
||||||
* impacting performances.
|
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();
|
update();
|
||||||
|
|
||||||
renderComplete(buffer);
|
if (buffer)
|
||||||
|
renderComplete(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ViewFinder::stop()
|
||||||
|
{
|
||||||
|
image_ = QImage();
|
||||||
|
|
||||||
|
if (buffer_) {
|
||||||
|
renderComplete(buffer_);
|
||||||
|
buffer_ = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
QImage ViewFinder::getCurrentImage()
|
QImage ViewFinder::getCurrentImage()
|
||||||
|
|
|
@ -36,6 +36,7 @@ public:
|
||||||
|
|
||||||
int setFormat(const libcamera::PixelFormat &format, const QSize &size);
|
int setFormat(const libcamera::PixelFormat &format, const QSize &size);
|
||||||
void render(libcamera::FrameBuffer *buffer, MappedBuffer *map);
|
void render(libcamera::FrameBuffer *buffer, MappedBuffer *map);
|
||||||
|
void stop();
|
||||||
|
|
||||||
QImage getCurrentImage();
|
QImage getCurrentImage();
|
||||||
|
|
||||||
|
@ -52,6 +53,7 @@ private:
|
||||||
libcamera::PixelFormat format_;
|
libcamera::PixelFormat format_;
|
||||||
QSize size_;
|
QSize size_;
|
||||||
|
|
||||||
|
libcamera::FrameBuffer *buffer_;
|
||||||
QImage image_;
|
QImage image_;
|
||||||
QMutex mutex_; /* Prevent concurrent access to image_ */
|
QMutex mutex_; /* Prevent concurrent access to image_ */
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue