30class QAndroidScreenCapture::Grabber :
public QtAndroidPrivate::ActivityResultListener,
31 public QFFmpegSurfaceCaptureGrabber
34 Grabber(QAndroidScreenCapture & screenCapture)
35 : m_activityRequestCode(REQUEST_CODE_MEDIA_PROJECTION + idCounter.fetchAndAddRelaxed(1))
36 , m_screenCapture(screenCapture)
38 injectContextToGrabbingThread(&m_resourceContext);
40 addFrameCallback(&screenCapture, &QAndroidScreenCapture::newVideoFrame);
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);
49 if (m_format.frameHeight() > 0 && m_format.frameWidth() > 0) {
50 QtAndroidPrivate::registerActivityResultListener(
this);
51 m_jniGrabber = QtScreenGrabber(QtAndroidPrivate::activity(), m_activityRequestCode);
53 updateError(QStringLiteral(
"Invalid Screen size: %1x%2. Screen capture not started")
54 .arg(m_format.frameHeight())
55 .arg(m_format.frameWidth()));
58 setFrameRate(screenCapture.frameRate().value_or(DefaultScreenCaptureFrameRate));
59 m_format.setStreamFrameRate(frameRate());
62 QVideoFrame grabFrame() override
64 return m_resourceContext.latestFrame();
67 bool handleActivityResult(jint requestCode, jint resultCode, jobject data) override
69 if (requestCode != m_activityRequestCode || m_jniGrabber ==
nullptr)
72 if (resultCode == RESULT_OK) {
73 const QtJniTypes::Intent intent(data);
74 const bool screenCaptureServiceStarted = m_jniGrabber.callMethod<
bool>(
75 "startScreenCaptureService",
77 reinterpret_cast<jlong>(&m_screenCapture),
78 m_format.frameWidth(),
79 m_format.frameHeight(),
81 if (!screenCaptureServiceStarted)
82 updateError(QStringLiteral(
"Cannot start screen capture service"));
83 }
else if (resultCode == RESULT_CANCEL) {
84 updateError(QStringLiteral(
"Screen capture canceled"));
92 QtAndroidPrivate::unregisterActivityResultListener(
this);
93 m_jniGrabber.callMethod<
bool>(
"stopScreenCaptureService");
96 QVideoFrameFormat format()
const {
return m_format; }
98 void onNewFrameReceived(QtJniTypes::Image image)
100 QMetaObject::invokeMethod(&m_resourceContext, &ResourceContext::updateLatestImageRef,
105 void updateError(
const QString &errorString)
107 QMetaObject::invokeMethod(&m_screenCapture,
108 &QPlatformSurfaceCapture::updateError,
109 Qt::QueuedConnection,
110 QPlatformSurfaceCapture::Error::InternalError,
114 QtJniTypes::QtScreenGrabber m_jniGrabber;
115 const int m_activityRequestCode;
116 QAndroidScreenCapture & m_screenCapture;
117 QVideoFrameFormat m_format;
119 class ResourceContext :
public QObject
122 ResourceContext() : m_frameFactory(QAndroidVideoFrameFactory::create()) { }
123 ~ResourceContext() override { updateLatestImageRef({ }); }
124 Q_DISABLE_COPY_MOVE(ResourceContext)
126 void updateLatestImageRef(QJniObject newImage)
128 auto oldImage = std::exchange(m_latestImage, newImage);
129 if (oldImage.isValid())
130 oldImage.callMethod<
void>(
"close");
133 QVideoFrame latestFrame()
135 Q_ASSERT(m_frameFactory);
136 return m_latestImage.isValid()
137 ? m_frameFactory->createVideoFrame(std::move(m_latestImage))
142 QJniObject m_latestImage;
143 std::shared_ptr<QAndroidVideoFrameFactory> m_frameFactory;
193static void onErrorUpdate(JNIEnv *env, jobject obj, QString errorString, jlong id)
197 auto cppObj =
reinterpret_cast<QAndroidScreenCapture*>(id);
198 QMetaObject::invokeMethod(cppObj,
199 &QPlatformSurfaceCapture::updateError,
200 Qt::QueuedConnection,
201 QPlatformSurfaceCapture::Error::InternalError,
207bool QAndroidScreenCapture::registerNativeMethods()
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)});