Mirage
Mirage

Reputation: 89

How use Camera in Android and Desktop with Qt

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 :

  1. QQuickView with containers to display QML Camera don't work Android
  2. I tried this : Qt QML Camera to C++ QImage on Android But I don't get frame.
  3. I also saw this : http://www.programering.com/a/MTN3IjMwATQ.html / http://blog.csdn.net/kl222/article/details/23187693 But It's not work with Android

Upvotes: 2

Views: 4596

Answers (1)

Mirage
Mirage

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

Related Questions