diff --git a/DOCS/client_api_examples/qml/main.qml b/DOCS/client_api_examples/qml/main.qml index d921e2a86c..4b31406554 100644 --- a/DOCS/client_api_examples/qml/main.qml +++ b/DOCS/client_api_examples/qml/main.qml @@ -34,6 +34,7 @@ Item { anchors.right: renderer.right anchors.margins: 100 wrapMode: Text.WordWrap - text: "QtQuick and mpv are both rendering stuff." + text: "QtQuick and mpv are both rendering stuff.\n + Click to load ../../../test.mkv" } } diff --git a/DOCS/client_api_examples/qml/mpvrenderer.cpp b/DOCS/client_api_examples/qml/mpvrenderer.cpp index ab92a2388f..13c1f0a747 100644 --- a/DOCS/client_api_examples/qml/mpvrenderer.cpp +++ b/DOCS/client_api_examples/qml/mpvrenderer.cpp @@ -7,7 +7,6 @@ #include <QtGui/QOpenGLFramebufferObject> #include <QtQuick/QQuickWindow> -#include <qsgsimpletexturenode.h> class MpvRenderer : public QQuickFramebufferObject::Renderer { @@ -19,11 +18,12 @@ class MpvRenderer : public QQuickFramebufferObject::Renderer return (void *)glctx->getProcAddress(QByteArray(name)); } - mpv_opengl_cb_context *mpv_gl; + mpv::qt::Handle mpv; QQuickWindow *window; + mpv_opengl_cb_context *mpv_gl; public: - MpvRenderer(mpv_opengl_cb_context *a_mpv_gl) - : mpv_gl(a_mpv_gl), window(NULL) + MpvRenderer(const MpvObject *obj) + : mpv(obj->mpv), window(obj->window()), mpv_gl(obj->mpv_gl) { int r = mpv_opengl_cb_init_gl(mpv_gl, NULL, get_proc_address, NULL); if (r < 0) @@ -32,47 +32,40 @@ public: virtual ~MpvRenderer() { + // Before we can really destroy the OpenGL state, we must make sure + // that the video output is destroyed. This is important for some + // forms of hardware decoding, where the decoder shares some state + // with the video output and the OpenGL context. + // Deselecting the video track is the easiest way to achieve this in + // a synchronous way. If no file is playing, setting the property + // will fail and do nothing. + mpv::qt::set_property_variant(mpv, "vid", "no"); + mpv_opengl_cb_uninit_gl(mpv_gl); } void render() { - assert(window); // must have been set by synchronize() - QOpenGLFramebufferObject *fbo = framebufferObject(); int vp[4] = {0, 0, fbo->width(), fbo->height()}; window->resetOpenGLState(); mpv_opengl_cb_render(mpv_gl, fbo->handle(), vp); window->resetOpenGLState(); } - - QOpenGLFramebufferObject *createFramebufferObject(const QSize &size) - { - QOpenGLFramebufferObjectFormat format; - return new QOpenGLFramebufferObject(size, format); - } - -protected: - virtual void synchronize(QQuickFramebufferObject *item) - { - window = item->window(); - } }; MpvObject::MpvObject(QQuickItem * parent) - : QQuickFramebufferObject(parent) + : QQuickFramebufferObject(parent), mpv_gl(0) { - mpv = mpv_create(); + mpv = mpv::qt::Handle::FromRawHandle(mpv_create()); if (!mpv) throw "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) { - mpv_terminate_destroy(mpv); + if (mpv_initialize(mpv) < 0) throw "could not initialize mpv context"; - } // Make use of the MPV_SUB_API_OPENGL_CB API. mpv::qt::set_option_variant(mpv, "vo", "opengl-cb"); @@ -80,20 +73,21 @@ MpvObject::MpvObject(QQuickItem * parent) // Request hw decoding, just for testing. mpv::qt::set_option_variant(mpv, "hwdec", "auto"); + // Setup the callback that will make QtQuick update and redraw if there + // is a new video frame. Use a queued connection: this makes sure the + // doUpdate() function is run on the GUI thread. mpv_gl = (mpv_opengl_cb_context *)mpv_get_sub_api(mpv, MPV_SUB_API_OPENGL_CB); - if (!mpv_gl) { - mpv_terminate_destroy(mpv); + if (!mpv_gl) throw "OpenGL not compiled in"; - } - - mpv_opengl_cb_set_update_callback(mpv_gl, on_update, (void *)this); - - connect(this, &MpvObject::onUpdate, this, &MpvObject::doUpdate, Qt::QueuedConnection); + mpv_opengl_cb_set_update_callback(mpv_gl, MpvObject::on_update, (void *)this); + connect(this, &MpvObject::onUpdate, this, &MpvObject::doUpdate, + Qt::QueuedConnection); } MpvObject::~MpvObject() { - mpv_terminate_destroy(mpv); + if (mpv_gl) + mpv_opengl_cb_set_update_callback(mpv_gl, NULL, NULL); } void MpvObject::on_update(void *ctx) @@ -120,5 +114,5 @@ QQuickFramebufferObject::Renderer *MpvObject::createRenderer() const { window()->setPersistentOpenGLContext(true); window()->setPersistentSceneGraph(true); - return new MpvRenderer(mpv_gl); + return new MpvRenderer(this); } diff --git a/DOCS/client_api_examples/qml/mpvrenderer.h b/DOCS/client_api_examples/qml/mpvrenderer.h index 68e690ff55..700505ad20 100644 --- a/DOCS/client_api_examples/qml/mpvrenderer.h +++ b/DOCS/client_api_examples/qml/mpvrenderer.h @@ -1,25 +1,27 @@ #ifndef MPVRENDERER_H_ #define MPVRENDERER_H_ -#include <assert.h> - #include <QtQuick/QQuickFramebufferObject> #include <mpv/client.h> #include <mpv/opengl_cb.h> #include <mpv/qthelper.hpp> +class MpvRenderer; + class MpvObject : public QQuickFramebufferObject { Q_OBJECT - mpv_handle *mpv; + mpv::qt::Handle mpv; mpv_opengl_cb_context *mpv_gl; + friend class MpvRenderer; + public: MpvObject(QQuickItem * parent = 0); virtual ~MpvObject(); - Renderer *createRenderer() const; + virtual Renderer *createRenderer() const; public slots: void loadfile(const QString& filename); signals: diff --git a/DOCS/client_api_examples/qml/mpvtest.pro b/DOCS/client_api_examples/qml/mpvtest.pro index 6681fa1884..df497e4dba 100644 --- a/DOCS/client_api_examples/qml/mpvtest.pro +++ b/DOCS/client_api_examples/qml/mpvtest.pro @@ -4,7 +4,7 @@ HEADERS += mpvrenderer.h SOURCES += mpvrenderer.cpp main.cpp CONFIG += link_pkgconfig debug -PKGCONFIG = mpv +PKGCONFIG += mpv RESOURCES += mpvtest.qrc