7944e4e21b
Basic UI outline with keyboard control. Python database object is exposed to QML and data can be queried from its methods. This should provide a generic structure that different UI themes can be built around.
88 lines
3.2 KiB
Python
88 lines
3.2 KiB
Python
from PyQt5.QtCore import QUrl, QSize, pyqtSignal, pyqtSlot
|
|
from PyQt5.QtGui import QOpenGLFramebufferObject
|
|
from PyQt5.QtOpenGL import QGLContext
|
|
from PyQt5.QtQuick import QQuickFramebufferObject
|
|
from mpv import MPV, MpvRenderContext, OpenGlCbGetProcAddrFn
|
|
|
|
|
|
def get_process_address(_, name):
|
|
glctx = QGLContext.currentContext()
|
|
if glctx is None:
|
|
return 0
|
|
return int(glctx.getProcAddress(name.decode('utf-8')))
|
|
|
|
|
|
class MpvObject(QQuickFramebufferObject):
|
|
"""MpvObject:
|
|
This is a QML widget that can be used to embed the output of a mpv instance.
|
|
It extends the QQuickFramebufferObject class to implement this functionality."""
|
|
|
|
# This signal allows triggers the update function to run on the correct thread
|
|
onUpdate = pyqtSignal()
|
|
|
|
def __init__(self, parent=None):
|
|
print("Creating MpvObject")
|
|
super(MpvObject, self).__init__(parent)
|
|
self.mpv = MPV(ytdl=True)
|
|
self.mpv_gl = None
|
|
self._proc_addr_wrapper = OpenGlCbGetProcAddrFn(get_process_address)
|
|
self.onUpdate.connect(self.doUpdate)
|
|
|
|
def on_update(self):
|
|
"""Function for mpv to call to trigger a framebuffer update"""
|
|
self.onUpdate.emit()
|
|
|
|
@pyqtSlot()
|
|
def doUpdate(self):
|
|
"""Slot for receiving the update event on the correct thread"""
|
|
self.update()
|
|
|
|
def createRenderer(self) -> 'QQuickFramebufferObject.Renderer':
|
|
"""Overrides the default createRenderer function to create a
|
|
MpvRenderer instance"""
|
|
print("Calling overridden createRenderer")
|
|
return MpvRenderer(self)
|
|
|
|
@pyqtSlot(str)
|
|
def play(self, url):
|
|
"""Temporary adapter fuction that allowing playing media from QML"""
|
|
self.mpv.play(url)
|
|
|
|
|
|
class MpvRenderer(QQuickFramebufferObject.Renderer):
|
|
"""MpvRenderer:
|
|
This class implements the QQuickFramebufferObject's Renderer subsystem.
|
|
It augments the base renderer with an instance of mpv's render API."""
|
|
|
|
def __init__(self, parent=None):
|
|
print("Creating MpvRenderer")
|
|
super(MpvRenderer, self).__init__()
|
|
self.obj = parent
|
|
self.ctx = None
|
|
|
|
def createFramebufferObject(self, size: QSize) -> QOpenGLFramebufferObject:
|
|
"""Overrides the base createFramebufferObject function, augmenting it to
|
|
create an MpvRenderContext using opengl"""
|
|
if self.obj.mpv_gl is None:
|
|
print("Creating mpv gl")
|
|
self.ctx = MpvRenderContext(self.obj.mpv, 'opengl',
|
|
opengl_init_params={
|
|
'get_proc_address': self.obj._proc_addr_wrapper
|
|
})
|
|
self.ctx.update_cb = self.obj.on_update
|
|
|
|
return QQuickFramebufferObject.Renderer.createFramebufferObject(self, size)
|
|
|
|
def render(self):
|
|
"""Overrides the base render function, calling mpv's render functions instead"""
|
|
if self.ctx:
|
|
factor = self.obj.scale()
|
|
rect = self.obj.size()
|
|
|
|
# width and height are floats
|
|
width = int(rect.width() * factor)
|
|
height = int(rect.height() * factor)
|
|
fbo = int(self.framebufferObject().handle())
|
|
|
|
self.ctx.render(flip_y=False, opengl_fbo={'w': width, 'h': height, 'fbo': fbo})
|