diff options
Diffstat (limited to 'src/plugins/android')
9 files changed, 143 insertions, 89 deletions
diff --git a/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtCameraListener.java b/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtCameraListener.java index 57700cd75..49cb0a947 100644 --- a/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtCameraListener.java +++ b/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtCameraListener.java @@ -57,6 +57,7 @@ public class QtCameraListener implements Camera.ShutterCallback, private int m_cameraId = -1; private boolean m_notifyNewFrames = false; + private boolean m_notifyWhenFrameAvailable = false; private byte[][] m_previewBuffers = null; private byte[] m_lastPreviewBuffer = null; private Camera.Size m_previewSize = null; @@ -73,6 +74,11 @@ public class QtCameraListener implements Camera.ShutterCallback, m_notifyNewFrames = notify; } + public void notifyWhenFrameAvailable(boolean notify) + { + m_notifyWhenFrameAvailable = notify; + } + public byte[] lastPreviewBuffer() { return m_lastPreviewBuffer; @@ -104,11 +110,16 @@ public class QtCameraListener implements Camera.ShutterCallback, return m_previewBytesPerLine; } + public void clearPreviewCallback(Camera camera) + { + camera.setPreviewCallbackWithBuffer(null); + } + public void setupPreviewCallback(Camera camera) { // Clear previous callback (also clears added buffers) + clearPreviewCallback(camera); m_lastPreviewBuffer = null; - camera.setPreviewCallbackWithBuffer(null); final Camera.Parameters params = camera.getParameters(); m_previewSize = params.getPreviewSize(); @@ -164,11 +175,17 @@ public class QtCameraListener implements Camera.ShutterCallback, m_lastPreviewBuffer = data; - if (data != null && m_notifyNewFrames) { - notifyNewPreviewFrame(m_cameraId, data, - m_previewSize.width, m_previewSize.height, - m_previewFormat, - m_previewBytesPerLine); + if (data != null) { + if (m_notifyWhenFrameAvailable) { + m_notifyWhenFrameAvailable = false; + notifyFrameAvailable(m_cameraId); + } + if (m_notifyNewFrames) { + notifyNewPreviewFrame(m_cameraId, data, + m_previewSize.width, m_previewSize.height, + m_previewFormat, + m_previewBytesPerLine); + } } } @@ -195,4 +212,5 @@ public class QtCameraListener implements Camera.ShutterCallback, private static native void notifyPictureCaptured(int id, byte[] data); private static native void notifyNewPreviewFrame(int id, byte[] data, int width, int height, int pixelFormat, int bytesPerLine); + private static native void notifyFrameAvailable(int id); } diff --git a/src/plugins/android/src/common/qandroidvideooutput.cpp b/src/plugins/android/src/common/qandroidvideooutput.cpp index a5cd3580b..1d0df27f2 100644 --- a/src/plugins/android/src/common/qandroidvideooutput.cpp +++ b/src/plugins/android/src/common/qandroidvideooutput.cpp @@ -66,6 +66,22 @@ static const GLfloat g_texture_data[] = { 0.f, 1.f }; +void OpenGLResourcesDeleter::deleteTextureHelper(quint32 id) +{ + if (id != 0) + glDeleteTextures(1, &id); +} + +void OpenGLResourcesDeleter::deleteFboHelper(void *fbo) +{ + delete reinterpret_cast<QOpenGLFramebufferObject *>(fbo); +} + +void OpenGLResourcesDeleter::deleteShaderProgramHelper(void *prog) +{ + delete reinterpret_cast<QOpenGLShaderProgram *>(prog); +} + class AndroidTextureVideoBuffer : public QAbstractVideoBuffer { @@ -130,40 +146,6 @@ private: QImage m_image; }; - -class OpenGLResourcesDeleter : public QObject -{ -public: - OpenGLResourcesDeleter() - : m_textureID(0) - , m_fbo(0) - , m_program(0) - { } - - ~OpenGLResourcesDeleter() - { - glDeleteTextures(1, &m_textureID); - delete m_fbo; - delete m_program; - } - - void setTexture(quint32 id) { - if (m_textureID) - glDeleteTextures(1, &m_textureID); - - m_textureID = id; - } - - void setFbo(QOpenGLFramebufferObject *fbo) { m_fbo = fbo; } - void setShaderProgram(QOpenGLShaderProgram *prog) { m_program = prog; } - -private: - quint32 m_textureID; - QOpenGLFramebufferObject *m_fbo; - QOpenGLShaderProgram *m_program; -}; - - QAndroidTextureVideoOutput::QAndroidTextureVideoOutput(QObject *parent) : QAndroidVideoOutput(parent) , m_surface(0) @@ -171,7 +153,6 @@ QAndroidTextureVideoOutput::QAndroidTextureVideoOutput(QObject *parent) , m_externalTex(0) , m_fbo(0) , m_program(0) - , m_glDeleter(0) , m_surfaceTextureCanAttachToContext(QtAndroidPrivate::androidSdkVersion() >= 16) { @@ -181,8 +162,12 @@ QAndroidTextureVideoOutput::~QAndroidTextureVideoOutput() { clearSurfaceTexture(); - if (m_glDeleter) + if (!m_glDeleter.isNull()) { // Make sure all of these are deleted on the render thread. + m_glDeleter->deleteFbo(m_fbo); + m_glDeleter->deleteShaderProgram(m_program); + m_glDeleter->deleteTexture(m_externalTex); m_glDeleter->deleteLater(); + } } QAbstractVideoSurface *QAndroidTextureVideoOutput::surface() const @@ -229,8 +214,7 @@ bool QAndroidTextureVideoOutput::initSurfaceTexture() // for the GL render thread to call us back to do it. if (QOpenGLContext::currentContext()) { glGenTextures(1, &m_externalTex); - m_glDeleter = new OpenGLResourcesDeleter; - m_glDeleter->setTexture(m_externalTex); + m_glDeleter.reset(new OpenGLResourcesDeleter); } else if (!m_externalTex) { return false; } @@ -245,10 +229,9 @@ bool QAndroidTextureVideoOutput::initSurfaceTexture() } else { delete m_surfaceTexture; m_surfaceTexture = 0; - if (m_glDeleter) - m_glDeleter->deleteLater(); + if (!m_glDeleter.isNull()) + m_glDeleter->deleteTexture(m_externalTex); m_externalTex = 0; - m_glDeleter = 0; } return m_surfaceTexture != 0; @@ -263,8 +246,14 @@ void QAndroidTextureVideoOutput::clearSurfaceTexture() } // Also reset the attached OpenGL texture - if (m_surfaceTextureCanAttachToContext) + // Note: The Android SurfaceTexture class does not release the texture on deletion, + // only if detachFromGLContext() called (API level >= 16), so we'll do it manually, + // on the render thread. + if (m_surfaceTextureCanAttachToContext) { + if (!m_glDeleter.isNull()) + m_glDeleter->deleteTexture(m_externalTex); m_externalTex = 0; + } } AndroidSurfaceTexture *QAndroidTextureVideoOutput::surfaceTexture() @@ -394,19 +383,17 @@ void QAndroidTextureVideoOutput::createGLResources() Q_ASSERT(QOpenGLContext::currentContext() != NULL); if (!m_glDeleter) - m_glDeleter = new OpenGLResourcesDeleter; + m_glDeleter.reset(new OpenGLResourcesDeleter); if (m_surfaceTextureCanAttachToContext && !m_externalTex) { m_surfaceTexture->detachFromGLContext(); glGenTextures(1, &m_externalTex); m_surfaceTexture->attachToGLContext(m_externalTex); - m_glDeleter->setTexture(m_externalTex); } if (!m_fbo || m_fbo->size() != m_nativeSize) { delete m_fbo; m_fbo = new QOpenGLFramebufferObject(m_nativeSize); - m_glDeleter->setFbo(m_fbo); } if (!m_program) { @@ -437,8 +424,6 @@ void QAndroidTextureVideoOutput::createGLResources() m_program->bindAttributeLocation("vertexCoordsArray", 0); m_program->bindAttributeLocation("textureCoordArray", 1); m_program->link(); - - m_glDeleter->setShaderProgram(m_program); } } @@ -448,8 +433,7 @@ void QAndroidTextureVideoOutput::customEvent(QEvent *e) // This is running in the render thread (OpenGL enabled) if (!m_surfaceTextureCanAttachToContext && !m_externalTex) { glGenTextures(1, &m_externalTex); - m_glDeleter = new OpenGLResourcesDeleter; // will cleanup GL resources in the correct thread - m_glDeleter->setTexture(m_externalTex); + m_glDeleter.reset(new OpenGLResourcesDeleter); // We'll use this to cleanup GL resources in the correct thread emit readyChanged(true); } } diff --git a/src/plugins/android/src/common/qandroidvideooutput.h b/src/plugins/android/src/common/qandroidvideooutput.h index 67bac7052..a12db75a2 100644 --- a/src/plugins/android/src/common/qandroidvideooutput.h +++ b/src/plugins/android/src/common/qandroidvideooutput.h @@ -50,7 +50,6 @@ class AndroidSurfaceTexture; class AndroidSurfaceHolder; class QOpenGLFramebufferObject; class QOpenGLShaderProgram; -class OpenGLResourcesDeleter; class QAbstractVideoSurface; class QAndroidVideoOutput : public QObject @@ -75,6 +74,19 @@ protected: QAndroidVideoOutput(QObject *parent) : QObject(parent) { } }; +class OpenGLResourcesDeleter : public QObject +{ + Q_OBJECT +public: + void deleteTexture(quint32 id) { QMetaObject::invokeMethod(this, "deleteTextureHelper", Qt::AutoConnection, Q_ARG(quint32, id)); } + void deleteFbo(QOpenGLFramebufferObject *fbo) { QMetaObject::invokeMethod(this, "deleteFboHelper", Qt::AutoConnection, Q_ARG(void *, fbo)); } + void deleteShaderProgram(QOpenGLShaderProgram *prog) { QMetaObject::invokeMethod(this, "deleteShaderProgramHelper", Qt::AutoConnection, Q_ARG(void *, prog)); } + +private: + Q_INVOKABLE void deleteTextureHelper(quint32 id); + Q_INVOKABLE void deleteFboHelper(void *fbo); + Q_INVOKABLE void deleteShaderProgramHelper(void *prog); +}; class QAndroidTextureVideoOutput : public QAndroidVideoOutput { @@ -114,7 +126,7 @@ private: quint32 m_externalTex; QOpenGLFramebufferObject *m_fbo; QOpenGLShaderProgram *m_program; - OpenGLResourcesDeleter *m_glDeleter; + QScopedPointer<OpenGLResourcesDeleter, QScopedPointerDeleteLater> m_glDeleter; bool m_surfaceTextureCanAttachToContext; diff --git a/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp b/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp index 0b082b02b..8663f8c5f 100644 --- a/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp +++ b/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp @@ -684,6 +684,9 @@ void QAndroidCameraSession::onCameraTakePictureFailed() { emit imageCaptureError(m_currentImageCaptureId, QCameraImageCapture::ResourceError, tr("Failed to capture image")); + + // Preview needs to be restarted and the preview call back must be setup again + m_camera->startPreview(); } void QAndroidCameraSession::onCameraPictureExposed() @@ -697,6 +700,9 @@ void QAndroidCameraSession::onCameraPictureExposed() void QAndroidCameraSession::onLastPreviewFrameFetched(const QVideoFrame &frame) { + if (m_captureCanceled) + return; + QtConcurrent::run(this, &QAndroidCameraSession::processPreviewImage, m_currentImageCaptureId, frame, diff --git a/src/plugins/android/src/mediacapture/qandroidviewfindersettingscontrol.cpp b/src/plugins/android/src/mediacapture/qandroidviewfindersettingscontrol.cpp index 2a2882cb9..01a826064 100644 --- a/src/plugins/android/src/mediacapture/qandroidviewfindersettingscontrol.cpp +++ b/src/plugins/android/src/mediacapture/qandroidviewfindersettingscontrol.cpp @@ -2,31 +2,37 @@ ** ** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2016 Ruslan Baratov -** Contact: http://www.qt.io/licensing/ +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $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 The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company 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 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** diff --git a/src/plugins/android/src/mediacapture/qandroidviewfindersettingscontrol.h b/src/plugins/android/src/mediacapture/qandroidviewfindersettingscontrol.h index a6bf70857..79ebf3fc2 100644 --- a/src/plugins/android/src/mediacapture/qandroidviewfindersettingscontrol.h +++ b/src/plugins/android/src/mediacapture/qandroidviewfindersettingscontrol.h @@ -2,31 +2,37 @@ ** ** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2016 Ruslan Baratov -** Contact: http://www.qt.io/licensing/ +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $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 The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company 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 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** diff --git a/src/plugins/android/src/wrappers/jni/androidcamera.cpp b/src/plugins/android/src/wrappers/jni/androidcamera.cpp index 3295e4d33..76d3ffb44 100644 --- a/src/plugins/android/src/wrappers/jni/androidcamera.cpp +++ b/src/plugins/android/src/wrappers/jni/androidcamera.cpp @@ -152,6 +152,16 @@ static void notifyNewPreviewFrame(JNIEnv *env, jobject, int id, jbyteArray data, Q_EMIT (*it)->newPreviewFrame(frame); } +static void notifyFrameAvailable(JNIEnv *, jobject, int id) +{ + QReadLocker locker(rwLock); + const auto it = cameras->constFind(id); + if (Q_UNLIKELY(it == cameras->cend())) + return; + + (*it)->fetchLastPreviewFrame(); +} + class AndroidCameraPrivate : public QObject { Q_OBJECT @@ -1540,6 +1550,9 @@ void AndroidCameraPrivate::stopPreview() { QJNIEnvironmentPrivate env; + // cancel any pending new frame notification + m_cameraListener.callMethod<void>("notifyWhenFrameAvailable", "(Z)V", false); + m_camera.callMethod<void>("stopPreview"); exceptionCheckAndClear(env); @@ -1550,6 +1563,11 @@ void AndroidCameraPrivate::takePicture() { QJNIEnvironmentPrivate env; + // We must clear the preview callback before calling takePicture(), otherwise the call will + // block and the camera server will be frozen until the next device restart... + // That problem only happens on some devices and on the emulator + m_cameraListener.callMethod<void>("clearPreviewCallback", "(Landroid/hardware/Camera;)V", m_camera.object()); + m_camera.callMethod<void>("takePicture", "(Landroid/hardware/Camera$ShutterCallback;" "Landroid/hardware/Camera$PictureCallback;" "Landroid/hardware/Camera$PictureCallback;)V", @@ -1576,8 +1594,11 @@ void AndroidCameraPrivate::fetchLastPreviewFrame() QJNIEnvironmentPrivate env; QJNIObjectPrivate data = m_cameraListener.callObjectMethod("lastPreviewBuffer", "()[B"); - if (!data.isValid()) + if (!data.isValid()) { + // If there's no buffer received yet, retry when the next one arrives + m_cameraListener.callMethod<void>("notifyWhenFrameAvailable", "(Z)V", true); return; + } const int arrayLength = env->GetArrayLength(static_cast<jbyteArray>(data.object())); if (arrayLength == 0) @@ -1643,7 +1664,8 @@ bool AndroidCamera::initJNI(JNIEnv *env) {"notifyAutoFocusComplete", "(IZ)V", (void *)notifyAutoFocusComplete}, {"notifyPictureExposed", "(I)V", (void *)notifyPictureExposed}, {"notifyPictureCaptured", "(I[B)V", (void *)notifyPictureCaptured}, - {"notifyNewPreviewFrame", "(I[BIIII)V", (void *)notifyNewPreviewFrame} + {"notifyNewPreviewFrame", "(I[BIIII)V", (void *)notifyNewPreviewFrame}, + {"notifyFrameAvailable", "(I)V", (void *)notifyFrameAvailable} }; if (clazz && env->RegisterNatives(clazz, diff --git a/src/plugins/android/src/wrappers/jni/androidsurfacetexture.cpp b/src/plugins/android/src/wrappers/jni/androidsurfacetexture.cpp index df09d0819..764315acd 100644 --- a/src/plugins/android/src/wrappers/jni/androidsurfacetexture.cpp +++ b/src/plugins/android/src/wrappers/jni/androidsurfacetexture.cpp @@ -62,7 +62,7 @@ static void notifyFrameAvailable(JNIEnv* , jobject, jlong id) Q_EMIT obj->frameAvailable(); } -AndroidSurfaceTexture::AndroidSurfaceTexture(unsigned int texName) +AndroidSurfaceTexture::AndroidSurfaceTexture(quint32 texName) : QObject() { Q_STATIC_ASSERT(sizeof (jlong) >= sizeof (void *)); @@ -163,7 +163,7 @@ jobject AndroidSurfaceTexture::surfaceHolder() return m_surfaceHolder.object(); } -void AndroidSurfaceTexture::attachToGLContext(int texName) +void AndroidSurfaceTexture::attachToGLContext(quint32 texName) { if (QtAndroidPrivate::androidSdkVersion() < 16 || !m_surfaceTexture.isValid()) return; diff --git a/src/plugins/android/src/wrappers/jni/androidsurfacetexture.h b/src/plugins/android/src/wrappers/jni/androidsurfacetexture.h index 0a271287a..911711774 100644 --- a/src/plugins/android/src/wrappers/jni/androidsurfacetexture.h +++ b/src/plugins/android/src/wrappers/jni/androidsurfacetexture.h @@ -51,7 +51,7 @@ class AndroidSurfaceTexture : public QObject { Q_OBJECT public: - explicit AndroidSurfaceTexture(unsigned int texName); + explicit AndroidSurfaceTexture(quint32 texName); ~AndroidSurfaceTexture(); jobject surfaceTexture(); @@ -63,7 +63,7 @@ public: void release(); // API level 14 void updateTexImage(); - void attachToGLContext(int texName); // API level 16 + void attachToGLContext(quint32 texName); // API level 16 void detachFromGLContext(); // API level 16 static bool initJNI(JNIEnv *env); |