mirror of
https://github.com/martinrotter/rssguard.git
synced 2025-02-03 18:57:37 +01:00
add optional opengl-based rendering for libmpv
This commit is contained in:
parent
a242564f9c
commit
61e15f9042
@ -125,6 +125,7 @@ option(FORCE_BUNDLE_ICONS "Forcibly bundle icon themes into RSS Guard." OFF)
|
||||
option(ENABLE_COMPRESSED_SITEMAP "Enable support for gzip-compressed sitemap feeds. Requires zlib." OFF)
|
||||
option(ENABLE_MEDIAPLAYER_QTMULTIMEDIA "Enable built-in media player. Requires QtMultimedia FFMPEG plugin." OFF)
|
||||
option(ENABLE_MEDIAPLAYER_LIBMPV "Enable built-in media player. Requires libmpv library." ON)
|
||||
option(MEDIAPLAYER_FORCE_OPENGL "Use opengl-based render API with libmpv." ON)
|
||||
|
||||
# Import Qt libraries.
|
||||
set(QT6_MIN_VERSION 6.3.0)
|
||||
@ -168,6 +169,16 @@ if(ENABLE_MEDIAPLAYER_LIBMPV)
|
||||
set(LibMPV_ROOT "${CMAKE_SOURCE_DIR}/resources/scripts/libmpv")
|
||||
endif()
|
||||
|
||||
if(MEDIAPLAYER_FORCE_OPENGL)
|
||||
list(APPEND QT_COMPONENTS OpenGL)
|
||||
|
||||
if(BUILD_WITH_QT6)
|
||||
list(APPEND QT_COMPONENTS OpenGLWidgets)
|
||||
endif()
|
||||
|
||||
add_compile_definitions(MEDIAPLAYER_LIBMPV_OPENGL)
|
||||
endif()
|
||||
|
||||
add_compile_definitions(ENABLE_MEDIAPLAYER_LIBMPV)
|
||||
endif()
|
||||
|
||||
|
@ -832,13 +832,27 @@ endif()
|
||||
|
||||
if(ENABLE_MEDIAPLAYER_QTMULTIMEDIA)
|
||||
target_link_libraries(rssguard PUBLIC
|
||||
Qt${QT_VERSION_MAJOR}::OpenGL
|
||||
Qt${QT_VERSION_MAJOR}::MultimediaWidgets
|
||||
)
|
||||
elseif(ENABLE_MEDIAPLAYER_LIBMPV)
|
||||
if(MEDIAPLAYER_FORCE_OPENGL)
|
||||
target_link_libraries(rssguard PUBLIC
|
||||
Qt${QT_VERSION_MAJOR}::OpenGL
|
||||
)
|
||||
|
||||
if(BUILD_WITH_QT6)
|
||||
target_link_libraries(rssguard PUBLIC
|
||||
Qt${QT_VERSION_MAJOR}::OpenGLWidgets
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
target_include_directories(rssguard AFTER
|
||||
PRIVATE
|
||||
${LibMPV_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
target_link_libraries(rssguard PUBLIC
|
||||
${LibMPV_LIBRARIES}
|
||||
)
|
||||
|
@ -48,12 +48,10 @@ LibMpvBackend::LibMpvBackend(Application* app, QWidget* parent)
|
||||
|
||||
setMouseTracking(true);
|
||||
layout()->addWidget(m_mpvContainer);
|
||||
|
||||
m_mpvContainer->bind();
|
||||
|
||||
mpv_set_option_string(m_mpvHandle, "msg-level", "all=v");
|
||||
mpv_set_option_string(m_mpvHandle, "config", "yes");
|
||||
mpv_set_option_string(m_mpvHandle, "force-window", "yes");
|
||||
mpv_set_option_string(m_mpvHandle, "script-opts", "osc-idlescreen=no");
|
||||
mpv_set_option_string(m_mpvHandle, "hwdec", "auto");
|
||||
mpv_set_option_string(m_mpvHandle, "osd-playing-msg", "${media-title}");
|
||||
@ -121,6 +119,7 @@ void LibMpvBackend::loadSettings() {
|
||||
}
|
||||
|
||||
LibMpvBackend::~LibMpvBackend() {
|
||||
m_mpvContainer->destroyHandle();
|
||||
destroyHandle();
|
||||
}
|
||||
|
||||
@ -155,7 +154,7 @@ void LibMpvBackend::handleMpvEvent(mpv_event* event) {
|
||||
}
|
||||
|
||||
case MPV_EVENT_SHUTDOWN: {
|
||||
destroyHandle();
|
||||
// destroyHandle();
|
||||
emit closed();
|
||||
break;
|
||||
}
|
||||
|
@ -4,6 +4,10 @@
|
||||
|
||||
#include <mpv/client.h>
|
||||
|
||||
#if defined(MEDIAPLAYER_LIBMPV_OPENGL)
|
||||
#include <QOpenGLContext>
|
||||
#endif
|
||||
|
||||
static void wakeup(void* ctx) {
|
||||
// This callback is invoked from any mpv thread (but possibly also
|
||||
// recursively from a thread that is calling the mpv API). Just notify
|
||||
@ -13,13 +17,27 @@ static void wakeup(void* ctx) {
|
||||
emit backend->launchMpvEvents();
|
||||
}
|
||||
|
||||
LibMpvWidget::LibMpvWidget(mpv_handle* mpv_handle, QWidget* parent) : QWidget(parent), m_mpvHandle(mpv_handle) {
|
||||
LibMpvWidget::LibMpvWidget(mpv_handle* mpv_handle, QWidget* parent)
|
||||
: BASE_WIDGET(parent), m_mpvHandle(mpv_handle)
|
||||
#if defined(MEDIAPLAYER_LIBMPV_OPENGL)
|
||||
,
|
||||
m_mpvGl(nullptr)
|
||||
#endif
|
||||
{
|
||||
#if !defined(MEDIAPLAYER_LIBMPV_OPENGL)
|
||||
setAttribute(Qt::WidgetAttribute::WA_DontCreateNativeAncestors);
|
||||
setAttribute(Qt::WidgetAttribute::WA_NativeWindow);
|
||||
#endif
|
||||
|
||||
setMouseTracking(true);
|
||||
}
|
||||
|
||||
LibMpvWidget::~LibMpvWidget() {
|
||||
destroyHandle();
|
||||
}
|
||||
|
||||
void LibMpvWidget::bind() {
|
||||
#if !defined(MEDIAPLAYER_LIBMPV_OPENGL)
|
||||
auto raw_wid = winId();
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
@ -31,6 +49,82 @@ void LibMpvWidget::bind() {
|
||||
#endif
|
||||
|
||||
mpv_set_option(m_mpvHandle, "wid", MPV_FORMAT_INT64, &wid);
|
||||
#endif
|
||||
|
||||
mpv_set_wakeup_callback(m_mpvHandle, wakeup, this);
|
||||
}
|
||||
|
||||
void LibMpvWidget::destroyHandle() {
|
||||
#if defined(MEDIAPLAYER_LIBMPV_OPENGL)
|
||||
makeCurrent();
|
||||
|
||||
if (m_mpvGl != nullptr) {
|
||||
mpv_render_context_free(m_mpvGl);
|
||||
m_mpvGl = nullptr;
|
||||
}
|
||||
|
||||
doneCurrent();
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(MEDIAPLAYER_LIBMPV_OPENGL)
|
||||
static void* get_proc_address(void* ctx, const char* name) {
|
||||
Q_UNUSED(ctx);
|
||||
|
||||
QOpenGLContext* glctx = QOpenGLContext::currentContext();
|
||||
|
||||
if (!glctx) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return reinterpret_cast<void*>(glctx->getProcAddress(QByteArray(name)));
|
||||
}
|
||||
|
||||
void LibMpvWidget::maybeUpdate() {
|
||||
// If the Qt window is not visible, Qt's update() will just skip rendering.
|
||||
// This confuses mpv's render API, and may lead to small occasional
|
||||
// freezes due to video rendering timing out.
|
||||
// Handle this by manually redrawing.
|
||||
// Note: Qt doesn't seem to provide a way to query whether update() will
|
||||
// be skipped, and the following code still fails when e.g. switching
|
||||
// to a different workspace with a reparenting window manager.
|
||||
if (window()->isMinimized()) {
|
||||
makeCurrent();
|
||||
paintGL();
|
||||
context()->swapBuffers(context()->surface());
|
||||
doneCurrent();
|
||||
}
|
||||
else {
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
void LibMpvWidget::on_update(void* ctx) {
|
||||
QMetaObject::invokeMethod((LibMpvWidget*)ctx, "maybeUpdate");
|
||||
}
|
||||
|
||||
void LibMpvWidget::initializeGL() {
|
||||
mpv_opengl_init_params gl_init_params[1] = {get_proc_address, nullptr};
|
||||
mpv_render_param params[]{{MPV_RENDER_PARAM_API_TYPE, const_cast<char*>(MPV_RENDER_API_TYPE_OPENGL)},
|
||||
{MPV_RENDER_PARAM_OPENGL_INIT_PARAMS, &gl_init_params},
|
||||
{MPV_RENDER_PARAM_INVALID, nullptr}};
|
||||
|
||||
if (mpv_render_context_create(&m_mpvGl, m_mpvHandle, params) < 0) {
|
||||
qFatal("failed to initialize mpv GL context");
|
||||
}
|
||||
|
||||
mpv_render_context_set_update_callback(m_mpvGl, LibMpvWidget::on_update, reinterpret_cast<void*>(this));
|
||||
}
|
||||
|
||||
void LibMpvWidget::paintGL() {
|
||||
mpv_opengl_fbo mpfbo{static_cast<int>(defaultFramebufferObject()), width(), height(), 0};
|
||||
int flip_y{1};
|
||||
|
||||
mpv_render_param params[] = {{MPV_RENDER_PARAM_OPENGL_FBO, &mpfbo},
|
||||
{MPV_RENDER_PARAM_FLIP_Y, &flip_y},
|
||||
{MPV_RENDER_PARAM_INVALID, nullptr}};
|
||||
// See render_gl.h on what OpenGL environment mpv expects, and
|
||||
// other API details.
|
||||
mpv_render_context_render(m_mpvGl, params);
|
||||
}
|
||||
#endif
|
||||
|
@ -3,15 +3,27 @@
|
||||
#ifndef LIBMPVWIDGET_H
|
||||
#define LIBMPVWIDGET_H
|
||||
|
||||
#if defined(MEDIAPLAYER_LIBMPV_OPENGL)
|
||||
#include <QOpenGLWidget>
|
||||
|
||||
#include <mpv/render_gl.h>
|
||||
|
||||
#define BASE_WIDGET QOpenGLWidget
|
||||
#else
|
||||
#include <QWidget>
|
||||
#define BASE_WIDGET QWidget
|
||||
#endif
|
||||
|
||||
struct mpv_handle;
|
||||
|
||||
class LibMpvWidget : public QWidget {
|
||||
class LibMpvWidget : public BASE_WIDGET {
|
||||
Q_OBJECT
|
||||
|
||||
friend class LibMpvBackend;
|
||||
|
||||
public:
|
||||
explicit LibMpvWidget(mpv_handle* mpv_handle, QWidget* parent = nullptr);
|
||||
virtual ~LibMpvWidget();
|
||||
|
||||
void bind();
|
||||
|
||||
@ -19,7 +31,23 @@ class LibMpvWidget : public QWidget {
|
||||
void launchMpvEvents();
|
||||
|
||||
private:
|
||||
void destroyHandle();
|
||||
|
||||
mpv_handle* m_mpvHandle;
|
||||
|
||||
#if defined(MEDIAPLAYER_LIBMPV_OPENGL)
|
||||
protected:
|
||||
virtual void initializeGL();
|
||||
virtual void paintGL();
|
||||
|
||||
private slots:
|
||||
void maybeUpdate();
|
||||
|
||||
private:
|
||||
static void on_update(void* ctx);
|
||||
|
||||
mpv_render_context* m_mpvGl;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // LIBMPVWIDGET_H
|
||||
|
@ -266,7 +266,7 @@ int TabWidget::addMediaPlayer(const QString& url, bool make_active) {
|
||||
player->setFocus(Qt::FocusReason::OtherFocusReason);
|
||||
}
|
||||
|
||||
QTimer::singleShot(500, player, [player, url]() {
|
||||
QTimer::singleShot(3000, player, [player, url]() {
|
||||
player->playUrl(url);
|
||||
});
|
||||
|
||||
|
@ -44,6 +44,10 @@
|
||||
#include <QThreadPool>
|
||||
#include <QTimer>
|
||||
|
||||
#if defined(MEDIAPLAYER_LIBMPV_OPENGL)
|
||||
#include <QQuickWindow>
|
||||
#endif
|
||||
|
||||
#if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)
|
||||
#include <QDBusConnection>
|
||||
#include <QDBusMessage>
|
||||
@ -79,6 +83,16 @@
|
||||
|
||||
Application::Application(const QString& id, int& argc, char** argv, const QStringList& raw_cli_args)
|
||||
: SingleApplication(id, argc, argv), m_rawCliArgs(raw_cli_args), m_updateFeedsLock(new Mutex()) {
|
||||
|
||||
#if defined(MEDIAPLAYER_LIBMPV_OPENGL)
|
||||
// HACK: Force rendering system to use OpenGL backend.
|
||||
#if QT_VERSION_MAJOR < 6
|
||||
QQuickWindow::setSceneGraphBackend(QSGRendererInterface::GraphicsApi::OpenGL);
|
||||
#else
|
||||
QQuickWindow::setGraphicsApi(QSGRendererInterface::GraphicsApi::OpenGL);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
QString custom_ua;
|
||||
|
||||
parseCmdArgumentsFromMyInstance(raw_cli_args, custom_ua);
|
||||
|
Loading…
x
Reference in New Issue
Block a user