diff options
author | Samuel Mira <samuel.mira@qt.io> | 2021-08-30 15:59:47 +0300 |
---|---|---|
committer | Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> | 2021-08-31 13:12:30 +0000 |
commit | cc1e7c1d053f3cfc9d853890029a97a429840edd (patch) | |
tree | 8d9b5e859aa6ef53ccf02db67f9672afb7bbc746 | |
parent | 02afb3a51bb348674b023e575821ee88172dc535 (diff) |
Add Track Selection from QML and updated example
Added Q_PROPERTY in QMediaPlayer.h for the obtaining track metadata and
for setting active track
Changed mediaplayer QML example to add track information and change.
Change-Id: I1ff228a858079a87b1253d3c7a1ff24d815f2182
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
(cherry picked from commit 72c36a33dbb510d9eb098033cd5a4087211418fb)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
8 files changed, 272 insertions, 9 deletions
diff --git a/examples/multimedia/video/mediaplayer/PlaybackControl.qml b/examples/multimedia/video/mediaplayer/PlaybackControl.qml index 8809bff57..6744d2b6d 100644 --- a/examples/multimedia/video/mediaplayer/PlaybackControl.qml +++ b/examples/multimedia/video/mediaplayer/PlaybackControl.qml @@ -67,6 +67,10 @@ Item { Behavior on opacity { NumberAnimation { duration: 300 }} function updateOpacity() { + //hover is not usable in mobile platforms + if (Qt.platform.os == "android" || Qt.platform.os == "ios") + return; + if (playbackControlHoover.hovered || mediaPlayerState != MediaPlayer.PlayingState || !mediaPlayer.hasVideo) root.opacity = 1; else diff --git a/examples/multimedia/video/mediaplayer/PlayerMenuBar.qml b/examples/multimedia/video/mediaplayer/PlayerMenuBar.qml index b8e906b7f..a8fabd30a 100644 --- a/examples/multimedia/video/mediaplayer/PlayerMenuBar.qml +++ b/examples/multimedia/video/mediaplayer/PlayerMenuBar.qml @@ -60,6 +60,9 @@ Item { required property MediaPlayer mediaPlayer required property VideoOutput videoOutput required property MetadataInfo metadataInfo + required property TracksInfo audioTracksInfo + required property TracksInfo videoTracksInfo + required property TracksInfo subtitleTracksInfo height: menuBar.height @@ -71,6 +74,18 @@ Item { mediaPlayer.play() } + function closeOverlays(){ + metadataInfo.visible = false; + audioTracksInfo.visible = false; + videoTracksInfo.visible = false; + subtitleTracksInfo.visible = false; + } + + function showOverlay(overlay){ + closeOverlays(); + overlay.visible = true; + } + Popup { id: urlPopup anchors.centerIn: Overlay.overlay @@ -133,7 +148,23 @@ Item { title: qsTr("&View") Action { text: qsTr("Metadata") - onTriggered: metadataInfo.visible = !metadataInfo.visible + onTriggered: showOverlay(metadataInfo) + } + } + + Menu { + title: qsTr("&Tracks") + Action { + text: qsTr("Audio") + onTriggered: showOverlay(audioTracksInfo) + } + Action { + text: qsTr("Video") + onTriggered: showOverlay(videoTracksInfo) + } + Action { + text: qsTr("Subtitles") + onTriggered: showOverlay(subtitleTracksInfo) } } } diff --git a/examples/multimedia/video/mediaplayer/TracksInfo.qml b/examples/multimedia/video/mediaplayer/TracksInfo.qml new file mode 100644 index 000000000..ad30a6beb --- /dev/null +++ b/examples/multimedia/video/mediaplayer/TracksInfo.qml @@ -0,0 +1,125 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtMultimedia + +Item { + id: root + implicitWidth: 200 + + property int selectedTrack: 0 + + 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); + if (!language) + return; + + elements.append( + { language: metadata.stringValue(LanguageKey) + , trackNumber: index + }) + }); + } + + ListModel { + id: elements + } + + Frame { + anchors.fill: parent + padding: 15 + + background: Rectangle { + color: "lightgray" + opacity: 0.7 + } + + ButtonGroup {id:group; } + + ListView { + id: trackList + visible: elements.count > 0 + anchors.fill: parent + model: elements + delegate: RowLayout { + width: trackList.width + RadioButton { + property int trackIndex : index + checked: trackIndex === selectedTrack +1 + text: model.language + ButtonGroup.group: group + onClicked: selectedTrack = model.trackNumber + } + } + } + + Text { + id: metadataNoList + visible: elements.count === 0 + text: qsTr("No tracks present") + } + } +} diff --git a/examples/multimedia/video/mediaplayer/main.qml b/examples/multimedia/video/mediaplayer/main.qml index b021e46e2..c7e03b24a 100644 --- a/examples/multimedia/video/mediaplayer/main.qml +++ b/examples/multimedia/video/mediaplayer/main.qml @@ -81,6 +81,14 @@ Window { onErrorOccurred: { mediaErrorText.text = mediaPlayer.errorString; mediaError.open() } onMetaDataChanged: { metadataInfo.read(mediaPlayer.metaData) } + onTracksChanged: { + audioTracksInfo.read(mediaPlayer.audioTracks); + audioTracksInfo.selectedTrack = mediaPlayer.activeAudioTrack +1; + videoTracksInfo.read(mediaPlayer.videoTracks); + videoTracksInfo.selectedTrack = mediaPlayer.activeVideoTrack +1; + subtitleTracksInfo.read(mediaPlayer.subtitleTracks); + subtitleTracksInfo.selectedTrack = mediaPlayer.activeSubtitleTrack +1; + } } PlayerMenuBar { @@ -94,6 +102,9 @@ Window { mediaPlayer: mediaPlayer videoOutput: videoOutput metadataInfo: metadataInfo + audioTracksInfo: audioTracksInfo + videoTracksInfo: videoTracksInfo + subtitleTracksInfo: subtitleTracksInfo onClosePlayer: root.close() } @@ -127,6 +138,38 @@ Window { visible: false } + TracksInfo { + 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 + } + + TracksInfo { + id: videoTracksInfo + + anchors.right: parent.right + anchors.top: videoOutput.fullScreen ? parent.top : menuBar.bottom + anchors.bottom: playbackControl.opacity ? playbackControl.bottom : parent.bottom + + visible: false + onSelectedTrackChanged: mediaPlayer.activeVideoTrack = videoTracksInfo.selectedTrack + } + + TracksInfo { + id: subtitleTracksInfo + + anchors.right: parent.right + anchors.top: videoOutput.fullScreen ? parent.top : menuBar.bottom + anchors.bottom: playbackControl.opacity ? playbackControl.bottom : parent.bottom + + visible: false + onSelectedTrackChanged: mediaPlayer.activeSubtitleTrack = subtitleTracksInfo.selectedTrack + } PlaybackControl { id: playbackControl diff --git a/examples/multimedia/video/mediaplayer/qml.qrc b/examples/multimedia/video/mediaplayer/qml.qrc index d9d06065d..39caf6616 100644 --- a/examples/multimedia/video/mediaplayer/qml.qrc +++ b/examples/multimedia/video/mediaplayer/qml.qrc @@ -7,5 +7,6 @@ <file>PlaybackSeekControl.qml</file> <file>PlaybackRateControl.qml</file> <file>PlayerMenuBar.qml</file> + <file>TracksInfo.qml</file> </qresource> </RCC> diff --git a/src/multimedia/platform/android/mediaplayer/qandroidmediaplayer.cpp b/src/multimedia/platform/android/mediaplayer/qandroidmediaplayer.cpp index 5d790bda8..373aa41ee 100644 --- a/src/multimedia/platform/android/mediaplayer/qandroidmediaplayer.cpp +++ b/src/multimedia/platform/android/mediaplayer/qandroidmediaplayer.cpp @@ -678,29 +678,75 @@ QPlatformMediaPlayer::TrackType convertTrackType(AndroidMediaPlayer::TrackType t return QPlatformMediaPlayer::TrackType::NTrackTypes; } +int QAndroidMediaPlayer::convertTrackNumber(int androidTrackNumber) +{ + int trackNumber = androidTrackNumber; + + int videoTrackCount = trackCount(QPlatformMediaPlayer::TrackType::VideoStream); + if (trackNumber <= videoTrackCount) + return trackNumber; + + trackNumber = trackNumber - videoTrackCount; + + int audioTrackCount = trackCount(QPlatformMediaPlayer::TrackType::AudioStream); + if (trackNumber <= audioTrackCount) + return trackNumber; + + trackNumber = trackNumber - audioTrackCount; + + auto subtitleTracks = mTracksMetadata.value(QPlatformMediaPlayer::TrackType::SubtitleStream); + int timedTextCount = 0; + int subtitleTextCount = 0; + for (const auto &track : subtitleTracks) { + if (track.androidTrackType() == 3) // 3 == TimedText + timedTextCount++; + + if (track.androidTrackType() == 4) // 4 == Subtitle + subtitleTextCount++; + } + + if (trackNumber <= timedTextCount) + return trackNumber; + + trackNumber = trackNumber - timedTextCount; + + if (trackNumber <= subtitleTextCount) + return trackNumber; + + return -1; +} + int QAndroidMediaPlayer::activeTrack(TrackType trackType) { + int androidTrackNumber = -1; + switch (trackType) { case QPlatformMediaPlayer::TrackType::VideoStream: { if (!mIsVideoTrackEnabled) return -1; - return mMediaPlayer->activeTrack(AndroidMediaPlayer::TrackType::Video); + androidTrackNumber = mMediaPlayer->activeTrack(AndroidMediaPlayer::TrackType::Video); } case QPlatformMediaPlayer::TrackType::AudioStream: { if (!mIsAudioTrackEnabled) return -1; - return mMediaPlayer->activeTrack(AndroidMediaPlayer::TrackType::Audio); + + androidTrackNumber = mMediaPlayer->activeTrack(AndroidMediaPlayer::TrackType::Audio); } case QPlatformMediaPlayer::TrackType::SubtitleStream: { int timedTextSelectedTrack = mMediaPlayer->activeTrack(AndroidMediaPlayer::TrackType::TimedText); - if (timedTextSelectedTrack > -1) - return timedTextSelectedTrack; + + if (timedTextSelectedTrack > -1) { + androidTrackNumber = timedTextSelectedTrack; + break; + } int subtitleSelectedTrack = mMediaPlayer->activeTrack(AndroidMediaPlayer::TrackType::Subtitle); - if (subtitleSelectedTrack > -1) - return subtitleSelectedTrack; + if (subtitleSelectedTrack > -1) { + androidTrackNumber = subtitleSelectedTrack; + break; + } return -1; } @@ -708,7 +754,7 @@ int QAndroidMediaPlayer::activeTrack(TrackType trackType) return -1; } - return -1; + return convertTrackNumber(androidTrackNumber); } void QAndroidMediaPlayer::disableTrack(TrackType trackType) diff --git a/src/multimedia/platform/android/mediaplayer/qandroidmediaplayer_p.h b/src/multimedia/platform/android/mediaplayer/qandroidmediaplayer_p.h index 315659559..f48f682d8 100644 --- a/src/multimedia/platform/android/mediaplayer/qandroidmediaplayer_p.h +++ b/src/multimedia/platform/android/mediaplayer/qandroidmediaplayer_p.h @@ -153,6 +153,7 @@ private: void setSubtitle(QString subtitle); void disableTrack(TrackType trackType); + int convertTrackNumber(int androidTrackNumber); friend class StateChangeNotifier; }; diff --git a/src/multimedia/playback/qmediaplayer.h b/src/multimedia/playback/qmediaplayer.h index 13d0bd90b..5796c89e6 100644 --- a/src/multimedia/playback/qmediaplayer.h +++ b/src/multimedia/playback/qmediaplayer.h @@ -72,7 +72,19 @@ class Q_MULTIMEDIA_EXPORT QMediaPlayer : public QObject Q_PROPERTY(Error error READ error NOTIFY errorChanged) Q_PROPERTY(QString errorString READ errorString NOTIFY errorChanged) Q_PROPERTY(QObject *videoOutput READ videoOutput WRITE setVideoOutput NOTIFY videoOutputChanged) - Q_PROPERTY(QAudioOutput *audioOutput READ audioOutput WRITE setAudioOutput NOTIFY audioOutputChanged) + Q_PROPERTY(QAudioOutput *audioOutput READ audioOutput WRITE setAudioOutput NOTIFY + audioOutputChanged) + + Q_PROPERTY(QList<QMediaMetaData> audioTracks READ audioTracks NOTIFY tracksChanged) + Q_PROPERTY(QList<QMediaMetaData> videoTracks READ videoTracks NOTIFY tracksChanged) + Q_PROPERTY(QList<QMediaMetaData> subtitleTracks READ subtitleTracks NOTIFY tracksChanged) + + Q_PROPERTY(int activeAudioTrack READ activeAudioTrack WRITE setActiveAudioTrack NOTIFY + activeTracksChanged) + Q_PROPERTY(int activeVideoTrack READ activeVideoTrack WRITE setActiveVideoTrack NOTIFY + activeTracksChanged) + Q_PROPERTY(int activeSubtitleTrack READ activeSubtitleTrack WRITE setActiveSubtitleTrack NOTIFY + activeTracksChanged) public: enum PlaybackState |