import ctypes import sys import gi gi.require_version("Gtk", "4.0") from gi.repository import GLib, Gtk from mpv import MPV, MpvGlGetProcAddressFn, MpvRenderContext from OpenGL import GL class MyApplication(Gtk.Application): def __init__(self): super().__init__(application_id="org.example.App") self.renderer = MyRenderer() self.renderer.connect("realize", self.on_renderer_ready) def on_renderer_ready(self, *_): self.renderer.play("test.webm") def do_activate(self): win = self.props.active_window if not win: win = Gtk.ApplicationWindow(application=self) win.set_default_size(1280, 720) win.set_child(self.renderer) win.present() class MyRenderer(Gtk.GLArea): def __init__(self, **properties): super().__init__(**properties) self.set_auto_render(False) self.connect("realize", self.on_realize) self._mpv = MPV(vo="libmpv", keep_open="yes") self._ctx = None self._ctx_opengl_params = {"get_proc_address": MpvGlGetProcAddressFn(get_proc_address_wrapper())} def on_realize(self, *_): self.make_current() self._ctx = MpvRenderContext(self._mpv, "opengl", opengl_init_params=self._ctx_opengl_params) self._ctx.update_cb = self.on_mpv_callback def on_mpv_callback(self): GLib.idle_add(self.call_frame_ready, None, GLib.PRIORITY_HIGH) def call_frame_ready(self, *_): if self._ctx.update(): self.queue_render() def do_render(self, *_): if not self._ctx: return False factor = self.get_scale_factor() width = self.get_width() * factor height = self.get_height() * factor fbo = GL.glGetIntegerv(GL.GL_DRAW_FRAMEBUFFER_BINDING) self._ctx.render(flip_y=True, opengl_fbo={"w": width, "h": height, "fbo": fbo}) return True def play(self, file): self._mpv.play(file) def get_proc_address_wrapper(): def glx_impl(name: bytes): from OpenGL import GLX return GLX.glXGetProcAddress(name.decode("utf-8")) def egl_impl(name: bytes): from OpenGL import EGL return EGL.eglGetProcAddress(name.decode("utf-8")) platform_func = None try: from OpenGL import GLX platform_func = glx_impl except (AttributeError, ImportError): pass if platform_func is None: try: from OpenGL import EGL platform_func = egl_impl except (AttributeError, ImportError): pass if platform_func is None: raise RuntimeError("Cannot initialize OpenGL") def wrapper(_, name: bytes): address = platform_func(name) return ctypes.cast(address, ctypes.c_void_p).value return wrapper if __name__ == "__main__": sys.exit(MyApplication().run(sys.argv))