From f9a576826c0d770aaae8aadbedaf83e1c0b72e0a Mon Sep 17 00:00:00 2001 From: Val Doroshchuk Date: Thu, 26 Jul 2018 15:08:28 +0200 Subject: Android: Fix fetching video frame data from the GUI thread MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If QAbstractVideoSurface is not used on rendering thread added a way to pass shared opengl context via GLContext surface property. Camera and media players that are created in Qt Quick will usually have their rendering done on the render thread, but the callback for custom video surface(s) (or probes) will usually be handle on the GUI thread, so to make it convenient to for the user to access the frame data, which is rendered on request, we now set-up context sharing and render to a fbo on the calling thread, if needed. Task-number: QTBUG-69333 Change-Id: I4cc5c1f741c82376f1402a047b946b59281c9a4c Reviewed-by: Christian Strømme --- .../android/src/common/qandroidvideooutput.cpp | 33 ++++++++++++++++++++++ .../android/src/common/qandroidvideooutput.h | 5 ++++ 2 files changed, 38 insertions(+) (limited to 'src/plugins/android/src') diff --git a/src/plugins/android/src/common/qandroidvideooutput.cpp b/src/plugins/android/src/common/qandroidvideooutput.cpp index 083ceff24..a4f4dbd5d 100644 --- a/src/plugins/android/src/common/qandroidvideooutput.cpp +++ b/src/plugins/android/src/common/qandroidvideooutput.cpp @@ -49,6 +49,8 @@ #include #include #include +#include +#include QT_BEGIN_NAMESPACE @@ -182,6 +184,8 @@ QAndroidTextureVideoOutput::QAndroidTextureVideoOutput(QObject *parent) QAndroidTextureVideoOutput::~QAndroidTextureVideoOutput() { + delete m_offscreenSurface; + delete m_glContext; clearSurfaceTexture(); if (m_glDeleter) { // Make sure all of these are deleted on the render thread. @@ -345,6 +349,35 @@ bool QAndroidTextureVideoOutput::renderFrameToFbo() if (!m_nativeSize.isValid() || !m_surfaceTexture) return false; + // Make sure we have an OpenGL context to make current. + if (!QOpenGLContext::currentContext() && !m_glContext) { + // Create Hidden QWindow surface to create context in this thread. + m_offscreenSurface = new QWindow(); + m_offscreenSurface->setSurfaceType(QWindow::OpenGLSurface); + // Needs geometry to be a valid surface, but size is not important. + m_offscreenSurface->setGeometry(0, 0, 1, 1); + m_offscreenSurface->create(); + + // Create OpenGL context and set share context from surface. + m_glContext = new QOpenGLContext(); + m_glContext->setFormat(m_offscreenSurface->requestedFormat()); + + auto surface = qobject_cast(m_surface->property("videoSurface").value()); + if (!surface) + surface = m_surface; + auto shareContext = qobject_cast(surface->property("GLContext").value()); + if (shareContext) + m_glContext->setShareContext(shareContext); + + if (!m_glContext->create()) { + qWarning("Failed to create QOpenGLContext"); + return false; + } + } + + if (m_glContext) + m_glContext->makeCurrent(m_offscreenSurface); + createGLResources(); m_surfaceTexture->updateTexImage(); diff --git a/src/plugins/android/src/common/qandroidvideooutput.h b/src/plugins/android/src/common/qandroidvideooutput.h index 2a35247e9..456fe8e22 100644 --- a/src/plugins/android/src/common/qandroidvideooutput.h +++ b/src/plugins/android/src/common/qandroidvideooutput.h @@ -51,6 +51,8 @@ class AndroidSurfaceHolder; class QOpenGLFramebufferObject; class QOpenGLShaderProgram; class QAbstractVideoSurface; +class QWindow; +class QOpenGLContext; class QAndroidVideoOutput : public QObject { @@ -132,6 +134,9 @@ private: bool m_surfaceTextureCanAttachToContext; + QWindow *m_offscreenSurface = nullptr; + QOpenGLContext *m_glContext = nullptr; + friend class AndroidTextureVideoBuffer; }; -- cgit v1.2.3 From 72fdf4b20e916ea87b334be1a35235ac1023e0d8 Mon Sep 17 00:00:00 2001 From: Val Doroshchuk Date: Wed, 13 Nov 2019 11:05:48 +0100 Subject: Android: Don't close camera when recording permission is asked If camera permission is granted and recording is requested it also requires recording audio permission. If it was not granted before the popup will be shown to ask the user to grant the permission and the app goes to inactive state, which destroys the camera handlers. When the camera is loaded but the app requires additional permissions, it should not destroy the camera. Change-Id: Iee3662a7ac3381b0eb29190779b0116f9f64304f Fixes: QTBUG-79909 Reviewed-by: Volker Hilsheimer --- src/plugins/android/src/common/qandroidmultimediautils.cpp | 5 +++++ src/plugins/android/src/common/qandroidmultimediautils.h | 1 + .../android/src/mediacapture/qandroidcamerasession.cpp | 11 ++++++++++- src/plugins/android/src/mediacapture/qandroidcamerasession.h | 2 ++ .../android/src/mediacapture/qandroidcapturesession.cpp | 6 ++++-- src/plugins/android/src/wrappers/jni/androidmediarecorder.cpp | 5 ----- src/plugins/android/src/wrappers/jni/androidmediarecorder.h | 1 - 7 files changed, 22 insertions(+), 9 deletions(-) (limited to 'src/plugins/android/src') diff --git a/src/plugins/android/src/common/qandroidmultimediautils.cpp b/src/plugins/android/src/common/qandroidmultimediautils.cpp index a4a7f773d..fa6e7da65 100644 --- a/src/plugins/android/src/common/qandroidmultimediautils.cpp +++ b/src/plugins/android/src/common/qandroidmultimediautils.cpp @@ -139,4 +139,9 @@ bool qt_androidRequestPermission(const QString &key) return true; } +bool qt_androidRequestRecordingPermission() +{ + return qt_androidRequestPermission(QLatin1String("android.permission.RECORD_AUDIO")); +} + QT_END_NAMESPACE diff --git a/src/plugins/android/src/common/qandroidmultimediautils.h b/src/plugins/android/src/common/qandroidmultimediautils.h index 0a837ae3c..bbd2e9aa5 100644 --- a/src/plugins/android/src/common/qandroidmultimediautils.h +++ b/src/plugins/android/src/common/qandroidmultimediautils.h @@ -56,6 +56,7 @@ QVideoFrame::PixelFormat qt_pixelFormatFromAndroidImageFormat(AndroidCamera::Ima AndroidCamera::ImageFormat qt_androidImageFormatFromPixelFormat(QVideoFrame::PixelFormat f); bool qt_androidRequestPermission(const QString &key); +bool qt_androidRequestRecordingPermission(); QT_END_NAMESPACE diff --git a/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp b/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp index 6a30e5300..9de3330c7 100644 --- a/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp +++ b/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp @@ -78,6 +78,7 @@ QAndroidCameraSession::QAndroidCameraSession(QObject *parent) , m_captureCanceled(false) , m_currentImageCaptureId(-1) , m_previewCallback(0) + , m_keepActive(false) { m_mediaStorageLocation.addStorageLocation( QMediaStorageLocation::Pictures, @@ -913,7 +914,7 @@ void QAndroidCameraSession::onApplicationStateChanged(Qt::ApplicationState state { switch (state) { case Qt::ApplicationInactive: - if (m_state != QCamera::UnloadedState) { + if (!m_keepActive && m_state != QCamera::UnloadedState) { m_savedState = m_state; close(); m_state = QCamera::UnloadedState; @@ -931,4 +932,12 @@ void QAndroidCameraSession::onApplicationStateChanged(Qt::ApplicationState state } } +bool QAndroidCameraSession::requestRecordingPermission() +{ + m_keepActive = true; + const bool result = qt_androidRequestRecordingPermission(); + m_keepActive = false; + return result; +} + QT_END_NAMESPACE diff --git a/src/plugins/android/src/mediacapture/qandroidcamerasession.h b/src/plugins/android/src/mediacapture/qandroidcamerasession.h index b51dcc628..728dc484e 100644 --- a/src/plugins/android/src/mediacapture/qandroidcamerasession.h +++ b/src/plugins/android/src/mediacapture/qandroidcamerasession.h @@ -112,6 +112,7 @@ public: virtual void onFrameAvailable(const QVideoFrame &frame) = 0; }; void setPreviewCallback(PreviewCallback *callback); + bool requestRecordingPermission(); Q_SIGNALS: void statusChanged(QCamera::Status status); @@ -196,6 +197,7 @@ private: QSet m_videoProbes; QMutex m_videoProbesMutex; PreviewCallback *m_previewCallback; + bool m_keepActive; }; QT_END_NAMESPACE diff --git a/src/plugins/android/src/mediacapture/qandroidcapturesession.cpp b/src/plugins/android/src/mediacapture/qandroidcapturesession.cpp index bc9bc983e..7cc3ad619 100644 --- a/src/plugins/android/src/mediacapture/qandroidcapturesession.cpp +++ b/src/plugins/android/src/mediacapture/qandroidcapturesession.cpp @@ -206,8 +206,10 @@ void QAndroidCaptureSession::start() delete m_mediaRecorder; } - - if (!AndroidMediaRecorder::requestRecordingPermission()) { + const bool granted = m_cameraSession + ? m_cameraSession->requestRecordingPermission() + : qt_androidRequestRecordingPermission(); + if (!granted) { setStatus(QMediaRecorder::UnavailableStatus); Q_EMIT error(QMediaRecorder::ResourceError, QLatin1String("Permission denied.")); return; diff --git a/src/plugins/android/src/wrappers/jni/androidmediarecorder.cpp b/src/plugins/android/src/wrappers/jni/androidmediarecorder.cpp index d0101411b..d607ab806 100644 --- a/src/plugins/android/src/wrappers/jni/androidmediarecorder.cpp +++ b/src/plugins/android/src/wrappers/jni/androidmediarecorder.cpp @@ -383,11 +383,6 @@ void AndroidMediaRecorder::setSurfaceHolder(AndroidSurfaceHolder *holder) } } -bool AndroidMediaRecorder::requestRecordingPermission() -{ - return qt_androidRequestPermission(QLatin1String("android.permission.RECORD_AUDIO")); -} - bool AndroidMediaRecorder::initJNI(JNIEnv *env) { jclass clazz = QJNIEnvironmentPrivate::findClass(QtMediaRecorderListenerClassName, diff --git a/src/plugins/android/src/wrappers/jni/androidmediarecorder.h b/src/plugins/android/src/wrappers/jni/androidmediarecorder.h index cd2d164d8..e4b3a80ea 100644 --- a/src/plugins/android/src/wrappers/jni/androidmediarecorder.h +++ b/src/plugins/android/src/wrappers/jni/androidmediarecorder.h @@ -160,7 +160,6 @@ public: void setSurfaceTexture(AndroidSurfaceTexture *texture); void setSurfaceHolder(AndroidSurfaceHolder *holder); - static bool requestRecordingPermission(); static bool initJNI(JNIEnv *env); Q_SIGNALS: -- cgit v1.2.3 From 49bf444b44dac10602af0af862f0951835ea5895 Mon Sep 17 00:00:00 2001 From: Val Doroshchuk Date: Fri, 15 Nov 2019 10:47:17 +0100 Subject: Android: Remove usage of qt_androidRequestPermission Use specific function instead, e.g. qt_androidRequestCameraPermission. Change-Id: I925e4d8ac4f1993c073930a79453894dd516d769 Reviewed-by: Volker Hilsheimer --- .../android/src/common/qandroidmultimediautils.cpp | 9 +++++++-- src/plugins/android/src/common/qandroidmultimediautils.h | 2 +- .../android/src/mediacapture/qandroidcamerasession.cpp | 2 +- src/plugins/android/src/wrappers/jni/androidcamera.cpp | 15 ++++----------- 4 files changed, 13 insertions(+), 15 deletions(-) (limited to 'src/plugins/android/src') diff --git a/src/plugins/android/src/common/qandroidmultimediautils.cpp b/src/plugins/android/src/common/qandroidmultimediautils.cpp index fa6e7da65..1f03d5d29 100644 --- a/src/plugins/android/src/common/qandroidmultimediautils.cpp +++ b/src/plugins/android/src/common/qandroidmultimediautils.cpp @@ -113,7 +113,7 @@ AndroidCamera::ImageFormat qt_androidImageFormatFromPixelFormat(QVideoFrame::Pix } } -bool qt_androidRequestPermission(const QString &key) +static bool androidRequestPermission(const QString &key) { using namespace QtAndroidPrivate; @@ -139,9 +139,14 @@ bool qt_androidRequestPermission(const QString &key) return true; } +bool qt_androidRequestCameraPermission() +{ + return androidRequestPermission(QLatin1String("android.permission.CAMERA")); +} + bool qt_androidRequestRecordingPermission() { - return qt_androidRequestPermission(QLatin1String("android.permission.RECORD_AUDIO")); + return androidRequestPermission(QLatin1String("android.permission.RECORD_AUDIO")); } QT_END_NAMESPACE diff --git a/src/plugins/android/src/common/qandroidmultimediautils.h b/src/plugins/android/src/common/qandroidmultimediautils.h index bbd2e9aa5..381671cb8 100644 --- a/src/plugins/android/src/common/qandroidmultimediautils.h +++ b/src/plugins/android/src/common/qandroidmultimediautils.h @@ -55,7 +55,7 @@ bool qt_sizeLessThan(const QSize &s1, const QSize &s2); QVideoFrame::PixelFormat qt_pixelFormatFromAndroidImageFormat(AndroidCamera::ImageFormat f); AndroidCamera::ImageFormat qt_androidImageFormatFromPixelFormat(QVideoFrame::PixelFormat f); -bool qt_androidRequestPermission(const QString &key); +bool qt_androidRequestCameraPermission(); bool qt_androidRequestRecordingPermission(); QT_END_NAMESPACE diff --git a/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp b/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp index 9de3330c7..f3ad84836 100644 --- a/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp +++ b/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp @@ -184,7 +184,7 @@ bool QAndroidCameraSession::open() m_status = QCamera::LoadingStatus; emit statusChanged(m_status); - m_camera = AndroidCamera::requestCameraPermission() ? AndroidCamera::open(m_selectedCamera) : nullptr; + m_camera = AndroidCamera::open(m_selectedCamera); if (m_camera) { connect(m_camera, SIGNAL(pictureExposed()), this, SLOT(onCameraPictureExposed())); diff --git a/src/plugins/android/src/wrappers/jni/androidcamera.cpp b/src/plugins/android/src/wrappers/jni/androidcamera.cpp index 2f32fb742..3ea7bc773 100644 --- a/src/plugins/android/src/wrappers/jni/androidcamera.cpp +++ b/src/plugins/android/src/wrappers/jni/androidcamera.cpp @@ -58,11 +58,6 @@ QT_BEGIN_NAMESPACE static const char QtCameraListenerClassName[] = "org/qtproject/qt5/android/multimedia/QtCameraListener"; -static QString cameraPermissionKey() -{ - return QStringLiteral("android.permission.CAMERA"); -} - typedef QHash CameraMap; Q_GLOBAL_STATIC(CameraMap, cameras) Q_GLOBAL_STATIC(QReadWriteLock, rwLock) @@ -324,6 +319,9 @@ AndroidCamera::~AndroidCamera() AndroidCamera *AndroidCamera::open(int cameraId) { + if (!qt_androidRequestCameraPermission()) + return nullptr; + AndroidCameraPrivate *d = new AndroidCameraPrivate(); QThread *worker = new QThread; worker->start(); @@ -764,7 +762,7 @@ QJNIObjectPrivate AndroidCamera::getCameraObject() int AndroidCamera::getNumberOfCameras() { - if (!requestCameraPermission()) + if (!qt_androidRequestCameraPermission()) return 0; return QJNIObjectPrivate::callStaticMethod("android/hardware/Camera", @@ -801,11 +799,6 @@ void AndroidCamera::getCameraInfo(int id, AndroidCameraInfo *info) } } -bool AndroidCamera::requestCameraPermission() -{ - return qt_androidRequestPermission(cameraPermissionKey()); -} - void AndroidCamera::startPreview() { Q_D(AndroidCamera); -- cgit v1.2.3