[Backend] Source formatted with clang-format.
This commit is contained in:
parent
6b1078f93b
commit
8fc36d20b7
|
@ -1,337 +1,372 @@
|
||||||
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <clocale>
|
#include <clocale>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
#include "MpvPlayerBackend.h"
|
#include "MpvPlayerBackend.h"
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QQuickWindow>
|
|
||||||
#include <QOpenGLContext>
|
#include <QOpenGLContext>
|
||||||
#include <QOpenGLFramebufferObject>
|
#include <QOpenGLFramebufferObject>
|
||||||
|
#include <QQuickWindow>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
namespace
|
void
|
||||||
|
wakeup(void* ctx)
|
||||||
{
|
{
|
||||||
|
QMetaObject::invokeMethod(
|
||||||
void wakeup(void *ctx)
|
(MpvPlayerBackend*)ctx, "on_mpv_events", Qt::QueuedConnection);
|
||||||
{
|
|
||||||
QMetaObject::invokeMethod((MpvPlayerBackend*)ctx, "on_mpv_events", Qt::QueuedConnection);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_mpv_redraw(void *ctx)
|
void
|
||||||
|
on_mpv_redraw(void* ctx)
|
||||||
{
|
{
|
||||||
MpvPlayerBackend::on_update(ctx);
|
MpvPlayerBackend::on_update(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *get_proc_address_mpv(void *ctx, const char *name)
|
static void*
|
||||||
|
get_proc_address_mpv(void* ctx, const char* name)
|
||||||
{
|
{
|
||||||
Q_UNUSED(ctx)
|
Q_UNUSED(ctx)
|
||||||
|
|
||||||
QOpenGLContext *glctx = QOpenGLContext::currentContext();
|
QOpenGLContext* glctx = QOpenGLContext::currentContext();
|
||||||
if (!glctx) return nullptr;
|
if (!glctx)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
return reinterpret_cast<void *>(glctx->getProcAddress(QByteArray(name)));
|
return reinterpret_cast<void*>(glctx->getProcAddress(QByteArray(name)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
}
|
|
||||||
|
|
||||||
class MpvRenderer : public QQuickFramebufferObject::Renderer
|
class MpvRenderer : public QQuickFramebufferObject::Renderer
|
||||||
{
|
{
|
||||||
MpvPlayerBackend *obj;
|
MpvPlayerBackend* obj;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
MpvRenderer(MpvPlayerBackend* new_obj)
|
||||||
|
: obj{ new_obj }
|
||||||
|
{}
|
||||||
|
|
||||||
MpvRenderer(MpvPlayerBackend *new_obj)
|
virtual ~MpvRenderer() {}
|
||||||
: obj{new_obj}
|
|
||||||
{
|
// This function is called when a new FBO is needed.
|
||||||
|
// This happens on the initial frame.
|
||||||
|
QOpenGLFramebufferObject* createFramebufferObject(const QSize& size)
|
||||||
|
{
|
||||||
|
// init mpv_gl:
|
||||||
|
if (!obj->mpv_gl) {
|
||||||
|
mpv_opengl_init_params gl_init_params{ get_proc_address_mpv,
|
||||||
|
nullptr,
|
||||||
|
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(&obj->mpv_gl, obj->mpv, params) < 0)
|
||||||
|
throw std::runtime_error("failed to initialize mpv GL context");
|
||||||
|
mpv_render_context_set_update_callback(obj->mpv_gl, on_mpv_redraw, obj);
|
||||||
|
QMetaObject::invokeMethod(obj, "startPlayer");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return QQuickFramebufferObject::Renderer::createFramebufferObject(size);
|
||||||
|
}
|
||||||
|
|
||||||
virtual ~MpvRenderer() {}
|
void render()
|
||||||
|
{
|
||||||
|
obj->window()->resetOpenGLState();
|
||||||
|
|
||||||
// This function is called when a new FBO is needed.
|
QOpenGLFramebufferObject* fbo = framebufferObject();
|
||||||
// This happens on the initial frame.
|
mpv_opengl_fbo mpfbo{ .fbo = static_cast<int>(fbo->handle()),
|
||||||
QOpenGLFramebufferObject * createFramebufferObject(const QSize &size)
|
.w = fbo->width(),
|
||||||
{
|
.h = fbo->height(),
|
||||||
// init mpv_gl:
|
.internal_format = 0 };
|
||||||
if (!obj->mpv_gl)
|
int flip_y{ 0 };
|
||||||
{
|
|
||||||
mpv_opengl_init_params gl_init_params{get_proc_address_mpv, nullptr, 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(&obj->mpv_gl, obj->mpv, params) < 0)
|
mpv_render_param params[] = {
|
||||||
throw std::runtime_error("failed to initialize mpv GL context");
|
// Specify the default framebuffer (0) as target. This will
|
||||||
mpv_render_context_set_update_callback(obj->mpv_gl, on_mpv_redraw, obj);
|
// render onto the entire screen. If you want to show the video
|
||||||
QMetaObject::invokeMethod(obj,"startPlayer");
|
// in a smaller rectangle or apply fancy transformations, you'll
|
||||||
}
|
// need to render into a separate FBO and draw it manually.
|
||||||
|
{ MPV_RENDER_PARAM_OPENGL_FBO, &mpfbo },
|
||||||
return QQuickFramebufferObject::Renderer::createFramebufferObject(size);
|
// Flip rendering (needed due to flipped GL coordinate system).
|
||||||
}
|
{ MPV_RENDER_PARAM_FLIP_Y, &flip_y },
|
||||||
|
{ MPV_RENDER_PARAM_INVALID, nullptr }
|
||||||
|
};
|
||||||
void render()
|
// See render_gl.h on what OpenGL environment mpv expects, and
|
||||||
{
|
// other API details.
|
||||||
|
mpv_render_context_render(obj->mpv_gl, params);
|
||||||
obj->window()->resetOpenGLState();
|
obj->window()->resetOpenGLState();
|
||||||
|
}
|
||||||
QOpenGLFramebufferObject *fbo = framebufferObject();
|
|
||||||
mpv_opengl_fbo mpfbo{.fbo = static_cast<int>(fbo->handle()), .w = fbo->width(), .h = fbo->height(), .internal_format = 0};
|
|
||||||
int flip_y{0};
|
|
||||||
|
|
||||||
mpv_render_param params[] = {
|
|
||||||
// Specify the default framebuffer (0) as target. This will
|
|
||||||
// render onto the entire screen. If you want to show the video
|
|
||||||
// in a smaller rectangle or apply fancy transformations, you'll
|
|
||||||
// need to render into a separate FBO and draw it manually.
|
|
||||||
{MPV_RENDER_PARAM_OPENGL_FBO, &mpfbo},
|
|
||||||
// Flip rendering (needed due to flipped GL coordinate system).
|
|
||||||
{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(obj->mpv_gl, params);
|
|
||||||
obj->window()->resetOpenGLState();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
MpvPlayerBackend::MpvPlayerBackend(QQuickItem * parent)
|
MpvPlayerBackend::MpvPlayerBackend(QQuickItem* parent)
|
||||||
: QQuickFramebufferObject(parent), mpv{mpv_create()}, mpv_gl(nullptr)
|
: QQuickFramebufferObject(parent)
|
||||||
|
, mpv{ mpv_create() }
|
||||||
|
, mpv_gl(nullptr)
|
||||||
{
|
{
|
||||||
|
if (!mpv)
|
||||||
|
throw std::runtime_error("could not create mpv context");
|
||||||
|
|
||||||
if (!mpv)
|
mpv_set_option_string(mpv, "terminal", "yes");
|
||||||
throw std::runtime_error("could not create mpv context");
|
mpv_set_option_string(mpv, "msg-level", "all=v");
|
||||||
|
|
||||||
mpv_set_option_string(mpv, "terminal", "yes");
|
// Fix?
|
||||||
mpv_set_option_string(mpv, "msg-level", "all=v");
|
mpv_set_option_string(mpv, "ytdl", "yes");
|
||||||
|
mpv_set_option_string(mpv, "vo", "libmpv");
|
||||||
|
// mpp_set_option_string(mpv, "no-sub-ass", "yes)
|
||||||
|
|
||||||
// Fix?
|
mpv_set_option_string(mpv, "slang", "en");
|
||||||
mpv_set_option_string(mpv, "ytdl", "yes");
|
|
||||||
mpv_set_option_string(mpv, "vo", "libmpv");
|
|
||||||
//mpp_set_option_string(mpv, "no-sub-ass", "yes)
|
|
||||||
|
|
||||||
mpv_set_option_string(mpv, "slang", "en");
|
mpv_set_option_string(mpv, "config", "yes");
|
||||||
|
// mpv_set_option_string(mpv, "sub-visibility", "no");
|
||||||
|
|
||||||
mpv_set_option_string(mpv, "config", "yes");
|
mpv_observe_property(mpv, 0, "playback-abort", MPV_FORMAT_NONE);
|
||||||
//mpv_set_option_string(mpv, "sub-visibility", "no");
|
mpv_observe_property(mpv, 0, "chapter-list", MPV_FORMAT_NODE);
|
||||||
|
mpv_observe_property(mpv, 0, "track-list", MPV_FORMAT_NODE);
|
||||||
|
mpv_observe_property(mpv, 0, "playlist-pos", MPV_FORMAT_DOUBLE);
|
||||||
|
mpv_observe_property(mpv, 0, "volume", MPV_FORMAT_DOUBLE);
|
||||||
|
mpv_observe_property(mpv, 0, "muted", MPV_FORMAT_DOUBLE);
|
||||||
|
mpv_observe_property(mpv, 0, "duration", MPV_FORMAT_DOUBLE);
|
||||||
|
mpv_observe_property(mpv, 0, "media-title", MPV_FORMAT_STRING);
|
||||||
|
mpv_observe_property(mpv, 0, "sub-text", MPV_FORMAT_STRING);
|
||||||
|
mpv_observe_property(mpv, 0, "time-pos", MPV_FORMAT_DOUBLE);
|
||||||
|
mpv_observe_property(mpv, 0, "demuxer-cache-duration", MPV_FORMAT_DOUBLE);
|
||||||
|
mpv_observe_property(mpv, 0, "pause", MPV_FORMAT_NONE);
|
||||||
|
mpv_set_wakeup_callback(mpv, wakeup, this);
|
||||||
|
|
||||||
|
if (mpv_initialize(mpv) < 0)
|
||||||
|
throw std::runtime_error("could not initialize mpv context");
|
||||||
|
|
||||||
|
connect(this,
|
||||||
|
&MpvPlayerBackend::onUpdate,
|
||||||
|
this,
|
||||||
mpv_observe_property(mpv, 0, "playback-abort", MPV_FORMAT_NONE);
|
&MpvPlayerBackend::doUpdate,
|
||||||
mpv_observe_property(mpv, 0, "chapter-list", MPV_FORMAT_NODE);
|
Qt::QueuedConnection);
|
||||||
mpv_observe_property(mpv, 0, "track-list", MPV_FORMAT_NODE);
|
|
||||||
mpv_observe_property(mpv, 0, "playlist-pos", MPV_FORMAT_DOUBLE);
|
|
||||||
mpv_observe_property(mpv, 0, "volume", MPV_FORMAT_DOUBLE);
|
|
||||||
mpv_observe_property(mpv, 0, "muted", MPV_FORMAT_DOUBLE);
|
|
||||||
mpv_observe_property(mpv, 0, "duration", MPV_FORMAT_DOUBLE);
|
|
||||||
mpv_observe_property(mpv, 0, "media-title", MPV_FORMAT_STRING);
|
|
||||||
mpv_observe_property(mpv, 0, "sub-text", MPV_FORMAT_STRING);
|
|
||||||
mpv_observe_property(mpv, 0, "time-pos", MPV_FORMAT_DOUBLE);
|
|
||||||
mpv_observe_property(mpv, 0, "demuxer-cache-duration", MPV_FORMAT_DOUBLE);
|
|
||||||
mpv_observe_property(mpv, 0, "pause", MPV_FORMAT_NONE);
|
|
||||||
mpv_set_wakeup_callback(mpv, wakeup, this);
|
|
||||||
|
|
||||||
if (mpv_initialize(mpv) < 0)
|
|
||||||
throw std::runtime_error("could not initialize mpv context");
|
|
||||||
|
|
||||||
connect(this, &MpvPlayerBackend::onUpdate, this, &MpvPlayerBackend::doUpdate,
|
|
||||||
Qt::QueuedConnection);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MpvPlayerBackend::~MpvPlayerBackend()
|
MpvPlayerBackend::~MpvPlayerBackend()
|
||||||
{
|
{
|
||||||
if (mpv_gl)
|
if (mpv_gl) {
|
||||||
{
|
mpv_render_context_free(mpv_gl);
|
||||||
mpv_render_context_free(mpv_gl);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
mpv_terminate_destroy(mpv);
|
mpv_terminate_destroy(mpv);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MpvPlayerBackend::on_update(void *ctx)
|
void
|
||||||
|
MpvPlayerBackend::on_update(void* ctx)
|
||||||
{
|
{
|
||||||
MpvPlayerBackend *self = (MpvPlayerBackend *)ctx;
|
MpvPlayerBackend* self = (MpvPlayerBackend*)ctx;
|
||||||
emit self->onUpdate();
|
emit self->onUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
// connected to onUpdate(); signal makes sure it runs on the GUI thread
|
// connected to onUpdate(); signal makes sure it runs on the GUI thread
|
||||||
void MpvPlayerBackend::doUpdate()
|
void
|
||||||
|
MpvPlayerBackend::doUpdate()
|
||||||
{
|
{
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QVariant
|
||||||
QVariant MpvPlayerBackend::getProperty(const QString &name) const
|
MpvPlayerBackend::getProperty(const QString& name) const
|
||||||
{
|
{
|
||||||
return mpv::qt::get_property_variant(mpv, name);
|
return mpv::qt::get_property_variant(mpv, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
void MpvPlayerBackend::command(const QVariant& params)
|
MpvPlayerBackend::command(const QVariant& params)
|
||||||
{
|
{
|
||||||
qDebug() << params;
|
qDebug() << params;
|
||||||
mpv::qt::command_variant(mpv, params);
|
mpv::qt::command_variant(mpv, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MpvPlayerBackend::setProperty(const QString& name, const QVariant& value)
|
void
|
||||||
|
MpvPlayerBackend::setProperty(const QString& name, const QVariant& value)
|
||||||
{
|
{
|
||||||
mpv::qt::set_property_variant(mpv, name, value);
|
mpv::qt::set_property_variant(mpv, name, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MpvPlayerBackend::setOption(const QString& name, const QVariant& value)
|
void
|
||||||
|
MpvPlayerBackend::setOption(const QString& name, const QVariant& value)
|
||||||
{
|
{
|
||||||
mpv::qt::set_option_variant(mpv, name, value);
|
mpv::qt::set_option_variant(mpv, name, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MpvPlayerBackend::launchAboutQt()
|
void
|
||||||
|
MpvPlayerBackend::launchAboutQt()
|
||||||
{
|
{
|
||||||
QApplication *qapp = qobject_cast<QApplication *>(QCoreApplication::instance());
|
QApplication* qapp =
|
||||||
qapp->aboutQt();
|
qobject_cast<QApplication*>(QCoreApplication::instance());
|
||||||
|
qapp->aboutQt();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MpvPlayerBackend::togglePlayPause()
|
void
|
||||||
|
MpvPlayerBackend::togglePlayPause()
|
||||||
{
|
{
|
||||||
command(QVariantList() << "cycle" << "pause");
|
command(QVariantList() << "cycle"
|
||||||
|
<< "pause");
|
||||||
}
|
}
|
||||||
|
|
||||||
void MpvPlayerBackend::toggleMute()
|
void
|
||||||
|
MpvPlayerBackend::toggleMute()
|
||||||
{
|
{
|
||||||
command(QVariantList() << "cycle" << "mute");
|
command(QVariantList() << "cycle"
|
||||||
|
<< "mute");
|
||||||
}
|
}
|
||||||
|
|
||||||
void MpvPlayerBackend::nextAudioTrack()
|
void
|
||||||
|
MpvPlayerBackend::nextAudioTrack()
|
||||||
{
|
{
|
||||||
command(QVariantList() << "cycle" << "audio");
|
command(QVariantList() << "cycle"
|
||||||
|
<< "audio");
|
||||||
}
|
}
|
||||||
void MpvPlayerBackend::nextSubtitleTrack()
|
void
|
||||||
|
MpvPlayerBackend::nextSubtitleTrack()
|
||||||
{
|
{
|
||||||
command(QVariantList() << "cycle" << "sub");
|
command(QVariantList() << "cycle"
|
||||||
|
<< "sub");
|
||||||
}
|
}
|
||||||
|
|
||||||
void MpvPlayerBackend::nextVideoTrack()
|
void
|
||||||
|
MpvPlayerBackend::nextVideoTrack()
|
||||||
{
|
{
|
||||||
command(QVariantList() << "cycle" << "video");
|
command(QVariantList() << "cycle"
|
||||||
|
<< "video");
|
||||||
}
|
}
|
||||||
|
|
||||||
void MpvPlayerBackend::prevPlaylistItem()
|
void
|
||||||
|
MpvPlayerBackend::prevPlaylistItem()
|
||||||
{
|
{
|
||||||
command(QVariantList() << "playlist-prev");
|
command(QVariantList() << "playlist-prev");
|
||||||
}
|
}
|
||||||
|
|
||||||
void MpvPlayerBackend::nextPlaylistItem()
|
void
|
||||||
|
MpvPlayerBackend::nextPlaylistItem()
|
||||||
{
|
{
|
||||||
command(QVariantList() << "playlist-next" << "force");
|
command(QVariantList() << "playlist-next"
|
||||||
|
<< "force");
|
||||||
}
|
}
|
||||||
|
|
||||||
void MpvPlayerBackend::loadFile(const QVariant &filename)
|
void
|
||||||
|
MpvPlayerBackend::loadFile(const QVariant& filename)
|
||||||
{
|
{
|
||||||
command(QVariantList() << "loadfile" << filename);
|
command(QVariantList() << "loadfile" << filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MpvPlayerBackend::setVolume(const QVariant &volume)
|
void
|
||||||
|
MpvPlayerBackend::setVolume(const QVariant& volume)
|
||||||
{
|
{
|
||||||
command(QVariantList() << "set" << "volume" << volume);
|
command(QVariantList() << "set"
|
||||||
|
<< "volume" << volume);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MpvPlayerBackend::addVolume(const QVariant &volume)
|
void
|
||||||
|
MpvPlayerBackend::addVolume(const QVariant& volume)
|
||||||
{
|
{
|
||||||
command(QVariantList() << "add" << "volume" << volume);
|
command(QVariantList() << "add"
|
||||||
|
<< "volume" << volume);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MpvPlayerBackend::seek(const QVariant &seekTime)
|
void
|
||||||
|
MpvPlayerBackend::seek(const QVariant& seekTime)
|
||||||
{
|
{
|
||||||
command(QVariantList() << "seek" << seekTime);
|
command(QVariantList() << "seek" << seekTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant MpvPlayerBackend::getTracks() const
|
QVariant
|
||||||
|
MpvPlayerBackend::getTracks() const
|
||||||
{
|
{
|
||||||
return mpv::qt::get_property_variant(mpv, "track-list");
|
return mpv::qt::get_property_variant(mpv, "track-list");
|
||||||
}
|
}
|
||||||
|
|
||||||
void MpvPlayerBackend::on_mpv_events()
|
void
|
||||||
|
MpvPlayerBackend::on_mpv_events()
|
||||||
{
|
{
|
||||||
while (mpv) {
|
while (mpv) {
|
||||||
mpv_event *event = mpv_wait_event(mpv, 0);
|
mpv_event* event = mpv_wait_event(mpv, 0);
|
||||||
|
|
||||||
if (event->event_id == MPV_EVENT_NONE) {
|
if (event->event_id == MPV_EVENT_NONE) {
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
handle_mpv_event(event);
|
|
||||||
}
|
}
|
||||||
|
handle_mpv_event(event);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MpvPlayerBackend::handle_mpv_event(mpv_event *event)
|
void
|
||||||
|
MpvPlayerBackend::handle_mpv_event(mpv_event* event)
|
||||||
{
|
{
|
||||||
switch (event->event_id) {
|
switch (event->event_id) {
|
||||||
case MPV_EVENT_PROPERTY_CHANGE: {
|
case MPV_EVENT_PROPERTY_CHANGE: {
|
||||||
mpv_event_property *prop = (mpv_event_property *)event->data;
|
mpv_event_property* prop = (mpv_event_property*)event->data;
|
||||||
if (strcmp(prop->name, "time-pos") == 0) {
|
if (strcmp(prop->name, "time-pos") == 0) {
|
||||||
if (prop->format == MPV_FORMAT_DOUBLE) {
|
if (prop->format == MPV_FORMAT_DOUBLE) {
|
||||||
double time = *(double *)prop->data;
|
double time = *(double*)prop->data;
|
||||||
QMetaObject::invokeMethod(this,"setProgressBarValue",Q_ARG(QVariant,time));
|
QMetaObject::invokeMethod(
|
||||||
}
|
this, "setProgressBarValue", Q_ARG(QVariant, time));
|
||||||
} else if (strcmp(prop->name, "duration") == 0) {
|
|
||||||
if (prop->format == MPV_FORMAT_DOUBLE) {
|
|
||||||
double time = *(double *)prop->data;Q_ARG(QVariant,"txt1"),
|
|
||||||
QMetaObject::invokeMethod(this,"setProgressBarEnd",Q_ARG(QVariant,time));
|
|
||||||
}
|
|
||||||
} else if (strcmp(prop->name, "volume") == 0) {
|
|
||||||
if (prop->format == MPV_FORMAT_DOUBLE) {
|
|
||||||
double volume = *(double *)prop->data;
|
|
||||||
QMetaObject::invokeMethod(this,"updateVolume",Q_ARG(QVariant,volume));
|
|
||||||
}
|
|
||||||
} else if (strcmp(prop->name, "muted") == 0) {
|
|
||||||
if (prop->format == MPV_FORMAT_DOUBLE) {
|
|
||||||
double muted = *(double *)prop->data;
|
|
||||||
QMetaObject::invokeMethod(this,"updateMuted",Q_ARG(QVariant,muted));
|
|
||||||
}
|
|
||||||
} else if (strcmp(prop->name, "media-title") == 0) {
|
|
||||||
if (prop->format == MPV_FORMAT_STRING) {
|
|
||||||
char *title = *(char **)prop->data;
|
|
||||||
QMetaObject::invokeMethod(this,"setTitle",Q_ARG(QVariant,title));
|
|
||||||
}
|
|
||||||
} else if (strcmp(prop->name, "sub-text") == 0) {
|
|
||||||
if (prop->format == MPV_FORMAT_STRING) {
|
|
||||||
char *subs = *(char **)prop->data;
|
|
||||||
QMetaObject::invokeMethod(this,"setSubtitles",Q_ARG(QVariant,subs));
|
|
||||||
}
|
|
||||||
} else if (strcmp(prop->name, "demuxer-cache-duration") == 0) {
|
|
||||||
if (prop->format == MPV_FORMAT_DOUBLE) {
|
|
||||||
double duration = *(double *)prop->data;
|
|
||||||
QMetaObject::invokeMethod(this,"setCachedDuration",Q_ARG(QVariant,duration));
|
|
||||||
}
|
|
||||||
} else if (strcmp(prop->name, "playlist-pos") == 0) {
|
|
||||||
if (prop->format == MPV_FORMAT_DOUBLE) {
|
|
||||||
double pos = *(double *)prop->data;
|
|
||||||
QMetaObject::invokeMethod(this,"updatePrev",Q_ARG(QVariant,pos));
|
|
||||||
}
|
|
||||||
} else if (strcmp(prop->name, "pause") == 0) {
|
|
||||||
QMetaObject::invokeMethod(this,"updatePlayPause");
|
|
||||||
}
|
}
|
||||||
break;
|
} else if (strcmp(prop->name, "duration") == 0) {
|
||||||
|
if (prop->format == MPV_FORMAT_DOUBLE) {
|
||||||
|
double time = *(double*)prop->data;
|
||||||
|
Q_ARG(QVariant, "txt1"),
|
||||||
|
QMetaObject::invokeMethod(
|
||||||
|
this, "setProgressBarEnd", Q_ARG(QVariant, time));
|
||||||
|
}
|
||||||
|
} else if (strcmp(prop->name, "volume") == 0) {
|
||||||
|
if (prop->format == MPV_FORMAT_DOUBLE) {
|
||||||
|
double volume = *(double*)prop->data;
|
||||||
|
QMetaObject::invokeMethod(
|
||||||
|
this, "updateVolume", Q_ARG(QVariant, volume));
|
||||||
|
}
|
||||||
|
} else if (strcmp(prop->name, "muted") == 0) {
|
||||||
|
if (prop->format == MPV_FORMAT_DOUBLE) {
|
||||||
|
double muted = *(double*)prop->data;
|
||||||
|
QMetaObject::invokeMethod(
|
||||||
|
this, "updateMuted", Q_ARG(QVariant, muted));
|
||||||
|
}
|
||||||
|
} else if (strcmp(prop->name, "media-title") == 0) {
|
||||||
|
if (prop->format == MPV_FORMAT_STRING) {
|
||||||
|
char* title = *(char**)prop->data;
|
||||||
|
QMetaObject::invokeMethod(this, "setTitle", Q_ARG(QVariant, title));
|
||||||
|
}
|
||||||
|
} else if (strcmp(prop->name, "sub-text") == 0) {
|
||||||
|
if (prop->format == MPV_FORMAT_STRING) {
|
||||||
|
char* subs = *(char**)prop->data;
|
||||||
|
QMetaObject::invokeMethod(
|
||||||
|
this, "setSubtitles", Q_ARG(QVariant, subs));
|
||||||
|
}
|
||||||
|
} else if (strcmp(prop->name, "demuxer-cache-duration") == 0) {
|
||||||
|
if (prop->format == MPV_FORMAT_DOUBLE) {
|
||||||
|
double duration = *(double*)prop->data;
|
||||||
|
QMetaObject::invokeMethod(
|
||||||
|
this, "setCachedDuration", Q_ARG(QVariant, duration));
|
||||||
|
}
|
||||||
|
} else if (strcmp(prop->name, "playlist-pos") == 0) {
|
||||||
|
if (prop->format == MPV_FORMAT_DOUBLE) {
|
||||||
|
double pos = *(double*)prop->data;
|
||||||
|
QMetaObject::invokeMethod(this, "updatePrev", Q_ARG(QVariant, pos));
|
||||||
|
}
|
||||||
|
} else if (strcmp(prop->name, "pause") == 0) {
|
||||||
|
QMetaObject::invokeMethod(this, "updatePlayPause");
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
case MPV_EVENT_SHUTDOWN: {
|
case MPV_EVENT_SHUTDOWN: {
|
||||||
exit(0);
|
exit(0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QQuickFramebufferObject::Renderer *MpvPlayerBackend::createRenderer() const
|
QQuickFramebufferObject::Renderer*
|
||||||
|
MpvPlayerBackend::createRenderer() const
|
||||||
{
|
{
|
||||||
window()->setPersistentOpenGLContext(true);
|
window()->setPersistentOpenGLContext(true);
|
||||||
window()->setPersistentSceneGraph(true);
|
window()->setPersistentSceneGraph(true);
|
||||||
return new MpvRenderer(const_cast<MpvPlayerBackend *>(this));
|
return new MpvRenderer(const_cast<MpvPlayerBackend*>(this));
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,69 +2,61 @@
|
||||||
#define MpvPlayerBackend_H
|
#define MpvPlayerBackend_H
|
||||||
|
|
||||||
#include <mpv/client.h>
|
#include <mpv/client.h>
|
||||||
#include <mpv/render_gl.h>
|
|
||||||
#include <mpv/qthelper.hpp>
|
#include <mpv/qthelper.hpp>
|
||||||
|
#include <mpv/render_gl.h>
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QOpenGLContext>
|
#include <QOpenGLContext>
|
||||||
#include <QQuickFramebufferObject>
|
#include <QQuickFramebufferObject>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class MpvRenderer;
|
class MpvRenderer;
|
||||||
|
|
||||||
class MpvPlayerBackend : public QQuickFramebufferObject
|
class MpvPlayerBackend : public QQuickFramebufferObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
mpv_handle *mpv;
|
mpv_handle* mpv;
|
||||||
mpv_render_context *mpv_gl;
|
mpv_render_context* mpv_gl;
|
||||||
|
|
||||||
friend class MpvRenderer;
|
friend class MpvRenderer;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static void on_update(void *ctx);
|
static void on_update(void* ctx);
|
||||||
|
|
||||||
MpvPlayerBackend(QQuickItem * parent = 0);
|
|
||||||
virtual ~MpvPlayerBackend();
|
|
||||||
virtual Renderer *createRenderer() const;
|
|
||||||
|
|
||||||
|
MpvPlayerBackend(QQuickItem* parent = 0);
|
||||||
|
virtual ~MpvPlayerBackend();
|
||||||
|
virtual Renderer* createRenderer() const;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void launchAboutQt();
|
void launchAboutQt();
|
||||||
void togglePlayPause();
|
void togglePlayPause();
|
||||||
void toggleMute();
|
void toggleMute();
|
||||||
void nextAudioTrack();
|
void nextAudioTrack();
|
||||||
void nextVideoTrack();
|
void nextVideoTrack();
|
||||||
void nextSubtitleTrack();
|
void nextSubtitleTrack();
|
||||||
void prevPlaylistItem();
|
void prevPlaylistItem();
|
||||||
void nextPlaylistItem();
|
void nextPlaylistItem();
|
||||||
QVariant getTracks() const;
|
QVariant getTracks() const;
|
||||||
|
|
||||||
void setVolume(const QVariant& volume);
|
|
||||||
void addVolume(const QVariant& volume);
|
|
||||||
void loadFile(const QVariant& filename);
|
|
||||||
void seek(const QVariant& seekTime);
|
|
||||||
void command(const QVariant& params);
|
|
||||||
void setProperty(const QString& name, const QVariant& value);
|
|
||||||
void setOption(const QString& name, const QVariant& value);
|
|
||||||
QVariant getProperty(const QString& name) const;
|
|
||||||
|
|
||||||
|
void setVolume(const QVariant& volume);
|
||||||
|
void addVolume(const QVariant& volume);
|
||||||
|
void loadFile(const QVariant& filename);
|
||||||
|
void seek(const QVariant& seekTime);
|
||||||
|
void command(const QVariant& params);
|
||||||
|
void setProperty(const QString& name, const QVariant& value);
|
||||||
|
void setOption(const QString& name, const QVariant& value);
|
||||||
|
QVariant getProperty(const QString& name) const;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void onUpdate();
|
void onUpdate();
|
||||||
void positionChanged(int value);
|
void positionChanged(int value);
|
||||||
void mpv_events();
|
void mpv_events();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void doUpdate();
|
void doUpdate();
|
||||||
void on_mpv_events();
|
void on_mpv_events();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void handle_mpv_event(mpv_event *event);
|
void handle_mpv_event(mpv_event* event);
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
79
src/main.cpp
79
src/main.cpp
|
@ -4,58 +4,65 @@
|
||||||
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
|
||||||
|
|
||||||
#include <QApplication>
|
|
||||||
#include <QQmlApplicationEngine>
|
|
||||||
#include <QProcessEnvironment>
|
|
||||||
#include "MpvPlayerBackend.h"
|
#include "MpvPlayerBackend.h"
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QProcessEnvironment>
|
||||||
|
#include <QQmlApplicationEngine>
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
#include "setenv_mingw.hpp"
|
#include "setenv_mingw.hpp"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int main( int argc, char *argv[] )
|
int
|
||||||
|
main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
setenv("QT_QUICK_CONTROLS_STYLE","Desktop",1);
|
setenv("QT_QUICK_CONTROLS_STYLE", "Desktop", 1);
|
||||||
QApplication app(argc, argv);
|
QApplication app(argc, argv);
|
||||||
app.setOrganizationName("KittehPlayer");
|
app.setOrganizationName("KittehPlayer");
|
||||||
app.setOrganizationDomain("namedkitten.pw");
|
app.setOrganizationDomain("namedkitten.pw");
|
||||||
app.setApplicationName("KittehPlayer");
|
app.setApplicationName("KittehPlayer");
|
||||||
for (int i = 1; i < argc; ++i) {
|
for (int i = 1; i < argc; ++i) {
|
||||||
if (!qstrcmp(argv[i], "--update")) {
|
if (!qstrcmp(argv[i], "--update")) {
|
||||||
QString program = QProcessEnvironment::systemEnvironment().value("APPDIR", "") + "/usr/bin/appimageupdatetool";
|
QString program =
|
||||||
QProcess updater;
|
QProcessEnvironment::systemEnvironment().value("APPDIR", "") +
|
||||||
updater.setProcessChannelMode(QProcess::ForwardedChannels);
|
"/usr/bin/appimageupdatetool";
|
||||||
updater.start(program, QStringList() << QProcessEnvironment::systemEnvironment().value("APPIMAGE", ""));
|
QProcess updater;
|
||||||
updater.waitForFinished();
|
updater.setProcessChannelMode(QProcess::ForwardedChannels);
|
||||||
qDebug() << program;
|
updater.start(program,
|
||||||
exit(0);
|
QStringList()
|
||||||
}
|
<< QProcessEnvironment::systemEnvironment().value(
|
||||||
|
"APPIMAGE", ""));
|
||||||
|
updater.waitForFinished();
|
||||||
|
qDebug() << program;
|
||||||
|
exit(0);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QProcess dpms;
|
QProcess dpms;
|
||||||
dpms.start("xset", QStringList() << "-dpms");
|
dpms.start("xset", QStringList() << "-dpms");
|
||||||
|
|
||||||
QString newpath = QProcessEnvironment::systemEnvironment().value("APPDIR", "") + "/usr/bin:" + QProcessEnvironment::systemEnvironment().value("PATH", "");
|
QString newpath =
|
||||||
qDebug() << newpath;
|
QProcessEnvironment::systemEnvironment().value("APPDIR", "") +
|
||||||
setenv("PATH", newpath.toUtf8().constData(), 1);
|
"/usr/bin:" + QProcessEnvironment::systemEnvironment().value("PATH", "");
|
||||||
|
qDebug() << newpath;
|
||||||
|
setenv("PATH", newpath.toUtf8().constData(), 1);
|
||||||
|
|
||||||
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||||
|
|
||||||
QApplication::setAttribute(Qt::AA_NativeWindows);
|
QApplication::setAttribute(Qt::AA_NativeWindows);
|
||||||
qmlRegisterType<MpvPlayerBackend>("player", 1, 0, "PlayerBackend");
|
qmlRegisterType<MpvPlayerBackend>("player", 1, 0, "PlayerBackend");
|
||||||
std::setlocale(LC_NUMERIC, "C");
|
std::setlocale(LC_NUMERIC, "C");
|
||||||
|
|
||||||
QQmlApplicationEngine engine;
|
QQmlApplicationEngine engine;
|
||||||
#ifdef QRC_SOURCE_PATH
|
#ifdef QRC_SOURCE_PATH
|
||||||
RuntimeQML *rt = new RuntimeQML(&engine, QRC_SOURCE_PATH"/qml.qrc");
|
RuntimeQML* rt = new RuntimeQML(&engine, QRC_SOURCE_PATH "/qml.qrc");
|
||||||
|
|
||||||
rt->setAutoReload(true);
|
rt->setAutoReload(true);
|
||||||
rt->setMainQmlFilename("main.qml");
|
rt->setMainQmlFilename("main.qml");
|
||||||
rt->reload();
|
rt->reload();
|
||||||
#else
|
#else
|
||||||
engine.load(QUrl(QStringLiteral("qrc:///player/main.qml")));
|
engine.load(QUrl(QStringLiteral("qrc:///player/main.qml")));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return app.exec();
|
return app.exec();
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,12 +31,13 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
int setenv( const char *var, const char *value, int overwrite )
|
int
|
||||||
|
setenv(const char* var, const char* value, int overwrite)
|
||||||
{
|
{
|
||||||
/* Core implementation for both setenv() and unsetenv() functions;
|
/* Core implementation for both setenv() and unsetenv() functions;
|
||||||
* at the outset, assume that the requested operation may fail.
|
* at the outset, assume that the requested operation may fail.
|
||||||
|
@ -46,40 +47,36 @@ int setenv( const char *var, const char *value, int overwrite )
|
||||||
/* The specified "var" name MUST be non-NULL, not a zero-length
|
/* The specified "var" name MUST be non-NULL, not a zero-length
|
||||||
* string, and must not include any '=' character.
|
* string, and must not include any '=' character.
|
||||||
*/
|
*/
|
||||||
if( var && *var && (strchr( var, '=' ) == NULL) )
|
if (var && *var && (strchr(var, '=') == NULL)) {
|
||||||
{
|
|
||||||
/* A properly named variable may be added to, removed from,
|
/* A properly named variable may be added to, removed from,
|
||||||
* or modified within the environment, ONLY if "overwrite"
|
* or modified within the environment, ONLY if "overwrite"
|
||||||
* mode is enabled, OR if the named variable does not yet
|
* mode is enabled, OR if the named variable does not yet
|
||||||
* exist...
|
* exist...
|
||||||
*/
|
*/
|
||||||
if( overwrite || getenv( var ) == NULL )
|
if (overwrite || getenv(var) == NULL) {
|
||||||
{
|
|
||||||
/* ... in which cases, we convert the specified name and
|
/* ... in which cases, we convert the specified name and
|
||||||
* value into the appropriate form for use with putenv(),
|
* value into the appropriate form for use with putenv(),
|
||||||
* (noting that we accept a NULL "value" as equivalent to
|
* (noting that we accept a NULL "value" as equivalent to
|
||||||
* a zero-length string, which renders putenv() as the
|
* a zero-length string, which renders putenv() as the
|
||||||
* equivalent of unsetenv()).
|
* equivalent of unsetenv()).
|
||||||
*/
|
*/
|
||||||
const char *fmt = "%s=%s";
|
const char* fmt = "%s=%s";
|
||||||
const char *val = value ? value : "";
|
const char* val = value ? value : "";
|
||||||
char buf[1 + snprintf( NULL, 0, fmt, var, val )];
|
char buf[1 + snprintf(NULL, 0, fmt, var, val)];
|
||||||
snprintf( buf, sizeof( buf ), fmt, var, val );
|
snprintf(buf, sizeof(buf), fmt, var, val);
|
||||||
if( (retval = putenv( buf )) != 0 )
|
if ((retval = putenv(buf)) != 0)
|
||||||
/*
|
/*
|
||||||
* If putenv() returns non-zero, indicating failure, the
|
* If putenv() returns non-zero, indicating failure, the
|
||||||
* most probable explanation is that there wasn't enough
|
* most probable explanation is that there wasn't enough
|
||||||
* free memory; ensure that errno is set accordingly.
|
* free memory; ensure that errno is set accordingly.
|
||||||
*/
|
*/
|
||||||
errno = ENOMEM;
|
errno = ENOMEM;
|
||||||
}
|
} else
|
||||||
else
|
|
||||||
/* The named variable already exists, and overwrite mode
|
/* The named variable already exists, and overwrite mode
|
||||||
* was not enabled; there is nothing to be done.
|
* was not enabled; there is nothing to be done.
|
||||||
*/
|
*/
|
||||||
retval = 0;
|
retval = 0;
|
||||||
}
|
} else
|
||||||
else
|
|
||||||
/* The specified environment variable name was invalid.
|
/* The specified environment variable name was invalid.
|
||||||
*/
|
*/
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
|
@ -89,4 +86,3 @@ int setenv( const char *var, const char *value, int overwrite )
|
||||||
*/
|
*/
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue