Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qandroidvideodevices.cpp
Go to the documentation of this file.
1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include <QtFFmpegMediaPluginImpl/private/qandroidvideodevices_p.h>
5
6#include <QtCore/private/qandroidextras_p.h>
7#include <QtCore/qcoreapplication.h>
8#include <QtCore/qcoreapplication_platform.h>
9#include <QtCore/qjnienvironment.h>
10#include <QtCore/qloggingcategory.h>
11
12#include <QtFFmpegMediaPluginImpl/private/qandroidvideoframebuffer_p.h>
13
14#include <QtMultimedia/private/qcameradevice_p.h>
15
16#include <jni.h>
17
18QT_BEGIN_NAMESPACE
19
20using namespace Qt::StringLiterals;
21
22Q_STATIC_LOGGING_CATEGORY(qLCAndroidVideoDevices, "qt.multimedia.ffmpeg.android.videoDevices");
23
25 QtCameraAvailabilityListener,
26 "org/qtproject/qt/android/multimedia/QtCameraAvailabilityListener");
27
28QAndroidVideoDevices::QAndroidVideoDevices(QPlatformMediaIntegration *integration)
29 : QPlatformVideoDevices(integration)
30{
31 registerNativeMethods();
32
33 m_javaCameraAvailabilityListener = QtJniTypes::QtCameraAvailabilityListener(
34 QtAndroidPrivate::activity(),
35 static_cast<jlong>(reinterpret_cast<size_t>(this)));
36}
37
38QAndroidVideoDevices::~QAndroidVideoDevices()
39{
40 m_javaCameraAvailabilityListener.callMethod<void>("cleanup");
41}
42
43QCameraFormat createCameraFormat(int width, int height, int fpsMin, int fpsMax)
44{
45 QCameraFormatPrivate *format = new QCameraFormatPrivate();
46
47 format->resolution = { width, height };
48
49 format->minFrameRate = fpsMin;
50 format->maxFrameRate = fpsMax;
51
52 format->pixelFormat = QVideoFrameFormat::PixelFormat::Format_YUV420P;
53
54 return format->create();
55}
56
57QList<QCameraDevice> QAndroidVideoDevices::findVideoInputs() const
58{
59 QList<QCameraDevice> devices;
60
61 QJniObject deviceManager(QtJniTypes::Traits<QtJniTypes::QtVideoDeviceManager>::className(),
62 QNativeInterface::QAndroidApplication::context());
63
64 if (!deviceManager.isValid()) {
65 qCWarning(qLCAndroidVideoDevices) << "Failed to connect to Qt Video Device Manager.";
66 return devices;
67 }
68
69 const QJniArray cameraIdList = deviceManager.callMethod<QtJniTypes::String[]>("getCameraIdList");
70 if (!cameraIdList.isValid())
71 return devices;
72
73 int cameraIndex = 0;
74 for (const auto &cameraId : cameraIdList) {
75 if (!cameraId.isValid())
76 continue;
77
78 auto info = std::make_unique<QCameraDevicePrivate>();
79 info->id = cameraId.toString().toUtf8();
80
81 info->orientation = deviceManager.callMethod<jint>("getSensorOrientation", cameraId);
82
83 // Will be set to -1 if facing can not be determined.
84 const int facing = deviceManager.callMethod<jint>("getLensFacing", cameraId);
85
86 // Values grabbed from Android docs CameraCharacteristics.LENS_FACING
87 constexpr int LENS_FACING_FRONT = 0;
88 constexpr int LENS_FACING_BACK = 1;
89 constexpr int LENS_FACING_EXTERNAL = 2;
90
91 switch (facing) {
92 case LENS_FACING_EXTERNAL:
93 info->position = QCameraDevice::Position::UnspecifiedPosition;
94 info->description = QStringLiteral(u"External Camera: %1").arg(cameraIndex);
95 break;
96 case LENS_FACING_BACK:
97 info->position = QCameraDevice::Position::BackFace;
98 info->description = QStringLiteral(u"Rear Camera: %1").arg(cameraIndex);
99 break;
100 case LENS_FACING_FRONT:
101 info->position = QCameraDevice::Position::FrontFace;
102 info->description = QStringLiteral(u"Front Camera: %1").arg(cameraIndex);
103 break;
104 default:
105 info->position = QCameraDevice::Position::UnspecifiedPosition;
106 info->description = QStringLiteral(u"Camera: %1").arg(cameraIndex);
107 break;
108 }
109 ++cameraIndex;
110
111 const auto fpsRanges = deviceManager.callMethod<QStringList>("getFpsRange", cameraId);
112
113 int maxFps = 0, minFps = 0;
114 for (auto range : fpsRanges) {
115 range = range.remove(u"["_s);
116 range = range.remove(u"]"_s);
117
118 const auto split = range.split(u","_s);
119
120 int min = split.at(0).toInt();
121 int max = split.at(1).toInt();
122
123 if (max > maxFps) {
124 maxFps = max;
125 minFps = min;
126 }
127 }
128
129 const static int imageFormat =
130 QJniObject::getStaticField<QtJniTypes::ImageFormat, jint>("YUV_420_888");
131
132 const QStringList sizes = deviceManager.callMethod<QStringList>(
133 "getStreamConfigurationsSizes", cameraId, imageFormat);
134
135 if (sizes.isEmpty())
136 continue;
137
138 for (const auto &sizeString : sizes) {
139 const auto split = sizeString.split(u"x"_s);
140
141 int width = split.at(0).toInt();
142 int height = split.at(1).toInt();
143
144 info->videoFormats.append(createCameraFormat(width, height, minFps, maxFps));
145 }
146
147
148 devices.push_back(info.release()->create());
149 }
150
151 return devices;
152}
153
154// Called from main looper thread in Android
156 JNIEnv*,
157 jobject,
158 jlong nativePtr)
159{
160 auto* videoDevices = reinterpret_cast<QAndroidVideoDevices*>(static_cast<size_t>(nativePtr));
161 videoDevices->onVideoInputsChanged();
162}
163Q_DECLARE_JNI_NATIVE_METHOD(onCameraAvailableNative)
164
165// Called from main looper thread in Android
167 JNIEnv*,
168 jobject,
169 jlong nativePtr)
170{
171 auto* videoDevices = reinterpret_cast<QAndroidVideoDevices*>(static_cast<size_t>(nativePtr));
172 videoDevices->onVideoInputsChanged();
173}
174Q_DECLARE_JNI_NATIVE_METHOD(onCameraUnavailableNative)
175
176void QAndroidVideoDevices::registerNativeMethods() {
177 QJniEnvironment().registerNativeMethods(
178 QtJniTypes::Traits<QtJniTypes::QtCameraAvailabilityListener>::className(),
179 {
180 Q_JNI_NATIVE_METHOD(onCameraAvailableNative),
181 Q_JNI_NATIVE_METHOD(onCameraUnavailableNative),
182 });
183}
184
185QT_END_NAMESPACE
Q_STATIC_LOGGING_CATEGORY(lcAccessibilityCore, "qt.accessibility.core")
static void onCameraUnavailableNative(JNIEnv *, jobject, jlong nativePtr)
static void onCameraAvailableNative(JNIEnv *, jobject, jlong nativePtr)
QCameraFormat createCameraFormat(int width, int height, int fpsMin, int fpsMax)
Q_DECLARE_JNI_CLASS(MotionEvent, "android/view/MotionEvent")