From c90247ffb6826cc4287ad342065b27c4d803e0db Mon Sep 17 00:00:00 2001 From: Romain Vimont Date: Tue, 7 Aug 2018 23:06:20 +0200 Subject: [PATCH] wip --- .../java/com/genymobile/scrcpy/Device.java | 39 ++------- .../java/com/genymobile/scrcpy/Options.java | 11 +++ .../com/genymobile/scrcpy/ScreenEncoder.java | 5 +- .../com/genymobile/scrcpy/ScreenInfo.java | 79 ++++++++++++++++++- 4 files changed, 96 insertions(+), 38 deletions(-) diff --git a/server/src/main/java/com/genymobile/scrcpy/Device.java b/server/src/main/java/com/genymobile/scrcpy/Device.java index b9b8bb71..fdc6725d 100644 --- a/server/src/main/java/com/genymobile/scrcpy/Device.java +++ b/server/src/main/java/com/genymobile/scrcpy/Device.java @@ -3,6 +3,7 @@ package com.genymobile.scrcpy; import com.genymobile.scrcpy.wrappers.ServiceManager; import android.graphics.Point; +import android.graphics.Rect; import android.os.Build; import android.os.RemoteException; import android.view.IRotationWatcher; @@ -20,7 +21,8 @@ public final class Device { private RotationListener rotationListener; public Device(Options options) { - screenInfo = computeScreenInfo(options.getMaxSize()); + options.setCrop(new Rect(100, 100, 300, 250)); + screenInfo = computeScreenInfo(options.getMaxSize(), options.getCrop()); registerRotationWatcher(new IRotationWatcher.Stub() { @Override public void onRotationChanged(int rotation) throws RemoteException { @@ -40,40 +42,9 @@ public final class Device { return screenInfo; } - private ScreenInfo computeScreenInfo(int maxSize) { + private ScreenInfo computeScreenInfo(int maxSize, Rect crop) { DisplayInfo displayInfo = serviceManager.getDisplayManager().getDisplayInfo(); - boolean rotated = (displayInfo.getRotation() & 1) != 0; - Size deviceSize = displayInfo.getSize(); - Size videoSize = computeVideoSize(deviceSize, maxSize); - return new ScreenInfo(deviceSize, videoSize, rotated); - } - - @SuppressWarnings("checkstyle:MagicNumber") - private static Size computeVideoSize(Size inputSize, int maxSize) { - // Compute the video size and the padding of the content inside this video. - // Principle: - // - scale down the great side of the screen to maxSize (if necessary); - // - scale down the other side so that the aspect ratio is preserved; - // - round this value to the nearest multiple of 8 (H.264 only accepts multiples of 8) - int w = inputSize.getWidth() & ~7; // in case it's not a multiple of 8 - int h = inputSize.getHeight() & ~7; - if (maxSize > 0) { - if (BuildConfig.DEBUG && maxSize % 8 != 0) { - throw new AssertionError("Max size must be a multiple of 8"); - } - boolean portrait = h > w; - int major = portrait ? h : w; - int minor = portrait ? w : h; - if (major > maxSize) { - int minorExact = minor * maxSize / major; - // +4 to round the value to the nearest multiple of 8 - minor = (minorExact + 4) & ~7; - major = maxSize; - } - w = portrait ? minor : major; - h = portrait ? major : minor; - } - return new Size(w, h); + return ScreenInfo.create(displayInfo, maxSize, crop); } public Point getPhysicalPoint(Position position) { diff --git a/server/src/main/java/com/genymobile/scrcpy/Options.java b/server/src/main/java/com/genymobile/scrcpy/Options.java index 332463e6..93df896a 100644 --- a/server/src/main/java/com/genymobile/scrcpy/Options.java +++ b/server/src/main/java/com/genymobile/scrcpy/Options.java @@ -1,9 +1,12 @@ package com.genymobile.scrcpy; +import android.graphics.Rect; + public class Options { private int maxSize; private int bitRate; private boolean tunnelForward; + private Rect crop; public int getMaxSize() { return maxSize; @@ -28,4 +31,12 @@ public class Options { public void setTunnelForward(boolean tunnelForward) { this.tunnelForward = tunnelForward; } + + public Rect getCrop() { + return crop; + } + + public void setCrop(Rect crop) { + this.crop = crop; + } } diff --git a/server/src/main/java/com/genymobile/scrcpy/ScreenEncoder.java b/server/src/main/java/com/genymobile/scrcpy/ScreenEncoder.java index 3014397c..7c9725cd 100644 --- a/server/src/main/java/com/genymobile/scrcpy/ScreenEncoder.java +++ b/server/src/main/java/com/genymobile/scrcpy/ScreenEncoder.java @@ -56,12 +56,13 @@ public class ScreenEncoder implements Device.RotationListener { do { MediaCodec codec = createCodec(); IBinder display = createDisplay(); - Rect deviceRect = device.getScreenInfo().getDeviceSize().toRect(); + Rect contentRect = device.getScreenInfo().getContentRect(); + System.out.println(contentRect); Rect videoRect = device.getScreenInfo().getVideoSize().toRect(); setSize(format, videoRect.width(), videoRect.height()); configure(codec, format); Surface surface = codec.createInputSurface(); - setDisplaySurface(display, surface, deviceRect, videoRect); + setDisplaySurface(display, surface, contentRect, videoRect); codec.start(); try { alive = encode(codec, outputStream); diff --git a/server/src/main/java/com/genymobile/scrcpy/ScreenInfo.java b/server/src/main/java/com/genymobile/scrcpy/ScreenInfo.java index 1f752758..9ca8dbe3 100644 --- a/server/src/main/java/com/genymobile/scrcpy/ScreenInfo.java +++ b/server/src/main/java/com/genymobile/scrcpy/ScreenInfo.java @@ -1,14 +1,64 @@ package com.genymobile.scrcpy; +import android.graphics.Rect; + public final class ScreenInfo { private final Size deviceSize; private final Size videoSize; + private final Rect crop; private final boolean rotated; - public ScreenInfo(Size deviceSize, Size videoSize, boolean rotated) { + private ScreenInfo(Size deviceSize, Size videoSize, Rect crop, boolean rotated) { this.deviceSize = deviceSize; this.videoSize = videoSize; this.rotated = rotated; + this.crop = crop; + } + + public static ScreenInfo create(DisplayInfo displayInfo, int maxSize, Rect crop) { + boolean rotated = (displayInfo.getRotation() & 1) != 0; + // the device size (provided by the system) takes the rotation into account + Size deviceSize = displayInfo.getSize(); + Size inputSize; + if (crop == null) { + inputSize = deviceSize; + } else { + if (rotated) { + // the crop (provided by the user) is expressed in the natural orientation + crop = rotateCrop(crop, deviceSize.rotate()); + } + inputSize = new Size(crop.width(), crop.height()); + } + Size videoSize = computeVideoSize(inputSize, maxSize); + return new ScreenInfo(deviceSize, videoSize, crop, rotated); + } + + @SuppressWarnings("checkstyle:MagicNumber") + private static Size computeVideoSize(Size inputSize, int maxSize) { + // Compute the video size and the padding of the content inside this video. + // Principle: + // - scale down the great side of the screen to maxSize (if necessary); + // - scale down the other side so that the aspect ratio is preserved; + // - round this value to the nearest multiple of 8 (H.264 only accepts multiples of 8) + int w = inputSize.getWidth() & ~7; // in case it's not a multiple of 8 + int h = inputSize.getHeight() & ~7; + if (maxSize > 0) { + if (BuildConfig.DEBUG && maxSize % 8 != 0) { + throw new AssertionError("Max size must be a multiple of 8"); + } + boolean portrait = h > w; + int major = portrait ? h : w; + int minor = portrait ? w : h; + if (major > maxSize) { + int minorExact = minor * maxSize / major; + // +4 to round the value to the nearest multiple of 8 + minor = (minorExact + 4) & ~7; + major = maxSize; + } + w = portrait ? minor : major; + h = portrait ? major : minor; + } + return new Size(w, h); } public Size getDeviceSize() { @@ -19,11 +69,36 @@ public final class ScreenInfo { return videoSize; } + public Rect getCrop() { + return crop; + } + + public Rect getContentRect() { + Rect crop = getCrop(); + return crop != null ? crop : deviceSize.toRect(); + } + public ScreenInfo withRotation(int rotation) { boolean newRotated = (rotation & 1) != 0; if (rotated == newRotated) { return this; } - return new ScreenInfo(deviceSize.rotate(), videoSize.rotate(), newRotated); + Rect newCrop = null; + if (crop != null) { + // the crop has typically a meaning only in one dimension, but we must rotate it so that the + // video size matches on rotation + newCrop = newRotated ? rotateCrop(crop, deviceSize) : unrotateCrop(crop, deviceSize); + } + return new ScreenInfo(deviceSize.rotate(), videoSize.rotate(), newCrop, newRotated); + } + + private static Rect rotateCrop(Rect crop, Size deviceSize) { + int w = deviceSize.getWidth(); + return new Rect(crop.top, w - crop.right, crop.bottom, w - crop.left); + } + + private static Rect unrotateCrop(Rect crop, Size deviceSize) { + int h = deviceSize.getHeight(); + return new Rect(h - crop.bottom, crop.left, h - crop.top, crop.right); } }