mirror of
https://github.com/Genymobile/scrcpy.git
synced 2025-07-30 20:58:57 +00:00
Add --capture-orientation
Deprecate --lock-video-orientation in favor of a more general option --capture-orientation, which supports all possible orientations (0, 90, 180, 270, flip0, flip90, flip180, flip270), and a "locked" flag via a '@' prefix. All the old "locked video orientations" are supported: - --lock-video-orientation -> --capture-orientation=@ - --lock-video-orientation=0 -> --capture-orientation=@0 - --lock-video-orientation=90 -> --capture-orientation=@90 - --lock-video-orientation=180 -> --capture-orientation=@180 - --lock-video-orientation=270 -> --capture-orientation=@270 In addition, --capture-orientation can rotate/flip the display without locking, so that it follows the physical device rotation. For example: scrcpy --capture-orientation=flip90 always flips and rotates the capture by 90° clockwise. The arguments are consistent with --display-orientation and --record-orientation and --orientation (which provide separate client-side orientation settings). Refs #4011 <https://github.com/Genymobile/scrcpy/issues/4011> PR #5455 <https://github.com/Genymobile/scrcpy/pull/5455>
This commit is contained in:
parent
9b03bfc3ae
commit
45382e3f01
16 changed files with 233 additions and 145 deletions
|
@ -4,6 +4,7 @@ import com.genymobile.scrcpy.audio.AudioCodec;
|
|||
import com.genymobile.scrcpy.audio.AudioSource;
|
||||
import com.genymobile.scrcpy.device.Device;
|
||||
import com.genymobile.scrcpy.device.NewDisplay;
|
||||
import com.genymobile.scrcpy.device.Orientation;
|
||||
import com.genymobile.scrcpy.device.Size;
|
||||
import com.genymobile.scrcpy.util.CodecOption;
|
||||
import com.genymobile.scrcpy.util.Ln;
|
||||
|
@ -13,6 +14,7 @@ import com.genymobile.scrcpy.video.VideoCodec;
|
|||
import com.genymobile.scrcpy.video.VideoSource;
|
||||
|
||||
import android.graphics.Rect;
|
||||
import android.util.Pair;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
@ -32,7 +34,6 @@ public class Options {
|
|||
private int videoBitRate = 8000000;
|
||||
private int audioBitRate = 128000;
|
||||
private float maxFps;
|
||||
private int lockVideoOrientation = -1;
|
||||
private boolean tunnelForward;
|
||||
private Rect crop;
|
||||
private boolean control = true;
|
||||
|
@ -59,6 +60,9 @@ public class Options {
|
|||
|
||||
private NewDisplay newDisplay;
|
||||
|
||||
private Orientation.Lock captureOrientationLock = Orientation.Lock.Unlocked;
|
||||
private Orientation captureOrientation = Orientation.Orient0;
|
||||
|
||||
private boolean listEncoders;
|
||||
private boolean listDisplays;
|
||||
private boolean listCameras;
|
||||
|
@ -123,10 +127,6 @@ public class Options {
|
|||
return maxFps;
|
||||
}
|
||||
|
||||
public int getLockVideoOrientation() {
|
||||
return lockVideoOrientation;
|
||||
}
|
||||
|
||||
public boolean isTunnelForward() {
|
||||
return tunnelForward;
|
||||
}
|
||||
|
@ -219,6 +219,14 @@ public class Options {
|
|||
return newDisplay;
|
||||
}
|
||||
|
||||
public Orientation getCaptureOrientation() {
|
||||
return captureOrientation;
|
||||
}
|
||||
|
||||
public Orientation.Lock getCaptureOrientationLock() {
|
||||
return captureOrientationLock;
|
||||
}
|
||||
|
||||
public boolean getList() {
|
||||
return listEncoders || listDisplays || listCameras || listCameraSizes || listApps;
|
||||
}
|
||||
|
@ -341,9 +349,6 @@ public class Options {
|
|||
case "max_fps":
|
||||
options.maxFps = parseFloat("max_fps", value);
|
||||
break;
|
||||
case "lock_video_orientation":
|
||||
options.lockVideoOrientation = Integer.parseInt(value);
|
||||
break;
|
||||
case "tunnel_forward":
|
||||
options.tunnelForward = Boolean.parseBoolean(value);
|
||||
break;
|
||||
|
@ -448,6 +453,11 @@ public class Options {
|
|||
case "new_display":
|
||||
options.newDisplay = parseNewDisplay(value);
|
||||
break;
|
||||
case "capture_orientation":
|
||||
Pair<Orientation.Lock, Orientation> pair = parseCaptureOrientation(value);
|
||||
options.captureOrientationLock = pair.first;
|
||||
options.captureOrientation = pair.second;
|
||||
break;
|
||||
case "send_device_meta":
|
||||
options.sendDeviceMeta = Boolean.parseBoolean(value);
|
||||
break;
|
||||
|
@ -571,4 +581,25 @@ public class Options {
|
|||
|
||||
return new NewDisplay(size, dpi);
|
||||
}
|
||||
|
||||
private static Pair<Orientation.Lock, Orientation> parseCaptureOrientation(String value) {
|
||||
if (value.isEmpty()) {
|
||||
throw new IllegalArgumentException("Empty capture orientation string");
|
||||
}
|
||||
|
||||
Orientation.Lock lock;
|
||||
if (value.charAt(0) == '@') {
|
||||
// Consume '@'
|
||||
value = value.substring(1);
|
||||
if (value.isEmpty()) {
|
||||
// Only '@': lock to the initial orientation (orientation is unused)
|
||||
return Pair.create(Orientation.Lock.LockedInitial, Orientation.Orient0);
|
||||
}
|
||||
lock = Orientation.Lock.LockedValue;
|
||||
} else {
|
||||
lock = Orientation.Lock.Unlocked;
|
||||
}
|
||||
|
||||
return Pair.create(lock, Orientation.getByName(value));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,9 +40,6 @@ public final class Device {
|
|||
public static final int INJECT_MODE_WAIT_FOR_RESULT = InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_RESULT;
|
||||
public static final int INJECT_MODE_WAIT_FOR_FINISH = InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH;
|
||||
|
||||
public static final int LOCK_VIDEO_ORIENTATION_UNLOCKED = -1;
|
||||
public static final int LOCK_VIDEO_ORIENTATION_INITIAL = -2;
|
||||
|
||||
private Device() {
|
||||
// not instantiable
|
||||
}
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
package com.genymobile.scrcpy.device;
|
||||
|
||||
public enum Orientation {
|
||||
|
||||
// @formatter:off
|
||||
Orient0("0"),
|
||||
Orient90("90"),
|
||||
Orient180("180"),
|
||||
Orient270("270"),
|
||||
Flip0("flip0"),
|
||||
Flip90("flip90"),
|
||||
Flip180("flip180"),
|
||||
Flip270("flip270");
|
||||
|
||||
public enum Lock {
|
||||
Unlocked, LockedInitial, LockedValue,
|
||||
}
|
||||
|
||||
private final String name;
|
||||
|
||||
Orientation(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public static Orientation getByName(String name) {
|
||||
for (Orientation orientation : values()) {
|
||||
if (orientation.name.equals(name)) {
|
||||
return orientation;
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Unknown orientation: " + name);
|
||||
}
|
||||
|
||||
public static Orientation fromRotation(int rotation) {
|
||||
assert rotation >= 0 && rotation < 4;
|
||||
return values()[rotation];
|
||||
}
|
||||
|
||||
public boolean isFlipped() {
|
||||
return (ordinal() & 4) != 0;
|
||||
}
|
||||
|
||||
public int getRotation() {
|
||||
return ordinal() & 3;
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@ import com.genymobile.scrcpy.control.PositionMapper;
|
|||
import com.genymobile.scrcpy.device.ConfigurationException;
|
||||
import com.genymobile.scrcpy.device.Device;
|
||||
import com.genymobile.scrcpy.device.DisplayInfo;
|
||||
import com.genymobile.scrcpy.device.Orientation;
|
||||
import com.genymobile.scrcpy.device.Size;
|
||||
import com.genymobile.scrcpy.opengl.AffineOpenGLFilter;
|
||||
import com.genymobile.scrcpy.opengl.OpenGLFilter;
|
||||
|
@ -30,7 +31,8 @@ public class ScreenCapture extends SurfaceCapture {
|
|||
private final int displayId;
|
||||
private int maxSize;
|
||||
private final Rect crop;
|
||||
private int lockVideoOrientation;
|
||||
private Orientation.Lock captureOrientationLock;
|
||||
private Orientation captureOrientation;
|
||||
|
||||
private DisplayInfo displayInfo;
|
||||
private Size videoSize;
|
||||
|
@ -49,7 +51,10 @@ public class ScreenCapture extends SurfaceCapture {
|
|||
assert displayId != Device.DISPLAY_ID_NONE;
|
||||
this.maxSize = options.getMaxSize();
|
||||
this.crop = options.getCrop();
|
||||
this.lockVideoOrientation = options.getLockVideoOrientation();
|
||||
this.captureOrientationLock = options.getCaptureOrientationLock();
|
||||
this.captureOrientation = options.getCaptureOrientation();
|
||||
assert captureOrientationLock != null;
|
||||
assert captureOrientation != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -72,9 +77,10 @@ public class ScreenCapture extends SurfaceCapture {
|
|||
Size displaySize = displayInfo.getSize();
|
||||
displaySizeMonitor.setSessionDisplaySize(displaySize);
|
||||
|
||||
if (lockVideoOrientation == Device.LOCK_VIDEO_ORIENTATION_INITIAL) {
|
||||
if (captureOrientationLock == Orientation.Lock.LockedInitial) {
|
||||
// The user requested to lock the video orientation to the current orientation
|
||||
lockVideoOrientation = displayInfo.getRotation();
|
||||
captureOrientationLock = Orientation.Lock.LockedValue;
|
||||
captureOrientation = Orientation.fromRotation(displayInfo.getRotation());
|
||||
}
|
||||
|
||||
VideoFilter filter = new VideoFilter(displaySize);
|
||||
|
@ -84,9 +90,8 @@ public class ScreenCapture extends SurfaceCapture {
|
|||
filter.addCrop(crop, transposed);
|
||||
}
|
||||
|
||||
if (lockVideoOrientation != Device.LOCK_VIDEO_ORIENTATION_UNLOCKED) {
|
||||
filter.addLockVideoOrientation(lockVideoOrientation, displayInfo.getRotation());
|
||||
}
|
||||
boolean locked = captureOrientationLock != Orientation.Lock.Unlocked;
|
||||
filter.addOrientation(displayInfo.getRotation(), locked, captureOrientation);
|
||||
|
||||
transform = filter.getInverseTransform();
|
||||
videoSize = filter.getOutputSize().limit(maxSize).round8();
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package com.genymobile.scrcpy.video;
|
||||
|
||||
import com.genymobile.scrcpy.device.Orientation;
|
||||
import com.genymobile.scrcpy.device.Size;
|
||||
import com.genymobile.scrcpy.util.AffineMatrix;
|
||||
|
||||
|
@ -78,8 +79,20 @@ public class VideoFilter {
|
|||
}
|
||||
}
|
||||
|
||||
public void addLockVideoOrientation(int lockVideoOrientation, int displayRotation) {
|
||||
int ccwRotation = (4 + lockVideoOrientation - displayRotation) % 4;
|
||||
public void addOrientation(Orientation captureOrientation) {
|
||||
if (captureOrientation.isFlipped()) {
|
||||
transform = AffineMatrix.hflip().multiply(transform);
|
||||
}
|
||||
int ccwRotation = (4 - captureOrientation.getRotation()) % 4;
|
||||
addRotation(ccwRotation);
|
||||
}
|
||||
|
||||
public void addOrientation(int displayRotation, boolean locked, Orientation captureOrientation) {
|
||||
if (locked) {
|
||||
// flip/rotate the current display from the natural device orientation (i.e. where display rotation is 0)
|
||||
int reverseDisplayRotation = (4 - displayRotation) % 4;
|
||||
addRotation(reverseDisplayRotation);
|
||||
}
|
||||
addOrientation(captureOrientation);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue