【发布时间】:2018-12-09 20:30:09
【问题描述】:
我正在实现自己的类,用于在 Windows 下探测来自 QCamera 的视频帧。它是 QAbstractVideoSurface 的子类。因此,我的探针生成了我试图在 QLabel(作为取景器)上绘制的 QPixmap。而且我在 QLabel setPixmap 调用时遇到了分段错误。
我确信我的 Qpixmap 制作精良,因为我可以使用 save() 将它保存在磁盘上。我的 QLabel 已初始化并且运行良好,因为我可以从磁盘加载 QPixmap 并将其设置为 QLabel。我猜像素图的格式有问题,但不知道如何纠正它:(
我的代码
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;
}
初始化代码
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();
和插槽
void MainWindow::video_probed(QImage InVideoFrame){
FramesProbed++;
std::cout<<FramesProbed<<std::endl;
}
void MainWindow::video_forward(QPixmap InVideoFrame){
Label->setPixmap(InVideoFrame); //<<<<<<<<< Segmentation Fault here
}
如果我将 video_forward 插槽更改为这样的内容
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);
}
它工作。当然慢 :) 但工作......
PS:在FrameProbe::present图像中有QImage::Format_RGB32格式。
【问题讨论】:
-
你试过使用 valgrind 吗?在未分配的情况下准确查看访问了哪些资源非常有帮助。
-
问题可能与 QPixmap 内部数据的隐式共享有关:doc.qt.io/qt-5/implicit-sharing.html。查看 video_forward 函数,您在离开该函数时已销毁 QPixmap 对象并与标签共享。除非您确定,否则请避免按值发送对象。如果可能,最好像 Qt 那样使用 const T&。
-
@AlexanderV 是的,这是我的问题。任何制作像素图真实副本的操作都可以解决问题。