Skip to content

Commit

Permalink
use media_loaded_v2 signal
Browse files Browse the repository at this point in the history
  • Loading branch information
cosven committed Feb 18, 2024
1 parent 9854e2b commit bf3dbfc
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 75 deletions.
34 changes: 24 additions & 10 deletions feeluown/gui/uimain/nowplaying_overlay.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,13 @@ def __init__(self, app: 'GuiApp', parent=None):
self.setup_ui()

self.artwork_view.mv_btn.clicked.connect(self.play_mv)
self.ctl_btns.media_btns.toggle_video_btn.clicked.connect(self.enter_video_mode)
self._app.player.video_channel_changed.connect(
self.on_video_channel_changed, aioqueue=True
self.ctl_btns.media_btns.toggle_video_btn.clicked.connect(
self.keep_and_enter_video_mode
)
self._app.player.media_loaded_v2.connect(
self.on_media_loaded, aioqueue=True
)
self._keep_video_mode = False

def setup_ui(self):
self._layout.setContentsMargins(0, 0, 11, 0)
Expand All @@ -76,20 +79,31 @@ def play_mv(self):
self._app.playlist.set_current_model(self._app.playlist.current_song_mv)
self.enter_video_mode()

def keep_and_enter_video_mode(self):
self._keep_video_mode = True
self.enter_video_mode()

def unkeep_and_enter_cover_mode(self):
self._keep_video_mode = False
self.enter_cover_mode()

def enter_video_mode(self):
# FIXME: should call watch_mgr.set_mode
self._app.watch_mgr.exit_pip_mode()
self._app.watch_mgr.exit_fullwindow_mode()
video_widget = self._app.ui.mpv_widget
video_widget.overlay_auto_visible = True
with video_widget.change_parent():
if video_widget.parent() == self.artwork_view:
self.artwork_view.set_body(video_widget)
else:
with video_widget.change_parent():
self.artwork_view.set_body(video_widget)
self.ctl_btns.hide()
self.progress.hide()
video_widget.ctl_bar.clear_adhoc_btns()
exit_btn = video_widget.ctl_bar.add_adhoc_btn('退出视频模式')
fullwindow_btn = video_widget.ctl_bar.add_adhoc_btn('窗口全屏')
exit_btn.clicked.connect(self.enter_cover_mode)
exit_btn.clicked.connect(self.unkeep_and_enter_cover_mode)
fullwindow_btn.clicked.connect(
lambda: self._app.watch_mgr.
enter_fullwindow_mode(go_back=self.enter_video_mode)
Expand All @@ -115,11 +129,11 @@ def showEvent(self, a0) -> None:
def sizeHint(self):
return QSize(500, 400)

def on_video_channel_changed(self, _):
if (
bool(self._app.player.video_channel) is False
and not self._app.ui.mpv_widget.is_changing_parent
):
def on_media_loaded(self, properties):
if bool(properties['video_format']) is True:
if self._keep_video_mode:
self.enter_video_mode()
else:
self.enter_cover_mode()


Expand Down
69 changes: 32 additions & 37 deletions feeluown/gui/watch.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,22 +57,30 @@ def __init__(self, app: 'GuiApp'):
self._pip_container = ResizableFramelessContainer()
self._fullwindow_container = FullWindowContainer(app, parent=app)

#: Is the video widget visible before.
self._is_visible_before_auto_set_to_none = False
self._keep_fullwindow_mode = False
self._keep_pip_mode = False

def initialize(self):
self._initialize_mpv_video_renderring()

self._ui = self._app.ui
self._ui.pc_panel.media_btns.toggle_video_btn.clicked.connect(
lambda: self.set_mode(Mode.fullwindow))
lambda: self.keep_and_set_mode(Mode.fullwindow))
self._app.player.media_changed.connect(self.on_media_changed, aioqueue=True)
self._app.player.video_channel_changed.connect(self.on_video_channel_changed, aioqueue=True) # noqa
self._app.player.media_loaded_v2.connect(self.on_media_loaded, aioqueue=True)

self._pip_container.setMinimumSize(200, 130)
self._pip_container.hide()
self._fullwindow_container.hide()

def keep_and_set_mode(self, mode):
mode = Mode(mode)
if mode is Mode.fullwindow:
self._keep_fullwindow_mode = True
elif mode is Mode.pip:
self._keep_pip_mode = True
self.set_mode(mode)

def set_mode(self, mode):
mode = Mode(mode) # So that user can call set_mode(0/1/2) in REPL.
if mode is Mode.none:
Expand All @@ -86,14 +94,14 @@ def set_mode(self, mode):
# current mode and enter mode
if mode is Mode.fullwindow:
self.exit_pip_mode()
self.enter_fullwindow_mode(go_back=self.exit_fullwindow_mode)
self.enter_fullwindow_mode(go_back=self.unkeep_and_exit_fullwindow_mode)
else:
self.exit_fullwindow_mode()
self.enter_pip_mode()

def enter_fullwindow_mode(self, go_back=None):
video_widget = self._app.ui.mpv_widget
logger.debug("enter video-show fullwindow mode")
video_widget = self._app.ui.mpv_widget
if video_widget.parent() != self._fullwindow_container:
with video_widget.change_parent():
self._fullwindow_container.set_body(video_widget)
Expand All @@ -104,26 +112,23 @@ def enter_fullwindow_mode(self, go_back=None):
video_widget.overlay_auto_visible = True
video_widget.ctl_bar.clear_adhoc_btns()
pip_btn = video_widget.ctl_bar.add_adhoc_btn('画中画')
pip_btn.clicked.connect(lambda: self.set_mode(Mode.pip))
pip_btn.clicked.connect(lambda: self.keep_and_set_mode(Mode.pip))
if go_back is not None:
hide_btn = video_widget.ctl_bar.add_adhoc_btn('最小化')
hide_btn.clicked.connect(go_back)

def unkeep_pip_and_enter_fullwindow_mode(self):
self._keep_pip_mode = False
self.set_mode(Mode.fullwindow)

def unkeep_and_exit_fullwindow_mode(self):
self._keep_fullwindow_mode = False
self.exit_fullwindow_mode()

def exit_fullwindow_mode(self):
self._app.ui.mpv_widget.hide()
self._fullwindow_container.hide()
logger.debug("exit video-show fullwindow mode")

def _is_pip_mode(self):
return self._app.ui.mpv_widget.parent() == self._pip_container

def _is_fullwindow_mode(self):
return (self._app.ui.mpv_widget.parent() == self._app and
self._app.ui.mpv_widget.isVisible())

def _is_none_mode(self):
return not (self._is_pip_mode() or self._is_fullwindow_mode())

def enter_pip_mode(self):
"""enter picture in picture mode"""
logger.debug("enter video-show picture in picture mode")
Expand All @@ -138,13 +143,13 @@ def enter_pip_mode(self):
fullscreen_btn = video_widget.ctl_bar.add_adhoc_btn('全屏')
hide_btn = video_widget.ctl_bar.add_adhoc_btn('退出画中画')
fullscreen_btn.clicked.connect(self.toggle_pip_fullscreen)
hide_btn.clicked.connect(lambda: self.set_mode(Mode.fullwindow))
hide_btn.clicked.connect(self.unkeep_pip_and_enter_fullwindow_mode)
self._pip_container.show()
self._app.ui.mpv_widget.show()
try:
width = int(self._app.player._mpv.width) # type: ignore
height = int(self._app.player._mpv.height) # type: ignore
except ValueError:
except TypeError:
logger.exception('mpv video width/height is not a valid int')
else:
proper_width = max(min(width, 640), 320)
Expand All @@ -169,24 +174,14 @@ def on_media_changed(self, media):
logger.debug('media is changed to none, hide video-show')
self.set_mode(Mode.none)

def on_video_channel_changed(self, _):
if bool(self._app.player.video_channel) is False:
# When the mpv widget is changing it's parent, the video_channel may be
# changed to empty manully (see mpv_widget.change_parent).
if not self._app.ui.mpv_widget.is_changing_parent:
return

# HELP(cosven): Even if player play a valid video, the video_format
# is changed to none first, and then it is changed to the real value.
# So check if the video widget is visible before hide it.
self._is_visible_before_auto_set_to_none = self._app.ui.mpv_widget.isVisible() # noqa
self.set_mode(Mode.none)
def on_media_loaded(self, properties):
if bool(properties['video_format']) is True:
if self._keep_fullwindow_mode:
self.set_mode(Mode.fullwindow)
elif self._keep_pip_mode:
self.set_mode(Mode.pip)
else:
if self._is_visible_before_auto_set_to_none is True:
if self._is_fullwindow_mode():
self.set_mode(Mode.fullwindow)
elif self._is_pip_mode():
self.set_mode(Mode.pip)
self.set_mode(Mode.none)

#
# private methods
Expand Down
9 changes: 0 additions & 9 deletions feeluown/gui/widgets/mpv_.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ def __init__(self, app, parent=None):
self.mpv = self._app.player._mpv # noqa
self.ctx = None
self.get_proc_addr_c = OpenGlCbGetProcAddrFn(get_proc_addr)
self._is_changing_parent = False

def initializeGL(self):
params = {'get_proc_address': self.get_proc_addr_c}
Expand Down Expand Up @@ -99,26 +98,18 @@ def sizeHint(self):
return QSize(self.mpv.width, self.mpv.height)
return super().sizeHint()

@property
def is_changing_parent(self):
return self._is_changing_parent

@contextmanager
def change_parent(self):
assert self._is_changing_parent is False, 'implementation bug'

# on macOS, changing mpv widget parent cause no side effects.
# on Linux (wayland), it seems changing mpv widget parent may cause segfault,
# so do some hack to avoid crash.
if not IS_MACOS:
self._is_changing_parent = True
self._before_change_mpv_widget_parent()
try:
yield
finally:
if not IS_MACOS:
self._after_change_mpv_widget_parent()
self._is_changing_parent = False

def _before_change_mpv_widget_parent(self):
"""
Expand Down
4 changes: 3 additions & 1 deletion feeluown/player/base_player.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ def __init__(self, _=None, **kwargs):
self._current_media = None
self._current_metadata = Metadata()
self._video_format = None
self._video_channel = False # False, True, 1, int

#: player position changed signal
self.position_changed = Signal()
Expand All @@ -62,7 +61,10 @@ def __init__(self, _=None, **kwargs):
#: media about to change: (old_media, media)
self.media_about_to_changed = Signal()
self.media_changed = Signal() # Media source is changed (not loaded yet).
# The difference between media_loaded and media_loaded_v2 is that
# media_loaded_v2 carries some media properties.
self.media_loaded = Signal() # Start to play the media.
self.media_loaded_v2 = Signal() # emit(properties)
# Metadata is changed, and it may be changed during playing.
self.metadata_changed = Signal()
self.media_finished = Signal() # Finish to play the media.
Expand Down
19 changes: 1 addition & 18 deletions feeluown/player/mpvplayer.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ def __init__(self, _=None, audio_device=b'auto', winid=None,

#: if video_format changes to None, there is no video available
self.video_format_changed = Signal()
self.video_channel_changed = Signal()

self._mpv.observe_property(
'time-pos',
Expand Down Expand Up @@ -272,20 +271,6 @@ def video_format(self, vformat):
# firstly changed to None, and then changed to the real format.
self.video_format_changed.emit(vformat)

@property
def video_channel(self):
return self._video_channel

@video_channel.setter
def video_channel(self, value):
"""
According to practice:
- when playing a audio, the video channel is changed to False.
- when playing a video, the video channel is changed to 1.
"""
self._video_channel = value
self.video_channel_changed.emit(value)

def _stop_mpv(self):
# Remove current media.
self._mpv.play("")
Expand All @@ -304,9 +289,6 @@ def _on_duration_changed(self, duration):
def _on_video_format_changed(self, vformat):
self.video_format = vformat

def _on_video_changed(self, video):
self.video_channel = video

def _on_event(self, event):
event_id = event['event_id']
if event_id == MpvEventID.END_FILE:
Expand All @@ -321,6 +303,7 @@ def _on_event(self, event):
elif event_id == MpvEventID.FILE_LOADED:
# If the media is a live streaming, this event may not be received.
self.media_loaded.emit()
self.media_loaded_v2.emit({'video_format': self._mpv.video_format})
elif event_id == MpvEventID.METADATA_UPDATE:
metadata = dict(self._mpv.metadata or {}) # type: ignore
logger.debug('metadata updated to %s', metadata)
Expand Down

0 comments on commit bf3dbfc

Please sign in to comment.