diff --git a/src/UI/DocumentViews/MpvContainer.cc b/src/UI/DocumentViews/MpvContainer.cc new file mode 100644 index 0000000000000000000000000000000000000000..26890478fca5ca99cacdc16db235b5d48147a5ea --- /dev/null +++ b/src/UI/DocumentViews/MpvContainer.cc @@ -0,0 +1,101 @@ +#include "MpvContainer.hh" + +#include <mpv/client.h> + +using namespace Vivy; +using namespace std::string_literals; + +void +MpvContainer::mpvEventWakeUpCB(void *user) +{ + MpvContainer *container = reinterpret_cast<MpvContainer *>(user); + emit container->mpvEvent(); +} + +MpvContainer::MpvContainer() + : mpv(mpv_create()) +{ + if (mpv == nullptr) + throw std::runtime_error("Failed to create the MPV context"); + + setAttribute(Qt::WA_DontCreateNativeAncestors); + setAttribute(Qt::WA_NativeWindow); + + quint64 wid = winId(); + mpv_set_option(mpv, "wid", MPV_FORMAT_INT64, &wid); + mpv_set_option_string(mpv, "input-default-bindings", "no"); + mpv_set_option_string(mpv, "input-vo-keyboard", "no"); + mpv_request_log_messages(mpv, "info"); + mpv_observe_property(mpv, 0, "time-pos", MPV_FORMAT_DOUBLE); + + connect(this, &MpvContainer::mpvEvent, this, &MpvContainer::onMpvEvent, Qt::QueuedConnection); + mpv_set_wakeup_callback(mpv, &MpvContainer::mpvEventWakeUpCB, this); + + if (mpv_initialize(mpv) < 0) + throw std::runtime_error("Failed to initialize the mpv context"); +} + +MpvContainer::~MpvContainer() noexcept +{ + // TODO: Do that in a private method + if (mpv) { + mpv_handle *tmp_mpv = mpv; + mpv = nullptr; // Stop all other callbacks here + mpv_destroy(tmp_mpv); + } +} + +void +MpvContainer::handleMpvEvent(mpv_event *event) noexcept +{ + // Declare here variables that can be used in the switch-case statements + qint64 w, h; + union { + mpv_event_log_message *msg; + mpv_event_property *prop; + mpv_handle *tmp_mpv; + }; + + switch (event->event_id) { + case MPV_EVENT_SHUTDOWN: + tmp_mpv = mpv; + mpv = nullptr; + mpv_destroy(mpv); + break; + + case MPV_EVENT_VIDEO_RECONFIG: + 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)) { + qDebug() << "Reconfigure video to" << w << "x" << h; + } + break; + + case MPV_EVENT_LOG_MESSAGE: + msg = reinterpret_cast<mpv_event_log_message *>(event->data); + qDebug() << "MPV message: [" << msg->prefix << "]" << msg->level << ":" << msg->text; + break; + + case MPV_EVENT_PROPERTY_CHANGE: + prop = reinterpret_cast<mpv_event_property *>(event->data); + if (prop->name == "time-pos"s) { + if (prop->format == MPV_FORMAT_DOUBLE) { + double time = *reinterpret_cast<double *>(prop->data); + qDebug() << "Playback time:" << time; + } else { + qCritical() << "Got playback time but not a double!"; + } + } + break; + } +} + +void +MpvContainer::onMpvEvent() noexcept +{ + while (mpv) { + mpv_event *event = mpv_wait_event(mpv, 0); + if (event->event_id == MPV_EVENT_NONE) + break; + handleMpvEvent(event); + } +} diff --git a/src/UI/DocumentViews/MpvContainer.hh b/src/UI/DocumentViews/MpvContainer.hh index 063670c93782b45c2050a38c1623eb14b1483eee..bda0f585818e74e0c7d5bc1a528dd7888f04a056 100644 --- a/src/UI/DocumentViews/MpvContainer.hh +++ b/src/UI/DocumentViews/MpvContainer.hh @@ -6,21 +6,31 @@ #include "../../Lib/Utils.hh" +extern "C" { struct mpv_handle; +struct mpv_event; +} namespace Vivy { class MpvContainer : public QWidget { + Q_OBJECT VIVY_UNMOVABLE_OBJECT(MpvContainer) private: - quint64 wid{ 0 }; mpv_handle *mpv{ nullptr }; public: - explicit MpvContainer() noexcept; + explicit MpvContainer(); ~MpvContainer() noexcept override; +private: + void handleMpvEvent(mpv_event *) noexcept; + static void mpvEventWakeUpCB(void *); // Must be static for function ptr + +private slots: + void onMpvEvent() noexcept; + signals: void mpvEvent(); };