Skip to content
Extraits de code Groupes Projets

Delete lua + Use OpenGL for MPV

Fermé Kubat a demandé de fusionner delete-lua vers master
3 fichiers
+ 92
36
Comparer les modifications
  • Côte à côte
  • En ligne
Fichiers
3
#include "PreCompiledHeaders.hh"
#include "UI/DocumentViews/MpvContainer.hh"
#include <QtGui/QOpenGLContext>
#include <QtCore/QMetaObject>
#include <mpv/client.h>
#include <mpv/render_gl.h>
using namespace Vivy;
using namespace std::string_literals;
static void *
get_proc_address(void *ctx, const char *name)
{
QOpenGLContext *glctx = QOpenGLContext::currentContext();
if (!glctx)
return nullptr;
return reinterpret_cast<void *>(glctx->getProcAddress(QByteArray(name)));
}
void
MpvContainer::mpvEventWakeUpCB(void *user) noexcept
{
MpvContainer *container = reinterpret_cast<MpvContainer *>(user);
emit container->mpvEvent();
QMetaObject::invokeMethod(reinterpret_cast<MpvContainer *>(user), "mpvEvent",
Qt::QueuedConnection);
}
MpvContainer::MpvContainer(QWidget *parent)
: QWidget(parent)
: QOpenGLWidget(parent)
, mpv(mpv_create())
{
if (mpv == nullptr)
@@ -21,7 +34,7 @@ MpvContainer::MpvContainer(QWidget *parent)
setAttribute(Qt::WA_DontCreateNativeAncestors);
setAttribute(Qt::WA_NativeWindow);
logWarning() << "Don't init MPV by default, you should use the reload button!";
initializeMpv();
}
void
@@ -31,8 +44,6 @@ MpvContainer::initializeMpv()
throw std::logic_error("MPV is already initialized!");
isMpvAlreadyInitialized = true;
quint64 wid = winId();
mpv_set_option(mpv, "wid", MPV_FORMAT_INT64, &wid);
mpv_set_option_string(mpv, "idle", "yes");
mpv_set_option_string(mpv, "loop-file", "inf");
mpv_set_option_string(mpv, "no-config", "yes");
@@ -56,14 +67,42 @@ MpvContainer::initializeMpv()
}
void
MpvContainer::reCreateMpvContext()
MpvContainer::initializeGL()
{
closeMpv();
mpv = mpv_create();
if (mpv == nullptr)
throw std::runtime_error("Failed to create the MPV context");
initializeMpv();
loadFile(previousLoadedFile);
mpv_opengl_init_params gl_init_params;
memset(&gl_init_params, 0, sizeof(mpv_opengl_init_params));
gl_init_params.get_proc_address = get_proc_address;
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(&mpv_gl, mpv, params) < 0) {
throw std::runtime_error("failed to initialize mpv GL context");
} else {
mpv_render_context_set_update_callback(mpv_gl, MpvContainer::onUpdate,
reinterpret_cast<void *>(this));
}
}
void
MpvContainer::paintGL() noexcept
{
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(mpv_gl, params);
}
void
MpvContainer::onUpdate(void *ctx) noexcept
{
QMetaObject::invokeMethod(reinterpret_cast<MpvContainer *>(ctx), "maybeUpdate");
}
void
@@ -82,24 +121,24 @@ MpvContainer::registerMpvDurationCallback(std::function<void(double)> callback)
mpvDurationCallback = callback;
}
void
MpvContainer::closeMpv() noexcept
MpvContainer::~MpvContainer() noexcept
{
makeCurrent();
logDebug() << "Closing the MPV context";
if (mpv_gl) {
mpv_render_context_free(mpv_gl);
}
if (mpv) {
logDebug() << "Closing the MPV context";
asyncCommand(AsyncCmdType::None, { "quit", nullptr });
mpv_wait_async_requests(mpv);
registerMpvTimeCallback(nullptr);
registerMpvDurationCallback(nullptr);
asyncCommand(AsyncCmdType::None, { "quit", nullptr });
mpv_wait_async_requests(mpv);
mpv_destroy(mpv);
mpv = nullptr; // Stop all other callbacks here
isMpvAlreadyInitialized = false; // De-init
}
}
MpvContainer::~MpvContainer() noexcept { closeMpv(); }
void
MpvContainer::handleMpvEvent(const mpv_event *const event) noexcept
{
@@ -117,7 +156,7 @@ MpvContainer::handleMpvEvent(const mpv_event *const event) noexcept
};
switch (event->event_id) {
case MPV_EVENT_SHUTDOWN: closeMpv(); break;
case MPV_EVENT_SHUTDOWN: logWarning() << "Ignore shutdown event for now..."; break;
case MPV_EVENT_LOG_MESSAGE:
msg = reinterpret_cast<mpv_event_log_message *>(event->data);
@@ -233,6 +272,27 @@ MpvContainer::onMpvEvent() noexcept
}
}
// Make Qt invoke mpv_render_context_render() to draw a new/updated video frame.
void
MpvContainer::maybeUpdate() noexcept
{
// 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
MpvContainer::loadFile(const QString &filename) noexcept
{
@@ -268,7 +328,7 @@ MpvContainer::printMpvError(int rc) const noexcept
if (rc == MPV_ERROR_SUCCESS)
return;
logError() << "MPV error:" << mpv_error_string(rc);
logError() << "MPV error: " << mpv_error_string(rc);
}
void
@@ -288,10 +348,6 @@ MpvContainer::mpvPause() noexcept
void
MpvContainer::mpvTogglePlayback() noexcept
{
if (!isMpvAlreadyInitialized) {
reCreateMpvContext();
}
logDebug() << "MPV: Toggling the playback";
asyncCommand(AsyncCmdType::TogglePlayback, { "cycle", "pause", "up", nullptr });
}
Chargement en cours