Refactor to always have the playbin

This commit is contained in:
Jan Hamal Dvořák 2025-03-09 09:46:03 +01:00
parent 18c1e6c4a7
commit ed71a3a05c

View file

@ -3,7 +3,7 @@ from __future__ import annotations
import os import os
import sys import sys
from pathlib import Path from pathlib import Path
from typing import Any, TypeVar, cast, overload from typing import Any, cast, overload
import gi import gi
@ -15,8 +15,6 @@ gi.require_version("Gst", "1.0")
gi.require_version("Pango", "1.0") gi.require_version("Pango", "1.0")
from gi.repository import Gdk, Gio, Gst, Gtk, Pango # NOQA: E402 from gi.repository import Gdk, Gio, Gst, Gtk, Pango # NOQA: E402
_T = TypeVar("_T")
class MainWindow(Gtk.ApplicationWindow): class MainWindow(Gtk.ApplicationWindow):
file_info_label: Gtk.Label file_info_label: Gtk.Label
@ -26,6 +24,7 @@ class MainWindow(Gtk.ApplicationWindow):
selection_model: Gtk.SingleSelection selection_model: Gtk.SingleSelection
video_widget: Gtk.Picture video_widget: Gtk.Picture
pipeline: Gst.Pipeline pipeline: Gst.Pipeline
playbin: Gst.Element
overlay_tick_callback_id: int overlay_tick_callback_id: int
overlay_label: Gtk.Label overlay_label: Gtk.Label
overlay_hide_time: float overlay_hide_time: float
@ -94,12 +93,14 @@ class MainWindow(Gtk.ApplicationWindow):
if not playbin: if not playbin:
raise RuntimeError("Failed to create playbin element") raise RuntimeError("Failed to create playbin element")
self.playbin = playbin
video_sink = Gst.ElementFactory.make("gtk4paintablesink", "gtk4paintablesink") video_sink = Gst.ElementFactory.make("gtk4paintablesink", "gtk4paintablesink")
if not video_sink: if not video_sink:
raise RuntimeError("Failed to create gtk4paintablesink element") raise RuntimeError("Failed to create gtk4paintablesink element")
playbin.set_property("video-sink", video_sink) self.playbin.set_property("video-sink", video_sink)
self.pipeline.add(playbin) self.pipeline.add(self.playbin)
# Link video widget to sink # Link video widget to sink
paintable = video_sink.get_property("paintable") paintable = video_sink.get_property("paintable")
@ -154,24 +155,20 @@ class MainWindow(Gtk.ApplicationWindow):
position = self._load_attribute("position", 0) position = self._load_attribute("position", 0)
# Start playing the video # Start playing the video
playbin = self.pipeline.get_by_name("playbin")
if not playbin:
return
full_path = os.path.abspath(file_item.full_path) full_path = os.path.abspath(file_item.full_path)
playbin.set_property("uri", f"file://{full_path}") self.playbin.set_property("uri", f"file://{full_path}")
track = self._load_attribute("subtitle_track", -2) track = self._load_attribute("subtitle_track", -2)
if track >= 0: if track >= 0:
flags = playbin.get_property("flags") flags = self.playbin.get_property("flags")
flags |= 0x00000004 # TEXT flag flags |= 0x00000004 # TEXT flag
playbin.set_property("flags", flags) self.playbin.set_property("flags", flags)
playbin.set_property("current-text", track) self.playbin.set_property("current-text", track)
elif track == -1: elif track == -1:
flags = playbin.get_property("flags") flags = self.playbin.get_property("flags")
flags &= ~0x00000004 # TEXT flag flags &= ~0x00000004 # TEXT flag
playbin.set_property("flags", flags) self.playbin.set_property("flags", flags)
if position: if position:
# Pause and wait for it to complete. # Pause and wait for it to complete.
@ -326,10 +323,6 @@ class MainWindow(Gtk.ApplicationWindow):
def _seek_relative(self, offset: int) -> None: def _seek_relative(self, offset: int) -> None:
"""Seek relative to current position by offset seconds""" """Seek relative to current position by offset seconds"""
playbin = self.pipeline.get_by_name("playbin")
if not playbin:
return
# Query current position # Query current position
success, current = self.pipeline.query_position(Gst.Format.TIME) success, current = self.pipeline.query_position(Gst.Format.TIME)
if not success: if not success:
@ -350,12 +343,8 @@ class MainWindow(Gtk.ApplicationWindow):
def _get_subtitle_info(self, track_index: int) -> str: def _get_subtitle_info(self, track_index: int) -> str:
"""Get subtitle track info including language if available""" """Get subtitle track info including language if available"""
playbin = self.pipeline.get_by_name("playbin")
if not playbin:
return str(track_index)
# Query the subtitle track's tags # Query the subtitle track's tags
caps: Gst.TagList | None = playbin.emit("get-text-tags", track_index) caps: Gst.TagList | None = self.playbin.emit("get-text-tags", track_index)
if not caps: if not caps:
return str(track_index) return str(track_index)
@ -365,10 +354,6 @@ class MainWindow(Gtk.ApplicationWindow):
def _save_position(self) -> None: def _save_position(self) -> None:
"""Save current playback position as xattr""" """Save current playback position as xattr"""
playbin = self.pipeline.get_by_name("playbin")
if not playbin:
return
success, position = self.pipeline.query_position(Gst.Format.TIME) success, position = self.pipeline.query_position(Gst.Format.TIME)
success2, duration = self.pipeline.query_duration(Gst.Format.TIME) success2, duration = self.pipeline.query_duration(Gst.Format.TIME)
@ -412,14 +397,10 @@ class MainWindow(Gtk.ApplicationWindow):
def _cycle_subtitles(self) -> None: def _cycle_subtitles(self) -> None:
"""Cycle through available subtitle tracks, including off state""" """Cycle through available subtitle tracks, including off state"""
playbin = self.pipeline.get_by_name("playbin")
if not playbin:
return
# Get current flags and subtitle track # Get current flags and subtitle track
flags = playbin.get_property("flags") flags = self.playbin.get_property("flags")
current = playbin.get_property("current-text") current = self.playbin.get_property("current-text")
n_text = playbin.get_property("n-text") n_text = self.playbin.get_property("n-text")
if n_text == 0: if n_text == 0:
self.show_overlay_text("No subtitles available") self.show_overlay_text("No subtitles available")
@ -428,8 +409,8 @@ class MainWindow(Gtk.ApplicationWindow):
# If subtitles are disabled, enable them and set to first track # If subtitles are disabled, enable them and set to first track
if not (flags & 0x00000004): # TEXT flag if not (flags & 0x00000004): # TEXT flag
flags |= 0x00000004 flags |= 0x00000004
playbin.set_property("flags", flags) self.playbin.set_property("flags", flags)
playbin.set_property("current-text", 0) self.playbin.set_property("current-text", 0)
track_info = self._get_subtitle_info(0) track_info = self._get_subtitle_info(0)
self.show_overlay_text(f"Subtitle track: {track_info}") self.show_overlay_text(f"Subtitle track: {track_info}")
self._save_attribute("subtitle_track", 0) self._save_attribute("subtitle_track", 0)
@ -438,14 +419,14 @@ class MainWindow(Gtk.ApplicationWindow):
# If we're on the last track, disable subtitles # If we're on the last track, disable subtitles
if current >= n_text - 1: if current >= n_text - 1:
flags &= ~0x00000004 # TEXT flag flags &= ~0x00000004 # TEXT flag
playbin.set_property("flags", flags) self.playbin.set_property("flags", flags)
self.show_overlay_text("Subtitles: Off") self.show_overlay_text("Subtitles: Off")
self._save_attribute("subtitle_track", -1) self._save_attribute("subtitle_track", -1)
return return
# Otherwise cycle to next track # Otherwise cycle to next track
next_track = current + 1 next_track = current + 1
playbin.set_property("current-text", next_track) self.playbin.set_property("current-text", next_track)
track_info = self._get_subtitle_info(next_track) track_info = self._get_subtitle_info(next_track)
self.show_overlay_text(f"Subtitle track: {track_info}") self.show_overlay_text(f"Subtitle track: {track_info}")
self._save_attribute("subtitle_track", next_track) self._save_attribute("subtitle_track", next_track)