Skip to content
Extraits de code Groupes Projets
Vérifiée Valider 4f95b65f rédigé par Kubat's avatar Kubat
Parcourir les fichiers

UI: Handle MPV events + set locale correctly for MPV

parent a6a50920
Aucune branche associée trouvée
Aucune étiquette associée trouvée
1 requête de fusion!15Video playback with mpv
...@@ -26,22 +26,35 @@ MpvContainer::MpvContainer() ...@@ -26,22 +26,35 @@ MpvContainer::MpvContainer()
mpv_set_option_string(mpv, "input-default-bindings", "no"); mpv_set_option_string(mpv, "input-default-bindings", "no");
mpv_set_option_string(mpv, "input-vo-keyboard", "no"); mpv_set_option_string(mpv, "input-vo-keyboard", "no");
mpv_request_log_messages(mpv, "info"); mpv_request_log_messages(mpv, "info");
mpv_observe_property(mpv, 0, "pause", MPV_FORMAT_FLAG);
mpv_observe_property(mpv, 0, "duration", MPV_FORMAT_DOUBLE);
mpv_observe_property(mpv, 0, "time-pos", MPV_FORMAT_DOUBLE); mpv_observe_property(mpv, 0, "time-pos", MPV_FORMAT_DOUBLE);
connect(this, &MpvContainer::mpvEvent, this, &MpvContainer::onMpvEvent, Qt::QueuedConnection); connect(this, &MpvContainer::mpvEvent, this, &MpvContainer::onMpvEvent, Qt::QueuedConnection);
mpv_set_wakeup_callback(mpv, &MpvContainer::mpvEventWakeUpCB, this); mpv_set_wakeup_callback(mpv, &MpvContainer::mpvEventWakeUpCB, this);
if (mpv_initialize(mpv) < 0) if (int rc = mpv_initialize(mpv); rc < 0) {
printMpvError(rc);
throw std::runtime_error("Failed to initialize the mpv context"); throw std::runtime_error("Failed to initialize the mpv context");
}
} }
void void
MpvContainer::registerMpvTimeCallback(void (*callback)(double)) noexcept MpvContainer::registerMpvTimeCallback(void (*callback)(double)) noexcept
{ {
if (mpv_time_callback) if (mpvTimeCallback)
qWarning() << "Override a previous mpv callback, was" << mpv_time_callback qWarning() << "Override a previous mpv callback, was" << mpvTimeCallback
<< "and now will be" << callback; << "and now will be" << callback;
mpv_time_callback = callback; mpvTimeCallback = callback;
}
void
MpvContainer::registerMpvDurationCallback(void (*callback)(double)) noexcept
{
if (mpvDurationCallback)
qWarning() << "Override a previous mpv callback, was" << mpvDurationCallback
<< "and now will be" << callback;
mpvDurationCallback = callback;
} }
void void
...@@ -49,6 +62,7 @@ MpvContainer::closeMpv() noexcept ...@@ -49,6 +62,7 @@ MpvContainer::closeMpv() noexcept
{ {
if (mpv) { if (mpv) {
registerMpvTimeCallback(nullptr); registerMpvTimeCallback(nullptr);
registerMpvDurationCallback(nullptr);
mpv_handle *tmp_mpv = mpv; mpv_handle *tmp_mpv = mpv;
mpv = nullptr; // Stop all other callbacks here mpv = nullptr; // Stop all other callbacks here
mpv_destroy(tmp_mpv); mpv_destroy(tmp_mpv);
...@@ -65,17 +79,24 @@ MpvContainer::handleMpvEvent(mpv_event *event) noexcept ...@@ -65,17 +79,24 @@ MpvContainer::handleMpvEvent(mpv_event *event) noexcept
{ {
// Declare here variables that can be used in the switch-case statements // Declare here variables that can be used in the switch-case statements
qint64 w, h; qint64 w, h;
double time;
union { union {
mpv_event_log_message *msg; mpv_event_log_message *msg;
mpv_event_property *prop; mpv_event_property *prop;
}; };
auto checkProp = [](mpv_event_property *prop, const std::string &str,
int format) noexcept -> bool {
return (prop->name == str) && (prop->format == format);
};
switch (event->event_id) { switch (event->event_id) {
case MPV_EVENT_SHUTDOWN: case MPV_EVENT_SHUTDOWN:
closeMpv(); closeMpv();
break; break;
case MPV_EVENT_VIDEO_RECONFIG: case MPV_EVENT_VIDEO_RECONFIG:
// TODO: Those are sync calls, prefer async calls
if (mpv_get_property(mpv, "dwidth", MPV_FORMAT_INT64, &w) >= 0 && if (mpv_get_property(mpv, "dwidth", MPV_FORMAT_INT64, &w) >= 0 &&
mpv_get_property(mpv, "dheight", MPV_FORMAT_INT64, &h) >= 0 && (w > 0 && h > 0)) { mpv_get_property(mpv, "dheight", MPV_FORMAT_INT64, &h) >= 0 && (w > 0 && h > 0)) {
qDebug() << "Reconfigure video to" << w << "x" << h; qDebug() << "Reconfigure video to" << w << "x" << h;
...@@ -89,14 +110,37 @@ MpvContainer::handleMpvEvent(mpv_event *event) noexcept ...@@ -89,14 +110,37 @@ MpvContainer::handleMpvEvent(mpv_event *event) noexcept
case MPV_EVENT_PROPERTY_CHANGE: case MPV_EVENT_PROPERTY_CHANGE:
prop = reinterpret_cast<mpv_event_property *>(event->data); prop = reinterpret_cast<mpv_event_property *>(event->data);
if (prop->name == "time-pos"s) { if (checkProp(prop, "time-pos"s, MPV_FORMAT_DOUBLE) && mpvTimeCallback) {
if (prop->format == MPV_FORMAT_DOUBLE) { time = *reinterpret_cast<double *>(prop->data);
double time = *reinterpret_cast<double *>(prop->data); mpvTimeCallback(time);
qDebug() << "Playback time:" << time; }
} else {
qCritical() << "Got playback time but not a double!"; else if (checkProp(prop, "duration"s, MPV_FORMAT_DOUBLE) && mpvDurationCallback) {
} time = *reinterpret_cast<double *>(prop->data);
mpvDurationCallback(time);
} }
else if (checkProp(prop, "pause"s, MPV_FORMAT_FLAG)) {
isPlaybackPaused = *reinterpret_cast<bool *>(prop->data);
emit mpvPlaybackToggled(!isPlaybackPaused);
}
break;
case MPV_EVENT_PAUSE:
isPlaybackPaused = true;
break;
case MPV_EVENT_UNPAUSE:
isPlaybackPaused = false;
break;
case MPV_EVENT_START_FILE:
qDebug() << "MPV: Begin of file";
break;
case MPV_EVENT_END_FILE:
qDebug() << "MPV: Reached end of file!";
break; break;
// Explicitly ignored // Explicitly ignored
...@@ -104,14 +148,10 @@ MpvContainer::handleMpvEvent(mpv_event *event) noexcept ...@@ -104,14 +148,10 @@ MpvContainer::handleMpvEvent(mpv_event *event) noexcept
case MPV_EVENT_GET_PROPERTY_REPLY: case MPV_EVENT_GET_PROPERTY_REPLY:
case MPV_EVENT_SET_PROPERTY_REPLY: case MPV_EVENT_SET_PROPERTY_REPLY:
case MPV_EVENT_COMMAND_REPLY: case MPV_EVENT_COMMAND_REPLY:
case MPV_EVENT_START_FILE:
case MPV_EVENT_END_FILE:
case MPV_EVENT_FILE_LOADED: case MPV_EVENT_FILE_LOADED:
case MPV_EVENT_TRACKS_CHANGED: case MPV_EVENT_TRACKS_CHANGED:
case MPV_EVENT_TRACK_SWITCHED: case MPV_EVENT_TRACK_SWITCHED:
case MPV_EVENT_IDLE: case MPV_EVENT_IDLE:
case MPV_EVENT_PAUSE:
case MPV_EVENT_UNPAUSE:
case MPV_EVENT_TICK: case MPV_EVENT_TICK:
case MPV_EVENT_SCRIPT_INPUT_DISPATCH: case MPV_EVENT_SCRIPT_INPUT_DISPATCH:
case MPV_EVENT_CLIENT_MESSAGE: case MPV_EVENT_CLIENT_MESSAGE:
...@@ -131,8 +171,46 @@ MpvContainer::onMpvEvent() noexcept ...@@ -131,8 +171,46 @@ MpvContainer::onMpvEvent() noexcept
{ {
while (mpv) { while (mpv) {
mpv_event *event = mpv_wait_event(mpv, 0); mpv_event *event = mpv_wait_event(mpv, 0);
if (event->event_id == MPV_EVENT_NONE) if (event == nullptr || event->event_id == MPV_EVENT_NONE)
break; break;
handleMpvEvent(event); handleMpvEvent(event);
} }
} }
void
MpvContainer::loadFile(const QString &filename) noexcept
{
const QByteArray c_filename = filename.toUtf8();
const char *args[] = { "loadfile", c_filename.data(), nullptr };
printMpvError(mpv_command_async(mpv, 0, args));
}
void
MpvContainer::printMpvError(int rc) const noexcept
{
if (rc == MPV_ERROR_SUCCESS)
return;
qCritical() << "MPV error:" << mpv_error_string(rc);
}
void
MpvContainer::mpvPlay() noexcept
{
if (isPlaybackPaused)
mpvTogglePlayback();
}
void
MpvContainer::mpvPause() noexcept
{
if (!isPlaybackPaused)
mpvTogglePlayback();
}
void
MpvContainer::mpvTogglePlayback() noexcept
{
const char *cmd[] = { "cycle", "pause", "up", nullptr };
printMpvError(mpv_command_async(mpv, 0, cmd));
}
...@@ -18,27 +18,39 @@ class MpvContainer : public QWidget { ...@@ -18,27 +18,39 @@ class MpvContainer : public QWidget {
VIVY_UNMOVABLE_OBJECT(MpvContainer) VIVY_UNMOVABLE_OBJECT(MpvContainer)
private: private:
bool isPlaybackPaused{ true };
mpv_handle *mpv{ nullptr }; mpv_handle *mpv{ nullptr };
void (*mpv_time_callback)(double){ nullptr }; void (*mpvTimeCallback)(double){ nullptr };
void (*mpvDurationCallback)(double){ nullptr };
public: public:
explicit MpvContainer(); explicit MpvContainer();
~MpvContainer() noexcept override; ~MpvContainer() noexcept override;
void loadFile(const QString &) noexcept;
// Register a callback for time change, don't use Qt's signals for that. // Register a callback for time change, don't use Qt's signals for that.
void registerMpvTimeCallback(void (*)(double)) noexcept; void registerMpvTimeCallback(void (*)(double)) noexcept;
void registerMpvDurationCallback(void (*)(double)) noexcept;
private: private:
void handleMpvEvent(mpv_event *) noexcept; void handleMpvEvent(mpv_event *) noexcept;
void closeMpv() noexcept; void closeMpv() noexcept;
void printMpvError(int) const noexcept;
// Must be static to be passed as a function ptr // Must be static to be passed as a function ptr
static void mpvEventWakeUpCB(void *) noexcept; static void mpvEventWakeUpCB(void *) noexcept;
public slots:
void mpvPlay() noexcept;
void mpvPause() noexcept;
void mpvTogglePlayback() noexcept;
private slots: private slots:
void onMpvEvent() noexcept; void onMpvEvent() noexcept;
signals: signals:
void mpvEvent(); void mpvEvent();
void mpvPlaybackToggled(bool isPlaying);
}; };
} }
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include <QtGlobal> #include <QtGlobal>
#include <QIcon> #include <QIcon>
#include <QFontDatabase> #include <QFontDatabase>
#include <locale>
using namespace Vivy; using namespace Vivy;
...@@ -34,6 +35,9 @@ VivyApplication::setTheme(Theme theme) noexcept ...@@ -34,6 +35,9 @@ VivyApplication::setTheme(Theme theme) noexcept
int int
VivyApplication::exec() noexcept VivyApplication::exec() noexcept
{ {
// For MPV
std::setlocale(LC_NUMERIC, "C");
// Add fonts // Add fonts
fontIdMonospace = QFontDatabase::addApplicationFont(":/fonts/FiraCode-Regular.ttf"); fontIdMonospace = QFontDatabase::addApplicationFont(":/fonts/FiraCode-Regular.ttf");
fontIdMonospaceBold = QFontDatabase::addApplicationFont(":/fonts/FiraCode-Bold.ttf"); fontIdMonospaceBold = QFontDatabase::addApplicationFont(":/fonts/FiraCode-Bold.ttf");
......
0% Chargement en cours ou .
You are about to add 0 people to the discussion. Proceed with caution.
Terminez d'abord l'édition de ce message.
Veuillez vous inscrire ou vous pour commenter