-
-
Notifications
You must be signed in to change notification settings - Fork 10.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
On-device OpenGL video filters #5455
Conversation
a1da0d6
to
bdb2e32
Compare
I've made some progress this week-end:
Please review/test! In particular, make sure that everything works with any crop, locked video orientation, physical device rotation, resize… on devices with and without Android 14. Check that:
In a virtual display ( TODOI wanted to add support for I will:
|
I submitted a new version where everything works (hopefully). I edited the original post and provided a binary for Windows. Feedback welcome (please report any issue). |
Reproducible 100%? Could you retry after reverting 239553f please? EDIT: ok, I reproduce, there was a bug in this commit (it resized to |
I updated the PR:
I published a new binary ( |
I tested post.glfilter.55 on my Xiaomi Android 14 device and it worked fine, showing the screen correctly when rotated after the app. |
For consistency with orientation parameters, I changed |
The rotation works on Android 9 although it looked glitchy (window rotates before the "content" does) glfilter.55_A9.mp4I have also tested S10+ running Android 14 custom rom, OneUI 6.1 port. Both main display and vd is broken: glfilter.55_A14.mp4glfilter.55_A14_vd.mp4 |
@4nric Thank you for your tests! Could you please re-test with I built a binary:
The problem with the virtual display is different: the display listener is broken between Android 14_r1 and Android 14_r29. see e26bdb0. For normal screen capture, I use a fallback by listening to device rotation changes, but for vd I have no solution. |
Oh, actually, we could also use a fallback, but the rotation watcher may not be registered immediately, just after a few milliseconds: diff --git server/src/main/java/com/genymobile/scrcpy/video/NewDisplayCapture.java server/src/main/java/com/genymobile/scrcpy/video/NewDisplayCapture.java
index 412eb8501..1a87a35ca 100644
--- server/src/main/java/com/genymobile/scrcpy/video/NewDisplayCapture.java
+++ server/src/main/java/com/genymobile/scrcpy/video/NewDisplayCapture.java
@@ -20,6 +20,8 @@ import android.hardware.display.VirtualDisplay;
import android.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
+import android.os.SystemClock;
+import android.view.IRotationWatcher;
import android.view.Surface;
import java.io.IOException;
@@ -191,6 +193,15 @@ public class NewDisplayCapture extends DisplayCapture {
}
}, handler);
+ SystemClock.sleep(100); // hack: if we register immediately, the display id is not known by the system
+ IRotationWatcher rotationWatcher = new IRotationWatcher.Stub() {
+ @Override
+ public void onRotationChanged(int rotation) {
+ Ln.i("NewDisplayCapture: onRotationChanged(" + rotation + ")");
+ invalidate();
+ }
+ };
+ ServiceManager.getWindowManager().registerRotationWatcher(rotationWatcher, virtualDisplayId);
} catch (Exception e) {
Ln.e("Could not create display", e);
throw new AssertionError("Could not create display"); |
@rom1v glad to test things 😊with |
How does it behave with scrcpy 2.7? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very nice work! :)
Do you have a measure of the performance impact of the OpenGL runner, memory/GPU-wise and especially on mirroring latency? Is it negligible compared to v2.7?
server/src/main/java/com/genymobile/scrcpy/device/Orientation.java
Outdated
Show resolved
Hide resolved
server/src/main/java/com/genymobile/scrcpy/opengl/AffineOpenGLFilter.java
Outdated
Show resolved
Hide resolved
server/src/main/java/com/genymobile/scrcpy/util/AffineMatrix.java
Outdated
Show resolved
Hide resolved
server/src/main/java/com/genymobile/scrcpy/video/NewDisplayCapture.java
Outdated
Show resolved
Hide resolved
server/src/main/java/com/genymobile/scrcpy/video/VideoFilter.java
Outdated
Show resolved
Hide resolved
server/src/main/java/com/genymobile/scrcpy/opengl/OpenGLFilter.java
Outdated
Show resolved
Hide resolved
server/src/main/java/com/genymobile/scrcpy/opengl/OpenGLFilter.java
Outdated
Show resolved
Hide resolved
Introduce several key components to perform OpenGL filters: - OpenGLRunner: a tool for running a filter to be rendered to a Surface from an OpenGL-dedicated thread - OpenGLFilter: a simple OpenGL filter API - AffineOpenGLFilter: a generic OpenGL implementation to apply any 2D affine transform - AffineMatrix: an affine transform matrix, with helpers to build matrices from semantic transformations (rotate, scale, translate…) PR #5455 <#5455>
Detecting display size changes is not straightforward: - from a DisplayListener, "display changed" events are received, but this does not imply that the size has changed (it must be checked); - on Android 14 (see e26bdb0), "display changed" events are not received on some versions, so as a fallback, a RotationWatcher and a DisplayFoldListener are registered, but unregistered as soon as a "display changed" event is actually received, which means that the problem is fixed. Extract a "display size monitor" to share the code between screen capture and virtual display capture. PR #5455 <#5455>
On Android 14, DisplayListener may be broken (it never sends events). This is fixed in recent Android 14 upgrades, but we can't really detect it directly. As a workaround, a RotationWatcher and DisplayFoldListener were registered as a fallback, until a first "display changed" event was triggered. To simplify, on Android 14, register a DisplayWindowListener (introduced in Android 11) to listen to configuration changes instead. Refs #5455 comment <#5455 (comment)> PR #5455 <#5455> Co-authored-by: Romain Vimont <rom@rom1v.com> Signed-off-by: Romain Vimont <rom@rom1v.com>
Deprecate --lock-video-orientation in favor of a more general option --capture-orientation, which supports all possible orientations (0, 90, 180, 270, flip0, flip90, flip180, flip270), and a "locked" flag via a '@' prefix. All the old "locked video orientations" are supported: - --lock-video-orientation -> --capture-orientation=@ - --lock-video-orientation=0 -> --capture-orientation=@0 - --lock-video-orientation=90 -> --capture-orientation=@90 - --lock-video-orientation=180 -> --capture-orientation=@180 - --lock-video-orientation=270 -> --capture-orientation=@270 In addition, --capture-orientation can rotate/flip the display without locking, so that it follows the physical device rotation. For example: scrcpy --capture-orientation=flip90 always flips and rotates the capture by 90° clockwise. The arguments are consistent with --display-orientation and --record-orientation and --orientation (which provide separate client-side orientation settings). Refs #4011 <#4011> PR #5455 <#5455>
On rotation, it is expected that many successive events are ignored due to size mismatch, when an event was generated from the mirroring window having the old size, but was received on the device with the new size (especially since mouse hover events are forwarded). Do not flood the console with warnings. PR #5455 <#5455>
I did not measure. In practice, I haven't noticed an additional latency. I'm pretty sure the internal implementation of (And if no transform is needed, OpenGL is not used, the capture is directly encoded as before.) |
I changed the behavior of |
Test version for "On-device OpenGL video filter prototype" Bug: Genymobile/scrcpy#5455
This PR implements on-device OpenGL video filters and fixes all the following issues:
--lock-video-orientation
broken on Android >= 14--crop
broken on Android >= 14Architecture
It first adds an architecture and tools to execute OpenGL filters:
OpenGLRunner
), which will run a filter to be rendered to aSurface
from an OpenGL-dedicated threadOpenGLFilter
)AffineOpenGLFilter
)AffineMatrix
)Crop
To fix #4162, the
--crop
option is reimplemented using filters on all devices. For screen mirroring, the command is the same, the change is transparent for users.But now, the specified crop also works for camera and virtual display mirroring (it worked only for screen mirroring before this PR).
Note: for sampling the input camera texture, I had to ignore the
SurfaceTexture
transform matrix (which is incorrect, it contains an additional 90° rotation which must not be used to sample the texture), and replace it by a vflip. See commitApply filters to camera capture
(and CameraCapture).Orientation
Before the change,
--lock-video-orientation
performed 2 actions:This option was broken for devices with Android >= 14.
To fix #4011, now that we can apply our own filters,
--lock-video-orientation
is deprecated in favor of a more general option--capture-orientation
, which supports all possible orientations (0, 90, 180, 270, flip0, flip90, flip180, flip270).To capture the video with a specific orientation:
This makes it consistent with client-side orientation (`--orientation).
The capture orientation can be locked by using a
@
prefix, so that a physical devicerotation does not change the captured video orientation:
The capture orientation now also works for camera and virtual display mirroring (
--lock-video-orientation
only worked for screen mirroring), so it also works #4426.Virtual display
#5370 implemented a virtual display feature, but the capture could not be rotated to follow the app rotation (#5428).
OpenGL filters are used to support virtual display rotation.
Rotation by a custom angle
A new option
--angle
rotates the video content by a custom angle in degrees (counter-clockwise).The center of rotation is the center of the visible area (after cropping).
This allows to capture the Meta Quest 3 with the correct angle (#4135, #4345, #4658).
EDIT: I just realized that I forgot to implement it for camera and virtual display. I'll do it later.
Testing
There are many combinations to tests:
Your help is welcome to report any problem.
Event positions
All mouse/touch events are mapped back to the device position, using the same (inverse) affine transform.
Scrcpy must work as expected with any combination: whatever the transform, clicking on the screen must click at the correct location on the device (you can enable "Pointer location" in developer options).
For example, if you enable "Pointer location" in developer options, then run:
the click must be performed just under the cursor
Consistency
Some specific values of
--capture-orientation
directly match the old--lock-video-orientation
feature:Running scrcpy v2.7 with the same
--crop
and a matching--lock-orientation-value
must give the same result.Also, the behavior between screen mirroring and virtual display must be consistent.
Special thanks to @yume-chan for unblocking me in #5444. 😉
old
Here is a binary of the current version:scrcpy-win64-glfilter.67.zip
SHA-256: 88c0cdd94152d1dcf06cc76e3e589db9c5ce04bee9d4f16fac21e5ead331643
Thank you for your feedback.