From 9d7fa2a7e61c6532f1c0883aa65b13d4f3323e52 Mon Sep 17 00:00:00 2001 From: Romain Vimont Date: Sat, 11 Apr 2026 16:29:37 +0200 Subject: [PATCH] Refactor CaptureReset into CaptureControl Expose `CaptureControl` directly in `SurfaceCapture` to remove a layer of indirection (`CaptureListener`). This will make it easier to expose other methods without boilerplate. --- .../genymobile/scrcpy/control/Controller.java | 2 +- .../scrcpy/video/CameraCapture.java | 6 +++--- ...{CaptureReset.java => CaptureControl.java} | 7 +------ .../scrcpy/video/NewDisplayCapture.java | 2 +- .../scrcpy/video/ScreenCapture.java | 2 +- .../scrcpy/video/SurfaceCapture.java | 20 +++++++------------ .../scrcpy/video/SurfaceEncoder.java | 14 ++++++------- 7 files changed, 21 insertions(+), 32 deletions(-) rename server/src/main/java/com/genymobile/scrcpy/video/{CaptureReset.java => CaptureControl.java} (84%) diff --git a/server/src/main/java/com/genymobile/scrcpy/control/Controller.java b/server/src/main/java/com/genymobile/scrcpy/control/Controller.java index 38ead2cf..c5811f11 100644 --- a/server/src/main/java/com/genymobile/scrcpy/control/Controller.java +++ b/server/src/main/java/com/genymobile/scrcpy/control/Controller.java @@ -815,7 +815,7 @@ public class Controller implements AsyncProcessor, VirtualDisplayListener { private void resetVideo() { if (surfaceCapture != null) { Ln.i("Video capture reset"); - surfaceCapture.invalidate(); + surfaceCapture.getCaptureControl().reset(); } } } diff --git a/server/src/main/java/com/genymobile/scrcpy/video/CameraCapture.java b/server/src/main/java/com/genymobile/scrcpy/video/CameraCapture.java index 4124854c..0e8799f6 100644 --- a/server/src/main/java/com/genymobile/scrcpy/video/CameraCapture.java +++ b/server/src/main/java/com/genymobile/scrcpy/video/CameraCapture.java @@ -323,7 +323,7 @@ public class CameraCapture extends SurfaceCapture { } catch (CameraAccessException e) { Ln.e("Camera error", e); disconnected.set(true); - invalidate(); + getCaptureControl().reset(); } } @@ -331,7 +331,7 @@ public class CameraCapture extends SurfaceCapture { public void onConfigureFailed(CameraCaptureSession session) { Ln.e("Camera configuration error"); disconnected.set(true); - invalidate(); + getCaptureControl().reset(); } }); @@ -388,7 +388,7 @@ public class CameraCapture extends SurfaceCapture { public void onDisconnected(CameraDevice camera) { Ln.w("Camera disconnected"); disconnected.set(true); - invalidate(); + getCaptureControl().reset(); } @Override diff --git a/server/src/main/java/com/genymobile/scrcpy/video/CaptureReset.java b/server/src/main/java/com/genymobile/scrcpy/video/CaptureControl.java similarity index 84% rename from server/src/main/java/com/genymobile/scrcpy/video/CaptureReset.java rename to server/src/main/java/com/genymobile/scrcpy/video/CaptureControl.java index 79d32d7c..001f297d 100644 --- a/server/src/main/java/com/genymobile/scrcpy/video/CaptureReset.java +++ b/server/src/main/java/com/genymobile/scrcpy/video/CaptureControl.java @@ -4,7 +4,7 @@ import android.media.MediaCodec; import java.util.concurrent.atomic.AtomicBoolean; -public class CaptureReset implements SurfaceCapture.CaptureListener { +public class CaptureControl { private final AtomicBoolean reset = new AtomicBoolean(); @@ -29,9 +29,4 @@ public class CaptureReset implements SurfaceCapture.CaptureListener { public synchronized void setRunningMediaCodec(MediaCodec runningMediaCodec) { this.runningMediaCodec = runningMediaCodec; } - - @Override - public void onInvalidated() { - reset(); - } } diff --git a/server/src/main/java/com/genymobile/scrcpy/video/NewDisplayCapture.java b/server/src/main/java/com/genymobile/scrcpy/video/NewDisplayCapture.java index e0ec2141..ceed4c84 100644 --- a/server/src/main/java/com/genymobile/scrcpy/video/NewDisplayCapture.java +++ b/server/src/main/java/com/genymobile/scrcpy/video/NewDisplayCapture.java @@ -201,7 +201,7 @@ public class NewDisplayCapture extends SurfaceCapture { ServiceManager.getWindowManager().setDisplayImePolicy(virtualDisplayId, displayImePolicy); } - displayMonitor.start(virtualDisplayId, this::invalidate); + displayMonitor.start(virtualDisplayId, () -> getCaptureControl().reset()); } catch (Exception e) { Ln.e("Could not create display", e); throw new AssertionError("Could not create display"); 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 adabdfb0..239402a3 100644 --- a/server/src/main/java/com/genymobile/scrcpy/video/ScreenCapture.java +++ b/server/src/main/java/com/genymobile/scrcpy/video/ScreenCapture.java @@ -61,7 +61,7 @@ public class ScreenCapture extends SurfaceCapture { @Override public void init() { - displayMonitor.start(displayId, this::invalidate); + displayMonitor.start(displayId, () -> getCaptureControl().reset()); } @Override diff --git a/server/src/main/java/com/genymobile/scrcpy/video/SurfaceCapture.java b/server/src/main/java/com/genymobile/scrcpy/video/SurfaceCapture.java index 908aff1e..81c19581 100644 --- a/server/src/main/java/com/genymobile/scrcpy/video/SurfaceCapture.java +++ b/server/src/main/java/com/genymobile/scrcpy/video/SurfaceCapture.java @@ -12,29 +12,23 @@ import java.io.IOException; */ public abstract class SurfaceCapture { - public interface CaptureListener { - void onInvalidated(); - } - - private CaptureListener listener; + private CaptureControl captureControl; private VideoConstraints constraints; - /** - * Notify the listener that the capture has been invalidated (for example, because its size changed, or due to a manual user request). - */ - public void invalidate() { - listener.onInvalidated(); - } /** * Called once before the first capture starts. */ - public final void init(CaptureListener listener, VideoConstraints constraints) throws ConfigurationException, IOException { - this.listener = listener; + public final void init(CaptureControl captureControl, VideoConstraints constraints) throws ConfigurationException, IOException { + this.captureControl = captureControl; this.constraints = constraints; init(); } + public CaptureControl getCaptureControl() { + return captureControl; + } + /** * Called once before the first capture starts. */ diff --git a/server/src/main/java/com/genymobile/scrcpy/video/SurfaceEncoder.java b/server/src/main/java/com/genymobile/scrcpy/video/SurfaceEncoder.java index 0333203e..5c56ed3a 100644 --- a/server/src/main/java/com/genymobile/scrcpy/video/SurfaceEncoder.java +++ b/server/src/main/java/com/genymobile/scrcpy/video/SurfaceEncoder.java @@ -43,7 +43,7 @@ public class SurfaceEncoder implements AsyncProcessor { private Thread thread; private final AtomicBoolean stopped = new AtomicBoolean(); - private final CaptureReset reset = new CaptureReset(); + private final CaptureControl captureControl = new CaptureControl(); public SurfaceEncoder(SurfaceCapture capture, Streamer streamer, Options options) { this.capture = capture; @@ -89,7 +89,7 @@ public class SurfaceEncoder implements AsyncProcessor { assert caps != null; // caps cannot be null for a video codec VideoConstraints constraints = createVideoConstraints(maxSize, minSizeAlignment, caps); - capture.init(reset, constraints); + capture.init(captureControl, constraints); try { boolean alive; @@ -97,7 +97,7 @@ public class SurfaceEncoder implements AsyncProcessor { streamer.writeVideoHeader(); do { - reset.consumeReset(); // If a capture reset was requested, it is implicitly fulfilled + captureControl.consumeReset(); // If a capture reset was requested, it is implicitly fulfilled capture.prepare(); Size size = capture.getSize(); @@ -118,12 +118,12 @@ public class SurfaceEncoder implements AsyncProcessor { mediaCodecStarted = true; // Set the MediaCodec instance to "interrupt" (by signaling an EOS) on reset - reset.setRunningMediaCodec(mediaCodec); + captureControl.setRunningMediaCodec(mediaCodec); if (stopped.get()) { alive = false; } else { - boolean resetRequested = reset.consumeReset(); + boolean resetRequested = captureControl.consumeReset(); if (!resetRequested) { // If a reset is requested during encode(), it will interrupt the encoding by an EOS streamer.writeSessionMeta(size.getWidth(), size.getHeight()); @@ -133,7 +133,7 @@ public class SurfaceEncoder implements AsyncProcessor { alive = !stopped.get() && !capture.isClosed(); } } finally { - reset.setRunningMediaCodec(null); + captureControl.setRunningMediaCodec(null); if (captureStarted) { capture.stop(); } @@ -275,7 +275,7 @@ public class SurfaceEncoder implements AsyncProcessor { public void stop() { if (thread != null) { stopped.set(true); - reset.reset(); + captureControl.reset(); } }