15#include <QtCore/qcoreapplication.h>
16#include <QtCore/qpermissions.h>
17#include <QtCore/private/qandroidextras_p.h>
18#include <private/qcameradevice_p.h>
19#include <QReadWriteLock>
20#include <private/qvideoframeconverter_p.h>
21#include <private/qvideotexturehelper_p.h>
28#include "libavutil/hwcontext.h"
29#include "libavutil/pixfmt.h"
34 "org/qtproject/qt/android/multimedia/QtVideoDeviceManager");
57 .resolution = { 1920, 1080 },
61 return defaultFormat->
create();
64bool checkCameraPermission()
70 qCWarning(qLCAndroidCamera) <<
"Access to camera not granted!";
75int sensorOrientation(
QString cameraId)
77 QJniObject deviceManager(QtJniTypes::className<QtJniTypes::QtVideoDeviceManager>(),
78 QNativeInterface::QAndroidApplication::context());
80 if (!deviceManager.isValid()) {
81 qCWarning(qLCAndroidCamera) <<
"Failed to connect to Qt Video Device Manager.";
85 return deviceManager.callMethod<jint>(
"getSensorOrientation",
86 QJniObject::fromString(cameraId).object<jstring>());
94 m_jniCamera =
QJniObject(QtJniTypes::className<QtJniTypes::QtCamera2>(),
95 QNativeInterface::QAndroidApplication::context());
101 : getDefaultCameraFormat();
102 updateCameraCharacteristics();
115 g_qcameras->remove(m_cameraDevice.
id());
117 m_jniCamera.callMethod<
void>(
"stopAndClose");
121 m_jniCamera.callMethod<
void>(
"stopBackgroundThread");
131 updateCameraCharacteristics();
132 m_cameraFormat = getDefaultCameraFormat();
156 qCWarning(qLCAndroidCamera) <<
"Received frame when not active... ignoring";
157 qCWarning(qLCAndroidCamera) <<
"state:" << m_state;
158 image.callMethod<
void>(
"close");
163 if (!androidFrame->isParsed()) {
164 qCWarning(qLCAndroidCamera) <<
"Failed to parse frame.. dropping frame";
169 int timestamp = androidFrame->timestamp();
170 m_androidFramePixelFormat = androidFrame->format();
171 if (m_waitingForFirstFrame) {
172 m_waitingForFirstFrame =
false;
177 avframe->width = androidFrame->size().width();
178 avframe->height = androidFrame->size().height();
181 avframe->extended_data = avframe->data;
182 avframe->pts = androidFrame->timestamp();
184 for (
int planeNumber = 0; planeNumber < androidFrame->numberPlanes(); planeNumber++) {
186 avframe->linesize[planeNumber] = plane.
rowStride;
187 avframe->data[planeNumber] = plane.
data;
190 avframe->data[3] =
nullptr;
191 avframe->buf[0] =
nullptr;
193 avframe->opaque_ref = av_buffer_create(NULL, 1,
deleteFrame, androidFrame, 0);
194 avframe->extended_data = avframe->data;
195 avframe->pts = timestamp;
201 if (lastTimestamp == 0)
202 lastTimestamp = timestamp;
215 lastTimestamp = timestamp;
225 int deviceOrientation = 0;
228 switch (screenOrientation) {
233 deviceOrientation = 90;
236 deviceOrientation = 180;
239 deviceOrientation = 270;
246 rotation = (sensorOrientation(m_cameraDevice.
id()) - deviceOrientation + 360) % 360;
247 rotation = (180 + rotation) % 360;
249 rotation = (sensorOrientation(m_cameraDevice.
id()) - deviceOrientation + 360) % 360;
259 if (!m_jniCamera.isValid()) {
264 if (active && checkCameraPermission()) {
270 m_cameraFormat = getDefaultCameraFormat();
279 g_qcameras->insert(m_cameraDevice.
id(),
this);
281 bool canOpen = m_jniCamera.callMethod<jboolean>(
282 "open", QJniObject::fromString(m_cameraDevice.
id()).object<jstring>());
285 g_qcameras->remove(m_cameraDevice.
id());
294 const static int imageFormat =
295 QJniObject::getStaticField<QtJniTypes::AndroidImageFormat, jint>(
"YUV_420_888");
296 m_jniCamera.callMethod<jboolean>(
"addImageReader", jint(
width), jint(
height),
300 m_jniCamera.callMethod<
void>(
"stopAndClose");
301 m_jniCamera.callMethod<
void>(
"clearSurfaces");
348void QAndroidCamera::updateCameraCharacteristics()
351 cleanCameraCharacteristics();
355 QJniObject deviceManager(QtJniTypes::className<QtJniTypes::QtVideoDeviceManager>(),
356 QNativeInterface::QAndroidApplication::context());
358 if (!deviceManager.isValid()) {
359 qCWarning(qLCAndroidCamera) <<
"Failed to connect to Qt Video Device Manager.";
360 cleanCameraCharacteristics();
364 const float maxZoom = deviceManager.callMethod<jfloat>(
365 "getMaxZoom", QJniObject::fromString(m_cameraDevice.
id()).object<jstring>());
368 m_TorchModeSupported = deviceManager.callMethod<jboolean>(
369 "isTorchModeSupported", QJniObject::fromString(m_cameraDevice.
id()).object<jstring>());
372 QJniObject flashModesObj = deviceManager.callMethod<QtJniTypes::StringArray>(
373 "getSupportedFlashModes",
374 QJniObject::fromString(m_cameraDevice.
id()).object<jstring>());
376 jobjectArray flashModes = flashModesObj.object<jobjectArray>();
377 int size = jniEnv->GetArrayLength(flashModes);
378 for (
int i = 0;
i <
size; ++
i) {
379 QJniObject flashModeObj = jniEnv->GetObjectArrayElement(flashModes,
i);
388void QAndroidCamera::cleanCameraCharacteristics()
394 m_TorchModeSupported =
false;
399 m_supportedFlashModes.
clear();
421 m_jniCamera.callMethod<
void>(
"setFlashMode", QJniObject::fromString(
flashMode).object<jstring>());
434 return m_supportedFlashModes.
size() > 1;
442 return m_TorchModeSupported;
458 m_jniCamera.callMethod<
void>(
"setTorchMode", jboolean(
torchMode));
465 m_jniCamera.callMethod<
void>(
"zoomTo", factor);
491 bool canStart = m_jniCamera.callMethod<jboolean>(
"start", 3);
500void QAndroidCamera::onCameraOpened()
502 bool canStart = m_jniCamera.callMethod<jboolean>(
"createSession");
514 QString(
"Capture error with Camera %1. Camera2 Api error code: %2")
521 m_waitingForFirstFrame =
true;
526 m_waitingForFirstFrame =
false;
532 m_jniCamera.callMethod<
void>(
"takePhoto");
540 QString(
"Capture session failure with Camera %1. Camera2 Api error code: %2")
547#define GET_CAMERA(cameraId) \
548 QString key = QJniObject(cameraId).toString(); \
549 QReadLocker locker(rwLock); \
550 if (!g_qcameras->contains(key)) { \
551 qCWarning(qLCAndroidCamera) << "Calling back a QtCamera2 after being destroyed."; \
554 QAndroidCamera *camera = g_qcameras->find(key).value();
557 QtJniTypes::AndroidImage
image)
568 QtJniTypes::AndroidImage
image)
595 camera->onCameraDisconnect();
615 camera->onCaptureSessionConfigured();
625 camera->onCaptureSessionConfigureFailed();
635 camera->onSessionActive();
645 camera->onSessionClosed();
656 camera->onCaptureSessionFailed(reason, framenumber);
662 static const bool registered = []() {
664 QtJniTypes::className<QtJniTypes::QtCamera2>(),
void onCameraDisconnect()
bool isTorchModeSupported(QCamera::TorchMode mode) const override
void onApplicationStateChanged()
QAndroidCamera(QCamera *camera)
void setFlashMode(QCamera::FlashMode mode) override
void onCaptureSessionFailed(int reason, long frameNumber)
void zoomTo(float factor, float rate) override
void setCamera(const QCameraDevice &camera) override
void onCaptureSessionConfigured()
bool setCameraFormat(const QCameraFormat &format) override
void frameAvailable(QJniObject image, bool takePhoto=false)
void onCaptured(const QVideoFrame &)
bool isFlashReady() const override
bool isFlashModeSupported(QCamera::FlashMode mode) const override
virtual ~QAndroidCamera()
std::optional< int > ffmpegHWPixelFormat() const override
void onCaptureSessionConfigureFailed()
void setActive(bool active) override
bool isActive() const override
void onCameraError(int error)
void setTorchMode(QCamera::TorchMode mode) override
bool isEmpty() const noexcept
Returns true if the byte array has size 0; otherwise returns false.
The QCameraDevice class provides general information about camera devices.
Position position
\qmlproperty enumeration QtMultimedia::cameraDevice::position
QString description
\qmlproperty string QtMultimedia::cameraDevice::description
QList< QCameraFormat > videoFormats
\qmlproperty CameraFormat QtMultimedia::cameraDevice::videoFormats
QByteArray id
\qmlproperty string QtMultimedia::cameraDevice::id
Access the camera for taking pictures or videos.
The QCamera class provides interface for system camera devices.
TorchMode
\value TorchOff Torch is Off.
QCameraDevice cameraDevice
\qmlproperty cameraDevice QtMultimedia::Camera::cameraDevice
QCameraFormat cameraFormat
\qmlproperty cameraFormat QtMultimedia::Camera::cameraFormat
FlashMode
\value FlashOff Flash is Off.
static AVPixelFormat toAVPixelFormat(QVideoFrameFormat::PixelFormat pixelFormat)
static std::unique_ptr< HWAccel > create(AVHWDeviceType deviceType)
static Qt::ApplicationState applicationState()
QScreen * primaryScreen
the primary (or default) screen of the application.
void applicationStateChanged(Qt::ApplicationState state)
qsizetype size() const noexcept
void append(parameter_type t)
Qt::ScreenOrientation primaryOrientation
the primary screen orientation
Qt::ScreenOrientation orientation
the screen orientation
constexpr int height() const noexcept
Returns the height.
constexpr int width() const noexcept
Returns the width.
\macro QT_RESTRICTED_CAST_FROM_ASCII
The QVideoFrame class represents a frame of video data.
void setRotationAngle(RotationAngle)
Sets the angle the frame should be rotated clockwise before displaying.
RotationAngle
The angle of the clockwise rotation that should be applied to a video frame before displaying.
void setMirrored(bool)
Sets the mirrored flag for the frame.
void setEndTime(qint64 time)
Sets the presentation time (in microseconds) when a frame should stop being displayed.
void setStartTime(qint64 time)
Sets the presentation time (in microseconds) when the frame should initially be displayed.
list append(new Employee("Blackpool", "Stephen"))
static void onFrameAvailable(JNIEnv *env, jobject obj, jstring cameraId, QtJniTypes::AndroidImage image)
static void onCaptureSessionFailed(JNIEnv *env, jobject obj, jstring cameraId, jint reason, jlong framenumber)
static void onSessionClosed(JNIEnv *env, jobject obj, jstring cameraId)
Q_DECLARE_JNI_CLASS(QtCamera2, "org/qtproject/qt/android/multimedia/QtCamera2")
#define GET_CAMERA(cameraId)
static void onPhotoAvailable(JNIEnv *env, jobject obj, jstring cameraId, QtJniTypes::AndroidImage image)
static void onCameraError(JNIEnv *env, jobject obj, jstring cameraId, jint error)
static void onCaptureSessionConfigureFailed(JNIEnv *env, jobject obj, jstring cameraId)
static void onCameraOpened(JNIEnv *env, jobject obj, jstring cameraId)
static void onSessionActive(JNIEnv *env, jobject obj, jstring cameraId)
static void onCameraDisconnect(JNIEnv *env, jobject obj, jstring cameraId)
static void deleteFrame(void *opaque, uint8_t *data)
static void onCaptureSessionConfigured(JNIEnv *env, jobject obj, jstring cameraId)
void newState(QList< State > &states, const char *token, const char *lexem, bool pre)
AVFrameUPtr makeAVFrame()
Combined button and popup list for selecting options.
@ InvertedLandscapeOrientation
@ InvertedPortraitOrientation
static org qtproject qt android multimedia QtVideoDeviceManager
DBusConnection const char DBusError * error
#define Q_GLOBAL_STATIC(TYPE, NAME,...)
#define Q_LOGGING_CATEGORY(name,...)
#define qCWarning(category,...)
GLint GLsizei GLsizei height
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLint GLsizei GLsizei GLenum format
Q_DECLARE_JNI_TYPE(File, "Ljava/io/File;")
QLatin1StringView QLatin1String
connect(quitButton, &QPushButton::clicked, &app, &QCoreApplication::quit, Qt::QueuedConnection)
bool contains(const AT &t) const noexcept