[Python] How do I use python-mpv with PySlide6 using GL Rendering for Wayland?

Discussão em 'Python' iniciado por Stack, Julho 7, 2025.

  1. Stack

    Stack Membro Participativo

    I'm in the process of updating a media browser application so that it will work with both X11 and Wayland. It currently uses the python-mpv library, and uses the X Window ID which obviously doesn't work in Wayland:

    self.player = mpv.MPV(wid=str(int(self.winId())),
    log_handler=print,
    loglevel='info',
    input_default_bindings=False,
    input_vo_keyboard=False, keep_open='yes',
    volume=self.current_volume,
    osc=init_window_options.show_controls)


    I found the following examples for getting python-mpv working using OpenGL rendering for Qt5/6. I verified the PySide6 example works with both X11 and Wayland. However, the example uses QtQuick and QML rendering. My application uses traditional QWidgets and layouts. I don't want to rewrite my application in QtQuick/QML. From what I've found, it's not advised or supported to mix QtQuick and QtWidget components.

    I found an example that shows the QOpenGLWidget. I've been digging through the documentation to see how I can adapt the renderer from the first example into a QOpenGLWidget, but the APIs seem very different. I took the approach of trying to render the mpv frames within the paintGL() function of a QOpenGLWidget

    import sys

    from OpenGL.GL import glClearColor
    from PySide6.QtGui import QOpenGLContext
    from PySide6.QtWidgets import QPushButton, QHBoxLayout
    from PySide6.QtCore import Qt, Signal, Slot
    from PySide6.QtOpenGLWidgets import QOpenGLWidget
    from PySide6.QtWidgets import QApplication, QWidget
    from mpv import MPV, MpvRenderContext, MpvGlGetProcAddressFn


    def get_process_address(_, name):
    print("get_process_address", name.decode('utf-8'))
    glctx = QOpenGLContext.currentContext()
    if glctx is None:
    return 0
    return int(glctx.getProcAddress(name))


    class MPVWidget(QOpenGLWidget):

    onUpdate = Signal()

    def __init__(self):
    super().__init__()

    self.setWindowTitle("OpenGL ES 2.0, PySide6, Python")
    self.resize(350, 350)
    print("MpvObject.init")
    self.mpv = MPV(ytdl=True, vo='libmpv', terminal="yes", msg_level="all=v")
    self._get_proc_address_resolver = MpvGlGetProcAddressFn(get_process_address)
    self._ctx = MpvRenderContext(
    self.mpv,
    api_type='opengl',
    opengl_init_params={'get_proc_address': self._get_proc_address_resolver}
    )
    self._ctx.update_cb = self._parent.onUpdate.emit
    self.onUpdate.connect(self.doUpdate)

    def on_update(self):
    self.onUpdate.emit()

    @Slot()
    def doUpdate(self):
    self.paintGL()

    @Slot(str)
    def play(self, url):
    print("MpvObject.play")
    self.mpv.play(url)

    def initializeGL(self):
    glClearColor(48 / 255, 56 / 255, 65 / 255, 1)

    def resizeGL(self, w, h):
    pass

    def paintGL(self):
    if self._ctx:
    factor = self._parent.scale()
    rect = self._parent.size()

    width = int(rect.width() * factor)
    height = int(rect.height() * factor)
    fbo = int(self.defaultFramebufferObject())

    self._ctx.render(flip_y=False, opengl_fbo={'w': width, 'h': height, 'fbo': fbo})

    class MainWidget(QWidget):

    def __init__(self):
    super().__init__()
    self. play_button = QPushButton("Play")
    self.play_button.clicked.connect(self.click_play)
    import locale
    locale.setlocale(locale.LC_NUMERIC, 'C')
    mpv_widget = MPVWidget()

    layout = QHBoxLayout()
    layout.addWidget(self.play_button)
    layout.addWidget(mpv_widget)
    self.setLayout(layout.layout())

    @Slot()
    def click_play(self):
    print("click")
    self.mpv_widget.play("demo.mp4")

    if __name__ == "__main__":
    QApplication.setAttribute(Qt.ApplicationAttribute.AA_UseDesktopOpenGL)
    app = QApplication(sys.argv)
    main_widget = MainWidget()
    main_widget.show()
    sys.exit(app.exec())


    However, I get an error that the OpenGL context can't be initialized:

    [libmpv_render] Can't load OpenGL functions.
    [libmpv_render] OpenGL not initialized.
    Traceback (most recent call last):
    File "/home/cassius/src/qtquick-mpv/opengl-example.py", line 92, in <module>
    main_widget = MainWidget()
    File "/home/cassius/src/qtquick-mpv/opengl-example.py", line 77, in __init__
    mpv_widget = MPVWidget()
    File "/home/cassius/src/qtquick-mpv/opengl-example.py", line 32, in __init__
    self._ctx = MpvRenderContext(
    ~~~~~~~~~~~~~~~~^
    self.mpv,
    ^^^^^^^^^
    api_type='opengl',
    ^^^^^^^^^^^^^^^^^^
    opengl_init_params={'get_proc_address': self._get_proc_address_resolver}
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    )
    ^
    File "/home/cassius/src/qtquick-mpv/.venv/lib/python3.13/site-packages/mpv.py", line 2121, in __init__
    _mpv_render_context_create(buf, mpv.handle, kwargs_to_render_param_array(kwargs))
    ~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    File "/home/cassius/src/qtquick-mpv/.venv/lib/python3.13/site-packages/mpv.py", line 142, in raise_for_ec
    raise ex
    ValueError: Generic error for signaling that certain system requirements are not fulfilled


    I realize one big issue is right here:

    fbo = int(self.defaultFramebufferObject())


    In the QQuick example that uses the QQuickFramebufferObject.Renderer, the author of that example calls handle() to get an int representing the OpenGL frame buffer. I can't seem to figure out how to do that using a QtOpenGLWidget default frame buffer.

    The Problem I'm trying to Solve


    I'm not sure if this is even the right approach. The end goal is to get python-mpv outputting in a widget I can hold in a traditional layout that I can use on both X11 or Wayland. It seems like the way this needs to be accomplished is using either the older/legacy Qt5 QQuickFramebufferObject, or the newer QRhi (which can support OpenGL, Vulkn or Metal). However, the only examples I can find that work use QQuick and my existing application is already built around QWidgets.

    How do I get python-mpv working on both X11/Wayland in PyQt6 or PySlide6 (I made a branch of my project that's converted to PySlide6, so either solution would work), presumably using some type of direct rendering context?

    Continue reading...

Compartilhe esta Página