From 278e9b488402074a847a48b9ef9ffdca4f9119ed Mon Sep 17 00:00:00 2001 From: Daniel Clarke Date: Fri, 30 Dec 2022 00:10:14 -0500 Subject: [PATCH 01/19] Operable but painfully slow mpv_renderer API --- src/bakaengine.cpp | 2 +- src/mpvhandler.cpp | 302 +++++++++++++++++++++++++----------------- src/mpvhandler.h | 23 ++-- src/ui/mainwindow.cpp | 4 +- src/ui/mainwindow.ui | 7 +- 5 files changed, 204 insertions(+), 134 deletions(-) diff --git a/src/bakaengine.cpp b/src/bakaengine.cpp index b20dd0c7..a5796d96 100644 --- a/src/bakaengine.cpp +++ b/src/bakaengine.cpp @@ -16,7 +16,7 @@ BakaEngine::BakaEngine(QObject *parent): QObject(parent), window(static_cast(parent)), - mpv(new MpvHandler(window->ui->mpvFrame->winId(), this)), + mpv(window->ui->mpvFrame), settings(new Settings(Util::SettingsLocation(), this)), gesture(new GestureHandler(this)), overlay(new OverlayHandler(this)), diff --git a/src/mpvhandler.cpp b/src/mpvhandler.cpp index e973139a..b1d127c7 100644 --- a/src/mpvhandler.cpp +++ b/src/mpvhandler.cpp @@ -1,5 +1,3 @@ -#include "mpvhandler.h" - #include #include #include @@ -8,18 +6,29 @@ #include #include "bakaengine.h" +#include "mpvtypes.h" #include "overlayhandler.h" #include "util.h" +#include "mpvhandler.h" +#include +#include +#include static void wakeup(void *ctx) { - MpvHandler *mpvhandler = (MpvHandler*)ctx; - QCoreApplication::postEvent(mpvhandler, new QEvent(QEvent::User)); + QMetaObject::invokeMethod((MpvHandler*)ctx, "on_mpv_events", Qt::QueuedConnection); +} + +static void *get_proc_address(void *ctx, const char *name) { + Q_UNUSED(ctx); + QOpenGLContext *glctx = QOpenGLContext::currentContext(); + if (!glctx) + return nullptr; + return reinterpret_cast(glctx->getProcAddress(QByteArray(name))); } -MpvHandler::MpvHandler(int64_t wid, QObject *parent): - QObject(parent), - baka(static_cast(parent)) +MpvHandler::MpvHandler(QWidget *parent, Qt::WindowFlags f): + QOpenGLWidget(parent, f) { // create mpv mpv = mpv_create(); @@ -27,7 +36,6 @@ MpvHandler::MpvHandler(int64_t wid, QObject *parent): throw "Could not create mpv object"; // set mpv options - mpv_set_option(mpv, "wid", MPV_FORMAT_INT64, &wid); mpv_set_option_string(mpv, "input-cursor", "no"); // no mouse handling mpv_set_option_string(mpv, "cursor-autohide", "no");// no cursor-autohide, we handle that mpv_set_option_string(mpv, "ytdl", "yes"); // youtube-dl support @@ -52,17 +60,47 @@ MpvHandler::MpvHandler(int64_t wid, QObject *parent): MpvHandler::~MpvHandler() { - if(mpv) - { - mpv_terminate_destroy(mpv); - mpv = NULL; - } + makeCurrent(); + if (mpv_gl) + mpv_render_context_free(mpv_gl); + mpv_terminate_destroy(mpv); } -void MpvHandler::Initialize() +void MpvHandler::Initialize(BakaEngine *baka) { if(mpv_initialize(mpv) < 0) throw "Could not initialize mpv"; + + this->baka = baka; +} + +void MpvHandler::initializeGL() +{ + mpv_opengl_init_params gl_init_params{get_proc_address, nullptr}; + mpv_render_param params[]{ + {MPV_RENDER_PARAM_API_TYPE, const_cast(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"); + mpv_render_context_set_update_callback(mpv_gl, MpvHandler::on_update, reinterpret_cast(this)); +} + +void MpvHandler::paintGL() +{ + mpv_opengl_fbo mpfbo{static_cast(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); } QString MpvHandler::getMediaInfo() @@ -133,136 +171,156 @@ QString MpvHandler::getMediaInfo() return out; } -bool MpvHandler::event(QEvent *event) +void MpvHandler::on_mpv_events() { - if(event->type() == QEvent::User) + while(mpv) { - while(mpv) + mpv_event *event = mpv_wait_event(mpv, 0); + if(event == nullptr || + event->event_id == MPV_EVENT_NONE) + { + break; + } + HandleErrorCode(event->error); + switch (event->event_id) + { + case MPV_EVENT_PROPERTY_CHANGE: { - mpv_event *event = mpv_wait_event(mpv, 0); - if(event == nullptr || - event->event_id == MPV_EVENT_NONE) + mpv_event_property *prop = (mpv_event_property*)event->data; + if(QString(prop->name) == "playback-time") // playback-time does the same thing as time-pos but works for streaming media { - break; + if(prop->format == MPV_FORMAT_DOUBLE) + { + setTime((int)*(double*)prop->data); + lastTime = time; + } } - HandleErrorCode(event->error); - switch (event->event_id) + else if(QString(prop->name) == "volume") { - case MPV_EVENT_PROPERTY_CHANGE: + if(prop->format == MPV_FORMAT_DOUBLE) + setVolume((int)*(double*)prop->data); + } + else if(QString(prop->name) == "sid") { - mpv_event_property *prop = (mpv_event_property*)event->data; - if(QString(prop->name) == "playback-time") // playback-time does the same thing as time-pos but works for streaming media - { - if(prop->format == MPV_FORMAT_DOUBLE) - { - setTime((int)*(double*)prop->data); - lastTime = time; - } - } - else if(QString(prop->name) == "volume") - { - if(prop->format == MPV_FORMAT_DOUBLE) - setVolume((int)*(double*)prop->data); - } - else if(QString(prop->name) == "sid") - { - if(prop->format == MPV_FORMAT_INT64) - setSid(*(int*)prop->data); - } - else if(QString(prop->name) == "aid") - { - if(prop->format == MPV_FORMAT_INT64) - setAid(*(int*)prop->data); - } - else if(QString(prop->name) == "sub-visibility") - { - if(prop->format == MPV_FORMAT_FLAG) - setSubtitleVisibility((bool)*(unsigned*)prop->data); - } - else if(QString(prop->name) == "mute") - { - if(prop->format == MPV_FORMAT_FLAG) - setMute((bool)*(unsigned*)prop->data); - } - else if(QString(prop->name) == "core-idle") - { - if(prop->format == MPV_FORMAT_FLAG) - { - if((bool)*(unsigned*)prop->data && playState == Mpv::Playing) - ShowText(tr("Buffering..."), 0); - else - ShowText(QString(), 0); - } - } - else if(QString(prop->name) == "idle-active") + if(prop->format == MPV_FORMAT_INT64) + setSid(*(int*)prop->data); + } + else if(QString(prop->name) == "aid") + { + if(prop->format == MPV_FORMAT_INT64) + setAid(*(int*)prop->data); + } + else if(QString(prop->name) == "sub-visibility") + { + if(prop->format == MPV_FORMAT_FLAG) + setSubtitleVisibility((bool)*(unsigned*)prop->data); + } + else if(QString(prop->name) == "mute") + { + if(prop->format == MPV_FORMAT_FLAG) + setMute((bool)*(unsigned*)prop->data); + } + else if(QString(prop->name) == "core-idle") + { + if(prop->format == MPV_FORMAT_FLAG) { - if(prop->format == MPV_FORMAT_FLAG) - { - if((bool)*(unsigned*)prop->data) - { - fileInfo.length = 0; - setTime(0); - setPlayState(Mpv::Idle); - } - } + if((bool)*(unsigned*)prop->data && playState == Mpv::Playing) + ShowText(tr("Buffering..."), 0); + else + ShowText(QString(), 0); } - else if(QString(prop->name) == "pause") + } + else if(QString(prop->name) == "idle-active") + { + if(prop->format == MPV_FORMAT_FLAG) { - if(prop->format == MPV_FORMAT_FLAG) + if((bool)*(unsigned*)prop->data) { - if((bool)*(unsigned*)prop->data) - { - setPlayState(Mpv::Paused); - ShowText(QString(), 0); - } - else - setPlayState(Mpv::Playing); + fileInfo.length = 0; + setTime(0); + setPlayState(Mpv::Idle); } } - else if(QString(prop->name) == "paused-for-cache") + } + else if(QString(prop->name) == "pause") + { + if(prop->format == MPV_FORMAT_FLAG) { - if(prop->format == MPV_FORMAT_FLAG) + if((bool)*(unsigned*)prop->data) { - if((bool)*(unsigned*)prop->data && playState == Mpv::Playing) - ShowText(tr("Your network is slow or stuck, please wait a bit"), 0); - else - ShowText(QString(), 0); + setPlayState(Mpv::Paused); + ShowText(QString(), 0); } + else + setPlayState(Mpv::Playing); } - break; } - // these two look like they're reversed but they aren't. the names are misleading. - case MPV_EVENT_START_FILE: - setPlayState(Mpv::Loaded); - break; - case MPV_EVENT_FILE_LOADED: - setPlayState(Mpv::Started); - LoadFileInfo(); - SetProperties(); - setPlayState(Mpv::Playing); - break; - case MPV_EVENT_END_FILE: - if(playState == Mpv::Loaded) - ShowText(tr("File couldn't be opened")); - setPlayState(Mpv::Stopped); - break; - case MPV_EVENT_SHUTDOWN: - QCoreApplication::quit(); - break; - case MPV_EVENT_LOG_MESSAGE: + else if(QString(prop->name) == "paused-for-cache") { - mpv_event_log_message *message = static_cast(event->data); - if(message != nullptr) - emit messageSignal(message->text); - break; - } - default: // unhandled events - break; + if(prop->format == MPV_FORMAT_FLAG) + { + if((bool)*(unsigned*)prop->data && playState == Mpv::Playing) + ShowText(tr("Your network is slow or stuck, please wait a bit"), 0); + else + ShowText(QString(), 0); + } } + break; } - return true; + // these two look like they're reversed but they aren't. the names are misleading. + case MPV_EVENT_START_FILE: + setPlayState(Mpv::Loaded); + break; + case MPV_EVENT_FILE_LOADED: + setPlayState(Mpv::Started); + LoadFileInfo(); + SetProperties(); + setPlayState(Mpv::Playing); + break; + case MPV_EVENT_END_FILE: + if(playState == Mpv::Loaded) + ShowText(tr("File couldn't be opened")); + setPlayState(Mpv::Stopped); + break; + case MPV_EVENT_SHUTDOWN: + QCoreApplication::quit(); + break; + case MPV_EVENT_LOG_MESSAGE: + { + mpv_event_log_message *message = static_cast(event->data); + if(message != nullptr) + emit messageSignal(message->text); + break; + } + default: // unhandled events + break; + } + } +} + +// Make Qt invoke mpv_render_context_render() to draw a new/updated video frame. +void MpvHandler::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()->isVisible()) { + makeCurrent(); + paintGL(); + context()->swapBuffers(context()->surface()); + doneCurrent(); + } else { + update(); } - return QObject::event(event); +} + +void MpvHandler::on_update(void *ctx) +{ + QMetaObject::invokeMethod((MpvHandler*)ctx, "maybeUpdate"); } void MpvHandler::AddOverlay(int id, int x, int y, QString file, int offset, int w, int h) diff --git a/src/mpvhandler.h b/src/mpvhandler.h index bcf80ebc..b6961ccd 100644 --- a/src/mpvhandler.h +++ b/src/mpvhandler.h @@ -1,11 +1,11 @@ #ifndef MPVHANDLER_H #define MPVHANDLER_H -#include +#include #include #include - #include +#include #include "mpvtypes.h" @@ -14,15 +14,15 @@ class BakaEngine; -class MpvHandler : public QObject +class MpvHandler Q_DECL_FINAL: public QOpenGLWidget { friend class BakaEngine; Q_OBJECT public: - explicit MpvHandler(int64_t wid, QObject *parent = 0); + explicit MpvHandler(QWidget *parent = 0, Qt::WindowFlags f = 0); ~MpvHandler(); - void Initialize(); + void Initialize(BakaEngine *baka); const Mpv::FileInfo &getFileInfo() { return fileInfo; } Mpv::PlayState getPlayState() { return playState; } QString getFile() { return file; } @@ -47,7 +47,8 @@ friend class BakaEngine; QString getMediaInfo(); protected: - virtual bool event(QEvent*); + void initializeGL() Q_DECL_OVERRIDE; + void paintGL() Q_DECL_OVERRIDE; bool FileExists(QString); @@ -122,7 +123,10 @@ protected slots: void Command(const char *args[]); void HandleErrorCode(int); -private slots: +private Q_SLOTS: + void on_mpv_events(); + void maybeUpdate(); + void setPlaylist(const QStringList& l) { emit playlistChanged(l); } void setFileInfo() { emit fileInfoChanged(fileInfo); } void setPlayState(Mpv::PlayState s) { emit playStateChanged(playState = s); } @@ -173,8 +177,11 @@ private slots: void messageSignal(QString m); private: + static void on_update(void *ctx); + BakaEngine *baka; - mpv_handle *mpv = nullptr; + mpv_handle *mpv; + mpv_render_context *mpv_gl; // variables Mpv::PlayState playState = Mpv::Idle; diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index fc6067c3..4eb6a02b 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -29,7 +29,7 @@ MainWindow::MainWindow(QWidget *parent): // initialize managers/handlers baka = new BakaEngine(this); - mpv = baka->mpv; + mpv = this->ui->mpvFrame; ui->playlistWidget->AttachEngine(baka); ui->mpvFrame->installEventFilter(this); // capture events on mpvFrame in the eventFilter function @@ -894,7 +894,7 @@ void MainWindow::Load(QString file) thumbnail_toolbar->addButton(next_toolbutton); #endif baka->LoadSettings(); - mpv->Initialize(); + mpv->Initialize(baka); mpv->LoadFile(file); } diff --git a/src/ui/mainwindow.ui b/src/ui/mainwindow.ui index e196777e..682686fb 100644 --- a/src/ui/mainwindow.ui +++ b/src/ui/mainwindow.ui @@ -202,7 +202,7 @@ QScrollBar::right-arrow:horizontal { Qt::Vertical - + 0 @@ -1733,6 +1733,11 @@ QSlider::handle:horizontal { QLineEdit
widgets/customlineedit.h
+ + MpvHandler + QOpenGLWidget +
mpvhandler.h
+
From 5b6c5dd94765dabcc3cc2857df401866c9e6896e Mon Sep 17 00:00:00 2001 From: Daniel Clarke Date: Mon, 2 Jan 2023 12:48:10 -0500 Subject: [PATCH 02/19] Address a few warnings --- src/mpvhandler.cpp | 10 +++++----- src/mpvhandler.h | 2 +- src/ui/mainwindow.cpp | 10 +++++----- src/widgets/dimdialog.cpp | 5 ++--- 4 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/mpvhandler.cpp b/src/mpvhandler.cpp index b1d127c7..221c2a2a 100644 --- a/src/mpvhandler.cpp +++ b/src/mpvhandler.cpp @@ -27,8 +27,8 @@ static void *get_proc_address(void *ctx, const char *name) { return reinterpret_cast(glctx->getProcAddress(QByteArray(name))); } -MpvHandler::MpvHandler(QWidget *parent, Qt::WindowFlags f): - QOpenGLWidget(parent, f) +MpvHandler::MpvHandler(QWidget *parent): + QOpenGLWidget(parent) { // create mpv mpv = mpv_create(); @@ -133,7 +133,7 @@ QString MpvHandler::getMediaInfo() QString out = outer.arg(tr("File"), fi.fileName()) + inner.arg(tr("Title"), fileInfo.media_title) + inner.arg(tr("File size"), Util::HumanSize(fi.size())) + - inner.arg(tr("Date created"), fi.created().toString()) + + inner.arg(tr("Date created"), fi.birthTime().toString()) + inner.arg(tr("Media length"), Util::FormatTime(fileInfo.length, fileInfo.length)) + '\n'; if(fileInfo.video_params.codec != QString()) out += outer.arg(tr("Video (x%0)").arg(QString::number(vtracks)), fileInfo.video_params.codec) + @@ -604,7 +604,7 @@ void MpvHandler::Speed(double d) void MpvHandler::Aspect(QString aspect) { const QByteArray tmp = aspect.toUtf8(); - const char *args[] = {"set", "video-aspect", tmp.constData(), NULL}; + const char *args[] = {"set", "video-aspect-override", tmp.constData(), NULL}; AsyncCommand(args); } @@ -880,7 +880,7 @@ void MpvHandler::LoadVideoParams() mpv_get_property(mpv, "dwidth", MPV_FORMAT_INT64, &fileInfo.video_params.dwidth); mpv_get_property(mpv, "dheight", MPV_FORMAT_INT64, &fileInfo.video_params.dheight); // though this has become useless, removing it causes a segfault--no clue: - mpv_get_property(mpv, "video-aspect", MPV_FORMAT_INT64, &fileInfo.video_params.aspect); + mpv_get_property(mpv, "video-params/aspect", MPV_FORMAT_INT64, &fileInfo.video_params.aspect); emit videoParamsChanged(fileInfo.video_params); } diff --git a/src/mpvhandler.h b/src/mpvhandler.h index b6961ccd..3f69c3bd 100644 --- a/src/mpvhandler.h +++ b/src/mpvhandler.h @@ -19,7 +19,7 @@ class MpvHandler Q_DECL_FINAL: public QOpenGLWidget friend class BakaEngine; Q_OBJECT public: - explicit MpvHandler(QWidget *parent = 0, Qt::WindowFlags f = 0); + MpvHandler(QWidget *parent = 0); ~MpvHandler(); void Initialize(BakaEngine *baka); diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 4eb6a02b..216b8789 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -43,10 +43,10 @@ MainWindow::MainWindow(QWidget *parent): {"mpv set sub-scale 1", ui->action_Reset_Size}, {"mpv add sub-scale +0.1", ui->action_Size}, {"mpv add sub-scale -0.1", ui->actionS_ize}, - {"mpv set video-aspect -1", ui->action_Auto_Detect}, // todo: make these baka-commands so we can output messages when they change - {"mpv set video-aspect 16:9", ui->actionForce_16_9}, - {"mpv set video-aspect 2.35:1", ui->actionForce_2_35_1}, - {"mpv set video-aspect 4:3", ui->actionForce_4_3}, + {"mpv set video-aspect-override -1", ui->action_Auto_Detect}, // todo: make these baka-commands so we can output messages when they change + {"mpv set video-aspect-override 16:9", ui->actionForce_16_9}, + {"mpv set video-aspect-override 2.35:1", ui->actionForce_2_35_1}, + {"mpv set video-aspect-override 4:3", ui->actionForce_4_3}, {"mpv cycle sub-visibility", ui->actionShow_Subtitles}, {"mpv set time-pos 0", ui->action_Restart}, {"mpv frame-step", ui->action_Frame_Step}, @@ -1023,7 +1023,7 @@ bool MainWindow::eventFilter(QObject *obj, QEvent *event) void MainWindow::wheelEvent(QWheelEvent *event) { - if(event->delta() > 0) + if(event->angleDelta().y() > 0) mpv->Volume(mpv->getVolume()+5, true); else mpv->Volume(mpv->getVolume()-5, true); diff --git a/src/widgets/dimdialog.cpp b/src/widgets/dimdialog.cpp index 75227dd4..e9c9acf1 100644 --- a/src/widgets/dimdialog.cpp +++ b/src/widgets/dimdialog.cpp @@ -1,12 +1,11 @@ #include "dimdialog.h" #include "ui/mainwindow.h" -#include "ui_mainwindow.h" -#include "util.h" #include #include #include +#include DimDialog::DimDialog(MainWindow *window, QWidget *parent) : QDialog(parent), @@ -38,7 +37,7 @@ DimDialog::DimDialog(MainWindow *window, QWidget *parent) : void DimDialog::show() { // set the geometry in the show so that we can fill the desktop (even on another monitor) - setGeometry(qApp->desktop()->screenGeometry(window->frameGeometry().center())); + setGeometry(qApp->screenAt(window->frameGeometry().center())->geometry()); emit visbilityChanged(true); QDialog::show(); } From 2be9dd2ebd7095e0aa7e68acbe744643dc60d48c Mon Sep 17 00:00:00 2001 From: Daniel Clarke Date: Mon, 2 Jan 2023 12:48:15 -0500 Subject: [PATCH 03/19] WIP --- src/mpvhandler.cpp | 215 ++++++++++++++++++++++++--------------------- src/mpvhandler.h | 1 + 2 files changed, 118 insertions(+), 98 deletions(-) diff --git a/src/mpvhandler.cpp b/src/mpvhandler.cpp index 221c2a2a..6666aa5e 100644 --- a/src/mpvhandler.cpp +++ b/src/mpvhandler.cpp @@ -41,6 +41,7 @@ MpvHandler::MpvHandler(QWidget *parent): mpv_set_option_string(mpv, "ytdl", "yes"); // youtube-dl support mpv_set_option_string(mpv, "sub-auto", "fuzzy"); // Automatic subfile detection mpv_set_option_string(mpv, "audio-client-name", "baka-mplayer"); // show correct icon in e.g. pavucontrol + mpv_set_option_string(mpv, "hwdec", "auto"); // get updates when these properties change mpv_observe_property(mpv, 0, "playback-time", MPV_FORMAT_DOUBLE); @@ -56,6 +57,21 @@ MpvHandler::MpvHandler(QWidget *parent): // setup callback event handling mpv_set_wakeup_callback(mpv, wakeup, this); + + connect(this, &MpvHandler::playStateChanged, + [=](Mpv::PlayState playState) + { + switch(playState) + { + case Mpv::Started: + this->LoadFileInfo(); + this->SetProperties(); + setPlayState(Mpv::Playing); + break; + default: + break; + } + }); } MpvHandler::~MpvHandler() @@ -77,10 +93,11 @@ void MpvHandler::Initialize(BakaEngine *baka) void MpvHandler::initializeGL() { mpv_opengl_init_params gl_init_params{get_proc_address, nullptr}; + int advancedControlEnable = 0; mpv_render_param params[]{ {MPV_RENDER_PARAM_API_TYPE, const_cast(MPV_RENDER_API_TYPE_OPENGL)}, {MPV_RENDER_PARAM_OPENGL_INIT_PARAMS, &gl_init_params}, - {MPV_RENDER_PARAM_INVALID, nullptr} + {MPV_RENDER_PARAM_ADVANCED_CONTROL, &advancedControlEnable} }; if (mpv_render_context_create(&mpv_gl, mpv, params) < 0) @@ -182,119 +199,121 @@ void MpvHandler::on_mpv_events() break; } HandleErrorCode(event->error); - switch (event->event_id) - { - case MPV_EVENT_PROPERTY_CHANGE: + handle_mpv_event(event); + } +} + +void MpvHandler::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(QString(prop->name) == "playback-time") // playback-time does the same thing as time-pos but works for streaming media { - mpv_event_property *prop = (mpv_event_property*)event->data; - if(QString(prop->name) == "playback-time") // playback-time does the same thing as time-pos but works for streaming media - { - if(prop->format == MPV_FORMAT_DOUBLE) - { - setTime((int)*(double*)prop->data); - lastTime = time; - } - } - else if(QString(prop->name) == "volume") + if(prop->format == MPV_FORMAT_DOUBLE) { - if(prop->format == MPV_FORMAT_DOUBLE) - setVolume((int)*(double*)prop->data); + setTime((int)*(double*)prop->data); + lastTime = time; } - else if(QString(prop->name) == "sid") - { - if(prop->format == MPV_FORMAT_INT64) - setSid(*(int*)prop->data); - } - else if(QString(prop->name) == "aid") - { - if(prop->format == MPV_FORMAT_INT64) - setAid(*(int*)prop->data); - } - else if(QString(prop->name) == "sub-visibility") - { - if(prop->format == MPV_FORMAT_FLAG) - setSubtitleVisibility((bool)*(unsigned*)prop->data); - } - else if(QString(prop->name) == "mute") - { - if(prop->format == MPV_FORMAT_FLAG) - setMute((bool)*(unsigned*)prop->data); - } - else if(QString(prop->name) == "core-idle") - { - if(prop->format == MPV_FORMAT_FLAG) - { - if((bool)*(unsigned*)prop->data && playState == Mpv::Playing) - ShowText(tr("Buffering..."), 0); - else - ShowText(QString(), 0); - } - } - else if(QString(prop->name) == "idle-active") + } + else if(QString(prop->name) == "volume") + { + if(prop->format == MPV_FORMAT_DOUBLE) + setVolume((int)*(double*)prop->data); + } + else if(QString(prop->name) == "sid") + { + if(prop->format == MPV_FORMAT_INT64) + setSid(*(int*)prop->data); + } + else if(QString(prop->name) == "aid") + { + if(prop->format == MPV_FORMAT_INT64) + setAid(*(int*)prop->data); + } + else if(QString(prop->name) == "sub-visibility") + { + if(prop->format == MPV_FORMAT_FLAG) + setSubtitleVisibility((bool)*(unsigned*)prop->data); + } + else if(QString(prop->name) == "mute") + { + if(prop->format == MPV_FORMAT_FLAG) + setMute((bool)*(unsigned*)prop->data); + } + else if(QString(prop->name) == "core-idle") + { + if(prop->format == MPV_FORMAT_FLAG) { - if(prop->format == MPV_FORMAT_FLAG) - { - if((bool)*(unsigned*)prop->data) - { - fileInfo.length = 0; - setTime(0); - setPlayState(Mpv::Idle); - } - } + if((bool)*(unsigned*)prop->data && playState == Mpv::Playing) + ShowText(tr("Buffering..."), 0); + else + ShowText(QString(), 0); } - else if(QString(prop->name) == "pause") + } + else if(QString(prop->name) == "idle-active") + { + if(prop->format == MPV_FORMAT_FLAG) { - if(prop->format == MPV_FORMAT_FLAG) + if((bool)*(unsigned*)prop->data) { - if((bool)*(unsigned*)prop->data) - { - setPlayState(Mpv::Paused); - ShowText(QString(), 0); - } - else - setPlayState(Mpv::Playing); + fileInfo.length = 0; + setTime(0); + setPlayState(Mpv::Idle); } } - else if(QString(prop->name) == "paused-for-cache") + } + else if(QString(prop->name) == "pause") + { + if(prop->format == MPV_FORMAT_FLAG) { - if(prop->format == MPV_FORMAT_FLAG) + if((bool)*(unsigned*)prop->data) { - if((bool)*(unsigned*)prop->data && playState == Mpv::Playing) - ShowText(tr("Your network is slow or stuck, please wait a bit"), 0); - else - ShowText(QString(), 0); + setPlayState(Mpv::Paused); + ShowText(QString(), 0); } + else + setPlayState(Mpv::Playing); } - break; } - // these two look like they're reversed but they aren't. the names are misleading. - case MPV_EVENT_START_FILE: - setPlayState(Mpv::Loaded); - break; - case MPV_EVENT_FILE_LOADED: - setPlayState(Mpv::Started); - LoadFileInfo(); - SetProperties(); - setPlayState(Mpv::Playing); - break; - case MPV_EVENT_END_FILE: - if(playState == Mpv::Loaded) - ShowText(tr("File couldn't be opened")); - setPlayState(Mpv::Stopped); - break; - case MPV_EVENT_SHUTDOWN: - QCoreApplication::quit(); - break; - case MPV_EVENT_LOG_MESSAGE: + else if(QString(prop->name) == "paused-for-cache") { - mpv_event_log_message *message = static_cast(event->data); - if(message != nullptr) - emit messageSignal(message->text); - break; - } - default: // unhandled events - break; + if(prop->format == MPV_FORMAT_FLAG) + { + if((bool)*(unsigned*)prop->data && playState == Mpv::Playing) + ShowText(tr("Your network is slow or stuck, please wait a bit"), 0); + else + ShowText(QString(), 0); + } } + break; + } + // these two look like they're reversed but they aren't. the names are misleading. + case MPV_EVENT_START_FILE: + setPlayState(Mpv::Loaded); + break; + case MPV_EVENT_FILE_LOADED: + setPlayState(Mpv::Started); + break; + case MPV_EVENT_END_FILE: + if(playState == Mpv::Loaded) + ShowText(tr("File couldn't be opened")); + setPlayState(Mpv::Stopped); + break; + case MPV_EVENT_SHUTDOWN: + QCoreApplication::quit(); + break; + case MPV_EVENT_LOG_MESSAGE: + { + mpv_event_log_message *message = static_cast(event->data); + if(message != nullptr) + emit messageSignal(message->text); + break; + } + default: // unhandled events + break; } } diff --git a/src/mpvhandler.h b/src/mpvhandler.h index 3f69c3bd..661081d1 100644 --- a/src/mpvhandler.h +++ b/src/mpvhandler.h @@ -125,6 +125,7 @@ protected slots: private Q_SLOTS: void on_mpv_events(); + void handle_mpv_event(mpv_event *event); void maybeUpdate(); void setPlaylist(const QStringList& l) { emit playlistChanged(l); } From f6ffe9b29c4e50ae0a17f26889641438bced7aaa Mon Sep 17 00:00:00 2001 From: Daniel Clarke Date: Sat, 14 Jan 2023 11:36:12 -0500 Subject: [PATCH 04/19] Follow recommendations for mpv embedding --- src/bakaengine.cpp | 2 +- src/mpvhandler.cpp | 14 ++++++++++++-- src/mpvhandler.h | 2 +- src/ui/mainwindow.ui | 2 +- 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/bakaengine.cpp b/src/bakaengine.cpp index b20dd0c7..a1fc18ed 100644 --- a/src/bakaengine.cpp +++ b/src/bakaengine.cpp @@ -16,7 +16,7 @@ BakaEngine::BakaEngine(QObject *parent): QObject(parent), window(static_cast(parent)), - mpv(new MpvHandler(window->ui->mpvFrame->winId(), this)), + mpv(new MpvHandler(window->ui->mpvFrame, this)), settings(new Settings(Util::SettingsLocation(), this)), gesture(new GestureHandler(this)), overlay(new OverlayHandler(this)), diff --git a/src/mpvhandler.cpp b/src/mpvhandler.cpp index e973139a..86170ee0 100644 --- a/src/mpvhandler.cpp +++ b/src/mpvhandler.cpp @@ -17,7 +17,7 @@ static void wakeup(void *ctx) QCoreApplication::postEvent(mpvhandler, new QEvent(QEvent::User)); } -MpvHandler::MpvHandler(int64_t wid, QObject *parent): +MpvHandler::MpvHandler(QWidget *widget, QObject *parent): QObject(parent), baka(static_cast(parent)) { @@ -26,8 +26,18 @@ MpvHandler::MpvHandler(int64_t wid, QObject *parent): if(!mpv) throw "Could not create mpv object"; - // set mpv options + // hand widget to mpv + widget->setAttribute(Qt::WA_DontCreateNativeAncestors); + widget->setAttribute(Qt::WA_NativeWindow); + WId _wid = widget->winId(); +#ifdef _WIN32 + int64_t wid = static_cast(_wid); +#else + int64_t wid = _wid; +#endif mpv_set_option(mpv, "wid", MPV_FORMAT_INT64, &wid); + + // set mpv options mpv_set_option_string(mpv, "input-cursor", "no"); // no mouse handling mpv_set_option_string(mpv, "cursor-autohide", "no");// no cursor-autohide, we handle that mpv_set_option_string(mpv, "ytdl", "yes"); // youtube-dl support diff --git a/src/mpvhandler.h b/src/mpvhandler.h index bcf80ebc..3f2c3971 100644 --- a/src/mpvhandler.h +++ b/src/mpvhandler.h @@ -19,7 +19,7 @@ class MpvHandler : public QObject friend class BakaEngine; Q_OBJECT public: - explicit MpvHandler(int64_t wid, QObject *parent = 0); + explicit MpvHandler(QWidget *container, QObject *parent = 0); ~MpvHandler(); void Initialize(); diff --git a/src/ui/mainwindow.ui b/src/ui/mainwindow.ui index e196777e..1dfacf31 100644 --- a/src/ui/mainwindow.ui +++ b/src/ui/mainwindow.ui @@ -202,7 +202,7 @@ QScrollBar::right-arrow:horizontal { Qt::Vertical - + 0 From 6685ff65d7045ff31ff375237b89354d46eb1d92 Mon Sep 17 00:00:00 2001 From: Daniel Clarke Date: Sat, 14 Jan 2023 11:37:22 -0500 Subject: [PATCH 05/19] Address rgb => rgba warning --- src/overlayhandler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/overlayhandler.cpp b/src/overlayhandler.cpp index db5819a3..3ed0a189 100644 --- a/src/overlayhandler.cpp +++ b/src/overlayhandler.cpp @@ -130,7 +130,7 @@ void OverlayHandler::showText(const QString &text, QFont font, QColor color, QPo // add over mpv as label QLabel *label = new QLabel(baka->window->ui->mpvFrame); - label->setStyleSheet("background-color:rgb(0,0,0,0);background-image:url();"); + label->setStyleSheet("background-color:rgba(0,0,0,0);background-image:url();"); label->setGeometry(pos.x(), pos.y(), canvas->width(), From afee2cd64f16f0ae86c38727093933f94ddf43f5 Mon Sep 17 00:00:00 2001 From: Daniel Clarke Date: Sat, 14 Jan 2023 17:22:14 -0500 Subject: [PATCH 06/19] Address some warnings --- src/mpvhandler.cpp | 2 +- src/ui/updatedialog.cpp | 2 +- src/ui/updatedialog.h | 5 ++--- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/mpvhandler.cpp b/src/mpvhandler.cpp index 86170ee0..0a45237c 100644 --- a/src/mpvhandler.cpp +++ b/src/mpvhandler.cpp @@ -105,7 +105,7 @@ QString MpvHandler::getMediaInfo() QString out = outer.arg(tr("File"), fi.fileName()) + inner.arg(tr("Title"), fileInfo.media_title) + inner.arg(tr("File size"), Util::HumanSize(fi.size())) + - inner.arg(tr("Date created"), fi.created().toString()) + + inner.arg(tr("Date created"), fi.birthTime().toString()) + inner.arg(tr("Media length"), Util::FormatTime(fileInfo.length, fileInfo.length)) + '\n'; if(fileInfo.video_params.codec != QString()) out += outer.arg(tr("Video (x%0)").arg(QString::number(vtracks)), fileInfo.video_params.codec) + diff --git a/src/ui/updatedialog.cpp b/src/ui/updatedialog.cpp index ca2e2de7..150d33a2 100644 --- a/src/ui/updatedialog.cpp +++ b/src/ui/updatedialog.cpp @@ -56,7 +56,7 @@ UpdateDialog::UpdateDialog(BakaEngine *baka, QWidget *parent) : ui->timeRemainingLabel->setVisible(true); if(timer != nullptr) delete timer; - timer = new QTime(); + timer = new QElapsedTimer(); timer->start(); } else if(timer) // don't execute this if timer is not defined--this shouldn't happen though.. but it does diff --git a/src/ui/updatedialog.h b/src/ui/updatedialog.h index eca005f9..65002c43 100644 --- a/src/ui/updatedialog.h +++ b/src/ui/updatedialog.h @@ -2,8 +2,7 @@ #define UPDATEDIALOG_H #include -#include - +#include namespace Ui { class UpdateDialog; @@ -28,7 +27,7 @@ protected slots: Ui::UpdateDialog *ui; BakaEngine *baka; - QTime *timer; + QElapsedTimer *timer; double avgSpeed = 1, lastSpeed = 0; int lastProgress, From eea97443b6b09a719940ad205cdbad7e4545a41c Mon Sep 17 00:00:00 2001 From: Daniel Clarke Date: Sat, 21 Jan 2023 11:42:07 -0500 Subject: [PATCH 07/19] Address warnings --- src/bakacommands.cpp | 13 +++--- src/bakaengine.cpp | 4 +- src/mpvhandler.cpp | 4 +- src/overlayhandler.cpp | 11 +++-- src/overlayhandler.h | 2 - src/settings.cpp | 2 +- src/ui/mainwindow.cpp | 80 +++++++++++++++++----------------- src/ui/preferencesdialog.cpp | 16 +++---- src/ui/screenshotdialog.cpp | 4 +- src/ui/updatedialog.cpp | 7 ++- src/updatemanager.cpp | 14 +++--- src/util.cpp | 4 +- src/widgets/customsplitter.cpp | 2 +- src/widgets/dimdialog.cpp | 8 ++-- src/widgets/playlistwidget.cpp | 35 +++++++++------ 15 files changed, 103 insertions(+), 103 deletions(-) diff --git a/src/bakacommands.cpp b/src/bakacommands.cpp index 6cd2698f..b2502ed4 100644 --- a/src/bakacommands.cpp +++ b/src/bakacommands.cpp @@ -2,12 +2,12 @@ #include #include -#include #include #include #include #include #include +#include #include "ui/mainwindow.h" #include "ui_mainwindow.h" @@ -20,7 +20,6 @@ #include "widgets/dimdialog.h" #include "mpvhandler.h" #include "overlayhandler.h" -#include "updatemanager.h" #include "util.h" @@ -41,7 +40,7 @@ void BakaEngine::BakaSh(QStringList &args) QProcess *p = new QProcess(this); p->start(arg, args); connect(p, &QProcess::readyRead, - [=] + p, [=] { Print(p->readAll(), QString("%0(%1))").arg(p->program(), QString::number(quintptr(p)))); }); @@ -100,7 +99,7 @@ void BakaEngine::BakaAddSubtitles(QStringList &args) { trackFile = QFileDialog::getOpenFileName(window, tr("Open Subtitle File"), mpv->getPath(), QString("%0 (%1)").arg(tr("Subtitle Files"), Mpv::subtitle_filetypes.join(" ")), - 0, QFileDialog::DontUseSheet); + 0); } else trackFile = args.join(' '); @@ -115,7 +114,7 @@ void BakaEngine::BakaAddAudio(QStringList &args) { trackFile = QFileDialog::getOpenFileName(window, tr("Open Audio File"), mpv->getPath(), QString("%0 (%1)").arg(tr("Audio Files"), Mpv::audio_filetypes.join(" ")), - 0, QFileDialog::DontUseSheet); + 0); } else trackFile = args.join(' '); @@ -389,7 +388,7 @@ void BakaEngine::Open() QString("%0 (%1);;").arg(tr("Video Files"), Mpv::video_filetypes.join(" "))+ QString("%0 (%1);;").arg(tr("Audio Files"), Mpv::audio_filetypes.join(" "))+ QString("%0 (*.*)").arg(tr("All Files")), - 0, QFileDialog::DontUseSheet)); + 0)); } @@ -433,7 +432,7 @@ void BakaEngine::FitWindow(int percent, bool msg) QRect mG = window->ui->mpvFrame->geometry(), // mpv geometry wfG = window->frameGeometry(), // frame geometry of window (window geometry + window frame) wG = window->geometry(), // window geometry - aG = qApp->desktop()->availableGeometry(wfG.center()); // available geometry of the screen we're in--(geometry not including the taskbar) + aG = qApp->screenAt(wfG.center())->availableGeometry(); // available geometry of the screen we're in--(geometry not including the taskbar) double a, // aspect ratio w, // width of vid we want diff --git a/src/bakaengine.cpp b/src/bakaengine.cpp index a1fc18ed..1ded1664 100644 --- a/src/bakaengine.cpp +++ b/src/bakaengine.cpp @@ -37,12 +37,12 @@ BakaEngine::BakaEngine(QObject *parent): } connect(mpv, &MpvHandler::messageSignal, - [=](QString msg) + mpv, [=](QString msg) { Print(msg, "mpv"); }); connect(update, &UpdateManager::messageSignal, - [=](QString msg) + update, [=](QString msg) { Print(msg, "update"); }); diff --git a/src/mpvhandler.cpp b/src/mpvhandler.cpp index 0a45237c..eb78cba9 100644 --- a/src/mpvhandler.cpp +++ b/src/mpvhandler.cpp @@ -617,7 +617,7 @@ void MpvHandler::AddSubtitleTrack(QString f) auto old = fileInfo.tracks; // save the current track-list LoadTracks(); // load the new track list auto current = fileInfo.tracks; - for(auto track : old) // remove the old tracks in current + for(auto &track : old) // remove the old tracks in current current.removeOne(track); Mpv::Track &track = current.first(); ShowText(QString("%0: %1 (%2)").arg(QString::number(track.id), track.title, track.external ? "external" : track.lang)); @@ -633,7 +633,7 @@ void MpvHandler::AddAudioTrack(QString f) auto old = fileInfo.tracks; LoadTracks(); auto current = fileInfo.tracks; - for(auto track : old) + for(auto &track : old) current.removeOne(track); Mpv::Track &track = current.first(); ShowText(QString("%0: %1 (%2)").arg(QString::number(track.id), track.title, track.external ? "external" : track.lang)); diff --git a/src/overlayhandler.cpp b/src/overlayhandler.cpp index 3ed0a189..ab1189f8 100644 --- a/src/overlayhandler.cpp +++ b/src/overlayhandler.cpp @@ -56,7 +56,7 @@ void OverlayHandler::showInfoText(bool show) refresh_timer = new QTimer(this); refresh_timer->setSingleShot(true); connect(refresh_timer, &QTimer::timeout, // on timeout - [=] { showInfoText(); }); + refresh_timer, [=] { showInfoText(); }); } refresh_timer->start(OVERLAY_REFRESH_RATE); showText(baka->mpv->getMediaInfo(), @@ -92,8 +92,8 @@ void OverlayHandler::showText(const QString &text, QFont font, QColor color, QPo const float fm_correction = 1.3; int w = 0, h = fm.height()*lines.length(); - for(auto line : lines) - w = std::max(fm.width(line), w); + for(auto &line : lines) + w = std::max(fm.horizontalAdvance(line), w); float xF = float(baka->window->ui->mpvFrame->width()-2*pos.x()) / (fm_correction*w); float yF = float(baka->window->ui->mpvFrame->height()-2*pos.y()) / h; font.setPointSizeF(std::min(font.pointSizeF()*std::min(xF, yF), font.pointSizeF())); @@ -103,7 +103,7 @@ void OverlayHandler::showText(const QString &text, QFont font, QColor color, QPo w = 0; QPainterPath path(QPoint(0, 0)); QPoint p = QPoint(0, h); - for(auto line : lines) + for(auto &line : lines) { path.addText(p, font, line); w = std::max(int(fm_correction*path.currentPosition().x()), w); @@ -143,10 +143,9 @@ void OverlayHandler::showText(const QString &text, QFont font, QColor color, QPo timer = nullptr; else { - timer = new QTimer(this); timer->start(duration); connect(timer, &QTimer::timeout, // on timeout - [=] { remove(id); }); + timer, [=] { remove(id); }); } if(overlays.find(id) != overlays.end()) diff --git a/src/overlayhandler.h b/src/overlayhandler.h index df5ec51d..4ab93416 100644 --- a/src/overlayhandler.h +++ b/src/overlayhandler.h @@ -3,12 +3,10 @@ #include #include -#include #include #include #include #include -#include #include class BakaEngine; diff --git a/src/settings.cpp b/src/settings.cpp index 18dbde6a..c12ada6c 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -94,7 +94,7 @@ void Settings::LoadIni() { QStringList recent = SplitQStringList(root["recent"].toString()); QJsonArray R; - for(auto str : recent) + for(auto &str : recent) { QJsonObject r; r["path"] = str; diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 34074f8b..d91bb7b9 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -13,7 +13,6 @@ #include "util.h" #include "widgets/dimdialog.h" #include "inputdialog.h" -#include "screenshotdialog.h" MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), @@ -104,7 +103,7 @@ MainWindow::MainWindow(QWidget *parent): { const QString cmd = action.key(); connect(*action, &QAction::triggered, - [=] { baka->Command(cmd); }); + this, [=] { baka->Command(cmd); }); } // setup signals & slots @@ -207,7 +206,7 @@ MainWindow::MainWindow(QWidget *parent): }); connect(baka->sysTrayIcon, &QSystemTrayIcon::activated, - [=](QSystemTrayIcon::ActivationReason reason) + baka->sysTrayIcon, [=](QSystemTrayIcon::ActivationReason reason) { if(reason == QSystemTrayIcon::Trigger) { @@ -229,7 +228,7 @@ MainWindow::MainWindow(QWidget *parent): // }); connect(autohide, &QTimer::timeout, // cursor autohide - [=] + autohide, [=] { if(ui->mpvFrame->geometry().contains(ui->mpvFrame->mapFromGlobal(cursor().pos()))) setCursor(QCursor(Qt::BlankCursor)); @@ -239,7 +238,7 @@ MainWindow::MainWindow(QWidget *parent): // dimDialog connect(baka->dimDialog, &DimDialog::visbilityChanged, - [=](bool dim) + baka->dimDialog, [=](bool dim) { ui->action_Dim_Lights->setChecked(dim); if(dim) @@ -251,7 +250,7 @@ MainWindow::MainWindow(QWidget *parent): // mpv connect(mpv, &MpvHandler::playlistChanged, - [=](const QStringList &list) + mpv, [=](const QStringList &list) { if(list.length() > 1) { @@ -272,7 +271,7 @@ MainWindow::MainWindow(QWidget *parent): }); connect(mpv, &MpvHandler::fileInfoChanged, - [=](const Mpv::FileInfo &fileInfo) + mpv, [=](const Mpv::FileInfo &fileInfo) { if(mpv->getPlayState() > 0) { @@ -324,7 +323,7 @@ MainWindow::MainWindow(QWidget *parent): }); connect(mpv, &MpvHandler::trackListChanged, - [=](const QList &trackList) + mpv, [=](const QList &trackList) { if(mpv->getPlayState() > 0) { @@ -454,7 +453,7 @@ MainWindow::MainWindow(QWidget *parent): }); connect(mpv, &MpvHandler::chaptersChanged, - [=](const QList &chapters) + mpv, [=](const QList &chapters) { if(mpv->getPlayState() > 0) { @@ -494,7 +493,7 @@ MainWindow::MainWindow(QWidget *parent): }); connect(mpv, &MpvHandler::playStateChanged, - [=](Mpv::PlayState playState) + mpv, [=](Mpv::PlayState playState) { switch(playState) { @@ -518,6 +517,7 @@ MainWindow::MainWindow(QWidget *parent): SetPlaybackControls(true); mpv->Play(); baka->overlay->showStatusText(QString(), 0); + [[fallthrough]]; case Mpv::Playing: SetPlayButtonIcon(false); if(onTop == "playing") @@ -563,13 +563,13 @@ MainWindow::MainWindow(QWidget *parent): }); connect(mpv, &MpvHandler::pathChanged, - [=]() + mpv, [=]() { pathChanged = true; }); connect(mpv, &MpvHandler::fileChanging, - [=](int t, int l) + mpv, [=](int t, int l) { if(current != nullptr) { @@ -586,7 +586,7 @@ MainWindow::MainWindow(QWidget *parent): // }); connect(mpv, &MpvHandler::timeChanged, - [=](int i) + mpv, [=](int i) { const Mpv::FileInfo &fi = mpv->getFileInfo(); // set the seekBar's location with NoSignal function so that it doesn't trigger a seek @@ -604,13 +604,13 @@ MainWindow::MainWindow(QWidget *parent): }); connect(mpv, &MpvHandler::volumeChanged, - [=](int volume) + mpv, [=](int volume) { ui->volumeSlider->setValueNoSignal(volume); }); connect(mpv, &MpvHandler::speedChanged, - [=](double speed) + mpv, [=](double speed) { static double last = 1; if(last != speed) @@ -626,7 +626,7 @@ MainWindow::MainWindow(QWidget *parent): }); connect(mpv, &MpvHandler::sidChanged, - [=](int sid) + mpv, [=](int sid) { QList actions = ui->menuSubtitle_Track->actions(); for(auto &action : actions) @@ -642,7 +642,7 @@ MainWindow::MainWindow(QWidget *parent): }); connect(mpv, &MpvHandler::aidChanged, - [=](int aid) + mpv, [=](int aid) { QList actions = ui->menuAudio_Tracks->actions(); for(auto &action : actions) @@ -658,7 +658,7 @@ MainWindow::MainWindow(QWidget *parent): }); connect(mpv, &MpvHandler::subtitleVisibilityChanged, - [=](bool b) + mpv, [=](bool b) { if(ui->actionShow_Subtitles->isEnabled()) ui->actionShow_Subtitles->setChecked(b); @@ -667,7 +667,7 @@ MainWindow::MainWindow(QWidget *parent): }); connect(mpv, &MpvHandler::muteChanged, - [=](bool b) + mpv, [=](bool b) { if(b) ui->muteButton->setIcon(QIcon(":/img/default_mute.svg")); @@ -677,80 +677,80 @@ MainWindow::MainWindow(QWidget *parent): }); connect(mpv, &MpvHandler::voChanged, - [=](QString vo) + mpv, [=](QString vo) { ui->action_Motion_Interpolation->setChecked(vo.contains("interpolation")); }); // ui connect(ui->seekBar, &SeekBar::valueChanged, // Playback: Seekbar clicked - [=](int i) + this, [=](int i) { mpv->Seek(mpv->Relative(((double)i/ui->seekBar->maximum())*mpv->getFileInfo().length), true); }); connect(ui->openButton, &OpenButton::LeftClick, // Playback: Open button (left click) - [=] + this, [=] { baka->Open(); }); connect(ui->openButton, &OpenButton::MiddleClick, // Playback: Open button (middle click) - [=] + this, [=] { baka->Jump(); }); connect(ui->openButton, &OpenButton::RightClick, // Playback: Open button (right click) - [=] + this, [=] { baka->OpenLocation(); }); connect(ui->rewindButton, &QPushButton::clicked, // Playback: Rewind button - [=] + this, [=] { mpv->Rewind(); }); connect(ui->previousButton, &IndexButton::clicked, // Playback: Previous button - [=] + this, [=] { ui->playlistWidget->PlayIndex(-1, true); }); connect(ui->playButton, &QPushButton::clicked, // Playback: Play/pause button - [=] + this, [=] { baka->PlayPause(); }); connect(ui->nextButton, &IndexButton::clicked, // Playback: Next button - [=] + this, [=] { ui->playlistWidget->PlayIndex(1, true); }); connect(ui->muteButton, &QPushButton::clicked, - [=] + this, [=] { mpv->Mute(!mpv->getMute()); }); connect(ui->volumeSlider, &CustomSlider::valueChanged, // Playback: Volume slider adjusted - [=](int i) + this, [=](int i) { mpv->Volume(i, true); }); connect(ui->playlistButton, &QPushButton::clicked, // Playback: Clicked the playlist button - [=] + this, [=] { TogglePlaylist(); }); connect(ui->splitter, &CustomSplitter::positionChanged, // Splitter position changed - [=](int i) + this, [=](int i) { blockSignals(true); if(i == 0) // right-most, playlist is hidden @@ -776,13 +776,13 @@ MainWindow::MainWindow(QWidget *parent): }); connect(ui->searchBox, &QLineEdit::textChanged, // Playlist: Search box - [=](QString s) + this, [=](QString s) { ui->playlistWidget->Search(s); }); connect(ui->indexLabel, &CustomLabel::clicked, // Playlist: Clicked the indexLabel - [=] + this, [=] { QString res = InputDialog::getInput(tr("Enter the file number you want to play:\nNote: Value must be from %0 - %1").arg("1", QString::number(ui->playlistWidget->count())), tr("Enter File Number"), @@ -799,25 +799,25 @@ MainWindow::MainWindow(QWidget *parent): }); connect(ui->playlistWidget, &PlaylistWidget::currentRowChanged, // Playlist: Playlist selection changed - [=](int) + this, [=](int) { SetIndexLabels(true); }); connect(ui->currentFileButton, &QPushButton::clicked, // Playlist: Select current file button - [=] + this, [=] { ui->playlistWidget->SelectIndex(ui->playlistWidget->CurrentIndex()); }); connect(ui->refreshButton, &QPushButton::clicked, // Playlist: Refresh playlist button - [=] + this, [=] { ui->playlistWidget->RefreshPlaylist(); }); connect(ui->inputLineEdit, &CustomLineEdit::submitted, - [=](QString s) + this, [=](QString s) { baka->Command(s); ui->inputLineEdit->setText(""); @@ -1036,7 +1036,7 @@ bool MainWindow::eventFilter(QObject *obj, QEvent *event) void MainWindow::wheelEvent(QWheelEvent *event) { - if(event->delta() > 0) + if(event->angleDelta().y() > 0) mpv->Volume(mpv->getVolume()+5, true); else mpv->Volume(mpv->getVolume()-5, true); @@ -1251,7 +1251,7 @@ void MainWindow::UpdateRecentFiles() if(n++ == 1) action->setShortcut(QKeySequence("Ctrl+Z")); connect(action, &QAction::triggered, - [=] + action, [=] { mpv->LoadFile(f); }); diff --git a/src/ui/preferencesdialog.cpp b/src/ui/preferencesdialog.cpp index e3f06cd1..0c1e5757 100644 --- a/src/ui/preferencesdialog.cpp +++ b/src/ui/preferencesdialog.cpp @@ -53,13 +53,13 @@ PreferencesDialog::PreferencesDialog(BakaEngine *baka, QWidget *parent) : PopulateShortcuts(); connect(ui->autoFitCheckBox, &QCheckBox::clicked, - [=](bool b) + this, [=](bool b) { ui->comboBox->setEnabled(b); }); connect(ui->changeButton, &QPushButton::clicked, - [=] + this, [=] { QString dir = QFileDialog::getExistingDirectory(this, tr("Choose screenshot directory"), screenshotDir); if(dir != QString()) @@ -67,13 +67,13 @@ PreferencesDialog::PreferencesDialog(BakaEngine *baka, QWidget *parent) : }); connect(ui->addKeyButton, &QPushButton::clicked, - [=] + this, [=] { SelectKey(true); }); connect(ui->editKeyButton, &QPushButton::clicked, - [=] + this, [=] { int i = ui->infoWidget->currentRow(); if(i == -1) @@ -86,7 +86,7 @@ PreferencesDialog::PreferencesDialog(BakaEngine *baka, QWidget *parent) : }); connect(ui->resetKeyButton, &QPushButton::clicked, - [=] + this, [=] { if(QMessageBox::question(this, tr("Reset All Key Bindings?"), tr("Are you sure you want to reset all shortcut keys to its original bindings?")) == QMessageBox::Yes) { @@ -98,7 +98,7 @@ PreferencesDialog::PreferencesDialog(BakaEngine *baka, QWidget *parent) : }); connect(ui->removeKeyButton, &QPushButton::clicked, - [=] + this, [=] { int row = ui->infoWidget->currentRow(); if(row == -1) @@ -109,14 +109,14 @@ PreferencesDialog::PreferencesDialog(BakaEngine *baka, QWidget *parent) : }); connect(ui->infoWidget, &QTableWidget::currentCellChanged, - [=](int r,int,int,int) + this, [=](int r,int,int,int) { ui->editKeyButton->setEnabled(r != -1); ui->removeKeyButton->setEnabled(r != -1); }); connect(ui->infoWidget, &QTableWidget::doubleClicked, - [=](const QModelIndex &index) + this, [=](const QModelIndex &index) { int i = index.row(); SelectKey(false, diff --git a/src/ui/screenshotdialog.cpp b/src/ui/screenshotdialog.cpp index 7ef09991..ca5def03 100644 --- a/src/ui/screenshotdialog.cpp +++ b/src/ui/screenshotdialog.cpp @@ -21,7 +21,7 @@ ScreenshotDialog::ScreenshotDialog(bool &_always, bool &_screenshot, MpvHandler ui->templateEdit->setText(mpv->getScreenshotTemplate()); connect(ui->browseButton, &QPushButton::clicked, - [=] + this, [=] { QString dir = QFileDialog::getExistingDirectory(this, tr("Choose screenshot directory"), ui->locationEdit->text()); if(dir != QString()) @@ -29,7 +29,7 @@ ScreenshotDialog::ScreenshotDialog(bool &_always, bool &_screenshot, MpvHandler }); connect(ui->saveButton, &QPushButton::clicked, - [=] + this, [=] { mpv->ScreenshotFormat(ui->formatComboBox->currentText()); mpv->ScreenshotDirectory(QDir::fromNativeSeparators(ui->locationEdit->text())); diff --git a/src/ui/updatedialog.cpp b/src/ui/updatedialog.cpp index 150d33a2..7ae589d8 100644 --- a/src/ui/updatedialog.cpp +++ b/src/ui/updatedialog.cpp @@ -3,7 +3,6 @@ #include "bakaengine.h" #include "updatemanager.h" -#include "util.h" #include @@ -24,7 +23,7 @@ UpdateDialog::UpdateDialog(BakaEngine *baka, QWidget *parent) : #endif connect(baka->update, &UpdateManager::progressSignal, - [=](int percent) + this, [=](int percent) { ui->progressBar->setValue(percent); if(percent == 100) @@ -78,14 +77,14 @@ UpdateDialog::UpdateDialog(BakaEngine *baka, QWidget *parent) : }); connect(baka->update, &UpdateManager::messageSignal, - [=](QString msg) + this, [=](QString msg) { ui->plainTextEdit->appendPlainText(msg+"\n"); }); #if defined(Q_OS_WIN) connect(ui->updateButton, &QPushButton::clicked, - [=] + this, [=] { ui->plainTextEdit->setPlainText(QString()); baka->update->DownloadUpdate(Util::DownloadFileUrl()); diff --git a/src/updatemanager.cpp b/src/updatemanager.cpp index 9cee91cd..bd0ab8cd 100644 --- a/src/updatemanager.cpp +++ b/src/updatemanager.cpp @@ -43,13 +43,13 @@ bool UpdateManager::CheckForUpdates() QNetworkReply *reply = manager->get(request); connect(reply, &QNetworkReply::downloadProgress, - [=](qint64 received, qint64 total) + reply, [=](qint64 received, qint64 total) { emit progressSignal((int)(50.0*received/total)); }); connect(reply, &QNetworkReply::finished, - [=] + reply, [=] { if(reply->error()) emit messageSignal(reply->errorString()); @@ -61,7 +61,7 @@ bool UpdateManager::CheckForUpdates() // go through the next 50% incrementally during parsing double amnt = 50.0/lines.length(), cur = 50+amnt; - for(auto line : lines) + for(auto &line : lines) { if((pair = line.split('=')).size() != 2) info[lastPair].append(line); @@ -99,13 +99,13 @@ bool UpdateManager::DownloadUpdate(const QString &url) QNetworkReply *reply = manager->get(request); connect(reply, &QNetworkReply::downloadProgress, - [=](qint64 received, qint64 total) + reply, [=](qint64 received, qint64 total) { emit progressSignal((int)(99.0*received/total)); }); connect(reply, &QNetworkReply::readyRead, - [=] + reply, [=] { if(reply->error()) emit messageSignal(reply->errorString()); @@ -114,7 +114,7 @@ bool UpdateManager::DownloadUpdate(const QString &url) }); connect(reply, &QNetworkReply::finished, - [=] + reply, [=] { if(reply->error()) { @@ -205,7 +205,7 @@ void UpdateManager::ApplyUpdate(const QString &file) exe).toUtf8()); f.close(); - QProcess::startDetached(bat); + QProcess::startDetached(bat, QStringList()); emit messageSignal(tr("Done. Restarting...")); baka->Quit(); } diff --git a/src/util.cpp b/src/util.cpp index 21336107..342b8967 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -128,7 +128,7 @@ QString ShortenPathToParent(const Recent &recent) QStringList ToNativeSeparators(QStringList list) { QStringList ret; - for(auto element : list) + for(auto &element : list) { if(Util::IsValidLocation(element)) ret.push_back(element); @@ -141,7 +141,7 @@ QStringList ToNativeSeparators(QStringList list) QStringList FromNativeSeparators(QStringList list) { QStringList ret; - for(auto element : list) + for(auto &element : list) ret.push_back(QDir::fromNativeSeparators(element)); return ret; } diff --git a/src/widgets/customsplitter.cpp b/src/widgets/customsplitter.cpp index 982bd30b..e2917385 100644 --- a/src/widgets/customsplitter.cpp +++ b/src/widgets/customsplitter.cpp @@ -15,7 +15,7 @@ CustomSplitter::CustomSplitter(QWidget *parent) : int CustomSplitter::position() const { - return sizes()[1]; + return sizes().at(1); } int CustomSplitter::normalPosition() const diff --git a/src/widgets/dimdialog.cpp b/src/widgets/dimdialog.cpp index 75227dd4..0905748d 100644 --- a/src/widgets/dimdialog.cpp +++ b/src/widgets/dimdialog.cpp @@ -1,12 +1,10 @@ #include "dimdialog.h" #include "ui/mainwindow.h" -#include "ui_mainwindow.h" -#include "util.h" #include #include -#include +#include DimDialog::DimDialog(MainWindow *window, QWidget *parent) : QDialog(parent), @@ -17,7 +15,7 @@ DimDialog::DimDialog(MainWindow *window, QWidget *parent) : setStyleSheet("background-color: black;"); connect(qApp, &QApplication::focusWindowChanged, - [=](QWindow *focusWindow) + this, [=](QWindow *focusWindow) { // note: focusWindow will be nullptr if anything is clicked outside of our program which is useful // the only other problem is that when dragging by the top handle @@ -38,7 +36,7 @@ DimDialog::DimDialog(MainWindow *window, QWidget *parent) : void DimDialog::show() { // set the geometry in the show so that we can fill the desktop (even on another monitor) - setGeometry(qApp->desktop()->screenGeometry(window->frameGeometry().center())); + setGeometry(qApp->screenAt(window->frameGeometry().center())->geometry()); emit visbilityChanged(true); QDialog::show(); } diff --git a/src/widgets/playlistwidget.cpp b/src/widgets/playlistwidget.cpp index 27f34280..25cadcbd 100644 --- a/src/widgets/playlistwidget.cpp +++ b/src/widgets/playlistwidget.cpp @@ -7,8 +7,11 @@ #include #include #include +#include -#include // for std::random_shuffle and std::sort +// for std::shuffle and std::sort +#include +#include PlaylistWidget::PlaylistWidget(QWidget *parent) : QListWidget(parent), @@ -23,7 +26,7 @@ void PlaylistWidget::AttachEngine(BakaEngine *baka) { this->baka = baka; connect(baka->mpv, &MpvHandler::playlistChanged, - [=](const QStringList &list) + this, [=](const QStringList &list) { playlist = list; newPlaylist = true; @@ -36,7 +39,7 @@ void PlaylistWidget::AttachEngine(BakaEngine *baka) }); connect(baka->mpv, &MpvHandler::fileChanged, - [=](QString f) + this, [=](QString f) { if(newPlaylist) { @@ -242,7 +245,9 @@ void PlaylistWidget::Shuffle() for(int i = 0; i < count(); ++i) newPlaylist.append(this->item(i)->text()); - std::random_shuffle(newPlaylist.begin(), newPlaylist.end()); + std::random_device rd; + std::mt19937 g(rd()); + std::shuffle(newPlaylist.begin(), newPlaylist.end(), g); // make current playing item the first auto iter = std::find(newPlaylist.begin(), newPlaylist.end(), file); std::swap(*iter, *newPlaylist.begin()); @@ -282,7 +287,7 @@ void PlaylistWidget::DeleteFromDisk(QListWidgetItem *item) playlist.removeOne(item->text()); QString r = item->text().left(item->text().lastIndexOf('.')+1); // get file root (no extension) // check and remove all subtitle_files with the same root as the video - for(auto ext : Mpv::subtitle_filetypes) + for(auto &ext : Mpv::subtitle_filetypes) { QFile subf(r+ext.mid(2)); if(subf.exists() && @@ -294,7 +299,7 @@ void PlaylistWidget::DeleteFromDisk(QListWidgetItem *item) subf.remove(); } // check and remove all external subtitle files in the video - for(auto track : baka->mpv->getFileInfo().tracks) + for(auto &track : baka->mpv->getFileInfo().tracks) { if(track.external) { @@ -320,24 +325,26 @@ void PlaylistWidget::contextMenuEvent(QContextMenuEvent *event) QListWidgetItem *item = itemAt(event->pos()); if(item != nullptr) { - QMenu *menu = new QMenu(); - connect(menu->addAction(tr("R&emove from Playlist")), &QAction::triggered, // Playlist: Remove from playlist (right-click) - [=] + QScopedPointer menu(new QMenu()); + QAction *removeFromPlaylist = menu->addAction(tr("R&emove from Playlist")); + connect(removeFromPlaylist, &QAction::triggered, // Playlist: Remove from playlist (right-click) + removeFromPlaylist, [=] { RemoveFromPlaylist(item); }); - connect(menu->addAction(tr("&Delete from Disk")), &QAction::triggered, // Playlist: Delete from Disk (right-click) - [=] + QAction *deleteFromDisk = menu->addAction(tr("&Delete from Disk")); + connect(deleteFromDisk, &QAction::triggered, // Playlist: Delete from Disk (right-click) + deleteFromDisk, [=] { DeleteFromDisk(item); }); - connect(menu->addAction(tr("&Refresh")), &QAction::triggered, // Playlist: Refresh (right-click) - [=] + QAction *refresh = menu->addAction(tr("&Refresh")); + connect(refresh, &QAction::triggered, // Playlist: Refresh (right-click) + refresh, [=] { RefreshPlaylist(); }); menu->exec(viewport()->mapToGlobal(event->pos())); - delete menu; } } From a47bd413e18d182e5714f5085ad2951c4384321b Mon Sep 17 00:00:00 2001 From: Daniel Clarke Date: Sat, 21 Jan 2023 12:04:07 -0500 Subject: [PATCH 08/19] Move most timers to stack from heap --- src/gesturehandler.cpp | 22 +++++++--------------- src/gesturehandler.h | 2 +- src/overlayhandler.cpp | 18 ++++++------------ src/overlayhandler.h | 3 ++- src/ui/mainwindow.cpp | 19 +++++++++---------- src/ui/mainwindow.h | 2 +- src/ui/updatedialog.cpp | 19 +++++-------------- src/ui/updatedialog.h | 2 +- 8 files changed, 32 insertions(+), 55 deletions(-) diff --git a/src/gesturehandler.cpp b/src/gesturehandler.cpp index 23284426..86100e3d 100644 --- a/src/gesturehandler.cpp +++ b/src/gesturehandler.cpp @@ -6,12 +6,11 @@ #include "bakaengine.h" #include "ui/mainwindow.h" #include "mpvhandler.h" -#include "util.h" GestureHandler::GestureHandler(QObject *parent): QObject(parent), baka(static_cast(parent)), - elapsedTimer(nullptr) + elapsedTimer() { timer_threshold = 10; // 10ms works quite well gesture_threshold = 15; // 15 pixels is probably fine for anything @@ -19,19 +18,13 @@ GestureHandler::GestureHandler(QObject *parent): GestureHandler::~GestureHandler() { - if(elapsedTimer) - { - delete elapsedTimer; - elapsedTimer = nullptr; - } } bool GestureHandler::Begin(int gesture_type, QPoint mousePos, QPoint windowPos) { - if(!elapsedTimer) + if(!elapsedTimer.isValid()) { - elapsedTimer = new QElapsedTimer(); - elapsedTimer->start(); + elapsedTimer.start(); this->gesture_type = gesture_type; this->gesture_state = NONE; // calculate pixel ratios based on physical dpi @@ -55,7 +48,7 @@ bool GestureHandler::Begin(int gesture_type, QPoint mousePos, QPoint windowPos) bool GestureHandler::Process(QPoint mousePos) { - if(elapsedTimer && elapsedTimer->elapsed() > timer_threshold) // 10ms seems pretty good for all purposes + if(elapsedTimer.isValid() && elapsedTimer.hasExpired(timer_threshold)) // 10ms seems pretty good for all purposes { QPoint delta = mousePos - start.mousePos; @@ -83,7 +76,7 @@ bool GestureHandler::Process(QPoint mousePos) } } - elapsedTimer->restart(); + elapsedTimer.restart(); return true; } else @@ -92,10 +85,9 @@ bool GestureHandler::Process(QPoint mousePos) bool GestureHandler::End() { - if(elapsedTimer) + if(elapsedTimer.isValid()) { - delete elapsedTimer; - elapsedTimer = nullptr; + elapsedTimer.invalidate(); QApplication::restoreOverrideCursor(); } else diff --git a/src/gesturehandler.h b/src/gesturehandler.h index 9b121ef7..a3015874 100644 --- a/src/gesturehandler.h +++ b/src/gesturehandler.h @@ -33,7 +33,7 @@ public slots: private: BakaEngine *baka; - QElapsedTimer *elapsedTimer; + QElapsedTimer elapsedTimer; double hRatio, vRatio; diff --git a/src/overlayhandler.cpp b/src/overlayhandler.cpp index ab1189f8..c3fbfd1d 100644 --- a/src/overlayhandler.cpp +++ b/src/overlayhandler.cpp @@ -12,7 +12,6 @@ #include #include #include -#include #include #include @@ -23,11 +22,14 @@ OverlayHandler::OverlayHandler(QObject *parent): QObject(parent), baka(static_cast(parent)), - refresh_timer(nullptr), + refresh_timer(this), min_overlay(1), max_overlay(60), overlay_id(min_overlay) { + refresh_timer.setSingleShot(true); + connect(&refresh_timer, &QTimer::timeout, // on timeout + this, [=] { showInfoText(); }); } OverlayHandler::~OverlayHandler() @@ -51,14 +53,7 @@ void OverlayHandler::showInfoText(bool show) { if(show) // show media info { - if(refresh_timer == nullptr) - { - refresh_timer = new QTimer(this); - refresh_timer->setSingleShot(true); - connect(refresh_timer, &QTimer::timeout, // on timeout - refresh_timer, [=] { showInfoText(); }); - } - refresh_timer->start(OVERLAY_REFRESH_RATE); + refresh_timer.start(OVERLAY_REFRESH_RATE); showText(baka->mpv->getMediaInfo(), QFont(Util::MonospaceFont(), 14, QFont::Bold), QColor(0xFFFF00), @@ -66,8 +61,7 @@ void OverlayHandler::showInfoText(bool show) } else // hide media info { - delete refresh_timer; - refresh_timer = nullptr; + refresh_timer.stop(); remove(OVERLAY_INFO); } } diff --git a/src/overlayhandler.h b/src/overlayhandler.h index 4ab93416..e4ce6d28 100644 --- a/src/overlayhandler.h +++ b/src/overlayhandler.h @@ -8,6 +8,7 @@ #include #include #include +#include class BakaEngine; class Overlay; @@ -33,7 +34,7 @@ protected slots: QHash overlays; QMutex overlay_mutex; - QTimer *refresh_timer; + QTimer refresh_timer; int min_overlay, max_overlay, overlay_id; diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index d91bb7b9..a8c9c894 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -16,7 +16,8 @@ MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), - ui(new Ui::MainWindow) + ui(new Ui::MainWindow), + autohide(this) { ui->setupUi(this); #if defined(Q_OS_UNIX) || defined(Q_OS_LINUX) @@ -29,11 +30,11 @@ MainWindow::MainWindow(QWidget *parent): // initialize managers/handlers baka = new BakaEngine(this); mpv = baka->mpv; + autohide.setSingleShot(true); ui->playlistWidget->AttachEngine(baka); ui->mpvFrame->installEventFilter(this); // capture events on mpvFrame in the eventFilter function ui->mpvFrame->setMouseTracking(true); - autohide = new QTimer(this); // command action mappings (action (right) performs command (left)) commandActionMap = { @@ -227,13 +228,11 @@ MainWindow::MainWindow(QWidget *parent): // { // }); - connect(autohide, &QTimer::timeout, // cursor autohide - autohide, [=] + connect(&autohide, &QTimer::timeout, // cursor autohide + this, [=] { if(ui->mpvFrame->geometry().contains(ui->mpvFrame->mapFromGlobal(cursor().pos()))) setCursor(QCursor(Qt::BlankCursor)); - if(autohide) - autohide->stop(); }); // dimDialog @@ -992,7 +991,7 @@ void MainWindow::mouseMoveEvent(QMouseEvent *event) else if(isFullScreenMode()) { setCursor(QCursor(Qt::ArrowCursor)); // show the cursor - autohide->stop(); + autohide.stop(); QRect playbackRect = geometry(); playbackRect.setTop(playbackRect.bottom() - 60); @@ -1005,8 +1004,8 @@ void MainWindow::mouseMoveEvent(QMouseEvent *event) bool showPlaylist = playlistRect.contains(event->globalPos()); ShowPlaylist(showPlaylist); - if(!(showPlayback || showPlaylist) && autohide) - autohide->start(500); + if(!(showPlayback || showPlaylist)) + autohide.start(500); } QMainWindow::mouseMoveEvent(event); } @@ -1177,7 +1176,7 @@ void MainWindow::HideAllControls(bool w, bool s) setContextMenuPolicy(Qt::NoContextMenu); } setCursor(QCursor(Qt::ArrowCursor)); // show cursor - autohide->stop(); + autohide.stop(); ShowPlaylist(playlistState); } } diff --git a/src/ui/mainwindow.h b/src/ui/mainwindow.h index 6d0f8b19..47b90037 100644 --- a/src/ui/mainwindow.h +++ b/src/ui/mainwindow.h @@ -99,7 +99,7 @@ private slots: firstItem = false, init = false, playlistState = false; - QTimer *autohide = nullptr; + QTimer autohide; // variables QList recent; diff --git a/src/ui/updatedialog.cpp b/src/ui/updatedialog.cpp index 7ae589d8..6d576d9d 100644 --- a/src/ui/updatedialog.cpp +++ b/src/ui/updatedialog.cpp @@ -10,7 +10,7 @@ UpdateDialog::UpdateDialog(BakaEngine *baka, QWidget *parent) : QDialog(parent), ui(new Ui::UpdateDialog), baka(baka), - timer(nullptr), + timer(), init(false) { ui->setupUi(this); @@ -31,11 +31,7 @@ UpdateDialog::UpdateDialog(BakaEngine *baka, QWidget *parent) : ui->updateLabel->setText(tr("Download Complete")); ui->progressBar->setVisible(false); ui->timeRemainingLabel->setVisible(false); - if(timer != nullptr) - { - delete timer; - timer = nullptr; - } + timer.invalidate(); if(!init) { @@ -53,12 +49,9 @@ UpdateDialog::UpdateDialog(BakaEngine *baka, QWidget *parent) : ui->progressBar->setVisible(true); ui->timeRemainingLabel->setText(QString()); ui->timeRemainingLabel->setVisible(true); - if(timer != nullptr) - delete timer; - timer = new QElapsedTimer(); - timer->start(); + timer.start(); } - else if(timer) // don't execute this if timer is not defined--this shouldn't happen though.. but it does + else if(timer.isValid()) { avgSpeed = 0.005*lastSpeed + 0.995*avgSpeed; @@ -67,7 +60,7 @@ UpdateDialog::UpdateDialog(BakaEngine *baka, QWidget *parent) : else ui->timeRemainingLabel->setText(tr("Calculating...")); - int time = timer->elapsed(); + int time = timer.elapsed(); if(time != lastTime) // prevent cases when we're too fast haha lastSpeed = (percent-lastProgress)/(time-lastTime); @@ -105,8 +98,6 @@ UpdateDialog::UpdateDialog(BakaEngine *baka, QWidget *parent) : UpdateDialog::~UpdateDialog() { - if(timer != nullptr) - delete timer; delete ui; } diff --git a/src/ui/updatedialog.h b/src/ui/updatedialog.h index 65002c43..24f5caf1 100644 --- a/src/ui/updatedialog.h +++ b/src/ui/updatedialog.h @@ -27,7 +27,7 @@ protected slots: Ui::UpdateDialog *ui; BakaEngine *baka; - QElapsedTimer *timer; + QElapsedTimer timer; double avgSpeed = 1, lastSpeed = 0; int lastProgress, From 127e0b9bed5ae07d25d3dd1075d6f836c941f687 Mon Sep 17 00:00:00 2001 From: Daniel Clarke Date: Sat, 21 Jan 2023 17:16:02 -0500 Subject: [PATCH 09/19] Replace loose pointers with smart pointers --- src/bakaengine.cpp | 17 +-------- src/bakaengine.h | 6 +-- src/gesturehandler.cpp | 4 -- src/gesturehandler.h | 1 - src/mpvhandler.h | 2 +- src/overlay.cpp | 19 ++------- src/overlay.h | 17 +++------ src/overlayhandler.cpp | 61 +++++++++++------------------ src/overlayhandler.h | 4 +- src/settings.cpp | 4 -- src/settings.h | 4 -- src/ui/aboutdialog.cpp | 5 +-- src/ui/aboutdialog.h | 3 +- src/ui/inputdialog.cpp | 5 +-- src/ui/inputdialog.h | 5 ++- src/ui/jumpdialog.cpp | 5 +-- src/ui/jumpdialog.h | 3 +- src/ui/keydialog.cpp | 5 +-- src/ui/keydialog.h | 3 +- src/ui/locationdialog.cpp | 5 +-- src/ui/locationdialog.h | 3 +- src/ui/mainwindow.cpp | 74 +++++++++++++++--------------------- src/ui/mainwindow.h | 9 +++-- src/ui/preferencesdialog.cpp | 5 +-- src/ui/preferencesdialog.h | 7 +++- src/ui/screenshotdialog.cpp | 5 +-- src/ui/screenshotdialog.h | 2 +- src/ui/updatedialog.cpp | 10 ++--- src/ui/updatedialog.h | 4 +- src/updatemanager.cpp | 14 ++----- src/updatemanager.h | 1 - src/versions/2_0_3.cpp | 12 +++--- src/widgets/dimdialog.cpp | 4 +- src/widgets/dimdialog.h | 2 +- 34 files changed, 120 insertions(+), 210 deletions(-) diff --git a/src/bakaengine.cpp b/src/bakaengine.cpp index 1ded1664..e705be40 100644 --- a/src/bakaengine.cpp +++ b/src/bakaengine.cpp @@ -29,7 +29,7 @@ BakaEngine::BakaEngine(QObject *parent): qtTranslator(nullptr) { if(Util::DimLightsSupported()) - dimDialog = new DimDialog(window, nullptr); + dimDialog = new DimDialog(window); else { dimDialog = nullptr; @@ -48,21 +48,6 @@ BakaEngine::BakaEngine(QObject *parent): }); } -BakaEngine::~BakaEngine() -{ - if(translator != nullptr) - delete translator; - if(qtTranslator != nullptr) - delete qtTranslator; - if(dimDialog != nullptr) - delete dimDialog; - delete update; - delete overlay; - delete gesture; - delete settings; - delete mpv; -} - void BakaEngine::LoadSettings() { settings->Load(); diff --git a/src/bakaengine.h b/src/bakaengine.h index fefad778..f064b7d6 100644 --- a/src/bakaengine.h +++ b/src/bakaengine.h @@ -8,6 +8,7 @@ #include #include #include +#include class MainWindow; class MpvHandler; @@ -22,7 +23,6 @@ class BakaEngine : public QObject Q_OBJECT public: explicit BakaEngine(QObject *parent = 0); - ~BakaEngine(); MainWindow *window; MpvHandler *mpv; @@ -35,8 +35,8 @@ class BakaEngine : public QObject QSystemTrayIcon *sysTrayIcon; QMenu *trayIconMenu; - QTranslator *translator, - *qtTranslator; + QScopedPointer translator, + qtTranslator; // input hash-table provides O(1) input-command lookups QHash> input; // [shortcut] = QPair diff --git a/src/gesturehandler.cpp b/src/gesturehandler.cpp index 86100e3d..2be23c3f 100644 --- a/src/gesturehandler.cpp +++ b/src/gesturehandler.cpp @@ -16,10 +16,6 @@ GestureHandler::GestureHandler(QObject *parent): gesture_threshold = 15; // 15 pixels is probably fine for anything } -GestureHandler::~GestureHandler() -{ -} - bool GestureHandler::Begin(int gesture_type, QPoint mousePos, QPoint windowPos) { if(!elapsedTimer.isValid()) diff --git a/src/gesturehandler.h b/src/gesturehandler.h index a3015874..438f906c 100644 --- a/src/gesturehandler.h +++ b/src/gesturehandler.h @@ -23,7 +23,6 @@ class GestureHandler : public QObject }; explicit GestureHandler(QObject *parent = 0); - ~GestureHandler(); public slots: bool Begin(int gesture_type, QPoint mousePos, QPoint windowPos); diff --git a/src/mpvhandler.h b/src/mpvhandler.h index 3f2c3971..6d66ab27 100644 --- a/src/mpvhandler.h +++ b/src/mpvhandler.h @@ -174,7 +174,7 @@ private slots: private: BakaEngine *baka; - mpv_handle *mpv = nullptr; + mpv_handle *mpv; // variables Mpv::PlayState playState = Mpv::Idle; diff --git a/src/overlay.cpp b/src/overlay.cpp index 1599263c..e1ca332c 100644 --- a/src/overlay.cpp +++ b/src/overlay.cpp @@ -1,17 +1,6 @@ #include "overlay.h" -Overlay::Overlay(QLabel *label, QImage *canvas, QTimer *timer, QObject *parent): - QObject(parent) -{ - this->label = label; - this->canvas = canvas; - this->timer = timer; -} - -Overlay::~Overlay() -{ - delete label; - delete canvas; - if(timer != nullptr) - delete timer; -} +Overlay::Overlay(QScopedPointer &label, QScopedPointer &timer): + label(label.take()), + timer(timer.take()) +{} diff --git a/src/overlay.h b/src/overlay.h index affa6d3d..97c97327 100644 --- a/src/overlay.h +++ b/src/overlay.h @@ -1,22 +1,15 @@ #ifndef OVERLAY_H #define OVERLAY_H -#include #include -#include #include +#include -class Overlay : public QObject -{ - Q_OBJECT -public: - explicit Overlay(QLabel *label, QImage *canvas, QTimer *timer, QObject *parent = 0); - ~Overlay(); +struct Overlay { + Overlay(QScopedPointer &label, QScopedPointer &timer); -private: - QLabel *label; - QImage *canvas; - QTimer *timer; + QScopedPointer label; + QScopedPointer timer; }; #endif // OVERLAY_H diff --git a/src/overlayhandler.cpp b/src/overlayhandler.cpp index c3fbfd1d..a8324f69 100644 --- a/src/overlayhandler.cpp +++ b/src/overlayhandler.cpp @@ -32,12 +32,6 @@ OverlayHandler::OverlayHandler(QObject *parent): this, [=] { showInfoText(); }); } -OverlayHandler::~OverlayHandler() -{ - for(auto o : overlays) - delete o; -} - void OverlayHandler::showStatusText(const QString &text, int duration) { if(text != QString()) @@ -73,10 +67,7 @@ void OverlayHandler::showText(const QString &text, QFont font, QColor color, QPo if(id == -1) // auto id { id = overlay_id; - if(overlay_id+1 > max_overlay) - overlay_id = min_overlay; - else - ++overlay_id; + overlay_id = std::max(min_overlay, (overlay_id + 1) % max_overlay); } QFontMetrics fm(font); @@ -104,10 +95,10 @@ void OverlayHandler::showText(const QString &text, QFont font, QColor color, QPo p += QPoint(0, h); } - QImage *canvas = new QImage(w, p.y(), QImage::Format_ARGB32); // make the canvas the right size - canvas->fill(QColor(0,0,0,0)); // fill it with nothing + QImage canvas(w, p.y(), QImage::Format_ARGB32); // make the canvas the right size + canvas.fill(QColor(0,0,0,0)); // fill it with nothing - QPainter painter(canvas); // prepare to paint + QPainter painter(&canvas); // prepare to paint painter.setRenderHint(QPainter::Antialiasing); painter.setCompositionMode(QPainter::CompositionMode_Overlay); painter.setFont(font); @@ -115,47 +106,39 @@ void OverlayHandler::showText(const QString &text, QFont font, QColor color, QPo painter.setBrush(color); painter.drawPath(path); - // add as mpv overlay - baka->mpv->AddOverlay( - id == -1 ? overlay_id : id, - pos.x(), pos.y(), - "&"+QString::number(quintptr(canvas->bits())), - 0, canvas->width(), canvas->height()); // add over mpv as label - QLabel *label = new QLabel(baka->window->ui->mpvFrame); + QScopedPointer label(new QLabel(baka->window->ui->mpvFrame)); label->setStyleSheet("background-color:rgba(0,0,0,0);background-image:url();"); label->setGeometry(pos.x(), pos.y(), - canvas->width(), - canvas->height()); - label->setPixmap(QPixmap::fromImage(*canvas)); + canvas.width(), + canvas.height()); + label->setPixmap(QPixmap::fromImage(canvas)); label->show(); - QTimer *timer; - if(duration == 0) - timer = nullptr; - else + QScopedPointer timer(new QTimer); + if(duration > 0) { timer->start(duration); - connect(timer, &QTimer::timeout, // on timeout - timer, [=] { remove(id); }); + connect(timer.get(), &QTimer::timeout, // on timeout + timer.get(), [this, id] { remove(id); }); } - if(overlays.find(id) != overlays.end()) - delete overlays[id]; - overlays[id] = new Overlay(label, canvas, timer, this); + // add as mpv overlay + baka->mpv->AddOverlay( + id, + pos.x(), pos.y(), + "&"+QString::number(quintptr(canvas.bits())), + 0, canvas.width(), canvas.height()); + + overlays[id].reset(new Overlay(label, timer)); overlay_mutex.unlock(); } void OverlayHandler::remove(int id) { - overlay_mutex.lock(); - baka->mpv->RemoveOverlay(id); - if(overlays.find(id) != overlays.end()) - { - delete overlays[id]; - overlays.remove(id); + if (overlays.remove(id)) { + baka->mpv->RemoveOverlay(id); } - overlay_mutex.unlock(); } diff --git a/src/overlayhandler.h b/src/overlayhandler.h index e4ce6d28..db7dceec 100644 --- a/src/overlayhandler.h +++ b/src/overlayhandler.h @@ -9,6 +9,7 @@ #include #include #include +#include class BakaEngine; class Overlay; @@ -18,7 +19,6 @@ class OverlayHandler : public QObject Q_OBJECT public: explicit OverlayHandler(QObject *parent = 0); - ~OverlayHandler(); public slots: void showStatusText(const QString &text, int duration = 4000); @@ -31,7 +31,7 @@ protected slots: private: BakaEngine *baka; - QHash overlays; + QHash> overlays; QMutex overlay_mutex; QTimer refresh_timer; diff --git a/src/settings.cpp b/src/settings.cpp index c12ada6c..63faff19 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -9,10 +9,6 @@ Settings::Settings(QString file, QObject *parent): this->file = file; } -Settings::~Settings() -{ -} - void Settings::Load() { QFile f(file); diff --git a/src/settings.h b/src/settings.h index 19336463..80a04849 100644 --- a/src/settings.h +++ b/src/settings.h @@ -11,14 +11,11 @@ #include #include -class BakaEngine; - class Settings : public QObject { Q_OBJECT public: explicit Settings(QString file, QObject *parent = 0); - ~Settings(); public slots: void Load(); @@ -34,7 +31,6 @@ public slots: QStringList SplitQStringList(QString list); private: - BakaEngine *baka; QJsonDocument document; QString file; }; diff --git a/src/ui/aboutdialog.cpp b/src/ui/aboutdialog.cpp index ba245242..0f9de159 100644 --- a/src/ui/aboutdialog.cpp +++ b/src/ui/aboutdialog.cpp @@ -12,10 +12,7 @@ AboutDialog::AboutDialog(QString version, QWidget *parent) : this, SLOT(close())); } -AboutDialog::~AboutDialog() -{ - delete ui; -} +AboutDialog::~AboutDialog() {} void AboutDialog::about(QString version, QWidget *parent) { diff --git a/src/ui/aboutdialog.h b/src/ui/aboutdialog.h index 2a3ce245..cd356df6 100644 --- a/src/ui/aboutdialog.h +++ b/src/ui/aboutdialog.h @@ -3,6 +3,7 @@ #include #include +#include namespace Ui { class AboutDialog; @@ -19,7 +20,7 @@ class AboutDialog : public QDialog static void about(QString version, QWidget *parent = 0); private: - Ui::AboutDialog *ui; + QScopedPointer ui; }; #endif // ABOUTDIALOG_H diff --git a/src/ui/inputdialog.cpp b/src/ui/inputdialog.cpp index edc0cfd8..c9cf9fa3 100644 --- a/src/ui/inputdialog.cpp +++ b/src/ui/inputdialog.cpp @@ -18,10 +18,7 @@ InputDialog::InputDialog(QString prompt, QString title, const std::function &validation, QWidget *parent) { diff --git a/src/ui/inputdialog.h b/src/ui/inputdialog.h index 69a62a85..d6bb87ab 100644 --- a/src/ui/inputdialog.h +++ b/src/ui/inputdialog.h @@ -3,6 +3,7 @@ #include #include +#include #include @@ -23,8 +24,10 @@ private slots: void validate(QString input); private: - Ui::InputDialog *ui; + QScopedPointer ui; const std::function &validation; + + // Q_DISABLE_COPY(Ui::InputDialog) }; #endif // INPUTDIALOG_H diff --git a/src/ui/jumpdialog.cpp b/src/ui/jumpdialog.cpp index 36e459e4..0c7f8a73 100644 --- a/src/ui/jumpdialog.cpp +++ b/src/ui/jumpdialog.cpp @@ -33,10 +33,7 @@ JumpDialog::JumpDialog(int _maxTime, QWidget *parent) : } } -JumpDialog::~JumpDialog() -{ - delete ui; -} +JumpDialog::~JumpDialog() {} int JumpDialog::getTime(int maxTime, QWidget *parent) { diff --git a/src/ui/jumpdialog.h b/src/ui/jumpdialog.h index 12ac2984..dbae4c1c 100644 --- a/src/ui/jumpdialog.h +++ b/src/ui/jumpdialog.h @@ -2,6 +2,7 @@ #define JUMPDIALOG_H #include +#include namespace Ui { class JumpDialog; @@ -21,7 +22,7 @@ private slots: void validate(); private: - Ui::JumpDialog *ui; + QScopedPointer ui; int time, maxTime; diff --git a/src/ui/keydialog.cpp b/src/ui/keydialog.cpp index 9c7cb8fb..067e84f7 100644 --- a/src/ui/keydialog.cpp +++ b/src/ui/keydialog.cpp @@ -32,10 +32,7 @@ KeyDialog::KeyDialog(QWidget *parent) : this, SLOT(reject())); } -KeyDialog::~KeyDialog() -{ - delete ui; -} +KeyDialog::~KeyDialog() {} QPair> KeyDialog::SelectKey(bool add, QPair> init) { diff --git a/src/ui/keydialog.h b/src/ui/keydialog.h index d4716a99..4b4be3d2 100644 --- a/src/ui/keydialog.h +++ b/src/ui/keydialog.h @@ -2,6 +2,7 @@ #define KEYDIALOG_H #include +#include namespace Ui { class KeyDialog; @@ -21,7 +22,7 @@ class KeyDialog : public QDialog void SetButtons(); private: - Ui::KeyDialog *ui; + QScopedPointer ui; bool add; }; diff --git a/src/ui/locationdialog.cpp b/src/ui/locationdialog.cpp index 64ffa639..b16ed9ee 100644 --- a/src/ui/locationdialog.cpp +++ b/src/ui/locationdialog.cpp @@ -28,10 +28,7 @@ LocationDialog::LocationDialog(QString path, QWidget *parent) : ui->urlEdit->setText(path); } -LocationDialog::~LocationDialog() -{ - delete ui; -} +LocationDialog::~LocationDialog() {} QString LocationDialog::getUrl(QString path, QWidget *parent) { diff --git a/src/ui/locationdialog.h b/src/ui/locationdialog.h index eb7b8789..9fafec0d 100644 --- a/src/ui/locationdialog.h +++ b/src/ui/locationdialog.h @@ -2,6 +2,7 @@ #define LOCATIONDIALOG_H #include +#include namespace Ui { class LocationDialog; @@ -21,7 +22,7 @@ private slots: void validate(QString input); private: - Ui::LocationDialog *ui; + QScopedPointer ui; }; #endif // LOCATIONDIALOG_H diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index a8c9c894..6dbe3462 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -118,30 +118,28 @@ MainWindow::MainWindow(QWidget *parent): if(lang != "en") { - QTranslator *tmp; - // load the system translations provided by Qt - tmp = baka->qtTranslator; - baka->qtTranslator = new QTranslator(); - baka->qtTranslator->load(QString("qt_%0").arg(lang), QLibraryInfo::location(QLibraryInfo::TranslationsPath)); - qApp->installTranslator(baka->qtTranslator); - if(tmp != nullptr) - delete tmp; + { + QScopedPointer _qtTranslator(baka->qtTranslator.take()); + baka->qtTranslator.reset(new QTranslator()); + baka->qtTranslator->load(QString("qt_%0").arg(lang), QLibraryInfo::location(QLibraryInfo::TranslationsPath)); + qApp->installTranslator(baka->qtTranslator.get()); + } // load the application translations - tmp = baka->translator; - baka->translator = new QTranslator(); - baka->translator->load(QString("baka-mplayer_%0").arg(lang), BAKA_MPLAYER_LANG_PATH); - qApp->installTranslator(baka->translator); - if(tmp != nullptr) - delete tmp; + { + QScopedPointer _translator(baka->translator.take()); + baka->translator.reset(new QTranslator()); + baka->translator->load(QString("baka-mplayer_%0").arg(lang), BAKA_MPLAYER_LANG_PATH); + qApp->installTranslator(baka->translator.get()); + } } else { - if(baka->qtTranslator != nullptr) - qApp->removeTranslator(baka->qtTranslator); - if(baka->translator != nullptr) - qApp->removeTranslator(baka->translator); + if (baka->qtTranslator) + qApp->removeTranslator(baka->qtTranslator.take()); + if (baka->translator) + qApp->removeTranslator(baka->translator.take()); } // save strings we want to keep @@ -284,24 +282,28 @@ MainWindow::MainWindow(QWidget *parent): QString f = mpv->getFile(), file = mpv->getPath()+f; if(f != QString() && maxRecent > 0) { - int i = recent.indexOf(file); - if(i >= 0) + int i; + for (i = 0; i < recent.length(); i++) { - int t = recent.at(i).time; + if (recent.at(i)->path == file) + break; + } + if(i < recent.length()) + { + int t = recent.at(i)->time; if(t > 0 && resume) mpv->Seek(t); recent.removeAt(i); } - if(recent.isEmpty() || recent.front() != file) + if(recent.isEmpty() || recent.front()->path != file) { UpdateRecentFiles(); // update after initialization and only if the current file is different from the first recent while(recent.length() > maxRecent-1) recent.removeLast(); - recent.push_front( - Recent(file, + recent.push_front(QSharedPointer(new Recent(file, (mpv->getPath() == QString() || !Util::IsValidFile(file)) ? - fileInfo.media_title : QString())); - current = &recent.front(); + fileInfo.media_title : QString()))); + current = recent.front().toWeakRef().toStrongRef(); } } @@ -831,7 +833,7 @@ MainWindow::MainWindow(QWidget *parent): MainWindow::~MainWindow() { - if(current != nullptr) + if(current) { int t = mpv->getTime(), l = mpv->getFileInfo().length; @@ -841,20 +843,6 @@ MainWindow::~MainWindow() current->time = 0; } baka->SaveSettings(); - - // Note: child objects _should_ not need to be deleted because - // all children should get deleted when mainwindow is deleted - // see: http://qt-project.org/doc/qt-4.8/objecttrees.html - - // but apparently they don't (https://github.com/u8sand/Baka-MPlayer/issues/47) -#if defined(Q_OS_WIN) - delete prev_toolbutton; - delete playpause_toolbutton; - delete next_toolbutton; - delete thumbnail_toolbar; -#endif - delete baka; - delete ui; } void MainWindow::Load(QString file) @@ -1246,13 +1234,13 @@ void MainWindow::UpdateRecentFiles() N = recent.length(); for(auto &f : recent) { - action = ui->menu_Recently_Opened->addAction(QString("%0. %1").arg(Util::FormatNumberWithAmpersand(n, N), Util::ShortenPathToParent(f).replace("&","&&"))); + action = ui->menu_Recently_Opened->addAction(QString("%0. %1").arg(Util::FormatNumberWithAmpersand(n, N), Util::ShortenPathToParent(*f.get()).replace("&","&&"))); if(n++ == 1) action->setShortcut(QKeySequence("Ctrl+Z")); connect(action, &QAction::triggered, action, [=] { - mpv->LoadFile(f); + mpv->LoadFile(f->path); }); } } diff --git a/src/ui/mainwindow.h b/src/ui/mainwindow.h index 47b90037..321bb86a 100644 --- a/src/ui/mainwindow.h +++ b/src/ui/mainwindow.h @@ -13,6 +13,8 @@ #include #include #include +#include +#include #if defined(Q_OS_WIN) #include @@ -50,7 +52,7 @@ friend class BakaEngine; bool getHideAllControls() { return hideAllControls; } bool isFullScreenMode() { return hideAllControls || isFullScreen(); } - Ui::MainWindow *ui; + QScopedPointer ui; QImage albumArt; public slots: void Load(QString f = QString()); @@ -102,8 +104,8 @@ private slots: QTimer autohide; // variables - QList recent; - Recent *current = nullptr; + QList> recent; + QSharedPointer current; QString lang, onTop; int autoFit, @@ -118,6 +120,7 @@ private slots: hideAllControls = false; QHash commandActionMap; + // Q_DISABLE_COPY(Ui::MainWindow) public slots: void setLang(QString s) { emit langChanged(lang = s); } void setOnTop(QString s) { emit onTopChanged(onTop = s); } diff --git a/src/ui/preferencesdialog.cpp b/src/ui/preferencesdialog.cpp index 0c1e5757..17895c1d 100644 --- a/src/ui/preferencesdialog.cpp +++ b/src/ui/preferencesdialog.cpp @@ -5,6 +5,7 @@ #include "ui/mainwindow.h" #include "mpvhandler.h" #include "ui/keydialog.h" +#include "ui_keydialog.h" #include #include @@ -18,7 +19,7 @@ PreferencesDialog::PreferencesDialog(BakaEngine *baka, QWidget *parent) : ui->setupUi(this); ui->infoWidget->sortByColumn(0, Qt::AscendingOrder); - sortLock = new SortLock(ui->infoWidget); + sortLock.reset(new SortLock(ui->infoWidget)); PopulateLangs(); @@ -166,8 +167,6 @@ PreferencesDialog::~PreferencesDialog() } else baka->input = saved; - delete sortLock; - delete ui; } void PreferencesDialog::showPreferences(BakaEngine *baka, QWidget *parent) diff --git a/src/ui/preferencesdialog.h b/src/ui/preferencesdialog.h index 5b3bfc4d..61e90dd7 100644 --- a/src/ui/preferencesdialog.h +++ b/src/ui/preferencesdialog.h @@ -6,6 +6,7 @@ #include #include #include +#include namespace Ui { class PreferencesDialog; @@ -31,7 +32,7 @@ class PreferencesDialog : public QDialog void SelectKey(bool add, QPair> init = (QPair>())); private: - Ui::PreferencesDialog *ui; + QScopedPointer ui; BakaEngine *baka; QHash> saved; @@ -47,7 +48,9 @@ class PreferencesDialog : public QDialog void unlock(); private: QTableWidget *parent; - } *sortLock; + }; + + QScopedPointer sortLock; }; #endif // PREFERENCESDIALOG_H diff --git a/src/ui/screenshotdialog.cpp b/src/ui/screenshotdialog.cpp index ca5def03..4541bb6c 100644 --- a/src/ui/screenshotdialog.cpp +++ b/src/ui/screenshotdialog.cpp @@ -41,10 +41,7 @@ ScreenshotDialog::ScreenshotDialog(bool &_always, bool &_screenshot, MpvHandler }); } -ScreenshotDialog::~ScreenshotDialog() -{ - delete ui; -} +ScreenshotDialog::~ScreenshotDialog() {} int ScreenshotDialog::showScreenshotDialog(bool &always, bool &screenshot, MpvHandler *mpv, QWidget *parent) { diff --git a/src/ui/screenshotdialog.h b/src/ui/screenshotdialog.h index 35ecc94b..df8ef5b0 100644 --- a/src/ui/screenshotdialog.h +++ b/src/ui/screenshotdialog.h @@ -20,7 +20,7 @@ class ScreenshotDialog : public QDialog static int showScreenshotDialog(bool &always, bool &screenshot, MpvHandler *mpv, QWidget *parent = 0); private: - Ui::ScreenshotDialog *ui; + QScopedPointer ui; bool &always, &screenshot; }; diff --git a/src/ui/updatedialog.cpp b/src/ui/updatedialog.cpp index 6d576d9d..4e54bb8f 100644 --- a/src/ui/updatedialog.cpp +++ b/src/ui/updatedialog.cpp @@ -95,16 +95,12 @@ UpdateDialog::UpdateDialog(BakaEngine *baka, QWidget *parent) : ShowInfo(); } } - -UpdateDialog::~UpdateDialog() -{ - delete ui; -} +UpdateDialog::~UpdateDialog() {} void UpdateDialog::CheckForUpdates(BakaEngine *baka, QWidget *parent) { - UpdateDialog *dialog = new UpdateDialog(baka, parent); - dialog->exec(); + UpdateDialog dialog(baka, parent); + dialog.exec(); } void UpdateDialog::ShowInfo() diff --git a/src/ui/updatedialog.h b/src/ui/updatedialog.h index 24f5caf1..30e6fe11 100644 --- a/src/ui/updatedialog.h +++ b/src/ui/updatedialog.h @@ -24,7 +24,7 @@ protected slots: void ShowInfo(); private: - Ui::UpdateDialog *ui; + QScopedPointer ui; BakaEngine *baka; QElapsedTimer timer; @@ -34,6 +34,8 @@ protected slots: lastTime, state; bool init; + + // Q_DISABLE_COPY(Ui::UpdateDialog) }; #endif // UPDATEDIALOG_H diff --git a/src/updatemanager.cpp b/src/updatemanager.cpp index bd0ab8cd..fdac0063 100644 --- a/src/updatemanager.cpp +++ b/src/updatemanager.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #if defined(Q_OS_WIN) #include @@ -24,12 +25,6 @@ UpdateManager::UpdateManager(QObject *parent) : manager(new QNetworkAccessManager(this)), busy(false) { - -} - -UpdateManager::~UpdateManager() -{ - delete manager; } bool UpdateManager::CheckForUpdates() @@ -87,11 +82,10 @@ bool UpdateManager::DownloadUpdate(const QString &url) emit progressSignal(0); QNetworkRequest request(url); QString filename = QDir::toNativeSeparators(QString("%0/Baka-MPlayer.zip").arg(QCoreApplication::applicationDirPath())); - QFile *file = new QFile(filename); + QSharedPointer file(new QFile(filename)); if(!file->open(QFile::WriteOnly | QFile::Truncate)) { emit messageSignal(tr("fopen error\n")); - delete file; busy = false; return false; } @@ -120,13 +114,13 @@ bool UpdateManager::DownloadUpdate(const QString &url) { emit messageSignal(reply->errorString()); file->close(); - delete file; + file->deleteLater(); } else { file->flush(); file->close(); - delete file; + file->deleteLater(); QUrl redirect = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl(); if(redirect.isEmpty()) { diff --git a/src/updatemanager.h b/src/updatemanager.h index 402439f5..27f32f9b 100644 --- a/src/updatemanager.h +++ b/src/updatemanager.h @@ -13,7 +13,6 @@ class UpdateManager : public QObject Q_OBJECT public: explicit UpdateManager(QObject *parent = 0); - ~UpdateManager(); const QMap &getInfo() { return info; } diff --git a/src/versions/2_0_3.cpp b/src/versions/2_0_3.cpp index 19c7a2c9..4d33c713 100644 --- a/src/versions/2_0_3.cpp +++ b/src/versions/2_0_3.cpp @@ -67,7 +67,7 @@ void BakaEngine::Load2_0_3() for(auto entry : root["recent"].toArray()) { QJsonObject entry_json = entry.toObject(); - window->recent.append(Recent(entry_json["path"].toString(), entry_json["title"].toString(), QJsonValueRef2(entry_json["time"]).toInt(0))); + window->recent.append(QSharedPointer(new Recent(entry_json["path"].toString(), entry_json["title"].toString(), QJsonValueRef2(entry_json["time"]).toInt(0)))); } window->setMaxRecent(QJsonValueRef2(root["maxRecent"]).toInt(5)); window->setGestures(QJsonValueRef2(root["gestures"]).toBool(true)); @@ -147,11 +147,11 @@ void BakaEngine::SaveSettings() for(auto &entry : window->recent) { QJsonObject recent_sub_object_json; - recent_sub_object_json["path"] = QDir::fromNativeSeparators(entry.path); - if(entry.title != QString()) - recent_sub_object_json["title"] = entry.title; - if(entry.time > 0) - recent_sub_object_json["time"] = entry.time; + recent_sub_object_json["path"] = QDir::fromNativeSeparators(entry->path); + if(entry->title != QString()) + recent_sub_object_json["title"] = entry->title; + if(entry->time > 0) + recent_sub_object_json["time"] = entry->time; recent_json.append(recent_sub_object_json); } root["recent"] = recent_json; diff --git a/src/widgets/dimdialog.cpp b/src/widgets/dimdialog.cpp index 0905748d..4dbe4454 100644 --- a/src/widgets/dimdialog.cpp +++ b/src/widgets/dimdialog.cpp @@ -6,9 +6,9 @@ #include #include -DimDialog::DimDialog(MainWindow *window, QWidget *parent) : +DimDialog::DimDialog(QWidget *parent) : QDialog(parent), - window(window) + window(static_cast(parent)) { setWindowFlags(Qt::Tool | Qt::FramelessWindowHint); setWindowOpacity(.6); diff --git a/src/widgets/dimdialog.h b/src/widgets/dimdialog.h index 5ef25090..2771c2e3 100644 --- a/src/widgets/dimdialog.h +++ b/src/widgets/dimdialog.h @@ -9,7 +9,7 @@ class DimDialog : public QDialog { Q_OBJECT public: - explicit DimDialog(MainWindow *window, QWidget *parent = 0); + explicit DimDialog(QWidget *parent = 0); void show(); bool close(); From eabff3cdb48656e1ff7280019c688d74ef21d52a Mon Sep 17 00:00:00 2001 From: Daniel Clarke Date: Sat, 21 Jan 2023 17:19:12 -0500 Subject: [PATCH 10/19] Fix mpv aspect warning --- src/mpvhandler.cpp | 12 ++++++------ src/ui/mainwindow.cpp | 8 ++++---- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/mpvhandler.cpp b/src/mpvhandler.cpp index eb78cba9..2bf8c15b 100644 --- a/src/mpvhandler.cpp +++ b/src/mpvhandler.cpp @@ -556,7 +556,7 @@ void MpvHandler::Speed(double d) void MpvHandler::Aspect(QString aspect) { const QByteArray tmp = aspect.toUtf8(); - const char *args[] = {"set", "video-aspect", tmp.constData(), NULL}; + const char *args[] = {"set", "video-aspect-override", tmp.constData(), NULL}; AsyncCommand(args); } @@ -827,12 +827,12 @@ void MpvHandler::LoadChapters() void MpvHandler::LoadVideoParams() { fileInfo.video_params.codec = mpv_get_property_string(mpv, "video-codec"); - mpv_get_property(mpv, "width", MPV_FORMAT_INT64, &fileInfo.video_params.width); - mpv_get_property(mpv, "height", MPV_FORMAT_INT64, &fileInfo.video_params.height); - mpv_get_property(mpv, "dwidth", MPV_FORMAT_INT64, &fileInfo.video_params.dwidth); - mpv_get_property(mpv, "dheight", MPV_FORMAT_INT64, &fileInfo.video_params.dheight); + mpv_get_property(mpv, "width", MPV_FORMAT_INT64, &fileInfo.video_params.width); + mpv_get_property(mpv, "height", MPV_FORMAT_INT64, &fileInfo.video_params.height); + mpv_get_property(mpv, "dwidth", MPV_FORMAT_INT64, &fileInfo.video_params.dwidth); + mpv_get_property(mpv, "dheight", MPV_FORMAT_INT64, &fileInfo.video_params.dheight); // though this has become useless, removing it causes a segfault--no clue: - mpv_get_property(mpv, "video-aspect", MPV_FORMAT_INT64, &fileInfo.video_params.aspect); + mpv_get_property(mpv, "video-params/aspect", MPV_FORMAT_INT64, &fileInfo.video_params.aspect); emit videoParamsChanged(fileInfo.video_params); } diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 6dbe3462..2f5c9c8d 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -43,10 +43,10 @@ MainWindow::MainWindow(QWidget *parent): {"mpv set sub-scale 1", ui->action_Reset_Size}, {"mpv add sub-scale +0.1", ui->action_Size}, {"mpv add sub-scale -0.1", ui->actionS_ize}, - {"mpv set video-aspect -1", ui->action_Auto_Detect}, // todo: make these baka-commands so we can output messages when they change - {"mpv set video-aspect 16:9", ui->actionForce_16_9}, - {"mpv set video-aspect 2.35:1", ui->actionForce_2_35_1}, - {"mpv set video-aspect 4:3", ui->actionForce_4_3}, + {"mpv set video-aspect-override -1", ui->action_Auto_Detect}, // todo: make these baka-commands so we can output messages when they change + {"mpv set video-aspect-override 16:9", ui->actionForce_16_9}, + {"mpv set video-aspect-override 2.35:1", ui->actionForce_2_35_1}, + {"mpv set video-aspect-override 4:3", ui->actionForce_4_3}, {"mpv cycle sub-visibility", ui->actionShow_Subtitles}, {"mpv set time-pos 0", ui->action_Restart}, {"mpv frame-step", ui->action_Frame_Step}, From 27a269f7283cb22ebc9ee1ece79e4b06b7177e05 Mon Sep 17 00:00:00 2001 From: Daniel Clarke Date: Sat, 21 Jan 2023 18:22:26 -0500 Subject: [PATCH 11/19] Fix overlay handler QLabel pointer handling --- src/overlay.cpp | 7 +++---- src/overlay.h | 15 +++++++++++---- src/overlayhandler.cpp | 41 ++++++++++++++++++++++++++++------------- src/overlayhandler.h | 3 ++- 4 files changed, 44 insertions(+), 22 deletions(-) diff --git a/src/overlay.cpp b/src/overlay.cpp index e1ca332c..065eab9e 100644 --- a/src/overlay.cpp +++ b/src/overlay.cpp @@ -1,6 +1,5 @@ #include "overlay.h" -Overlay::Overlay(QScopedPointer &label, QScopedPointer &timer): - label(label.take()), - timer(timer.take()) -{} +Overlay::Overlay():label(nullptr), timer(new QTimer()) {} +Overlay::Overlay(const Overlay &overlay):label(overlay.label), timer(overlay.timer) {} +Overlay::~Overlay() {} diff --git a/src/overlay.h b/src/overlay.h index 97c97327..a9f9f24f 100644 --- a/src/overlay.h +++ b/src/overlay.h @@ -3,13 +3,20 @@ #include #include -#include +#include struct Overlay { - Overlay(QScopedPointer &label, QScopedPointer &timer); +public: + Overlay(); + Overlay(const Overlay &overlay); + ~Overlay(); - QScopedPointer label; - QScopedPointer timer; + // we use a ptr because this label needs to have a parent of another object + // and that object will try to delete it + QLabel *label; + + // sharing this pointer seems simpler for dealing with the copy constructor + QSharedPointer timer; }; #endif // OVERLAY_H diff --git a/src/overlayhandler.cpp b/src/overlayhandler.cpp index a8324f69..068dde31 100644 --- a/src/overlayhandler.cpp +++ b/src/overlayhandler.cpp @@ -32,6 +32,8 @@ OverlayHandler::OverlayHandler(QObject *parent): this, [=] { showInfoText(); }); } +OverlayHandler::~OverlayHandler() {} + void OverlayHandler::showStatusText(const QString &text, int duration) { if(text != QString()) @@ -70,6 +72,15 @@ void OverlayHandler::showText(const QString &text, QFont font, QColor color, QPo overlay_id = std::max(min_overlay, (overlay_id + 1) % max_overlay); } + Overlay &overlay = overlays[id]; + if (overlay.label == nullptr) + { + // this label is owned by baka->window->ui->mpvFrame which will try to + // delete it when it is destroyed + overlay.label = new QLabel(baka->window->ui->mpvFrame); + overlay.label->setStyleSheet("background-color:rgba(0,0,0,0);background-image:url();"); + } + QFontMetrics fm(font); QStringList lines = text.split('\n'); // the 1.3 was pretty much determined through trial and error; this formula isn't perfect @@ -106,23 +117,19 @@ void OverlayHandler::showText(const QString &text, QFont font, QColor color, QPo painter.setBrush(color); painter.drawPath(path); - // add over mpv as label - QScopedPointer label(new QLabel(baka->window->ui->mpvFrame)); - label->setStyleSheet("background-color:rgba(0,0,0,0);background-image:url();"); - label->setGeometry(pos.x(), + overlay.label->setGeometry(pos.x(), pos.y(), canvas.width(), canvas.height()); - label->setPixmap(QPixmap::fromImage(canvas)); - label->show(); + overlay.label->setPixmap(QPixmap::fromImage(canvas)); + overlay.label->show(); - QScopedPointer timer(new QTimer); if(duration > 0) { - timer->start(duration); - connect(timer.get(), &QTimer::timeout, // on timeout - timer.get(), [this, id] { remove(id); }); + overlay.timer->start(duration); + connect(overlay.timer.get(), &QTimer::timeout, // on timeout + overlay.timer.get(), [this, id] { remove(id); }); } // add as mpv overlay @@ -132,13 +139,21 @@ void OverlayHandler::showText(const QString &text, QFont font, QColor color, QPo "&"+QString::number(quintptr(canvas.bits())), 0, canvas.width(), canvas.height()); - overlays[id].reset(new Overlay(label, timer)); overlay_mutex.unlock(); } void OverlayHandler::remove(int id) { - if (overlays.remove(id)) { - baka->mpv->RemoveOverlay(id); + overlay_mutex.lock(); + if (overlays.contains(id)) { + baka->mpv->RemoveOverlay(id); + { + Overlay &overlay = overlays[id]; + overlay.timer->stop(); + overlay.label->hide(); + overlay.label->deleteLater(); + } + overlays.remove(id); } + overlay_mutex.unlock(); } diff --git a/src/overlayhandler.h b/src/overlayhandler.h index db7dceec..53aa73ad 100644 --- a/src/overlayhandler.h +++ b/src/overlayhandler.h @@ -19,6 +19,7 @@ class OverlayHandler : public QObject Q_OBJECT public: explicit OverlayHandler(QObject *parent = 0); + ~OverlayHandler(); public slots: void showStatusText(const QString &text, int duration = 4000); @@ -31,7 +32,7 @@ protected slots: private: BakaEngine *baka; - QHash> overlays; + QHash overlays; QMutex overlay_mutex; QTimer refresh_timer; From a503f989a7ae1fc6dce788f7eb6da1dda67008d3 Mon Sep 17 00:00:00 2001 From: Daniel Clarke Date: Sat, 28 Jan 2023 12:44:21 -0500 Subject: [PATCH 12/19] mpvhandler overhall for RENDER_PARAM_ADVANCED_CONTROL --- src/bakacommands.cpp | 140 +++---- src/mpvhandler.cpp | 909 ++++++++++++++++++++--------------------- src/mpvhandler.h | 24 +- src/mpvtypes.h | 8 + src/overlayhandler.cpp | 10 +- 5 files changed, 549 insertions(+), 542 deletions(-) diff --git a/src/bakacommands.cpp b/src/bakacommands.cpp index 6cd2698f..b16f2288 100644 --- a/src/bakacommands.cpp +++ b/src/bakacommands.cpp @@ -427,87 +427,87 @@ void BakaEngine::FitWindow(int percent, bool msg) if(window->isFullScreen() || window->isMaximized() || !window->ui->menuFit_Window->isEnabled()) return; - mpv->LoadVideoParams(); - - const Mpv::VideoParams &vG = mpv->getFileInfo().video_params; // video geometry - QRect mG = window->ui->mpvFrame->geometry(), // mpv geometry - wfG = window->frameGeometry(), // frame geometry of window (window geometry + window frame) - wG = window->geometry(), // window geometry - aG = qApp->desktop()->availableGeometry(wfG.center()); // available geometry of the screen we're in--(geometry not including the taskbar) - - double a, // aspect ratio - w, // width of vid we want - h; // height of vid we want - - // obtain natural video aspect ratio - if(vG.width == 0 || vG.height == 0) // width/height are 0 when there is no output - return; - if(vG.dwidth == 0 || vG.dheight == 0) // dwidth/height are 0 on load - a = double(vG.width)/vG.height; // use video width and height for aspect ratio - else - a = double(vG.dwidth)/vG.dheight; // use display width and height for aspect ratio + mpv->LoadVideoParams([=]() { + const Mpv::VideoParams &vG = mpv->getFileInfo().video_params; // video geometry + QRect mG = window->ui->mpvFrame->geometry(), // mpv geometry + wfG = window->frameGeometry(), // frame geometry of window (window geometry + window frame) + wG = window->geometry(), // window geometry + aG = qApp->desktop()->availableGeometry(wfG.center()); // available geometry of the screen we're in--(geometry not including the taskbar) + + double a, // aspect ratio + w, // width of vid we want + h; // height of vid we want + + // obtain natural video aspect ratio + if(vG.width == 0 || vG.height == 0) // width/height are 0 when there is no output + return; + if(vG.dwidth == 0 || vG.dheight == 0) // dwidth/height are 0 on load + a = double(vG.width)/vG.height; // use video width and height for aspect ratio + else + a = double(vG.dwidth)/vG.dheight; // use display width and height for aspect ratio - // calculate resulting display: - if(percent == 0) // fit to window - { - // set our current mpv frame dimensions - w = mG.width(); - h = mG.height(); + // calculate resulting display: + if(percent == 0) // fit to window + { + // set our current mpv frame dimensions + w = mG.width(); + h = mG.height(); - double cmp = w/h - a, // comparison - eps = 0.01; // epsilon (deal with rounding errors) we consider -eps < 0 < eps ==> 0 + double cmp = w/h - a, // comparison + eps = 0.01; // epsilon (deal with rounding errors) we consider -eps < 0 < eps ==> 0 - if(cmp > eps) // too wide - w = h * a; // calculate width based on the correct height - else if(cmp < -eps) // too long - h = w / a; // calculate height based on the correct width - } - else // fit into desired dimensions - { - double scale = percent / 100.0; // get scale + if(cmp > eps) // too wide + w = h * a; // calculate width based on the correct height + else if(cmp < -eps) // too long + h = w / a; // calculate height based on the correct width + } + else // fit into desired dimensions + { + double scale = percent / 100.0; // get scale - w = vG.width * scale; // get scaled width - h = vG.height * scale; // get scaled height - } + w = vG.width * scale; // get scaled width + h = vG.height * scale; // get scaled height + } - double dW = w + (wfG.width() - mG.width()), // calculate display width of the window - dH = h + (wfG.height() - mG.height()); // calculate display height of the window + double dW = w + (wfG.width() - mG.width()), // calculate display width of the window + dH = h + (wfG.height() - mG.height()); // calculate display height of the window - if(dW > aG.width()) // if the width is bigger than the available area - { - dW = aG.width(); // set the width equal to the available area - w = dW - (wfG.width() - mG.width()); // calculate the width - h = w / a; // calculate height - dH = h + (wfG.height() - mG.height()); // calculate new display height - } - if(dH > aG.height()) // if the height is bigger than the available area - { - dH = aG.height(); // set the height equal to the available area - h = dH - (wfG.height() - mG.height()); // calculate the height - w = h * a; // calculate the width accordingly - dW = w + (wfG.width() - mG.width()); // calculate new display width - } + if(dW > aG.width()) // if the width is bigger than the available area + { + dW = aG.width(); // set the width equal to the available area + w = dW - (wfG.width() - mG.width()); // calculate the width + h = w / a; // calculate height + dH = h + (wfG.height() - mG.height()); // calculate new display height + } + if(dH > aG.height()) // if the height is bigger than the available area + { + dH = aG.height(); // set the height equal to the available area + h = dH - (wfG.height() - mG.height()); // calculate the height + w = h * a; // calculate the width accordingly + dW = w + (wfG.width() - mG.width()); // calculate new display width + } - // get the centered rectangle we want - QRect rect = QStyle::alignedRect(Qt::LeftToRight, - Qt::AlignCenter, - QSize(dW, - dH), - percent == 0 ? wfG : aG); // center in window (autofit) or on our screen + // get the centered rectangle we want + QRect rect = QStyle::alignedRect(Qt::LeftToRight, + Qt::AlignCenter, + QSize(dW, + dH), + percent == 0 ? wfG : aG); // center in window (autofit) or on our screen - // adjust the rect to compensate for the frame - rect.setLeft(rect.left() + (wG.left() - wfG.left())); - rect.setTop(rect.top() + (wG.top() - wfG.top())); - rect.setRight(rect.right() - (wfG.right() - wG.right())); - rect.setBottom(rect.bottom() - (wfG.bottom() - wG.bottom())); + // adjust the rect to compensate for the frame + rect.setLeft(rect.left() + (wG.left() - wfG.left())); + rect.setTop(rect.top() + (wG.top() - wfG.top())); + rect.setRight(rect.right() - (wfG.right() - wG.right())); + rect.setBottom(rect.bottom() - (wfG.bottom() - wG.bottom())); - // finally set the geometry of the window - window->setGeometry(rect); + // finally set the geometry of the window + window->setGeometry(rect); - // note: the above block is required because there is no setFrameGeometry function + // note: the above block is required because there is no setFrameGeometry function - if(msg) - mpv->ShowText(tr("Fit Window: %0").arg(percent == 0 ? tr("To Current Size") : (QString::number(percent)+"%"))); + if(msg) + mpv->ShowText(tr("Fit Window: %0").arg(percent == 0 ? tr("To Current Size") : (QString::number(percent)+"%"))); + }); } void BakaEngine::BakaDeinterlace(QStringList &args) diff --git a/src/mpvhandler.cpp b/src/mpvhandler.cpp index 6666aa5e..2c9857b8 100644 --- a/src/mpvhandler.cpp +++ b/src/mpvhandler.cpp @@ -14,9 +14,12 @@ #include #include +#include +#include + static void wakeup(void *ctx) { - QMetaObject::invokeMethod((MpvHandler*)ctx, "on_mpv_events", Qt::QueuedConnection); + QMetaObject::invokeMethod((MpvHandler*)ctx, "onMpvEvents", Qt::QueuedConnection); } static void *get_proc_address(void *ctx, const char *name) { @@ -27,6 +30,58 @@ static void *get_proc_address(void *ctx, const char *name) { return reinterpret_cast(glctx->getProcAddress(QByteArray(name))); } +static inline QVariant node_to_variant(const mpv_node *node) +{ + switch (node->format) { + case MPV_FORMAT_STRING: + return QVariant(QString::fromUtf8(node->u.string)); + case MPV_FORMAT_FLAG: + return QVariant(static_cast(node->u.flag)); + case MPV_FORMAT_INT64: + return QVariant(static_cast(node->u.int64)); + case MPV_FORMAT_DOUBLE: + return QVariant(node->u.double_); + case MPV_FORMAT_NODE_ARRAY: { + mpv_node_list *list = node->u.list; + QVariantList qlist; + for (int n = 0; n < list->num; n++) + qlist.append(node_to_variant(&list->values[n])); + return QVariant(qlist); + } + case MPV_FORMAT_NODE_MAP: { + mpv_node_list *list = node->u.list; + QVariantMap qmap; + for (int n = 0; n < list->num; n++) { + qmap.insert(QString::fromUtf8(list->keys[n]), + node_to_variant(&list->values[n])); + } + return QVariant(qmap); + } + default: // MPV_FORMAT_NONE, unknown values (e.g. future extensions) + return QVariant(); + } +} + +static inline QVariant mpv_data_as_variant(void *data, mpv_format format) { + if (data == nullptr) { + return QVariant(); + } + switch(format) { + case MPV_FORMAT_STRING: + return QVariant(QString::fromUtf8(static_cast(data))); + case MPV_FORMAT_FLAG: + return QVariant(*static_cast(data)); + case MPV_FORMAT_INT64: + return QVariant(*static_cast(data)); + case MPV_FORMAT_DOUBLE: + return QVariant(*static_cast(data)); + case MPV_FORMAT_NODE: + return node_to_variant(static_cast(data)); + default: + return QVariant(); + } +} + MpvHandler::MpvHandler(QWidget *parent): QOpenGLWidget(parent) { @@ -44,16 +99,62 @@ MpvHandler::MpvHandler(QWidget *parent): mpv_set_option_string(mpv, "hwdec", "auto"); // get updates when these properties change - mpv_observe_property(mpv, 0, "playback-time", MPV_FORMAT_DOUBLE); - mpv_observe_property(mpv, 0, "volume", MPV_FORMAT_DOUBLE); - mpv_observe_property(mpv, 0, "sid", MPV_FORMAT_INT64); - mpv_observe_property(mpv, 0, "aid", MPV_FORMAT_INT64); - mpv_observe_property(mpv, 0, "sub-visibility", MPV_FORMAT_FLAG); - mpv_observe_property(mpv, 0, "mute", MPV_FORMAT_FLAG); - mpv_observe_property(mpv, 0, "core-idle", MPV_FORMAT_FLAG); - mpv_observe_property(mpv, 0, "idle-active", MPV_FORMAT_FLAG); - mpv_observe_property(mpv, 0, "pause", MPV_FORMAT_FLAG); - mpv_observe_property(mpv, 0, "paused-for-cache", MPV_FORMAT_FLAG); + ObserveProperty("playback-time", MPV_FORMAT_DOUBLE, [=](QVariant &prop) { + setTime((int)prop.toDouble()); + lastTime = time; + }); + ObserveProperty("duration", MPV_FORMAT_DOUBLE, [=](QVariant &prop) { + fileInfo.length = prop.toDouble(); + setTime(time); + }); + ObserveProperty("volume", MPV_FORMAT_DOUBLE, [=](QVariant &prop) { + setVolume((int)prop.toDouble()); + }); + ObserveProperty("sid", MPV_FORMAT_INT64, [=](QVariant &prop) { + setSid(prop.toULongLong()); + }); + ObserveProperty("aid", MPV_FORMAT_INT64, [=](QVariant &prop) { + setAid(prop.toULongLong()); + }); + ObserveProperty("sub-visibility", MPV_FORMAT_FLAG, [=](QVariant &prop) { + setSubtitleVisibility(prop.toBool()); + }); + ObserveProperty("mute", MPV_FORMAT_FLAG, [=](QVariant &prop) { + setMute(prop.toBool()); + }); + ObserveProperty("core-idle", MPV_FORMAT_FLAG, [=](QVariant &prop) { + bool coreIdle = prop.toBool(); + if(coreIdle && playState == Mpv::Playing) + ShowText(tr("Buffering..."), 0); + else + ShowText(QString(), 0); + }); + ObserveProperty("idle-active", MPV_FORMAT_FLAG, [=](QVariant &prop) { + bool idleActive = prop.toBool(); + if(idleActive) + { + fileInfo.length = 0; + setTime(0); + setPlayState(Mpv::Idle); + } + }); + ObserveProperty("pause", MPV_FORMAT_FLAG, [=](QVariant &prop) { + bool pause = prop.toBool(); + if(pause) + { + setPlayState(Mpv::Paused); + ShowText(QString(), 0); + } + else + setPlayState(Mpv::Playing); + }); + ObserveProperty("paused-for-cache", MPV_FORMAT_FLAG, [=](QVariant &prop) { + bool pausedForCache = prop.toBool(); + if(pausedForCache && playState == Mpv::Playing) + ShowText(tr("Your network is slow or stuck, please wait a bit"), 0); + else + ShowText(QString(), 0); + }); // setup callback event handling mpv_set_wakeup_callback(mpv, wakeup, this); @@ -65,7 +166,6 @@ MpvHandler::MpvHandler(QWidget *parent): { case Mpv::Started: this->LoadFileInfo(); - this->SetProperties(); setPlayState(Mpv::Playing); break; default: @@ -93,7 +193,7 @@ void MpvHandler::Initialize(BakaEngine *baka) void MpvHandler::initializeGL() { mpv_opengl_init_params gl_init_params{get_proc_address, nullptr}; - int advancedControlEnable = 0; + int advancedControlEnable = 1; mpv_render_param params[]{ {MPV_RENDER_PARAM_API_TYPE, const_cast(MPV_RENDER_API_TYPE_OPENGL)}, {MPV_RENDER_PARAM_OPENGL_INIT_PARAMS, &gl_init_params}, @@ -120,75 +220,82 @@ void MpvHandler::paintGL() mpv_render_context_render(mpv_gl, params); } -QString MpvHandler::getMediaInfo() +void MpvHandler::getMediaInfo(std::function cb) { QFileInfo fi(path+file); + QList properties{ + {"avsync", MPV_FORMAT_DOUBLE}, + {"estimated-vf-fps", MPV_FORMAT_DOUBLE}, + {"video-bitrate", MPV_FORMAT_DOUBLE}, + {"audio-bitrate", MPV_FORMAT_DOUBLE}, + {"current-vo", MPV_FORMAT_STRING}, + {"current-ao", MPV_FORMAT_STRING}, + {"hwdec-active", MPV_FORMAT_STRING} + }; + GetProperties(properties, [=](QSharedPointer property_values) { + double avsync = property_values->value("avsync").toDouble(); + double fps = property_values->value("estimated-vf-fps").toDouble(); + double vbitrate = property_values->value("video-bitrate").toDouble(); + double abitrate = property_values->value("audio-bitrate").toDouble(); + QString current_vo = property_values->value("current-vo").toString(); + QString current_ao = property_values->value("current-ao").toString(); + QString hwdec_active = property_values->value("hwdec-active").toString(); + int vtracks = 0, + atracks = 0; + + for(auto &track : fileInfo.tracks) + { + if(track.type == "video") + ++vtracks; + else if(track.type == "audio") + ++atracks; + } - double avsync, fps, vbitrate, abitrate; - - mpv_get_property(mpv, "avsync", MPV_FORMAT_DOUBLE, &avsync); - mpv_get_property(mpv, "estimated-vf-fps", MPV_FORMAT_DOUBLE, &fps); - mpv_get_property(mpv, "video-bitrate", MPV_FORMAT_DOUBLE, &vbitrate); - mpv_get_property(mpv, "audio-bitrate", MPV_FORMAT_DOUBLE, &abitrate); - QString current_vo = mpv_get_property_string(mpv, "current-vo"), - current_ao = mpv_get_property_string(mpv, "current-ao"), - hwdec_active = mpv_get_property_string(mpv, "hwdec-active"); - - int vtracks = 0, - atracks = 0; - - for(auto &track : fileInfo.tracks) - { - if(track.type == "video") - ++vtracks; - else if(track.type == "audio") - ++atracks; - } - - const QString outer = "%0: %1\n", inner = " %0: %1\n"; - - QString out = outer.arg(tr("File"), fi.fileName()) + - inner.arg(tr("Title"), fileInfo.media_title) + - inner.arg(tr("File size"), Util::HumanSize(fi.size())) + - inner.arg(tr("Date created"), fi.birthTime().toString()) + - inner.arg(tr("Media length"), Util::FormatTime(fileInfo.length, fileInfo.length)) + '\n'; - if(fileInfo.video_params.codec != QString()) - out += outer.arg(tr("Video (x%0)").arg(QString::number(vtracks)), fileInfo.video_params.codec) + - inner.arg(tr("Video Output"), QString("%0 (hwdec %1)").arg(current_vo, hwdec_active)) + - inner.arg(tr("Resolution"), QString("%0 x %1 (%2)").arg(QString::number(fileInfo.video_params.width), - QString::number(fileInfo.video_params.height), - Util::Ratio(fileInfo.video_params.width, fileInfo.video_params.height))) + - inner.arg(tr("FPS"), QString::number(fps)) + - inner.arg(tr("A/V Sync"), QString::number(avsync)) + - inner.arg(tr("Bitrate"), tr("%0 kbps").arg(vbitrate/1000)) + '\n'; - if(fileInfo.audio_params.codec != QString()) - out += outer.arg(tr("Audio (x%0)").arg(QString::number(atracks)), fileInfo.audio_params.codec) + - inner.arg(tr("Audio Output"), current_ao) + - inner.arg(tr("Sample Rate"), QString::number(fileInfo.audio_params.samplerate)) + - inner.arg(tr("Channels"), QString::number(fileInfo.audio_params.channels)) + - inner.arg(tr("Bitrate"), tr("%0 kbps").arg(abitrate)) + '\n'; - - if(fileInfo.chapters.length() > 0) - { - out += outer.arg(tr("Chapters"), QString()); - int n = 1; - for(auto &chapter : fileInfo.chapters) - out += inner.arg(QString::number(n++), chapter.title); - out += '\n'; - } + const QString outer = "%0: %1\n", inner = " %0: %1\n"; + + QString out = outer.arg(tr("File"), fi.fileName()) + + inner.arg(tr("Title"), fileInfo.media_title) + + inner.arg(tr("File size"), Util::HumanSize(fi.size())) + + inner.arg(tr("Date created"), fi.birthTime().toString()) + + inner.arg(tr("Media length"), Util::FormatTime(fileInfo.length, fileInfo.length)) + '\n'; + if(fileInfo.video_params.codec != QString()) + out += outer.arg(tr("Video (x%0)").arg(QString::number(vtracks)), fileInfo.video_params.codec) + + inner.arg(tr("Video Output"), QString("%0 (hwdec %1)").arg(current_vo, hwdec_active)) + + inner.arg(tr("Resolution"), QString("%0 x %1 (%2)").arg(QString::number(fileInfo.video_params.width), + QString::number(fileInfo.video_params.height), + Util::Ratio(fileInfo.video_params.width, fileInfo.video_params.height))) + + inner.arg(tr("FPS"), QString::number(fps)) + + inner.arg(tr("A/V Sync"), QString::number(avsync)) + + inner.arg(tr("Bitrate"), tr("%0 kbps").arg(vbitrate/1000)) + '\n'; + if(fileInfo.audio_params.codec != QString()) + out += outer.arg(tr("Audio (x%0)").arg(QString::number(atracks)), fileInfo.audio_params.codec) + + inner.arg(tr("Audio Output"), current_ao) + + inner.arg(tr("Sample Rate"), QString::number(fileInfo.audio_params.samplerate)) + + inner.arg(tr("Channels"), QString::number(fileInfo.audio_params.channels)) + + inner.arg(tr("Bitrate"), tr("%0 kbps").arg(abitrate)) + '\n'; + + if(fileInfo.chapters.length() > 0) + { + out += outer.arg(tr("Chapters"), QString()); + int n = 1; + for(auto &chapter : fileInfo.chapters) + out += inner.arg(QString::number(n++), chapter.title); + out += '\n'; + } - if(fileInfo.metadata.size() > 0) - { - out += outer.arg(tr("Metadata"), QString()); - for(auto data = fileInfo.metadata.begin(); data != fileInfo.metadata.end(); ++data) - out += inner.arg(data.key(), *data); - out += '\n'; - } + if(fileInfo.metadata.size() > 0) + { + out += outer.arg(tr("Metadata"), QString()); + for(auto data = fileInfo.metadata.begin(); data != fileInfo.metadata.end(); ++data) + out += inner.arg(data.key(), *data); + out += '\n'; + } - return out; + cb(out); + }); } -void MpvHandler::on_mpv_events() +void MpvHandler::onMpvEvents() { while(mpv) { @@ -198,7 +305,6 @@ void MpvHandler::on_mpv_events() { break; } - HandleErrorCode(event->error); handle_mpv_event(event); } } @@ -207,86 +313,24 @@ void MpvHandler::handle_mpv_event(mpv_event *event) { switch (event->event_id) { - case MPV_EVENT_PROPERTY_CHANGE: + case MPV_EVENT_COMMAND_REPLY: { - mpv_event_property *prop = (mpv_event_property*)event->data; - if(QString(prop->name) == "playback-time") // playback-time does the same thing as time-pos but works for streaming media - { - if(prop->format == MPV_FORMAT_DOUBLE) - { - setTime((int)*(double*)prop->data); - lastTime = time; - } - } - else if(QString(prop->name) == "volume") + // qDebug() << "commandReply " << event->reply_userdata; + auto cb = reply_callbacks.find(event->reply_userdata); + if (cb != reply_callbacks.end()) { - if(prop->format == MPV_FORMAT_DOUBLE) - setVolume((int)*(double*)prop->data); + cb.value()(event); + reply_callbacks.remove(event->reply_userdata); } - else if(QString(prop->name) == "sid") - { - if(prop->format == MPV_FORMAT_INT64) - setSid(*(int*)prop->data); - } - else if(QString(prop->name) == "aid") - { - if(prop->format == MPV_FORMAT_INT64) - setAid(*(int*)prop->data); - } - else if(QString(prop->name) == "sub-visibility") - { - if(prop->format == MPV_FORMAT_FLAG) - setSubtitleVisibility((bool)*(unsigned*)prop->data); - } - else if(QString(prop->name) == "mute") - { - if(prop->format == MPV_FORMAT_FLAG) - setMute((bool)*(unsigned*)prop->data); - } - else if(QString(prop->name) == "core-idle") - { - if(prop->format == MPV_FORMAT_FLAG) - { - if((bool)*(unsigned*)prop->data && playState == Mpv::Playing) - ShowText(tr("Buffering..."), 0); - else - ShowText(QString(), 0); - } - } - else if(QString(prop->name) == "idle-active") - { - if(prop->format == MPV_FORMAT_FLAG) - { - if((bool)*(unsigned*)prop->data) - { - fileInfo.length = 0; - setTime(0); - setPlayState(Mpv::Idle); - } - } - } - else if(QString(prop->name) == "pause") - { - if(prop->format == MPV_FORMAT_FLAG) - { - if((bool)*(unsigned*)prop->data) - { - setPlayState(Mpv::Paused); - ShowText(QString(), 0); - } - else - setPlayState(Mpv::Playing); - } - } - else if(QString(prop->name) == "paused-for-cache") + break; + } + case MPV_EVENT_PROPERTY_CHANGE: + { + // qDebug() << "propertyChange " << event->reply_userdata; + auto cb = reply_callbacks.find(event->reply_userdata); + if (cb != reply_callbacks.end()) { - if(prop->format == MPV_FORMAT_FLAG) - { - if((bool)*(unsigned*)prop->data && playState == Mpv::Playing) - ShowText(tr("Your network is slow or stuck, please wait a bit"), 0); - else - ShowText(QString(), 0); - } + cb.value()(event); } break; } @@ -328,10 +372,12 @@ void MpvHandler::maybeUpdate() // be skipped, and the following code still fails when e.g. switching // to a different workspace with a reparenting window manager. if (window()->isVisible()) { - makeCurrent(); - paintGL(); - context()->swapBuffers(context()->surface()); - doneCurrent(); + if (mpv_render_context_update(mpv_gl) & MPV_RENDER_UPDATE_FRAME) { + makeCurrent(); + paintGL(); + context()->swapBuffers(context()->surface()); + doneCurrent(); + } } else { update(); } @@ -344,34 +390,23 @@ void MpvHandler::on_update(void *ctx) void MpvHandler::AddOverlay(int id, int x, int y, QString file, int offset, int w, int h) { - QByteArray tmp_id = QString::number(id).toUtf8(), - tmp_x = QString::number(x).toUtf8(), - tmp_y = QString::number(y).toUtf8(), - tmp_file = file.toUtf8(), - tmp_offset = QString::number(offset).toUtf8(), - tmp_w = QString::number(w).toUtf8(), - tmp_h = QString::number(h).toUtf8(), - tmp_stride = QString::number(4*w).toUtf8(); - - const char *args[] = {"overlay_add", - tmp_id.constData(), - tmp_x.constData(), - tmp_y.constData(), - tmp_file.constData(), - tmp_offset.constData(), - "bgra", - tmp_w.constData(), - tmp_h.constData(), - tmp_stride.constData(), - NULL}; - Command(args); + Command({ + "overlay_add", + QString::number(id), + QString::number(x), + QString::number(y), + file, + QString::number(offset), + "bgra", + QString::number(w), + QString::number(h), + QString::number(4*w) + }); } void MpvHandler::RemoveOverlay(int id) { - QByteArray tmp = QString::number(id).toUtf8(); - const char *args[] = {"overlay_remove", tmp.constData(), NULL}; - AsyncCommand(args); + Command({"overlay_remove", QString::number(id)}); } bool MpvHandler::FileExists(QString f) @@ -457,7 +492,7 @@ void MpvHandler::Play() if(playState > 0 && mpv) { int f = 0; - mpv_set_property_async(mpv, MPV_REPLY_PROPERTY, "pause", MPV_FORMAT_FLAG, &f); + mpv_set_property_async(mpv, reply_userdata++, "pause", MPV_FORMAT_FLAG, &f); } } @@ -466,7 +501,7 @@ void MpvHandler::Pause() if(playState > 0 && mpv) { int f = 1; - mpv_set_property_async(mpv, MPV_REPLY_PROPERTY, "pause", MPV_FORMAT_FLAG, &f); + mpv_set_property_async(mpv, reply_userdata++, "pause", MPV_FORMAT_FLAG, &f); } } @@ -481,10 +516,7 @@ void MpvHandler::PlayPause(QString fileIfStopped) if(playState < 0) // not playing, play plays the selected playlist file PlayFile(fileIfStopped); else - { - const char *args[] = {"cycle", "pause", NULL}; - AsyncCommand(args); - } + Command({"cycle", "pause"}); } void MpvHandler::Restart() @@ -513,8 +545,7 @@ void MpvHandler::Mute(bool m) { if(playState > 0) { - const char *args[] = {"set", "mute", m ? "yes" : "no", NULL}; - AsyncCommand(args); + Command({"set", "mute", m ? "yes" : "no"}); } else setMute(m); @@ -526,30 +557,25 @@ void MpvHandler::Seek(int pos, bool relative, bool osd) { if(relative) { - const QByteArray tmp = (((pos >= 0) ? "+" : QString())+QString::number(pos)).toUtf8(); + const QString tmp = ((pos >= 0) ? "+" : QString())+QString::number(pos); if(osd) { - const char *args[] = {"osd-msg", "seek", tmp.constData(), NULL}; - AsyncCommand(args); + Command({"osd-msg", "seek", tmp}); } else { - const char *args[] = {"seek", tmp.constData(), NULL}; - AsyncCommand(args); + Command({"seek", tmp}); } } else { - const QByteArray tmp = QString::number(pos).toUtf8(); if(osd) { - const char *args[] = {"osd-msg", "seek", tmp.constData(), "absolute", NULL}; - AsyncCommand(args); + Command({"osd-msg", "seek", QString::number(pos), "absolute"}); } else { - const char *args[] = {"seek", tmp.constData(), "absolute", NULL}; - AsyncCommand(args); + Command({"seek", QString::number(pos), "absolute"}); } } } @@ -564,34 +590,30 @@ int MpvHandler::Relative(int pos) void MpvHandler::FrameStep() { - const char *args[] = {"frame-step", NULL}; - AsyncCommand(args); + Command({"frame-step"}); } void MpvHandler::FrameBackStep() { - const char *args[] = {"frame-back-step", NULL}; - AsyncCommand(args); + Command({"frame-back-step"}); } void MpvHandler::Chapter(int c) { - mpv_set_property_async(mpv, MPV_REPLY_PROPERTY, "chapter", MPV_FORMAT_INT64, &c); + mpv_set_property_async(mpv, reply_userdata++, "chapter", MPV_FORMAT_INT64, &c); // const QByteArray tmp = QString::number(c).toUtf8(); // const char *args[] = {"set", "chapter", tmp.constData(), NULL}; -// AsyncCommand(args); +// Command(args); } void MpvHandler::NextChapter() { - const char *args[] = {"add", "chapter", "1", NULL}; - AsyncCommand(args); + Command({"add", "chapter", "1"}); } void MpvHandler::PreviousChapter() { - const char *args[] = {"add", "chapter", "-1", NULL}; - AsyncCommand(args); + Command({"add", "chapter", "-1"}); } void MpvHandler::Volume(int level, bool osd) @@ -602,7 +624,7 @@ void MpvHandler::Volume(int level, bool osd) if(playState > 0) { - mpv_set_property_async(mpv, MPV_REPLY_PROPERTY, "volume", MPV_FORMAT_DOUBLE, &v); + mpv_set_property_async(mpv, reply_userdata++, "volume", MPV_FORMAT_DOUBLE, &v); if(osd) ShowText(tr("Volume: %0%").arg(QString::number(level))); } @@ -616,43 +638,34 @@ void MpvHandler::Volume(int level, bool osd) void MpvHandler::Speed(double d) { if(playState > 0) - mpv_set_property_async(mpv, MPV_REPLY_PROPERTY, "speed", MPV_FORMAT_DOUBLE, &d); + mpv_set_property_async(mpv, reply_userdata++, "speed", MPV_FORMAT_DOUBLE, &d); setSpeed(d); } void MpvHandler::Aspect(QString aspect) { - const QByteArray tmp = aspect.toUtf8(); - const char *args[] = {"set", "video-aspect-override", tmp.constData(), NULL}; - AsyncCommand(args); + Command({"set", "video-aspect-override", aspect}); } void MpvHandler::Vid(int vid) { - const QByteArray tmp = QString::number(vid).toUtf8(); - const char *args[] = {"set", "vid", tmp.constData(), NULL}; - AsyncCommand(args); + Command({"set", "vid", QString::number(vid)}); } void MpvHandler::Aid(int aid) { - const QByteArray tmp = QString::number(aid).toUtf8(); - const char *args[] = {"set", "aid", tmp.constData(), NULL}; - AsyncCommand(args); + Command({"set", "aid", QString::number(aid)}); } void MpvHandler::Sid(int sid) { - const QByteArray tmp = QString::number(sid).toUtf8(); - const char *args[] = {"set", "sid", tmp.constData(), NULL}; - AsyncCommand(args); + Command({"set", "sid", QString::number(sid)}); } void MpvHandler::Screenshot(bool withSubs) { - const char *args[] = {"screenshot", (withSubs ? "subtitles" : "video"), NULL}; - AsyncCommand(args); + Command({"screenshot", (withSubs ? "subtitles" : "video")}); } void MpvHandler::ScreenshotFormat(QString s) @@ -677,14 +690,12 @@ void MpvHandler::AddSubtitleTrack(QString f) { if(f == QString()) return; - const QByteArray tmp = f.toUtf8(); - const char *args[] = {"sub-add", tmp.constData(), NULL}; - Command(args); + Command({"sub-add", f}); // this could be more efficient if we saved tracks in a bst auto old = fileInfo.tracks; // save the current track-list LoadTracks(); // load the new track list auto current = fileInfo.tracks; - for(auto track : old) // remove the old tracks in current + for(auto &track : old) // remove the old tracks in current current.removeOne(track); Mpv::Track &track = current.first(); ShowText(QString("%0: %1 (%2)").arg(QString::number(track.id), track.title, track.external ? "external" : track.lang)); @@ -694,13 +705,11 @@ void MpvHandler::AddAudioTrack(QString f) { if(f == QString()) return; - const QByteArray tmp = f.toUtf8(); - const char *args[] = {"audio-add", tmp.constData(), NULL}; - Command(args); + Command({"audio-add", f}); auto old = fileInfo.tracks; LoadTracks(); auto current = fileInfo.tracks; - for(auto track : old) + for(auto &track : old) current.removeOne(track); Mpv::Track &track = current.first(); ShowText(QString("%0: %1 (%2)").arg(QString::number(track.id), track.title, track.external ? "external" : track.lang)); @@ -708,39 +717,37 @@ void MpvHandler::AddAudioTrack(QString f) void MpvHandler::ShowSubtitles(bool b) { - const char *args[] = {"set", "sub-visibility", b ? "yes" : "no", NULL}; - AsyncCommand(args); + Command({"set", "sub-visibility", b ? "yes" : "no"}); } void MpvHandler::SubtitleScale(double scale, bool relative) { - const QByteArray tmp = QString::number(scale).toUtf8(); - const char *args[] = {relative?"add":"set", "sub-scale", tmp.constData(), NULL}; - AsyncCommand(args); + Command({relative?"add":"set", "sub-scale", QString::number(scale)}); } void MpvHandler::Deinterlace(bool deinterlace) { - HandleErrorCode(mpv_set_property_string(mpv, "deinterlace", deinterlace ? "yes" : "auto")); + HandleErrorCode(mpv_set_property_string(mpv, "deinterlace", deinterlace ? "yes" : "auto"), "deinterlace"); ShowText(tr("Deinterlacing: %0").arg(deinterlace ? tr("enabled") : tr("disabled"))); } void MpvHandler::Interpolate(bool interpolate) { - if(vo == QString()) - vo = mpv_get_property_string(mpv, "current-vo"); - QStringList vos = vo.split(','); - for(auto &o : vos) - { - int i = o.indexOf(":interpolation"); - if(interpolate && i == -1) - o.append(":interpolation"); - else if(i != -1) - o.remove(i, QString(":interpolation").length()); - } - setVo(vos.join(',')); - SetOption("vo", vo); - ShowText(tr("Motion Interpolation: %0").arg(interpolate ? tr("enabled") : tr("disabled"))); + GetProperty("current-vo", MPV_FORMAT_STRING, [=](const QVariant &prop) { + vo = prop.toString(); + QStringList vos = vo.split(','); + for(auto &o : vos) + { + int i = o.indexOf(":interpolation"); + if(interpolate && i == -1) + o.append(":interpolation"); + else if(i != -1) + o.remove(i, QString(":interpolation").length()); + } + setVo(vos.join(',')); + SetOption("vo", vo); + ShowText(tr("Motion Interpolation: %0").arg(interpolate ? tr("enabled") : tr("disabled"))); + }); } void MpvHandler::Vo(QString o) @@ -764,222 +771,142 @@ void MpvHandler::ShowText(QString text, int duration) tmp2 = QString::number(duration).toUtf8(), tmp3 = QString::number(level).toUtf8(); const char *args[] = {"show_text", tmp1.constData(), tmp2.constData(), tmp3.constData(), NULL}; - AsyncCommand(args); + Command(args); */ } void MpvHandler::LoadFileInfo() { - // get media-title - fileInfo.media_title = mpv_get_property_string(mpv, "media-title"); - // get length - double len; - mpv_get_property(mpv, "duration", MPV_FORMAT_DOUBLE, &len); - fileInfo.length = (int)len; - - LoadTracks(); - LoadChapters(); - LoadVideoParams(); - LoadAudioParams(); - LoadMetadata(); - - emit fileInfoChanged(fileInfo); -} - -void MpvHandler::LoadTracks() -{ - fileInfo.tracks.clear(); - mpv_node node; - mpv_get_property(mpv, "track-list", MPV_FORMAT_NODE, &node); - if(node.format == MPV_FORMAT_NODE_ARRAY) - { - for(int i = 0; i < node.u.list->num; i++) - { - if(node.u.list->values[i].format == MPV_FORMAT_NODE_MAP) - { - Mpv::Track track; - for(int n = 0; n < node.u.list->values[i].u.list->num; n++) - { - if(QString(node.u.list->values[i].u.list->keys[n]) == "id") - { - if(node.u.list->values[i].u.list->values[n].format == MPV_FORMAT_INT64) - track.id = node.u.list->values[i].u.list->values[n].u.int64; - } - else if(QString(node.u.list->values[i].u.list->keys[n]) == "type") - { - if(node.u.list->values[i].u.list->values[n].format == MPV_FORMAT_STRING) - track.type = node.u.list->values[i].u.list->values[n].u.string; - } - else if(QString(node.u.list->values[i].u.list->keys[n]) == "src-id") - { - if(node.u.list->values[i].u.list->values[n].format == MPV_FORMAT_INT64) - track.src_id = node.u.list->values[i].u.list->values[n].u.int64; - } - else if(QString(node.u.list->values[i].u.list->keys[n]) == "title") - { - if(node.u.list->values[i].u.list->values[n].format == MPV_FORMAT_STRING) - track.title = node.u.list->values[i].u.list->values[n].u.string; - } - else if(QString(node.u.list->values[i].u.list->keys[n]) == "lang") - { - if(node.u.list->values[i].u.list->values[n].format == MPV_FORMAT_STRING) - track.lang = node.u.list->values[i].u.list->values[n].u.string; - } - else if(QString(node.u.list->values[i].u.list->keys[n]) == "albumart") - { - if(node.u.list->values[i].u.list->values[n].format == MPV_FORMAT_FLAG) - track.albumart = node.u.list->values[i].u.list->values[n].u.flag; - } - else if(QString(node.u.list->values[i].u.list->keys[n]) == "default") - { - if(node.u.list->values[i].u.list->values[n].format == MPV_FORMAT_FLAG) - track._default = node.u.list->values[i].u.list->values[n].u.flag; - } - else if(QString(node.u.list->values[i].u.list->keys[n]) == "external") - { - if(node.u.list->values[i].u.list->values[n].format == MPV_FORMAT_FLAG) - track.external = node.u.list->values[i].u.list->values[n].u.flag; - } - else if(QString(node.u.list->values[i].u.list->keys[n]) == "external-filename") - { - if(node.u.list->values[i].u.list->values[n].format == MPV_FORMAT_STRING) - track.external_filename = node.u.list->values[i].u.list->values[n].u.string; - } - else if(QString(node.u.list->values[i].u.list->keys[n]) == "codec") - { - if(node.u.list->values[i].u.list->values[n].format == MPV_FORMAT_STRING) - track.codec = node.u.list->values[i].u.list->values[n].u.string; - } - } - fileInfo.tracks.push_back(track); - } + QList properties = { + {"media-title", MPV_FORMAT_STRING}, + {"track-list", MPV_FORMAT_NODE}, + {"chapter-list", MPV_FORMAT_NODE}, + // video params + {"video-codec", MPV_FORMAT_STRING}, + {"width", MPV_FORMAT_INT64}, + {"height", MPV_FORMAT_INT64}, + {"dwidth", MPV_FORMAT_INT64}, + {"dheight", MPV_FORMAT_INT64}, + {"video-params/aspect", MPV_FORMAT_INT64}, + // audio params + {"audio-codec", MPV_FORMAT_STRING}, + {"audio-params", MPV_FORMAT_NODE}, + // metadata + {"metadata", MPV_FORMAT_NODE} + }; + GetProperties(properties, [=] (QSharedPointer property_values) { + fileInfo.media_title = property_values->value("media-title").toString(); + fileInfo.tracks.clear(); + for (auto &rawTrack : property_values->value("track-list").toList()) { + auto rawTrackMap = rawTrack.toMap(); + Mpv::Track track; + track.id = rawTrackMap.value("id").toLongLong(); + track.type= rawTrackMap.value("type").toString(); + track.src_id = rawTrackMap.value("src-id").toLongLong(); + track.title = rawTrackMap.value("title").toString(); + track.lang = rawTrackMap.value("lang").toString(); + track.albumart = rawTrackMap.value("albumart").toBool(); + track._default = rawTrackMap.value("default").toBool(); + track.external = rawTrackMap.value("external").toBool(); + track.external_filename = rawTrackMap.value("external-filename").toString(); + track.codec = rawTrackMap.value("codec").toString(); + fileInfo.tracks.push_back(track); } - } - - emit trackListChanged(fileInfo.tracks); -} - -void MpvHandler::LoadChapters() -{ - fileInfo.chapters.clear(); - mpv_node node; - mpv_get_property(mpv, "chapter-list", MPV_FORMAT_NODE, &node); - if(node.format == MPV_FORMAT_NODE_ARRAY) - { - for(int i = 0; i < node.u.list->num; i++) - { - if(node.u.list->values[i].format == MPV_FORMAT_NODE_MAP) - { - Mpv::Chapter ch; - for(int n = 0; n < node.u.list->values[i].u.list->num; n++) - { - if(QString(node.u.list->values[i].u.list->keys[n]) == "title") - { - if(node.u.list->values[i].u.list->values[n].format == MPV_FORMAT_STRING) - ch.title = node.u.list->values[i].u.list->values[n].u.string; - } - else if(QString(node.u.list->values[i].u.list->keys[n]) == "time") - { - if(node.u.list->values[i].u.list->values[n].format == MPV_FORMAT_DOUBLE) - ch.time = (int)node.u.list->values[i].u.list->values[n].u.double_; - } - } - fileInfo.chapters.push_back(ch); - } + emit trackListChanged(fileInfo.tracks); + + fileInfo.chapters.clear(); + for (auto &rawChapter : property_values->value("chapter-list").toList()) { + auto rawChapterMap = rawChapter.toMap(); + Mpv::Chapter ch; + ch.title = rawChapterMap.value("title").toString(); + ch.time = rawChapterMap.value("time").toDouble(); + fileInfo.chapters.push_back(ch); } - } - emit chaptersChanged(fileInfo.chapters); -} - -void MpvHandler::LoadVideoParams() -{ - fileInfo.video_params.codec = mpv_get_property_string(mpv, "video-codec"); - mpv_get_property(mpv, "width", MPV_FORMAT_INT64, &fileInfo.video_params.width); - mpv_get_property(mpv, "height", MPV_FORMAT_INT64, &fileInfo.video_params.height); - mpv_get_property(mpv, "dwidth", MPV_FORMAT_INT64, &fileInfo.video_params.dwidth); - mpv_get_property(mpv, "dheight", MPV_FORMAT_INT64, &fileInfo.video_params.dheight); - // though this has become useless, removing it causes a segfault--no clue: - mpv_get_property(mpv, "video-params/aspect", MPV_FORMAT_INT64, &fileInfo.video_params.aspect); - - emit videoParamsChanged(fileInfo.video_params); -} - -void MpvHandler::LoadAudioParams() -{ - fileInfo.audio_params.codec = mpv_get_property_string(mpv, "audio-codec"); - mpv_node node; - mpv_get_property(mpv, "audio-params", MPV_FORMAT_NODE, &node); - if(node.format == MPV_FORMAT_NODE_MAP) - { - for(int i = 0; i < node.u.list->num; i++) - { - if(QString(node.u.list->keys[i]) == "samplerate") - { - if(node.u.list->values[i].format == MPV_FORMAT_INT64) - fileInfo.audio_params.samplerate = node.u.list->values[i].u.int64; - } - else if(QString(node.u.list->keys[i]) == "channel-count") - { - if(node.u.list->values[i].format == MPV_FORMAT_INT64) - fileInfo.audio_params.channels = node.u.list->values[i].u.int64; - } + emit chaptersChanged(fileInfo.chapters); + + fileInfo.video_params.codec = property_values->value("video-codec").toString(); + fileInfo.video_params.width = property_values->value("width").toLongLong(); + fileInfo.video_params.height = property_values->value("height").toLongLong(); + fileInfo.video_params.dwidth = property_values->value("dwidth").toLongLong(); + fileInfo.video_params.dheight = property_values->value("dheight").toLongLong(); + // though this has become useless, removing it causes a segfault--no clue: + fileInfo.video_params.aspect = property_values->value("video-params/aspect").toLongLong(); + emit videoParamsChanged(fileInfo.video_params); + + fileInfo.audio_params.codec = property_values->value("audio-codec").toString(); + fileInfo.audio_params.samplerate = property_values->value("audio-params").toList().first().toMap().value("samplerate").toLongLong(); + fileInfo.audio_params.channels = property_values->value("audio-params").toList().first().toMap().value("channel-count").toLongLong(); + emit audioParamsChanged(fileInfo.audio_params); + + fileInfo.metadata.clear(); + for (auto &rawMetadataKey : property_values->value("metadata").toMap().keys()) { + fileInfo.metadata[rawMetadataKey] = property_values->value("metadata").toMap().value(rawMetadataKey).toString(); } - } - - emit audioParamsChanged(fileInfo.audio_params); -} -void MpvHandler::LoadMetadata() -{ - fileInfo.metadata.clear(); - mpv_node node; - mpv_get_property(mpv, "metadata", MPV_FORMAT_NODE, &node); - if(node.format == MPV_FORMAT_NODE_MAP) - for(int n = 0; n < node.u.list->num; n++) - if(node.u.list->values[n].format == MPV_FORMAT_STRING) - fileInfo.metadata[node.u.list->keys[n]] = node.u.list->values[n].u.string; -} + emit fileInfoChanged(fileInfo); + Volume(volume); + Speed(speed); + Mute(mute); + }); +} + +void MpvHandler::LoadTracks() { + GetProperty("track-list", MPV_FORMAT_NODE, [=] (const QVariant &prop) { + QList rawTrackList = prop.toList(); + fileInfo.tracks.clear(); + for (auto &rawTrack : rawTrackList) { + auto rawTrackMap = rawTrack.toMap(); + Mpv::Track track; + track.id = rawTrackMap.value("id").toLongLong(); + track.type= rawTrackMap.value("type").toString(); + track.src_id = rawTrackMap.value("src-id").toLongLong(); + track.title = rawTrackMap.value("title").toString(); + track.lang = rawTrackMap.value("lang").toString(); + track.albumart = rawTrackMap.value("albumart").toBool(); + track._default = rawTrackMap.value("default").toBool(); + track.external = rawTrackMap.value("external").toBool(); + track.external_filename = rawTrackMap.value("external-filename").toString(); + track.codec = rawTrackMap.value("codec").toString(); + fileInfo.tracks.push_back(track); + } -void MpvHandler::LoadOsdSize() -{ - mpv_get_property(mpv, "osd-width", MPV_FORMAT_INT64, &osdWidth); - mpv_get_property(mpv, "osd-height", MPV_FORMAT_INT64, &osdHeight); + emit trackListChanged(fileInfo.tracks); + }); } -void MpvHandler::Command(const QStringList &strlist) -{ - // convert input string into char array - int len = strlist.length(); - char **data = new char*[len+1]; - for(int i = 0; i < len; ++i) - { - data[i] = new char[strlist[i].length()+1]; - memcpy(data[i], QByteArray(strlist[i].toUtf8()).begin(), strlist[i].length()+1); - } - data[len] = NULL; - AsyncCommand(const_cast(data)); - for(int i = 0; i < len; ++i) - delete [] data[i]; - delete [] data; - -// const QByteArray tmp = str.toUtf8(); -// mpv_command_string(mpv, tmp.constData()); +void MpvHandler::LoadVideoParams(std::function cb) { + QList properties{ + {"video-codec", MPV_FORMAT_STRING}, + {"width", MPV_FORMAT_INT64}, + {"height", MPV_FORMAT_INT64}, + {"dwidth", MPV_FORMAT_INT64}, + {"dheight", MPV_FORMAT_INT64}, + {"video-params/aspect", MPV_FORMAT_INT64} + }; + GetProperties(properties, [=](QSharedPointer property_values) { + fileInfo.video_params.codec = property_values->value("video-codec").toString(); + fileInfo.video_params.width = property_values->value("width").toLongLong(); + fileInfo.video_params.height = property_values->value("height").toLongLong(); + fileInfo.video_params.dwidth = property_values->value("dwidth").toLongLong(); + fileInfo.video_params.dheight = property_values->value("dheight").toLongLong(); + // though this has become useless, removing it causes a segfault--no clue: + fileInfo.video_params.aspect = property_values->value("video-params/aspect").toLongLong(); + emit videoParamsChanged(fileInfo.video_params); + cb(); + }); } void MpvHandler::SetOption(QString key, QString val) { QByteArray tmp1 = key.toUtf8(), tmp2 = val.toUtf8(); - HandleErrorCode(mpv_set_option_string(mpv, tmp1.constData(), tmp2.constData())); + HandleErrorCode(mpv_set_option_string(mpv, tmp1.constData(), tmp2.constData()), "set option"); } void MpvHandler::OpenFile(QString f) { emit fileChanging(time, fileInfo.length); - - const QByteArray tmp = f.toUtf8(); - const char *args[] = {"loadfile", tmp.constData(), NULL}; - Command(args); + Command({"loadfile", f}); } QString MpvHandler::PopulatePlaylist() @@ -1003,28 +930,98 @@ QString MpvHandler::PopulatePlaylist() return QString(); } -void MpvHandler::SetProperties() +void MpvHandler::Command(const QStringList &args, std::function on_event) { - Volume(volume); - Speed(speed); - Mute(mute); + const int *nargs = new int(args.length()); + char **cargs = new char*[*nargs+1]; + for (int i = 0; i < args.length(); i++) { + QString arg = args.at(i); + cargs[i] = new char[arg.length()+1]; + memcpy(cargs[i], arg.toUtf8().constData(), arg.length()); + cargs[i][arg.length()] = '\0'; + } + cargs[*nargs] = NULL; + const unsigned long id = reply_userdata++; + reply_callbacks[id] = [=](mpv_event *event) { + if (!HandleErrorCode(event->error, QString(args.join(" ")) + " command reply")) { + if (on_event != nullptr) { + on_event(event); + } + } + for (int i = 0; i < *nargs; i++) { + delete [] cargs[i]; + } + delete [] cargs; + }; + // qDebug() << "sendCommand " << args.join(" ") << " (" << id << ")"; + int error = mpv_command_async(mpv, id, (const char **)cargs); + if (HandleErrorCode(error, QString(args.join(" ")))) + { + mpv_event error_event{MPV_EVENT_NONE, error, id, nullptr}; + reply_callbacks[id](&error_event); + reply_callbacks.remove(id); + } } -void MpvHandler::AsyncCommand(const char *args[]) +void MpvHandler::ObserveProperty(const char *name, mpv_format format, std::function on_property) { - mpv_command_async(mpv, MPV_REPLY_COMMAND, args); + const unsigned long id = reply_userdata++; + reply_callbacks[id] = [=](mpv_event *event) { + if (!HandleErrorCode(event->error, QString("get prop %0").arg(name))) { + mpv_event_property *prop = (mpv_event_property*)event->data; + QVariant propValue = mpv_data_as_variant(prop->data, format); + on_property(propValue); + // qDebug() << "observedProperty " << name << "(" << id << ")"; + } + }; + // qDebug() << "observeProperty " << name << "(" << id << ")"; + HandleErrorCode(mpv_observe_property(mpv, id, name, format), QString("observe prop %0").arg(name)); } -void MpvHandler::Command(const char *args[]) +void MpvHandler::GetProperty(const char *name, mpv_format format, std::function on_property) { - HandleErrorCode(mpv_command(mpv, args)); + const unsigned long id = reply_userdata++; + reply_callbacks[id] = [=](mpv_event *event) { + if (!HandleErrorCode(event->error, QString("get prop %0").arg(name))) { + mpv_event_property *prop = (mpv_event_property*)event->data; + QVariant propValue = mpv_data_as_variant(prop->data, format); + on_property(propValue); + // qDebug() << "recvdProperty " << prop->name; + } + reply_callbacks.remove(id); + }; + // qDebug() << "getProperty " << name << "(" << id << ")"; + int error = mpv_get_property_async(mpv, id, name, format); + if (HandleErrorCode(error, QString("get prop %0").arg(name))) + { + QVariant prop = QVariant(); + on_property(prop); + reply_callbacks.remove(id); + } } -void MpvHandler::HandleErrorCode(int error_code) +void MpvHandler::GetProperties(const QList &properties, std::function)> on_event) +{ + QSharedPointer property_values(new QVariantMap()); + // qDebug() << "getProperties " << property_values->keys().join(","); + for (const Mpv::Property &prop : properties) + { + GetProperty(prop.name, prop.format, [=, n_properties = properties.length()](const QVariant &propValue) { + property_values->insert(prop.name, QVariant(propValue)); + if (property_values->keys().length() == n_properties) { + // qDebug() << "recvdProperties " << property_values->keys().join(","); + on_event(property_values); + } + }); + } +} + +bool MpvHandler::HandleErrorCode(int error_code, QString ctx) { if(error_code >= 0) - return; + return false; QString error = mpv_error_string(error_code); if(error != QString()) - emit messageSignal(error+"\n"); + emit messageSignal("["+ctx+"]"+error+"\n"); + return true; } diff --git a/src/mpvhandler.h b/src/mpvhandler.h index 661081d1..9f642528 100644 --- a/src/mpvhandler.h +++ b/src/mpvhandler.h @@ -4,6 +4,8 @@ #include #include #include +#include +#include #include #include @@ -44,7 +46,7 @@ friend class BakaEngine; int getOsdWidth() { return osdWidth; } int getOsdHeight() { return osdHeight; } - QString getMediaInfo(); + void getMediaInfo(std::function cb); protected: void initializeGL() Q_DECL_OVERRIDE; @@ -104,27 +106,23 @@ public slots: void ShowText(QString text, int duration = 4000); void LoadTracks(); - void LoadChapters(); - void LoadVideoParams(); - void LoadAudioParams(); - void LoadMetadata(); - void LoadOsdSize(); + void LoadVideoParams(std::function cb); - void Command(const QStringList &strlist); + void Command(const QStringList &strlist, std::function on_event = nullptr); void SetOption(QString key, QString val); protected slots: void OpenFile(QString); QString PopulatePlaylist(); void LoadFileInfo(); - void SetProperties(); - void AsyncCommand(const char *args[]); - void Command(const char *args[]); - void HandleErrorCode(int); + void ObserveProperty(const char *name, mpv_format format, std::function on_property); + void GetProperty(const char *name, mpv_format format, std::function on_property); + void GetProperties(const QList &properties, std::function)> on_event); + bool HandleErrorCode(int, QString ctx = "unknown"); private Q_SLOTS: - void on_mpv_events(); + void onMpvEvents(); void handle_mpv_event(mpv_event *event); void maybeUpdate(); @@ -209,6 +207,8 @@ private Q_SLOTS: mute = false; int osdWidth, osdHeight; + unsigned long long reply_userdata = 0; + QHash> reply_callbacks; }; #endif // MPVHANDLER_H diff --git a/src/mpvtypes.h b/src/mpvtypes.h index 646fdead..8f1b7ed8 100644 --- a/src/mpvtypes.h +++ b/src/mpvtypes.h @@ -6,6 +6,7 @@ #include #include #include +#include namespace Mpv { @@ -74,6 +75,12 @@ namespace Mpv QList tracks; // audio, video, and subs QList chapters; }; + + struct Property + { + const char *name; + mpv_format format; + }; } Q_DECLARE_METATYPE(Mpv::PlayState) // so we can pass it with signals & slots Q_DECLARE_METATYPE(Mpv::Chapter) @@ -81,6 +88,7 @@ Q_DECLARE_METATYPE(Mpv::Track) Q_DECLARE_METATYPE(Mpv::VideoParams) Q_DECLARE_METATYPE(Mpv::AudioParams) Q_DECLARE_METATYPE(Mpv::FileInfo) +Q_DECLARE_METATYPE(Mpv::Property) #endif // MPVTYPES_H diff --git a/src/overlayhandler.cpp b/src/overlayhandler.cpp index db5819a3..f39f35f9 100644 --- a/src/overlayhandler.cpp +++ b/src/overlayhandler.cpp @@ -59,10 +59,12 @@ void OverlayHandler::showInfoText(bool show) [=] { showInfoText(); }); } refresh_timer->start(OVERLAY_REFRESH_RATE); - showText(baka->mpv->getMediaInfo(), - QFont(Util::MonospaceFont(), - 14, QFont::Bold), QColor(0xFFFF00), - QPoint(20, 20), 0, OVERLAY_INFO); + baka->mpv->getMediaInfo([=](QString mediaInfo) { + showText(mediaInfo, + QFont(Util::MonospaceFont(), + 14, QFont::Bold), QColor(0xFFFF00), + QPoint(20, 20), 0, OVERLAY_INFO); + }); } else // hide media info { From e233fca6463ea4416ce67c439bb3e45a74be91e4 Mon Sep 17 00:00:00 2001 From: Daniel Clarke Date: Sat, 28 Jan 2023 12:45:30 -0500 Subject: [PATCH 13/19] Fix some command error feedback --- src/bakacommands.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bakacommands.cpp b/src/bakacommands.cpp index b16f2288..f6137cc3 100644 --- a/src/bakacommands.cpp +++ b/src/bakacommands.cpp @@ -52,7 +52,7 @@ void BakaEngine::BakaSh(QStringList &args) // }); } else - RequiresParameters("mpv"); + RequiresParameters("sh"); } void BakaEngine::BakaNew(QStringList &args) @@ -287,7 +287,7 @@ void BakaEngine::BakaPlaylist(QStringList &args) InvalidParameter(arg); } else - RequiresParameters("baka playlist"); + RequiresParameters("playlist"); } void BakaEngine::BakaJump(QStringList &args) From 28d7edb9f3591b34706b1c7c397ba56f100eaa8a Mon Sep 17 00:00:00 2001 From: Daniel Clarke Date: Sat, 28 Jan 2023 12:47:20 -0500 Subject: [PATCH 14/19] Use c++1y --- src/Baka-MPlayer.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Baka-MPlayer.pro b/src/Baka-MPlayer.pro index 81425ee8..f6ee7b56 100644 --- a/src/Baka-MPlayer.pro +++ b/src/Baka-MPlayer.pro @@ -11,7 +11,7 @@ greaterThan(QT_MAJOR_VERSION, 4): QT += widgets TARGET = baka-mplayer TEMPLATE = app -CONFIG += c++11 link_pkgconfig +CONFIG += c++1y link_pkgconfig isEmpty(DESTDIR):DESTDIR=build OBJECTS_DIR = $${DESTDIR}/obj From a894318acb7b9e48eae8ac82f64210de282de23a Mon Sep 17 00:00:00 2001 From: Daniel Clarke Date: Sat, 28 Jan 2023 12:47:42 -0500 Subject: [PATCH 15/19] Add mpv get command for debugging mpv props --- src/bakacommands.cpp | 19 +++++++++++++++++++ src/bakaengine.h | 10 ++++++++++ src/mpvhandler.cpp | 15 +++++---------- 3 files changed, 34 insertions(+), 10 deletions(-) diff --git a/src/bakacommands.cpp b/src/bakacommands.cpp index f6137cc3..22e57c27 100644 --- a/src/bakacommands.cpp +++ b/src/bakacommands.cpp @@ -32,6 +32,25 @@ void BakaEngine::BakaMpv(QStringList &args) RequiresParameters("mpv"); } +void BakaEngine::BakaGet(QStringList &args) +{ + if(!args.empty()) + { + QString arg = args.front(); + args.pop_front(); + if(args.empty()) + { + mpv->Command({"expand-properties", "print-text", QString("${%0}").arg(arg)}); + } + else + { + InvalidParameter(args.join(' ')); + } + } + else + RequiresParameters("get"); +} + void BakaEngine::BakaSh(QStringList &args) { if(!args.empty()) diff --git a/src/bakaengine.h b/src/bakaengine.h index fefad778..c64e2258 100644 --- a/src/bakaengine.h +++ b/src/bakaengine.h @@ -133,6 +133,15 @@ protected slots: } } }, + {"get", // command + {&BakaEngine::BakaGet, + { + // params description + QString(), tr("prints mpv property"), + QString() // advanced + } + } + }, {"sh", {&BakaEngine::BakaSh, { @@ -432,6 +441,7 @@ protected slots: }; // Baka Command Functions void BakaMpv(QStringList&); + void BakaGet(QStringList&); void BakaSh(QStringList&); void BakaNew(QStringList&); void BakaOpenLocation(QStringList&); diff --git a/src/mpvhandler.cpp b/src/mpvhandler.cpp index 2c9857b8..46970c54 100644 --- a/src/mpvhandler.cpp +++ b/src/mpvhandler.cpp @@ -371,16 +371,11 @@ void MpvHandler::maybeUpdate() // 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()->isVisible()) { - if (mpv_render_context_update(mpv_gl) & MPV_RENDER_UPDATE_FRAME) { - makeCurrent(); - paintGL(); - context()->swapBuffers(context()->surface()); - doneCurrent(); - } - } else { - update(); - } + makeCurrent(); + mpv_render_context_update(mpv_gl); + paintGL(); + context()->swapBuffers(context()->surface()); + doneCurrent(); } void MpvHandler::on_update(void *ctx) From b9f21b694c64dec7a04c7468b86902f1bfb42ffa Mon Sep 17 00:00:00 2001 From: Daniel Clarke Date: Sat, 28 Jan 2023 13:01:07 -0500 Subject: [PATCH 16/19] Apparently fix render API performance issues --- src/mpvhandler.cpp | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/src/mpvhandler.cpp b/src/mpvhandler.cpp index 46970c54..c668f17d 100644 --- a/src/mpvhandler.cpp +++ b/src/mpvhandler.cpp @@ -361,21 +361,10 @@ void MpvHandler::handle_mpv_event(mpv_event *event) } } -// Make Qt invoke mpv_render_context_render() to draw a new/updated video frame. void MpvHandler::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. - makeCurrent(); mpv_render_context_update(mpv_gl); - paintGL(); - context()->swapBuffers(context()->surface()); - doneCurrent(); + update(); } void MpvHandler::on_update(void *ctx) From 95c9835ec980e58b8ea13904d19fe4b62d7bf1d2 Mon Sep 17 00:00:00 2001 From: Daniel Clarke Date: Sat, 28 Jan 2023 15:56:28 -0500 Subject: [PATCH 17/19] Eliminate mpvhandler dependency on bakaengine --- src/bakacommands.cpp | 12 +++++------ src/bakaengine.cpp | 4 ++++ src/mpvhandler.cpp | 46 ++++++++++++++----------------------------- src/mpvhandler.h | 8 ++------ src/ui/mainwindow.cpp | 14 ++++++------- 5 files changed, 34 insertions(+), 50 deletions(-) diff --git a/src/bakacommands.cpp b/src/bakacommands.cpp index b03b53e0..6e15dc2b 100644 --- a/src/bakacommands.cpp +++ b/src/bakacommands.cpp @@ -177,9 +177,9 @@ void BakaEngine::Screenshot(bool subs) if(i != -1) dir.remove(0, i+1); if(subs) - mpv->ShowText(tr("Saved to \"%0\", with subs").arg(dir)); + overlay->showStatusText(tr("Saved to \"%0\", with subs").arg(dir)); else - mpv->ShowText(tr("Saved to \"%0\", without subs").arg(dir)); + overlay->showStatusText(tr("Saved to \"%0\", without subs").arg(dir)); } @@ -524,7 +524,7 @@ void BakaEngine::FitWindow(int percent, bool msg) // note: the above block is required because there is no setFrameGeometry function if(msg) - mpv->ShowText(tr("Fit Window: %0").arg(percent == 0 ? tr("To Current Size") : (QString::number(percent)+"%"))); + overlay->showStatusText(tr("Fit Window: %0").arg(percent == 0 ? tr("To Current Size") : (QString::number(percent)+"%"))); }); } @@ -584,7 +584,7 @@ void BakaEngine::BakaSpeed(QStringList &args) mpv->Speed(mpv->getSpeed()+arg.toDouble()); else mpv->Speed(arg.toDouble()); - mpv->ShowText(tr("Speed: %0x").arg(QString::number(mpv->getSpeed(), 'f', 2))); + overlay->showStatusText(tr("Speed: %0x").arg(QString::number(mpv->getSpeed(), 'f', 2))); } else InvalidParameter(args.join(' ')); @@ -599,7 +599,7 @@ void BakaEngine::BakaFullScreen(QStringList &args) { window->FullScreen(!window->isFullScreen()); if(window->isFullScreen()) - mpv->ShowText(tr("Press ESC or double-click to leave full screen")); + overlay->showStatusText(tr("Press ESC or double-click to leave full screen")); } else InvalidParameter(args.join(' ')); @@ -619,7 +619,7 @@ void BakaEngine::BakaHideAllControls(QStringList &args) { if(i->first == "hide_all_controls") { - mpv->ShowText(tr("Press %0 to show all controls again").arg(i.key())); + overlay->showStatusText(tr("Press %0 to show all controls again").arg(i.key())); break; } } diff --git a/src/bakaengine.cpp b/src/bakaengine.cpp index 6c6baf40..cd84a433 100644 --- a/src/bakaengine.cpp +++ b/src/bakaengine.cpp @@ -46,6 +46,10 @@ BakaEngine::BakaEngine(QObject *parent): { Print(msg, "update"); }); + connect(mpv, &MpvHandler::showText, + overlay, [=](QString msg, int duration) { + overlay->showStatusText(msg, duration); + }); } void BakaEngine::LoadSettings() diff --git a/src/mpvhandler.cpp b/src/mpvhandler.cpp index 06662857..b54a2d9d 100644 --- a/src/mpvhandler.cpp +++ b/src/mpvhandler.cpp @@ -5,7 +5,6 @@ #include #include -#include "bakaengine.h" #include "mpvtypes.h" #include "overlayhandler.h" #include "util.h" @@ -83,8 +82,7 @@ static inline QVariant mpv_data_as_variant(void *data, mpv_format format) { } MpvHandler::MpvHandler(QWidget *parent): - QOpenGLWidget(parent), - baka(nullptr) + QOpenGLWidget(parent) { // create mpv mpv = mpv_create(); @@ -126,9 +124,9 @@ MpvHandler::MpvHandler(QWidget *parent): ObserveProperty("core-idle", MPV_FORMAT_FLAG, [=](QVariant &prop) { bool coreIdle = prop.toBool(); if(coreIdle && playState == Mpv::Playing) - ShowText(tr("Buffering..."), 0); + emit showText(tr("Buffering..."), 0); else - ShowText(QString(), 0); + emit showText(QString(), 0); }); ObserveProperty("idle-active", MPV_FORMAT_FLAG, [=](QVariant &prop) { bool idleActive = prop.toBool(); @@ -144,7 +142,7 @@ MpvHandler::MpvHandler(QWidget *parent): if(pause) { setPlayState(Mpv::Paused); - ShowText(QString(), 0); + emit showText(QString(), 0); } else setPlayState(Mpv::Playing); @@ -152,9 +150,9 @@ MpvHandler::MpvHandler(QWidget *parent): ObserveProperty("paused-for-cache", MPV_FORMAT_FLAG, [=](QVariant &prop) { bool pausedForCache = prop.toBool(); if(pausedForCache && playState == Mpv::Playing) - ShowText(tr("Your network is slow or stuck, please wait a bit"), 0); + emit showText(tr("Your network is slow or stuck, please wait a bit"), 0); else - ShowText(QString(), 0); + emit showText(QString(), 0); }); // setup callback event handling @@ -183,12 +181,10 @@ MpvHandler::~MpvHandler() mpv_terminate_destroy(mpv); } -void MpvHandler::Initialize(BakaEngine *baka) +void MpvHandler::Initialize() { if(mpv_initialize(mpv) < 0) throw "Could not initialize mpv"; - - this->baka = baka; } void MpvHandler::initializeGL() @@ -344,7 +340,7 @@ void MpvHandler::handle_mpv_event(mpv_event *event) break; case MPV_EVENT_END_FILE: if(playState == Mpv::Loaded) - ShowText(tr("File couldn't be opened")); + emit showText(tr("File couldn't be opened")); setPlayState(Mpv::Stopped); break; case MPV_EVENT_SHUTDOWN: @@ -426,7 +422,7 @@ QString MpvHandler::LoadPlaylist(QString f) QFileInfo fi(f); if(!fi.exists()) // file doesn't exist { - ShowText(tr("File does not exist")); // tell the user + emit showText(tr("File does not exist")); // tell the user return QString(); // don't do anything more } else if(fi.isDir()) // if directory @@ -465,7 +461,7 @@ bool MpvHandler::PlayFile(QString f) } else { - ShowText(tr("File no longer exists")); // tell the user + emit showText(tr("File no longer exists")); // tell the user return false; } } @@ -611,7 +607,7 @@ void MpvHandler::Volume(int level, bool osd) { mpv_set_property_async(mpv, reply_userdata++, "volume", MPV_FORMAT_DOUBLE, &v); if(osd) - ShowText(tr("Volume: %0%").arg(QString::number(level))); + emit showText(tr("Volume: %0%").arg(QString::number(level))); } else { @@ -683,7 +679,7 @@ void MpvHandler::AddSubtitleTrack(QString f) for(auto &track : old) // remove the old tracks in current current.removeOne(track); Mpv::Track &track = current.first(); - ShowText(QString("%0: %1 (%2)").arg(QString::number(track.id), track.title, track.external ? "external" : track.lang)); + emit showText(QString("%0: %1 (%2)").arg(QString::number(track.id), track.title, track.external ? "external" : track.lang)); } void MpvHandler::AddAudioTrack(QString f) @@ -697,7 +693,7 @@ void MpvHandler::AddAudioTrack(QString f) for(auto &track : old) current.removeOne(track); Mpv::Track &track = current.first(); - ShowText(QString("%0: %1 (%2)").arg(QString::number(track.id), track.title, track.external ? "external" : track.lang)); + emit showText(QString("%0: %1 (%2)").arg(QString::number(track.id), track.title, track.external ? "external" : track.lang)); } void MpvHandler::ShowSubtitles(bool b) @@ -713,7 +709,7 @@ void MpvHandler::SubtitleScale(double scale, bool relative) void MpvHandler::Deinterlace(bool deinterlace) { HandleErrorCode(mpv_set_property_string(mpv, "deinterlace", deinterlace ? "yes" : "auto"), "deinterlace"); - ShowText(tr("Deinterlacing: %0").arg(deinterlace ? tr("enabled") : tr("disabled"))); + emit showText(tr("Deinterlacing: %0").arg(deinterlace ? tr("enabled") : tr("disabled"))); } void MpvHandler::Interpolate(bool interpolate) @@ -731,7 +727,7 @@ void MpvHandler::Interpolate(bool interpolate) } setVo(vos.join(',')); SetOption("vo", vo); - ShowText(tr("Motion Interpolation: %0").arg(interpolate ? tr("enabled") : tr("disabled"))); + emit showText(tr("Motion Interpolation: %0").arg(interpolate ? tr("enabled") : tr("disabled"))); }); } @@ -748,18 +744,6 @@ void MpvHandler::MsgLevel(QString level) setMsgLevel(level); } -void MpvHandler::ShowText(QString text, int duration) -{ - baka->overlay->showStatusText(text, duration); - /* - const QByteArray tmp1 = text.toUtf8(), - tmp2 = QString::number(duration).toUtf8(), - tmp3 = QString::number(level).toUtf8(); - const char *args[] = {"show_text", tmp1.constData(), tmp2.constData(), tmp3.constData(), NULL}; - Command(args); - */ -} - void MpvHandler::LoadFileInfo() { QList properties = { diff --git a/src/mpvhandler.h b/src/mpvhandler.h index 2f97bb9f..5b69aee5 100644 --- a/src/mpvhandler.h +++ b/src/mpvhandler.h @@ -14,8 +14,6 @@ #define MPV_REPLY_COMMAND 1 #define MPV_REPLY_PROPERTY 2 -class BakaEngine; - class MpvHandler Q_DECL_FINAL: public QOpenGLWidget { friend class BakaEngine; @@ -24,7 +22,7 @@ friend class BakaEngine; explicit MpvHandler(QWidget *parent = 0); ~MpvHandler(); - void Initialize(BakaEngine *baka); + void Initialize(); const Mpv::FileInfo &getFileInfo() { return fileInfo; } Mpv::PlayState getPlayState() { return playState; } QString getFile() { return file; } @@ -103,8 +101,6 @@ public slots: void MsgLevel(QString level); - void ShowText(QString text, int duration = 4000); - void LoadTracks(); void LoadVideoParams(std::function cb); @@ -173,12 +169,12 @@ private Q_SLOTS: void subtitleVisibilityChanged(bool); void muteChanged(bool); + void showText(QString m, int duration = 4000); void messageSignal(QString m); private: static void on_update(void *ctx); - BakaEngine *baka; mpv_handle *mpv; mpv_render_context *mpv_gl; diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index aba8f10f..77d49954 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -359,7 +359,7 @@ MainWindow::MainWindow(QWidget *parent): else if(!mpv->getSubtitleVisibility()) mpv->ShowSubtitles(true); mpv->Sid(track.id); - mpv->ShowText(QString("%0 %1: %2 (%3)").arg(tr("Sub"), QString::number(track.id), track.title, track.lang + (track.external ? "*" : ""))); + baka->overlay->showStatusText(QString("%0 %1: %2 (%3)").arg(tr("Sub"), QString::number(track.id), track.title, track.lang + (track.external ? "*" : ""))); }); } else if(track.type == "audio") @@ -371,7 +371,7 @@ MainWindow::MainWindow(QWidget *parent): if(mpv->getAid() != track.id) // don't allow selection of the same track { mpv->Aid(track.id); - mpv->ShowText(QString("%0 %1: %2 (%3)").arg(tr("Audio"), QString::number(track.id), track.title, track.lang)); + baka->overlay->showStatusText(QString("%0 %1: %2 (%3)").arg(tr("Audio"), QString::number(track.id), track.title, track.lang)); } else action->setChecked(true); // recheck the track @@ -499,7 +499,7 @@ MainWindow::MainWindow(QWidget *parent): switch(playState) { case Mpv::Loaded: - baka->mpv->ShowText("Loading...", 0); + baka->overlay->showStatusText("Loading...", 0); break; case Mpv::Started: @@ -617,7 +617,7 @@ MainWindow::MainWindow(QWidget *parent): if(last != speed) { if(init) - mpv->ShowText(tr("Speed: %0x").arg(QString::number(speed))); + baka->overlay->showStatusText(tr("Speed: %0x").arg(QString::number(speed))); if(speed <= 0.25) ui->action_Decrease->setEnabled(false); else @@ -664,7 +664,7 @@ MainWindow::MainWindow(QWidget *parent): if(ui->actionShow_Subtitles->isEnabled()) ui->actionShow_Subtitles->setChecked(b); if(init) - mpv->ShowText(b ? tr("Subtitles visible") : tr("Subtitles hidden")); + baka->overlay->showStatusText(b ? tr("Subtitles visible") : tr("Subtitles hidden")); }); connect(mpv, &MpvHandler::muteChanged, @@ -674,7 +674,7 @@ MainWindow::MainWindow(QWidget *parent): ui->muteButton->setIcon(QIcon(":/img/default_mute.svg")); else ui->muteButton->setIcon(QIcon(":/img/default_unmute.svg")); - mpv->ShowText(b ? tr("Muted") : tr("Unmuted")); + baka->overlay->showStatusText(b ? tr("Muted") : tr("Unmuted")); }); connect(mpv, &MpvHandler::voChanged, @@ -890,7 +890,7 @@ void MainWindow::Load(QString file) thumbnail_toolbar->addButton(next_toolbutton); #endif baka->LoadSettings(); - mpv->Initialize(baka); + mpv->Initialize(); mpv->LoadFile(file); } From c33cf0020ca8ce6f54e68f97293b93bb9d54f717 Mon Sep 17 00:00:00 2001 From: Daniel Clarke Date: Sun, 29 Jan 2023 17:24:22 -0500 Subject: [PATCH 18/19] Don't connect dimDialog if null --- src/ui/mainwindow.cpp | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 77d49954..f06af4ab 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -234,15 +234,17 @@ MainWindow::MainWindow(QWidget *parent): }); // dimDialog - connect(baka->dimDialog, &DimDialog::visbilityChanged, - baka->dimDialog, [=](bool dim) - { - ui->action_Dim_Lights->setChecked(dim); - if(dim) - Util::SetAlwaysOnTop(winId(), true); - else if(onTop == "never" || (onTop == "playing" && mpv->getPlayState() > 0)) - Util::SetAlwaysOnTop(winId(), false); - }); + if (baka->dimDialog) { + connect(baka->dimDialog, &DimDialog::visbilityChanged, + baka->dimDialog, [=](bool dim) + { + ui->action_Dim_Lights->setChecked(dim); + if(dim) + Util::SetAlwaysOnTop(winId(), true); + else if(onTop == "never" || (onTop == "playing" && mpv->getPlayState() > 0)) + Util::SetAlwaysOnTop(winId(), false); + }); + } // mpv From 327d643d40b4b6ddfb2efce9682c5244a4144d43 Mon Sep 17 00:00:00 2001 From: Daniel Clarke Date: Sun, 29 Jan 2023 18:16:54 -0500 Subject: [PATCH 19/19] Fix missing include for windows build --- src/ui/updatedialog.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ui/updatedialog.cpp b/src/ui/updatedialog.cpp index 4e54bb8f..5dd4ed35 100644 --- a/src/ui/updatedialog.cpp +++ b/src/ui/updatedialog.cpp @@ -6,6 +6,10 @@ #include +#if defined(Q_OS_WIN) +#include "util.h" +#endif + UpdateDialog::UpdateDialog(BakaEngine *baka, QWidget *parent) : QDialog(parent), ui(new Ui::UpdateDialog),