使用 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 .
在
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 } } }
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
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()
While
urlPopup
handles prompting and capturing a url, it is the
loadUrl
function that interacts with
mediaPlayer
像这样:
function loadUrl(url) { mediaPlayer.stop() mediaPlayer.source = url mediaPlayer.play() }
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 项。
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
像这样:
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
This item has controls for Playback control , Play Pause Stop , Playback rate control and Playback seek 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 , 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 像这样:
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} } ]
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) }
This type is defined in
PlaybackRateControl.qml
像这样:
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"
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