Reputation: 89
I would like to display and get frame of Camera on my Qt robot project who use QWidgets/C++, on Desktop and Android. Camera work in programs with only QML but my actual project need to use QWidgets in C++.
I tried various way :
Upvotes: 2
Views: 4596
Reputation: 89
I find a answer to my problem (The goal is to get frame from camera and display on QWidget on Android and Windows)
First in QML : get a camera and filter :
Item {
signal submitFrame(var img)//used to send QImage to C++ after filter process
Camera {
id: camera
}
MyFilter {
id: filter
onFinished: submitFrame(result)
}
VideoOutput {
source: camera
filters: [ filter ]
}
}
QAbstractVideoFilter subclass :
class MyFilter : public QAbstractVideoFilter
{
Q_OBJECT
public:
MyFilter();
QVideoFilterRunnable *createFilterRunnable();
signals:
void finished(const QVariant& result); //send QImage got to QML
public slots:
};
QVideoFilterRunnable subclass :
class MyFilterRunnable : public QVideoFilterRunnable
{
public:
MyFilterRunnable(MyFilter *filter);
~MyFilterRunnable();
QVideoFrame run(QVideoFrame *input, const QVideoSurfaceFormat &surfaceFormat, RunFlags flags) Q_DECL_OVERRIDE;
private:
MyFilter *m_filter;
};
Process frame (Convert QVideoframe to QImage)
QVideoFrame run(QVideoFrame *input, const QVideoSurfaceFormat &surfaceFormat, RunFlags flags) Q_DECL_OVERRIDE;
//On Android
if(frame->handleType() == QAbstractVideoBuffer::GLTextureHandle){
/* ...
Need treatment with OpenGL or other to "convert" frame to QImage.
see here : http://code.qt.io/cgit/qt/qtmultimedia.git/tree/examples/multimedia/video/qmlvideofilter_opencl in file rgbframehelper.h
... */
emit m_filter->finished(QVariant (imgToDisplay));// send QImage got to QML
}
//On Windows
else{
//easy convert VideoFrame to QImage
QImage::Format format = VideoFrame::imageFormatFromPixelFormat(frame->pixelFormat());
if (fmt != QImage::Format_Invalid){
QImage img=QImage(frame->bits(), frame->width(), frame->height(), format);
QImage imgToDisplay = img.convertToFormat(QImage::Format_RGB888);
emit m_filter->finished(QVariant(imgToDisplay));// send QImage got to QML
}
}
Now on C++, MainWindow :
qmlRegisterType<MyFilter>("my.uri", 1, 0, "MyFilter");
//load QML
QQuickView *view=new QQuickView();
view->setSource(QUrl("qrc:///main.qml"));
view->show();
//connect to get QImage as QVariant from QML to this C++ class
QObject *topLevel =view->rootObject();
QObject::connect(topLevel, SIGNAL(submitFrame(const QVariant &)),this, SLOT(handleFrame(const QVariant &)));
And display slot :
void MainWindow::handleFrame(const QVariant &in)
{
//cast Qvariant =>QImage
QImage image = in.value<QImage>();
// QImage to QPixmap for display
ui->label->setPixmap(QPixmap::fromImage(image));
ui->label->resize(image.size());
ui->label->update();
}
To summarize : QML camera "send" frames to c++ filter. Filter convert frames to QImage and send these QImage to QML as QVariant. From C++ display class, get QVariant with connect and cast to QImage for display on QWidget.
It's certainly not the best way (Android convert frame to QImage is too slow and maybe to much exanche with QML and C++) but It sufficient for my project (I get ~15 fps).
If someone has a better idea, please do share.
Upvotes: 6