diff --git a/server/src/main/java/com/genymobile/scrcpy/Server.java b/server/src/main/java/com/genymobile/scrcpy/Server.java index eb8b533a..06332d12 100644 --- a/server/src/main/java/com/genymobile/scrcpy/Server.java +++ b/server/src/main/java/com/genymobile/scrcpy/Server.java @@ -156,6 +156,7 @@ public final class Server { if (controller != null) { controller.setSurfaceCapture(surfaceCapture); + controller.setSurfaceEncoder(surfaceEncoder); } } diff --git a/server/src/main/java/com/genymobile/scrcpy/control/ControlMessage.java b/server/src/main/java/com/genymobile/scrcpy/control/ControlMessage.java index 0eb96adc..11e5b9c8 100644 --- a/server/src/main/java/com/genymobile/scrcpy/control/ControlMessage.java +++ b/server/src/main/java/com/genymobile/scrcpy/control/ControlMessage.java @@ -25,6 +25,7 @@ public final class ControlMessage { public static final int TYPE_OPEN_HARD_KEYBOARD_SETTINGS = 15; public static final int TYPE_START_APP = 16; public static final int TYPE_RESET_VIDEO = 17; + public static final int TYPE_REQUEST_IDR = 18; public static final long SEQUENCE_INVALID = 0; diff --git a/server/src/main/java/com/genymobile/scrcpy/control/ControlMessageReader.java b/server/src/main/java/com/genymobile/scrcpy/control/ControlMessageReader.java index e503ec61..b7286e5e 100644 --- a/server/src/main/java/com/genymobile/scrcpy/control/ControlMessageReader.java +++ b/server/src/main/java/com/genymobile/scrcpy/control/ControlMessageReader.java @@ -56,6 +56,8 @@ public class ControlMessageReader { return parseUhidDestroy(); case ControlMessage.TYPE_START_APP: return parseStartApp(); + case ControlMessage.TYPE_REQUEST_IDR: + return ControlMessage.createEmpty(type); default: throw new ControlProtocolException("Unknown event type: " + type); } 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 5e64a4c5..71358d7a 100644 --- a/server/src/main/java/com/genymobile/scrcpy/control/Controller.java +++ b/server/src/main/java/com/genymobile/scrcpy/control/Controller.java @@ -12,6 +12,7 @@ import com.genymobile.scrcpy.device.Size; import com.genymobile.scrcpy.util.Ln; import com.genymobile.scrcpy.util.LogUtils; import com.genymobile.scrcpy.video.SurfaceCapture; +import com.genymobile.scrcpy.video.SurfaceEncoder; import com.genymobile.scrcpy.video.VirtualDisplayListener; import com.genymobile.scrcpy.wrappers.ClipboardManager; import com.genymobile.scrcpy.wrappers.InputManager; @@ -99,6 +100,7 @@ public class Controller implements AsyncProcessor, VirtualDisplayListener { // Used for resetting video encoding on RESET_VIDEO message private SurfaceCapture surfaceCapture; + private SurfaceEncoder surfaceEncoder; public Controller(ControlChannel controlChannel, CleanUp cleanUp, Options options) { this.displayId = options.getDisplayId(); @@ -154,6 +156,10 @@ public class Controller implements AsyncProcessor, VirtualDisplayListener { this.surfaceCapture = surfaceCapture; } + public void setSurfaceEncoder(SurfaceEncoder surfaceEncoder) { + this.surfaceEncoder = surfaceEncoder; + } + private UhidManager getUhidManager() { if (uhidManager == null) { uhidManager = new UhidManager(sender); @@ -307,6 +313,9 @@ public class Controller implements AsyncProcessor, VirtualDisplayListener { case ControlMessage.TYPE_RESET_VIDEO: resetVideo(); break; + case ControlMessage.TYPE_REQUEST_IDR: + requestIdr(); + break; default: // do nothing } @@ -728,4 +737,11 @@ public class Controller implements AsyncProcessor, VirtualDisplayListener { surfaceCapture.requestInvalidate(); } } + + public void requestIdr() { + if (surfaceEncoder != null) { + Ln.i("Requesting IDR"); + surfaceEncoder.requestIdr(); + } + } } 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 236a5f48..4d01f688 100644 --- a/server/src/main/java/com/genymobile/scrcpy/video/SurfaceEncoder.java +++ b/server/src/main/java/com/genymobile/scrcpy/video/SurfaceEncoder.java @@ -20,6 +20,7 @@ import android.os.Build; import android.os.Looper; import android.os.SystemClock; import android.view.Surface; +import android.os.Bundle; import java.io.IOException; import java.nio.ByteBuffer; @@ -52,6 +53,8 @@ public class SurfaceEncoder implements AsyncProcessor { private final CaptureReset reset = new CaptureReset(); + private final AtomicBoolean idrRequested = new AtomicBoolean(); + public SurfaceEncoder(SurfaceCapture capture, Streamer streamer, Options options) { this.capture = capture; this.streamer = streamer; @@ -199,6 +202,13 @@ public class SurfaceEncoder implements AsyncProcessor { boolean eos; do { + if (idrRequested.get()) { + Bundle bundle = new Bundle(); + bundle.putInt(MediaCodec.PARAMETER_KEY_REQUEST_SYNC_FRAME, 0); + codec.setParameters(bundle); + idrRequested.set(false); + } + int outputBufferId = codec.dequeueOutputBuffer(bufferInfo, -1); try { eos = (bufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0; @@ -323,4 +333,8 @@ public class SurfaceEncoder implements AsyncProcessor { thread.join(); } } + + public void requestIdr() { + idrRequested.set(true); + } }