File indexing completed on 2024-05-19 04:45:39

0001 /*
0002  * SPDX-FileCopyrightText: 2023 George Florea Bănuș <georgefb899@gmail.com>
0003  *
0004  * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0005  */
0006 
0007 #include "mpvrenderer.h"
0008 #include "mpvabstractitem.h"
0009 #include "mpvabstractitem_p.h"
0010 #include "mpvcontroller.h"
0011 
0012 #include <QGuiApplication>
0013 #include <QOpenGLContext>
0014 #include <QOpenGLFramebufferObject>
0015 #include <QQuickWindow>
0016 
0017 static void *get_proc_address_mpv(void *ctx, const char *name)
0018 {
0019     Q_UNUSED(ctx)
0020 
0021     QOpenGLContext *glctx = QOpenGLContext::currentContext();
0022     if (!glctx) {
0023         return nullptr;
0024     }
0025 
0026     return reinterpret_cast<void *>(glctx->getProcAddress(QByteArray(name)));
0027 }
0028 
0029 void on_mpv_redraw(void *ctx)
0030 {
0031     QMetaObject::invokeMethod(static_cast<MpvAbstractItem *>(ctx), &MpvAbstractItem::update, Qt::QueuedConnection);
0032 }
0033 
0034 MpvRenderer::MpvRenderer(MpvAbstractItem *new_obj)
0035     : m_mpvAItem{new_obj}
0036 {
0037     m_mpvAItem->window()->setPersistentSceneGraph(true);
0038 }
0039 
0040 void MpvRenderer::render()
0041 {
0042     QOpenGLFramebufferObject *fbo = framebufferObject();
0043     mpv_opengl_fbo mpfbo;
0044     mpfbo.fbo = static_cast<int>(fbo->handle());
0045     mpfbo.w = fbo->width();
0046     mpfbo.h = fbo->height();
0047     mpfbo.internal_format = 0;
0048 
0049     int flip_y{0};
0050 
0051     mpv_render_param params[] = {// Specify the default framebuffer (0) as target. This will
0052                                  // render onto the entire screen. If you want to show the video
0053                                  // in a smaller rectangle or apply fancy transformations, you'll
0054                                  // need to render into a separate FBO and draw it manually.
0055                                  {MPV_RENDER_PARAM_OPENGL_FBO, &mpfbo},
0056                                  {MPV_RENDER_PARAM_FLIP_Y, &flip_y},
0057                                  {MPV_RENDER_PARAM_INVALID, nullptr}};
0058     // See render_gl.h on what OpenGL environment mpv expects, and
0059     // other API details.
0060     mpv_render_context_render(m_mpvAItem->d_ptr->m_mpv_gl, params);
0061 }
0062 
0063 QOpenGLFramebufferObject *MpvRenderer::createFramebufferObject(const QSize &size)
0064 {
0065     // init mpv_gl:
0066     if (!m_mpvAItem->d_ptr->m_mpv_gl) {
0067 #if MPV_CLIENT_API_VERSION < MPV_MAKE_VERSION(2, 0)
0068         mpv_opengl_init_params gl_init_params{get_proc_address_mpv, nullptr, nullptr};
0069 #else
0070         mpv_opengl_init_params gl_init_params{get_proc_address_mpv, nullptr};
0071 #endif
0072 
0073         mpv_render_param display{MPV_RENDER_PARAM_INVALID, nullptr};
0074 #if defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN) && !defined(Q_OS_ANDROID)
0075         if (QGuiApplication::platformName() == QStringLiteral("xcb")) {
0076             display.type = MPV_RENDER_PARAM_X11_DISPLAY;
0077             display.data = qGuiApp->nativeInterface<QNativeInterface::QX11Application>()->display();
0078         }
0079 
0080         if (QGuiApplication::platformName() == QStringLiteral("wayland")) {
0081             display.type = MPV_RENDER_PARAM_WL_DISPLAY;
0082             display.data = qGuiApp->nativeInterface<QNativeInterface::QWaylandApplication>()->display();
0083         }
0084 #endif
0085         mpv_render_param params[]{{MPV_RENDER_PARAM_API_TYPE, const_cast<char *>(MPV_RENDER_API_TYPE_OPENGL)},
0086                                   {MPV_RENDER_PARAM_OPENGL_INIT_PARAMS, &gl_init_params},
0087                                   display,
0088                                   {MPV_RENDER_PARAM_INVALID, nullptr}};
0089 
0090         int result = mpv_render_context_create(&m_mpvAItem->d_ptr->m_mpv_gl, m_mpvAItem->d_ptr->m_mpv, params);
0091         if (result < 0) {
0092             qFatal("failed to initialize mpv GL context");
0093         }
0094 
0095         mpv_render_context_set_update_callback(m_mpvAItem->d_ptr->m_mpv_gl, on_mpv_redraw, m_mpvAItem);
0096         Q_EMIT m_mpvAItem->ready();
0097     }
0098 
0099     return QQuickFramebufferObject::Renderer::createFramebufferObject(size);
0100 }