Recording audio and video using Qt Quick.
QML Recorder demonstrates a simple application that can record audio and video separate or together, using a microphone, a camera, or with screen capturing.
要运行范例从 Qt Creator ,打开 Welcome 模式,然后选择范例从 Examples 。更多信息,拜访 构建和运行范例 .
At its core, this is a QML application, see 采用 Qt Quick 快速入门编程 . This documentation is focused on how this example uses the Qt Multimedia QML types .
The example uses the QML Camera and AudioInput types connected to a CaptureSession 。 MediaRecorder object is then used to record the captured audio and video.
除了 QtMultimedia , features of Qt Quick Windows, Controls, and Layouts are used to implement the graphic user interface and functionality. Playback won't be covered here, for that see the QML Media Player Example .
The example demonstrates the following:
The application implements recording.
在
main.qml
,
captureSession
is declared like so:
CaptureSession {
id: captureSession
recorder: recorder
audioInput: controls.audioInput
camera: controls.camera
screenCapture: controls.screenCapture
videoOutput: videoOutput
}
在
main.qml
,
MediaRecorder
recorder
handles recording media as well as capturing a thumbnail for the file and appending it to a 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
is declared in the
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: "white"
opacity: 0.8
}
Behavior on x { NumberAnimation { duration: 200 } }
MediaList {
id: mediaList
anchors.fill: parent
playback: playback
These are defined in
Controls.qml
and declared in main.qml.
Its root is a
Row
包含
Columns
inputControls
,
recordButton
,
optionButtons
, each defined in their own .qml files.
Defined in
VideoSourceSelect.qml
,
VideoSourceSlect
is comprised of a
Switch
和
ComboBox
and enables the user to select from available cameras.
Row { id: root height: Style.height property Camera selectedCamera: cameraAvailable ? camera : null property ScreenCapture selectedScreenCapture: screenAvailable ? screenCapture : null property bool cameraAvailable: (comboBox.currentValue.type === 'camera') && cameraSwitch.checked property bool screenAvailable: (comboBox.currentValue.type === 'screen') && cameraSwitch.checked Component.onCompleted: { videoSourceModel.populate() comboBox.currentIndex = 0 } Camera { id: camera active: cameraAvailable } ScreenCapture { id: screenCapture active: screenAvailable } MediaDevices { id: mediaDevices } Switch { id: cameraSwitch anchors.verticalCenter: parent.verticalCenter checked: true } ListModel { id: videoSourceModel property var cameras: mediaDevices.videoInputs property var screens: Application.screens function populate() { videoSourceModel.clear() for (var camera of cameras) videoSourceModel.append({ text: camera.description, value: { type: 'camera', camera: camera } }) for (var screen of screens) videoSourceModel.append({ text: screen.name, value: { type: 'screen', screen: screen }}) } }
comboBox
, declared in the above snippet, assigns the current video source.
ComboBox {
id: comboBox
width: Style.widthLong
height: Style.height
background: StyleRectangle { anchors.fill: parent }
model: videoSourceModel
displayText: typeof currentValue === 'undefined' ? "Unavailable" : currentText
font.pointSize: Style.fontSize
textRole: "text"
valueRole: "value"
onCurrentValueChanged: {
if (currentValue.type === 'screen')
screenCapture.screen = currentValue.screen
else if (currentValue.type === 'camera')
camera.cameraDevice = currentValue.camera
Implemented in the same way as
Selecting a video source
and defined in
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 audioInput of audioInputs) audioInputModel.append({ text: audioInput.description, value: { type: 'audioInput', audioInput: audioInput } }) } } 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"