Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
androidmediarecorder.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
5#include "androidcamera_p.h"
8#include "qandroidglobal_p.h"
10
11#include <qmap.h>
12#include <QtCore/qcoreapplication.h>
13#include <QtCore/qlogging.h>
14#include <QtCore/qurl.h>
15
17
18static Q_LOGGING_CATEGORY(lcMediaRecorder, "qt.multimedia.mediarecorder.android")
19
21Q_GLOBAL_STATIC(CamcorderProfiles, g_camcorderProfiles)
22
24{
25 return QStringLiteral("%1-%2");
26}
27
28bool AndroidCamcorderProfile::hasProfile(jint cameraId, Quality quality)
29{
30 if (g_camcorderProfiles->contains(profileKey().arg(cameraId).arg(quality)))
31 return true;
32
33 return QJniObject::callStaticMethod<jboolean>("android/media/CamcorderProfile",
34 "hasProfile",
35 "(II)Z",
36 cameraId,
37 quality);
38}
39
41{
42 const QString key = profileKey().arg(cameraId).arg(quality);
44
45 if (it != g_camcorderProfiles->constEnd())
47
48 QJniObject camProfile = QJniObject::callStaticObjectMethod("android/media/CamcorderProfile",
49 "get",
50 "(II)Landroid/media/CamcorderProfile;",
51 cameraId,
52 quality);
53
54 return AndroidCamcorderProfile((*g_camcorderProfiles)[key] = camProfile);
55}
56
58{
59 switch (field) {
60 case audioBitRate:
61 return m_camcorderProfile.getField<jint>("audioBitRate");
62 case audioChannels:
63 return m_camcorderProfile.getField<jint>("audioChannels");
64 case audioCodec:
65 return m_camcorderProfile.getField<jint>("audioCodec");
66 case audioSampleRate:
67 return m_camcorderProfile.getField<jint>("audioSampleRate");
68 case duration:
69 return m_camcorderProfile.getField<jint>("duration");
70 case fileFormat:
71 return m_camcorderProfile.getField<jint>("fileFormat");
72 case quality:
73 return m_camcorderProfile.getField<jint>("quality");
74 case videoBitRate:
75 return m_camcorderProfile.getField<jint>("videoBitRate");
76 case videoCodec:
77 return m_camcorderProfile.getField<jint>("videoCodec");
79 return m_camcorderProfile.getField<jint>("videoFrameHeight");
80 case videoFrameRate:
81 return m_camcorderProfile.getField<jint>("videoFrameRate");
82 case videoFrameWidth:
83 return m_camcorderProfile.getField<jint>("videoFrameWidth");
84 }
85
86 return 0;
87}
88
89AndroidCamcorderProfile::AndroidCamcorderProfile(const QJniObject &camcorderProfile)
90{
91 m_camcorderProfile = camcorderProfile;
92}
93
95 "org/qtproject/qt/android/multimedia/QtMediaRecorderListener";
96typedef QMap<jlong, AndroidMediaRecorder*> MediaRecorderMap;
97Q_GLOBAL_STATIC(MediaRecorderMap, mediaRecorders)
98
99static void notifyError(JNIEnv* , jobject, jlong id, jint what, jint extra)
100{
101 AndroidMediaRecorder *obj = mediaRecorders->value(id, 0);
102 if (obj)
103 emit obj->error(what, extra);
104}
105
106static void notifyInfo(JNIEnv* , jobject, jlong id, jint what, jint extra)
107{
108 AndroidMediaRecorder *obj = mediaRecorders->value(id, 0);
109 if (obj)
110 emit obj->info(what, extra);
111}
112
114 : QObject()
115 , m_id(reinterpret_cast<jlong>(this))
116{
117 m_mediaRecorder = QJniObject("android/media/MediaRecorder");
118 if (m_mediaRecorder.isValid()) {
119 QJniObject listener(QtMediaRecorderListenerClassName, "(J)V", m_id);
120 m_mediaRecorder.callMethod<void>("setOnErrorListener",
121 "(Landroid/media/MediaRecorder$OnErrorListener;)V",
122 listener.object());
123 m_mediaRecorder.callMethod<void>("setOnInfoListener",
124 "(Landroid/media/MediaRecorder$OnInfoListener;)V",
125 listener.object());
126 mediaRecorders->insert(m_id, this);
127 }
128}
129
131{
132 if (m_isVideoSourceSet || m_isAudioSourceSet)
133 reset();
134
135 release();
136 mediaRecorders->remove(m_id);
137}
138
140{
141 m_mediaRecorder.callMethod<void>("release");
142}
143
145{
146 QJniEnvironment env;
147 auto methodId = env->GetMethodID(m_mediaRecorder.objectClass(), "prepare", "()V");
148 env->CallVoidMethod(m_mediaRecorder.object(), methodId);
149
150 if (env.checkAndClearExceptions())
151 return false;
152 return true;
153}
154
156{
157 m_mediaRecorder.callMethod<void>("reset");
158 m_isAudioSourceSet = false; // Now setAudioSource can be used again.
159 m_isVideoSourceSet = false;
160}
161
163{
164 QJniEnvironment env;
165 auto methodId = env->GetMethodID(m_mediaRecorder.objectClass(), "start", "()V");
166 env->CallVoidMethod(m_mediaRecorder.object(), methodId);
167
168 if (env.checkAndClearExceptions())
169 return false;
170 return true;
171}
172
174{
175 m_mediaRecorder.callMethod<void>("stop");
176}
177
179{
180 m_mediaRecorder.callMethod<void>("setAudioChannels", "(I)V", numChannels);
181}
182
184{
185 QJniEnvironment env;
186 m_mediaRecorder.callMethod<void>("setAudioEncoder", "(I)V", int(encoder));
187}
188
190{
191 m_mediaRecorder.callMethod<void>("setAudioEncodingBitRate", "(I)V", bitRate);
192}
193
195{
196 m_mediaRecorder.callMethod<void>("setAudioSamplingRate", "(I)V", samplingRate);
197}
198
200{
201 if (!m_isAudioSourceSet) {
202 QJniEnvironment env;
203 auto methodId = env->GetMethodID(m_mediaRecorder.objectClass(), "setAudioSource", "(I)V");
204 env->CallVoidMethod(m_mediaRecorder.object(), methodId, source);
205 if (!env.checkAndClearExceptions())
206 m_isAudioSourceSet = true;
207 } else {
208 qCWarning(lcMediaRecorder) << "Audio source already set. Not setting a new source.";
209 }
210}
211
213{
214 return m_isAudioSourceSet;
215}
216
218{
219 const bool ret = QJniObject::callStaticMethod<jboolean>(
220 "org/qtproject/qt/android/multimedia/QtAudioDeviceManager",
221 "setAudioInput",
222 "(Landroid/media/MediaRecorder;I)Z",
223 m_mediaRecorder.object(),
224 id.toInt());
225 if (!ret)
226 qCWarning(lcMediaRecorder) << "No default input device was set.";
227
228 return ret;
229}
230
232{
233 QJniObject cam = camera->getCameraObject();
234 m_mediaRecorder.callMethod<void>("setCamera", "(Landroid/hardware/Camera;)V", cam.object());
235}
236
238{
239 m_mediaRecorder.callMethod<void>("setVideoEncoder", "(I)V", int(encoder));
240}
241
243{
244 m_mediaRecorder.callMethod<void>("setVideoEncodingBitRate", "(I)V", bitRate);
245}
246
248{
249 m_mediaRecorder.callMethod<void>("setVideoFrameRate", "(I)V", rate);
250}
251
253{
254 m_mediaRecorder.callMethod<void>("setVideoSize", "(II)V", size.width(), size.height());
255}
256
258{
259 QJniEnvironment env;
260
261 auto methodId = env->GetMethodID(m_mediaRecorder.objectClass(), "setVideoSource", "(I)V");
262 env->CallVoidMethod(m_mediaRecorder.object(), methodId, source);
263
264 if (!env.checkAndClearExceptions())
265 m_isVideoSourceSet = true;
266}
267
269{
270 m_mediaRecorder.callMethod<void>("setOrientationHint", "(I)V", degrees);
271}
272
274{
275 QJniEnvironment env;
276 auto methodId = env->GetMethodID(m_mediaRecorder.objectClass(), "setOutputFormat", "(I)V");
277 env->CallVoidMethod(m_mediaRecorder.object(), methodId, format);
278 // setAudioSource cannot be set after outputFormat is set.
279 if (!env.checkAndClearExceptions())
280 m_isAudioSourceSet = true;
281}
282
284{
285 if (QUrl(path).scheme() == QLatin1String("content")) {
286 const QJniObject fileDescriptor = QJniObject::callStaticObjectMethod(
287 "org/qtproject/qt/android/QtNative",
288 "openFdObjectForContentUrl",
289 "(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;)Ljava/io/FileDescriptor;",
290 QNativeInterface::QAndroidApplication::context().object(),
291 QJniObject::fromString(path).object(),
292 QJniObject::fromString(QLatin1String("rw")).object());
293
294 m_mediaRecorder.callMethod<void>("setOutputFile",
295 "(Ljava/io/FileDescriptor;)V",
296 fileDescriptor.object());
297 } else {
298 m_mediaRecorder.callMethod<void>("setOutputFile",
299 "(Ljava/lang/String;)V",
300 QJniObject::fromString(path).object());
301 }
302}
303
305{
306 m_mediaRecorder.callMethod<void>("setPreviewDisplay",
307 "(Landroid/view/Surface;)V",
308 texture->surface());
309}
310
312{
313 QJniObject surfaceHolder(holder->surfaceHolder());
314 QJniObject surface = surfaceHolder.callObjectMethod("getSurface",
315 "()Landroid/view/Surface;");
316 if (!surface.isValid())
317 return;
318
319 m_mediaRecorder.callMethod<void>("setPreviewDisplay",
320 "(Landroid/view/Surface;)V",
321 surface.object());
322}
323
325{
326 static const JNINativeMethod methods[] = {
327 {"notifyError", "(JII)V", (void *)notifyError},
328 {"notifyInfo", "(JII)V", (void *)notifyInfo}
329 };
330
331 const int size = std::size(methods);
332 return QJniEnvironment().registerNativeMethods(QtMediaRecorderListenerClassName, methods, size);
333}
334
336
337#include "moc_androidmediarecorder_p.cpp"
static JNINativeMethod methods[]
static QT_BEGIN_NAMESPACE QJniObject CamcorderProfiles
QMap< jlong, AndroidMediaRecorder * > MediaRecorderMap
static void notifyError(JNIEnv *, jobject, jlong id, jint what, jint extra)
static void notifyInfo(JNIEnv *, jobject, jlong id, jint what, jint extra)
static const char QtMediaRecorderListenerClassName[]
static QString profileKey()
int getValue(Field field) const
static bool hasProfile(jint cameraId, Quality quality)
static AndroidCamcorderProfile get(jint cameraId, Quality quality)
bool setAudioInput(const QByteArray &id)
void setCamera(AndroidCamera *camera)
void setAudioEncodingBitRate(int bitRate)
void setVideoEncoder(VideoEncoder encoder)
void setAudioChannels(int numChannels)
void setOutputFormat(OutputFormat format)
void setOrientationHint(int degrees)
void setAudioSamplingRate(int samplingRate)
void setAudioEncoder(AudioEncoder encoder)
void setVideoEncodingBitRate(int bitRate)
void setOutputFile(const QString &path)
void setVideoSize(const QSize &size)
void setVideoSource(VideoSource source)
void setSurfaceTexture(AndroidSurfaceTexture *texture)
void setSurfaceHolder(AndroidSurfaceHolder *holder)
void setAudioSource(AudioSource source)
jobject surfaceHolder() const
\inmodule QtCore
Definition qbytearray.h:57
\inmodule QtCore
\inmodule QtCore
Definition qmap.h:187
\inmodule QtCore
Definition qobject.h:103
const_iterator constEnd() const noexcept
Definition qset.h:143
const_iterator constFind(const T &value) const
Definition qset.h:161
\inmodule QtCore
Definition qsize.h:25
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
\inmodule QtCore
Definition qurl.h:94
#define this
Definition dialogs.cpp:9
QCamera * camera
Definition camera.cpp:19
QSet< QString >::iterator it
Combined button and popup list for selecting options.
#define Q_GLOBAL_STATIC(TYPE, NAME,...)
#define Q_LOGGING_CATEGORY(name,...)
#define qCWarning(category,...)
return ret
GLuint64 key
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLenum GLuint texture
GLint GLsizei GLsizei GLenum format
GLsizei GLsizei GLchar * source
GLhandleARB obj
[2]
GLuint GLenum * rate
GLsizei const GLchar *const * path
SSL_CTX int void * arg
QLatin1StringView QLatin1String
Definition qstringfwd.h:31
#define QStringLiteral(str)
#define emit