// SPDX-License-Identifier: Unlicense import QtQuick 2.14 import QtQuick.Controls 2.13 import QtQuick.Layouts 1.6 import QtMultimedia 5.11 Page { property bool loaded: media.status !== MediaPlayer.NoMedia && media.status !== MediaPlayer.InvalidMedia && media.status !== MediaPlayer.UnknownStatus property alias source: media.source property alias time: media.position function pause(yes) { if (yes === undefined) yes = media.playbackState === MediaPlayer.PlayingState if (yes) media.pause() else media.play() } function seek(offset, relative) { if (relative) offset += media.position media.seek(offset) } Keys.onPressed: { switch (event.key) { // (Un)pause video. case Qt.Key_Space: pause() break // Seek video. case Qt.Key_Left: seek(-500, true) break case Qt.Key_Right: seek(500, true) break // Change playback rate. case Qt.Key_Equal: rate.reset() break case Qt.Key_Comma: rate.decrease() break case Qt.Key_Period: rate.increase() break default: return // don’t accept the event } event.accepted = true } // Video. ColumnLayout { spacing: 0 anchors.fill: parent Rectangle { Layout.fillWidth: true Layout.fillHeight: true color: 'black' clip: true VideoOutput { anchors.fill: parent fillMode: VideoOutput.PreserveAspectFit source: media transform: Scale { id: zoom property real scale: 1.0 xScale: scale yScale: scale origin.x: wheel.point.position.x origin.y: wheel.point.position.y } MediaPlayer { id: media notifyInterval: 100 playbackRate: Number.fromLocaleString(rate.displayText) volume: QtMultimedia.convertVolume( volume.value, QtMultimedia.LogarithmicVolumeScale, QtMultimedia.LinearVolumeScale) } TapHandler { acceptedButtons: Qt.RightButton onTapped: pause() } WheelHandler { id: wheel onWheel: zoom.scale = Math.max(1.0, (event.angleDelta.y > 0 ? 1.1 : 0.9) * zoom.scale) } } } // Video controls. RowLayout { Layout.margins: 5 Button { icon.name: 'media-playback-pause' implicitWidth: implicitHeight checkable: true checked: media.playbackState !== MediaPlayer.PlayingState onClicked: checked ? media.pause() : media.play() focusPolicy: Qt.NoFocus } Label { text: new Date(media.position).toISOString().substr(12, 9) } Slider { Layout.fillWidth: true from: 0; to: media.duration value: media.position onMoved: media.seek(value) focusPolicy: Qt.NoFocus } Label { text: new Date(media.duration).toISOString().substr(12, 7) } Volume { id: volume muted: media.muted focusPolicy: Qt.NoFocus } // Playback speed control. SpinBox { id: rate implicitWidth: 80 from: 25; to: 250; stepSize: 25 value: 100 function reset() { value = 100 } textFromValue: function (value, locale) { return (value / 100).toLocaleString(locale, 'f', 2) } } } } }