diff options
author | wm4 <wm4@nowhere> | 2014-12-30 22:34:34 +0100 |
---|---|---|
committer | wm4 <wm4@nowhere> | 2014-12-30 22:40:25 +0100 |
commit | 10f51a8c57e857ab8ed09a04237879f8bb329a0f (patch) | |
tree | 5c03034fc1d2e8e688b6dbf6c7c70b338b12c2c4 /DOCS/client_api_examples | |
parent | 50c40b6dedcaf35bd2af68a3535b023c871d1295 (diff) | |
download | mpv-10f51a8c57e857ab8ed09a04237879f8bb329a0f.tar.bz2 mpv-10f51a8c57e857ab8ed09a04237879f8bb329a0f.tar.xz |
DOCS/client_api_examples: qtquick: fix destruction
Destruction (e.g. when closing the window) was a bit broken. This commit
fixes some possible crashes, and should make lifetime management
relatively sane. (Still a bit complex, though. Maybe this code should be
moved into a tiny library.)
QtQuick runs the renderer on a separate thread. This thread is rather
loosely connected to the main thread. The loose separation is enforced
by the API, which also makes coordination of initialization and
destruction harder. Throw refcounting at the problem, which fixes it.
The refcounting wrapper introduced in the previous commit is used for
this.
Also contains some general cleanups.
Diffstat (limited to 'DOCS/client_api_examples')
-rw-r--r-- | DOCS/client_api_examples/qml/main.qml | 3 | ||||
-rw-r--r-- | DOCS/client_api_examples/qml/mpvrenderer.cpp | 58 | ||||
-rw-r--r-- | DOCS/client_api_examples/qml/mpvrenderer.h | 10 | ||||
-rw-r--r-- | DOCS/client_api_examples/qml/mpvtest.pro | 2 |
4 files changed, 35 insertions, 38 deletions
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 |