render_wallpaper.py drives headless Firefox frame by frame (four at a time, resuming where it stopped), then ffmpeg. Thirty seconds at 30 fps is exactly one plasma cycle, so frame 900 meets frame 0 and the loop has no seam. plasma-plugin/dev.emil.video is a minimal Plasma 6 video wallpaper: one file per screen, filling the screen, looping. H.264 is encoded Baseline because Qt here decodes through openh264, which rejects High profile and leaves a frozen frame; a new source also has to be played explicitly. The #shot hash learned info=0 to hide the on-screen hint for renders.
59 lines
1.8 KiB
QML
59 lines
1.8 KiB
QML
import QtQuick
|
|
import QtMultimedia
|
|
import org.kde.plasma.plasmoid
|
|
|
|
// Plays one video file, filling the screen and looping for ever. Plasma keeps a
|
|
// separate configuration per screen, so every monitor gets its own video.
|
|
WallpaperItem {
|
|
id: root
|
|
|
|
readonly property var activeConfiguration: {
|
|
if (typeof wallpaper !== "undefined" && wallpaper && wallpaper.configuration)
|
|
return wallpaper.configuration
|
|
return typeof configuration !== "undefined" ? configuration : null
|
|
}
|
|
|
|
function option(name, fallback) {
|
|
if (!activeConfiguration)
|
|
return fallback
|
|
const value = activeConfiguration[name]
|
|
return value === undefined ? fallback : value
|
|
}
|
|
|
|
readonly property string videoPath: String(option("videoPath", ""))
|
|
// shortcut: keeps decoding behind fullscreen windows too, add window tracking
|
|
// (as the shader wallpaper plugin does) if the cost ever shows up in a game
|
|
readonly property bool shouldPlay: videoPath.length > 0 && root.visible
|
|
|
|
Rectangle {
|
|
anchors.fill: parent
|
|
color: "#03111d"
|
|
}
|
|
|
|
VideoOutput {
|
|
id: output
|
|
anchors.fill: parent
|
|
fillMode: VideoOutput.PreserveAspectCrop
|
|
}
|
|
|
|
MediaPlayer {
|
|
id: player
|
|
videoOutput: output
|
|
source: root.videoPath.length > 0 ? "file://" + root.videoPath : ""
|
|
loops: MediaPlayer.Infinite
|
|
playbackRate: Number(root.option("playbackRate", 1.0))
|
|
|
|
// Some containers do not restart on their own when they run out of frames.
|
|
onMediaStatusChanged: {
|
|
if (mediaStatus === MediaPlayer.EndOfMedia) {
|
|
position = 0
|
|
play()
|
|
}
|
|
}
|
|
|
|
onErrorOccurred: console.warn("video wallpaper:", error, errorString)
|
|
}
|
|
|
|
Component.onCompleted: player.play()
|
|
}
|