I am trying to get QVideoFrame s from QCamera using probe to process it while at the same time I need to show the content to QML VideoOutput. This is what I have done:
#include <QObject>
#include <QAbstractVideoSurface>
#include <QVideoSurfaceFormat>
class FrameProvider: public QObject {
Q_OBJECT
Q_PROPERTY(QAbstractVideoSurface *videoSurface READ getVideoSurface WRITE setVideoSurface NOTIFY videoSurfaceChanged)
public:
FrameProvider(QObject *parent = nullptr)
: QObject(parent) {}
QAbstractVideoSurface* getVideoSurface() const { return m_surface; }
void setVideoSurface(QAbstractVideoSurface *surface) {
if (m_surface != surface && m_surface && m_surface->isActive()) {
m_surface->stop();
}
m_surface = surface;
if (m_surface && m_format.isValid()) {
m_format = m_surface->nearestFormat(m_format);
m_surface->start(m_format);
}
emit videoSurfaceChanged();
}
public slots:
void setFrame(const QVideoFrame &frame) {
if (m_surface) {
//do processing
m_surface->present(frame);
}
}
signals:
void videoSurfaceChanged();
private:
QAbstractVideoSurface *m_surface = NULL;
QVideoSurfaceFormat m_format;
};
The FrameProvider receives the frames from QVideoProbe in its getFrames method and processes it and then sends it to its present() method for displaying in QML.
main(...) {
//some code
auto ctxt = engine.rootContext();
auto camera = new QCamera();
camera->setCaptureMode(QCamera::CaptureVideo);
FrameProvider fp;
auto probe = new QVideoProbe();
if(probe->setSource(camera)) {
QObject::connect(probe, SIGNAL(videoFrameProbed(QVideoFrame)), &fp, SLOT(setFrame(QVideoFrame)));
}
ctxt->setContextProperty("frameProvider", &fp);
camera->start();
engine.load(url);
}
In QML, I simply display it as,
VideoOutput {
source: frameProvider
width: 320
height: 480
}
I followed the QT Documentation, this example and that example. I get signals that getFrame is receiving probed frames but QML window is completely blank. I am running KDE Plasma on top of Arch Linux, if the platform matters. What am I missing?
Ok so I found an answer for this problem. Actually the problem is with the format conversion between QCamera and VideoOutput. I just added this code in FrameProvider,
void setFormat(int width, int height, QVideoFrame::PixelFormat frameFormat) {
QSize size(width, height);
QVideoSurfaceFormat format(size, frameFormat);
m_format = format;
if (m_surface) {
if (m_surface->isActive())
m_surface->stop();
m_format = m_surface->nearestFormat(m_format);
m_surface->start(m_format);
}
}
and call it for conversion whenever a new frame is made available like,
void setFrame(const QVideoFrame &frame) {
if (m_surface) {
//do other processing with the received frame
...
//after you are done with processing
setFormat(frame.width(), frame.height(), frame.pixelFormat());
m_surface->present(frame);
}
}
And that solved my problem.