11#include <private/qvideoframe_p.h>
14#include <qstringlist.h>
16#include <QtCore/qthread.h>
17#include <QtCore/qreadwritelock.h>
18#include <QtCore/qmutex.h>
19#include <QtMultimedia/private/qmemoryvideobuffer_p.h>
20#include <QtMultimedia/private/qmultimedia_ranges_p.h>
21#include <QtCore/qcoreapplication.h>
26namespace ranges = QtMultimediaPrivate::ranges;
33Q_GLOBAL_STATIC(CameraMap, cameras)
34Q_GLOBAL_STATIC(QReadWriteLock, rwLock)
36static QRect areaToRect(jobject areaObj)
38 QJniObject area(areaObj);
39 QJniObject rect = area.getObjectField(
"rect",
"Landroid/graphics/Rect;");
41 return QRect(rect.getField<jint>(
"left"),
42 rect.getField<jint>(
"top"),
43 rect.callMethod<jint>(
"width"),
44 rect.callMethod<jint>(
"height"));
47static QJniObject rectToArea(
const QRect &rect)
49 QJniObject jrect(
"android/graphics/Rect",
51 rect.left(), rect.top(), rect.right(), rect.bottom());
53 QJniObject area(
"android/hardware/Camera$Area",
54 "(Landroid/graphics/Rect;I)V",
61static void notifyAutoFocusComplete(JNIEnv* , jobject,
int id, jboolean success)
63 QReadLocker locker(rwLock);
64 const auto it = cameras->constFind(id);
65 if (Q_UNLIKELY(it == cameras->cend()))
68 Q_EMIT (*it)->autoFocusComplete(success);
71static void notifyPictureExposed(JNIEnv* , jobject,
int id)
73 QReadLocker locker(rwLock);
74 const auto it = cameras->constFind(id);
75 if (Q_UNLIKELY(it == cameras->cend()))
78 Q_EMIT (*it)->pictureExposed();
81static void notifyPictureCaptured(JNIEnv *env, jobject,
int id, jbyteArray data)
83 QReadLocker locker(rwLock);
84 const auto it = cameras->constFind(id);
85 if (Q_UNLIKELY(it == cameras->cend())) {
86 qCWarning(lcAndroidCamera) <<
"Could not obtain camera!";
90 AndroidCamera *camera = (*it);
92 const int arrayLength = env->GetArrayLength(data);
93 QByteArray bytes(arrayLength, Qt::Uninitialized);
94 env->GetByteArrayRegion(data, 0, arrayLength,
reinterpret_cast<jbyte *>(bytes.data()));
96 auto parameters = camera->getParametersObject();
99 parameters.callObjectMethod(
"getPictureSize",
"()Landroid/hardware/Camera$Size;");
101 if (!size.isValid()) {
102 qCWarning(lcAndroidCamera) <<
"Picture Size is not valid!";
106 QSize pictureSize(size.getField<jint>(
"width"), size.getField<jint>(
"height"));
108 auto format = AndroidCamera::ImageFormat(parameters.callMethod<jint>(
"getPictureFormat"));
110 if (format == AndroidCamera::ImageFormat::UnknownImageFormat) {
111 qCWarning(lcAndroidCamera) <<
"Android Camera Image Format is UnknownImageFormat!";
115 int bytesPerLine = 0;
118 case AndroidCamera::ImageFormat::YV12:
119 bytesPerLine = (pictureSize.width() + 15) & ~15;
121 case AndroidCamera::ImageFormat::NV21:
122 bytesPerLine = pictureSize.width();
124 case AndroidCamera::ImageFormat::RGB565:
125 case AndroidCamera::ImageFormat::YUY2:
126 bytesPerLine = pictureSize.width() * 2;
132 auto pictureFormat = qt_pixelFormatFromAndroidImageFormat(format);
134 emit camera->pictureCaptured(bytes, pictureFormat, pictureSize, bytesPerLine);
137static void notifyNewPreviewFrame(JNIEnv *env, jobject,
int id, jbyteArray data,
138 int width,
int height,
int format,
int bpl)
140 QReadLocker locker(rwLock);
141 const auto it = cameras->constFind(id);
142 if (Q_UNLIKELY(it == cameras->cend()))
145 const int arrayLength = env->GetArrayLength(data);
146 if (arrayLength == 0)
149 QByteArray bytes(arrayLength, Qt::Uninitialized);
150 env->GetByteArrayRegion(data, 0, arrayLength, (jbyte*)bytes.data());
152 QVideoFrameFormat frameFormat(
153 QSize(width, height),
154 qt_pixelFormatFromAndroidImageFormat(AndroidCamera::ImageFormat(format)));
156 QVideoFrame frame = QVideoFramePrivate::createFrame(
157 std::make_unique<QMemoryVideoBuffer>(std::move(bytes), bpl), std::move(frameFormat));
159 Q_EMIT (*it)->newPreviewFrame(frame);
162static void notifyFrameAvailable(JNIEnv *, jobject,
int id)
164 QReadLocker locker(rwLock);
165 const auto it = cameras->constFind(id);
166 if (Q_UNLIKELY(it == cameras->cend()))
169 (*it)->fetchLastPreviewFrame();
172class AndroidCameraPrivate :
public QObject
176 AndroidCameraPrivate();
177 ~AndroidCameraPrivate();
179 Q_INVOKABLE
bool init(
int cameraId);
181 Q_INVOKABLE
void release();
182 Q_INVOKABLE
bool lock();
183 Q_INVOKABLE
bool unlock();
184 Q_INVOKABLE
bool reconnect();
186 Q_INVOKABLE AndroidCamera::CameraFacing getFacing();
187 Q_INVOKABLE
int getNativeOrientation();
189 Q_INVOKABLE QSize getPreferredPreviewSizeForVideo();
190 Q_INVOKABLE QList<QSize> getSupportedPreviewSizes();
191 static QList<QSize> getSupportedPreviewSizes(QJniObject ¶meters);
193 Q_INVOKABLE QList<AndroidCamera::FpsRange> getSupportedPreviewFpsRange();
195 Q_INVOKABLE AndroidCamera::FpsRange getPreviewFpsRange();
196 static AndroidCamera::FpsRange getPreviewFpsRange(QJniObject ¶meters);
197 Q_INVOKABLE
void setPreviewFpsRange(
int min,
int max);
199 Q_INVOKABLE AndroidCamera::ImageFormat getPreviewFormat();
200 Q_INVOKABLE
void setPreviewFormat(AndroidCamera::ImageFormat fmt);
201 Q_INVOKABLE QList<AndroidCamera::ImageFormat> getSupportedPreviewFormats();
202 static QList<AndroidCamera::ImageFormat> getSupportedPreviewFormats(QJniObject ¶meters);
204 Q_INVOKABLE QSize previewSize()
const {
return m_previewSize; }
205 Q_INVOKABLE QSize getPreviewSize();
206 Q_INVOKABLE
void updatePreviewSize();
207 Q_INVOKABLE
bool setPreviewTexture(
void *surfaceTexture);
208 Q_INVOKABLE
bool setPreviewDisplay(
void *surfaceHolder);
209 Q_INVOKABLE
void setDisplayOrientation(
int degrees);
211 Q_INVOKABLE
bool isZoomSupported();
212 Q_INVOKABLE
int getMaxZoom();
213 Q_INVOKABLE QList<
int> getZoomRatios();
214 Q_INVOKABLE
int getZoom();
215 Q_INVOKABLE
void setZoom(
int value);
217 Q_INVOKABLE QString getFlashMode();
218 Q_INVOKABLE
void setFlashMode(
const QString &value);
220 Q_INVOKABLE QString getFocusMode();
221 Q_INVOKABLE
void setFocusMode(
const QString &value);
223 Q_INVOKABLE
int getMaxNumFocusAreas();
224 Q_INVOKABLE QList<QRect> getFocusAreas();
225 Q_INVOKABLE
void setFocusAreas(
const QList<QRect> &areas);
227 Q_INVOKABLE
void autoFocus();
228 Q_INVOKABLE
void cancelAutoFocus();
230 Q_INVOKABLE
bool isAutoExposureLockSupported();
231 Q_INVOKABLE
bool getAutoExposureLock();
232 Q_INVOKABLE
void setAutoExposureLock(
bool toggle);
234 Q_INVOKABLE
bool isAutoWhiteBalanceLockSupported();
235 Q_INVOKABLE
bool getAutoWhiteBalanceLock();
236 Q_INVOKABLE
void setAutoWhiteBalanceLock(
bool toggle);
238 Q_INVOKABLE
int getExposureCompensation();
239 Q_INVOKABLE
void setExposureCompensation(
int value);
240 Q_INVOKABLE
float getExposureCompensationStep();
241 Q_INVOKABLE
int getMinExposureCompensation();
242 Q_INVOKABLE
int getMaxExposureCompensation();
244 Q_INVOKABLE QString getSceneMode();
245 Q_INVOKABLE
void setSceneMode(
const QString &value);
247 Q_INVOKABLE QString getWhiteBalance();
248 Q_INVOKABLE
void setWhiteBalance(
const QString &value);
250 Q_INVOKABLE
void updateRotation();
252 Q_INVOKABLE QList<QSize> getSupportedPictureSizes();
253 Q_INVOKABLE QList<QSize> getSupportedVideoSizes();
254 Q_INVOKABLE
void setPictureSize(
const QSize &size);
255 Q_INVOKABLE
void setJpegQuality(
int quality);
257 Q_INVOKABLE
void startPreview();
258 Q_INVOKABLE
void stopPreview();
260 Q_INVOKABLE
void takePicture();
262 Q_INVOKABLE
void setupPreviewFrameCallback();
263 Q_INVOKABLE
void notifyNewFrames(
bool notify);
264 Q_INVOKABLE
void fetchLastPreviewFrame();
266 Q_INVOKABLE
void applyParameters();
268 Q_INVOKABLE QStringList callParametersStringListMethod(
const QByteArray &methodName);
271 QRecursiveMutex m_parametersMutex;
275 QJniObject m_parameters;
277 QJniObject m_cameraListener;
280 void previewSizeChanged();
281 void previewStarted();
282 void previewFailedToStart();
283 void previewStopped();
285 void autoFocusStarted();
287 void whiteBalanceChanged();
289 void takePictureFailed();
291 void lastPreviewFrameFetched(
const QVideoFrame &frame);
294AndroidCamera::AndroidCamera(AndroidCameraPrivate *d, QThread *worker)
300 connect(d, &AndroidCameraPrivate::previewSizeChanged,
this, &AndroidCamera::previewSizeChanged);
307 connect(d, &AndroidCameraPrivate::lastPreviewFrameFetched,
this, &AndroidCamera::lastPreviewFrameFetched);
313 if (d->m_camera.isValid()) {
315 QWriteLocker locker(rwLock);
316 cameras->remove(cameraId());
320 m_worker->wait(5000);
328 AndroidCameraPrivate *d =
new AndroidCameraPrivate();
329 QThread *worker =
new QThread;
331 d->moveToThread(worker);
332 connect(worker, &QThread::finished, d, &AndroidCameraPrivate::deleteLater);
334 QMetaObject::invokeMethod(d,
"init", Qt::BlockingQueuedConnection, Q_RETURN_ARG(
bool, ok), Q_ARG(
int, cameraId));
343 QWriteLocker locker(rwLock);
344 cameras->insert(cameraId, q);
351 Q_D(
const AndroidCamera);
352 return d->m_cameraId;
359 QMetaObject::invokeMethod(d,
"lock", Qt::BlockingQueuedConnection, Q_RETURN_ARG(
bool, ok));
367 QMetaObject::invokeMethod(d,
"unlock", Qt::BlockingQueuedConnection, Q_RETURN_ARG(
bool, ok));
375 QMetaObject::invokeMethod(d,
"reconnect", Qt::BlockingQueuedConnection, Q_RETURN_ARG(
bool, ok));
382 QMetaObject::invokeMethod(d,
"release", Qt::BlockingQueuedConnection);
388 return d->getFacing();
394 return d->getNativeOrientation();
400 return d->getPreferredPreviewSizeForVideo();
406 return d->getSupportedPreviewSizes();
412 return d->getSupportedPreviewFpsRange();
418 return d->getPreviewFpsRange();
424 QMetaObject::invokeMethod(d,
"setPreviewFpsRange", Q_ARG(
int, range.min), Q_ARG(
int, range.max));
430 return d->getPreviewFormat();
436 QMetaObject::invokeMethod(d,
"setPreviewFormat", Q_ARG(AndroidCamera::ImageFormat, fmt));
442 return d->getSupportedPreviewFormats();
447 Q_D(
const AndroidCamera);
448 return d->m_previewSize;
454 return d->getPreviewSize();
460 d->m_parametersMutex.lock();
461 bool areParametersValid = d->m_parameters.isValid();
462 d->m_parametersMutex.unlock();
463 if (!areParametersValid)
466 d->m_previewSize = size;
467 QMetaObject::invokeMethod(d,
"updatePreviewSize");
474 QMetaObject::invokeMethod(d,
476 Qt::BlockingQueuedConnection,
477 Q_RETURN_ARG(
bool, ok),
478 Q_ARG(
void *, surfaceTexture ? surfaceTexture->surfaceTexture() : 0));
486 QMetaObject::invokeMethod(d,
488 Qt::BlockingQueuedConnection,
489 Q_RETURN_ARG(
bool, ok),
490 Q_ARG(
void *, surfaceHolder ? surfaceHolder->surfaceHolder() : 0));
497 QMetaObject::invokeMethod(d,
"setDisplayOrientation", Qt::QueuedConnection, Q_ARG(
int, degrees));
503 return d->isZoomSupported();
509 return d->getMaxZoom();
515 return d->getZoomRatios();
527 QMetaObject::invokeMethod(d,
"setZoom", Q_ARG(
int, value));
533 return d->callParametersStringListMethod(
"getSupportedFlashModes");
539 return d->getFlashMode();
545 QMetaObject::invokeMethod(d,
"setFlashMode", Q_ARG(QString, value));
551 return d->callParametersStringListMethod(
"getSupportedFocusModes");
557 return d->getFocusMode();
563 QMetaObject::invokeMethod(d,
"setFocusMode", Q_ARG(QString, value));
569 return d->getMaxNumFocusAreas();
575 return d->getFocusAreas();
581 QMetaObject::invokeMethod(d,
"setFocusAreas", Q_ARG(QList<QRect>, areas));
587 QMetaObject::invokeMethod(d,
"autoFocus");
593 QMetaObject::invokeMethod(d,
"cancelAutoFocus", Qt::QueuedConnection);
599 return d->isAutoExposureLockSupported();
605 return d->getAutoExposureLock();
611 QMetaObject::invokeMethod(d,
"setAutoExposureLock", Q_ARG(
bool, toggle));
617 return d->isAutoWhiteBalanceLockSupported();
623 return d->getAutoWhiteBalanceLock();
629 QMetaObject::invokeMethod(d,
"setAutoWhiteBalanceLock", Q_ARG(
bool, toggle));
635 return d->getExposureCompensation();
641 QMetaObject::invokeMethod(d,
"setExposureCompensation", Q_ARG(
int, value));
647 return d->getExposureCompensationStep();
653 return d->getMinExposureCompensation();
659 return d->getMaxExposureCompensation();
665 return d->callParametersStringListMethod(
"getSupportedSceneModes");
671 return d->getSceneMode();
677 QMetaObject::invokeMethod(d,
"setSceneMode", Q_ARG(QString, value));
683 return d->callParametersStringListMethod(
"getSupportedWhiteBalance");
689 return d->getWhiteBalance();
695 QMetaObject::invokeMethod(d,
"setWhiteBalance", Q_ARG(QString, value));
702 d->m_parametersMutex.lock();
703 bool areParametersValid = d->m_parameters.isValid();
704 d->m_parametersMutex.unlock();
705 if (!areParametersValid)
708 d->m_rotation = rotation;
709 QMetaObject::invokeMethod(d,
"updateRotation");
714 Q_D(
const AndroidCamera);
715 return d->m_rotation;
721 return d->getSupportedPictureSizes();
727 return d->getSupportedVideoSizes();
733 QMetaObject::invokeMethod(d,
"setPictureSize", Q_ARG(QSize, size));
739 QMetaObject::invokeMethod(d,
"setJpegQuality", Q_ARG(
int, quality));
745 QMetaObject::invokeMethod(d,
"takePicture", Qt::BlockingQueuedConnection);
751 QMetaObject::invokeMethod(d,
"setupPreviewFrameCallback");
757 QMetaObject::invokeMethod(d,
"notifyNewFrames", Q_ARG(
bool, notify));
763 QMetaObject::invokeMethod(d,
"fetchLastPreviewFrame");
777 return QJniObject::callStaticMethod<jint>(
"android/hardware/Camera",
778 "getNumberOfCameras");
785 QJniObject cameraInfo(
"android/hardware/Camera$CameraInfo");
786 QJniObject::callStaticMethod<
void>(
"android/hardware/Camera",
788 "(ILandroid/hardware/Camera$CameraInfo;)V",
789 id, cameraInfo.object());
791 AndroidCamera::CameraFacing facing = AndroidCamera::CameraFacing(cameraInfo.getField<jint>(
"facing"));
793 info->orientation = (360 - cameraInfo.getField<jint>(
"orientation")) % 360;
796 case AndroidCamera::CameraFacingBack:
797 info->id = QByteArray(
"back");
798 info->description = QStringLiteral(
"Rear-facing camera");
799 info->position = QCameraDevice::BackFace;
800 info->isDefault =
true;
802 case AndroidCamera::CameraFacingFront:
803 info->id = QByteArray(
"front");
804 info->description = QStringLiteral(
"Front-facing camera");
805 info->position = QCameraDevice::FrontFace;
813 info->id.append(QByteArray::number(id));
814 info->description.append(QStringLiteral(
" %1").arg(id));
818QVideoFrameFormat::PixelFormat
AndroidCamera::QtPixelFormatFromAndroidImageFormat(AndroidCamera::ImageFormat format)
821 case AndroidCamera::NV21:
822 return QVideoFrameFormat::Format_NV21;
823 case AndroidCamera::YUY2:
824 return QVideoFrameFormat::Format_YUYV;
825 case AndroidCamera::JPEG:
826 return QVideoFrameFormat::Format_Jpeg;
827 case AndroidCamera::YV12:
828 return QVideoFrameFormat::Format_YV12;
830 return QVideoFrameFormat::Format_Invalid;
834AndroidCamera::ImageFormat
AndroidCamera::AndroidImageFormatFromQtPixelFormat(QVideoFrameFormat::PixelFormat format)
837 case QVideoFrameFormat::Format_NV21:
838 return AndroidCamera::NV21;
839 case QVideoFrameFormat::Format_YUYV:
840 return AndroidCamera::YUY2;
841 case QVideoFrameFormat::Format_Jpeg:
842 return AndroidCamera::JPEG;
843 case QVideoFrameFormat::Format_YV12:
844 return AndroidCamera::YV12;
846 return AndroidCamera::UnknownImageFormat;
852 QList<QCameraFormat> formats;
853 AndroidCamera::FpsRange range = getPreviewFpsRange();
854 for (
const auto &previewSize : getSupportedVideoSizes()) {
855 for (
const auto &previewFormat : getSupportedPreviewFormats()) {
856 QCameraFormatPrivate * format =
new QCameraFormatPrivate();
857 format->pixelFormat = QtPixelFormatFromAndroidImageFormat(previewFormat);
858 format->resolution = previewSize;
859 format->minFrameRate = range.min;
860 format->maxFrameRate = range.max;
861 formats.append(format->create());
871 QMetaObject::invokeMethod(d,
"startPreview");
877 QMetaObject::invokeMethod(d,
"stopPreview");
883 QMetaObject::invokeMethod(d,
"stopPreview", Qt::BlockingQueuedConnection);
889 return d->m_parameters;
892AndroidCameraPrivate::AndroidCameraPrivate()
897AndroidCameraPrivate::~AndroidCameraPrivate()
903bool AndroidCameraPrivate::init(
int cameraId)
905 m_cameraId = cameraId;
908 const bool opened = s_activeCameras & (1 << cameraId);
912 m_camera = QJniObject::callStaticObjectMethod(
"android/hardware/Camera",
914 "(I)Landroid/hardware/Camera;",
916 if (!m_camera.isValid())
919 m_cameraListener = QJniObject(QtCameraListenerClassName,
"(I)V", m_cameraId);
920 m_info = QJniObject(
"android/hardware/Camera$CameraInfo");
921 m_camera.callStaticMethod<
void>(
"android/hardware/Camera",
923 "(ILandroid/hardware/Camera$CameraInfo;)V",
927 QJniObject params = m_camera.callObjectMethod(
"getParameters",
928 "()Landroid/hardware/Camera$Parameters;");
929 m_parameters = QJniObject(params);
930 s_activeCameras |= 1 << cameraId;
935void AndroidCameraPrivate::release()
937 m_previewSize = QSize();
938 m_parametersMutex.lock();
939 m_parameters = QJniObject();
940 m_parametersMutex.unlock();
941 if (m_camera.isValid()) {
942 m_camera.callMethod<
void>(
"release");
943 s_activeCameras &= ~(1 << m_cameraId);
947bool AndroidCameraPrivate::lock()
950 auto methodId = env->GetMethodID(m_camera.objectClass(),
"lock",
"()V");
951 env->CallVoidMethod(m_camera.object(), methodId);
953 if (env.checkAndClearExceptions())
958bool AndroidCameraPrivate::unlock()
961 auto methodId = env->GetMethodID(m_camera.objectClass(),
"unlock",
"()V");
962 env->CallVoidMethod(m_camera.object(), methodId);
964 if (env.checkAndClearExceptions())
969bool AndroidCameraPrivate::reconnect()
972 auto methodId = env->GetMethodID(m_camera.objectClass(),
"reconnect",
"()V");
973 env->CallVoidMethod(m_camera.object(), methodId);
975 if (env.checkAndClearExceptions())
980AndroidCamera::CameraFacing AndroidCameraPrivate::getFacing()
982 return AndroidCamera::CameraFacing(m_info.getField<jint>(
"facing"));
985int AndroidCameraPrivate::getNativeOrientation()
987 return m_info.getField<jint>(
"orientation");
990QSize AndroidCameraPrivate::getPreferredPreviewSizeForVideo()
992 const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
994 if (!m_parameters.isValid())
997 QJniObject size = m_parameters.callObjectMethod(
"getPreferredPreviewSizeForVideo",
998 "()Landroid/hardware/Camera$Size;");
1000 if (!size.isValid())
1003 return QSize(size.getField<jint>(
"width"), size.getField<jint>(
"height"));
1006QList<QSize> AndroidCameraPrivate::getSupportedPreviewSizes()
1008 const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
1009 return getSupportedPreviewSizes(m_parameters);
1012QList<QSize> AndroidCameraPrivate::getSupportedPreviewSizes(QJniObject ¶meters)
1016 if (parameters.isValid()) {
1017 QJniObject sizeList = parameters.callObjectMethod(
"getSupportedPreviewSizes",
1018 "()Ljava/util/List;");
1019 int count = sizeList.callMethod<jint>(
"size");
1020 for (
int i = 0; i < count; ++i) {
1021 QJniObject size = sizeList.callObjectMethod(
"get",
1022 "(I)Ljava/lang/Object;",
1024 list.append(QSize(size.getField<jint>(
"width"), size.getField<jint>(
"height")));
1027 ranges::sort(list, qt_sizeLessThan);
1033QList<AndroidCamera::FpsRange> AndroidCameraPrivate::getSupportedPreviewFpsRange()
1035 const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
1037 QJniEnvironment env;
1039 QList<AndroidCamera::FpsRange> rangeList;
1041 if (m_parameters.isValid()) {
1042 QJniObject rangeListNative = m_parameters.callObjectMethod(
"getSupportedPreviewFpsRange",
1043 "()Ljava/util/List;");
1044 int count = rangeListNative.callMethod<jint>(
"size");
1046 rangeList.reserve(count);
1048 for (
int i = 0; i < count; ++i) {
1049 QJniObject range = rangeListNative.callObjectMethod(
"get",
1050 "(I)Ljava/lang/Object;",
1053 jintArray jRange =
static_cast<jintArray>(range.object());
1054 jint* rangeArray = env->GetIntArrayElements(jRange, 0);
1056 AndroidCamera::FpsRange fpsRange;
1058 fpsRange.min = rangeArray[0];
1059 fpsRange.max = rangeArray[1];
1061 env->ReleaseIntArrayElements(jRange, rangeArray, 0);
1063 rangeList << fpsRange;
1070AndroidCamera::FpsRange AndroidCameraPrivate::getPreviewFpsRange()
1072 const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
1073 return getPreviewFpsRange(m_parameters);
1076AndroidCamera::FpsRange AndroidCameraPrivate::getPreviewFpsRange(QJniObject ¶meters)
1078 QJniEnvironment env;
1080 AndroidCamera::FpsRange range;
1082 if (!parameters.isValid())
1085 jintArray jRangeArray = env->NewIntArray(2);
1086 parameters.callMethod<
void>(
"getPreviewFpsRange",
"([I)V", jRangeArray);
1088 jint* jRangeElements = env->GetIntArrayElements(jRangeArray, 0);
1092 range.min = jRangeElements[0] / 1000;
1093 range.max = jRangeElements[1] / 1000;
1095 env->ReleaseIntArrayElements(jRangeArray, jRangeElements, 0);
1096 env->DeleteLocalRef(jRangeArray);
1101void AndroidCameraPrivate::setPreviewFpsRange(
int min,
int max)
1103 const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
1105 if (!m_parameters.isValid())
1110 m_parameters.callMethod<
void>(
"setPreviewFpsRange",
"(II)V", min * 1000, max * 1000);
1113AndroidCamera::ImageFormat AndroidCameraPrivate::getPreviewFormat()
1115 const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
1117 if (!m_parameters.isValid())
1118 return AndroidCamera::UnknownImageFormat;
1120 return AndroidCamera::ImageFormat(m_parameters.callMethod<jint>(
"getPreviewFormat"));
1123void AndroidCameraPrivate::setPreviewFormat(AndroidCamera::ImageFormat fmt)
1125 const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
1127 if (!m_parameters.isValid())
1130 m_parameters.callMethod<
void>(
"setPreviewFormat",
"(I)V", jint(fmt));
1134QList<AndroidCamera::ImageFormat> AndroidCameraPrivate::getSupportedPreviewFormats()
1136 const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
1137 return getSupportedPreviewFormats(m_parameters);
1140QList<AndroidCamera::ImageFormat> AndroidCameraPrivate::getSupportedPreviewFormats(QJniObject ¶meters)
1142 QList<AndroidCamera::ImageFormat> list;
1144 if (parameters.isValid()) {
1145 QJniObject formatList = parameters.callObjectMethod(
"getSupportedPreviewFormats",
1146 "()Ljava/util/List;");
1147 int count = formatList.callMethod<jint>(
"size");
1148 for (
int i = 0; i < count; ++i) {
1149 QJniObject format = formatList.callObjectMethod(
"get",
1150 "(I)Ljava/lang/Object;",
1152 list.append(AndroidCamera::ImageFormat(format.callMethod<jint>(
"intValue")));
1159QSize AndroidCameraPrivate::getPreviewSize()
1161 const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
1163 if (!m_parameters.isValid())
1166 QJniObject size = m_parameters.callObjectMethod(
"getPreviewSize",
1167 "()Landroid/hardware/Camera$Size;");
1169 if (!size.isValid())
1172 return QSize(size.getField<jint>(
"width"), size.getField<jint>(
"height"));
1175void AndroidCameraPrivate::updatePreviewSize()
1177 const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
1179 if (m_previewSize.isValid()) {
1180 m_parameters.callMethod<
void>(
"setPreviewSize",
"(II)V", m_previewSize.width(), m_previewSize.height());
1184 emit previewSizeChanged();
1187bool AndroidCameraPrivate::setPreviewTexture(
void *surfaceTexture)
1189 QJniEnvironment env;
1190 auto methodId = env->GetMethodID(m_camera.objectClass(),
"setPreviewTexture",
1191 "(Landroid/graphics/SurfaceTexture;)V");
1192 env->CallVoidMethod(m_camera.object(), methodId,
static_cast<jobject>(surfaceTexture));
1194 if (env.checkAndClearExceptions())
1199bool AndroidCameraPrivate::setPreviewDisplay(
void *surfaceHolder)
1201 QJniEnvironment env;
1202 auto methodId = env->GetMethodID(m_camera.objectClass(),
"setPreviewDisplay",
1203 "(Landroid/view/SurfaceHolder;)V");
1204 env->CallVoidMethod(m_camera.object(), methodId,
static_cast<jobject>(surfaceHolder));
1206 if (env.checkAndClearExceptions())
1211void AndroidCameraPrivate::setDisplayOrientation(
int degrees)
1213 m_camera.callMethod<
void>(
"setDisplayOrientation",
"(I)V", degrees);
1214 m_cameraListener.callMethod<
void>(
"setPhotoRotation",
"(I)V", degrees);
1217bool AndroidCameraPrivate::isZoomSupported()
1219 const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
1221 if (!m_parameters.isValid())
1224 return m_parameters.callMethod<jboolean>(
"isZoomSupported");
1227int AndroidCameraPrivate::getMaxZoom()
1229 const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
1231 if (!m_parameters.isValid())
1234 return m_parameters.callMethod<jint>(
"getMaxZoom");
1237QList<
int> AndroidCameraPrivate::getZoomRatios()
1239 const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
1243 if (m_parameters.isValid()) {
1244 QJniObject ratioList = m_parameters.callObjectMethod(
"getZoomRatios",
1245 "()Ljava/util/List;");
1246 int count = ratioList.callMethod<jint>(
"size");
1247 for (
int i = 0; i < count; ++i) {
1248 QJniObject zoomRatio = ratioList.callObjectMethod(
"get",
1249 "(I)Ljava/lang/Object;",
1252 ratios.append(zoomRatio.callMethod<jint>(
"intValue"));
1259int AndroidCameraPrivate::getZoom()
1261 const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
1263 if (!m_parameters.isValid())
1266 return m_parameters.callMethod<jint>(
"getZoom");
1269void AndroidCameraPrivate::setZoom(
int value)
1271 const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
1273 if (!m_parameters.isValid())
1276 m_parameters.callMethod<
void>(
"setZoom",
"(I)V", value);
1280QString AndroidCameraPrivate::getFlashMode()
1282 const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
1286 if (m_parameters.isValid()) {
1287 QJniObject flashMode = m_parameters.callObjectMethod(
"getFlashMode",
1288 "()Ljava/lang/String;");
1289 if (flashMode.isValid())
1290 value = flashMode.toString();
1296void AndroidCameraPrivate::setFlashMode(
const QString &value)
1298 const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
1300 if (!m_parameters.isValid())
1303 m_parameters.callMethod<
void>(
"setFlashMode",
1304 "(Ljava/lang/String;)V",
1305 QJniObject::fromString(value).object());
1309QString AndroidCameraPrivate::getFocusMode()
1311 const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
1315 if (m_parameters.isValid()) {
1316 QJniObject focusMode = m_parameters.callObjectMethod(
"getFocusMode",
1317 "()Ljava/lang/String;");
1318 if (focusMode.isValid())
1319 value = focusMode.toString();
1325void AndroidCameraPrivate::setFocusMode(
const QString &value)
1327 const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
1329 if (!m_parameters.isValid())
1332 m_parameters.callMethod<
void>(
"setFocusMode",
1333 "(Ljava/lang/String;)V",
1334 QJniObject::fromString(value).object());
1338int AndroidCameraPrivate::getMaxNumFocusAreas()
1340 const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
1342 if (!m_parameters.isValid())
1345 return m_parameters.callMethod<jint>(
"getMaxNumFocusAreas");
1348QList<QRect> AndroidCameraPrivate::getFocusAreas()
1351 const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
1353 if (m_parameters.isValid()) {
1354 QJniObject list = m_parameters.callObjectMethod(
"getFocusAreas",
1355 "()Ljava/util/List;");
1357 if (list.isValid()) {
1358 int count = list.callMethod<jint>(
"size");
1359 for (
int i = 0; i < count; ++i) {
1360 QJniObject area = list.callObjectMethod(
"get",
1361 "(I)Ljava/lang/Object;",
1364 areas.append(areaToRect(area.object()));
1372void AndroidCameraPrivate::setFocusAreas(
const QList<QRect> &areas)
1374 const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
1376 if (!m_parameters.isValid() || areas.isEmpty())
1381 if (!areas.isEmpty()) {
1382 QJniEnvironment env;
1383 QJniObject arrayList(
"java/util/ArrayList",
"(I)V", areas.size());
1384 for (
int i = 0; i < areas.size(); ++i) {
1385 arrayList.callMethod<jboolean>(
"add",
1386 "(Ljava/lang/Object;)Z",
1387 rectToArea(areas.at(i)).object());
1392 m_parameters.callMethod<
void>(
"setFocusAreas",
"(Ljava/util/List;)V", list.object());
1397void AndroidCameraPrivate::autoFocus()
1399 QJniEnvironment env;
1400 auto methodId = env->GetMethodID(m_camera.objectClass(),
"autoFocus",
1401 "(Landroid/hardware/Camera$AutoFocusCallback;)V");
1402 env->CallVoidMethod(m_camera.object(), methodId, m_cameraListener.object());
1404 if (!env.checkAndClearExceptions())
1405 emit autoFocusStarted();
1408void AndroidCameraPrivate::cancelAutoFocus()
1410 QJniEnvironment env;
1411 m_camera.callMethod<
void>(
"cancelAutoFocus");
1414bool AndroidCameraPrivate::isAutoExposureLockSupported()
1416 const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
1418 if (!m_parameters.isValid())
1421 return m_parameters.callMethod<jboolean>(
"isAutoExposureLockSupported");
1424bool AndroidCameraPrivate::getAutoExposureLock()
1426 const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
1428 if (!m_parameters.isValid())
1431 return m_parameters.callMethod<jboolean>(
"getAutoExposureLock");
1434void AndroidCameraPrivate::setAutoExposureLock(
bool toggle)
1436 const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
1438 if (!m_parameters.isValid())
1441 m_parameters.callMethod<
void>(
"setAutoExposureLock",
"(Z)V", toggle);
1445bool AndroidCameraPrivate::isAutoWhiteBalanceLockSupported()
1447 const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
1449 if (!m_parameters.isValid())
1452 return m_parameters.callMethod<jboolean>(
"isAutoWhiteBalanceLockSupported");
1455bool AndroidCameraPrivate::getAutoWhiteBalanceLock()
1457 const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
1459 if (!m_parameters.isValid())
1462 return m_parameters.callMethod<jboolean>(
"getAutoWhiteBalanceLock");
1465void AndroidCameraPrivate::setAutoWhiteBalanceLock(
bool toggle)
1467 const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
1469 if (!m_parameters.isValid())
1472 m_parameters.callMethod<
void>(
"setAutoWhiteBalanceLock",
"(Z)V", toggle);
1476int AndroidCameraPrivate::getExposureCompensation()
1478 const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
1480 if (!m_parameters.isValid())
1483 return m_parameters.callMethod<jint>(
"getExposureCompensation");
1486void AndroidCameraPrivate::setExposureCompensation(
int value)
1488 const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
1490 if (!m_parameters.isValid())
1493 m_parameters.callMethod<
void>(
"setExposureCompensation",
"(I)V", value);
1497float AndroidCameraPrivate::getExposureCompensationStep()
1499 const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
1501 if (!m_parameters.isValid())
1504 return m_parameters.callMethod<jfloat>(
"getExposureCompensationStep");
1507int AndroidCameraPrivate::getMinExposureCompensation()
1509 const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
1511 if (!m_parameters.isValid())
1514 return m_parameters.callMethod<jint>(
"getMinExposureCompensation");
1517int AndroidCameraPrivate::getMaxExposureCompensation()
1519 const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
1521 if (!m_parameters.isValid())
1524 return m_parameters.callMethod<jint>(
"getMaxExposureCompensation");
1527QString AndroidCameraPrivate::getSceneMode()
1529 const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
1533 if (m_parameters.isValid()) {
1534 QJniObject sceneMode = m_parameters.callObjectMethod(
"getSceneMode",
1535 "()Ljava/lang/String;");
1536 if (sceneMode.isValid())
1537 value = sceneMode.toString();
1543void AndroidCameraPrivate::setSceneMode(
const QString &value)
1545 const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
1547 if (!m_parameters.isValid())
1550 m_parameters.callMethod<
void>(
"setSceneMode",
1551 "(Ljava/lang/String;)V",
1552 QJniObject::fromString(value).object());
1556QString AndroidCameraPrivate::getWhiteBalance()
1558 const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
1562 if (m_parameters.isValid()) {
1563 QJniObject wb = m_parameters.callObjectMethod(
"getWhiteBalance",
1564 "()Ljava/lang/String;");
1566 value = wb.toString();
1572void AndroidCameraPrivate::setWhiteBalance(
const QString &value)
1574 const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
1576 if (!m_parameters.isValid())
1579 m_parameters.callMethod<
void>(
"setWhiteBalance",
1580 "(Ljava/lang/String;)V",
1581 QJniObject::fromString(value).object());
1584 emit whiteBalanceChanged();
1587void AndroidCameraPrivate::updateRotation()
1589 const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
1591 m_parameters.callMethod<
void>(
"setRotation",
"(I)V", m_rotation);
1595QList<QSize> AndroidCameraPrivate::getSupportedPictureSizes()
1597 const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
1601 if (m_parameters.isValid()) {
1602 QJniObject sizeList = m_parameters.callObjectMethod(
"getSupportedPictureSizes",
1603 "()Ljava/util/List;");
1604 int count = sizeList.callMethod<jint>(
"size");
1605 for (
int i = 0; i < count; ++i) {
1606 QJniObject size = sizeList.callObjectMethod(
"get",
1607 "(I)Ljava/lang/Object;",
1609 list.append(QSize(size.getField<jint>(
"width"), size.getField<jint>(
"height")));
1612 ranges::sort(list, qt_sizeLessThan);
1618QList<QSize> AndroidCameraPrivate::getSupportedVideoSizes()
1620 const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
1623 if (m_parameters.isValid()) {
1624 QJniObject sizeList = m_parameters.callObjectMethod(
"getSupportedVideoSizes",
1625 "()Ljava/util/List;");
1626 if (!sizeList.isValid())
1629 int count = sizeList.callMethod<jint>(
"size");
1630 for (
int i = 0; i < count; ++i) {
1631 const QJniObject size = sizeList.callObjectMethod(
"get",
"(I)Ljava/lang/Object;", i);
1633 list.append(QSize(size.getField<jint>(
"width"), size.getField<jint>(
"height")));
1635 ranges::sort(list, qt_sizeLessThan);
1641void AndroidCameraPrivate::setPictureSize(
const QSize &size)
1643 const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
1645 if (!m_parameters.isValid())
1648 m_parameters.callMethod<
void>(
"setPictureSize",
"(II)V", size.width(), size.height());
1652void AndroidCameraPrivate::setJpegQuality(
int quality)
1654 const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
1656 if (!m_parameters.isValid())
1659 m_parameters.callMethod<
void>(
"setJpegQuality",
"(I)V", quality);
1663void AndroidCameraPrivate::startPreview()
1665 setupPreviewFrameCallback();
1667 QJniEnvironment env;
1668 auto methodId = env->GetMethodID(m_camera.objectClass(),
"startPreview",
"()V");
1669 env->CallVoidMethod(m_camera.object(), methodId);
1671 if (env.checkAndClearExceptions())
1672 emit previewFailedToStart();
1674 emit previewStarted();
1677void AndroidCameraPrivate::stopPreview()
1680 m_cameraListener.callMethod<
void>(
"notifyWhenFrameAvailable",
"(Z)V",
false);
1681 m_camera.callMethod<
void>(
"stopPreview");
1682 emit previewStopped();
1685void AndroidCameraPrivate::takePicture()
1690 m_cameraListener.callMethod<
void>(
"clearPreviewCallback",
"(Landroid/hardware/Camera;)V", m_camera.object());
1692 QJniEnvironment env;
1693 auto methodId = env->GetMethodID(m_camera.objectClass(),
"takePicture",
1694 "(Landroid/hardware/Camera$ShutterCallback;"
1695 "Landroid/hardware/Camera$PictureCallback;"
1696 "Landroid/hardware/Camera$PictureCallback;)V");
1697 env->CallVoidMethod(m_camera.object(), methodId, m_cameraListener.object(),
1698 jobject(0), m_cameraListener.object());
1700 if (env.checkAndClearExceptions())
1701 emit takePictureFailed();
1704void AndroidCameraPrivate::setupPreviewFrameCallback()
1706 m_cameraListener.callMethod<
void>(
"setupPreviewCallback",
"(Landroid/hardware/Camera;)V", m_camera.object());
1709void AndroidCameraPrivate::notifyNewFrames(
bool notify)
1711 m_cameraListener.callMethod<
void>(
"notifyNewFrames",
"(Z)V", notify);
1714void AndroidCameraPrivate::fetchLastPreviewFrame()
1716 QJniEnvironment env;
1717 QJniObject data = m_cameraListener.callObjectMethod(
"lastPreviewBuffer",
"()[B");
1719 if (!data.isValid()) {
1721 m_cameraListener.callMethod<
void>(
"notifyWhenFrameAvailable",
"(Z)V",
true);
1725 const int arrayLength = env->GetArrayLength(
static_cast<jbyteArray>(data.object()));
1726 if (arrayLength == 0)
1729 QByteArray bytes(arrayLength, Qt::Uninitialized);
1730 env->GetByteArrayRegion(
static_cast<jbyteArray>(data.object()),
1733 reinterpret_cast<jbyte *>(bytes.data()));
1735 const int width = m_cameraListener.callMethod<jint>(
"previewWidth");
1736 const int height = m_cameraListener.callMethod<jint>(
"previewHeight");
1737 const int format = m_cameraListener.callMethod<jint>(
"previewFormat");
1738 const int bpl = m_cameraListener.callMethod<jint>(
"previewBytesPerLine");
1740 QVideoFrameFormat frameFormat(
1741 QSize(width, height),
1742 qt_pixelFormatFromAndroidImageFormat(AndroidCamera::ImageFormat(format)));
1744 QVideoFrame frame = QVideoFramePrivate::createFrame(
1745 std::make_unique<QMemoryVideoBuffer>(std::move(bytes), bpl), std::move(frameFormat));
1747 emit lastPreviewFrameFetched(frame);
1750void AndroidCameraPrivate::applyParameters()
1752 QJniEnvironment env;
1753 m_camera.callMethod<
void>(
"setParameters",
1754 "(Landroid/hardware/Camera$Parameters;)V",
1755 m_parameters.object());
1758QStringList AndroidCameraPrivate::callParametersStringListMethod(
const QByteArray &methodName)
1760 const std::lock_guard<QRecursiveMutex> locker(m_parametersMutex);
1762 QStringList stringList;
1764 if (m_parameters.isValid()) {
1765 QJniObject list = m_parameters.callObjectMethod(methodName.constData(),
1766 "()Ljava/util/List;");
1768 if (list.isValid()) {
1769 int count = list.callMethod<jint>(
"size");
1770 for (
int i = 0; i < count; ++i) {
1771 QJniObject string = list.callObjectMethod(
"get",
1772 "(I)Ljava/lang/Object;",
1774 stringList.append(string.toString());
1784 static const JNINativeMethod methods[] = {
1785 {
"notifyAutoFocusComplete",
"(IZ)V", (
void *)notifyAutoFocusComplete},
1786 {
"notifyPictureExposed",
"(I)V", (
void *)notifyPictureExposed},
1787 {
"notifyPictureCaptured",
"(I[B)V", (
void *)notifyPictureCaptured},
1788 {
"notifyNewPreviewFrame",
"(I[BIIII)V", (
void *)notifyNewPreviewFrame},
1789 {
"notifyFrameAvailable",
"(I)V", (
void *)notifyFrameAvailable}
1792 const int size =
std::size(methods);
1798#include "androidcamera.moc"
1799#include "moc_androidcamera_p.cpp"
QHash< int, AndroidCamera * > CameraMap
static qint32 s_activeCameras
static const char QtCameraListenerClassName[]
void setupPreviewFrameCallback()
QJniObject getCameraObject()
ImageFormat getPreviewFormat()
QSize getPreferredPreviewSizeForVideo()
void setPictureSize(const QSize &size)
void setFlashMode(const QString &value)
QSize actualPreviewSize()
int getExposureCompensation()
QString getWhiteBalance()
void setExposureCompensation(int value)
bool getAutoExposureLock()
float getExposureCompensationStep()
QList< QCameraFormat > getSupportedFormats()
void setFocusAreas(const QList< QRect > &areas)
bool getAutoWhiteBalanceLock()
QList< QRect > getFocusAreas()
void stopPreviewSynchronous()
QStringList getSupportedFocusModes()
bool setPreviewDisplay(AndroidSurfaceHolder *surfaceHolder)
void setRotation(int rotation)
QList< FpsRange > getSupportedPreviewFpsRange()
bool isAutoWhiteBalanceLockSupported()
static int getNumberOfCameras()
QJniObject getParametersObject()
void previewFailedToStart()
void setWhiteBalance(const QString &value)
bool setPreviewTexture(AndroidSurfaceTexture *surfaceTexture)
void setAutoExposureLock(bool toggle)
FpsRange getPreviewFpsRange()
void fetchLastPreviewFrame()
void setPreviewFpsRange(FpsRange)
void setJpegQuality(int quality)
QStringList getSupportedSceneModes()
QList< QSize > getSupportedPictureSizes()
QList< QSize > getSupportedPreviewSizes()
static AndroidCamera * open(int cameraId)
void setSceneMode(const QString &value)
QList< QSize > getSupportedVideoSizes()
static bool registerNativeMethods()
void setFocusMode(const QString &value)
QList< ImageFormat > getSupportedPreviewFormats()
void setDisplayOrientation(int degrees)
QSize previewSize() const
int getMaxNumFocusAreas()
QStringList getSupportedWhiteBalance()
int getMinExposureCompensation()
int getNativeOrientation()
void notifyNewFrames(bool notify)
void whiteBalanceChanged()
void setPreviewSize(const QSize &size)
int getMaxExposureCompensation()
void setPreviewFormat(ImageFormat fmt)
QStringList getSupportedFlashModes()
QList< int > getZoomRatios()
void setAutoWhiteBalanceLock(bool toggle)
bool isAutoExposureLockSupported()
QT_BEGIN_NAMESPACE Q_STATIC_LOGGING_CATEGORY(lcSynthesizedIterableAccess, "qt.iterable.synthesized", QtWarningMsg)