aboutsummaryrefslogtreecommitdiffhomepage
path: root/DOCS/client_api_examples
diff options
context:
space:
mode:
Diffstat (limited to 'DOCS/client_api_examples')
-rw-r--r--DOCS/client_api_examples/qt_opengl/main.cpp13
-rw-r--r--DOCS/client_api_examples/qt_opengl/mainwindow.cpp53
-rw-r--r--DOCS/client_api_examples/qt_opengl/mainwindow.h27
-rw-r--r--DOCS/client_api_examples/qt_opengl/mpvwidget.cpp128
-rw-r--r--DOCS/client_api_examples/qt_opengl/mpvwidget.h38
-rw-r--r--DOCS/client_api_examples/qt_opengl/qt_opengl.pro13
6 files changed, 272 insertions, 0 deletions
diff --git a/DOCS/client_api_examples/qt_opengl/main.cpp b/DOCS/client_api_examples/qt_opengl/main.cpp
new file mode 100644
index 0000000000..086a4b4617
--- /dev/null
+++ b/DOCS/client_api_examples/qt_opengl/main.cpp
@@ -0,0 +1,13 @@
+#include <QApplication>
+#include "mainwindow.h"
+
+int main(int argc, char *argv[])
+{
+ QApplication a(argc, argv);
+ // Qt sets the locale in the QApplication constructor, but libmpv requires
+ // the LC_NUMERIC category to be set to "C", so change it back.
+ setlocale(LC_NUMERIC, "C");
+ MainWindow w;
+ w.show();
+ return a.exec();
+}
diff --git a/DOCS/client_api_examples/qt_opengl/mainwindow.cpp b/DOCS/client_api_examples/qt_opengl/mainwindow.cpp
new file mode 100644
index 0000000000..2e3cf210ee
--- /dev/null
+++ b/DOCS/client_api_examples/qt_opengl/mainwindow.cpp
@@ -0,0 +1,53 @@
+#include "mainwindow.h"
+#include "mpvwidget.h"
+#include <QPushButton>
+#include <QSlider>
+#include <QLayout>
+#include <QFileDialog>
+
+MainWindow::MainWindow(QWidget *parent) : QWidget(parent)
+{
+ m_mpv = new MpvWidget(this);
+ m_slider = new QSlider();
+ m_slider->setOrientation(Qt::Horizontal);
+ m_openBtn = new QPushButton("Open");
+ m_playBtn = new QPushButton("Pause");
+ QHBoxLayout *hb = new QHBoxLayout();
+ hb->addWidget(m_openBtn);
+ hb->addWidget(m_playBtn);
+ QVBoxLayout *vl = new QVBoxLayout();
+ vl->addWidget(m_mpv);
+ vl->addWidget(m_slider);
+ vl->addLayout(hb);
+ setLayout(vl);
+ connect(m_slider, SIGNAL(sliderMoved(int)), SLOT(seek(int)));
+ connect(m_openBtn, SIGNAL(clicked()), SLOT(openMedia()));
+ connect(m_playBtn, SIGNAL(clicked()), SLOT(pauseResume()));
+ connect(m_mpv, SIGNAL(positionChanged(int)), m_slider, SLOT(setValue(int)));
+ connect(m_mpv, SIGNAL(durationChanged(int)), this, SLOT(setSliderRange(int)));
+}
+
+void MainWindow::openMedia()
+{
+ QString file = QFileDialog::getOpenFileName(0, "Open a video");
+ if (file.isEmpty())
+ return;
+ m_mpv->command(QStringList() << "loadfile" << file);
+}
+
+void MainWindow::seek(int pos)
+{
+ m_mpv->command(QVariantList() << "seek" << pos << "absolute");
+}
+
+void MainWindow::pauseResume()
+{
+ const bool paused = m_mpv->getProperty("pause").toBool();
+ m_mpv->setProperty("pause", !paused);
+}
+
+void MainWindow::setSliderRange(int duration)
+{
+ const int time0 = m_mpv->getProperty("time-start").toInt();
+ m_slider->setRange(time0, time0+duration);
+}
diff --git a/DOCS/client_api_examples/qt_opengl/mainwindow.h b/DOCS/client_api_examples/qt_opengl/mainwindow.h
new file mode 100644
index 0000000000..523b385bb4
--- /dev/null
+++ b/DOCS/client_api_examples/qt_opengl/mainwindow.h
@@ -0,0 +1,27 @@
+#ifndef MainWindow_H
+#define MainWindow_H
+
+#include <QtWidgets/QWidget>
+
+class MpvWidget;
+class QSlider;
+class QPushButton;
+class MainWindow : public QWidget
+{
+ Q_OBJECT
+public:
+ explicit MainWindow(QWidget *parent = 0);
+public Q_SLOTS:
+ void openMedia();
+ void seek(int pos);
+ void pauseResume();
+private Q_SLOTS:
+ void setSliderRange(int duration);
+private:
+ MpvWidget *m_mpv;
+ QSlider *m_slider;
+ QPushButton *m_openBtn;
+ QPushButton *m_playBtn;
+};
+
+#endif // MainWindow_H
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");
+}
diff --git a/DOCS/client_api_examples/qt_opengl/mpvwidget.h b/DOCS/client_api_examples/qt_opengl/mpvwidget.h
new file mode 100644
index 0000000000..a219681393
--- /dev/null
+++ b/DOCS/client_api_examples/qt_opengl/mpvwidget.h
@@ -0,0 +1,38 @@
+#ifndef PLAYERWINDOW_H
+#define PLAYERWINDOW_H
+
+#include <QtWidgets/QOpenGLWidget>
+#include <mpv/client.h>
+#include <mpv/opengl_cb.h>
+#include <mpv/qthelper.hpp>
+
+class MpvWidget Q_DECL_FINAL: public QOpenGLWidget
+{
+ Q_OBJECT
+public:
+ MpvWidget(QWidget *parent = 0, Qt::WindowFlags f = 0);
+ ~MpvWidget();
+ void command(const QVariant& params);
+ void setProperty(const QString& name, const QVariant& value);
+ QVariant getProperty(const QString& name) const;
+ QSize sizeHint() const { return QSize(480, 270);}
+Q_SIGNALS:
+ void durationChanged(int value);
+ void positionChanged(int value);
+protected:
+ void initializeGL() Q_DECL_OVERRIDE;
+ void paintGL() Q_DECL_OVERRIDE;
+private Q_SLOTS:
+ void swapped();
+ void on_mpv_events();
+private:
+ void handle_mpv_event(mpv_event *event);
+ static void on_update(void *ctx);
+
+ mpv::qt::Handle mpv;
+ mpv_opengl_cb_context *mpv_gl;
+};
+
+
+
+#endif // PLAYERWINDOW_H
diff --git a/DOCS/client_api_examples/qt_opengl/qt_opengl.pro b/DOCS/client_api_examples/qt_opengl/qt_opengl.pro
new file mode 100644
index 0000000000..8a2bcc665d
--- /dev/null
+++ b/DOCS/client_api_examples/qt_opengl/qt_opengl.pro
@@ -0,0 +1,13 @@
+CONFIG -= app_bundle
+QT += widgets
+
+QT_CONFIG -= no-pkg-config
+CONFIG += link_pkgconfig debug
+PKGCONFIG += mpv
+
+HEADERS = \
+ mpvwidget.h \
+ mainwindow.h
+SOURCES = main.cpp \
+ mpvwidget.cpp \
+ mainwindow.cpp