QT QLabel setPixmap from QAbstractVideoSurface

Multi tool use
QT QLabel setPixmap from QAbstractVideoSurface
I'm implementing my own class for probing video frames from QCamera under windows. It's a subclass of QAbstractVideoSurface. So, my probe generates QPixmap which I tried to draw on QLabel (as viewfinder). And I've got segmentation fault on QLabel setPixmap call.
I'm sure my Qpixmap is well made, because I can save it on the disk with a save(). My QLabel is inititalized and works well, because I can load QPixmap from the disk and set it to QLabel. I guess there is problem with a format of a pixmap, but can't clue how to correct it :(
My code
frameprobe.h
#ifndef FRAMEPROBE_H
#define FRAMEPROBE_H
#include <QAbstractVideoSurface>
#include <QList>
#include <QPixmap>
class FrameProbe : public QAbstractVideoSurface
{
Q_OBJECT
public:
explicit FrameProbe(QObject *parent = 0);
QList<QVideoFrame::PixelFormat> supportedPixelFormats(QAbstractVideoBuffer::HandleType handleType) const;
bool present(const QVideoFrame &frame);
signals:
void frameAvailable(QImage frame);
void frameReady(QPixmap frame);
public slots:
};
#endif // FRAMEPROBE_H
frameprobe.cpp
#include "frameprobe.h"
FrameProbe::FrameProbe(QObject *parent) :
QAbstractVideoSurface(parent)
{
}
QList<QVideoFrame::PixelFormat> FrameProbe::supportedPixelFormats(QAbstractVideoBuffer::HandleType handleType) const
{
Q_UNUSED(handleType);
return QList<QVideoFrame::PixelFormat>()
<< QVideoFrame::Format_ARGB32
<< QVideoFrame::Format_ARGB32_Premultiplied
<< QVideoFrame::Format_RGB32
<< QVideoFrame::Format_RGB24
<< QVideoFrame::Format_RGB565
<< QVideoFrame::Format_RGB555
<< QVideoFrame::Format_ARGB8565_Premultiplied
<< QVideoFrame::Format_BGRA32
<< QVideoFrame::Format_BGRA32_Premultiplied
<< QVideoFrame::Format_BGR32
<< QVideoFrame::Format_BGR24
<< QVideoFrame::Format_BGR565
<< QVideoFrame::Format_BGR555
<< QVideoFrame::Format_BGRA5658_Premultiplied
<< QVideoFrame::Format_AYUV444
<< QVideoFrame::Format_AYUV444_Premultiplied
<< QVideoFrame::Format_YUV444
<< QVideoFrame::Format_YUV420P
<< QVideoFrame::Format_YV12
<< QVideoFrame::Format_UYVY
<< QVideoFrame::Format_YUYV
<< QVideoFrame::Format_NV12
<< QVideoFrame::Format_NV21
<< QVideoFrame::Format_IMC1
<< QVideoFrame::Format_IMC2
<< QVideoFrame::Format_IMC3
<< QVideoFrame::Format_IMC4
<< QVideoFrame::Format_Y8
<< QVideoFrame::Format_Y16
<< QVideoFrame::Format_Jpeg
<< QVideoFrame::Format_CameraRaw
<< QVideoFrame::Format_AdobeDng;
}
bool FrameProbe::present(const QVideoFrame &frame)
{
if (frame.isValid()) {
QVideoFrame cloneFrame(frame);
cloneFrame.map(QAbstractVideoBuffer::ReadOnly);
QImage::Format imageFormat = QVideoFrame::imageFormatFromPixelFormat(cloneFrame.pixelFormat());
const QImage image(cloneFrame.bits(),
cloneFrame.width(),
cloneFrame.height(),
imageFormat);
emit frameAvailable(image);
emit frameReady(QPixmap::fromImage(image));
cloneFrame.unmap();
return true;
}
return false;
}
init code
QCamera * MyCamera= new QCamera(CameraDeviceName);
MyCamera->setCaptureMode( QCamera::CaptureVideo );
Label = new QLabel();
Label->setText("Label");
FrameProbe * VSurface = new FrameProbe();
MyCamera->setViewfinder(VSurface);
connect(VSurface, SIGNAL(frameAvailable(QImage)), this, SLOT(video_probed(QImage)));
connect(VSurface, SIGNAL(frameReady(QPixmap)), this,SLOT(video_forward(QPixmap)));
ui->gridLayout->addWidget(Label,0,0);
MyCamera->start();
and slots
void MainWindow::video_probed(QImage InVideoFrame){
FramesProbed++;
std::cout<<FramesProbed<<std::endl;
}
void MainWindow::video_forward(QPixmap InVideoFrame){
Label->setPixmap(InVideoFrame); //<<<<<<<<< Segmentation Fault here
}
If I change video_forward slot to something like this
void MainWindow::video_forward(QPixmap InVideoFrame){
InVideoFrame.save("c:\temp\a.jpg",0,-1);
QPixmap a;
a.load("c:\temp\a.jpg");
Label->setPixmap(a);
}
it work. Of course slow :) but work...
PS: In the FrameProbe::present image have QImage::Format_RGB32 format.
The problem is likely with implicit sharing of QPixmap internal data: doc.qt.io/qt-5/implicit-sharing.html. See video_forward function and there you have QPixmap object destroyed while leaving the function and it is shared with label. Also avoid sending objects by value as you do unless you sure. Better use const T& as Qt does if possible.
– Alexander V
Jul 1 at 16:24
@AlexanderV yes, it was my problem. Any actions which made a real copy of the Pixmap solves the problem.
– Abbey Road
Jul 3 at 10:43
1 Answer
1
Solution:
bool FrameProbe::present(const QVideoFrame &frame)
{
...
emit frameAvailable(image.copy());
...
}
// slot video_probed
connect(VSurface, &FrameProbe::frameAvailable, [=](QImage a){
Label->setPixmap(QPixmap::fromImage(a));
});
So why crashed:
Because you are using below to construct QImage
:
QImage
QImage::QImage(uchar *data, int width, int height, Format format,
QImageCleanupFunction cleanupFunction = Q_NULLPTR, void *cleanupInfo =
Q_NULLPTR)
The first param data
is set from cloneFrame
and it will be released after cloneFrame.unmap();
. data
won't exist in the QLabel::paintEvent
stack.
data
cloneFrame
cloneFrame.unmap();
data
QLabel::paintEvent
Thank you! This is just sandbox, not a real application. I just separate QImage for later image processing and QPixmap for display as viewfinder in different slots.
– Abbey Road
Jul 2 at 10:48
@AbbeyRoad I see, The solution sending
image.copy()
didn't work?– Jiu
Jul 3 at 0:20
image.copy()
image.copy() work like a charm. And any other solutions which made a real copy of data (e.g not implicit shared copy).
– Abbey Road
Jul 3 at 10:41
@AbbeyRoad
image.copy()
is copy the data of QImage
...I didn't see other ways...– Jiu
yesterday
image.copy()
QImage
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
Have you tried using valgrind? It is very helpful to see exactly what resource was accessed while not allocated.
– Benjamin Barrois
Jul 1 at 10:05