[Multiple] Added Direct backend and backend interface support.
This commit is contained in:
parent
75c7225dca
commit
71f8cccee1
|
@ -4,7 +4,6 @@ project(KittehPlayer)
|
||||||
include_directories(${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR})
|
include_directories(${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR})
|
||||||
set(CMAKE_AUTOMOC ON)
|
set(CMAKE_AUTOMOC ON)
|
||||||
|
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Werror -fstrict-aliasing -Wno-deprecated-declarations -Wno-unused-variable")
|
|
||||||
|
|
||||||
option(DEVELOP "Enable runtime QML reloading for developing." OFF)
|
option(DEVELOP "Enable runtime QML reloading for developing." OFF)
|
||||||
option(DISCORD "Enable Discord SDK." OFF)
|
option(DISCORD "Enable Discord SDK." OFF)
|
||||||
|
@ -12,6 +11,7 @@ option(DISCORD "Enable Discord SDK." OFF)
|
||||||
|
|
||||||
find_package(Qt5Core REQUIRED)
|
find_package(Qt5Core REQUIRED)
|
||||||
find_package(Qt5Gui REQUIRED)
|
find_package(Qt5Gui REQUIRED)
|
||||||
|
find_package(Qt5QuickWidgets REQUIRED)
|
||||||
find_package(Qt5 CONFIG REQUIRED COMPONENTS Qml Quick Gui Widgets Core X11Extras)
|
find_package(Qt5 CONFIG REQUIRED COMPONENTS Qml Quick Gui Widgets Core X11Extras)
|
||||||
|
|
||||||
find_package(Qt5QuickCompiler)
|
find_package(Qt5QuickCompiler)
|
||||||
|
@ -26,6 +26,7 @@ pkg_check_modules(Xext REQUIRED xext)
|
||||||
set(SOURCES
|
set(SOURCES
|
||||||
src/main.cpp
|
src/main.cpp
|
||||||
src/MpvPlayerBackend.cpp
|
src/MpvPlayerBackend.cpp
|
||||||
|
src/DirectMpvPlayerBackend.cpp
|
||||||
src/utils.cpp
|
src/utils.cpp
|
||||||
src/enums.hpp
|
src/enums.hpp
|
||||||
)
|
)
|
||||||
|
|
|
@ -3,7 +3,7 @@ TARGET = KittehPlayer
|
||||||
TEMPLATE = app
|
TEMPLATE = app
|
||||||
QT += qml quickcontrols2 widgets x11extras
|
QT += qml quickcontrols2 widgets x11extras
|
||||||
|
|
||||||
SOURCES += src/main.cpp src/MpvPlayerBackend.cpp src/utils.cpp
|
SOURCES += src/main.cpp src/MpvPlayerBackend.cpp src/DirectMpvPlayerBackend.cpp src/utils.cpp
|
||||||
|
|
||||||
CONFIG += debug
|
CONFIG += debug
|
||||||
CONFIG-=qtquickcompiler
|
CONFIG-=qtquickcompiler
|
||||||
|
@ -31,7 +31,7 @@ unix {
|
||||||
|
|
||||||
INSTALLS += target
|
INSTALLS += target
|
||||||
|
|
||||||
HEADERS += src/MpvPlayerBackend.h src/utils.hpp
|
HEADERS += src/MpvPlayerBackend.h src/DirectMpvPlayerBackend.h src/utils.hpp
|
||||||
|
|
||||||
|
|
||||||
DISTFILES += KittehPlayer.desktop KittehPlayer.png README.md LICENSE.txt
|
DISTFILES += KittehPlayer.desktop KittehPlayer.png README.md LICENSE.txt
|
||||||
|
|
584
src/DirectMpvPlayerBackend.cpp
Normal file
584
src/DirectMpvPlayerBackend.cpp
Normal file
|
@ -0,0 +1,584 @@
|
||||||
|
#include <clocale>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#include "DirectMpvPlayerBackend.h"
|
||||||
|
|
||||||
|
#include "utils.hpp"
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QMainWindow>
|
||||||
|
#include <QOpenGLContext>
|
||||||
|
#include <QOpenGLFramebufferObject>
|
||||||
|
#include <QQuickWindow>
|
||||||
|
|
||||||
|
#include <QSequentialIterable>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#ifdef DISCORD
|
||||||
|
#include "discord_rpc.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void
|
||||||
|
wakeup(void* ctx)
|
||||||
|
{
|
||||||
|
QMetaObject::invokeMethod(
|
||||||
|
(DirectMpvPlayerBackend*)ctx, "on_mpv_events", Qt::QueuedConnection);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void*
|
||||||
|
get_proc_address(void* ctx, const char* name)
|
||||||
|
{
|
||||||
|
(void)ctx;
|
||||||
|
QOpenGLContext* glctx = QOpenGLContext::currentContext();
|
||||||
|
if (!glctx)
|
||||||
|
return NULL;
|
||||||
|
return (void*)glctx->getProcAddress(QByteArray(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
MpvRenderer::MpvRenderer(mpv_handle* a_mpv, mpv_opengl_cb_context* a_mpv_gl)
|
||||||
|
: mpv(a_mpv)
|
||||||
|
, mpv_gl(a_mpv_gl)
|
||||||
|
, window(0)
|
||||||
|
, size()
|
||||||
|
{
|
||||||
|
int r = mpv_opengl_cb_init_gl(mpv_gl, NULL, get_proc_address, NULL);
|
||||||
|
if (r < 0)
|
||||||
|
qDebug() << "could not initialize OpenGL";
|
||||||
|
}
|
||||||
|
|
||||||
|
MpvRenderer::~MpvRenderer()
|
||||||
|
{
|
||||||
|
// Until this call is done, we need to make sure the player remains
|
||||||
|
// alive. This is done implicitly with the mpv::qt::Handle instance
|
||||||
|
// in this class.
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MpvRenderer::paint()
|
||||||
|
{
|
||||||
|
window->resetOpenGLState();
|
||||||
|
|
||||||
|
// This uses 0 as framebuffer, which indicates that mpv will render directly
|
||||||
|
// to the frontbuffer. Note that mpv will always switch framebuffers
|
||||||
|
// explicitly. Some QWindow setups (such as using QQuickWidget) actually
|
||||||
|
// want you to render into a FBO in the beforeRendering() signal, and this
|
||||||
|
// code won't work there.
|
||||||
|
// The negation is used for rendering with OpenGL's flipped coordinates.
|
||||||
|
mpv_opengl_cb_draw(mpv_gl, 0, size.width(), -size.height());
|
||||||
|
|
||||||
|
window->resetOpenGLState();
|
||||||
|
}
|
||||||
|
|
||||||
|
DirectMpvPlayerBackend::DirectMpvPlayerBackend(QQuickItem* parent)
|
||||||
|
: QQuickItem(parent)
|
||||||
|
, mpv_gl(0)
|
||||||
|
, renderer(0)
|
||||||
|
{
|
||||||
|
mpv = mpv_create();
|
||||||
|
if (!mpv)
|
||||||
|
throw std::runtime_error("could not create mpv context");
|
||||||
|
|
||||||
|
#ifdef DISCORD
|
||||||
|
DiscordEventHandlers handlers;
|
||||||
|
memset(&handlers, 0, sizeof(handlers));
|
||||||
|
Discord_Initialize("511220330996432896", &handlers, 1, NULL);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
mpv_set_option_string(mpv, "terminal", "yes");
|
||||||
|
mpv_set_option_string(mpv, "msg-level", "all=v");
|
||||||
|
|
||||||
|
// Fix?
|
||||||
|
mpv_set_option_string(mpv, "ytdl", "yes");
|
||||||
|
|
||||||
|
mpv_set_option_string(mpv, "slang", "en");
|
||||||
|
|
||||||
|
mpv_set_option_string(mpv, "config", "yes");
|
||||||
|
// mpv_set_option_string(mpv, "sub-visibility", "no");
|
||||||
|
mpv_observe_property(mpv, 0, "tracks-menu", MPV_FORMAT_NONE);
|
||||||
|
mpv_observe_property(mpv, 0, "playback-abort", MPV_FORMAT_NONE);
|
||||||
|
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, "audio-device-list", MPV_FORMAT_NODE);
|
||||||
|
mpv_observe_property(mpv, 0, "playlist-pos", MPV_FORMAT_DOUBLE);
|
||||||
|
mpv_observe_property(mpv, 0, "volume", MPV_FORMAT_NONE);
|
||||||
|
mpv_observe_property(mpv, 0, "mute", MPV_FORMAT_NONE);
|
||||||
|
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");
|
||||||
|
|
||||||
|
// Make use of the MPV_SUB_API_OPENGL_CB API.
|
||||||
|
mpv::qt::set_option_variant(mpv, "vo", "opengl-cb");
|
||||||
|
|
||||||
|
// Setup the callback that will make QtQuick update and redraw if there
|
||||||
|
// is a new video frame. Use a queued connection: this makes sure the
|
||||||
|
// doUpdate() function is run on the GUI thread.
|
||||||
|
mpv_gl = (mpv_opengl_cb_context*)mpv_get_sub_api(mpv, MPV_SUB_API_OPENGL_CB);
|
||||||
|
if (!mpv_gl)
|
||||||
|
throw std::runtime_error("OpenGL not compiled in");
|
||||||
|
mpv_opengl_cb_set_update_callback(
|
||||||
|
mpv_gl, DirectMpvPlayerBackend::on_update, (void*)this);
|
||||||
|
|
||||||
|
connect(this,
|
||||||
|
&DirectMpvPlayerBackend::onUpdate,
|
||||||
|
this,
|
||||||
|
&DirectMpvPlayerBackend::doUpdate,
|
||||||
|
Qt::QueuedConnection);
|
||||||
|
connect(this,
|
||||||
|
&DirectMpvPlayerBackend::positionChanged,
|
||||||
|
&DirectMpvPlayerBackend::updateDurationString);
|
||||||
|
connect(this,
|
||||||
|
&DirectMpvPlayerBackend::durationChanged,
|
||||||
|
&DirectMpvPlayerBackend::updateDurationString);
|
||||||
|
|
||||||
|
connect(this,
|
||||||
|
&QQuickItem::windowChanged,
|
||||||
|
this,
|
||||||
|
&DirectMpvPlayerBackend::handleWindowChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
DirectMpvPlayerBackend::~DirectMpvPlayerBackend()
|
||||||
|
{
|
||||||
|
printf("Shutting down...\n");
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
printf("MPV terminated.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
DirectMpvPlayerBackend::sync()
|
||||||
|
{
|
||||||
|
|
||||||
|
if (!renderer) {
|
||||||
|
renderer = new MpvRenderer(mpv, mpv_gl);
|
||||||
|
connect(window(),
|
||||||
|
&QQuickWindow::beforeRendering,
|
||||||
|
renderer,
|
||||||
|
&MpvRenderer::paint,
|
||||||
|
Qt::DirectConnection);
|
||||||
|
QMetaObject::invokeMethod(this, "startPlayer");
|
||||||
|
}
|
||||||
|
renderer->window = window();
|
||||||
|
renderer->size = window()->size() * window()->devicePixelRatio();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
DirectMpvPlayerBackend::swapped()
|
||||||
|
{
|
||||||
|
mpv_opengl_cb_report_flip(mpv_gl, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
DirectMpvPlayerBackend::cleanup()
|
||||||
|
{
|
||||||
|
if (renderer) {
|
||||||
|
delete renderer;
|
||||||
|
renderer = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
DirectMpvPlayerBackend::on_update(void* ctx)
|
||||||
|
{
|
||||||
|
DirectMpvPlayerBackend* self = (DirectMpvPlayerBackend*)ctx;
|
||||||
|
emit self->onUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
DirectMpvPlayerBackend::doUpdate()
|
||||||
|
{
|
||||||
|
window()->update();
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant
|
||||||
|
DirectMpvPlayerBackend::getProperty(const QString& name) const
|
||||||
|
{
|
||||||
|
return mpv::qt::get_property_variant(mpv, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
DirectMpvPlayerBackend::command(const QVariant& params)
|
||||||
|
{
|
||||||
|
mpv::qt::command_variant(mpv, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
DirectMpvPlayerBackend::setProperty(const QString& name, const QVariant& value)
|
||||||
|
{
|
||||||
|
mpv::qt::set_property_variant(mpv, name, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
DirectMpvPlayerBackend::setOption(const QString& name, const QVariant& value)
|
||||||
|
{
|
||||||
|
mpv::qt::set_option_variant(mpv, name, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
DirectMpvPlayerBackend::launchAboutQt()
|
||||||
|
{
|
||||||
|
QApplication* qapp =
|
||||||
|
qobject_cast<QApplication*>(QCoreApplication::instance());
|
||||||
|
qapp->aboutQt();
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DISCORD
|
||||||
|
void
|
||||||
|
DirectMpvPlayerBackend::updateDiscord()
|
||||||
|
{
|
||||||
|
char buffer[256];
|
||||||
|
DiscordRichPresence discordPresence;
|
||||||
|
memset(&discordPresence, 0, sizeof(discordPresence));
|
||||||
|
discordPresence.state = getProperty("pause").toBool() ? "Paused" : "Playing";
|
||||||
|
sprintf(buffer,
|
||||||
|
"Currently Playing: Video %s",
|
||||||
|
getProperty("media-title").toString().toUtf8().constData());
|
||||||
|
discordPresence.details = buffer;
|
||||||
|
discordPresence.startTimestamp = time(0);
|
||||||
|
discordPresence.endTimestamp = time(0) + (getProperty("duration").toFloat() -
|
||||||
|
getProperty("time-pos").toFloat());
|
||||||
|
discordPresence.instance = 0;
|
||||||
|
Discord_UpdatePresence(&discordPresence);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
QVariant
|
||||||
|
DirectMpvPlayerBackend::playerCommand(const Enums::Commands& cmd)
|
||||||
|
{
|
||||||
|
return playerCommand(cmd, QVariant("NoArgProvided"));
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant
|
||||||
|
DirectMpvPlayerBackend::playerCommand(const Enums::Commands& cmd,
|
||||||
|
const QVariant& args)
|
||||||
|
{
|
||||||
|
switch (cmd) {
|
||||||
|
case Enums::Commands::TogglePlayPause: {
|
||||||
|
command(QVariantList() << "cycle"
|
||||||
|
<< "pause");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Enums::Commands::ToggleMute: {
|
||||||
|
command(QVariantList() << "cycle"
|
||||||
|
<< "mute");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Enums::Commands::SetAudioDevice: {
|
||||||
|
setProperty("audio-device", args.toString());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Enums::Commands::GetAudioDevices: {
|
||||||
|
QVariant drivers = getProperty("audio-device-list");
|
||||||
|
QVariant currentDevice = getProperty("audio-device");
|
||||||
|
|
||||||
|
QVariantMap newDrivers;
|
||||||
|
|
||||||
|
QSequentialIterable iterable = drivers.value<QSequentialIterable>();
|
||||||
|
foreach (const QVariant& v, iterable) {
|
||||||
|
QVariantMap item = v.toMap();
|
||||||
|
item["selected"] = currentDevice == item["name"];
|
||||||
|
newDrivers[item["description"].toString()] = item;
|
||||||
|
}
|
||||||
|
QMap<QString, QVariant> pulseItem;
|
||||||
|
pulseItem["name"] = "pulse";
|
||||||
|
pulseItem["description"] = "Default (pulseaudio)";
|
||||||
|
pulseItem["selected"] = currentDevice == "pulse";
|
||||||
|
newDrivers[pulseItem["description"].toString()] = pulseItem;
|
||||||
|
return QVariant(newDrivers);
|
||||||
|
}
|
||||||
|
case Enums::Commands::SetVolume: {
|
||||||
|
command(QVariantList() << "set"
|
||||||
|
<< "volume" << args);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Enums::Commands::AddVolume: {
|
||||||
|
|
||||||
|
command(QVariantList() << "add"
|
||||||
|
<< "volume" << args);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Enums::Commands::AddSpeed: {
|
||||||
|
|
||||||
|
QString speedString =
|
||||||
|
QString::number(getProperty("speed").toDouble() + args.toDouble());
|
||||||
|
QVariant newSpeed =
|
||||||
|
QVariant(speedString.left(speedString.lastIndexOf('.') + 2));
|
||||||
|
|
||||||
|
playerCommand(Enums::Commands::SetSpeed, newSpeed);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Enums::Commands::SubtractSpeed: {
|
||||||
|
|
||||||
|
QString speedString =
|
||||||
|
QString::number(getProperty("speed").toDouble() - args.toDouble());
|
||||||
|
QVariant newSpeed =
|
||||||
|
QVariant(speedString.left(speedString.lastIndexOf('.') + 2));
|
||||||
|
playerCommand(Enums::Commands::SetSpeed, newSpeed);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Enums::Commands::ChangeSpeed: {
|
||||||
|
|
||||||
|
playerCommand(
|
||||||
|
Enums::Commands::SetSpeed,
|
||||||
|
QVariant(getProperty("speed").toDouble() * args.toDouble()));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Enums::Commands::SetSpeed: {
|
||||||
|
|
||||||
|
command(QVariantList() << "set"
|
||||||
|
<< "speed" << args.toString());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Enums::Commands::ToggleStats: {
|
||||||
|
|
||||||
|
command(QVariantList() << "script-binding"
|
||||||
|
<< "stats/display-stats-toggle");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Enums::Commands::NextAudioTrack: {
|
||||||
|
|
||||||
|
command(QVariantList() << "cycle"
|
||||||
|
<< "audio");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Enums::Commands::NextSubtitleTrack: {
|
||||||
|
|
||||||
|
command(QVariantList() << "cycle"
|
||||||
|
<< "sub");
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Enums::Commands::NextVideoTrack: {
|
||||||
|
command(QVariantList() << "cycle"
|
||||||
|
<< "video");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Enums::Commands::PreviousPlaylistItem: {
|
||||||
|
|
||||||
|
command(QVariantList() << "playlist-prev");
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Enums::Commands::NextPlaylistItem: {
|
||||||
|
|
||||||
|
command(QVariantList() << "playlist-next"
|
||||||
|
<< "force");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Enums::Commands::LoadFile: {
|
||||||
|
command(QVariantList() << "loadfile" << args);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Enums::Commands::AppendFile: {
|
||||||
|
|
||||||
|
command(QVariantList() << "loadfile" << args << "append-play");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Enums::Commands::Seek: {
|
||||||
|
|
||||||
|
command(QVariantList() << "seek" << args);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Enums::Commands::SeekAbsolute: {
|
||||||
|
|
||||||
|
command(QVariantList() << "seek" << args << "absolute");
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Enums::Commands::GetTracks: {
|
||||||
|
|
||||||
|
return mpv::qt::get_property_variant(mpv, "track-list");
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Enums::Commands::ForwardFrame: {
|
||||||
|
|
||||||
|
command(QVariantList() << "frame-step");
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Enums::Commands::BackwardFrame: {
|
||||||
|
|
||||||
|
command(QVariantList() << "frame-back-step");
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Enums::Commands::SetTrack: {
|
||||||
|
|
||||||
|
command(QVariantList() << "set" << args.toList()[0] << args.toList()[1]);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default: {
|
||||||
|
qDebug() << "Command not found: " << cmd;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return QVariant("NoOutput");
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant
|
||||||
|
DirectMpvPlayerBackend::createTimestamp(const QVariant& seconds) const
|
||||||
|
{
|
||||||
|
int d = seconds.toInt();
|
||||||
|
double h = floor(d / 3600);
|
||||||
|
double m = floor(d % 3600 / 60);
|
||||||
|
double s = floor(d % 3600 % 60);
|
||||||
|
|
||||||
|
QString hour = h > 0 ? QString::number(h) + ":" : "";
|
||||||
|
QString minute = h < 1 ? QString::number(m) + ":"
|
||||||
|
: (m < 10 ? "0" + QString::number(m) + ":"
|
||||||
|
: QString::number(m) + ":");
|
||||||
|
QString second = s < 10 ? "0" + QString::number(s) : QString::number(s);
|
||||||
|
return hour + minute + second;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
DirectMpvPlayerBackend::handleWindowChanged(QQuickWindow* win)
|
||||||
|
{
|
||||||
|
if (!win)
|
||||||
|
return;
|
||||||
|
connect(win,
|
||||||
|
&QQuickWindow::beforeSynchronizing,
|
||||||
|
this,
|
||||||
|
&DirectMpvPlayerBackend::sync,
|
||||||
|
Qt::DirectConnection);
|
||||||
|
connect(win,
|
||||||
|
&QQuickWindow::sceneGraphInvalidated,
|
||||||
|
this,
|
||||||
|
&DirectMpvPlayerBackend::cleanup,
|
||||||
|
Qt::DirectConnection);
|
||||||
|
connect(win,
|
||||||
|
&QQuickWindow::frameSwapped,
|
||||||
|
this,
|
||||||
|
&DirectMpvPlayerBackend::swapped,
|
||||||
|
Qt::DirectConnection);
|
||||||
|
win->setClearBeforeRendering(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
DirectMpvPlayerBackend::toggleOnTop()
|
||||||
|
{
|
||||||
|
onTop = !onTop;
|
||||||
|
Utils::AlwaysOnTop(window()->winId(), onTop);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
DirectMpvPlayerBackend::on_mpv_events()
|
||||||
|
{
|
||||||
|
while (mpv) {
|
||||||
|
mpv_event* event = mpv_wait_event(mpv, 0);
|
||||||
|
if (event->event_id == MPV_EVENT_NONE) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
handle_mpv_event(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
DirectMpvPlayerBackend::updateDurationString()
|
||||||
|
{
|
||||||
|
emit durationStringChanged(
|
||||||
|
QString("%1 / %2 (%3x)")
|
||||||
|
.arg(createTimestamp(getProperty("time-pos")).toString(),
|
||||||
|
createTimestamp(getProperty("duration")).toString(),
|
||||||
|
getProperty("speed").toString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
DirectMpvPlayerBackend::updateAppImage()
|
||||||
|
{
|
||||||
|
Utils::updateAppImage();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
DirectMpvPlayerBackend::handle_mpv_event(mpv_event* event)
|
||||||
|
{
|
||||||
|
switch (event->event_id) {
|
||||||
|
case MPV_EVENT_PROPERTY_CHANGE: {
|
||||||
|
mpv_event_property* prop = (mpv_event_property*)event->data;
|
||||||
|
if (strcmp(prop->name, "time-pos") == 0) {
|
||||||
|
if (prop->format == MPV_FORMAT_DOUBLE) {
|
||||||
|
double time = *(double*)prop->data;
|
||||||
|
emit positionChanged(time);
|
||||||
|
}
|
||||||
|
} else if (strcmp(prop->name, "duration") == 0) {
|
||||||
|
if (prop->format == MPV_FORMAT_DOUBLE) {
|
||||||
|
double time = *(double*)prop->data;
|
||||||
|
emit durationChanged(time);
|
||||||
|
}
|
||||||
|
} else if (strcmp(prop->name, "mute") == 0 ||
|
||||||
|
strcmp(prop->name, "volume") == 0) {
|
||||||
|
double volume = getProperty("volume").toDouble();
|
||||||
|
bool mute = getProperty("mute").toBool();
|
||||||
|
if (mute || volume == 0) {
|
||||||
|
emit volumeStatusChanged(Enums::VolumeStatus::Muted);
|
||||||
|
} else {
|
||||||
|
if (volume < 25) {
|
||||||
|
emit volumeStatusChanged(Enums::VolumeStatus::Low);
|
||||||
|
} else {
|
||||||
|
emit volumeStatusChanged(Enums::VolumeStatus::Normal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// emit volumeChanged(volume);
|
||||||
|
} else if (strcmp(prop->name, "media-title") == 0) {
|
||||||
|
if (prop->format == MPV_FORMAT_STRING) {
|
||||||
|
char* title = *(char**)prop->data;
|
||||||
|
emit titleChanged(QString(title));
|
||||||
|
}
|
||||||
|
} else if (strcmp(prop->name, "sub-text") == 0) {
|
||||||
|
if (prop->format == MPV_FORMAT_STRING) {
|
||||||
|
char* subs = *(char**)prop->data;
|
||||||
|
emit subtitlesChanged(QString(subs));
|
||||||
|
}
|
||||||
|
} else if (strcmp(prop->name, "demuxer-cache-duration") == 0) {
|
||||||
|
if (prop->format == MPV_FORMAT_DOUBLE) {
|
||||||
|
double duration = *(double*)prop->data;
|
||||||
|
emit cachedDurationChanged(duration);
|
||||||
|
}
|
||||||
|
} else if (strcmp(prop->name, "playlist-pos") == 0) {
|
||||||
|
if (prop->format == MPV_FORMAT_DOUBLE) {
|
||||||
|
double pos = *(double*)prop->data;
|
||||||
|
emit playlistPositionChanged(pos);
|
||||||
|
}
|
||||||
|
} else if (strcmp(prop->name, "pause") == 0) {
|
||||||
|
if (getProperty("pause").toBool()) {
|
||||||
|
emit playStatusChanged(Enums::PlayStatus::Paused);
|
||||||
|
} else {
|
||||||
|
emit playStatusChanged(Enums::PlayStatus::Playing);
|
||||||
|
}
|
||||||
|
} else if (strcmp(prop->name, "tracks-menu") == 0) {
|
||||||
|
emit tracksChanged();
|
||||||
|
} else if (strcmp(prop->name, "audio-device-list") == 0) {
|
||||||
|
emit audioDevicesChanged();
|
||||||
|
}
|
||||||
|
#ifdef DISCORD
|
||||||
|
updateDiscord();
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MPV_EVENT_SHUTDOWN: {
|
||||||
|
qApp->exit();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
100
src/DirectMpvPlayerBackend.h
Normal file
100
src/DirectMpvPlayerBackend.h
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
#ifndef DirectMpvPlayerBackend_Hc
|
||||||
|
#define DirectMpvPlayerBackend_H
|
||||||
|
|
||||||
|
#include <mpv/client.h>
|
||||||
|
#include <mpv/opengl_cb.h>
|
||||||
|
#include <mpv/qthelper.hpp>
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QOpenGLContext>
|
||||||
|
#include <QQuickFramebufferObject>
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
#include "backendinterface.hpp"
|
||||||
|
#include "enums.hpp"
|
||||||
|
|
||||||
|
class MpvRenderer : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
mpv_handle* mpv;
|
||||||
|
mpv_opengl_cb_context* mpv_gl;
|
||||||
|
|
||||||
|
public:
|
||||||
|
QQuickWindow* window;
|
||||||
|
QSize size;
|
||||||
|
|
||||||
|
friend class MpvObject;
|
||||||
|
MpvRenderer(mpv_handle* a_mpv, mpv_opengl_cb_context* a_mpv_gl);
|
||||||
|
virtual ~MpvRenderer();
|
||||||
|
public slots:
|
||||||
|
void paint();
|
||||||
|
};
|
||||||
|
|
||||||
|
class DirectMpvPlayerBackend
|
||||||
|
: public QQuickItem
|
||||||
|
, public BackendInterface
|
||||||
|
{
|
||||||
|
Q_INTERFACES(BackendInterface)
|
||||||
|
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
mpv_handle* mpv;
|
||||||
|
mpv_opengl_cb_context* mpv_gl;
|
||||||
|
MpvRenderer* renderer;
|
||||||
|
bool onTop = false;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static void on_update(void* ctx);
|
||||||
|
|
||||||
|
DirectMpvPlayerBackend(QQuickItem* parent = 0);
|
||||||
|
virtual ~DirectMpvPlayerBackend();
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
QVariant playerCommand(const Enums::Commands& command, const QVariant& args);
|
||||||
|
QVariant playerCommand(const Enums::Commands& command);
|
||||||
|
void launchAboutQt();
|
||||||
|
void toggleOnTop();
|
||||||
|
void updateAppImage();
|
||||||
|
// Optional but handy for MPV or custom backend settings.
|
||||||
|
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;
|
||||||
|
// Misc
|
||||||
|
QVariant createTimestamp(const QVariant& seconds) const;
|
||||||
|
//
|
||||||
|
void sync();
|
||||||
|
void swapped();
|
||||||
|
void cleanup();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void onUpdate();
|
||||||
|
void mpv_events();
|
||||||
|
// All below required for Player API
|
||||||
|
void playStatusChanged(const Enums::PlayStatus& status);
|
||||||
|
void volumeStatusChanged(const Enums::VolumeStatus& status);
|
||||||
|
void volumeChanged(const int& volume);
|
||||||
|
void durationChanged(const double& duration);
|
||||||
|
void positionChanged(const double& position);
|
||||||
|
void cachedDurationChanged(const double& duration);
|
||||||
|
void playlistPositionChanged(const double& position);
|
||||||
|
void titleChanged(const QString& title);
|
||||||
|
void subtitlesChanged(const QString& subtitles);
|
||||||
|
void durationStringChanged(const QString& string);
|
||||||
|
void tracksChanged();
|
||||||
|
void audioDevicesChanged();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void doUpdate();
|
||||||
|
void on_mpv_events();
|
||||||
|
void updateDurationString();
|
||||||
|
void handleWindowChanged(QQuickWindow* win);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void handle_mpv_event(mpv_event* event);
|
||||||
|
#ifdef DISCORD
|
||||||
|
void updateDiscord();
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -1,4 +1,4 @@
|
||||||
#ifndef MpvPlayerBackend_H
|
#ifndef MpvPlayerBackend_Hc
|
||||||
#define MpvPlayerBackend_H
|
#define MpvPlayerBackend_H
|
||||||
|
|
||||||
#include <mpv/client.h>
|
#include <mpv/client.h>
|
||||||
|
@ -9,13 +9,19 @@
|
||||||
#include <QOpenGLContext>
|
#include <QOpenGLContext>
|
||||||
#include <QQuickFramebufferObject>
|
#include <QQuickFramebufferObject>
|
||||||
|
|
||||||
|
#include "backendinterface.hpp"
|
||||||
#include "enums.hpp"
|
#include "enums.hpp"
|
||||||
|
|
||||||
class MpvRenderer;
|
class MpvRenderer;
|
||||||
|
|
||||||
class MpvPlayerBackend : public QQuickFramebufferObject
|
class MpvPlayerBackend
|
||||||
|
: public QQuickFramebufferObject
|
||||||
|
, public BackendInterface
|
||||||
{
|
{
|
||||||
|
Q_INTERFACES(BackendInterface)
|
||||||
|
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
mpv_handle* mpv;
|
mpv_handle* mpv;
|
||||||
mpv_render_context* mpv_gl;
|
mpv_render_context* mpv_gl;
|
||||||
bool onTop = false;
|
bool onTop = false;
|
||||||
|
@ -30,7 +36,6 @@ public:
|
||||||
virtual Renderer* createRenderer() const;
|
virtual Renderer* createRenderer() const;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
// All 5 required for Player API
|
|
||||||
QVariant playerCommand(const Enums::Commands& command, const QVariant& args);
|
QVariant playerCommand(const Enums::Commands& command, const QVariant& args);
|
||||||
QVariant playerCommand(const Enums::Commands& command);
|
QVariant playerCommand(const Enums::Commands& command);
|
||||||
void launchAboutQt();
|
void launchAboutQt();
|
||||||
|
@ -41,7 +46,7 @@ public slots:
|
||||||
void setProperty(const QString& name, const QVariant& value);
|
void setProperty(const QString& name, const QVariant& value);
|
||||||
void setOption(const QString& name, const QVariant& value);
|
void setOption(const QString& name, const QVariant& value);
|
||||||
QVariant getProperty(const QString& name) const;
|
QVariant getProperty(const QString& name) const;
|
||||||
// Misc function.
|
// Misc
|
||||||
QVariant createTimestamp(const QVariant& seconds) const;
|
QVariant createTimestamp(const QVariant& seconds) const;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
46
src/backendinterface.hpp
Normal file
46
src/backendinterface.hpp
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
#include <QObject>
|
||||||
|
#include <QOpenGLContext>
|
||||||
|
#include <QQuickFramebufferObject>
|
||||||
|
|
||||||
|
#include "enums.hpp"
|
||||||
|
|
||||||
|
#ifndef BackendInterface_H
|
||||||
|
#define BackendInterface_H
|
||||||
|
|
||||||
|
class BackendInterface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~BackendInterface(){};
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
// All 5 required for Player API
|
||||||
|
virtual QVariant playerCommand(const Enums::Commands& command,
|
||||||
|
const QVariant& args) = 0;
|
||||||
|
virtual QVariant playerCommand(const Enums::Commands& command) = 0;
|
||||||
|
virtual void launchAboutQt() = 0;
|
||||||
|
virtual void toggleOnTop() = 0;
|
||||||
|
virtual void updateAppImage() = 0;
|
||||||
|
// Optional but handy for MPV or custom backend settings.
|
||||||
|
virtual void command(const QVariant& params) = 0;
|
||||||
|
virtual void setProperty(const QString& name, const QVariant& value) = 0;
|
||||||
|
virtual void setOption(const QString& name, const QVariant& value) = 0;
|
||||||
|
virtual QVariant getProperty(const QString& name) const = 0;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
// All below required for Player API
|
||||||
|
virtual void playStatusChanged(const Enums::PlayStatus& status) = 0;
|
||||||
|
virtual void volumeStatusChanged(const Enums::VolumeStatus& status) = 0;
|
||||||
|
virtual void volumeChanged(const int& volume) = 0;
|
||||||
|
virtual void durationChanged(const double& duration) = 0;
|
||||||
|
virtual void positionChanged(const double& position) = 0;
|
||||||
|
virtual void cachedDurationChanged(const double& duration) = 0;
|
||||||
|
virtual void playlistPositionChanged(const double& position) = 0;
|
||||||
|
virtual void titleChanged(const QString& title) = 0;
|
||||||
|
virtual void subtitlesChanged(const QString& subtitles) = 0;
|
||||||
|
virtual void durationStringChanged(const QString& string) = 0;
|
||||||
|
virtual void tracksChanged() = 0;
|
||||||
|
virtual void audioDevicesChanged() = 0;
|
||||||
|
};
|
||||||
|
Q_DECLARE_INTERFACE(BackendInterface, "NamedKitten.BackendInterface");
|
||||||
|
|
||||||
|
#endif
|
|
@ -47,6 +47,12 @@ enum class Commands : int
|
||||||
SetTrack = 23
|
SetTrack = 23
|
||||||
};
|
};
|
||||||
Q_ENUM_NS(Commands)
|
Q_ENUM_NS(Commands)
|
||||||
|
enum class Backends : int
|
||||||
|
{
|
||||||
|
MpvBackend = 0,
|
||||||
|
DirectMpvBackend = 1
|
||||||
|
};
|
||||||
|
Q_ENUM_NS(Backends)
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
28
src/main.cpp
28
src/main.cpp
|
@ -2,7 +2,10 @@
|
||||||
#include "runtimeqml/runtimeqml.h"
|
#include "runtimeqml/runtimeqml.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "DirectMpvPlayerBackend.h"
|
||||||
#include "MpvPlayerBackend.h"
|
#include "MpvPlayerBackend.h"
|
||||||
|
|
||||||
|
#include "enums.hpp"
|
||||||
#include "utils.hpp"
|
#include "utils.hpp"
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
|
||||||
|
@ -51,6 +54,8 @@ catchUnixSignals(std::initializer_list<int> quitSignals)
|
||||||
int
|
int
|
||||||
main(int argc, char* argv[])
|
main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
|
|
||||||
|
Enums::Backends backend = Enums::Backends::MpvBackend;
|
||||||
setenv("QT_QUICK_CONTROLS_STYLE", "Desktop", 1);
|
setenv("QT_QUICK_CONTROLS_STYLE", "Desktop", 1);
|
||||||
QApplication app(argc, argv);
|
QApplication app(argc, argv);
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
|
@ -79,8 +84,9 @@ main(int argc, char* argv[])
|
||||||
QProcess notifier;
|
QProcess notifier;
|
||||||
notifier.setProcessChannelMode(QProcess::ForwardedChannels);
|
notifier.setProcessChannelMode(QProcess::ForwardedChannels);
|
||||||
notifier.start("notify-send",
|
notifier.start("notify-send",
|
||||||
QStringList()
|
QStringList() << "KittehPlayer"
|
||||||
<< "KittehPlayer" << "New update avalable!" << "--icon=KittehPlayer");
|
<< "New update avalable!"
|
||||||
|
<< "--icon=KittehPlayer");
|
||||||
notifier.waitForFinished();
|
notifier.waitForFinished();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -94,6 +100,12 @@ main(int argc, char* argv[])
|
||||||
for (int i = 1; i < argc; ++i) {
|
for (int i = 1; i < argc; ++i) {
|
||||||
if (!qstrcmp(argv[i], "--update")) {
|
if (!qstrcmp(argv[i], "--update")) {
|
||||||
Utils::updateAppImage();
|
Utils::updateAppImage();
|
||||||
|
} else if (!qstrcmp(argv[i], "--backend=mpv")) {
|
||||||
|
qDebug() << "Using MPV backend.";
|
||||||
|
backend = Enums::Backends::MpvBackend;
|
||||||
|
} else if (!qstrcmp(argv[i], "--backend=direct-mpv")) {
|
||||||
|
qDebug() << "Using Direct MPV backend.";
|
||||||
|
backend = Enums::Backends::DirectMpvBackend;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,9 +130,21 @@ main(int argc, char* argv[])
|
||||||
);
|
);
|
||||||
qRegisterMetaType<Enums::PlayStatus>("Enums.PlayStatus");
|
qRegisterMetaType<Enums::PlayStatus>("Enums.PlayStatus");
|
||||||
qRegisterMetaType<Enums::VolumeStatus>("Enums.VolumeStatus");
|
qRegisterMetaType<Enums::VolumeStatus>("Enums.VolumeStatus");
|
||||||
|
qRegisterMetaType<Enums::Backends>("Enums.Backends");
|
||||||
|
|
||||||
qRegisterMetaType<Enums::Commands>("Enums.Commands");
|
qRegisterMetaType<Enums::Commands>("Enums.Commands");
|
||||||
|
|
||||||
|
switch (backend) {
|
||||||
|
case Enums::Backends::MpvBackend: {
|
||||||
qmlRegisterType<MpvPlayerBackend>("player", 1, 0, "PlayerBackend");
|
qmlRegisterType<MpvPlayerBackend>("player", 1, 0, "PlayerBackend");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Enums::Backends::DirectMpvBackend: {
|
||||||
|
qmlRegisterType<DirectMpvPlayerBackend>("player", 1, 0, "PlayerBackend");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::setlocale(LC_NUMERIC, "C");
|
std::setlocale(LC_NUMERIC, "C");
|
||||||
|
|
||||||
QQmlApplicationEngine engine;
|
QQmlApplicationEngine engine;
|
||||||
|
|
148
src/qml/main.qml
148
src/qml/main.qml
|
@ -19,23 +19,6 @@ ApplicationWindow {
|
||||||
id: translate
|
id: translate
|
||||||
}
|
}
|
||||||
|
|
||||||
property int lastScreenVisibility
|
|
||||||
|
|
||||||
function toggleFullscreen() {
|
|
||||||
if (mainWindow.visibility != Window.FullScreen) {
|
|
||||||
lastScreenVisibility = mainWindow.visibility
|
|
||||||
mainWindow.visibility = Window.FullScreen
|
|
||||||
} else {
|
|
||||||
mainWindow.visibility = lastScreenVisibility
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PlayerBackend {
|
|
||||||
id: player
|
|
||||||
anchors.fill: parent
|
|
||||||
width: parent.width
|
|
||||||
height: parent.height
|
|
||||||
|
|
||||||
Settings {
|
Settings {
|
||||||
id: appearance
|
id: appearance
|
||||||
category: "Appearance"
|
category: "Appearance"
|
||||||
|
@ -56,7 +39,85 @@ ApplicationWindow {
|
||||||
property bool nyanCat: false
|
property bool nyanCat: false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Settings {
|
||||||
|
id: keybinds
|
||||||
|
category: "Keybinds"
|
||||||
|
property string playPause: "K"
|
||||||
|
property string forward10: "L"
|
||||||
|
property string rewind10: "J"
|
||||||
|
property string forward5: "Right"
|
||||||
|
property string rewind5: "Left"
|
||||||
|
property string openFile: "Ctrl+O"
|
||||||
|
property string openURI: "Ctrl+Shift+O"
|
||||||
|
property string quit: "Ctrl+Q"
|
||||||
|
property string fullscreen: "F"
|
||||||
|
property string tracks: "Ctrl+T"
|
||||||
|
property string statsForNerds: "I"
|
||||||
|
property string forwardFrame: "."
|
||||||
|
property string backwardFrame: ","
|
||||||
|
property string cycleSub: "Alt+S"
|
||||||
|
property string cycleSubBackwards: "Alt+Shift+S"
|
||||||
|
property string cycleAudio: "A"
|
||||||
|
property string cycleVideo: "V"
|
||||||
|
property string cycleVideoAspect: "Shift+A"
|
||||||
|
property string screenshot: "S"
|
||||||
|
property string screenshotWithoutSubtitles: "Shift+S"
|
||||||
|
property string fullScreenshot: "Ctrl+S"
|
||||||
|
property string nyanCat: "Ctrl+N"
|
||||||
|
property string decreaseSpeedByPointOne: "["
|
||||||
|
property string increaseSpeedByPointOne: "]"
|
||||||
|
property string halveSpeed: "{"
|
||||||
|
property string doubleSpeed: "}"
|
||||||
|
property string increaseVolume: "*"
|
||||||
|
property string decreaseVolume: "/"
|
||||||
|
property string mute: "m"
|
||||||
|
property string customKeybind0: ""
|
||||||
|
property string customKeybind0Command: ""
|
||||||
|
property string customKeybind1: ""
|
||||||
|
property string customKeybind1Command: ""
|
||||||
|
property string customKeybind2: ""
|
||||||
|
property string customKeybind2Command: ""
|
||||||
|
property string customKeybind3: ""
|
||||||
|
property string customKeybind3Command: ""
|
||||||
|
property string customKeybind4: ""
|
||||||
|
property string customKeybind4Command: ""
|
||||||
|
property string customKeybind5: ""
|
||||||
|
property string customKeybind5Command: ""
|
||||||
|
property string customKeybind6: ""
|
||||||
|
property string customKeybind6Command: ""
|
||||||
|
property string customKeybind7: ""
|
||||||
|
property string customKeybind7Command: ""
|
||||||
|
property string customKeybind8: ""
|
||||||
|
property string customKeybind8Command: ""
|
||||||
|
property string customKeybind9: ""
|
||||||
|
property string customKeybind9Command: ""
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
property int lastScreenVisibility
|
||||||
|
|
||||||
|
function toggleFullscreen() {
|
||||||
|
if (mainWindow.visibility != Window.FullScreen) {
|
||||||
|
lastScreenVisibility = mainWindow.visibility
|
||||||
|
mainWindow.visibility = Window.FullScreen
|
||||||
|
} else {
|
||||||
|
mainWindow.visibility = lastScreenVisibility
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PlayerBackend {
|
||||||
|
id: player
|
||||||
|
anchors.fill: parent
|
||||||
|
width: parent.width
|
||||||
|
height: parent.height
|
||||||
|
z: 1
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function startPlayer() {
|
function startPlayer() {
|
||||||
|
console.log(player)
|
||||||
|
console.log(typeof(player))
|
||||||
var args = Qt.application.arguments
|
var args = Qt.application.arguments
|
||||||
var len = Qt.application.arguments.length
|
var len = Qt.application.arguments.length
|
||||||
var argNo = 0
|
var argNo = 0
|
||||||
|
@ -228,59 +289,6 @@ ApplicationWindow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Settings {
|
|
||||||
id: keybinds
|
|
||||||
category: "Keybinds"
|
|
||||||
property string playPause: "K"
|
|
||||||
property string forward10: "L"
|
|
||||||
property string rewind10: "J"
|
|
||||||
property string forward5: "Right"
|
|
||||||
property string rewind5: "Left"
|
|
||||||
property string openFile: "Ctrl+O"
|
|
||||||
property string openURI: "Ctrl+Shift+O"
|
|
||||||
property string quit: "Ctrl+Q"
|
|
||||||
property string fullscreen: "F"
|
|
||||||
property string tracks: "Ctrl+T"
|
|
||||||
property string statsForNerds: "I"
|
|
||||||
property string forwardFrame: "."
|
|
||||||
property string backwardFrame: ","
|
|
||||||
property string cycleSub: "Alt+S"
|
|
||||||
property string cycleSubBackwards: "Alt+Shift+S"
|
|
||||||
property string cycleAudio: "A"
|
|
||||||
property string cycleVideo: "V"
|
|
||||||
property string cycleVideoAspect: "Shift+A"
|
|
||||||
property string screenshot: "S"
|
|
||||||
property string screenshotWithoutSubtitles: "Shift+S"
|
|
||||||
property string fullScreenshot: "Ctrl+S"
|
|
||||||
property string nyanCat: "Ctrl+N"
|
|
||||||
property string decreaseSpeedByPointOne: "["
|
|
||||||
property string increaseSpeedByPointOne: "]"
|
|
||||||
property string halveSpeed: "{"
|
|
||||||
property string doubleSpeed: "}"
|
|
||||||
property string increaseVolume: "*"
|
|
||||||
property string decreaseVolume: "/"
|
|
||||||
property string mute: "m"
|
|
||||||
property string customKeybind0: ""
|
|
||||||
property string customKeybind0Command: ""
|
|
||||||
property string customKeybind1: ""
|
|
||||||
property string customKeybind1Command: ""
|
|
||||||
property string customKeybind2: ""
|
|
||||||
property string customKeybind2Command: ""
|
|
||||||
property string customKeybind3: ""
|
|
||||||
property string customKeybind3Command: ""
|
|
||||||
property string customKeybind4: ""
|
|
||||||
property string customKeybind4Command: ""
|
|
||||||
property string customKeybind5: ""
|
|
||||||
property string customKeybind5Command: ""
|
|
||||||
property string customKeybind6: ""
|
|
||||||
property string customKeybind6Command: ""
|
|
||||||
property string customKeybind7: ""
|
|
||||||
property string customKeybind7Command: ""
|
|
||||||
property string customKeybind8: ""
|
|
||||||
property string customKeybind8Command: ""
|
|
||||||
property string customKeybind9: ""
|
|
||||||
property string customKeybind9Command: ""
|
|
||||||
}
|
|
||||||
|
|
||||||
MainMenu {
|
MainMenu {
|
||||||
id: menuBar
|
id: menuBar
|
||||||
|
|
Loading…
Reference in a new issue