diff options
Diffstat (limited to 'src/multimedia/platform/android/wrappers/jni/androidcamera.cpp')
-rw-r--r-- | src/multimedia/platform/android/wrappers/jni/androidcamera.cpp | 1747 |
1 files changed, 0 insertions, 1747 deletions
diff --git a/src/multimedia/platform/android/wrappers/jni/androidcamera.cpp b/src/multimedia/platform/android/wrappers/jni/androidcamera.cpp deleted file mode 100644 index e40921f38..000000000 --- a/src/multimedia/platform/android/wrappers/jni/androidcamera.cpp +++ /dev/null @@ -1,1747 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2016 Ruslan Baratov -** Contact: https://www.qt.io/licensing/ -** -** 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 The Qt Company. For licensing terms -** 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 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. -** -** 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$ -** -****************************************************************************/ - -#include "androidcamera_p.h" -#include "androidsurfacetexture_p.h" -#include "androidsurfaceview_p.h" -#include "qandroidmultimediautils_p.h" -#include "qandroidglobal_p.h" - -#include <qstringlist.h> -#include <qdebug.h> -#include <QtCore/qthread.h> -#include <QtCore/qreadwritelock.h> -#include <QtCore/qmutex.h> -#include <QtMultimedia/private/qmemoryvideobuffer_p.h> -#include <QtCore/qcoreapplication.h> - -#include <mutex> - -QT_BEGIN_NAMESPACE - -static const char QtCameraListenerClassName[] = "org/qtproject/qt/android/multimedia/QtCameraListener"; - -typedef QHash<int, AndroidCamera *> CameraMap; -Q_GLOBAL_STATIC(CameraMap, cameras) -Q_GLOBAL_STATIC(QReadWriteLock, rwLock) - -static QRect areaToRect(jobject areaObj) -{ - QJniObject area(areaObj); - QJniObject rect = area.getObjectField("rect", "Landroid/graphics/Rect;"); - - return QRect(rect.getField<jint>("left"), - rect.getField<jint>("top"), - rect.callMethod<jint>("width"), - rect.callMethod<jint>("height")); -} - -static QJniObject rectToArea(const QRect &rect) -{ - QJniObject jrect("android/graphics/Rect", - "(IIII)V", - rect.left(), rect.top(), rect.right(), rect.bottom()); - - QJniObject area("android/hardware/Camera$Area", - "(Landroid/graphics/Rect;I)V", - jrect.object(), 500); - - return area; -} - -// native method for QtCameraLisener.java -static void notifyAutoFocusComplete(JNIEnv* , jobject, int id, jboolean success) -{ - QReadLocker locker(rwLock); - const auto it = cameras->constFind(id); - if (Q_UNLIKELY(it == cameras->cend())) - return; - - Q_EMIT (*it)->autoFocusComplete(success); -} - -static void notifyPictureExposed(JNIEnv* , jobject, int id) -{ - QReadLocker locker(rwLock); - const auto it = cameras->constFind(id); - if (Q_UNLIKELY(it == cameras->cend())) - return; - - Q_EMIT (*it)->pictureExposed(); -} - -static void notifyPictureCaptured(JNIEnv *env, jobject, int id, jbyteArray data) -{ - QReadLocker locker(rwLock); - const auto it = cameras->constFind(id); - if (Q_UNLIKELY(it == cameras->cend())) - return; - - const int arrayLength = env->GetArrayLength(data); - 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, int format, int bpl) -{ - QReadLocker locker(rwLock); - const auto it = cameras->constFind(id); - if (Q_UNLIKELY(it == cameras->cend())) - return; - - const int arrayLength = env->GetArrayLength(data); - if (arrayLength == 0) - return; - - QByteArray bytes(arrayLength, Qt::Uninitialized); - env->GetByteArrayRegion(data, 0, arrayLength, (jbyte*)bytes.data()); - - QVideoFrame frame(new QMemoryVideoBuffer(bytes, bpl), - QVideoFrameFormat(QSize(width, height), - qt_pixelFormatFromAndroidImageFormat(AndroidCamera::ImageFormat(format)))); - - 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 -public: - AndroidCameraPrivate(); - ~AndroidCameraPrivate(); - - Q_INVOKABLE bool init(int cameraId); - - Q_INVOKABLE void release(); - Q_INVOKABLE bool lock(); - Q_INVOKABLE bool unlock(); - Q_INVOKABLE bool reconnect(); - - Q_INVOKABLE AndroidCamera::CameraFacing getFacing(); - Q_INVOKABLE int getNativeOrientation(); - - Q_INVOKABLE QSize getPreferredPreviewSizeForVideo(); - Q_INVOKABLE QList<QSize> getSupportedPreviewSizes(); - static QList<QSize> getSupportedPreviewSizes(QJniObject ¶meters); - - Q_INVOKABLE QList<AndroidCamera::FpsRange> getSupportedPreviewFpsRange(); - - Q_INVOKABLE AndroidCamera::FpsRange getPreviewFpsRange(); - static AndroidCamera::FpsRange getPreviewFpsRange(QJniObject ¶meters); - Q_INVOKABLE void setPreviewFpsRange(int min, int max); - - Q_INVOKABLE AndroidCamera::ImageFormat getPreviewFormat(); - Q_INVOKABLE void setPreviewFormat(AndroidCamera::ImageFormat fmt); - Q_INVOKABLE QList<AndroidCamera::ImageFormat> getSupportedPreviewFormats(); - static QList<AndroidCamera::ImageFormat> getSupportedPreviewFormats(QJniObject ¶meters); - - Q_INVOKABLE QSize previewSize() const { return m_previewSize; } - Q_INVOKABLE QSize getPreviewSize(); - Q_INVOKABLE void updatePreviewSize(); - Q_INVOKABLE bool setPreviewTexture(void *surfaceTexture); - Q_INVOKABLE bool setPreviewDisplay(void *surfaceHolder); - Q_INVOKABLE void setDisplayOrientation(int degrees); - - Q_INVOKABLE bool isZoomSupported(); - Q_INVOKABLE int getMaxZoom(); - Q_INVOKABLE QList<int> getZoomRatios(); - Q_INVOKABLE int getZoom(); - Q_INVOKABLE void setZoom(int value); - - Q_INVOKABLE QString getFlashMode(); - Q_INVOKABLE void setFlashMode(const QString &value); - - Q_INVOKABLE QString getFocusMode(); - Q_INVOKABLE void setFocusMode(const QString &value); - - Q_INVOKABLE int getMaxNumFocusAreas(); - Q_INVOKABLE QList<QRect> getFocusAreas(); - Q_INVOKABLE void setFocusAreas(const QList<QRect> &areas); - - Q_INVOKABLE void autoFocus(); - Q_INVOKABLE void cancelAutoFocus(); - - Q_INVOKABLE bool isAutoExposureLockSupported(); - Q_INVOKABLE bool getAutoExposureLock(); - Q_INVOKABLE void setAutoExposureLock(bool toggle); - - Q_INVOKABLE bool isAutoWhiteBalanceLockSupported(); - Q_INVOKABLE bool getAutoWhiteBalanceLock(); - Q_INVOKABLE void setAutoWhiteBalanceLock(bool toggle); - - Q_INVOKABLE int getExposureCompensation(); - Q_INVOKABLE void setExposureCompensation(int value); - Q_INVOKABLE float getExposureCompensationStep(); - Q_INVOKABLE int getMinExposureCompensation(); - Q_INVOKABLE int getMaxExposureCompensation(); - - Q_INVOKABLE QString getSceneMode(); - Q_INVOKABLE void setSceneMode(const QString &value); - - Q_INVOKABLE QString getWhiteBalance(); - Q_INVOKABLE void setWhiteBalance(const QString &value); - - Q_INVOKABLE void updateRotation(); - - Q_INVOKABLE QList<QSize> getSupportedPictureSizes(); - Q_INVOKABLE void setPictureSize(const QSize &size); - Q_INVOKABLE void setJpegQuality(int quality); - - Q_INVOKABLE void startPreview(); - Q_INVOKABLE void stopPreview(); - - Q_INVOKABLE void takePicture(); - - Q_INVOKABLE void setupPreviewFrameCallback(); - Q_INVOKABLE void notifyNewFrames(bool notify); - Q_INVOKABLE void fetchLastPreviewFrame(); - - Q_INVOKABLE void applyParameters(); - - Q_INVOKABLE QStringList callParametersStringListMethod(const QByteArray &methodName); - - int m_cameraId; - QRecursiveMutex m_parametersMutex; - QSize m_previewSize; - int m_rotation; - QJniObject m_info; - QJniObject m_parameters; - QJniObject m_camera; - QJniObject m_cameraListener; - -Q_SIGNALS: - void previewSizeChanged(); - void previewStarted(); - void previewFailedToStart(); - void previewStopped(); - - void autoFocusStarted(); - - void whiteBalanceChanged(); - - void takePictureFailed(); - - void lastPreviewFrameFetched(const QVideoFrame &frame); -}; - -AndroidCamera::AndroidCamera(AndroidCameraPrivate *d, QThread *worker) - : QObject(), - d_ptr(d), - m_worker(worker) - -{ - connect(d, &AndroidCameraPrivate::previewSizeChanged, this, &AndroidCamera::previewSizeChanged); - connect(d, &AndroidCameraPrivate::previewStarted, this, &AndroidCamera::previewStarted); - connect(d, &AndroidCameraPrivate::previewFailedToStart, this, &AndroidCamera::previewFailedToStart); - connect(d, &AndroidCameraPrivate::previewStopped, this, &AndroidCamera::previewStopped); - connect(d, &AndroidCameraPrivate::autoFocusStarted, this, &AndroidCamera::autoFocusStarted); - connect(d, &AndroidCameraPrivate::whiteBalanceChanged, this, &AndroidCamera::whiteBalanceChanged); - connect(d, &AndroidCameraPrivate::takePictureFailed, this, &AndroidCamera::takePictureFailed); - connect(d, &AndroidCameraPrivate::lastPreviewFrameFetched, this, &AndroidCamera::lastPreviewFrameFetched); -} - -AndroidCamera::~AndroidCamera() -{ - Q_D(AndroidCamera); - if (d->m_camera.isValid()) { - release(); - QWriteLocker locker(rwLock); - cameras->remove(cameraId()); - } - - m_worker->exit(); - m_worker->wait(5000); -} - -AndroidCamera *AndroidCamera::open(int cameraId) -{ - if (!qt_androidRequestCameraPermission()) - return nullptr; - - AndroidCameraPrivate *d = new AndroidCameraPrivate(); - QThread *worker = new QThread; - worker->start(); - d->moveToThread(worker); - connect(worker, &QThread::finished, d, &AndroidCameraPrivate::deleteLater); - bool ok = true; - QMetaObject::invokeMethod(d, "init", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, ok), Q_ARG(int, cameraId)); - if (!ok) { - worker->quit(); - worker->wait(5000); - delete worker; - return 0; - } - - AndroidCamera *q = new AndroidCamera(d, worker); - QWriteLocker locker(rwLock); - cameras->insert(cameraId, q); - - return q; -} - -int AndroidCamera::cameraId() const -{ - Q_D(const AndroidCamera); - return d->m_cameraId; -} - -bool AndroidCamera::lock() -{ - Q_D(AndroidCamera); - bool ok = true; - QMetaObject::invokeMethod(d, "lock", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, ok)); - return ok; -} - -bool AndroidCamera::unlock() -{ - Q_D(AndroidCamera); - bool ok = true; - QMetaObject::invokeMethod(d, "unlock", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, ok)); - return ok; -} - -bool AndroidCamera::reconnect() -{ - Q_D(AndroidCamera); - bool ok = true; - QMetaObject::invokeMethod(d, "reconnect", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, ok)); - return ok; -} - -void AndroidCamera::release() -{ - Q_D(AndroidCamera); - QMetaObject::invokeMethod(d, "release", Qt::BlockingQueuedConnection); -} - -AndroidCamera::CameraFacing AndroidCamera::getFacing() -{ - Q_D(AndroidCamera); - return d->getFacing(); -} - -int AndroidCamera::getNativeOrientation() -{ - Q_D(AndroidCamera); - return d->getNativeOrientation(); -} - -QSize AndroidCamera::getPreferredPreviewSizeForVideo() -{ - Q_D(AndroidCamera); - return d->getPreferredPreviewSizeForVideo(); -} - -QList<QSize> AndroidCamera::getSupportedPreviewSizes() -{ - Q_D(AndroidCamera); - return d->getSupportedPreviewSizes(); -} - -QList<AndroidCamera::FpsRange> AndroidCamera::getSupportedPreviewFpsRange() -{ - Q_D(AndroidCamera); - return d->getSupportedPreviewFpsRange(); -} - -AndroidCamera::FpsRange AndroidCamera::getPreviewFpsRange() -{ - Q_D(AndroidCamera); - return d->getPreviewFpsRange(); -} - -void AndroidCamera::setPreviewFpsRange(FpsRange range) -{ - Q_D(AndroidCamera); - QMetaObject::invokeMethod(d, "setPreviewFpsRange", Q_ARG(int, range.min), Q_ARG(int, range.max)); -} - -AndroidCamera::ImageFormat AndroidCamera::getPreviewFormat() -{ - Q_D(AndroidCamera); - return d->getPreviewFormat(); -} - -void AndroidCamera::setPreviewFormat(ImageFormat fmt) -{ - Q_D(AndroidCamera); - QMetaObject::invokeMethod(d, "setPreviewFormat", Q_ARG(AndroidCamera::ImageFormat, fmt)); -} - -QList<AndroidCamera::ImageFormat> AndroidCamera::getSupportedPreviewFormats() -{ - Q_D(AndroidCamera); - return d->getSupportedPreviewFormats(); -} - -QSize AndroidCamera::previewSize() const -{ - Q_D(const AndroidCamera); - return d->m_previewSize; -} - -QSize AndroidCamera::actualPreviewSize() -{ - Q_D(AndroidCamera); - return d->getPreviewSize(); -} - -void AndroidCamera::setPreviewSize(const QSize &size) -{ - Q_D(AndroidCamera); - d->m_parametersMutex.lock(); - bool areParametersValid = d->m_parameters.isValid(); - d->m_parametersMutex.unlock(); - if (!areParametersValid) - return; - - d->m_previewSize = size; - QMetaObject::invokeMethod(d, "updatePreviewSize"); -} - -bool AndroidCamera::setPreviewTexture(AndroidSurfaceTexture *surfaceTexture) -{ - Q_D(AndroidCamera); - bool ok = true; - QMetaObject::invokeMethod(d, - "setPreviewTexture", - Qt::BlockingQueuedConnection, - Q_RETURN_ARG(bool, ok), - Q_ARG(void *, surfaceTexture ? surfaceTexture->surfaceTexture() : 0)); - return ok; -} - -bool AndroidCamera::setPreviewDisplay(AndroidSurfaceHolder *surfaceHolder) -{ - Q_D(AndroidCamera); - bool ok = true; - QMetaObject::invokeMethod(d, - "setPreviewDisplay", - Qt::BlockingQueuedConnection, - Q_RETURN_ARG(bool, ok), - Q_ARG(void *, surfaceHolder ? surfaceHolder->surfaceHolder() : 0)); - return ok; -} - -void AndroidCamera::setDisplayOrientation(int degrees) -{ - Q_D(AndroidCamera); - QMetaObject::invokeMethod(d, "setDisplayOrientation", Qt::QueuedConnection, Q_ARG(int, degrees)); -} - -bool AndroidCamera::isZoomSupported() -{ - Q_D(AndroidCamera); - return d->isZoomSupported(); -} - -int AndroidCamera::getMaxZoom() -{ - Q_D(AndroidCamera); - return d->getMaxZoom(); -} - -QList<int> AndroidCamera::getZoomRatios() -{ - Q_D(AndroidCamera); - return d->getZoomRatios(); -} - -int AndroidCamera::getZoom() -{ - Q_D(AndroidCamera); - return d->getZoom(); -} - -void AndroidCamera::setZoom(int value) -{ - Q_D(AndroidCamera); - QMetaObject::invokeMethod(d, "setZoom", Q_ARG(int, value)); -} - -QStringList AndroidCamera::getSupportedFlashModes() -{ - Q_D(AndroidCamera); - return d->callParametersStringListMethod("getSupportedFlashModes"); -} - -QString AndroidCamera::getFlashMode() -{ - Q_D(AndroidCamera); - return d->getFlashMode(); -} - -void AndroidCamera::setFlashMode(const QString &value) -{ - Q_D(AndroidCamera); - QMetaObject::invokeMethod(d, "setFlashMode", Q_ARG(QString, value)); -} - -QStringList AndroidCamera::getSupportedFocusModes() -{ - Q_D(AndroidCamera); - return d->callParametersStringListMethod("getSupportedFocusModes"); -} - -QString AndroidCamera::getFocusMode() -{ - Q_D(AndroidCamera); - return d->getFocusMode(); -} - -void AndroidCamera::setFocusMode(const QString &value) -{ - Q_D(AndroidCamera); - QMetaObject::invokeMethod(d, "setFocusMode", Q_ARG(QString, value)); -} - -int AndroidCamera::getMaxNumFocusAreas() -{ - Q_D(AndroidCamera); - return d->getMaxNumFocusAreas(); -} - -QList<QRect> AndroidCamera::getFocusAreas() -{ - Q_D(AndroidCamera); - return d->getFocusAreas(); -} - -void AndroidCamera::setFocusAreas(const QList<QRect> &areas) -{ - Q_D(AndroidCamera); - QMetaObject::invokeMethod(d, "setFocusAreas", Q_ARG(QList<QRect>, areas)); -} - -void AndroidCamera::autoFocus() -{ - Q_D(AndroidCamera); - QMetaObject::invokeMethod(d, "autoFocus"); -} - -void AndroidCamera::cancelAutoFocus() -{ - Q_D(AndroidCamera); - QMetaObject::invokeMethod(d, "cancelAutoFocus", Qt::QueuedConnection); -} - -bool AndroidCamera::isAutoExposureLockSupported() -{ - Q_D(AndroidCamera); - return d->isAutoExposureLockSupported(); -} - -bool AndroidCamera::getAutoExposureLock() -{ - Q_D(AndroidCamera); - return d->getAutoExposureLock(); -} - -void AndroidCamera::setAutoExposureLock(bool toggle) -{ - Q_D(AndroidCamera); - QMetaObject::invokeMethod(d, "setAutoExposureLock", Q_ARG(bool, toggle)); -} - -bool AndroidCamera::isAutoWhiteBalanceLockSupported() -{ - Q_D(AndroidCamera); - return d->isAutoWhiteBalanceLockSupported(); -} - -bool AndroidCamera::getAutoWhiteBalanceLock() -{ - Q_D(AndroidCamera); - return d->getAutoWhiteBalanceLock(); -} - -void AndroidCamera::setAutoWhiteBalanceLock(bool toggle) -{ - Q_D(AndroidCamera); - QMetaObject::invokeMethod(d, "setAutoWhiteBalanceLock", Q_ARG(bool, toggle)); -} - -int AndroidCamera::getExposureCompensation() -{ - Q_D(AndroidCamera); - return d->getExposureCompensation(); -} - -void AndroidCamera::setExposureCompensation(int value) -{ - Q_D(AndroidCamera); - QMetaObject::invokeMethod(d, "setExposureCompensation", Q_ARG(int, value)); -} - -float AndroidCamera::getExposureCompensationStep() -{ - Q_D(AndroidCamera); - return d->getExposureCompensationStep(); -} - -int AndroidCamera::getMinExposureCompensation() -{ - Q_D(AndroidCamera); - return d->getMinExposureCompensation(); -} - -int AndroidCamera::getMaxExposureCompensation() -{ - Q_D(AndroidCamera); - return d->getMaxExposureCompensation(); -} - -QStringList AndroidCamera::getSupportedSceneModes() -{ - Q_D(AndroidCamera); - return d->callParametersStringListMethod("getSupportedSceneModes"); -} - -QString AndroidCamera::getSceneMode() -{ - Q_D(AndroidCamera); - return d->getSceneMode(); -} - -void AndroidCamera::setSceneMode(const QString &value) -{ - Q_D(AndroidCamera); - QMetaObject::invokeMethod(d, "setSceneMode", Q_ARG(QString, value)); -} - -QStringList AndroidCamera::getSupportedWhiteBalance() -{ - Q_D(AndroidCamera); - return d->callParametersStringListMethod("getSupportedWhiteBalance"); -} - -QString AndroidCamera::getWhiteBalance() -{ - Q_D(AndroidCamera); - return d->getWhiteBalance(); -} - -void AndroidCamera::setWhiteBalance(const QString &value) -{ - Q_D(AndroidCamera); - QMetaObject::invokeMethod(d, "setWhiteBalance", Q_ARG(QString, value)); -} - -void AndroidCamera::setRotation(int rotation) -{ - Q_D(AndroidCamera); - //We need to do it here and not in worker class because we cache rotation - d->m_parametersMutex.lock(); - bool areParametersValid = d->m_parameters.isValid(); - d->m_parametersMutex.unlock(); - if (!areParametersValid) - return; - - d->m_rotation = rotation; - QMetaObject::invokeMethod(d, "updateRotation"); -} - -int AndroidCamera::getRotation() const -{ - Q_D(const AndroidCamera); - return d->m_rotation; -} - -QList<QSize> AndroidCamera::getSupportedPictureSizes() -{ - Q_D(AndroidCamera); - return d->getSupportedPictureSizes(); -} - -void AndroidCamera::setPictureSize(const QSize &size) -{ - Q_D(AndroidCamera); - QMetaObject::invokeMethod(d, "setPictureSize", Q_ARG(QSize, size)); -} - -void AndroidCamera::setJpegQuality(int quality) -{ - Q_D(AndroidCamera); - QMetaObject::invokeMethod(d, "setJpegQuality", Q_ARG(int, quality)); -} - -void AndroidCamera::takePicture() -{ - Q_D(AndroidCamera); - QMetaObject::invokeMethod(d, "takePicture", Qt::BlockingQueuedConnection); -} - -void AndroidCamera::setupPreviewFrameCallback() -{ - Q_D(AndroidCamera); - QMetaObject::invokeMethod(d, "setupPreviewFrameCallback"); -} - -void AndroidCamera::notifyNewFrames(bool notify) -{ - Q_D(AndroidCamera); - QMetaObject::invokeMethod(d, "notifyNewFrames", Q_ARG(bool, notify)); -} - -void AndroidCamera::fetchLastPreviewFrame() -{ - Q_D(AndroidCamera); - QMetaObject::invokeMethod(d, "fetchLastPreviewFrame"); -} - -QJniObject AndroidCamera::getCameraObject() -{ - Q_D(AndroidCamera); - return d->m_camera; -} - -int AndroidCamera::getNumberOfCameras() -{ - if (!qt_androidRequestCameraPermission()) - return 0; - - return QJniObject::callStaticMethod<jint>("android/hardware/Camera", - "getNumberOfCameras"); -} - -void AndroidCamera::getCameraInfo(int id, QCameraDevicePrivate *info) -{ - Q_ASSERT(info); - - QJniObject cameraInfo("android/hardware/Camera$CameraInfo"); - QJniObject::callStaticMethod<void>("android/hardware/Camera", - "getCameraInfo", - "(ILandroid/hardware/Camera$CameraInfo;)V", - id, cameraInfo.object()); - - AndroidCamera::CameraFacing facing = AndroidCamera::CameraFacing(cameraInfo.getField<jint>("facing")); - // The orientation provided by Android is counter-clockwise, we need it clockwise - info->orientation = (360 - cameraInfo.getField<jint>("orientation")) % 360; - - switch (facing) { - case AndroidCamera::CameraFacingBack: - info->id = QByteArray("back"); - info->description = QStringLiteral("Rear-facing camera"); - info->position = QCameraDevice::BackFace; - info->isDefault = true; - break; - case AndroidCamera::CameraFacingFront: - info->id = QByteArray("front"); - info->description = QStringLiteral("Front-facing camera"); - info->position = QCameraDevice::FrontFace; - break; - default: - break; - } -} - -QVideoFrameFormat::PixelFormat AndroidCamera::QtPixelFormatFromAndroidImageFormat(AndroidCamera::ImageFormat format) -{ - switch (format) { - case AndroidCamera::NV21: - return QVideoFrameFormat::Format_NV21; - case AndroidCamera::YUY2: - return QVideoFrameFormat::Format_YUYV; - case AndroidCamera::JPEG: - return QVideoFrameFormat::Format_Jpeg; - case AndroidCamera::YV12: - return QVideoFrameFormat::Format_YV12; - default: - return QVideoFrameFormat::Format_Invalid; - } -} - -AndroidCamera::ImageFormat AndroidCamera::AndroidImageFormatFromQtPixelFormat(QVideoFrameFormat::PixelFormat format) -{ - switch (format) { - case QVideoFrameFormat::Format_NV21: - return AndroidCamera::NV21; - case QVideoFrameFormat::Format_YUYV: - return AndroidCamera::YUY2; - case QVideoFrameFormat::Format_Jpeg: - return AndroidCamera::JPEG; - case QVideoFrameFormat::Format_YV12: - return AndroidCamera::YV12; - default: - return AndroidCamera::UnknownImageFormat; - } -} - -void AndroidCamera::getSupportedFormats(int id, QList<QCameraFormat> &formats) -{ - QJniObject camera = QJniObject::callStaticObjectMethod("android/hardware/Camera", - "open", - "(I)Landroid/hardware/Camera;", - id); - if (!camera.isValid()) - return; - - QJniObject cameraParams = camera.callObjectMethod("getParameters", - "()Landroid/hardware/Camera$Parameters;"); - if (!cameraParams.isValid()) { - camera.callMethod<void>("release"); - return; - } - AndroidCamera::FpsRange range = AndroidCameraPrivate::getPreviewFpsRange(cameraParams); - - for (const auto &previewSize : AndroidCameraPrivate::getSupportedPreviewSizes(cameraParams)) - { - for (const auto &previewFormat : AndroidCameraPrivate::getSupportedPreviewFormats(cameraParams)) - { - QCameraFormatPrivate * format = new QCameraFormatPrivate(); - format->pixelFormat = QtPixelFormatFromAndroidImageFormat(previewFormat); - format->resolution = previewSize; - format->minFrameRate = range.min; - format->maxFrameRate = range.max; - formats.append(format->create()); - } - } - - camera.callMethod<void>("release"); -} - -void AndroidCamera::startPreview() -{ - Q_D(AndroidCamera); - QMetaObject::invokeMethod(d, "startPreview"); -} - -void AndroidCamera::stopPreview() -{ - Q_D(AndroidCamera); - QMetaObject::invokeMethod(d, "stopPreview"); -} - -void AndroidCamera::stopPreviewSynchronous() -{ - Q_D(AndroidCamera); - QMetaObject::invokeMethod(d, "stopPreview", Qt::BlockingQueuedConnection); -} - -AndroidCameraPrivate::AndroidCameraPrivate() - : QObject() -{ -} - -AndroidCameraPrivate::~AndroidCameraPrivate() -{ -} - -static qint32 s_activeCameras = 0; - -bool AndroidCameraPrivate::init(int cameraId) -{ - m_cameraId = cameraId; - QJniEnvironment env; - - const bool opened = s_activeCameras & (1 << cameraId); - if (opened) - return false; - - m_camera = QJniObject::callStaticObjectMethod("android/hardware/Camera", - "open", - "(I)Landroid/hardware/Camera;", - cameraId); - if (!m_camera.isValid()) - return false; - - m_cameraListener = QJniObject(QtCameraListenerClassName, "(I)V", m_cameraId); - m_info = QJniObject("android/hardware/Camera$CameraInfo"); - m_camera.callStaticMethod<void>("android/hardware/Camera", - "getCameraInfo", - "(ILandroid/hardware/Camera$CameraInfo;)V", - cameraId, - m_info.object()); - - QJniObject params = m_camera.callObjectMethod("getParameters", - "()Landroid/hardware/Camera$Parameters;"); - m_parameters = QJniObject(params); - s_activeCameras |= 1 << cameraId; - - return true; -} - -void AndroidCameraPrivate::release() -{ - m_previewSize = QSize(); - m_parametersMutex.lock(); - m_parameters = QJniObject(); - m_parametersMutex.unlock(); - if (m_camera.isValid()) { - m_camera.callMethod<void>("release"); - s_activeCameras &= ~(1 << m_cameraId); - } -} - -bool AndroidCameraPrivate::lock() -{ - QJniEnvironment env; - auto methodId = env->GetMethodID(m_camera.objectClass(), "lock", "()V"); - env->CallVoidMethod(m_camera.object(), methodId); - - if (env.checkAndClearExceptions()) - return false; - return true; -} - -bool AndroidCameraPrivate::unlock() -{ - QJniEnvironment env; - auto methodId = env->GetMethodID(m_camera.objectClass(), "unlock", "()V"); - env->CallVoidMethod(m_camera.object(), methodId); - - if (env.checkAndClearExceptions()) - return false; - return true; -} - -bool AndroidCameraPrivate::reconnect() -{ - QJniEnvironment env; - auto methodId = env->GetMethodID(m_camera.objectClass(), "reconnect", "()V"); - env->CallVoidMethod(m_camera.object(), methodId); - - if (env.checkAndClearExceptions()) - return false; - return true; -} - -AndroidCamera::CameraFacing AndroidCameraPrivate::getFacing() -{ - return AndroidCamera::CameraFacing(m_info.getField<jint>("facing")); -} - -int AndroidCameraPrivate::getNativeOrientation() -{ - return m_info.getField<jint>("orientation"); -} - -QSize AndroidCameraPrivate::getPreferredPreviewSizeForVideo() -{ - const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex); - - if (!m_parameters.isValid()) - return QSize(); - - QJniObject size = m_parameters.callObjectMethod("getPreferredPreviewSizeForVideo", - "()Landroid/hardware/Camera$Size;"); - - if (!size.isValid()) - return QSize(); - - return QSize(size.getField<jint>("width"), size.getField<jint>("height")); -} - -QList<QSize> AndroidCameraPrivate::getSupportedPreviewSizes() -{ - const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex); - return getSupportedPreviewSizes(m_parameters); -} - -QList<QSize> AndroidCameraPrivate::getSupportedPreviewSizes(QJniObject ¶meters) -{ - QList<QSize> list; - - if (parameters.isValid()) { - QJniObject sizeList = parameters.callObjectMethod("getSupportedPreviewSizes", - "()Ljava/util/List;"); - int count = sizeList.callMethod<jint>("size"); - for (int i = 0; i < count; ++i) { - QJniObject size = sizeList.callObjectMethod("get", - "(I)Ljava/lang/Object;", - i); - list.append(QSize(size.getField<jint>("width"), size.getField<jint>("height"))); - } - - std::sort(list.begin(), list.end(), qt_sizeLessThan); - } - - return list; -} - -QList<AndroidCamera::FpsRange> AndroidCameraPrivate::getSupportedPreviewFpsRange() -{ - const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex); - - QJniEnvironment env; - - QList<AndroidCamera::FpsRange> rangeList; - - if (m_parameters.isValid()) { - QJniObject rangeListNative = m_parameters.callObjectMethod("getSupportedPreviewFpsRange", - "()Ljava/util/List;"); - int count = rangeListNative.callMethod<jint>("size"); - - rangeList.reserve(count); - - for (int i = 0; i < count; ++i) { - QJniObject range = rangeListNative.callObjectMethod("get", - "(I)Ljava/lang/Object;", - i); - - jintArray jRange = static_cast<jintArray>(range.object()); - jint* rangeArray = env->GetIntArrayElements(jRange, 0); - - AndroidCamera::FpsRange fpsRange; - - fpsRange.min = rangeArray[0]; - fpsRange.max = rangeArray[1]; - - env->ReleaseIntArrayElements(jRange, rangeArray, 0); - - rangeList << fpsRange; - } - } - - return rangeList; -} - -AndroidCamera::FpsRange AndroidCameraPrivate::getPreviewFpsRange() -{ - const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex); - return getPreviewFpsRange(m_parameters); -} - -AndroidCamera::FpsRange AndroidCameraPrivate::getPreviewFpsRange(QJniObject ¶meters) -{ - QJniEnvironment env; - - AndroidCamera::FpsRange range; - - if (!parameters.isValid()) - return range; - - jintArray jRangeArray = env->NewIntArray(2); - parameters.callMethod<void>("getPreviewFpsRange", "([I)V", jRangeArray); - - jint* jRangeElements = env->GetIntArrayElements(jRangeArray, 0); - - range.min = jRangeElements[0]; - range.max = jRangeElements[1]; - - env->ReleaseIntArrayElements(jRangeArray, jRangeElements, 0); - env->DeleteLocalRef(jRangeArray); - - return range; -} - -void AndroidCameraPrivate::setPreviewFpsRange(int min, int max) -{ - const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex); - - if (!m_parameters.isValid()) - return; - - QJniEnvironment env; - m_parameters.callMethod<void>("setPreviewFpsRange", "(II)V", min, max); -} - -AndroidCamera::ImageFormat AndroidCameraPrivate::getPreviewFormat() -{ - const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex); - - if (!m_parameters.isValid()) - return AndroidCamera::UnknownImageFormat; - - return AndroidCamera::ImageFormat(m_parameters.callMethod<jint>("getPreviewFormat")); -} - -void AndroidCameraPrivate::setPreviewFormat(AndroidCamera::ImageFormat fmt) -{ - const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex); - - if (!m_parameters.isValid()) - return; - - m_parameters.callMethod<void>("setPreviewFormat", "(I)V", jint(fmt)); - applyParameters(); -} - -QList<AndroidCamera::ImageFormat> AndroidCameraPrivate::getSupportedPreviewFormats() -{ - const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex); - return getSupportedPreviewFormats(m_parameters); -} - -QList<AndroidCamera::ImageFormat> AndroidCameraPrivate::getSupportedPreviewFormats(QJniObject ¶meters) -{ - QList<AndroidCamera::ImageFormat> list; - - if (parameters.isValid()) { - QJniObject formatList = parameters.callObjectMethod("getSupportedPreviewFormats", - "()Ljava/util/List;"); - int count = formatList.callMethod<jint>("size"); - for (int i = 0; i < count; ++i) { - QJniObject format = formatList.callObjectMethod("get", - "(I)Ljava/lang/Object;", - i); - list.append(AndroidCamera::ImageFormat(format.callMethod<jint>("intValue"))); - } - } - - return list; -} - -QSize AndroidCameraPrivate::getPreviewSize() -{ - const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex); - - if (!m_parameters.isValid()) - return QSize(); - - QJniObject size = m_parameters.callObjectMethod("getPreviewSize", - "()Landroid/hardware/Camera$Size;"); - - if (!size.isValid()) - return QSize(); - - return QSize(size.getField<jint>("width"), size.getField<jint>("height")); -} - -void AndroidCameraPrivate::updatePreviewSize() -{ - const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex); - - if (m_previewSize.isValid()) { - m_parameters.callMethod<void>("setPreviewSize", "(II)V", m_previewSize.width(), m_previewSize.height()); - applyParameters(); - } - - emit previewSizeChanged(); -} - -bool AndroidCameraPrivate::setPreviewTexture(void *surfaceTexture) -{ - QJniEnvironment env; - auto methodId = env->GetMethodID(m_camera.objectClass(), "setPreviewTexture", - "(Landroid/graphics/SurfaceTexture;)V"); - env->CallVoidMethod(m_camera.object(), methodId, static_cast<jobject>(surfaceTexture)); - - if (env.checkAndClearExceptions()) - return false; - return true; -} - -bool AndroidCameraPrivate::setPreviewDisplay(void *surfaceHolder) -{ - QJniEnvironment env; - auto methodId = env->GetMethodID(m_camera.objectClass(), "setPreviewDisplay", - "(Landroid/view/SurfaceHolder;)V"); - env->CallVoidMethod(m_camera.object(), methodId, static_cast<jobject>(surfaceHolder)); - - if (env.checkAndClearExceptions()) - return false; - return true; -} - -void AndroidCameraPrivate::setDisplayOrientation(int degrees) -{ - m_camera.callMethod<void>("setDisplayOrientation", "(I)V", degrees); -} - -bool AndroidCameraPrivate::isZoomSupported() -{ - const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex); - - if (!m_parameters.isValid()) - return false; - - return m_parameters.callMethod<jboolean>("isZoomSupported"); -} - -int AndroidCameraPrivate::getMaxZoom() -{ - const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex); - - if (!m_parameters.isValid()) - return 0; - - return m_parameters.callMethod<jint>("getMaxZoom"); -} - -QList<int> AndroidCameraPrivate::getZoomRatios() -{ - const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex); - - QList<int> ratios; - - if (m_parameters.isValid()) { - QJniObject ratioList = m_parameters.callObjectMethod("getZoomRatios", - "()Ljava/util/List;"); - int count = ratioList.callMethod<jint>("size"); - for (int i = 0; i < count; ++i) { - QJniObject zoomRatio = ratioList.callObjectMethod("get", - "(I)Ljava/lang/Object;", - i); - - ratios.append(zoomRatio.callMethod<jint>("intValue")); - } - } - - return ratios; -} - -int AndroidCameraPrivate::getZoom() -{ - const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex); - - if (!m_parameters.isValid()) - return 0; - - return m_parameters.callMethod<jint>("getZoom"); -} - -void AndroidCameraPrivate::setZoom(int value) -{ - const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex); - - if (!m_parameters.isValid()) - return; - - m_parameters.callMethod<void>("setZoom", "(I)V", value); - applyParameters(); -} - -QString AndroidCameraPrivate::getFlashMode() -{ - const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex); - - QString value; - - if (m_parameters.isValid()) { - QJniObject flashMode = m_parameters.callObjectMethod("getFlashMode", - "()Ljava/lang/String;"); - if (flashMode.isValid()) - value = flashMode.toString(); - } - - return value; -} - -void AndroidCameraPrivate::setFlashMode(const QString &value) -{ - const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex); - - if (!m_parameters.isValid()) - return; - - m_parameters.callMethod<void>("setFlashMode", - "(Ljava/lang/String;)V", - QJniObject::fromString(value).object()); - applyParameters(); -} - -QString AndroidCameraPrivate::getFocusMode() -{ - const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex); - - QString value; - - if (m_parameters.isValid()) { - QJniObject focusMode = m_parameters.callObjectMethod("getFocusMode", - "()Ljava/lang/String;"); - if (focusMode.isValid()) - value = focusMode.toString(); - } - - return value; -} - -void AndroidCameraPrivate::setFocusMode(const QString &value) -{ - const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex); - - if (!m_parameters.isValid()) - return; - - m_parameters.callMethod<void>("setFocusMode", - "(Ljava/lang/String;)V", - QJniObject::fromString(value).object()); - applyParameters(); -} - -int AndroidCameraPrivate::getMaxNumFocusAreas() -{ - const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex); - - if (!m_parameters.isValid()) - return 0; - - return m_parameters.callMethod<jint>("getMaxNumFocusAreas"); -} - -QList<QRect> AndroidCameraPrivate::getFocusAreas() -{ - QList<QRect> areas; - const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex); - - if (m_parameters.isValid()) { - QJniObject list = m_parameters.callObjectMethod("getFocusAreas", - "()Ljava/util/List;"); - - if (list.isValid()) { - int count = list.callMethod<jint>("size"); - for (int i = 0; i < count; ++i) { - QJniObject area = list.callObjectMethod("get", - "(I)Ljava/lang/Object;", - i); - - areas.append(areaToRect(area.object())); - } - } - } - - return areas; -} - -void AndroidCameraPrivate::setFocusAreas(const QList<QRect> &areas) -{ - const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex); - - if (!m_parameters.isValid() || areas.isEmpty()) - return; - - QJniObject list; - - if (!areas.isEmpty()) { - QJniEnvironment env; - QJniObject arrayList("java/util/ArrayList", "(I)V", areas.size()); - for (int i = 0; i < areas.size(); ++i) { - arrayList.callMethod<jboolean>("add", - "(Ljava/lang/Object;)Z", - rectToArea(areas.at(i)).object()); - } - list = arrayList; - } - - m_parameters.callMethod<void>("setFocusAreas", "(Ljava/util/List;)V", list.object()); - - applyParameters(); -} - -void AndroidCameraPrivate::autoFocus() -{ - QJniEnvironment env; - auto methodId = env->GetMethodID(m_camera.objectClass(), "autoFocus", - "(Landroid/hardware/Camera$AutoFocusCallback;)V"); - env->CallVoidMethod(m_camera.object(), methodId, m_cameraListener.object()); - - if (!env.checkAndClearExceptions()) - emit autoFocusStarted(); -} - -void AndroidCameraPrivate::cancelAutoFocus() -{ - QJniEnvironment env; - m_camera.callMethod<void>("cancelAutoFocus"); -} - -bool AndroidCameraPrivate::isAutoExposureLockSupported() -{ - const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex); - - if (!m_parameters.isValid()) - return false; - - return m_parameters.callMethod<jboolean>("isAutoExposureLockSupported"); -} - -bool AndroidCameraPrivate::getAutoExposureLock() -{ - const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex); - - if (!m_parameters.isValid()) - return false; - - return m_parameters.callMethod<jboolean>("getAutoExposureLock"); -} - -void AndroidCameraPrivate::setAutoExposureLock(bool toggle) -{ - const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex); - - if (!m_parameters.isValid()) - return; - - m_parameters.callMethod<void>("setAutoExposureLock", "(Z)V", toggle); - applyParameters(); -} - -bool AndroidCameraPrivate::isAutoWhiteBalanceLockSupported() -{ - const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex); - - if (!m_parameters.isValid()) - return false; - - return m_parameters.callMethod<jboolean>("isAutoWhiteBalanceLockSupported"); -} - -bool AndroidCameraPrivate::getAutoWhiteBalanceLock() -{ - const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex); - - if (!m_parameters.isValid()) - return false; - - return m_parameters.callMethod<jboolean>("getAutoWhiteBalanceLock"); -} - -void AndroidCameraPrivate::setAutoWhiteBalanceLock(bool toggle) -{ - const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex); - - if (!m_parameters.isValid()) - return; - - m_parameters.callMethod<void>("setAutoWhiteBalanceLock", "(Z)V", toggle); - applyParameters(); -} - -int AndroidCameraPrivate::getExposureCompensation() -{ - const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex); - - if (!m_parameters.isValid()) - return 0; - - return m_parameters.callMethod<jint>("getExposureCompensation"); -} - -void AndroidCameraPrivate::setExposureCompensation(int value) -{ - const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex); - - if (!m_parameters.isValid()) - return; - - m_parameters.callMethod<void>("setExposureCompensation", "(I)V", value); - applyParameters(); -} - -float AndroidCameraPrivate::getExposureCompensationStep() -{ - const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex); - - if (!m_parameters.isValid()) - return 0; - - return m_parameters.callMethod<jfloat>("getExposureCompensationStep"); -} - -int AndroidCameraPrivate::getMinExposureCompensation() -{ - const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex); - - if (!m_parameters.isValid()) - return 0; - - return m_parameters.callMethod<jint>("getMinExposureCompensation"); -} - -int AndroidCameraPrivate::getMaxExposureCompensation() -{ - const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex); - - if (!m_parameters.isValid()) - return 0; - - return m_parameters.callMethod<jint>("getMaxExposureCompensation"); -} - -QString AndroidCameraPrivate::getSceneMode() -{ - const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex); - - QString value; - - if (m_parameters.isValid()) { - QJniObject sceneMode = m_parameters.callObjectMethod("getSceneMode", - "()Ljava/lang/String;"); - if (sceneMode.isValid()) - value = sceneMode.toString(); - } - - return value; -} - -void AndroidCameraPrivate::setSceneMode(const QString &value) -{ - const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex); - - if (!m_parameters.isValid()) - return; - - m_parameters.callMethod<void>("setSceneMode", - "(Ljava/lang/String;)V", - QJniObject::fromString(value).object()); - applyParameters(); -} - -QString AndroidCameraPrivate::getWhiteBalance() -{ - const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex); - - QString value; - - if (m_parameters.isValid()) { - QJniObject wb = m_parameters.callObjectMethod("getWhiteBalance", - "()Ljava/lang/String;"); - if (wb.isValid()) - value = wb.toString(); - } - - return value; -} - -void AndroidCameraPrivate::setWhiteBalance(const QString &value) -{ - const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex); - - if (!m_parameters.isValid()) - return; - - m_parameters.callMethod<void>("setWhiteBalance", - "(Ljava/lang/String;)V", - QJniObject::fromString(value).object()); - applyParameters(); - - emit whiteBalanceChanged(); -} - -void AndroidCameraPrivate::updateRotation() -{ - const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex); - - m_parameters.callMethod<void>("setRotation", "(I)V", m_rotation); - applyParameters(); -} - -QList<QSize> AndroidCameraPrivate::getSupportedPictureSizes() -{ - const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex); - - QList<QSize> list; - - if (m_parameters.isValid()) { - QJniObject sizeList = m_parameters.callObjectMethod("getSupportedPictureSizes", - "()Ljava/util/List;"); - int count = sizeList.callMethod<jint>("size"); - for (int i = 0; i < count; ++i) { - QJniObject size = sizeList.callObjectMethod("get", - "(I)Ljava/lang/Object;", - i); - list.append(QSize(size.getField<jint>("width"), size.getField<jint>("height"))); - } - - std::sort(list.begin(), list.end(), qt_sizeLessThan); - } - - return list; -} - -void AndroidCameraPrivate::setPictureSize(const QSize &size) -{ - const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex); - - if (!m_parameters.isValid()) - return; - - m_parameters.callMethod<void>("setPictureSize", "(II)V", size.width(), size.height()); - applyParameters(); -} - -void AndroidCameraPrivate::setJpegQuality(int quality) -{ - const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex); - - if (!m_parameters.isValid()) - return; - - m_parameters.callMethod<void>("setJpegQuality", "(I)V", quality); - applyParameters(); -} - -void AndroidCameraPrivate::startPreview() -{ - setupPreviewFrameCallback(); - - QJniEnvironment env; - auto methodId = env->GetMethodID(m_camera.objectClass(), "startPreview", "()V"); - env->CallVoidMethod(m_camera.object(), methodId); - - if (env.checkAndClearExceptions()) - emit previewFailedToStart(); - else - emit previewStarted(); -} - -void AndroidCameraPrivate::stopPreview() -{ - // cancel any pending new frame notification - m_cameraListener.callMethod<void>("notifyWhenFrameAvailable", "(Z)V", false); - m_camera.callMethod<void>("stopPreview"); - emit previewStopped(); -} - -void AndroidCameraPrivate::takePicture() -{ - // 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()); - - QJniEnvironment env; - auto methodId = env->GetMethodID(m_camera.objectClass(), "takePicture", - "(Landroid/hardware/Camera$ShutterCallback;" - "Landroid/hardware/Camera$PictureCallback;" - "Landroid/hardware/Camera$PictureCallback;)V"); - env->CallVoidMethod(m_camera.object(), methodId, m_cameraListener.object(), - jobject(0), m_cameraListener.object()); - - if (env.checkAndClearExceptions()) - emit takePictureFailed(); -} - -void AndroidCameraPrivate::setupPreviewFrameCallback() -{ - m_cameraListener.callMethod<void>("setupPreviewCallback", "(Landroid/hardware/Camera;)V", m_camera.object()); -} - -void AndroidCameraPrivate::notifyNewFrames(bool notify) -{ - m_cameraListener.callMethod<void>("notifyNewFrames", "(Z)V", notify); -} - -void AndroidCameraPrivate::fetchLastPreviewFrame() -{ - QJniEnvironment env; - QJniObject data = m_cameraListener.callObjectMethod("lastPreviewBuffer", "()[B"); - - 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) - return; - - QByteArray bytes(arrayLength, Qt::Uninitialized); - env->GetByteArrayRegion(static_cast<jbyteArray>(data.object()), - 0, - arrayLength, - reinterpret_cast<jbyte *>(bytes.data())); - - const int width = m_cameraListener.callMethod<jint>("previewWidth"); - const int height = m_cameraListener.callMethod<jint>("previewHeight"); - const int format = m_cameraListener.callMethod<jint>("previewFormat"); - const int bpl = m_cameraListener.callMethod<jint>("previewBytesPerLine"); - - QVideoFrame frame(new QMemoryVideoBuffer(bytes, bpl), - QVideoFrameFormat(QSize(width, height), - qt_pixelFormatFromAndroidImageFormat(AndroidCamera::ImageFormat(format)))); - - emit lastPreviewFrameFetched(frame); -} - -void AndroidCameraPrivate::applyParameters() -{ - QJniEnvironment env; - m_camera.callMethod<void>("setParameters", - "(Landroid/hardware/Camera$Parameters;)V", - m_parameters.object()); -} - -QStringList AndroidCameraPrivate::callParametersStringListMethod(const QByteArray &methodName) -{ - const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex); - - QStringList stringList; - - if (m_parameters.isValid()) { - QJniObject list = m_parameters.callObjectMethod(methodName.constData(), - "()Ljava/util/List;"); - - if (list.isValid()) { - int count = list.callMethod<jint>("size"); - for (int i = 0; i < count; ++i) { - QJniObject string = list.callObjectMethod("get", - "(I)Ljava/lang/Object;", - i); - stringList.append(string.toString()); - } - } - } - - return stringList; -} - -bool AndroidCamera::registerNativeMethods() -{ - static const JNINativeMethod methods[] = { - {"notifyAutoFocusComplete", "(IZ)V", (void *)notifyAutoFocusComplete}, - {"notifyPictureExposed", "(I)V", (void *)notifyPictureExposed}, - {"notifyPictureCaptured", "(I[B)V", (void *)notifyPictureCaptured}, - {"notifyNewPreviewFrame", "(I[BIIII)V", (void *)notifyNewPreviewFrame}, - {"notifyFrameAvailable", "(I)V", (void *)notifyFrameAvailable} - }; - - const int size = std::size(methods); - return QJniEnvironment().registerNativeMethods(QtCameraListenerClassName, methods, size); -} - -QT_END_NAMESPACE - -#include "androidcamera.moc" |