QML视频示例

转换视频和相机取景器内容。

QML视频演示了可以应用于QML VideoOutputCamera 类型的各种转换(移动;调整大小;旋转;改变宽高比)。

它还展示了如何将本地代码与QML结合以实现更高级的功能 - 在这种情况下,使用C++代码计算QML帧率。此值在QML中以半透明项的形式渲染在视频内容上。

以下图像显示了应用程序执行视频叠加场景,该场景创建了一个虚拟叠加项(只是一个半透明的Rectangle),它在VideoOutput项中移动。

运行示例

要从Qt Creator运行示例,请打开欢迎模式并从示例中选择示例。有关更多信息,请访问构建和运行示例

应用结构

Main.qml文件创建了一个包含以下项目的UI:

  • 两个Button实例,每个实例显示一个文件名,并且可以用来启动FileDialog
  • 一个退出Button
  • 一个SceneSelectionPanel,它是一个可翻页的列表,显示可用的场景。
  • 在左下角,一个显示QML重绘速率的项 - 上面的数字是瞬间帧率,下面的数字是过去一秒的平均值。

目录列表中的每个场景都由自己的QML文件实现 - 例如视频基本场景(仅显示屏幕中央的静态VideoOutput)由VideoBasic.qml文件实现。从代码中可以看出,这种类型使用了一种继承方式;一个VideoBasic项 ...

SceneBasic {
    contentType: "video"
}

... 是SceneBasic类型 ...

import QtQuick
import QtQuick.Controls

Scene {
    id: root
    property string contentType
    ...
    Content {
        id: content
    ...
    }

    Label {
        anchors {
            horizontalCenter: parent.horizontalCenter
            bottom: parent.bottom
            margins: 20
        }
        text: content.started ? qsTr("Tap the screen to stop content")
                              : qsTr("Tap the screen to start content")
        z: 2.0
    }

    MouseArea {
        anchors.fill: parent
        onClicked: {
            if (content.started)
                content.stop()
            else
                content.start()
        }
    }

    Component.onCompleted: root.content = content
}

... 它本身又是一个Scene

import QtQuick
import QtQuick.Controls

Rectangle {
    id: root
    ...
    property QtObject content
    ...
    Button {
        id: closeButton
        anchors {
            top: parent.top
            right: parent.right
            margins: root.margins
        }
        z: 2.0
        text: qsTr("Back")
        onClicked: root.close()
    }
}

SceneBasic描述了场景的结构和行为,但对要显示的内容类型不做任何假设 - 这通过Content进行了抽象。

这种模式允许我们定义一个特定的用例(在这种情况下,简单地显示一个静态的内容),然后为视频内容(VideoBasic)和摄像头内容({CameraBasic})实例化该用例。这种方法被用来实现许多其他场景 - 例如,“反复从左到右滑动内容再返回”是由SceneMove实现的,VideoMoveCameraMove都基于它。

根据顶层场景实例中contentType属性值,嵌入的内容项会创建一个< Popup>或一个MediaPlayer项。

计算和显示 QML 绘制速率

QML 绘制速率由 FrequencyMonitor 类计算,该类将事件流(通过 notify() 插槽接收)转换为瞬时频率和平均频率

class FrequencyMonitor : public QObject
{
    Q_OBJECT
    Q_PROPERTY(qreal instantaneousFrequency READ instantaneousFrequency NOTIFY
                       instantaneousFrequencyChanged)
    Q_PROPERTY(qreal averageFrequency READ averageFrequency NOTIFY averageFrequencyChanged)

public:
    ...
    static void qmlRegisterType();

public slots:
    Q_INVOKABLE void notify();
};

FrequencyMonitor 类如以下所示公开给 QML:

void FrequencyMonitor::qmlRegisterType()
{
    ::qmlRegisterType<FrequencyMonitor>("FrequencyMonitor", 1, 0, "FrequencyMonitor");
}

然后通过定义一个名为 FrequencyItem 的 QML 元素来显示其数据,如下所示:

import FrequencyMonitor 1.0

Rectangle {
    id: root
    ...
    function notify() {
        monitor.notify()
    }

    FrequencyMonitor {
        id: monitor
        onAverageFrequencyChanged: {
            averageFrequencyText.text = monitor.averageFrequency.toFixed(2)
        }
    }

    Text {
        id: labelText
        anchors {
            left: parent.left
            top: parent.top
            margins: 10
        }
        color: root.textColor
        font.pixelSize: 0.6 * root.textSize
        text: root.label
        width: root.width - 2*anchors.margins
        elide: Text.ElideRight
    }

    Text {
        id: averageFrequencyText
        anchors {
            right: parent.right
            bottom: parent.bottom
            margins: 10
        }
        color: root.textColor
        font.pixelSize: root.textSize
    }
}

结果如下所示

接下来就是将QQuickView对象的 afterRendering() 信号连接到一个 JavaScript 函数,该函数最终调用frequencyItem.notify()

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);
    ...
    QQuickView viewer;
    ...
    QQuickItem *rootObject = viewer.rootObject();
    ...
    QObject::connect(&viewer, SIGNAL(afterRendering()), rootObject, SLOT(qmlFramePainted()));

示例项目 @ code.qt.io

© 2024 Qt 公司有限公司. 本文件中包含的文档贡献权属于各自的所有者。本文件中提供的文档根据自由软件基金会发布的 GNU 自由文档许可协议第 1.3 版 的条款进行许可。Qt 和相关徽标是芬兰及/或世界其他地区的 The Qt Company Ltd. 的商标。所有其他商标均为各自所有者的财产。