简体   繁体   中英

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.

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(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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM