QML ビデオレコーダー
Qt Quick を使用した音声および動画の録画。

QML レコーダーは、マイク、カメラ、または画面キャプチャを使用して、音声と動画を別々に、あるいは同時に記録できるシンプルなアプリケーションの例です。
例の動作
サンプルは以下の手順で実行できます。
- Qt Creator
Welcome モードを開き、Examples からこのサンプルを選択します。詳細については、Qt Creator の「チュートリアル:ビルドと実行」を参照してください。
- Qt Extension for Visual Studio Code
Command Palette から `Qt: Open Qt examples ` コマンドを実行し、リストからこのサンプルを選択します。詳細については、Qt Extension for Visual Studio Code: チュートリアル「ビルドと実行」を参照してください。
概要
本質的には、これは QML アプリケーションです。「Qt Quick アプリケーションの入門」を参照してください。このドキュメントでは、この例が Qt Multimedia QML Typesを使用する方法に焦点を当てています。
このサンプルでは、CaptureSession に接続されたQMLのCamera およびAudioInput タイプを使用しています。その後、MediaRecorder オブジェクトを使用して、キャプチャされたオーディオとビデオを記録します。
QtMultimedia に加え、Qt Quick のウィンドウ、コントロール、レイアウトの機能を使用して、グラフィカルユーザーインターフェースと機能を実装しています。再生機能についてはここでは扱いません。それについては、「QML Media Player サンプル」を参照してください。
このサンプルでは、以下の機能を実演しています:
- 入力デバイスを選択できます。
- 入力タイプを切り替えることができます。
- 画質、コーデックの選択、ファイル形式、メタデータの割り当てなど、キャプチャに関する設定が可能です。
- キャプチャされたファイルは保存され、再生可能です。
録画
このアプリケーションは録画機能を実装しています。
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 = 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.qml で定義され、Main.qml で宣言されています。
そのルートは、Columns inputControls 、recordButton 、optionButtons を含むRow であり、これらはそれぞれ独自の .qml ファイルで定義されています。
動画ソースの選択
VideoSourceSelect.qml で定義されているVideoSourceSlect は、Switch とComboBox で構成されており、ユーザーが利用可能なカメラから選択できるようにします。
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:
root.cameraAvailable
&& PermissionHelper.cameraStatus === Qt.PermissionStatus.Granted
}
ScreenCapture {
id: screenCapture
active: root.screenAvailable
}
WindowCapture {
id: windowCapture
active: root.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"© 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.