首页 > 解决方案 > 使用 QML 操作 QCamera

问题描述

我正在尝试使用探针从 QCamera 获取 QVideoFrame 来处理它,同时我需要将内容显示给 QML VideoOutput。这就是我所做的:

#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;
};

FrameProvider 在其 getFrames 方法中从 QVideoProbe 接收帧并对其进行处理,然后将其发送到它的 present() 方法以在 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);
}

在 QML 中,我只是将其显示为,

VideoOutput {
        source: frameProvider
        width: 320
        height: 480
    }

我遵循了QT 文档这个例子那个例子。我收到 getFrame 正在接收探测帧但 QML 窗口完全空白的信号。如果平台很重要,我会在 Arch Linux 上运行 KDE Plasma。我错过了什么?

标签: qtqmlqcamera

解决方案


好的,所以我找到了这个问题的答案。实际上问题在于 QCamera 和 VideoOutput 之间的格式转换。我刚刚在 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);
        }
    }

并在有新框架可用时调用它进行转换,例如,

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);
        }
    }

这解决了我的问题。


推荐阅读