qt - 使用 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。我错过了什么?
解决方案
好的,所以我找到了这个问题的答案。实际上问题在于 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);
}
}
这解决了我的问题。
推荐阅读
- php - 在自定义帖子类型中使用 ACF 复选框字段来过滤不同自定义帖子类型的结果
- android - 带有数据绑定的 Android 分页库
- uml - UML 中的模型“汽车必须由个人或公司拥有”
- node.js - 如何批量加载 Firebase EqualTo() 查询?
- php - 具有 Passport API 身份验证的 API 更新端点
- android - 启动 APK 安装程序 Kitkat
- java - 如何解决 ClassNotFoundException:com.beust.jcommander.ParameterException
- scala - 为什么一个演员要开始两次?
- javascript - 使用 MochaJS 在 setInterval() 中测试对外部函数的回调
- java - 通过蓝牙 (Android-Studio) 向 OBD-ii 设备发送数据时应用程序崩溃