【问题标题】:Custom source property for VideoOutput QMLVideoOutput QML 的自定义源属性
【发布时间】:2017-10-06 20:46:52
【问题描述】:

要为VideoOutput QML 对象提供自定义帧源,具体需要做什么?

VideoOuput 本身是否向“源”提供QAbstractVideoSurface 类的实例?

Qt5 文档说明了关于提供有关此问题的以下内容:

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

根据以下文档,我做了以下操作:

  1. 我实现了我自己的类myFrameProvider,它派生自QObject,它具有可写的videoSurface 属性。
  2. 创建一个连接到将帧发送到 myFrameProvider 的类。
  3. 实例化 myFrameProvider 类,并使其在与“VideoOutput”小部件相同的 QML 上下文中可访问。

之后 - 每当访问“videSurface”属性时,我都会收到段错误。 我应该设置自己的视频表面属性吗?

【问题讨论】:

    标签: c++ qt video qtquick2 qtmultimedia


    【解决方案1】:

    在遇到类似问题时,我偶然发现了您的问题。过了一会儿,我找到了一个对我有用的解决方案。即使您的问题是一个较老的问题并且您可能继续前进,我也想分享我的答案以可能帮助其他人。

    我在“使用低级视频帧”部分的QT documentation 中找到了答案。那里发布的那段代码作为起点非常有帮助,但我必须对其进行修改,以使其正常工作。一个最小的工作示例如下所示:

    FrameProvider.h

    #include <QObject>
    #include <QAbstractVideoSurface>
    #include <QVideoSurfaceFormat>
    
    class FameProvider : public QObject
    {
        Q_OBJECT
        Q_PROPERTY(QAbstractVideoSurface *videoSurface READ videoSurface WRITE setVideoSurface)
    
    
    public:
        QAbstractVideoSurface* videoSurface() const { return m_surface; }
    
    private:
        QAbstractVideoSurface *m_surface = NULL;
        QVideoSurfaceFormat m_format;
    
    public:
    
    
        void setVideoSurface(QAbstractVideoSurface *surface)
        {
            if (m_surface && m_surface != 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);
    
            }
        }
    
        void setFormat(int width, int heigth, int format)
        {
            QSize size(width, heigth);
            QVideoSurfaceFormat format(size, format);
            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);
            }
        }
    
    public slots:
        void onNewVideoContentReceived(const QVideoFrame &frame)
        {
    
            if (m_surface)
                m_surface->present(frame);
        }
    };
    

    ma​​in.qml

    import QtQuick 2.9
    import QtQuick.Controls 2.2
    import QtQuick.Controls.Material 2.2
    import QtMultimedia 5.4
    import com.yourcompany.FrameProvider 1.0
    
    ApplicationWindow {
        objectName: "mainWindow"
        visible: true
        width: 640
        height: 480
    
        FrameProvider{
            objectName: "provider"
            id: provider
        }
    
        VideoOutput {
            id: display
            objectName: "display"
            anchors.top: parent.top
            anchors.bottom: parent.bottom
            width: parent.width
            source: provider
        }
    }
    

    ma​​in.cpp

    #include <QGuiApplication>
    #include <QQmlApplicationEngine>
    
     int main(int argc, char *argv[])
    {
        // initialize the qml application engine
        QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
        QGuiApplication app(argc, argv);
        QQmlApplicationEngine engine;
    
        //register the custom control to the qml application engine
        qmlRegisterType<FameProvider>("com.yourcompany.FrameProvider", 1, 0, "FrameProvider");
    
        // start the view
        engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
        if (engine.rootObjects().isEmpty())
        {
        return -1;
        }
    
        // find your custom control
        QObject *rootObject = engine.rootObjects().first();
        Qobject *display = rootObject->findChild<QObject *>("display");
        auto provider = qvariant_cast<FameProvider *>(display->property("source"));
    
        // Create your custom frame source class, which inherits from QObject. This source is expected to have the following public fields and signals:
        // - int width
        // - int height
        // - int format (following QVideoFrame::PixelFormat)
        // - signals: void newFrameAvailable(const QVideoFrame &frame);
        CustomFramesource source;
    
        // Set the correct format for the video surface (Make sure your selected format is supported by the surface)
        provider->setFormat(source.width,source.height, source.format);
    
        // Connect your frame source with the provider
        QObject::connect(&source, SIGNAL(newFrameAvailable(const QVideoFrame &)), provider, SLOT(onNewVideoContentReceived(const QVideoFrame &)));
    
        // run the app
        int retVal =  app.exec();
    
        return 0;
    }
    

    MWE 是从我的实际代码中浓缩出来的,因此未经测试。我希望它无论如何都能运行并显示所有需要的步骤。

    【讨论】:

    • 这个答案的一个关键部分是向m_format 成员提供一些东西,如Qt video document 中给出的那样。您也可以在构造函数中静态设置它;但是您需要提供的格式来匹配video surface supported types。顺便说一句,QVideoFrame startTimeendTime 似乎没有用于任何事情,并且不清楚绝对时基是什么。
    猜你喜欢
    • 2023-03-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-19
    • 1970-01-01
    • 2020-09-16
    • 2015-07-12
    相关资源
    最近更新 更多