summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2014-12-30 22:34:34 +0100
committerwm4 <wm4@nowhere>2014-12-30 22:40:25 +0100
commit10f51a8c57e857ab8ed09a04237879f8bb329a0f (patch)
tree5c03034fc1d2e8e688b6dbf6c7c70b338b12c2c4
parent50c40b6dedcaf35bd2af68a3535b023c871d1295 (diff)
downloadmpv-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.
-rw-r--r--DOCS/client_api_examples/qml/main.qml3
-rw-r--r--DOCS/client_api_examples/qml/mpvrenderer.cpp58
-rw-r--r--DOCS/client_api_examples/qml/mpvrenderer.h10
-rw-r--r--DOCS/client_api_examples/qml/mpvtest.pro2
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