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::Traits<QtJniTypes::QtVideoDeviceManager>::className(),
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::Traits<QtJniTypes::QtCamera2>::className(),
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;
227 int deviceOrientation = 0;
228 switch (screenOrientation) {
233 deviceOrientation = 270;
236 deviceOrientation = 180;
239 deviceOrientation = 90;
244 int rotation = (sensorOrientation(m_cameraDevice.
id()) - deviceOrientation *
sign + 360) % 360;
254 if (!m_jniCamera.isValid()) {
259 if (active && checkCameraPermission()) {
265 m_cameraFormat = getDefaultCameraFormat();
274 g_qcameras->insert(m_cameraDevice.
id(),
this);
279 const static int imageFormat =
280 QJniObject::getStaticField<QtJniTypes::AndroidImageFormat, jint>(
"YUV_420_888");
281 m_jniCamera.callMethod<
void>(
"prepareCamera", jint(
width), jint(
height),
285 bool canOpen = m_jniCamera.callMethod<jboolean>(
286 "open", QJniObject::fromString(m_cameraDevice.
id()).object<jstring>());
289 g_qcameras->remove(m_cameraDevice.
id());
295 m_jniCamera.callMethod<
void>(
"stopAndClose");
296 m_jniCamera.callMethod<
void>(
"clearSurfaces");
335 const auto chosenFormat =
format.isNull() ? getDefaultCameraFormat() :
format;
340 m_cameraFormat = chosenFormat;
351void QAndroidCamera::updateCameraCharacteristics()
354 cleanCameraCharacteristics();
358 QJniObject deviceManager(QtJniTypes::Traits<QtJniTypes::QtVideoDeviceManager>::className(),
359 QNativeInterface::QAndroidApplication::context());
361 if (!deviceManager.isValid()) {
362 qCWarning(qLCAndroidCamera) <<
"Failed to connect to Qt Video Device Manager.";
363 cleanCameraCharacteristics();
367 const float maxZoom = deviceManager.callMethod<jfloat>(
368 "getMaxZoom", QJniObject::fromString(m_cameraDevice.
id()).object<jstring>());
374 m_TorchModeSupported = deviceManager.callMethod<jboolean>(
375 "isTorchModeSupported", QJniObject::fromString(m_cameraDevice.
id()).object<jstring>());
377 m_supportedFlashModes.
clear();
379 QJniObject flashModesObj = deviceManager.callMethod<QtJniTypes::StringArray>(
380 "getSupportedFlashModes",
381 QJniObject::fromString(m_cameraDevice.
id()).object<jstring>());
383 jobjectArray flashModes = flashModesObj.object<jobjectArray>();
384 int size = jniEnv->GetArrayLength(flashModes);
385 for (
int i = 0;
i <
size; ++
i) {
386 QJniObject flashModeObj = jniEnv->GetObjectArrayElement(flashModes,
i);
395void QAndroidCamera::cleanCameraCharacteristics()
404 m_TorchModeSupported =
false;
409 m_supportedFlashModes.
clear();
432 m_jniCamera.callMethod<
void>(
"setFlashMode", QJniObject::fromString(
flashMode).object<jstring>());
445 return m_supportedFlashModes.
size() > 1;
453 return m_TorchModeSupported;
469 m_jniCamera.callMethod<
void>(
"setTorchMode", jboolean(
torchMode));
476 m_jniCamera.callMethod<
void>(
"zoomTo", factor);
502 bool canStart = m_jniCamera.callMethod<jboolean>(
"start", 3);
511void QAndroidCamera::onCameraOpened()
513 bool canStart = m_jniCamera.callMethod<jboolean>(
"createSession");
525 QString(
"Capture error with Camera %1. Camera2 Api error code: %2")
532 m_waitingForFirstFrame =
true;
537 m_waitingForFirstFrame =
false;
543 m_jniCamera.callMethod<
void>(
"takePhoto");
548 m_jniCamera.callMethod<
void>(
"saveExifToFile", QJniObject::fromString(filename).object<jstring>());
556 QStringLiteral(
"Capture session failure with Camera %1. Camera2 Api error code: %2")
563#define GET_CAMERA(cameraId) \
564 QString key = QJniObject(cameraId).toString(); \
565 QReadLocker locker(rwLock); \
566 if (!g_qcameras->contains(key)) { \
567 qCWarning(qLCAndroidCamera) << "Calling back a QtCamera2 after being destroyed."; \
570 QAndroidCamera *camera = g_qcameras->find(key).value();
573 QtJniTypes::AndroidImage
image)
584 QtJniTypes::AndroidImage
image)
611 camera->onCameraDisconnect();
631 camera->onCaptureSessionConfigured();
641 camera->onCaptureSessionConfigureFailed();
651 camera->onSessionActive();
661 camera->onSessionClosed();
672 camera->onCaptureSessionFailed(reason, framenumber);
678 static const bool registered = []() {
680 QtJniTypes::Traits<QtJniTypes::QtCamera2>::className(),
Q_DECLARE_JNI_TYPE(StringArray, "[Ljava/lang/String;")
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
void updateExif(const QString &filename)
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 setRotation(QtVideo::Rotation angle)
Sets the angle the frame should be rotated clockwise before displaying.
void setMirrored(bool)
Sets the mirrored flag for the frame and sets the flag to the underlying \l surfaceFormat.
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)
QMap< QString, QAndroidCamera * > QAndroidCameraMap
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
QLatin1StringView QLatin1String
#define QStringLiteral(str)
connect(quitButton, &QPushButton::clicked, &app, &QCoreApplication::quit, Qt::QueuedConnection)
bool contains(const AT &t) const noexcept