Handle virtual display rotation
Listen to display size changes and rotate the virtual display accordingly. Note: use `git show -b` to Show this commit ignoring whitespace changes. Fixes #5428 <https://github.com/Genymobile/scrcpy/issues/5428> Refs #5370 <https://github.com/Genymobile/scrcpy/pull/5370> PR #5455 <https://github.com/Genymobile/scrcpy/pull/5455>
This commit is contained in:
parent
39d51ff2cc
commit
9b03bfc3ae
@ -6,10 +6,13 @@ import com.genymobile.scrcpy.control.PositionMapper;
|
|||||||
import com.genymobile.scrcpy.device.DisplayInfo;
|
import com.genymobile.scrcpy.device.DisplayInfo;
|
||||||
import com.genymobile.scrcpy.device.NewDisplay;
|
import com.genymobile.scrcpy.device.NewDisplay;
|
||||||
import com.genymobile.scrcpy.device.Size;
|
import com.genymobile.scrcpy.device.Size;
|
||||||
|
import com.genymobile.scrcpy.opengl.AffineOpenGLFilter;
|
||||||
|
import com.genymobile.scrcpy.opengl.OpenGLFilter;
|
||||||
|
import com.genymobile.scrcpy.opengl.OpenGLRunner;
|
||||||
|
import com.genymobile.scrcpy.util.AffineMatrix;
|
||||||
import com.genymobile.scrcpy.util.Ln;
|
import com.genymobile.scrcpy.util.Ln;
|
||||||
import com.genymobile.scrcpy.wrappers.ServiceManager;
|
import com.genymobile.scrcpy.wrappers.ServiceManager;
|
||||||
|
|
||||||
import android.hardware.display.DisplayManager;
|
|
||||||
import android.hardware.display.VirtualDisplay;
|
import android.hardware.display.VirtualDisplay;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.view.Surface;
|
import android.view.Surface;
|
||||||
@ -19,8 +22,8 @@ import java.io.IOException;
|
|||||||
public class NewDisplayCapture extends SurfaceCapture {
|
public class NewDisplayCapture extends SurfaceCapture {
|
||||||
|
|
||||||
// Internal fields copied from android.hardware.display.DisplayManager
|
// Internal fields copied from android.hardware.display.DisplayManager
|
||||||
private static final int VIRTUAL_DISPLAY_FLAG_PUBLIC = DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC;
|
private static final int VIRTUAL_DISPLAY_FLAG_PUBLIC = android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC;
|
||||||
private static final int VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY = DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY;
|
private static final int VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY = android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY;
|
||||||
private static final int VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH = 1 << 6;
|
private static final int VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH = 1 << 6;
|
||||||
private static final int VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT = 1 << 7;
|
private static final int VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT = 1 << 7;
|
||||||
private static final int VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_REMOVAL = 1 << 8;
|
private static final int VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_REMOVAL = 1 << 8;
|
||||||
@ -35,12 +38,18 @@ public class NewDisplayCapture extends SurfaceCapture {
|
|||||||
private final VirtualDisplayListener vdListener;
|
private final VirtualDisplayListener vdListener;
|
||||||
private final NewDisplay newDisplay;
|
private final NewDisplay newDisplay;
|
||||||
|
|
||||||
|
private final DisplaySizeMonitor displaySizeMonitor = new DisplaySizeMonitor();
|
||||||
|
|
||||||
|
private AffineMatrix displayTransform;
|
||||||
|
private OpenGLRunner glRunner;
|
||||||
|
|
||||||
private Size mainDisplaySize;
|
private Size mainDisplaySize;
|
||||||
private int mainDisplayDpi;
|
private int mainDisplayDpi;
|
||||||
private int maxSize; // only used if newDisplay.getSize() != null
|
private int maxSize; // only used if newDisplay.getSize() != null
|
||||||
|
|
||||||
private VirtualDisplay virtualDisplay;
|
private VirtualDisplay virtualDisplay;
|
||||||
private Size size;
|
private Size size; // the logical size of the display (including rotation)
|
||||||
|
private Size physicalSize; // the physical size of the display (without rotation)
|
||||||
private int dpi;
|
private int dpi;
|
||||||
|
|
||||||
public NewDisplayCapture(VirtualDisplayListener vdListener, Options options) {
|
public NewDisplayCapture(VirtualDisplayListener vdListener, Options options) {
|
||||||
@ -69,12 +78,28 @@ public class NewDisplayCapture extends SurfaceCapture {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void prepare() {
|
public void prepare() {
|
||||||
|
if (virtualDisplay == null) {
|
||||||
if (!newDisplay.hasExplicitSize()) {
|
if (!newDisplay.hasExplicitSize()) {
|
||||||
size = mainDisplaySize.limit(maxSize).round8();
|
size = mainDisplaySize.limit(maxSize).round8();
|
||||||
}
|
}
|
||||||
if (!newDisplay.hasExplicitDpi()) {
|
if (!newDisplay.hasExplicitDpi()) {
|
||||||
dpi = scaleDpi(mainDisplaySize, mainDisplayDpi, size);
|
dpi = scaleDpi(mainDisplaySize, mainDisplayDpi, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
physicalSize = size;
|
||||||
|
// Set the current display size to avoid an unnecessary call to invalidate()
|
||||||
|
displaySizeMonitor.setSessionDisplaySize(size);
|
||||||
|
} else {
|
||||||
|
DisplayInfo displayInfo = ServiceManager.getDisplayManager().getDisplayInfo(virtualDisplay.getDisplay().getDisplayId());
|
||||||
|
size = displayInfo.getSize();
|
||||||
|
dpi = displayInfo.getDpi();
|
||||||
|
|
||||||
|
VideoFilter displayFilter = new VideoFilter(size);
|
||||||
|
displayFilter.addRotation(displayInfo.getRotation());
|
||||||
|
// The display info gives the oriented size, but the virtual display video always remains in the origin orientation
|
||||||
|
displayTransform = displayFilter.getInverseTransform();
|
||||||
|
physicalSize = displayFilter.getOutputSize();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void startNew(Surface surface) {
|
public void startNew(Surface surface) {
|
||||||
@ -100,28 +125,48 @@ public class NewDisplayCapture extends SurfaceCapture {
|
|||||||
.createNewVirtualDisplay("scrcpy", size.getWidth(), size.getHeight(), dpi, surface, flags);
|
.createNewVirtualDisplay("scrcpy", size.getWidth(), size.getHeight(), dpi, surface, flags);
|
||||||
virtualDisplayId = virtualDisplay.getDisplay().getDisplayId();
|
virtualDisplayId = virtualDisplay.getDisplay().getDisplayId();
|
||||||
Ln.i("New display: " + size.getWidth() + "x" + size.getHeight() + "/" + dpi + " (id=" + virtualDisplayId + ")");
|
Ln.i("New display: " + size.getWidth() + "x" + size.getHeight() + "/" + dpi + " (id=" + virtualDisplayId + ")");
|
||||||
|
|
||||||
|
displaySizeMonitor.start(virtualDisplayId, this::invalidate);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Ln.e("Could not create display", e);
|
Ln.e("Could not create display", e);
|
||||||
throw new AssertionError("Could not create display");
|
throw new AssertionError("Could not create display");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vdListener != null) {
|
|
||||||
PositionMapper positionMapper = new PositionMapper(size, null);
|
|
||||||
vdListener.onNewVirtualDisplay(virtualDisplayId, positionMapper);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void start(Surface surface) throws IOException {
|
public void start(Surface surface) throws IOException {
|
||||||
|
if (displayTransform != null) {
|
||||||
|
assert glRunner == null;
|
||||||
|
OpenGLFilter glFilter = new AffineOpenGLFilter(displayTransform);
|
||||||
|
glRunner = new OpenGLRunner(glFilter);
|
||||||
|
surface = glRunner.start(physicalSize, size, surface);
|
||||||
|
}
|
||||||
|
|
||||||
if (virtualDisplay == null) {
|
if (virtualDisplay == null) {
|
||||||
startNew(surface);
|
startNew(surface);
|
||||||
} else {
|
} else {
|
||||||
virtualDisplay.setSurface(surface);
|
virtualDisplay.setSurface(surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (vdListener != null) {
|
||||||
|
// The virtual display rotation must only be applied to video, it is already taken into account when injecting events!
|
||||||
|
PositionMapper positionMapper = PositionMapper.create(size, null, size);
|
||||||
|
vdListener.onNewVirtualDisplay(virtualDisplay.getDisplay().getDisplayId(), positionMapper);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stop() {
|
||||||
|
if (glRunner != null) {
|
||||||
|
glRunner.stopAndRelease();
|
||||||
|
glRunner = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void release() {
|
public void release() {
|
||||||
|
displaySizeMonitor.stopAndRelease();
|
||||||
|
|
||||||
if (virtualDisplay != null) {
|
if (virtualDisplay != null) {
|
||||||
virtualDisplay.release();
|
virtualDisplay.release();
|
||||||
virtualDisplay = null;
|
virtualDisplay = null;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user