From ae2d094362fbdc4d402b0315d981015ffe5c4967 Mon Sep 17 00:00:00 2001 From: Romain Vimont Date: Thu, 5 Mar 2020 22:01:35 +0100 Subject: [PATCH] Handle locked video orientation from ScreenInfo Centralize video size management in ScreenInfo. This allows to always send the correct initial video size to the client if the video orientation is locked. --- .../java/com/genymobile/scrcpy/Device.java | 45 ++--------- .../com/genymobile/scrcpy/ScreenEncoder.java | 20 +++-- .../com/genymobile/scrcpy/ScreenInfo.java | 74 ++++++++++++++++--- 3 files changed, 80 insertions(+), 59 deletions(-) diff --git a/server/src/main/java/com/genymobile/scrcpy/Device.java b/server/src/main/java/com/genymobile/scrcpy/Device.java index 1eebc679..1b1fbf7d 100644 --- a/server/src/main/java/com/genymobile/scrcpy/Device.java +++ b/server/src/main/java/com/genymobile/scrcpy/Device.java @@ -22,14 +22,12 @@ public final class Device { private final ServiceManager serviceManager = new ServiceManager(); - private final int lockedVideoOrientation; private ScreenInfo screenInfo; private RotationListener rotationListener; public Device(Options options) { - lockedVideoOrientation = options.getLockedVideoOrientation(); DisplayInfo displayInfo = serviceManager.getDisplayManager().getDisplayInfo(); - screenInfo = ScreenInfo.computeScreenInfo(displayInfo, options.getCrop(), options.getMaxSize()); + screenInfo = ScreenInfo.computeScreenInfo(displayInfo, options.getCrop(), options.getMaxSize(), options.getLockedVideoOrientation()); registerRotationWatcher(new IRotationWatcher.Stub() { @Override public void onRotationChanged(int rotation) throws RemoteException { @@ -49,55 +47,28 @@ public final class Device { return screenInfo; } - /** - * Return the rotation to apply to the device rotation to get the requested locked video orientation - * - * @param deviceRotation the device rotation - * @return the rotation offset - */ - public int getVideoRotation(int deviceRotation) { - if (lockedVideoOrientation == -1) { - // no offset - return 0; - } - return (deviceRotation + 4 - lockedVideoOrientation) % 4; - } - - /** - * Return the rotation to apply to the requested locked video orientation to get the device rotation - * - * @param deviceRotation the device rotation - * @return the (reverse) rotation offset - */ - private int getReverseVideoRotation(int deviceRotation) { - if (lockedVideoOrientation == -1) { - // no offset - return 0; - } - return (lockedVideoOrientation + 4 - deviceRotation) % 4; - } - public Point getPhysicalPoint(Position position) { // it hides the field on purpose, to read it with a lock @SuppressWarnings("checkstyle:HiddenField") ScreenInfo screenInfo = getScreenInfo(); // read with synchronization - Size videoSize = screenInfo.getVideoSize(); - int deviceRotation = screenInfo.getDeviceRotation(); - int reverseVideoRotation = getReverseVideoRotation(deviceRotation); + // ignore the locked video orientation, the events will apply in coordinates considered in the physical device orientation + Size unlockedVideoSize = screenInfo.getUnlockedVideoSize(); + + int reverseVideoRotation = screenInfo.getReverseVideoRotation(); // reverse the video rotation to apply the events Position devicePosition = position.rotate(reverseVideoRotation); Size clientVideoSize = devicePosition.getScreenSize(); - if (!videoSize.equals(clientVideoSize)) { + if (!unlockedVideoSize.equals(clientVideoSize)) { // The client sends a click relative to a video with wrong dimensions, // the device may have been rotated since the event was generated, so ignore the event return null; } Rect contentRect = screenInfo.getContentRect(); Point point = devicePosition.getPoint(); - int convertedX = contentRect.left + point.getX() * contentRect.width() / videoSize.getWidth(); - int convertedY = contentRect.top + point.getY() * contentRect.height() / videoSize.getHeight(); + int convertedX = contentRect.left + point.getX() * contentRect.width() / unlockedVideoSize.getWidth(); + int convertedY = contentRect.top + point.getY() * contentRect.height() / unlockedVideoSize.getHeight(); return new Point(convertedX, convertedY); } diff --git a/server/src/main/java/com/genymobile/scrcpy/ScreenEncoder.java b/server/src/main/java/com/genymobile/scrcpy/ScreenEncoder.java index 61bccc93..e99084af 100644 --- a/server/src/main/java/com/genymobile/scrcpy/ScreenEncoder.java +++ b/server/src/main/java/com/genymobile/scrcpy/ScreenEncoder.java @@ -66,12 +66,15 @@ public class ScreenEncoder implements Device.RotationListener { IBinder display = createDisplay(); ScreenInfo screenInfo = device.getScreenInfo(); Rect contentRect = screenInfo.getContentRect(); + // include the locked video orientation Rect videoRect = screenInfo.getVideoSize().toRect(); - int videoRotation = device.getVideoRotation(screenInfo.getDeviceRotation()); - setSize(format, videoRotation, videoRect.width(), videoRect.height()); + // does not include the locked video orientation + Rect unlockedVideoRect = screenInfo.getUnlockedVideoSize().toRect(); + int videoRotation = screenInfo.getVideoRotation(); + setSize(format, videoRect.width(), videoRect.height()); configure(codec, format); Surface surface = codec.createInputSurface(); - setDisplaySurface(display, surface, videoRotation, contentRect, videoRect); + setDisplaySurface(display, surface, videoRotation, contentRect, unlockedVideoRect); codec.start(); try { alive = encode(codec, fd); @@ -170,14 +173,9 @@ public class ScreenEncoder implements Device.RotationListener { codec.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE); } - private static void setSize(MediaFormat format, int orientation, int width, int height) { - if (orientation % 2 == 0) { - format.setInteger(MediaFormat.KEY_WIDTH, width); - format.setInteger(MediaFormat.KEY_HEIGHT, height); - return; - } - format.setInteger(MediaFormat.KEY_WIDTH, height); - format.setInteger(MediaFormat.KEY_HEIGHT, width); + private static void setSize(MediaFormat format, int width, int height) { + format.setInteger(MediaFormat.KEY_WIDTH, width); + format.setInteger(MediaFormat.KEY_HEIGHT, height); } private static void setDisplaySurface(IBinder display, Surface surface, int orientation, Rect deviceRect, Rect displayRect) { diff --git a/server/src/main/java/com/genymobile/scrcpy/ScreenInfo.java b/server/src/main/java/com/genymobile/scrcpy/ScreenInfo.java index 3e7cadc3..0204de82 100644 --- a/server/src/main/java/com/genymobile/scrcpy/ScreenInfo.java +++ b/server/src/main/java/com/genymobile/scrcpy/ScreenInfo.java @@ -9,27 +9,53 @@ public final class ScreenInfo { private final Rect contentRect; // device size, possibly cropped /** - * Video size, possibly smaller than the device size, already taking the device rotation and crop into account + * Video size, possibly smaller than the device size, already taking the device rotation and crop into account. + *

+ * However, it does not include the locked video orientation. */ - private final Size videoSize; + private final Size unlockedVideoSize; /** * Device rotation, related to the natural device orientation (0, 1, 2 or 3) */ private final int deviceRotation; - public ScreenInfo(Rect contentRect, Size videoSize, int deviceRotation) { + /** + * The locked video orientation (-1: disabled, 0: normal, 1: 90° CCW, 2: 180°, 3: 90° CW) + */ + private final int lockedVideoOrientation; + + public ScreenInfo(Rect contentRect, Size unlockedVideoSize, int deviceRotation, int lockedVideoOrientation) { this.contentRect = contentRect; - this.videoSize = videoSize; + this.unlockedVideoSize = unlockedVideoSize; this.deviceRotation = deviceRotation; + this.lockedVideoOrientation = lockedVideoOrientation; } public Rect getContentRect() { return contentRect; } + /** + * Return the video size as if locked video orientation was not set. + * + * @return the unlocked video size + */ + public Size getUnlockedVideoSize() { + return unlockedVideoSize; + } + + /** + * Return the actual video size if locked video orientation is set. + * + * @return the actual video size + */ public Size getVideoSize() { - return videoSize; + if (getVideoRotation() % 2 == 0) { + return unlockedVideoSize; + } + + return unlockedVideoSize.rotate(); } public int getDeviceRotation() { @@ -43,18 +69,18 @@ public final class ScreenInfo { // true if changed between portrait and landscape boolean orientationChanged = (deviceRotation + newDeviceRotation) % 2 != 0; Rect newContentRect; - Size newVideoSize; + Size newUnlockedVideoSize; if (orientationChanged) { newContentRect = flipRect(contentRect); - newVideoSize = videoSize.rotate(); + newUnlockedVideoSize = unlockedVideoSize.rotate(); } else { newContentRect = contentRect; - newVideoSize = videoSize; + newUnlockedVideoSize = unlockedVideoSize; } - return new ScreenInfo(newContentRect, newVideoSize, newDeviceRotation); + return new ScreenInfo(newContentRect, newUnlockedVideoSize, newDeviceRotation, lockedVideoOrientation); } - public static ScreenInfo computeScreenInfo(DisplayInfo displayInfo, Rect crop, int maxSize) { + public static ScreenInfo computeScreenInfo(DisplayInfo displayInfo, Rect crop, int maxSize, int lockedVideoOrientation) { int rotation = displayInfo.getRotation(); Size deviceSize = displayInfo.getSize(); Rect contentRect = new Rect(0, 0, deviceSize.getWidth(), deviceSize.getHeight()); @@ -71,7 +97,7 @@ public final class ScreenInfo { } Size videoSize = computeVideoSize(contentRect.width(), contentRect.height(), maxSize); - return new ScreenInfo(contentRect, videoSize, rotation); + return new ScreenInfo(contentRect, videoSize, rotation, lockedVideoOrientation); } private static String formatCrop(Rect rect) { @@ -109,4 +135,30 @@ public final class ScreenInfo { private static Rect flipRect(Rect crop) { return new Rect(crop.top, crop.left, crop.bottom, crop.right); } + + /** + * Return the rotation to apply to the device rotation to get the requested locked video orientation + * + * @return the rotation offset + */ + public int getVideoRotation() { + if (lockedVideoOrientation == -1) { + // no offset + return 0; + } + return (deviceRotation + 4 - lockedVideoOrientation) % 4; + } + + /** + * Return the rotation to apply to the requested locked video orientation to get the device rotation + * + * @return the (reverse) rotation offset + */ + public int getReverseVideoRotation() { + if (lockedVideoOrientation == -1) { + // no offset + return 0; + } + return (lockedVideoOrientation + 4 - deviceRotation) % 4; + } }