Handle resized video stream
Accept a parameter to limit the video size. For instance, with "-m 960", the great side of the video will be scaled down to 960 (if necessary), while the other side will be scaled down so that the aspect ratio is preserved. Both dimensions must be a multiple of 8, so black bands might be added, and the mouse positions must be computed accordingly.
This commit is contained in:
parent
2c4ea6869e
commit
89f6a3cfe7
18 changed files with 274 additions and 87 deletions
|
@ -9,15 +9,16 @@
|
|||
struct args {
|
||||
const char *serial;
|
||||
Uint16 port;
|
||||
Uint16 maximum_size;
|
||||
};
|
||||
|
||||
int parse_args(struct args *args, int argc, char *argv[]) {
|
||||
int c;
|
||||
while ((c = getopt(argc, argv, "p:")) != -1) {
|
||||
while ((c = getopt(argc, argv, "p:m:")) != -1) {
|
||||
switch (c) {
|
||||
case 'p': {
|
||||
char *endptr;
|
||||
long int value = strtol(optarg, &endptr, 0);
|
||||
long value = strtol(optarg, &endptr, 0);
|
||||
if (*optarg == '\0' || *endptr != '\0') {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Invalid port: %s\n", optarg);
|
||||
return -1;
|
||||
|
@ -29,6 +30,20 @@ int parse_args(struct args *args, int argc, char *argv[]) {
|
|||
args->port = (Uint16) value;
|
||||
break;
|
||||
}
|
||||
case 'm': {
|
||||
char *endptr;
|
||||
long value = strtol(optarg, &endptr, 0);
|
||||
if (*optarg == '\0' || *endptr != '\0') {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Invalid maximum size: %s\n", optarg);
|
||||
return -1;
|
||||
}
|
||||
if (value & ~0xffff) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Maximum size must be between 0 and 65535: %ld\n", value);
|
||||
return -1;
|
||||
}
|
||||
args->maximum_size = (Uint16) value;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// getopt prints the error message on stderr
|
||||
return -1;
|
||||
|
@ -65,7 +80,7 @@ int main(int argc, char *argv[]) {
|
|||
|
||||
SDL_LogSetAllPriority(SDL_LOG_PRIORITY_DEBUG);
|
||||
|
||||
res = scrcpy(args.serial, args.port) ? 0 : 1;
|
||||
res = scrcpy(args.serial, args.port, args.maximum_size) ? 0 : 1;
|
||||
|
||||
avformat_network_deinit(); // ignore failure
|
||||
|
||||
|
|
|
@ -382,7 +382,7 @@ void event_loop(void) {
|
|||
}
|
||||
}
|
||||
|
||||
SDL_bool scrcpy(const char *serial, Uint16 local_port) {
|
||||
SDL_bool scrcpy(const char *serial, Uint16 local_port, Uint16 maximum_size) {
|
||||
SDL_bool ret = 0;
|
||||
|
||||
process_t push_proc = push_server(serial);
|
||||
|
@ -402,7 +402,7 @@ SDL_bool scrcpy(const char *serial, Uint16 local_port) {
|
|||
}
|
||||
|
||||
// server will connect to our socket
|
||||
process_t server = start_server(serial);
|
||||
process_t server = start_server(serial, maximum_size);
|
||||
if (server == PROCESS_NONE) {
|
||||
ret = SDL_FALSE;
|
||||
SDLNet_TCP_Close(server_socket);
|
||||
|
|
|
@ -3,6 +3,6 @@
|
|||
|
||||
#include <SDL2/SDL_stdinc.h>
|
||||
|
||||
SDL_bool scrcpy(const char *serial, Uint16 local_port);
|
||||
SDL_bool scrcpy(const char *serial, Uint16 local_port, Uint16 maximum_size);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -21,13 +21,16 @@ process_t disable_tunnel(const char *serial) {
|
|||
return adb_reverse_remove(serial, SOCKET_NAME);
|
||||
}
|
||||
|
||||
process_t start_server(const char *serial) {
|
||||
process_t start_server(const char *serial, Uint16 maximum_size) {
|
||||
char maximum_size_string[6];
|
||||
sprintf(maximum_size_string, "%d", maximum_size);
|
||||
const char *const cmd[] = {
|
||||
"shell",
|
||||
"CLASSPATH=/data/local/tmp/scrcpy-server.jar",
|
||||
"app_process",
|
||||
"/system/bin",
|
||||
"com.genymobile.scrcpy.ScrCpyServer"
|
||||
"com.genymobile.scrcpy.ScrCpyServer",
|
||||
maximum_size_string,
|
||||
};
|
||||
return adb_execute(serial, cmd, sizeof(cmd) / sizeof(cmd[0]));
|
||||
}
|
||||
|
|
|
@ -4,5 +4,5 @@ process_t push_server(const char *serial);
|
|||
process_t enable_tunnel(const char *serial, Uint16 local_port);
|
||||
process_t disable_tunnel(const char *serial);
|
||||
|
||||
process_t start_server(const char *serial);
|
||||
process_t start_server(const char *serial, Uint16 maximum_size);
|
||||
void stop_server(process_t server);
|
||||
|
|
|
@ -24,13 +24,16 @@ SRC := com/genymobile/scrcpy/ScrCpyServer.java \
|
|||
com/genymobile/scrcpy/ControlEventReader.java \
|
||||
com/genymobile/scrcpy/DesktopConnection.java \
|
||||
com/genymobile/scrcpy/Device.java \
|
||||
com/genymobile/scrcpy/DisplayInfo.java \
|
||||
com/genymobile/scrcpy/EventController.java \
|
||||
com/genymobile/scrcpy/Ln.java \
|
||||
com/genymobile/scrcpy/Options.java \
|
||||
com/genymobile/scrcpy/Point.java \
|
||||
com/genymobile/scrcpy/Position.java \
|
||||
com/genymobile/scrcpy/ScreenInfo.java \
|
||||
com/genymobile/scrcpy/ScreenStreamer.java \
|
||||
com/genymobile/scrcpy/ScreenStreamerSession.java \
|
||||
com/genymobile/scrcpy/Size.java \
|
||||
com/genymobile/scrcpy/wrappers/DisplayManager.java \
|
||||
com/genymobile/scrcpy/wrappers/InputManager.java \
|
||||
com/genymobile/scrcpy/wrappers/ServiceManager.java \
|
||||
|
|
|
@ -36,12 +36,9 @@ public class DesktopConnection implements Closeable {
|
|||
public static DesktopConnection open(Device device) throws IOException {
|
||||
LocalSocket socket = connect(SOCKET_NAME);
|
||||
|
||||
ScreenInfo initialScreenInfo = device.getScreenInfo();
|
||||
int width = initialScreenInfo.getLogicalWidth();
|
||||
int height = initialScreenInfo.getLogicalHeight();
|
||||
|
||||
DesktopConnection connection = new DesktopConnection(socket);
|
||||
connection.send(Device.getDeviceName(), width, height);
|
||||
Size videoSize = device.getScreenInfo().getVideoSize();
|
||||
connection.send(Device.getDeviceName(), videoSize.getWidth(), videoSize.getHeight());
|
||||
return connection;
|
||||
}
|
||||
|
||||
|
@ -81,4 +78,3 @@ public class DesktopConnection implements Closeable {
|
|||
return event;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ import android.view.IRotationWatcher;
|
|||
import com.genymobile.scrcpy.wrappers.InputManager;
|
||||
import com.genymobile.scrcpy.wrappers.ServiceManager;
|
||||
|
||||
public class Device {
|
||||
public final class Device {
|
||||
|
||||
public interface RotationListener {
|
||||
void onRotationChanged(int rotation);
|
||||
|
@ -18,13 +18,12 @@ public class Device {
|
|||
private ScreenInfo screenInfo;
|
||||
private RotationListener rotationListener;
|
||||
|
||||
public Device() {
|
||||
screenInfo = readScreenInfo();
|
||||
public Device(Options options) {
|
||||
screenInfo = computeScreenInfo(options.getMaximumSize());
|
||||
registerRotationWatcher(new IRotationWatcher.Stub() {
|
||||
@Override
|
||||
public void onRotationChanged(int rotation) throws RemoteException {
|
||||
synchronized (Device.this) {
|
||||
// update screenInfo cache
|
||||
screenInfo = screenInfo.withRotation(rotation);
|
||||
|
||||
// notify
|
||||
|
@ -37,23 +36,59 @@ public class Device {
|
|||
}
|
||||
|
||||
public synchronized ScreenInfo getScreenInfo() {
|
||||
if (screenInfo == null) {
|
||||
screenInfo = readScreenInfo();
|
||||
}
|
||||
return screenInfo;
|
||||
}
|
||||
|
||||
public Point getPhysicalPoint(Position position) {
|
||||
ScreenInfo screenInfo = getScreenInfo();
|
||||
int deviceWidth = screenInfo.getLogicalWidth();
|
||||
int deviceHeight = screenInfo.getLogicalHeight();
|
||||
int scaledX = position.getX() * deviceWidth / position.getScreenWidth();
|
||||
int scaledY = position.getY() * deviceHeight / position.getScreenHeight();
|
||||
return new Point(scaledX, scaledY);
|
||||
private ScreenInfo computeScreenInfo(int maximumSize) {
|
||||
DisplayInfo displayInfo = serviceManager.getDisplayManager().getDisplayInfo();
|
||||
boolean rotated = (displayInfo.getRotation() & 1) != 0;
|
||||
Size deviceSize = displayInfo.getSize();
|
||||
int w = deviceSize.getWidth();
|
||||
int h = deviceSize.getHeight();
|
||||
int padding = 0;
|
||||
if (maximumSize > 0) {
|
||||
assert maximumSize % 8 == 0;
|
||||
boolean portrait = h > w;
|
||||
int major = portrait ? h : w;
|
||||
int minor = portrait ? w : h;
|
||||
if (major > maximumSize) {
|
||||
int minorExact = minor * maximumSize / major;
|
||||
// +7 to ceil the value on rounding to the next multiple of 8,
|
||||
// so that any necessary black bands to keep the aspect ratio are added to the smallest dimension
|
||||
minor = (minorExact + 7) & ~7;
|
||||
major = maximumSize;
|
||||
padding = minor - minorExact;
|
||||
}
|
||||
w = portrait ? minor : major;
|
||||
h = portrait ? major : minor;
|
||||
}
|
||||
return new ScreenInfo(deviceSize, new Size(w, h), padding, rotated);
|
||||
}
|
||||
|
||||
private ScreenInfo readScreenInfo() {
|
||||
return serviceManager.getDisplayManager().getScreenInfo();
|
||||
public Point getPhysicalPoint(Position position) {
|
||||
ScreenInfo screenInfo = getScreenInfo(); // read with synchronization
|
||||
Size videoSize = screenInfo.getVideoSize();
|
||||
Size clientVideoSize = position.getScreenSize();
|
||||
if (!videoSize.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;
|
||||
}
|
||||
Size deviceSize = screenInfo.getDeviceSize();
|
||||
int xPadding = screenInfo.getXPadding();
|
||||
int yPadding = screenInfo.getYPadding();
|
||||
int contentWidth = videoSize.getWidth() - xPadding;
|
||||
int contentHeight = videoSize.getHeight() - yPadding;
|
||||
Point point = position.getPoint();
|
||||
int x = point.getX() - xPadding / 2;
|
||||
int y = point.getY() - yPadding / 2;
|
||||
if (x < 0 || x >= contentWidth || y < 0 || y >= contentHeight) {
|
||||
// out of screen
|
||||
return null;
|
||||
}
|
||||
int scaledX = x * deviceSize.getWidth() / videoSize.getWidth();
|
||||
int scaledY = y * deviceSize.getHeight() / videoSize.getHeight();
|
||||
return new Point(scaledX, scaledY);
|
||||
}
|
||||
|
||||
public static String getDeviceName() {
|
||||
|
|
20
server/src/com/genymobile/scrcpy/DisplayInfo.java
Normal file
20
server/src/com/genymobile/scrcpy/DisplayInfo.java
Normal file
|
@ -0,0 +1,20 @@
|
|||
package com.genymobile.scrcpy;
|
||||
|
||||
public final class DisplayInfo {
|
||||
private final Size size;
|
||||
private final int rotation;
|
||||
|
||||
public DisplayInfo(Size size, int rotation) {
|
||||
this.size = size;
|
||||
this.rotation = rotation;
|
||||
}
|
||||
|
||||
public Size getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
public int getRotation() {
|
||||
return rotation;
|
||||
}
|
||||
}
|
||||
|
13
server/src/com/genymobile/scrcpy/Options.java
Normal file
13
server/src/com/genymobile/scrcpy/Options.java
Normal file
|
@ -0,0 +1,13 @@
|
|||
package com.genymobile.scrcpy;
|
||||
|
||||
public class Options {
|
||||
private int maximumSize;
|
||||
|
||||
public int getMaximumSize() {
|
||||
return maximumSize;
|
||||
}
|
||||
|
||||
public void setMaximumSize(int maximumSize) {
|
||||
this.maximumSize = maximumSize;
|
||||
}
|
||||
}
|
|
@ -1,5 +1,7 @@
|
|||
package com.genymobile.scrcpy;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class Point {
|
||||
private int x;
|
||||
private int y;
|
||||
|
@ -17,6 +19,20 @@ public class Point {
|
|||
return y;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Point point = (Point) o;
|
||||
return x == point.x &&
|
||||
y == point.y;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(x, y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Point{" +
|
||||
|
|
|
@ -1,42 +1,48 @@
|
|||
package com.genymobile.scrcpy;
|
||||
|
||||
public class Position {
|
||||
import java.util.Objects;
|
||||
|
||||
private int x;
|
||||
private int y;
|
||||
private int screenWidth;
|
||||
private int screenHeight;
|
||||
public class Position {
|
||||
private Point point;
|
||||
private Size screenSize;
|
||||
|
||||
public Position(Point point, Size screenSize) {
|
||||
this.point = point;
|
||||
this.screenSize = screenSize;
|
||||
}
|
||||
|
||||
public Position(int x, int y, int screenWidth, int screenHeight) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.screenWidth = screenWidth;
|
||||
this.screenHeight = screenHeight;
|
||||
this(new Point(x, y), new Size(screenWidth, screenHeight));
|
||||
}
|
||||
|
||||
public int getX() {
|
||||
return x;
|
||||
public Point getPoint() {
|
||||
return point;
|
||||
}
|
||||
|
||||
public int getY() {
|
||||
return y;
|
||||
public Size getScreenSize() {
|
||||
return screenSize;
|
||||
}
|
||||
|
||||
public int getScreenWidth() {
|
||||
return screenWidth;
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Position position = (Position) o;
|
||||
return Objects.equals(point, position.point) &&
|
||||
Objects.equals(screenSize, position.screenSize);
|
||||
}
|
||||
|
||||
public int getScreenHeight() {
|
||||
return screenHeight;
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(point, screenSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Point{" +
|
||||
"x=" + x +
|
||||
", y=" + y +
|
||||
", screenWidth=" + screenWidth +
|
||||
", screenHeight=" + screenHeight +
|
||||
return "Position{" +
|
||||
"point=" + point +
|
||||
", screenSize=" + screenSize +
|
||||
'}';
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -6,10 +6,10 @@ public class ScrCpyServer {
|
|||
|
||||
private static final String TAG = "scrcpy";
|
||||
|
||||
private static void scrcpy() throws IOException {
|
||||
final Device device = new Device();
|
||||
private static void scrcpy(Options options) throws IOException {
|
||||
final Device device = new Device(options);
|
||||
try (DesktopConnection connection = DesktopConnection.open(device)) {
|
||||
final ScreenStreamer streamer = new ScreenStreamer(connection);
|
||||
final ScreenStreamer streamer = new ScreenStreamer(device, connection);
|
||||
device.setRotationListener(new Device.RotationListener() {
|
||||
@Override
|
||||
public void onRotationChanged(int rotation) {
|
||||
|
@ -43,8 +43,13 @@ public class ScrCpyServer {
|
|||
}
|
||||
|
||||
public static void main(String... args) throws Exception {
|
||||
Options options = new Options();
|
||||
if (args.length > 0) {
|
||||
int maximumSize = Integer.parseInt(args[0]) & ~7; // multiple of 8
|
||||
options.setMaximumSize(maximumSize);
|
||||
}
|
||||
try {
|
||||
scrcpy();
|
||||
scrcpy(options);
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
throw t;
|
||||
|
|
|
@ -1,26 +1,39 @@
|
|||
package com.genymobile.scrcpy;
|
||||
|
||||
public class ScreenInfo {
|
||||
private final int width;
|
||||
private final int height;
|
||||
private int rotation;
|
||||
public final class ScreenInfo {
|
||||
private final Size deviceSize;
|
||||
private final Size videoSize;
|
||||
private final int padding; // padding inside the video stream, along the smallest dimension
|
||||
private final boolean rotated;
|
||||
|
||||
public ScreenInfo(int width, int height, int rotation) {
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.rotation = rotation;
|
||||
public ScreenInfo(Size deviceSize, Size videoSize, int padding, boolean rotated) {
|
||||
this.deviceSize = deviceSize;
|
||||
this.videoSize = videoSize;
|
||||
this.padding = padding;
|
||||
this.rotated = rotated;
|
||||
}
|
||||
|
||||
public Size getDeviceSize() {
|
||||
return deviceSize;
|
||||
}
|
||||
|
||||
public Size getVideoSize() {
|
||||
return videoSize;
|
||||
}
|
||||
|
||||
public int getXPadding() {
|
||||
return videoSize.getWidth() < videoSize.getHeight() ? padding : 0;
|
||||
}
|
||||
|
||||
public int getYPadding() {
|
||||
return videoSize.getHeight() < videoSize.getWidth() ? padding : 0;
|
||||
}
|
||||
|
||||
public ScreenInfo withRotation(int rotation) {
|
||||
return new ScreenInfo(width, height, rotation);
|
||||
boolean newRotated = (rotation & 1) != 0;
|
||||
if (rotated == newRotated) {
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getLogicalWidth() {
|
||||
return (rotation & 1) == 0 ? width : height;
|
||||
}
|
||||
|
||||
public int getLogicalHeight() {
|
||||
return (rotation & 1) == 0 ? height : width;
|
||||
return new ScreenInfo(deviceSize.rotate(), videoSize.rotate(), padding, newRotated);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,15 +5,17 @@ import java.io.InterruptedIOException;
|
|||
|
||||
public class ScreenStreamer {
|
||||
|
||||
private final Device device;
|
||||
private final DesktopConnection connection;
|
||||
private ScreenStreamerSession currentStreamer; // protected by 'this'
|
||||
|
||||
public ScreenStreamer(DesktopConnection connection) {
|
||||
public ScreenStreamer(Device device, DesktopConnection connection) {
|
||||
this.device = device;
|
||||
this.connection = connection;
|
||||
}
|
||||
|
||||
private synchronized ScreenStreamerSession newScreenStreamerSession() {
|
||||
currentStreamer = new ScreenStreamerSession(connection);
|
||||
currentStreamer = new ScreenStreamerSession(device, connection);
|
||||
return currentStreamer;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,16 +2,20 @@ package com.genymobile.scrcpy;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
public class ScreenStreamerSession {
|
||||
|
||||
private final Device device;
|
||||
private final DesktopConnection connection;
|
||||
private Process screenRecordProcess; // protected by 'this'
|
||||
private final AtomicBoolean stopped = new AtomicBoolean();
|
||||
private final byte[] buffer = new byte[0x10000];
|
||||
|
||||
public ScreenStreamerSession(DesktopConnection connection) {
|
||||
public ScreenStreamerSession(Device device, DesktopConnection connection) {
|
||||
this.device = device;
|
||||
this.connection = connection;
|
||||
}
|
||||
|
||||
|
@ -28,7 +32,8 @@ public class ScreenStreamerSession {
|
|||
*/
|
||||
private boolean streamScreenOnce() throws IOException {
|
||||
Ln.d("Recording...");
|
||||
Process process = startScreenRecord();
|
||||
Size videoSize = device.getScreenInfo().getVideoSize();
|
||||
Process process = startScreenRecord(videoSize);
|
||||
setCurrentProcess(process);
|
||||
InputStream inputStream = process.getInputStream();
|
||||
int r;
|
||||
|
@ -44,8 +49,15 @@ public class ScreenStreamerSession {
|
|||
killCurrentProcess();
|
||||
}
|
||||
|
||||
private static Process startScreenRecord() throws IOException {
|
||||
Process process = new ProcessBuilder("screenrecord", "--output-format=h264", "-").start();
|
||||
private static Process startScreenRecord(Size videoSize) throws IOException {
|
||||
List<String> command = new ArrayList<>();
|
||||
command.add("screenrecord");
|
||||
command.add("--output-format=h264");
|
||||
if (videoSize != null) {
|
||||
command.add("--size=" + videoSize.getWidth() + "x" + videoSize.getHeight());
|
||||
}
|
||||
command.add("-");
|
||||
Process process = new ProcessBuilder(command).start();
|
||||
process.getOutputStream().close();
|
||||
return process;
|
||||
}
|
||||
|
|
47
server/src/com/genymobile/scrcpy/Size.java
Normal file
47
server/src/com/genymobile/scrcpy/Size.java
Normal file
|
@ -0,0 +1,47 @@
|
|||
package com.genymobile.scrcpy;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public final class Size {
|
||||
private final int width;
|
||||
private final int height;
|
||||
|
||||
public Size(int width, int height) {
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
}
|
||||
|
||||
public int getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
public int getHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
public Size rotate() {
|
||||
return new Size(height, width);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Size size = (Size) o;
|
||||
return width == size.width &&
|
||||
height == size.height;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(width, height);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Size{" +
|
||||
"width=" + width +
|
||||
", height=" + height +
|
||||
'}';
|
||||
}
|
||||
}
|
|
@ -2,7 +2,8 @@ package com.genymobile.scrcpy.wrappers;
|
|||
|
||||
import android.os.IInterface;
|
||||
|
||||
import com.genymobile.scrcpy.ScreenInfo;
|
||||
import com.genymobile.scrcpy.DisplayInfo;
|
||||
import com.genymobile.scrcpy.Size;
|
||||
|
||||
public class DisplayManager {
|
||||
private final IInterface manager;
|
||||
|
@ -11,15 +12,15 @@ public class DisplayManager {
|
|||
this.manager = manager;
|
||||
}
|
||||
|
||||
public ScreenInfo getScreenInfo() {
|
||||
public DisplayInfo getDisplayInfo() {
|
||||
try {
|
||||
Object displayInfo = manager.getClass().getMethod("getDisplayInfo", int.class).invoke(manager, 0);
|
||||
Class<?> cls = displayInfo.getClass();
|
||||
// width and height do not depend on the rotation
|
||||
int width = (Integer) cls.getMethod("getNaturalWidth").invoke(displayInfo);
|
||||
int height = (Integer) cls.getMethod("getNaturalHeight").invoke(displayInfo);
|
||||
// width and height already take the rotation into account
|
||||
int width = cls.getDeclaredField("logicalWidth").getInt(displayInfo);
|
||||
int height = cls.getDeclaredField("logicalHeight").getInt(displayInfo);
|
||||
int rotation = cls.getDeclaredField("rotation").getInt(displayInfo);
|
||||
return new ScreenInfo(width, height, rotation);
|
||||
return new DisplayInfo(new Size(width, height), rotation);
|
||||
} catch (Exception e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue