From 10f51a8c57e857ab8ed09a04237879f8bb329a0f Mon Sep 17 00:00:00 2001 From: wm4 Date: Tue, 30 Dec 2014 22:34:34 +0100 Subject: 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. --- DOCS/client_api_examples/qml/main.qml | 3 +- DOCS/client_api_examples/qml/mpvrenderer.cpp | 58 +++++++++++++--------------- DOCS/client_api_examples/qml/mpvrenderer.h | 10 +++-- DOCS/client_api_examples/qml/mpvtest.pro | 2 +- 4 files changed, 35 insertions(+), 38 deletions(-) (limited to 'DOCS') 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 #include -#include 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 - #include #include #include #include +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 -- cgit v1.2.3