QAbstractVideoSurface示例

6

我正在尝试制作一个具有更多功能并为VideoOutput元素提供源的QML相机项,就像这样:

VideoOutput{
    source:mycamera
}
MyCustomCamera{
    id:mycamera
}

在文档中提到

如果您正在扩展自己的C++类以与VideoOutput进行交互,您可以提供一个基于QObject的类,该类具有mediaObject属性,该属性公开了一个派生自QMediaObject的类,该类具有可用的QVideoRendererControl,或者您可以提供一个基于QObject的类,该类具有可写的videoSurface属性,该属性可以接受基于QAbstractVideoSurface的类,并且可以遵循正确的协议将QVideoFrames传递给它。

我尝试给我的对象添加了一个私有属性mediaObject,其类型为QCamera,但似乎QCamera没有QVideoRenderControl(或者是我的问题不知道如何正确使用它)。

无论如何,我需要实现我一开始展示的效果。

否则,是否有人可以给我一个简短的例子,说明什么是“可写的videoSurface属性,可以接受blablabla并遵循正确的协议”?


你找到任何解决方案了吗?像你一样,我也阅读了文档,但无法弄清楚如何实现自定义源。 - Ali Shirvani
一样啊。这边有进展吗?我不确定我应该实现多少个类以及哪些已经实现了。很遗憾我们只有一个段落。 - Xyz
2个回答

8

我无法帮助您解决主要问题,但我可以给您一个videoSurface的使用示例。您可以像这样使用“可写videoSurface”:

我的示例由三个主要步骤组成:

  1. 编写一个具有QAbstactVideoSurface属性的类。此类将是您的视频提供者,可以通过调用其present()函数在VideoOutput上显示帧。

videoadapter.h

#ifndef VIDEOADAPTER_H
#define VIDEOADAPTER_H
#include <QObject>
#include <QAbstractVideoSurface>
#include <QVideoSurfaceFormat>
#include <QTimer>

class VideoAdapter : public QObject
{
  Q_OBJECT
  Q_PROPERTY(QAbstractVideoSurface* videoSurface READ videoSurface WRITE setVideoSurface NOTIFY signalVideoSurfaceChanged)
public:
  explicit VideoAdapter(QObject *parent = nullptr);

  QAbstractVideoSurface *videoSurface() const;
  void setVideoSurface(QAbstractVideoSurface *videoSurface);

signals:
  void signalVideoSurfaceChanged();

private slots:
  void slotTick();

private:
  void startSurface();

private:
  QAbstractVideoSurface *mVideoSurface;
  QVideoSurfaceFormat *mSurfaceFormat;
  QImage *mImage;
  QTimer mTimer;
};

#endif // VIDEOADAPTER_H

videoadapter.cpp

#include "videoadapter.h"
#include <QDebug>

VideoAdapter::VideoAdapter(QObject *parent)
  : QObject(parent), mVideoSurface(nullptr), mSurfaceFormat(nullptr)
{
  mTimer.setInterval(1000);
  connect(&mTimer, &QTimer::timeout, this, &VideoAdapter::slotTick);
}

QAbstractVideoSurface *VideoAdapter::videoSurface() const
{
  return mVideoSurface;
}

void VideoAdapter::setVideoSurface(QAbstractVideoSurface *videoSurface)
{
  if(videoSurface != mVideoSurface)
  {
    mVideoSurface = videoSurface;
    emit signalVideoSurfaceChanged();
    startSurface();

    // This is the test timer that will tick for us to present the image
    // on the video surface
    mTimer.start();
  }
}

void VideoAdapter::slotTick()
{
  QVideoFrame frame(*mImage);
  mVideoSurface->present(frame);
}

void VideoAdapter::startSurface()
{
  mImage = new QImage("../resources/images/test.jpg");
  auto pixelFormat = QVideoFrame::pixelFormatFromImageFormat(mImage->format());
  mSurfaceFormat = new QVideoSurfaceFormat(mImage->size(), pixelFormat);
  if(!mVideoSurface->start(*mSurfaceFormat))
  {
    qDebug() << "Surface couldn't be started!";
  }
}

这个类只加载一个图像文件并使用计时器显示它,但在您的情况下,您将拥有一个帧源,因此您可以更改它以适应您的需求。如果您可以将您的帧转换为QImageQVideoFrame,您可以像这样显示它。

  1. You have to make this class usable in QML. In my case i created an object and made it visible to QML via setting it as a property.

    int main(int argc, char *argv[])
    {
      QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    
      QGuiApplication app(argc, argv);
    
      QQmlApplicationEngine engine;
    
      QQmlDebuggingEnabler enabler;
    
      VideoAdapter adapter;
      // When you do this this object is made visible to QML context with the
      // given name
      engine.rootContext()->setContextProperty("videoAdapter", &adapter);
    
      const QUrl url(QStringLiteral("qrc:/main.qml"));
      QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                       &app, [url](QObject *obj, const QUrl &objUrl) {
          if (!obj && url == objUrl)
              QCoreApplication::exit(-1);
      }, Qt::QueuedConnection);
      engine.load(url);
    
      return app.exec();
    }
    
  2. You give this object to the VideoOutput as source in QML.

    Window {
      visible: true
      width: 640
      height: 480
      color: "black"
      title: qsTr("Video Player")
    
      VideoOutput {
        id: videoPlayer
        anchors.fill: parent
        source: videoAdapter
      }
    }
    

正如我所说的,这个例子很简单,只加载一个图片并周期性地显示那张图片。

这个问题是一个老问题了,你可能已经不再关注它,但希望它至少能帮助其他人。


0

@U.Tuken提供的代码很好,除非我将Q_PROPERTY中属性名称从"videoSurface"更改为其他单词,否则它不起作用。这非常奇怪,因为从Qt的角度来看,"videoSurface"只是一个名称。

此外,我遇到了错误

"qt.gui.icc:fromIccProfile:最小标记尺寸不合法"。

如果导入的“JPG”格式不正确,则会出现此错误。 根据此链接。

更改“JPG”文件可帮助我摆脱上述警告。


我面临着完全相同的问题!将"videoSurface"更改为其他内容是行不通的。你找到任何解决办法了吗? - LeXela-ED

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接