summaryrefslogtreecommitdiffstats
path: root/DOCS/client_api_examples/qml/mpvrenderer.cpp
blob: ab92a2388f62801778d5894e869dc15d01006f87 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
#include "mpvrenderer.h"

#include <QObject>
#include <QtGlobal>
#include <QOpenGLContext>

#include <QtGui/QOpenGLFramebufferObject>

#include <QtQuick/QQuickWindow>
#include <qsgsimpletexturenode.h>

class MpvRenderer : public QQuickFramebufferObject::Renderer
{
    static void *get_proc_address(void *ctx, const char *name) {
        (void)ctx;
        QOpenGLContext *glctx = QOpenGLContext::currentContext();
        if (!glctx)
            return NULL;
        return (void *)glctx->getProcAddress(QByteArray(name));
    }

    mpv_opengl_cb_context *mpv_gl;
    QQuickWindow *window;
public:
    MpvRenderer(mpv_opengl_cb_context *a_mpv_gl)
        : mpv_gl(a_mpv_gl), window(NULL)
    {
        int r = mpv_opengl_cb_init_gl(mpv_gl, NULL, get_proc_address, NULL);
        if (r < 0)
            throw "could not initialize OpenGL";
    }

    virtual ~MpvRenderer()
    {
        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)
{
    mpv = 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);
        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");

    // 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) {
        mpv_terminate_destroy(mpv);
        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);
}

MpvObject::~MpvObject()
{
    mpv_terminate_destroy(mpv);
}

void MpvObject::on_update(void *ctx)
{
    MpvObject *self = (MpvObject *)ctx;
    emit self->onUpdate();
}

// connected to onUpdate(); signal makes sure it runs on the GUI thread
void MpvObject::doUpdate()
{
    update();
}

void MpvObject::loadfile(const QString& filename)
{
    QVariantList cmd;
    cmd.append("loadfile");
    cmd.append(filename);
    mpv::qt::command_variant(mpv, cmd);
}

QQuickFramebufferObject::Renderer *MpvObject::createRenderer() const
{
    window()->setPersistentOpenGLContext(true);
    window()->setPersistentSceneGraph(true);
    return new MpvRenderer(mpv_gl);
}