[英]Painting a QVideoFrame on a QVideoWidget with QT6
I'd like to process the stream of my webcam frame by frame with QT6.我想用 QT6 逐帧处理我的网络摄像头的 stream。 I've checked the internet but since QTMultimedia was heavily reworked with QT6, and since QT6 is pretty new, all the documentation/questions available are outdated.
我已经检查过互联网,但由于 QTMultimedia 使用 QT6 进行了大量重新设计,并且由于 QT6 相当新,所有可用的文档/问题都已过时。
So, In order to achieve my goal, I'm using a QMediaCaptureSession
with a camera set on QMediaDevices::defaultVideoInput()
.所以,为了实现我的目标,我使用
QMediaCaptureSession
和QMediaDevices::defaultVideoInput()
上的摄像头。 I checked that this was working by setting the video output of the QMediaCaptureSession
to a QVideoWidget
with m_session.setVideoOutput(ui->videowidget);
我通过使用
m_session.setVideoOutput(ui->videowidget);
将QVideoWidget
的视频 output 设置为QMediaCaptureSession
来检查这是否有效。 , and it's working fine, except that I can't process the frames (basically, it's rendering my webcam on the QVideoWidget
). ,它工作正常,除了我无法处理帧(基本上,它在
QVideoWidget
上渲染我的网络摄像头)。
Now, to process the frames, I have to use a QVideoSink
as far as I understand the documentation here and there .现在,要处理帧,据我了解这里和 那里的文档,我必须使用
QVideoSink
。 So I replaced m_session.setVideoOutput(ui->videowidget);
所以我替换
m_session.setVideoOutput(ui->videowidget);
with m_session.setVideoSink(&mysink);
与
m_session.setVideoSink(&mysink);
, where mysink
is a QVideoSink
. ,其中
mysink
是QVideoSink
。
Then, since I want to process the frames, I'm connecting the videoFrameChanged
signal of mysink
to a function processVideoFrame
where I want to do 2 things:然后,因为我想处理帧,所以我将 mysink 的
videoFrameChanged
信号连接到processVideoFrame
mysink
我想做两件事:
ui->videowidget
ui->videowidget
This is the point where I'm struggling.这就是我苦苦挣扎的地方。 I do not understand how to use the
paint
function of the class QVideoFrame
to render the processed frame on the QVideoWidget
.我不明白如何使用 class QVideoFrame 的
paint
function在QVideoFrame
上渲染处理后的QVideoWidget
。 More precisely:更确切地说:
QPainter
.QPainter
。 I tried a straightforward new QPainter(ui->videowidget)
but it ends up in a QWidget::paintEngine: Should no longer be called
exception and nothing is renderednew QPainter(ui->videowidget)
但它最终出现在QWidget::paintEngine: Should no longer be called
异常并且没有渲染任何内容rect
of QVideoFrame::paint
?QVideoFrame::paint
的第二个参数rect
实际代表什么? I made a MWE, code is below.我做了一个MWE,代码如下。
mwe_videosinkpainting.h mwe_videosinkpainting.h
#ifndef MWE_VIDEOSINKPAINTING_H
#define MWE_VIDEOSINKPAINTING_H
#include <QMainWindow>
#include <QMediaCaptureSession>
#include <QMediaDevices>
#include <QCamera>
#include <QVideoSink>
#include <QPainter>
QT_BEGIN_NAMESPACE
namespace Ui { class MWE_VideoSinkPainting; }
QT_END_NAMESPACE
class MWE_VideoSinkPainting : public QMainWindow
{
Q_OBJECT
public:
MWE_VideoSinkPainting(QWidget *parent = nullptr);
~MWE_VideoSinkPainting();
private slots:
void processVideoFrame();
private:
Ui::MWE_VideoSinkPainting *ui;
QVideoSink mysink;
QMediaCaptureSession m_session;
QScopedPointer<QCamera> m_camera;
};
#endif // MWE_VIDEOSINKPAINTING_H
mwe_videosinking.cpp mwe_videosinking.cpp
#include "mwe_videosinkpainting.h"
#include "ui_mwe_videosinkpainting.h"
MWE_VideoSinkPainting::MWE_VideoSinkPainting(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MWE_VideoSinkPainting)
{
ui->setupUi(this);
m_camera.reset(new QCamera(QMediaDevices::defaultVideoInput()));
m_session.setCamera(m_camera.data());
//m_session.setVideoOutput(ui->videowidget);
connect(&mysink, &QVideoSink::videoFrameChanged, this, &MWE_VideoSinkPainting::processVideoFrame);
m_session.setVideoSink(&mysink);
m_camera->start();
}
MWE_VideoSinkPainting::~MWE_VideoSinkPainting()
{
delete ui;
}
void MWE_VideoSinkPainting::processVideoFrame()
{
QVideoFrame videoframe = mysink.videoFrame();
if(videoframe.map(QVideoFrame::ReadOnly))
{
//This is the part I'm struggling to understand and achieve
videoframe.paint(new QPainter(ui->videowidget), QRectF(0.0f,0.0f,100.0f,100.0f), QVideoFrame::PaintOptions());
videoframe.unmap();
}
}
main.cpp主文件
#include "mwe_videosinkpainting.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MWE_VideoSinkPainting w;
w.show();
return a.exec();
}
ui_mwe_videosinkpainting.h (just so that you have the whole code, it has no value for the question) ui_mwe_videosinkpainting.h(只是为了让你拥有整个代码,它对这个问题没有价值)
#ifndef UI_MWE_VIDEOSINKPAINTING_H
#define UI_MWE_VIDEOSINKPAINTING_H
#include <QtCore/QVariant>
#include <QtMultimediaWidgets/QVideoWidget>
#include <QtWidgets/QApplication>
#include <QtWidgets/QGridLayout>
#include <QtWidgets/QHBoxLayout>
#include <QtWidgets/QMainWindow>
#include <QtWidgets/QMenuBar>
#include <QtWidgets/QStatusBar>
#include <QtWidgets/QWidget>
QT_BEGIN_NAMESPACE
class Ui_MWE_VideoSinkPainting
{
public:
QWidget *centralwidget;
QGridLayout *gridLayout;
QVideoWidget *videowidget;
QHBoxLayout *horizontalLayout;
QMenuBar *menubar;
QStatusBar *statusbar;
void setupUi(QMainWindow *MWE_VideoSinkPainting)
{
if (MWE_VideoSinkPainting->objectName().isEmpty())
MWE_VideoSinkPainting->setObjectName(QString::fromUtf8("MWE_VideoSinkPainting"));
MWE_VideoSinkPainting->resize(800, 600);
centralwidget = new QWidget(MWE_VideoSinkPainting);
centralwidget->setObjectName(QString::fromUtf8("centralwidget"));
gridLayout = new QGridLayout(centralwidget);
gridLayout->setObjectName(QString::fromUtf8("gridLayout"));
videowidget = new QVideoWidget(centralwidget);
videowidget->setObjectName(QString::fromUtf8("videowidget"));
horizontalLayout = new QHBoxLayout(videowidget);
horizontalLayout->setObjectName(QString::fromUtf8("horizontalLayout"));
gridLayout->addWidget(videowidget, 0, 0, 1, 1);
MWE_VideoSinkPainting->setCentralWidget(centralwidget);
menubar = new QMenuBar(MWE_VideoSinkPainting);
menubar->setObjectName(QString::fromUtf8("menubar"));
menubar->setGeometry(QRect(0, 0, 800, 21));
MWE_VideoSinkPainting->setMenuBar(menubar);
statusbar = new QStatusBar(MWE_VideoSinkPainting);
statusbar->setObjectName(QString::fromUtf8("statusbar"));
MWE_VideoSinkPainting->setStatusBar(statusbar);
retranslateUi(MWE_VideoSinkPainting);
QMetaObject::connectSlotsByName(MWE_VideoSinkPainting);
} // setupUi
void retranslateUi(QMainWindow *MWE_VideoSinkPainting)
{
MWE_VideoSinkPainting->setWindowTitle(QCoreApplication::translate("MWE_VideoSinkPainting", "MWE_VideoSinkPainting", nullptr));
} // retranslateUi
};
namespace Ui {
class MWE_VideoSinkPainting: public Ui_MWE_VideoSinkPainting {};
} // namespace Ui
QT_END_NAMESPACE
#endif // UI_MWE_VIDEOSINKPAINTING_H
The answer is quite straightforward: you can use setVideoSink
AND setVideoOutput
.答案非常简单:您可以使用
setVideoSink
和setVideoOutput
。
The code I gave in OP is good, you just have to uncomment setVideoOutput(ui->videowidget);
我在 OP 中提供的代码很好,您只需取消注释
setVideoOutput(ui->videowidget);
of mwe_videosinking.cpp and to call setVideoSink
BEFORE calling setVideoOutput
mwe_videosinking.cpp并在调用
setVideoSink
之前调用setVideoOutput
Since I cannot format code in a comment...由于我无法在评论中格式化代码...
So, you mean change this...所以,你的意思是改变这个...
ui->setupUi(this);
m_camera.reset(new QCamera(QMediaDevices::defaultVideoInput()));
m_session.setCamera(m_camera.data());
//m_session.setVideoOutput(ui->videowidget);
connect(&mysink, &QVideoSink::videoFrameChanged, this, &MWE_VideoSinkPainting::processVideoFrame);
m_session.setVideoSink(&mysink);
m_camera->start();
...to this? ……到这个?
ui->setupUi(this);
m_camera.reset(new QCamera(QMediaDevices::defaultVideoInput()));
m_session.setCamera(m_camera.data());
m_session.setVideoSink(&mysink);
m_session.setVideoOutput(ui->videowidget);
connect(&mysink, &QVideoSink::videoFrameChanged, this, &MWE_VideoSinkPainting::processVideoFrame);
m_camera->start();
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.