diff --git a/server/src/main/java/com/genymobile/scrcpy/video/ScreenCapture.java b/server/src/main/java/com/genymobile/scrcpy/video/ScreenCapture.java index 5f4e1803f9..76559cfb02 100644 --- a/server/src/main/java/com/genymobile/scrcpy/video/ScreenCapture.java +++ b/server/src/main/java/com/genymobile/scrcpy/video/ScreenCapture.java @@ -43,7 +43,10 @@ public class ScreenCapture extends SurfaceCapture { private IBinder display; private VirtualDisplay virtualDisplay; + private Rect orientedCrop; + private AffineMatrix transform; + private AffineMatrix filterTransform; private OpenGLRunner glRunner; public ScreenCapture(VirtualDisplayListener vdListener, Options options) { @@ -85,19 +88,40 @@ public void prepare() throws ConfigurationException { captureOrientation = Orientation.fromRotation(displayInfo.getRotation()); } - VideoFilter filter = new VideoFilter(displaySize); + orientedCrop = null; + filterTransform = null; + transform = null; - if (crop != null) { - boolean transposed = (displayInfo.getRotation() % 2) != 0; - filter.addCrop(crop, transposed); - } + boolean onlyCrop = crop != null + && angle == 0f + && captureOrientationLock == Orientation.Lock.Unlocked + && captureOrientation == Orientation.Orient0; + + if (onlyCrop) { + orientedCrop = new Rect(crop); + if ((displayInfo.getRotation() % 2) != 0) { + orientedCrop = new Rect(crop.top, crop.left, crop.bottom, crop.right); + } - boolean locked = captureOrientationLock != Orientation.Lock.Unlocked; - filter.addOrientation(displayInfo.getRotation(), locked, captureOrientation); - filter.addAngle(angle); + videoSize = new Size(orientedCrop.width(), orientedCrop.height()).limit(maxSize).round8(); + transform = AffineMatrix.translate(orientedCrop.left, orientedCrop.top); + filterTransform = null; + } else { + VideoFilter filter = new VideoFilter(displaySize); + + if (crop != null) { + boolean transposed = (displayInfo.getRotation() % 2) != 0; + filter.addCrop(crop, transposed); + } - transform = filter.getInverseTransform(); - videoSize = filter.getOutputSize().limit(maxSize).round8(); + boolean locked = captureOrientationLock != Orientation.Lock.Unlocked; + filter.addOrientation(displayInfo.getRotation(), locked, captureOrientation); + filter.addAngle(angle); + + filterTransform = filter.getInverseTransform(); + transform = filterTransform; + videoSize = filter.getOutputSize().limit(maxSize).round8(); + } } @Override @@ -112,29 +136,38 @@ public void start(Surface surface) throws IOException { } Size inputSize; - if (transform != null) { + if (filterTransform != null) { // If there is a filter, it must receive the full display content inputSize = displayInfo.getSize(); assert glRunner == null; - OpenGLFilter glFilter = new AffineOpenGLFilter(transform); + OpenGLFilter glFilter = new AffineOpenGLFilter(filterTransform); glRunner = new OpenGLRunner(glFilter); surface = glRunner.start(inputSize, videoSize, surface); } else { // If there is no filter, the display must be rendered at target video size directly - inputSize = videoSize; + if (orientedCrop != null) { + inputSize = new Size(orientedCrop.width(), orientedCrop.height()); + } else { + inputSize = videoSize; + } } try { - virtualDisplay = ServiceManager.getDisplayManager() - .createVirtualDisplay("scrcpy", inputSize.getWidth(), inputSize.getHeight(), displayId, surface); - Ln.d("Display: using DisplayManager API"); + if (orientedCrop == null) { + virtualDisplay = ServiceManager.getDisplayManager() + .createVirtualDisplay("scrcpy", inputSize.getWidth(), inputSize.getHeight(), displayId, surface); + Ln.d("Display: using DisplayManager API"); + } else { + throw new Exception("Use SurfaceControl for crop"); + } } catch (Exception displayManagerException) { try { display = createDisplay(); Size deviceSize = displayInfo.getSize(); int layerStack = displayInfo.getLayerStack(); - setDisplaySurface(display, surface, deviceSize.toRect(), inputSize.toRect(), layerStack); + Rect layerRect = orientedCrop != null ? orientedCrop : deviceSize.toRect(); + setDisplaySurface(display, surface, layerRect, inputSize.toRect(), layerStack); Ln.d("Display: using SurfaceControl API"); } catch (Exception surfaceControlException) { Ln.e("Could not create display using DisplayManager", displayManagerException);