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:
Christian Strømme
2015-11-28 15:32:37 +01:00
committed by Yoann Lopes
parent 7f04598859
commit ece9005efe

View File

@@ -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;
} }