Android: Camera updates
There's no need for callbacks to block any other threads from reading from the camera pool, so use a read/write lock instead. There's also no benefits gained from using a QMap, so use a QHash map instead. Change-Id: Iaac74c0173d2dddc296f5d2c03116724ffdc588c Reviewed-by: Yoann Lopes <yoann.lopes@theqtcompany.com>
This commit is contained in:
committed by
Yoann Lopes
parent
7f04598859
commit
ece9005efe
@@ -37,16 +37,18 @@
|
|||||||
|
|
||||||
#include <qstringlist.h>
|
#include <qstringlist.h>
|
||||||
#include <qdebug.h>
|
#include <qdebug.h>
|
||||||
#include <qmutex.h>
|
|
||||||
#include <QtCore/private/qjnihelpers_p.h>
|
#include <QtCore/private/qjnihelpers_p.h>
|
||||||
#include <QtCore/qthread.h>
|
#include <QtCore/qthread.h>
|
||||||
|
#include <QtCore/qreadwritelock.h>
|
||||||
|
#include <QtCore/qmutex.h>
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
static const char QtCameraListenerClassName[] = "org/qtproject/qt5/android/multimedia/QtCameraListener";
|
static const char QtCameraListenerClassName[] = "org/qtproject/qt5/android/multimedia/QtCameraListener";
|
||||||
static QMutex g_cameraMapMutex;
|
|
||||||
typedef QMap<int, AndroidCamera *> CameraMap;
|
typedef QHash<int, AndroidCamera *> CameraMap;
|
||||||
Q_GLOBAL_STATIC(CameraMap, g_cameraMap)
|
Q_GLOBAL_STATIC(CameraMap, cameras)
|
||||||
|
Q_GLOBAL_STATIC(QReadWriteLock, rwLock)
|
||||||
|
|
||||||
static inline bool exceptionCheckAndClear(JNIEnv *env)
|
static inline bool exceptionCheckAndClear(JNIEnv *env)
|
||||||
{
|
{
|
||||||
@@ -88,43 +90,49 @@ static QJNIObjectPrivate rectToArea(const QRect &rect)
|
|||||||
// native method for QtCameraLisener.java
|
// native method for QtCameraLisener.java
|
||||||
static void notifyAutoFocusComplete(JNIEnv* , jobject, int id, jboolean success)
|
static void notifyAutoFocusComplete(JNIEnv* , jobject, int id, jboolean success)
|
||||||
{
|
{
|
||||||
QMutexLocker locker(&g_cameraMapMutex);
|
QReadLocker locker(rwLock);
|
||||||
AndroidCamera *obj = g_cameraMap->value(id, 0);
|
const auto it = cameras->constFind(id);
|
||||||
if (obj)
|
if (Q_UNLIKELY(it == cameras->cend()))
|
||||||
Q_EMIT obj->autoFocusComplete(success);
|
return;
|
||||||
|
|
||||||
|
Q_EMIT (*it)->autoFocusComplete(success);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void notifyPictureExposed(JNIEnv* , jobject, int id)
|
static void notifyPictureExposed(JNIEnv* , jobject, int id)
|
||||||
{
|
{
|
||||||
QMutexLocker locker(&g_cameraMapMutex);
|
QReadLocker locker(rwLock);
|
||||||
AndroidCamera *obj = g_cameraMap->value(id, 0);
|
const auto it = cameras->constFind(id);
|
||||||
if (obj)
|
if (Q_UNLIKELY(it == cameras->cend()))
|
||||||
Q_EMIT obj->pictureExposed();
|
return;
|
||||||
|
|
||||||
|
Q_EMIT (*it)->pictureExposed();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void notifyPictureCaptured(JNIEnv *env, jobject, int id, jbyteArray data)
|
static void notifyPictureCaptured(JNIEnv *env, jobject, int id, jbyteArray data)
|
||||||
{
|
{
|
||||||
QMutexLocker locker(&g_cameraMapMutex);
|
QReadLocker locker(rwLock);
|
||||||
AndroidCamera *obj = g_cameraMap->value(id, 0);
|
const auto it = cameras->constFind(id);
|
||||||
if (obj) {
|
if (Q_UNLIKELY(it == cameras->cend()))
|
||||||
const int arrayLength = env->GetArrayLength(data);
|
return;
|
||||||
QByteArray bytes(arrayLength, Qt::Uninitialized);
|
|
||||||
env->GetByteArrayRegion(data, 0, arrayLength, (jbyte*)bytes.data());
|
const int arrayLength = env->GetArrayLength(data);
|
||||||
Q_EMIT obj->pictureCaptured(bytes);
|
QByteArray bytes(arrayLength, Qt::Uninitialized);
|
||||||
}
|
env->GetByteArrayRegion(data, 0, arrayLength, (jbyte*)bytes.data());
|
||||||
|
Q_EMIT (*it)->pictureCaptured(bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void notifyNewPreviewFrame(JNIEnv *env, jobject, int id, jbyteArray data, int width, int height)
|
static void notifyNewPreviewFrame(JNIEnv *env, jobject, int id, jbyteArray data, int width, int height)
|
||||||
{
|
{
|
||||||
QMutexLocker locker(&g_cameraMapMutex);
|
QReadLocker locker(rwLock);
|
||||||
AndroidCamera *obj = g_cameraMap->value(id, 0);
|
const auto it = cameras->constFind(id);
|
||||||
if (obj) {
|
if (Q_UNLIKELY(it == cameras->cend()))
|
||||||
const int arrayLength = env->GetArrayLength(data);
|
return;
|
||||||
QByteArray bytes(arrayLength, Qt::Uninitialized);
|
|
||||||
env->GetByteArrayRegion(data, 0, arrayLength, (jbyte*)bytes.data());
|
|
||||||
|
|
||||||
Q_EMIT obj->newPreviewFrame(bytes, width, height);
|
const int arrayLength = env->GetArrayLength(data);
|
||||||
}
|
QByteArray bytes(arrayLength, Qt::Uninitialized);
|
||||||
|
env->GetByteArrayRegion(data, 0, arrayLength, (jbyte*)bytes.data());
|
||||||
|
|
||||||
|
Q_EMIT (*it)->newPreviewFrame(bytes, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
class AndroidCameraPrivate : public QObject
|
class AndroidCameraPrivate : public QObject
|
||||||
@@ -255,12 +263,11 @@ AndroidCamera::~AndroidCamera()
|
|||||||
{
|
{
|
||||||
Q_D(AndroidCamera);
|
Q_D(AndroidCamera);
|
||||||
if (d->m_camera.isValid()) {
|
if (d->m_camera.isValid()) {
|
||||||
g_cameraMapMutex.lock();
|
release();
|
||||||
g_cameraMap->remove(d->m_cameraId);
|
QWriteLocker locker(rwLock);
|
||||||
g_cameraMapMutex.unlock();
|
cameras->remove(cameraId());
|
||||||
}
|
}
|
||||||
|
|
||||||
release();
|
|
||||||
m_worker->exit();
|
m_worker->exit();
|
||||||
m_worker->wait(5000);
|
m_worker->wait(5000);
|
||||||
}
|
}
|
||||||
@@ -283,9 +290,9 @@ AndroidCamera *AndroidCamera::open(int cameraId)
|
|||||||
}
|
}
|
||||||
|
|
||||||
AndroidCamera *q = new AndroidCamera(d, worker);
|
AndroidCamera *q = new AndroidCamera(d, worker);
|
||||||
g_cameraMapMutex.lock();
|
QWriteLocker locker(rwLock);
|
||||||
g_cameraMap->insert(cameraId, q);
|
cameras->insert(cameraId, q);
|
||||||
g_cameraMapMutex.unlock();
|
|
||||||
return q;
|
return q;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user