Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Toggle main menu visibility
Loading...
Searching...
No Matches
qandroidscreencapture.cpp
Go to the documentation of this file.
1
// Copyright (C) 2024 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
/
qandroidscreencapture_p
.
h
>
5
6
#
include
<
QtCore
/
private
/
qjnihelpers_p
.
h
>
7
#
include
<
QtCore
/
qreadwritelock
.
h
>
8
#
include
<
QtMultimedia
/
private
/
qsurfacecapturegrabber_p
.
h
>
9
10
#
include
<
QtFFmpegMediaPluginImpl
/
private
/
qandroidvideoframefactory_p
.
h
>
11
#
include
<
QtFFmpegMediaPluginImpl
/
private
/
qffmpegvideobuffer_p
.
h
>
12
13
QT_BEGIN_NAMESPACE
14
15
Q_DECLARE_JNI_CLASS
(QtScreenGrabber,
16
"org/qtproject/qt/android/multimedia/qffmpeg/QtScreenGrabber"
)
17
Q_DECLARE_JNI_CLASS(QtScreenCaptureService,
18
"org/qtproject/qt/android/multimedia/qffmpeg/QtScreenCaptureService"
)
19
Q_DECLARE_JNI_CLASS(Size,
"android/util/Size"
)
20
21
22
namespace
{
23
QAtomicInteger
<
int
>
idCounter
= 0;
24
constexpr
int
REQUEST_CODE_MEDIA_PROJECTION
= 24680;
// Arbitrary
25
constexpr
int
RESULT_CANCEL
= 0;
26
constexpr
int
RESULT_OK
= -1;
27
28
}
29
30
class
QAndroidScreenCapture::Grabber :
public
QtAndroidPrivate::ActivityResultListener,
31
public
QSurfaceCaptureGrabber
32
{
33
public
:
34
Grabber(QAndroidScreenCapture & screenCapture)
35
: m_activityRequestCode(REQUEST_CODE_MEDIA_PROJECTION + idCounter.fetchAndAddRelaxed(1))
36
, m_screenCapture(screenCapture)
37
{
38
injectContextToGrabbingThread(&m_resourceContext);
39
40
addFrameCallback(&screenCapture, &QAndroidScreenCapture::newVideoFrame);
41
42
using
namespace
QtJniTypes;
43
const
auto
sizeObj = QtScreenGrabber::callStaticMethod<Size>(
44
"getScreenCaptureSize"
, QtAndroidPrivate::activity());
45
const
QSize size = QSize(sizeObj.callMethod<
int
>(
"getWidth"
),
46
sizeObj.callMethod<
int
>(
"getHeight"
));
47
m_format = QVideoFrameFormat(size, QVideoFrameFormat::Format_RGBA8888);
48
49
if
(m_format.frameHeight() > 0 && m_format.frameWidth() > 0) {
50
QtAndroidPrivate::registerActivityResultListener(
this
);
51
m_jniGrabber = QtScreenGrabber(QtAndroidPrivate::activity(), m_activityRequestCode);
52
}
else
{
53
updateError(QStringLiteral(
"Invalid Screen size: %1x%2. Screen capture not started"
)
54
.arg(m_format.frameHeight())
55
.arg(m_format.frameWidth()));
56
}
57
58
setFrameRate(screenCapture.frameRate().value_or(DefaultScreenCaptureFrameRate));
59
m_format.setStreamFrameRate(frameRate());
60
}
61
62
QVideoFrame grabFrame() override
63
{
64
return
m_resourceContext.latestFrame();
65
}
66
67
bool
handleActivityResult(jint requestCode, jint resultCode, jobject data) override
68
{
69
if
(requestCode != m_activityRequestCode || m_jniGrabber ==
nullptr
)
70
return
false
;
71
72
if
(resultCode == RESULT_OK) {
73
const
QtJniTypes::Intent intent(data);
74
const
bool
screenCaptureServiceStarted = m_jniGrabber.callMethod<
bool
>(
75
"startScreenCaptureService"
,
76
resultCode,
77
reinterpret_cast
<jlong>(&m_screenCapture),
78
m_format.frameWidth(),
79
m_format.frameHeight(),
80
intent);
81
if
(!screenCaptureServiceStarted)
82
updateError(QStringLiteral(
"Cannot start screen capture service"
));
83
}
else
if
(resultCode == RESULT_CANCEL) {
84
updateError(QStringLiteral(
"Screen capture canceled"
));
85
}
86
return
true
;
87
}
88
89
~Grabber() override
90
{
91
stop();
92
QtAndroidPrivate::unregisterActivityResultListener(
this
);
93
m_jniGrabber.callMethod<
bool
>(
"stopScreenCaptureService"
);
94
}
95
96
QVideoFrameFormat format()
const
{
return
m_format; }
97
98
void
onNewFrameReceived(QtJniTypes::Image image)
99
{
100
QMetaObject::invokeMethod(&m_resourceContext, &ResourceContext::updateLatestImageRef,
101
image);
102
}
103
104
private
:
105
void
updateError(
const
QString &errorString)
106
{
107
QMetaObject::invokeMethod(&m_screenCapture,
108
&QPlatformSurfaceCapture::updateError,
109
Qt::QueuedConnection,
110
QPlatformSurfaceCapture::Error::InternalError,
111
errorString);
112
}
113
114
QtJniTypes::QtScreenGrabber m_jniGrabber;
115
const
int
m_activityRequestCode;
116
QAndroidScreenCapture & m_screenCapture;
117
QVideoFrameFormat m_format;
118
119
class
ResourceContext :
public
QObject
120
{
121
public
:
122
ResourceContext() : m_frameFactory(QAndroidVideoFrameFactory::create()) { }
123
~ResourceContext() override { updateLatestImageRef({ }); }
124
Q_DISABLE_COPY_MOVE(ResourceContext)
125
126
void
updateLatestImageRef(QJniObject newImage)
127
{
128
auto
oldImage = std::exchange(m_latestImage, newImage);
129
if
(oldImage.isValid())
130
oldImage.callMethod<
void
>(
"close"
);
131
}
132
133
QVideoFrame latestFrame()
134
{
135
Q_ASSERT(m_frameFactory);
136
return
m_latestImage.isValid()
137
? m_frameFactory->createVideoFrame(std::move(m_latestImage))
138
: QVideoFrame();
139
}
140
141
private
:
142
QJniObject m_latestImage;
143
std::shared_ptr<QAndroidVideoFrameFactory> m_frameFactory;
144
} m_resourceContext;
145
};
146
147
QAndroidScreenCapture::QAndroidScreenCapture()
148
: QPlatformSurfaceCapture(ScreenSource{})
149
{
150
}
151
152
QAndroidScreenCapture::~QAndroidScreenCapture()
153
{
154
}
155
156
QVideoFrameFormat QAndroidScreenCapture::frameFormat()
const
157
{
158
return
m_grabber ? m_grabber->format() : QVideoFrameFormat();
159
}
160
161
bool
QAndroidScreenCapture::setActiveInternal(
bool
active)
162
{
163
if
(active ==
static_cast
<
bool
>(m_grabber))
164
return
true
;
165
166
if
(m_grabber) {
167
m_grabber.reset();
168
}
else
{
169
m_grabber = std::make_unique<Grabber>(*
this
);
170
m_grabber->start();
171
}
172
173
return
bool
(m_grabber) == active;
174
}
175
176
void
QAndroidScreenCapture::onNewFrameReceived(QtJniTypes::Image image)
177
{
178
if
(m_grabber)
179
m_grabber->onNewFrameReceived(image);
180
else
if
(image.isValid())
181
image.callMethod<
void
>(
"close"
);
182
}
183
184
static
void
onScreenFrameAvailable
(JNIEnv *env, jobject obj, QtJniTypes::Image image, jlong id)
185
{
186
Q_UNUSED(env);
187
Q_UNUSED(obj);
188
auto
*cppObj =
reinterpret_cast
<QAndroidScreenCapture*>(id);
189
cppObj->onNewFrameReceived(image);
190
}
191
Q_DECLARE_JNI_NATIVE_METHOD(onScreenFrameAvailable)
192
193
static
void
onErrorUpdate
(JNIEnv *env, jobject obj, QString errorString, jlong id)
194
{
195
Q_UNUSED(env);
196
Q_UNUSED(obj);
197
auto
cppObj =
reinterpret_cast
<QAndroidScreenCapture*>(id);
198
QMetaObject::invokeMethod(cppObj,
199
&QPlatformSurfaceCapture::updateError,
200
Qt::QueuedConnection,
201
QPlatformSurfaceCapture::Error::InternalError,
202
errorString);
203
}
204
Q_DECLARE_JNI_NATIVE_METHOD(onErrorUpdate)
205
206
207
bool
QAndroidScreenCapture::registerNativeMethods()
208
{
209
using
namespace
QtJniTypes;
210
static
const
bool
registered = []() {
211
return
QtScreenCaptureService::registerNativeMethods(
212
{ Q_JNI_NATIVE_METHOD(onScreenFrameAvailable),
213
Q_JNI_NATIVE_METHOD(onErrorUpdate)});
214
}();
215
return
registered;
216
}
217
218
QT_END_NAMESPACE
QtScreenCaptureService::RESULT_CANCEL
constexpr int RESULT_CANCEL
Definition
qandroidscreencapture.cpp:25
QtScreenCaptureService::REQUEST_CODE_MEDIA_PROJECTION
constexpr int REQUEST_CODE_MEDIA_PROJECTION
Definition
qandroidscreencapture.cpp:24
QtScreenCaptureService::idCounter
QAtomicInteger< int > idCounter
Definition
qandroidscreencapture.cpp:23
QtScreenCaptureService::RESULT_OK
constexpr int RESULT_OK
Definition
qandroidscreencapture.cpp:26
onScreenFrameAvailable
static void onScreenFrameAvailable(JNIEnv *env, jobject obj, QtJniTypes::Image image, jlong id)
Definition
qandroidscreencapture.cpp:184
onErrorUpdate
static void onErrorUpdate(JNIEnv *env, jobject obj, QString errorString, jlong id)
Definition
qandroidscreencapture.cpp:193
Q_DECLARE_JNI_CLASS
Q_DECLARE_JNI_CLASS(MotionEvent, "android/view/MotionEvent")
qtmultimedia
src
plugins
multimedia
ffmpeg
android
qandroidscreencapture.cpp
Generated on
for Qt by
1.18.0