allow requesting IDR frames through the control channel

This commit is contained in:
Andreas Lüdeke 2025-01-17 12:04:02 +01:00
parent c27d116a66
commit 48b780e95b
No known key found for this signature in database
GPG key ID: 8904863CEE2E3CA0
5 changed files with 34 additions and 0 deletions

View file

@ -156,6 +156,7 @@ public final class Server {
if (controller != null) {
controller.setSurfaceCapture(surfaceCapture);
controller.setSurfaceEncoder(surfaceEncoder);
}
}

View file

@ -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;

View file

@ -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);
}

View file

@ -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();
}
}
}

View file

@ -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);
}
}