Skip to content
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

Android 14 beta lock orientation doesn't work as expected when the device goes into landscape mode. #4011

Open
2 tasks done
ssalenik opened this issue May 18, 2023 · 14 comments

Comments

@ssalenik
Copy link

  • I have read the FAQ.
  • I have searched in existing issues.

Environment

  • OS: macOS
  • scrcpy version: 2.0
  • installation method: brew
  • device model: Pixel 7,
  • Android version: Android 14 Beta (UpsideDownCake)

Describe the bug
Android 14 beta lock orientation doesn't work as expected when the device goes into landscape mode.
eg: if you launch: scrcpy --lock-video-orientation=0 then go into landscape in an app, you get this:
image

Looks like it no longer rotates the display output to fit the surface of the codec, but instead it keeps it in its orientation and scales it. Not clear if its a "bug" which will be fixed in the release, but seems possibly unlikely since its already in beta.

@vikingden8
Copy link

me too, I think this is a problem on new Android 14

@ssalenik
Copy link
Author

ssalenik commented Oct 5, 2023

OK, so now that the 14 source is released, I think the issue is due to this change in the SurfaceControl.setDisplayProjection fn:
Android 13: https://android.googlesource.com/platform/frameworks/base.git/+/refs/heads/android13-dev/core/java/android/view/SurfaceControl.java#2355

Android 14: https://android.googlesource.com/platform/frameworks/base.git/+/refs/tags/android-14.0.0_r2/core/java/android/view/SurfaceControl.java#2331

This fn now ignores the orientation param:

/**
--
  | * Because this API is now going through {@link DisplayManager}, orientation and displayRect
  | * will automatically be computed based on configuration changes. Because of this, the params
  | * orientation and displayRect are ignored
  | *
  | * @hide
  | */
  ```


@rom1v
Copy link
Collaborator

rom1v commented Oct 5, 2023

@ssalenik Thank you 👍

Reported here.

@ssalenik
Copy link
Author

ssalenik commented Oct 5, 2023

Thanks. I think it may be possible to find a work around by re-implementing this public static VirtualDisplay createVirtualDisplay fn here:
https://android.googlesource.com/platform/frameworks/base.git/+/refs/tags/android-14.0.0_r2/core/java/android/hardware/display/DisplayManager.java#1567

which is what is called by SurfaceControl.createDisplay fn here:
https://android.googlesource.com/platform/frameworks/base.git/+/refs/tags/android-14.0.0_r2/core/java/android/view/SurfaceControl.java#2385

And possibly adding this hidden display flag VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT: https://android.googlesource.com/platform/frameworks/base.git/+/refs/tags/android-14.0.0_r2/core/java/android/hardware/display/DisplayManager.java#372

To the VirtualDisplayConfig here:
https://android.googlesource.com/platform/frameworks/base.git/+/refs/tags/android-14.0.0_r2/core/java/android/hardware/display/DisplayManager.java#1577

I've used this hidden flag before with the MediaProjection api to accomplish the same thing.

@ssalenik
Copy link
Author

ssalenik commented Oct 7, 2023

FYI, I tried doing what I suggested above, but it didn't work.
I was able to re-implement the public static VirtualDisplay createVirtualDisplay fn in DisplayManager and add passing the VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT flag to the VirtualDisplayConfig, but it did not change the behaviour.

@ssalenik
Copy link
Author

@rom1v fyi, in my own code I was able to create a work around for this by manually rotating the surface myself.
This requires to create a 2nd "intermediate" surface which the display writes to, then using opengl code to rotate it before outputting to the encoder surface.
I used this fairly old but still working google grafika library to help me do it so I didn't really have to write any opengl code., specifically the Sprite2d to do the rotation:
https://github.com/google/grafika/blob/master/app/src/main/java/com/android/grafika/gles/Sprite2d.java

@rom1v
Copy link
Collaborator

rom1v commented Feb 28, 2024

This requires to create a 2nd "intermediate" surface which the display writes to, then using opengl code to rotate it before outputting to the encoder surface.

@ssalenik Do you have a public branch which does this?

@ssalenik
Copy link
Author

No, unfortunately that code is not open source. But I'll see if maybe I can make a patch, or at least write out the concept better with the scrcpy code.

@rom1v
Copy link
Collaborator

rom1v commented Apr 2, 2024

But I'll see if maybe I can make a patch, or at least write out the concept better with the scrcpy code.

@ssalenik Indeed, a base branch in the scrcpy codebase would help a lot 😉 Setting a surface from a SurfaceTexture to capture the display, executing a simple hardcoded shader (using a simple swizzle to just swap the color channels for example) and encoding the result to produce the video stream would be absolutely perfect (without additional libraries) 😎

Otherwise, I'll probably investigate in the future (at first glance, this sample should help).

@eiyooooo
Copy link
Contributor

eiyooooo commented Apr 7, 2024

It seems that the "virtualDisplay" created by this method (introduced in Android 14)

virtualDisplay = ServiceManager.getDisplayManager()
.createVirtualDisplay("scrcpy", videoRect.width(), videoRect.height(), device.getDisplayId(), surface);

can rotate by

public void freezeRotation(int displayId, int rotation) {
try {
try {
Method method = getFreezeDisplayRotationMethod();
method.invoke(manager, displayId, rotation);
} catch (ReflectiveOperationException e) {
if (displayId == 0) {
Method method = getFreezeRotationMethod();
method.invoke(manager, rotation);
} else {
Ln.e("Could not invoke method", e);
}
}
} catch (ReflectiveOperationException e) {
Ln.e("Could not invoke method", e);
}
}

I don't have any device running Android 14, so it's hard for me to test.

You can try to rotate the "virtualDisplay" for this issue, it might be a solution.

Not this issue, seeing #4840

@gassion
Copy link

gassion commented Apr 16, 2024

I have also encountered this problem, is there any good solution to solve it now? Thank you very much. @ssalenik

@jaimeceballos
Copy link

I have problems when trying to crop screen on android 14. All screen fits into cropped size.
image

@sbfkcel
Copy link

sbfkcel commented Oct 14, 2024

Encountered the same problem

rom1v added a commit that referenced this issue Oct 28, 2024
The options --lock-video-orientation and --crop are broken since Android
14. Hopefully, they will be reimplemented differently.

Meanwhile, when running Android >= 14, fail with an error to prevent
incorrect behavior.

Refs #4011 <#4011>
Refs #4162 <#4162>
rom1v added a commit that referenced this issue Oct 31, 2024
The options --lock-video-orientation and --crop are broken since Android
14. Hopefully, they will be reimplemented differently.

Meanwhile, when running Android >= 14, fail with an error to prevent
incorrect behavior.

Refs #4011 <#4011>
Refs #4162 <#4162>
PR #5417 <#5417>
@rom1v
Copy link
Collaborator

rom1v commented Nov 11, 2024

Please test #5455.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants