Add shortcut to reset video capture/encoding

Reset video capture/encoding on MOD+Shift+r.

Like on device rotation, this starts a new encoding session which
produces a video stream starting by a key frame.

PR #5432 <https://github.com/Genymobile/scrcpy/pull/5432>
This commit is contained in:
Romain Vimont 2024-10-31 22:47:35 +01:00
commit 104195fc3b
15 changed files with 106 additions and 8 deletions

View file

@ -225,6 +225,10 @@ public final class Server {
SurfaceEncoder surfaceEncoder = new SurfaceEncoder(surfaceCapture, videoStreamer, options.getVideoBitRate(), options.getMaxFps(),
options.getVideoCodecOptions(), options.getVideoEncoder(), options.getDownsizeOnError());
asyncProcessors.add(surfaceEncoder);
if (controller != null) {
controller.setSurfaceCapture(surfaceCapture);
}
}
Completion completion = new Completion(asyncProcessors.size());

View file

@ -24,6 +24,7 @@ public final class ControlMessage {
public static final int TYPE_UHID_DESTROY = 14;
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 long SEQUENCE_INVALID = 0;

View file

@ -46,6 +46,7 @@ public class ControlMessageReader {
case ControlMessage.TYPE_COLLAPSE_PANELS:
case ControlMessage.TYPE_ROTATE_DEVICE:
case ControlMessage.TYPE_OPEN_HARD_KEYBOARD_SETTINGS:
case ControlMessage.TYPE_RESET_VIDEO:
return ControlMessage.createEmpty(type);
case ControlMessage.TYPE_UHID_CREATE:
return parseUhidCreate();

View file

@ -9,6 +9,7 @@ import com.genymobile.scrcpy.device.Point;
import com.genymobile.scrcpy.device.Position;
import com.genymobile.scrcpy.util.Ln;
import com.genymobile.scrcpy.util.LogUtils;
import com.genymobile.scrcpy.video.SurfaceCapture;
import com.genymobile.scrcpy.video.VirtualDisplayListener;
import com.genymobile.scrcpy.wrappers.ClipboardManager;
import com.genymobile.scrcpy.wrappers.InputManager;
@ -93,6 +94,9 @@ public class Controller implements AsyncProcessor, VirtualDisplayListener {
private boolean keepDisplayPowerOff;
// Used for resetting video encoding on RESET_VIDEO message
private SurfaceCapture surfaceCapture;
public Controller(int displayId, ControlChannel controlChannel, CleanUp cleanUp, boolean clipboardAutosync, boolean powerOn) {
this.displayId = displayId;
this.controlChannel = controlChannel;
@ -143,6 +147,10 @@ public class Controller implements AsyncProcessor, VirtualDisplayListener {
}
}
public void setSurfaceCapture(SurfaceCapture surfaceCapture) {
this.surfaceCapture = surfaceCapture;
}
private UhidManager getUhidManager() {
if (uhidManager == null) {
uhidManager = new UhidManager(sender);
@ -293,6 +301,9 @@ public class Controller implements AsyncProcessor, VirtualDisplayListener {
case ControlMessage.TYPE_START_APP:
startAppAsync(msg.getText());
break;
case ControlMessage.TYPE_RESET_VIDEO:
resetVideo();
break;
default:
// do nothing
}
@ -680,4 +691,11 @@ public class Controller implements AsyncProcessor, VirtualDisplayListener {
}
}
}
private void resetVideo() {
if (surfaceCapture != null) {
Ln.i("Video capture reset");
surfaceCapture.requestInvalidate();
}
}
}

View file

@ -355,4 +355,9 @@ public class CameraCapture extends SurfaceCapture {
public boolean isClosed() {
return disconnected.get();
}
@Override
public void requestInvalidate() {
// do nothing (the user could not request a reset anyway for now, since there is no controller for camera mirroring)
}
}

View file

@ -14,6 +14,8 @@ import android.hardware.display.VirtualDisplay;
import android.os.Build;
import android.view.Surface;
import java.io.IOException;
public class NewDisplayCapture extends SurfaceCapture {
// Internal fields copied from android.hardware.display.DisplayManager
@ -72,13 +74,8 @@ public class NewDisplayCapture extends SurfaceCapture {
}
}
@Override
public void start(Surface surface) {
if (virtualDisplay != null) {
virtualDisplay.release();
virtualDisplay = null;
}
public void startNew(Surface surface) {
int virtualDisplayId;
try {
int flags = DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC
@ -113,6 +110,15 @@ public class NewDisplayCapture extends SurfaceCapture {
}
}
@Override
public void start(Surface surface) throws IOException {
if (virtualDisplay == null) {
startNew(surface);
} else {
virtualDisplay.setSurface(surface);
}
}
@Override
public void release() {
if (virtualDisplay != null) {
@ -142,4 +148,9 @@ public class NewDisplayCapture extends SurfaceCapture {
int num = size.getMax();
return initialDpi * num / den;
}
@Override
public void requestInvalidate() {
invalidate();
}
}

View file

@ -291,4 +291,9 @@ public class ScreenCapture extends SurfaceCapture {
}
}
}
@Override
public void requestInvalidate() {
invalidate();
}
}

View file

@ -79,4 +79,11 @@ public abstract class SurfaceCapture {
public boolean isClosed() {
return false;
}
/**
* Manually request to invalidate (typically a user request).
* <p>
* The capture implementation is free to ignore the request and do nothing.
*/
public abstract void requestInvalidate();
}