DOCS/client_api_examples: add qt widget + opengl-cb example

This commit is contained in:
wang-bin 2015-10-11 17:19:36 +08:00 committed by wm4
parent 78caf6ae86
commit 52de5ea6ad
6 changed files with 272 additions and 0 deletions

View File

@ -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();
}

View File

@ -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);
}

View File

@ -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

View File

@ -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");
}

View File

@ -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

View File

@ -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