Android: Fix QtSurfaceTexture

Don't extend SurfaceTexture as this causes ART to fail when it doesn't
find the postEventFromNative() function. The postEventFromNative()
function was implemented sometime after API 11, so to avoid this
situation we can use composition instead.

Task-number: QTBUG-37605

Change-Id: Ie1013d218291ba0035f1bb18a0c0655fd2170bfd
Reviewed-by: Yoann Lopes <yoann.lopes@digia.com>
This commit is contained in:
Christian Strømme
2014-03-19 13:48:19 +01:00
committed by The Qt Project
parent 3c3e2c324b
commit cc41c7df3c
10 changed files with 80 additions and 169 deletions

View File

@@ -7,7 +7,7 @@ JAVACLASSPATH += $$PWD/src
JAVASOURCES += $$PWD/src/org/qtproject/qt5/android/multimedia/QtAndroidMediaPlayer.java \ JAVASOURCES += $$PWD/src/org/qtproject/qt5/android/multimedia/QtAndroidMediaPlayer.java \
$$PWD/src/org/qtproject/qt5/android/multimedia/QtCamera.java \ $$PWD/src/org/qtproject/qt5/android/multimedia/QtCamera.java \
$$PWD/src/org/qtproject/qt5/android/multimedia/QtSurfaceTexture.java \ $$PWD/src/org/qtproject/qt5/android/multimedia/QtSurfaceTextureListener.java \
$$PWD/src/org/qtproject/qt5/android/multimedia/QtSurfaceTextureHolder.java \ $$PWD/src/org/qtproject/qt5/android/multimedia/QtSurfaceTextureHolder.java \
$$PWD/src/org/qtproject/qt5/android/multimedia/QtMultimediaUtils.java \ $$PWD/src/org/qtproject/qt5/android/multimedia/QtMultimediaUtils.java \
$$PWD/src/org/qtproject/qt5/android/multimedia/QtMediaRecorder.java $$PWD/src/org/qtproject/qt5/android/multimedia/QtMediaRecorder.java

View File

@@ -43,15 +43,13 @@ package org.qtproject.qt5.android.multimedia;
import android.graphics.SurfaceTexture; import android.graphics.SurfaceTexture;
public class QtSurfaceTexture extends SurfaceTexture implements SurfaceTexture.OnFrameAvailableListener public class QtSurfaceTextureListener implements SurfaceTexture.OnFrameAvailableListener
{ {
private int texID; private final int texID;
public QtSurfaceTexture(int texName) public QtSurfaceTextureListener(int texName)
{ {
super(texName);
texID = texName; texID = texName;
setOnFrameAvailableListener(this);
} }
@Override @Override

View File

@@ -42,7 +42,6 @@
#include "qandroidvideorendercontrol.h" #include "qandroidvideorendercontrol.h"
#include <QtCore/private/qjni_p.h> #include <QtCore/private/qjni_p.h>
#include "jsurfacetextureholder.h"
#include <QAbstractVideoSurface> #include <QAbstractVideoSurface>
#include <QVideoSurfaceFormat> #include <QVideoSurfaceFormat>
#include <qevent.h> #include <qevent.h>
@@ -51,6 +50,7 @@
#include <qopenglfunctions.h> #include <qopenglfunctions.h>
#include <qopenglshaderprogram.h> #include <qopenglshaderprogram.h>
#include <qopenglframebufferobject.h> #include <qopenglframebufferobject.h>
#include <QtCore/private/qjnihelpers_p.h>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
@@ -177,7 +177,7 @@ bool QAndroidVideoRendererControl::initSurfaceTexture()
m_surfaceTexture = new JSurfaceTexture(m_externalTex); m_surfaceTexture = new JSurfaceTexture(m_externalTex);
if (m_surfaceTexture->isValid()) { if (m_surfaceTexture->object()) {
connect(m_surfaceTexture, SIGNAL(frameAvailable()), this, SLOT(onFrameAvailable())); connect(m_surfaceTexture, SIGNAL(frameAvailable()), this, SLOT(onFrameAvailable()));
} else { } else {
delete m_surfaceTexture; delete m_surfaceTexture;
@@ -193,11 +193,11 @@ bool QAndroidVideoRendererControl::initSurfaceTexture()
void QAndroidVideoRendererControl::clearSurfaceTexture() void QAndroidVideoRendererControl::clearSurfaceTexture()
{ {
if (m_surfaceTexture) { if (m_surfaceTexture) {
m_surfaceTexture->callMethod<void>("release");
delete m_surfaceTexture; delete m_surfaceTexture;
m_surfaceTexture = 0; m_surfaceTexture = 0;
} }
if (m_androidSurface) { if (m_androidSurface) {
if (QtAndroidPrivate::androidSdkVersion() > 13)
m_androidSurface->callMethod<void>("release"); m_androidSurface->callMethod<void>("release");
delete m_androidSurface; delete m_androidSurface;
m_androidSurface = 0; m_androidSurface = 0;
@@ -218,7 +218,9 @@ jobject QAndroidVideoRendererControl::surfaceHolder()
"(Landroid/graphics/SurfaceTexture;)V", "(Landroid/graphics/SurfaceTexture;)V",
m_surfaceTexture->object()); m_surfaceTexture->object());
m_surfaceHolder = new JSurfaceTextureHolder(m_androidSurface->object()); m_surfaceHolder = new QJNIObjectPrivate("org/qtproject/qt5/android/multimedia/QtSurfaceTextureHolder",
"(Landroid/view/Surface;)V",
m_androidSurface->object());
} }
return m_surfaceHolder->object(); return m_surfaceHolder->object();

View File

@@ -49,7 +49,6 @@
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class JSurfaceTextureHolder;
class QOpenGLTexture; class QOpenGLTexture;
class QOpenGLFramebufferObject; class QOpenGLFramebufferObject;
class QOpenGLShaderProgram; class QOpenGLShaderProgram;
@@ -115,7 +114,7 @@ private:
QJNIObjectPrivate *m_androidSurface; QJNIObjectPrivate *m_androidSurface;
JSurfaceTexture *m_surfaceTexture; JSurfaceTexture *m_surfaceTexture;
JSurfaceTextureHolder *m_surfaceHolder; QJNIObjectPrivate *m_surfaceHolder;
quint32 m_externalTex; quint32 m_externalTex;
QOpenGLFramebufferObject *m_fbo; QOpenGLFramebufferObject *m_fbo;

View File

@@ -48,7 +48,6 @@
#include "qandroidcamerasession.h" #include "qandroidcamerasession.h"
#include "jmediaplayer.h" #include "jmediaplayer.h"
#include "jsurfacetexture.h" #include "jsurfacetexture.h"
#include "jsurfacetextureholder.h"
#include "jcamera.h" #include "jcamera.h"
#include "jmultimediautils.h" #include "jmultimediautils.h"
#include "jmediarecorder.h" #include "jmediarecorder.h"
@@ -165,14 +164,14 @@ Q_DECL_EXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void * /*reserved*/)
JNIEnv *jniEnv = uenv.nativeEnvironment; JNIEnv *jniEnv = uenv.nativeEnvironment;
if (!JMediaPlayer::initJNI(jniEnv) || if (!JMediaPlayer::initJNI(jniEnv) ||
!JSurfaceTexture::initJNI(jniEnv) ||
!JSurfaceTextureHolder::initJNI(jniEnv) ||
!JCamera::initJNI(jniEnv) || !JCamera::initJNI(jniEnv) ||
!JMultimediaUtils::initJNI(jniEnv) || !JMultimediaUtils::initJNI(jniEnv) ||
!JMediaRecorder::initJNI(jniEnv)) { !JMediaRecorder::initJNI(jniEnv)) {
return JNI_ERR; return JNI_ERR;
} }
JSurfaceTexture::initJNI(jniEnv);
return JNI_VERSION_1_4; return JNI_VERSION_1_4;
} }

View File

@@ -41,10 +41,11 @@
#include "jsurfacetexture.h" #include "jsurfacetexture.h"
#include <QtCore/private/qjni_p.h> #include <QtCore/private/qjni_p.h>
#include <QtCore/private/qjnihelpers_p.h>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
static jclass g_qtSurfaceTextureClass = 0; static jclass g_qtSurfaceTextureListenerClass = 0;
static QMap<int, JSurfaceTexture*> g_objectMap; static QMap<int, JSurfaceTexture*> g_objectMap;
// native method for QtSurfaceTexture.java // native method for QtSurfaceTexture.java
@@ -57,37 +58,75 @@ static void notifyFrameAvailable(JNIEnv* , jobject, int id)
JSurfaceTexture::JSurfaceTexture(unsigned int texName) JSurfaceTexture::JSurfaceTexture(unsigned int texName)
: QObject() : QObject()
, QJNIObjectPrivate(g_qtSurfaceTextureClass, "(I)V", jint(texName))
, m_texID(int(texName)) , m_texID(int(texName))
{ {
if (isValid()) // API level 11 or higher is required
g_objectMap.insert(int(texName), this); if (QtAndroidPrivate::androidSdkVersion() < 11) {
else // If the class is not available, it means the Android version is < 3.0
qWarning("Camera preview and video playback require Android 3.0 (API level 11) or later."); qWarning("Camera preview and video playback require Android 3.0 (API level 11) or later.");
return;
}
QJNIEnvironmentPrivate env;
m_surfaceTexture = QJNIObjectPrivate("android/graphics/SurfaceTexture", "(I)V", jint(texName));
if (env->ExceptionCheck()) {
#ifdef QT_DEBUG
env->ExceptionDescribe();
#endif // QT_DEBUG
env->ExceptionClear();
}
if (m_surfaceTexture.isValid())
g_objectMap.insert(int(texName), this);
QJNIObjectPrivate listener(g_qtSurfaceTextureListenerClass, "(I)V", jint(texName));
m_surfaceTexture.callMethod<void>("setOnFrameAvailableListener",
"(Landroid/graphics/SurfaceTexture$OnFrameAvailableListener;)V",
listener.object());
} }
JSurfaceTexture::~JSurfaceTexture() JSurfaceTexture::~JSurfaceTexture()
{ {
if (isValid()) if (m_surfaceTexture.isValid()) {
release();
g_objectMap.remove(m_texID); g_objectMap.remove(m_texID);
} }
}
QMatrix4x4 JSurfaceTexture::getTransformMatrix() QMatrix4x4 JSurfaceTexture::getTransformMatrix()
{ {
QMatrix4x4 matrix;
if (!m_surfaceTexture.isValid())
return matrix;
QJNIEnvironmentPrivate env; QJNIEnvironmentPrivate env;
QMatrix4x4 matrix;
jfloatArray array = env->NewFloatArray(16); jfloatArray array = env->NewFloatArray(16);
callMethod<void>("getTransformMatrix", "([F)V", array); m_surfaceTexture.callMethod<void>("getTransformMatrix", "([F)V", array);
env->GetFloatArrayRegion(array, 0, 16, matrix.data()); env->GetFloatArrayRegion(array, 0, 16, matrix.data());
env->DeleteLocalRef(array); env->DeleteLocalRef(array);
return matrix; return matrix;
} }
void JSurfaceTexture::release()
{
if (QtAndroidPrivate::androidSdkVersion() < 14)
return;
m_surfaceTexture.callMethod<void>("release");
}
void JSurfaceTexture::updateTexImage() void JSurfaceTexture::updateTexImage()
{ {
callMethod<void>("updateTexImage"); if (!m_surfaceTexture.isValid())
return;
m_surfaceTexture.callMethod<void>("updateTexImage");
}
jobject JSurfaceTexture::object()
{
return m_surfaceTexture.object();
} }
static JNINativeMethod methods[] = { static JNINativeMethod methods[] = {
@@ -96,26 +135,22 @@ static JNINativeMethod methods[] = {
bool JSurfaceTexture::initJNI(JNIEnv *env) bool JSurfaceTexture::initJNI(JNIEnv *env)
{ {
// SurfaceTexture is available since API 11, try to find it first before loading // SurfaceTexture is available since API 11.
// our custom class if (QtAndroidPrivate::androidSdkVersion() < 11)
jclass surfaceTextureClass = env->FindClass("android/graphics/SurfaceTexture"); return false;
if (env->ExceptionCheck())
env->ExceptionClear();
if (surfaceTextureClass) { jclass clazz = env->FindClass("org/qtproject/qt5/android/multimedia/QtSurfaceTextureListener");
jclass clazz = env->FindClass("org/qtproject/qt5/android/multimedia/QtSurfaceTexture");
if (env->ExceptionCheck()) if (env->ExceptionCheck())
env->ExceptionClear(); env->ExceptionClear();
if (clazz) { if (clazz) {
g_qtSurfaceTextureClass = static_cast<jclass>(env->NewGlobalRef(clazz)); g_qtSurfaceTextureListenerClass = static_cast<jclass>(env->NewGlobalRef(clazz));
if (env->RegisterNatives(g_qtSurfaceTextureClass, if (env->RegisterNatives(g_qtSurfaceTextureListenerClass,
methods, methods,
sizeof(methods) / sizeof(methods[0])) < 0) { sizeof(methods) / sizeof(methods[0])) < 0) {
return false; return false;
} }
} }
}
return true; return true;
} }

View File

@@ -49,7 +49,7 @@
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class JSurfaceTexture : public QObject, public QJNIObjectPrivate class JSurfaceTexture : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
@@ -57,7 +57,10 @@ public:
~JSurfaceTexture(); ~JSurfaceTexture();
int textureID() const { return m_texID; } int textureID() const { return m_texID; }
jobject object();
QMatrix4x4 getTransformMatrix(); QMatrix4x4 getTransformMatrix();
void release(); // API level 14
void updateTexImage(); void updateTexImage();
static bool initJNI(JNIEnv *env); static bool initJNI(JNIEnv *env);
@@ -67,6 +70,7 @@ Q_SIGNALS:
private: private:
int m_texID; int m_texID;
QJNIObjectPrivate m_surfaceTexture;
}; };
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@@ -1,65 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "jsurfacetextureholder.h"
QT_BEGIN_NAMESPACE
static jclass g_qtSurfaceTextureHolderClass = 0;
JSurfaceTextureHolder::JSurfaceTextureHolder(jobject surface)
: QJNIObjectPrivate(g_qtSurfaceTextureHolderClass, "(Landroid/view/Surface;)V", surface)
{
}
bool JSurfaceTextureHolder::initJNI(JNIEnv *env)
{
jclass clazz = env->FindClass("org/qtproject/qt5/android/multimedia/QtSurfaceTextureHolder");
if (env->ExceptionCheck())
env->ExceptionClear();
if (clazz)
g_qtSurfaceTextureHolderClass = static_cast<jclass>(env->NewGlobalRef(clazz));
return true;
}
QT_END_NAMESPACE

View File

@@ -1,59 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef JSURFACETEXTUREHOLDER_H
#define JSURFACETEXTUREHOLDER_H
#include <QtCore/private/qjni_p.h>
QT_BEGIN_NAMESPACE
class JSurfaceTextureHolder : public QJNIObjectPrivate
{
public:
JSurfaceTextureHolder(jobject surface);
static bool initJNI(JNIEnv *env);
};
QT_END_NAMESPACE
#endif // JSURFACETEXTUREHOLDER_H

View File

@@ -5,7 +5,6 @@ INCLUDEPATH += $$PWD
HEADERS += \ HEADERS += \
$$PWD/jmediaplayer.h \ $$PWD/jmediaplayer.h \
$$PWD/jsurfacetexture.h \ $$PWD/jsurfacetexture.h \
$$PWD/jsurfacetextureholder.h \
$$PWD/jmediametadataretriever.h \ $$PWD/jmediametadataretriever.h \
$$PWD/jcamera.h \ $$PWD/jcamera.h \
$$PWD/jmultimediautils.h \ $$PWD/jmultimediautils.h \
@@ -14,7 +13,6 @@ HEADERS += \
SOURCES += \ SOURCES += \
$$PWD/jmediaplayer.cpp \ $$PWD/jmediaplayer.cpp \
$$PWD/jsurfacetexture.cpp \ $$PWD/jsurfacetexture.cpp \
$$PWD/jsurfacetextureholder.cpp \
$$PWD/jmediametadataretriever.cpp \ $$PWD/jmediametadataretriever.cpp \
$$PWD/jcamera.cpp \ $$PWD/jcamera.cpp \
$$PWD/jmultimediautils.cpp \ $$PWD/jmultimediautils.cpp \