Skip to content

Commit

Permalink
Handle locked video orientation from ScreenInfo
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
rom1v committed Mar 8, 2020
1 parent c5f5d1e commit ae2d094
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 59 deletions.
45 changes: 8 additions & 37 deletions server/src/main/java/com/genymobile/scrcpy/Device.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,12 @@ public interface RotationListener {

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 {
Expand All @@ -49,55 +47,28 @@ public synchronized ScreenInfo getScreenInfo() {
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);
}

Expand Down
20 changes: 9 additions & 11 deletions server/src/main/java/com/genymobile/scrcpy/ScreenEncoder.java
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,15 @@ public void streamScreen(Device device, FileDescriptor fd) throws IOException {
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);
Expand Down Expand Up @@ -170,14 +173,9 @@ private static void configure(MediaCodec codec, MediaFormat format) {
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) {
Expand Down
74 changes: 63 additions & 11 deletions server/src/main/java/com/genymobile/scrcpy/ScreenInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -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.
* <p>
* 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() {
Expand All @@ -43,18 +69,18 @@ public ScreenInfo withDeviceRotation(int newDeviceRotation) {
// 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());
Expand All @@ -71,7 +97,7 @@ public static ScreenInfo computeScreenInfo(DisplayInfo displayInfo, Rect crop, i
}

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) {
Expand Down Expand Up @@ -109,4 +135,30 @@ private static Size computeVideoSize(int w, int h, int maxSize) {
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;
}
}

0 comments on commit ae2d094

Please sign in to comment.