diff options
Diffstat (limited to 'DOCS/client_api_examples/qt_opengl/mpvwidget.cpp')
-rw-r--r-- | DOCS/client_api_examples/qt_opengl/mpvwidget.cpp | 128 |
1 files changed, 128 insertions, 0 deletions
diff --git a/DOCS/client_api_examples/qt_opengl/mpvwidget.cpp b/DOCS/client_api_examples/qt_opengl/mpvwidget.cpp new file mode 100644 index 0000000000..2f3bf7e200 --- /dev/null +++ b/DOCS/client_api_examples/qt_opengl/mpvwidget.cpp @@ -0,0 +1,128 @@ +#include "mpvwidget.h" +#include <stdexcept> +#include <QtGui/QOpenGLContext> +#include <QtCore/QMetaObject> + +static void wakeup(void *ctx) +{ + QMetaObject::invokeMethod((MpvWidget*)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 NULL; + return (void *)glctx->getProcAddress(QByteArray(name)); +} + +MpvWidget::MpvWidget(QWidget *parent, Qt::WindowFlags f) + : QOpenGLWidget(parent, f) +{ + mpv = mpv::qt::Handle::FromRawHandle(mpv_create()); + if (!mpv) + throw std::runtime_error("could not create mpv context"); + + mpv_set_option_string(mpv, "terminal", "yes"); + mpv_set_option_string(mpv, "msg-level", "all=v"); + if (mpv_initialize(mpv) < 0) + throw std::runtime_error("could not initialize mpv context"); + + // Make use of the MPV_SUB_API_OPENGL_CB API. + mpv::qt::set_option_variant(mpv, "vo", "opengl-cb"); + + // Request hw decoding, just for testing. + mpv::qt::set_option_variant(mpv, "hwdec", "auto"); + + mpv_gl = (mpv_opengl_cb_context *)mpv_get_sub_api(mpv, MPV_SUB_API_OPENGL_CB); + if (!mpv_gl) + throw std::runtime_error("OpenGL not compiled in"); + mpv_opengl_cb_set_update_callback(mpv_gl, MpvWidget::on_update, (void *)this); + connect(this, SIGNAL(frameSwapped()), SLOT(swapped())); + + mpv_observe_property(mpv, 0, "duration", MPV_FORMAT_DOUBLE); + mpv_observe_property(mpv, 0, "time-pos", MPV_FORMAT_DOUBLE); + mpv_set_wakeup_callback(mpv, wakeup, this); +} + +MpvWidget::~MpvWidget() +{ + if (mpv_gl) + mpv_opengl_cb_set_update_callback(mpv_gl, NULL, NULL); + // Until this call is done, we need to make sure the player remains + // alive. This is done implicitly with the mpv::qt::Handle instance + // in this class. + mpv_opengl_cb_uninit_gl(mpv_gl); +} + +void MpvWidget::command(const QVariant& params) +{ + mpv::qt::command_variant(mpv, params); +} + +void MpvWidget::setProperty(const QString& name, const QVariant& value) +{ + mpv::qt::set_property_variant(mpv, name, value); +} + +QVariant MpvWidget::getProperty(const QString &name) const +{ + return mpv::qt::get_property_variant(mpv, name); +} + +void MpvWidget::initializeGL() +{ + int r = mpv_opengl_cb_init_gl(mpv_gl, NULL, get_proc_address, NULL); + if (r < 0) + throw std::runtime_error("could not initialize OpenGL"); +} + +void MpvWidget::paintGL() +{ + mpv_opengl_cb_draw(mpv_gl, QOpenGLContext::currentContext()->defaultFramebufferObject(), width(), -height()); +} + +void MpvWidget::swapped() +{ + mpv_opengl_cb_report_flip(mpv_gl, 0); +} + +void MpvWidget::on_mpv_events() +{ + // Process all events, until the event queue is empty. + while (mpv) { + mpv_event *event = mpv_wait_event(mpv, 0); + if (event->event_id == MPV_EVENT_NONE) { + break; + } + handle_mpv_event(event); + } +} + +void MpvWidget::handle_mpv_event(mpv_event *event) +{ + switch (event->event_id) { + case MPV_EVENT_PROPERTY_CHANGE: { + mpv_event_property *prop = (mpv_event_property *)event->data; + if (strcmp(prop->name, "time-pos") == 0) { + if (prop->format == MPV_FORMAT_DOUBLE) { + double time = *(double *)prop->data; + Q_EMIT positionChanged(time); + } + } else if (strcmp(prop->name, "duration") == 0) { + if (prop->format == MPV_FORMAT_DOUBLE) { + double time = *(double *)prop->data; + Q_EMIT durationChanged(time); + } + } + break; + } + default: ; + // Ignore uninteresting or unknown events. + } +} + +void MpvWidget::on_update(void *ctx) +{ + QMetaObject::invokeMethod((MpvWidget*)ctx, "update"); +} |