summaryrefslogtreecommitdiffstats
path: root/src/plugins/multimedia/android/wrappers/jni/androidsurfacetexture.cpp
blob: c5860b265ea745ff6a490d411bea3bf27a0ad7d9 (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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only

#include "androidsurfacetexture_p.h"
#include <QtCore/qmutex.h>
#include <QtCore/qcoreapplication.h>

QT_BEGIN_NAMESPACE

static const char QtSurfaceTextureListenerClassName[] = "org/qtproject/qt/android/multimedia/QtSurfaceTextureListener";
typedef QList<jlong> SurfaceTextures;
Q_GLOBAL_STATIC(SurfaceTextures, g_surfaceTextures);
Q_GLOBAL_STATIC(QMutex, g_textureMutex);

static QAtomicInteger<quint64> indexCounter = 0u;

// native method for QtSurfaceTexture.java
static void notifyFrameAvailable(JNIEnv* , jobject, jlong id)
{
    const QMutexLocker lock(g_textureMutex());
    const int idx = g_surfaceTextures->indexOf(id);
    if (idx == -1)
        return;

    AndroidSurfaceTexture *obj = reinterpret_cast<AndroidSurfaceTexture *>(g_surfaceTextures->at(idx));
    if (obj)
        Q_EMIT obj->frameAvailable();
}

AndroidSurfaceTexture::AndroidSurfaceTexture(quint32 texName)
    : QObject()
    , m_index(indexCounter.fetchAndAddRelaxed(1))
{
    Q_STATIC_ASSERT(sizeof (jlong) >= sizeof (void *));
    m_surfaceTexture = QJniObject("android/graphics/SurfaceTexture", "(I)V", jint(texName));

    if (!m_surfaceTexture.isValid())
        return;

    const QMutexLocker lock(g_textureMutex());
    g_surfaceTextures->append(jlong(this));
    QJniObject listener(QtSurfaceTextureListenerClassName, "(J)V", jlong(this));
    setOnFrameAvailableListener(listener);
}

AndroidSurfaceTexture::~AndroidSurfaceTexture()
{
    if (m_surface.isValid())
        m_surface.callMethod<void>("release");

    if (m_surfaceTexture.isValid()) {
        release();
        const QMutexLocker lock(g_textureMutex());
        const int idx = g_surfaceTextures->indexOf(jlong(this));
        if (idx != -1)
            g_surfaceTextures->remove(idx);
    }
}

QMatrix4x4 AndroidSurfaceTexture::getTransformMatrix()
{
    QMatrix4x4 matrix;
    if (!m_surfaceTexture.isValid())
        return matrix;

    QJniEnvironment env;
    jfloatArray array = env->NewFloatArray(16);
    m_surfaceTexture.callMethod<void>("getTransformMatrix", "([F)V", array);
    env->GetFloatArrayRegion(array, 0, 16, matrix.data());
    env->DeleteLocalRef(array);

    return matrix;
}

void AndroidSurfaceTexture::release()
{
    m_surfaceTexture.callMethod<void>("release");
}

void AndroidSurfaceTexture::updateTexImage()
{
    if (!m_surfaceTexture.isValid())
        return;

    m_surfaceTexture.callMethod<void>("updateTexImage");
}

jobject AndroidSurfaceTexture::surfaceTexture()
{
    return m_surfaceTexture.object();
}

jobject AndroidSurfaceTexture::surface()
{
    if (!m_surface.isValid()) {
        m_surface = QJniObject("android/view/Surface",
                               "(Landroid/graphics/SurfaceTexture;)V",
                               m_surfaceTexture.object());
    }

    return m_surface.object();
}

jobject AndroidSurfaceTexture::surfaceHolder()
{
    if (!m_surfaceHolder.isValid()) {
        m_surfaceHolder = QJniObject("org/qtproject/qt/android/multimedia/QtSurfaceTextureHolder",
                                     "(Landroid/view/Surface;)V",
                                     surface());
    }

    return m_surfaceHolder.object();
}

void AndroidSurfaceTexture::attachToGLContext(quint32 texName)
{
    if (!m_surfaceTexture.isValid())
        return;

    m_surfaceTexture.callMethod<void>("attachToGLContext", "(I)V", texName);
}

void AndroidSurfaceTexture::detachFromGLContext()
{
    if (!m_surfaceTexture.isValid())
        return;

    m_surfaceTexture.callMethod<void>("detachFromGLContext");
}

bool AndroidSurfaceTexture::registerNativeMethods()
{
    static const JNINativeMethod methods[] = {
        {"notifyFrameAvailable", "(J)V", (void *)notifyFrameAvailable}
    };
    const int size = std::size(methods);
    if (QJniEnvironment().registerNativeMethods(QtSurfaceTextureListenerClassName, methods, size))
        return false;

    return true;
}

void AndroidSurfaceTexture::setOnFrameAvailableListener(const QJniObject &listener)
{
    m_surfaceTexture.callMethod<void>("setOnFrameAvailableListener",
                                      "(Landroid/graphics/SurfaceTexture$OnFrameAvailableListener;)V",
                                      listener.object());
}

QT_END_NAMESPACE

#include "moc_androidsurfacetexture_p.cpp"