fuzbal/Video.qml

151 lines
4.1 KiB
QML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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 // dont 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)
}
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
focusPolicy: Qt.NoFocus
from: 25; to: 250; stepSize: 25
value: 100
function reset() { value = 100 }
textFromValue: function (value, locale) {
return (value / 100).toLocaleString(locale, 'f', 2)
}
}
}
}
}