QML 媒体播放器范例

使用 Qt Quick 播放音频和视频。

This example demonstrates a simple multimedia player that can play audio and video files using various codecs.

运行范例

要运行范例从 Qt Creator ,打开 Welcome 模式,然后选择范例从 Examples 。更多信息,拜访 构建和运行范例 .

概述

At its core this is a QML application, see 采用 Qt Quick 快速入门编程 for information specific to that. This documentation is focused on how this example utilizes the Qt Multimedia QML types .

Using MediaPlayer and VideoOutput

main.qml a MediaPlayer instance is connected to a VideoOutput to play back the video:

    MediaPlayer {
        id: mediaPlayer
        function updateMetadata() {
            metadataInfo.clear();
            metadataInfo.read(mediaPlayer.metaData);
            metadataInfo.read(mediaPlayer.audioTracks[mediaPlayer.activeAudioTrack]);
            metadataInfo.read(mediaPlayer.videoTracks[mediaPlayer.activeVideoTrack]);
        }
        videoOutput: videoOutput
					

videoOutput is declared like so:

    VideoOutput {
        id: videoOutput
        property bool fullScreen: false
        anchors.top: fullScreen ? parent.top : menuBar.bottom
        anchors.bottom: playbackControl.top
        anchors.left: parent.left
        anchors.right: parent.right
        TapHandler {
            onDoubleTapped: {
                parent.fullScreen ?  showNormal() : showFullScreen()
                parent.fullScreen = !parent.fullScreen
            }
            onTapped: {
                metadataInfo.visible = false
                audioTracksInfo.visible = false
                videoTracksInfo.visible = false
                subtitleTracksInfo.visible = false
            }
        }
    }
					

PlayerMenuBar

This QML type handles media selection from a url or local file, exiting the application, viewing meta data, and the selection of available video, audio or subtitle tracks.

Accessing the mediaPlayer object is done through properties:

    required property MediaPlayer mediaPlayer
    required property VideoOutput videoOutput
    required property MetadataInfo metadataInfo
    required property TracksInfo audioTracksInfo
    required property TracksInfo videoTracksInfo
    required property TracksInfo subtitleTracksInfo
					
fileDialog

A FileDialog, fileDialog , is created with an onAccepted function that will stop mediaPlayer , load the source by setting the source property and then play it automatically:

    FileDialog {
        id: fileDialog
        title: "Please choose a file"
        onAccepted: {
            mediaPlayer.stop()
            mediaPlayer.source = fileDialog.currentFile
            mediaPlayer.play()
        }
    }
					

This is triggered in the Menu File , which is a child of the MenuBar :

    MenuBar {
        id: menuBar
        anchors.left: parent.left
        anchors.right: parent.right
        Menu {
            title: qsTr("&File")
            Action {
                text: qsTr("&Open")
                onTriggered: fileDialog.open()
					
loadUrl

While urlPopup handles prompting and capturing a url, it is the loadUrl function that interacts with mediaPlayer like so:

    function loadUrl(url) {
        mediaPlayer.stop()
        mediaPlayer.source = url
        mediaPlayer.play()
    }
					
Getting meta data

In the declaration of mediaPlayer , in main.qml , there is the function updateMetadata() :

        function updateMetadata() {
            metadataInfo.clear();
            metadataInfo.read(mediaPlayer.metaData);
            metadataInfo.read(mediaPlayer.audioTracks[mediaPlayer.activeAudioTrack]);
            metadataInfo.read(mediaPlayer.videoTracks[mediaPlayer.activeVideoTrack]);
					

It is called in the following places:

        onMetaDataChanged: { updateMetadata() }
        onTracksChanged: {
            audioTracksInfo.read(mediaPlayer.audioTracks);
            audioTracksInfo.selectedTrack = mediaPlayer.activeAudioTrack;
            videoTracksInfo.read(mediaPlayer.videoTracks);
            videoTracksInfo.selectedTrack = mediaPlayer.activeVideoTrack;
            subtitleTracksInfo.read(mediaPlayer.subtitleTracks);
            subtitleTracksInfo.selectedTrack = mediaPlayer.activeSubtitleTrack;
            updateMetadata()
        }
					

Reading MetaData is done by the MetadataInfo type's read() function

    function read(metadata) {
        if (metadata) {
            for (var key of metadata.keys()) {
                if (metadata.stringValue(key)) {
                    elements.append(
                                { name: metadata.metaDataKeyToString(key)
                                , value: metadata.stringValue(key)
                                })
                }
            }
        }
    }
					

The information is displayed via an Overlay 项。

Tracks information and control

This is defined in TracksInfo.qml and reading available tracks is done in a similar way to MetadataInfo :

    function read(metadataList) {
        var LanguageKey = 6;
        elements.clear()
        elements.append(
                    { language: "No Selected Track"
                    , trackNumber: -1
                    })
        if (!metadataList)
            return;
        metadataList.forEach(function (metadata, index) {
            var language = metadata.stringValue(LanguageKey);
            var label = language ? metadata.stringValue(LanguageKey) : "track " + (index + 1)
            elements.append(
                        { language: label
                        , trackNumber: index
                        })
        });
    }
					

To set a track, the property selectedTrack is set like so:

        ListView {
            id: trackList
            visible: elements.count > 0
            anchors.fill: parent
            model: elements
            delegate: RowLayout {
                width: trackList.width
                RadioButton {
                    checked: model.trackNumber === selectedTrack
                    text: model.language
                    ButtonGroup.group: group
                    onClicked: selectedTrack = model.trackNumber
                }
            }
        }
					

The onSelectectedTrackChanged signal, in each relevant TracksInfo instance in main.qml , is what makes changes to mediaPlayer like so:

        id: audioTracksInfo
        anchors.right: parent.right
        anchors.top: videoOutput.fullScreen ? parent.top : menuBar.bottom
        anchors.bottom: playbackControl.opacity ? playbackControl.bottom : parent.bottom
        visible: false
        onSelectedTrackChanged:  mediaPlayer.activeAudioTrack = audioTracksInfo.selectedTrack
					

playbackControlPanel

This item has controls for Playback control , Play Pause Stop , Playback rate control and Playback seek control .

Playback control

This qml type handles media playback and interacts with the MediaPlayer in main.qml .

Here are the property definitions.

    required property MediaPlayer mediaPlayer
    property int mediaPlayerState: mediaPlayer.playbackState
					

Connections:

        target: mediaPlayer
        function onPlaybackStateChanged() { updateOpacity() }
        function onHasVideoChanged() { updateOpacity() }
    }
					
Play Pause Stop

Play , stop and pause interactions with the MediaPlayer object are done like so:

                    RoundButton {
                        id: pauseButton
                        radius: 50.0
                        text: "\u2016";
                        onClicked: mediaPlayer.pause()
                    }
                    RoundButton {
                        id: playButton
                        radius: 50.0
                        text: "\u25B6";
                        onClicked: mediaPlayer.play()
                    }
                    RoundButton {
                        id: stopButton
                        radius: 50.0
                        text: "\u25A0";
                        onClicked: mediaPlayer.stop()
                    }
                }
					

Playback states done using playbackstate like so:

        State {
            name: "playing"
            when: mediaPlayerState == MediaPlayer.PlayingState
            PropertyChanges { target: pauseButton; visible: true}
            PropertyChanges { target: playButton; visible: false}
            PropertyChanges { target: stopButton; visible: true}
        },
        State {
            name: "stopped"
            when: mediaPlayerState == MediaPlayer.StoppedState
            PropertyChanges { target: pauseButton; visible: false}
            PropertyChanges { target: playButton; visible: true}
            PropertyChanges { target: stopButton; visible: false}
        },
        State {
            name: "paused"
            when: mediaPlayerState == MediaPlayer.PausedState
            PropertyChanges { target: pauseButton; visible: false}
            PropertyChanges { target: playButton; visible: true}
            PropertyChanges { target: stopButton; visible: true}
        }
    ]
					
Playback seek control

Defined in PlaybackSeekControl.qml , this component comprises of an item with a Text, mediaTime ,和 Slider , mediaSlider , in a RowLayout .

mediaTime 使用 MediaPlayer 's position property like so:

        Text {
            id: mediaTime
            Layout.minimumWidth: 50
            Layout.minimumHeight: 18
            horizontalAlignment: Text.AlignRight
            text: {
                var m = Math.floor(mediaPlayer.position / 60000)
                var ms = (mediaPlayer.position / 1000 - m * 60).toFixed(1)
                return `${m}:${ms.padStart(4, 0)}`
            }
        }
					

mediaSlider 使用 MediaPlayer seekable , duration ,和 position properties like so:

        Slider {
            id: mediaSlider
            Layout.fillWidth: true
            enabled: mediaPlayer.seekable
            to: 1.0
            value: mediaPlayer.position / mediaPlayer.duration
            onMoved: mediaPlayer.setPosition(value * mediaPlayer.duration)
        }
					
Playback rate control

This type is defined in PlaybackRateControl.qml like so:

        Slider {
            id: slider
            Layout.fillWidth: true
            snapMode: Slider.SnapOnRelease
            enabled: true
            from: 0.5
            to: 2.5
            stepSize: 0.5
            value: 1.0
            onMoved: { mediaPlayer.setPlaybackRate(value) }
        }
        Text {
            text: "Rate " + slider.value + "x"
					
Audio control

This type is defined in AudioControl.qml , and utilizes the muted and volume properties of the AudioOutput instantiated within the MediaPlayer , which is instantiated in main.qml .

    required property MediaPlayer mediaPlayer
    property bool muted: false
    property real volume: volumeSlider.value/100.
    implicitHeight: buttons.height
    RowLayout {
        anchors.fill: parent
        Item {
            id: buttons
            width: muteButton.implicitWidth
            height: muteButton.implicitHeight
            RoundButton {
                id: muteButton
                radius: 50.0
                icon.source: muted ? "qrc:///Mute_Icon.svg" : "qrc:///Speaker_Icon.svg"
                onClicked: { muted = !muted }
            }
        }
        Slider {
            id: volumeSlider
            Layout.fillWidth: true
            Layout.alignment: Qt.AlignVCenter
            enabled: true
            to: 100.0
            value: 100.0
					

范例工程 @ code.qt.io