QML 视频示例
对视频和相机取景器内容进行变换。
QML 视频示例演示了可应用于 QML `VideoOutput ` 和 `Camera ` 类型的各种变换(移动、调整大小、旋转、更改宽高比)。
它还展示了如何将原生代码与 QML 结合以实现更高级的功能——在此示例中,使用 C++ 代码来计算 QML 的帧率。该值在 QML 中以半透明项的形式渲染,并叠加在视频内容之上。
下图展示了应用程序执行视频叠加场景的过程:该场景创建了一个虚拟叠加项(仅为一个半透明的Rectangle ),该项在VideoOutput 项上移动。

运行示例
您可以通过以下方式运行示例:
- Qt Creator
打开Welcome 模式,并从Examples 中选择该示例。有关更多信息,请参阅Qt Creator :教程:构建和运行。
- Qt Extension for Visual Studio Code
在“Command Palette ”中运行“Qt: Open Qt examples ”命令,并从列表中选择该示例。有关更多信息,请参阅Qt Extension for Visual Studio Code :教程:构建和运行。
应用程序结构
Main.qml 文件会创建一个包含以下元素的用户界面:
- 两个
Button实例,每个实例均显示一个文件名,并可用于启动FileDialog。 - 一个退出用的
Button。 - 一个
SceneSelectionPanel,这是一个可滑动的列表,用于显示可用的场景。 - 左下角有一个显示 QML 重绘速率的控件——上方的数值为瞬时帧率,下方的数值为过去一秒内的平均帧率。

可滑动列表中的每个场景都在各自的 QML 文件中实现——例如,video-basic 场景(仅在屏幕中央显示一个静态的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 实现的,而 VideoMove 和CameraMove 正是基于该实现的。
根据顶级场景实例中 contentType 属性的值,嵌入的Content 项会创建MediaPlayer 或Camera 项。
计算和显示 QML 绘制速率
QML 绘制速率由 FrequencyMonitor 类计算得出,该类将事件流(通过 notify() 槽接收)转换为瞬时频率和平均频率:
class FrequencyMonitor : public QObject
{
Q_OBJECT
QML_ELEMENT
Q_PROPERTY(qreal instantaneousFrequency READ instantaneousFrequency NOTIFY
instantaneousFrequencyChanged)
Q_PROPERTY(qreal averageFrequency READ averageFrequency NOTIFY averageFrequencyChanged)
...
public slots:
Q_INVOKABLE void notify();
};通过如上所示在类声明中添加宏QML_ELEMENT ,将 FrequencyMonitor 类暴露给 QML;并通过定义名为 FrequencyItem 的 QML 项来显示其数据,如下所示:
import frequencymonitor
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()));© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.