QML 视频录制器

使用 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 媒体播放器范例 .

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