Skip to content

Instantly share code, notes, and snippets.

@jaseg
Last active December 2, 2024 19:01
Show Gist options
  • Save jaseg/657e8ecca3267c0d82ec85d40f423caa to your computer and use it in GitHub Desktop.
Save jaseg/657e8ecca3267c0d82ec85d40f423caa to your computer and use it in GitHub Desktop.
Basic test of python-mpv mpv render context mapping used with GTK
#!/usr/bin/env python3
import ctypes
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, GLib
gi.require_version('GL', '1.0')
from OpenGL import GL, GLX
from mpv import MPV, MpvRenderContext, OpenGlCbGetProcAddrFn
def get_process_address(_, name):
address = GLX.glXGetProcAddress(name.decode("utf-8"))
return ctypes.cast(address, ctypes.c_void_p).value
class MainClass(Gtk.Window):
def __init__(self, media):
super(MainClass, self).__init__()
self.media = media
self.set_default_size(600, 400)
self.connect("destroy", self.on_destroy)
frame = Gtk.Frame()
self.area = OpenGlArea()
self.area.connect("realize", self.play)
frame.add(self.area)
self.add(frame)
self.show_all()
def on_destroy(self, widget, data=None):
Gtk.main_quit()
def play(self, arg1):
self.area.play(self.media)
class OpenGlArea(Gtk.GLArea):
def __init__(self, **properties):
super().__init__(**properties)
self._proc_addr_wrapper = OpenGlCbGetProcAddrFn(get_process_address)
self.ctx = None
self.mpv = MPV() # log_handler=print, loglevel='debug')
self.connect("realize", self.on_realize)
self.connect("render", self.on_render)
self.connect("unrealize", self.on_unrealize)
def on_realize(self, area):
print('\033[91mon_realize called\033[0m')
self.make_current()
self.ctx = MpvRenderContext(self.mpv, 'opengl',
opengl_init_params={'get_proc_address': self._proc_addr_wrapper})
self.ctx.update_cb = self.wrapped_c_render_func
def on_unrealize(self, arg):
print('\033[91munrealize called\033[0m')
self.ctx.free()
self.mpv.terminate()
def wrapped_c_render_func(self):
print('\033[91mwrapped_c_render_func called\033[0m')
GLib.idle_add(self.call_frame_ready, None, GLib.PRIORITY_HIGH)
def call_frame_ready(self, *args):
print('\033[91mcall_frame_ready called\033[0m')
if self.ctx.update():
self.queue_render()
def on_render(self, arg1, arg2):
print('\033[91mon_render called\033[0m')
if self.ctx:
factor = self.get_scale_factor()
rect = self.get_allocated_size()[0]
width = rect.width * factor
height = rect.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
return False
def play(self, media):
self.mpv.play(media)
if __name__ == '__main__':
import locale
locale.setlocale(locale.LC_NUMERIC, 'C')
application = MainClass(media='test.webm')
Gtk.main()
@trin94
Copy link

trin94 commented Jan 6, 2020

One final suggestion 🙈

I came across this while seeking very often in quick succession which printed
mpv_render_context_render() not being called or stuck in the logs (msg-level=all=v).

I then had a look at Celluloid (former gnome-mpv):

The Callback asks GLib to call a function whenever there are no higher priority events pending.
The function will emit another event whose handler then queues the redraw.

There is absolutely no difference during normal playback.
But during excessive seeking not all frames will be drawn.

Changes to the sample code

Notice I have omitted the second event ("frame-ready") as I could not notice a performance difference here.

Import

gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Gdk

Code

    def wrapped_c_render_func(self):
        print('\033[91mrender wrapper called\033[0m')
        if self.ctx.update():
            self.queue_render()

⏭️ should be changed to ⏭️

Import

gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, GLib

Code

    def wrapped_c_render_func(self):
        print('\033[91mwrapped_c_render_func called\033[0m')
        GLib.idle_add(self.call_frame_ready, None, GLib.PRIORITY_HIGH)

    def call_frame_ready(self, *args):
        print('\033[91mcall_frame_ready called\033[0m')
        if self.ctx.update():
            self.queue_render()

@jaseg
Copy link
Author

jaseg commented Jan 6, 2020

That makes sense. I've updated the gist. Thank you!

@JPThiel
Copy link

JPThiel commented Sep 8, 2022

On Ubuntu 22.04.1:
I have the import error :
from mpv import MPV, MpvRenderContext,OpenGlCbGetProcAddrFn
ImportError: cannot import name 'OpenGlCbGetProcAddrFn' from 'mpv' (/home/jp/.local/lib/python3.10/site-packages/mpv.py)

On Ubuntu 20.04, it was OK !!!!

Thanks for your response

@trin94
Copy link

trin94 commented Sep 9, 2022

Please use the MpvGlGetProcAddressFn function instead. The usage is the same. 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment