-
Notifications
You must be signed in to change notification settings - Fork 68
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Windows] Controls do not work in PyQT (?) #103
Comments
I don't know Qt that well myself, but I guess the problem is that Qt catches all input events and they never get forwarded to mpv. My first idea on how to make this work without rewriting all of libmpv's input bindings would be to catch all key press events on the player QWidget and forward them into mpv using the keypress command. There is also a The reason |
Thank you very much @jaseg for your helpful answer. I have tried using the keypress and keybind commands yet they do not seem to work #First I tried this
player.command('keybind esc stop')
player.command('keybind right seek 1 relative')
#And then I tried
player.keybind('esc stop')
player.keybind('right seek 1 relative') Example errors I get:
And when I tried using
Do you have any further suggestions? Thank you. |
@jaseg I have tried your recommendations and have written ...
from pynput import keyboard
def play(url, title):
#From https://stackoverflow.com/q/9377914/
class TitleBar(QWidget):
def __init__(self, parent):
super(MyBar, self).__init__()
self.parent = parent
print(self.parent.width())
self.layout = QHBoxLayout()
self.layout.setContentsMargins(0,0,0,0)
btn_size = 35
self.btn_close = QPushButton("x")
self.btn_close.clicked.connect(self.btn_close_clicked)
self.btn_close.setFixedSize(btn_size,btn_size)
self.btn_close.setStyleSheet("background-color: red;")
self.btn_min = QPushButton("-")
self.btn_min.clicked.connect(self.btn_min_clicked)
self.btn_min.setFixedSize(btn_size, btn_size)
self.btn_min.setStyleSheet("background-color: gray;")
self.btn_max = QPushButton("+")
self.btn_max.clicked.connect(self.btn_max_clicked)
self.btn_max.setFixedSize(btn_size, btn_size)
self.btn_max.setStyleSheet("background-color: gray;")
self.title.setFixedHeight(35)
self.title.setAlignment(Qt.AlignCenter)
self.layout.addWidget(self.btn_min)
self.layout.addWidget(self.btn_max)
self.layout.addWidget(self.btn_close)
self.setLayout(self.layout)
self.start = QPoint(0, 0)
self.pressing = False
def resizeEvent(self, QResizeEvent):
super(MyBar, self).resizeEvent(QResizeEvent)
self.title.setFixedWidth(self.parent.width())
def mousePressEvent(self, event):
self.start = self.mapToGlobal(event.pos())
self.pressing = True
def mouseMoveEvent(self, event):
if self.pressing:
self.end = self.mapToGlobal(event.pos())
self.movement = self.end-self.start
self.parent.setGeometry(self.mapToGlobal(self.movement).x(),
self.mapToGlobal(self.movement).y(),
self.parent.width(),
self.parent.height())
self.start = self.end
def mouseReleaseEvent(self, QMouseEvent):
self.pressing = False
def btn_close_clicked(self):
self.parent.close()
def btn_max_clicked(self):
self.parent.showMaximized()
def btn_min_clicked(self):
self.parent.showMinimized()
class MainWin(QMainWindow):
def on_press(self,key):
print('{0} pressed'.format(
key))
if key == keyboard.Key.right:
self.player.command('seek', '0.2', 'absolute+keyframes')
def on_release(self, key):
print('{0} released'.format(
key))
if key == keyboard.Key.esc:
try:
print("Quitting")
sys.exit('quit')
except KeyboardInterrupt:
sys.exit('quit')
def __init__(self, parent=None):
super().__init__(parent)
self.container = QWidget(self)
self.setCentralWidget(self.container)
self.container.setAttribute(Qt.WA_DontCreateNativeAncestors)
self.container.setAttribute(Qt.WA_NativeWindow)
self.setWindowTitle(title)
self.resize(1000, 563)
self.player = mpv.MPV(wid=str(int(self.container.winId())), ytdl=True, player_operation_mode='pseudo-gui',
script_opts='osc-layout=box,osc-seekbarstyle=bar,osc-deadzonesize=0,osc-minmousemove=3',
input_default_bindings=True,
input_vo_keyboard=True,
osc=True) #
#player.play(url)
# Collect events until released
with keyboard.Listener(
on_press=self.on_press,
on_release=self.on_release) as listener:
Thread(target = self.player.play, args=(url,)).start()
listener.join()
#Process(target=player.play, args=(url,)).start()
#player.wait_for_playback()
del self.player
#@player.command('keybind esc stop')
#def passthru():
# pass
#@player.command('keybind right seek 1 relative')
#def passthru():
# pass
app = QApplication(sys.argv)
import locale
locale.setlocale(locale.LC_NUMERIC, 'C')
win = MainWin()
win.show()
sys.exit(app.exec_())
play(url, title) it registers commands, but does them all in a seperate process, which upon exiting plays the video. I couldn't seem to get keypress or keybind to give me anything but my prior error.
Do you have suggestions? Thank you. |
Are you on windows? |
I found a stackoverflow post on keypresses in PyQt, I will try to tweak it to input to mpv. player commands aren't working
def __init__(self, parent=None): #, parent=None
super(MainWin, self).__init__(parent) #parent
self.container = QWidget(self)
self.setCentralWidget(self.container)
self.container.setAttribute(Qt.WA_DontCreateNativeAncestors)
self.container.setAttribute(Qt.WA_NativeWindow)
self.setWindowTitle(title)
self.resize(1000, 563)
self.player = mpv.MPV(wid=str(int(self.container.winId())), ytdl=True, player_operation_mode='pseudo-gui',
script_opts='osc-layout=box,osc-seekbarstyle=bar,osc-deadzonesize=0,osc-minmousemove=3',
input_default_bindings=True,
input_vo_keyboard=True,
osc=True) #
self.player.play(url)
#player.wait_for_playback()
del self.player
def keyPressEvent(self, event):
if event.key() == Qt.Key_Q:
print("Quitting")
sys.exit('quit')
elif event.key() == Qt.Key_Right:
self.player.command('seek', '0.2', 'absolute+keyframes')
event.accept() |
Sorry in my gist I forgot the options: |
That seems very likely, but I cannot run any VM because of credential guard (whatever that is). I'll continue tweaking the code; and if I cannot find a solution then I can mark it up to libmpv on windows |
Would love to have an update on this, I really like this module |
@reaganiwadha All I can say is that on my (Linux) machine, the example from the README works for me with OP's code, both for keyboard and for mouse input. I only needed to change their custom key binding handler a bit to mesh with both libmpv and PyQt's respective event loops. If things don't work for you, please post an example script that I can run to reproduce the behavior, post your Python, PyQt and libmpv versions, and tell us what operating system you're running things on. At this point, I suspect that this is a Windows-only issue. #!/usr/bin/env python3
import mpv
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class Test(QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.container = QWidget(self)
self.setCentralWidget(self.container)
self.container.setAttribute(Qt.WA_DontCreateNativeAncestors)
self.container.setAttribute(Qt.WA_NativeWindow)
player = mpv.MPV(wid=str(int(self.container.winId())),
vo='x11', # You may not need this
loglevel='debug',
script_opts='osc-layout=box,osc-seekbarstyle=bar,osc-deadzonesize=0,osc-minmousemove=3',
input_default_bindings=True,
input_vo_keyboard=True,
osc=True)
@player.on_key_press('esc')
def my_key_binding(*args):
print('ESC pressed')
# Note: We can't just call sys.exit() here because that would only terminate the python interpreter, but not libmpv or PyQt.
player.quit() # Tell libmpv to terminate itself
QApplication.instance().quit() # Tell PyQt to terminate. This closes the window, and makes PyQt return from app.exec below.
player.loop = 'inf'
player.play('tests/test.webm')
app = QApplication(sys.argv)
# This is necessary since PyQT stomps over the locale settings needed by libmpv.
# This needs to happen after importing PyQT before creating the first mpv.MPV instance.
import locale
locale.setlocale(locale.LC_NUMERIC, 'C')
win = Test()
win.show()
sys.exit(app.exec_()) |
I have the same issue in my GTK application with mpv.py. The overlay controls appear when a video is played in Linux but not in Windows. This appears to be a specific libmpv-2.dll for Windows issue. |
#!/usr/bin/env python3
import time
import gi
import mpv
import platform
import ctypes
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
class MainClass(Gtk.Window):
def __init__(self):
super(MainClass, self).__init__()
self.set_default_size(600, 400)
self.connect("destroy", self.on_destroy)
widget = Gtk.Frame()
self.add(widget)
self.show_all()
IS_WINDOWS = platform.system() == "Windows"
gdk_window = widget.get_property("window")
if gdk_window is not None:
if IS_WINDOWS:
# Windows-specific handling
if not gdk_window.ensure_native():
print("Error - video playback requires a native window")
ctypes.pythonapi.PyCapsule_GetPointer.restype = ctypes.c_void_p
ctypes.pythonapi.PyCapsule_GetPointer.argtypes = [ctypes.py_object]
drawingarea_gpointer = ctypes.cast(ctypes.pythonapi.PyCapsule_GetPointer(gdk_window.__gpointer__, None), ctypes.c_void_p)
gdkdll = ctypes.CDLL("libgdk-3-0.dll")
wid = gdkdll.gdk_win32_window_get_handle(drawingarea_gpointer)
else:
# Linux-specific handling
wid = gdk_window.get_xid()
else:
raise RuntimeError("Failed to get window handle")
# Must be created >after< the widget is shown, else property 'window' will be None
self.mpv = mpv.MPV(wid=str(wid), input_default_bindings=True, input_vo_keyboard=True, osc=True, ytdl=True, loglevel='debug')
video_url = "https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.ism/.m3u8" #test demo m3u8 url which is legal
# video_url = "test.webm"
self.mpv.play(video_url)
def on_destroy(self, widget, data=None):
self.mpv.terminate()
Gtk.main_quit()
if __name__ == '__main__':
# This is necessary since like Qt, Gtk stomps over the locale settings needed by libmpv.
# Like with Qt, this needs to happen after importing Gtk but before creating the first mpv.MPV instance.
import locale
locale.setlocale(locale.LC_NUMERIC, 'C')
application = MainClass()
Gtk.main() I took the reference PyGObject code and created a version which will work on both Windows (with MSYS2) and Linux for testing and I can reproduce the issue easily. In Linux the on-screen controls are visible at the bottom but the Windows it does not. |
Take this code for instance.
It works pretty well, it plays video in the window and it read the video from the
url
variable and the window title fromtitle
. Yet despite me having set not only the pseudo-gui and keyboard bindings, neither of them initiate so inside my window is video playing with no keyboard or in-window controls. I am relatively new to PyQt, so maybe this is a simple to fix issue.Another oddity with the PyQt integration is that wait_for_playback() is automatic, and actually trying to call it prevents the video from playing.
I really like this module, and it is very handy for several of my video projects (ie this)
The text was updated successfully, but these errors were encountered: