QML Video Recorder

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:

  • Input devices can be selected.
  • An input type switched off.
  • Settings for capturing such as quality, codec choice, file format, and assigning metadata.
  • Captured files are stored and can be played back.

Recording

The application implements recording.

captureSession

main.qml , captureSession is declared like so:

    CaptureSession {
        id: captureSession
        recorder: recorder
        audioInput: controls.audioInput
        camera: controls.camera
        screenCapture: controls.screenCapture
        videoOutput: videoOutput
    }
					
recorder

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
					
controls

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.

Selecting a video source

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
					
Selecting an audio input

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"
					

范例工程 @ code.qt.io