QML 录像机
使用 Qt Quick 录制音频和视频。
此QML 录像机演示了一个简单的应用程序,可以单独或同时录制音频和视频,使用麦克风、相机或屏幕捕捉。
运行示例
要从 Qt Creator 运行示例,请打开欢迎模式并从示例中选择示例。有关更多信息,请访问构建和运行示例。
概述
从核心来看,这是一个 QML 应用程序,请参阅使用 Qt Quick 开发程序入门。本文档着重介绍此示例如何使用 Qt Multimedia QML 类型。
该示例使用连接到 CaptureSession 的 QML Camera 和 AudioInput 类型。然后使用 MediaRecorder 对象来录制捕获的音频和视频。
除了 QtMultimedia 之外,还使用了 Qt Quick 窗口、控件和布局的功能来实现图形用户界面和功能。不会介绍播放功能,有关播放功能,请参阅QML 媒体播放器示例。
该示例演示了以下内容
- 可以选择输入设备。
- 关闭了输入类型。
- 捕获设置,如质量、编解码器选择、文件格式以及分配元数据。
- 捕获的文件被存储并可播放。
录制
应用程序实现了录制功能。
captureSession
在 main.qml
中,captureSession
被声明如下
CaptureSession { id: captureSession recorder: recorder audioInput: controls.audioInput camera: controls.camera screenCapture: controls.screenCapture windowCapture: controls.windowCapture videoOutput: videoOutput }
recorder
在 main.qml
中,MediaRecorder recorder
负责录制媒体以及捕获文件的缩略图并将其添加到 ListModel mediaList
中。
MediaRecorder { id: recorder onRecorderStateChanged: (state) => { if (state === MediaRecorder.StoppedState) { root.contentOrientation = Qt.PrimaryOrientation mediaList.append() } else if (state === MediaRecorder.RecordingState && captureSession.camera) { // lock orientation while recording and create a preview image root.contentOrientation = root.screen.orientation; videoOutput.grabToImage(function(res) { mediaList.mediaThumbnail = res.url }) } } onActualLocationChanged: (url) => { mediaList.mediaUrl = url } onErrorOccurred: { recorderErrorText.text = recorder.errorString; recorderError.open(); } }
mediaList
在 Frame mediaListFrame
中声明
Frame { id: mediaListFrame height: 150 width: parent.width anchors.bottom: controlsFrame.top x: controls.capturesVisible ? 0 : parent.width background: Rectangle { anchors.fill: parent color: palette.base opacity: 0.8 } Behavior on x { NumberAnimation { duration: 200 } } MediaList { id: mediaList anchors.fill: parent playback: playback
controls
这些在 Controls.qml
中定义,并在 main.qml 中声明。
它的根是一个 Row,其中包含定义在各自的 .qml 文件中的 Columns inputControls
、recordButton
、optionButtons
。
选择视频源
定义在 VideoSourceSelect.qml
中,VideoSourceSelect
包含一个 开关 和一个 组合框,允许用户从可用的摄像头中选择。
Row { id: root height: Style.height property Camera selectedCamera: cameraAvailable ? camera : null property ScreenCapture selectedScreenCapture: screenAvailable ? screenCapture : null property WindowCapture selectedWindowCapture: windowAvailable ? windowCapture : null property bool sourceAvailable: typeof comboBox.currentValue !== 'undefined' && comboBox.currentValue.type !== 'toggler' && videoSourceSwitch.checked property bool cameraAvailable: sourceAvailable && comboBox.currentValue.type === 'camera' property bool screenAvailable: sourceAvailable && comboBox.currentValue.type === 'screen' property bool windowAvailable: sourceAvailable && comboBox.currentValue.type === 'window' Component.onCompleted: { videoSourceModel.populate() for (var i = 0; i < videoSourceModel.count; i++) { if (videoSourceModel.get(i).value.type !== 'toggler') { comboBox.currentIndex = i break } } } Camera { id: camera active: cameraAvailable } ScreenCapture { id: screenCapture active: screenAvailable } WindowCapture { id: windowCapture active: windowAvailable } MediaDevices { id: mediaDevices onVideoInputsChanged: { videoSourceModel.populate() for (var i = 0; i < videoSourceModel.count; i++) { if (videoSourceModel.get(i).value.type !== 'toggler') { comboBox.currentIndex = i break } } } } Switch { id: videoSourceSwitch anchors.verticalCenter: parent.verticalCenter checked: true } ListModel { id: videoSourceModel property var enabledSources: { 'camera': true, 'screen': true, 'window': false } function toggleEnabledSource(type) { enabledSources[type] = !enabledSources[type] populate() } function appendItem(text, value) { append({ text: text, value: value}) } function appendToggler(name, sourceType) { appendItem((enabledSources[sourceType] ? "- Hide " : "+ Show ") + name, { type: 'toggler', 'sourceType': sourceType }) } function populate() { clear() appendToggler('Cameras', 'camera') if (enabledSources['camera']) for (var camera of mediaDevices.videoInputs) appendItem(camera.description, { type: 'camera', camera: camera }) appendToggler('Screens', 'screen') if (enabledSources['screen']) for (var screen of Application.screens) appendItem(screen.name, { type: 'screen', screen: screen }) appendToggler('Windows', 'window') if (enabledSources['window']) for (var window of windowCapture.capturableWindows()) appendItem(window.description, { type: 'window', window: window }) } }
在上面的代码段中声明的 comboBox
被赋值为当前视频源。
ComboBox { id: comboBox width: Style.widthLong height: Style.height background: StyleRectangle { anchors.fill: parent } model: videoSourceModel displayText: typeof currentValue === 'undefined' || currentValue.type === 'toggler' ? "Unavailable" : currentText font.pointSize: Style.fontSize textRole: "text" valueRole: "value" onCurrentValueChanged: { if (typeof currentValue === 'undefined') return if (currentValue.type === 'screen') screenCapture.screen = currentValue.screen else if (currentValue.type === 'camera') camera.cameraDevice = currentValue.camera
选择音频输入
与 选择视频源 以相同方式实现,并在 AudioInputSelect.qml
中定义,如下所示
Row { id: root height: Style.height property AudioInput selected: available ? audioInput : null property bool available: (typeof comboBox.currentValue !== 'undefined') && audioSwitch.checked Component.onCompleted: { audioInputModel.populate() comboBox.currentIndex = 0 } MediaDevices { id: mediaDevices } AudioInput { id: audioInput; muted: !audioSwitch.checked } Switch { id: audioSwitch; height: Style.height; checked: true } ListModel { id: audioInputModel property var audioInputs: mediaDevices.audioInputs function populate() { audioInputModel.clear() for (var audioDevice of audioInputs) audioInputModel.append({ text: audioDevice.description, value: { type: 'audioDevice', audioDevice: audioDevice } }) } } ComboBox { id: comboBox width: Style.widthLong height: Style.height background: StyleRectangle { anchors.fill: parent } model: audioInputModel textRole: "text" font.pointSize: Style.fontSize displayText: typeof currentValue === 'undefined' ? "unavailable" : currentText valueRole: "value"
© 2024 Qt 公司有限公司。此处包含的文档贡献者是各自所有者的版权。所提供的文档是根据自由软件基金会发布的 GNU 自由文档许可版本 1.3 的条款许可的。Qt 及其相关标志是芬兰及其他国家的 Qt 公司商标。所有其他商标均为其各自所有者的财产。