mirror of
https://github.com/Genymobile/scrcpy.git
synced 2025-08-11 02:28:57 +00:00
Add option --max-fps
Add an option to limit the capture frame rate. It only works for devices with Android >= 10. Fixes <https://github.com/Genymobile/scrcpy/issues/488>
This commit is contained in:
parent
fb976816f9
commit
1d97d7213d
10 changed files with 87 additions and 12 deletions
|
@ -5,6 +5,7 @@ import android.graphics.Rect;
|
|||
public class Options {
|
||||
private int maxSize;
|
||||
private int bitRate;
|
||||
private int maxFps;
|
||||
private boolean tunnelForward;
|
||||
private Rect crop;
|
||||
private boolean sendFrameMeta; // send PTS so that the client may record properly
|
||||
|
@ -26,6 +27,14 @@ public class Options {
|
|||
this.bitRate = bitRate;
|
||||
}
|
||||
|
||||
public int getMaxFps() {
|
||||
return maxFps;
|
||||
}
|
||||
|
||||
public void setMaxFps(int maxFps) {
|
||||
this.maxFps = maxFps;
|
||||
}
|
||||
|
||||
public boolean isTunnelForward() {
|
||||
return tunnelForward;
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import android.graphics.Rect;
|
|||
import android.media.MediaCodec;
|
||||
import android.media.MediaCodecInfo;
|
||||
import android.media.MediaFormat;
|
||||
import android.os.Build;
|
||||
import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
import android.view.Surface;
|
||||
|
@ -26,18 +27,20 @@ public class ScreenEncoder implements Device.RotationListener {
|
|||
private final ByteBuffer headerBuffer = ByteBuffer.allocate(12);
|
||||
|
||||
private int bitRate;
|
||||
private int maxFps;
|
||||
private int iFrameInterval;
|
||||
private boolean sendFrameMeta;
|
||||
private long ptsOrigin;
|
||||
|
||||
public ScreenEncoder(boolean sendFrameMeta, int bitRate, int iFrameInterval) {
|
||||
public ScreenEncoder(boolean sendFrameMeta, int bitRate, int maxFps, int iFrameInterval) {
|
||||
this.sendFrameMeta = sendFrameMeta;
|
||||
this.bitRate = bitRate;
|
||||
this.maxFps = maxFps;
|
||||
this.iFrameInterval = iFrameInterval;
|
||||
}
|
||||
|
||||
public ScreenEncoder(boolean sendFrameMeta, int bitRate) {
|
||||
this(sendFrameMeta, bitRate, DEFAULT_I_FRAME_INTERVAL);
|
||||
public ScreenEncoder(boolean sendFrameMeta, int bitRate, int maxFps) {
|
||||
this(sendFrameMeta, bitRate, maxFps, DEFAULT_I_FRAME_INTERVAL);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -60,7 +63,7 @@ public class ScreenEncoder implements Device.RotationListener {
|
|||
// <https://github.com/Genymobile/scrcpy/issues/921>
|
||||
Looper.prepareMainLooper();
|
||||
|
||||
MediaFormat format = createFormat(bitRate, iFrameInterval);
|
||||
MediaFormat format = createFormat(bitRate, maxFps, iFrameInterval);
|
||||
device.setRotationListener(this);
|
||||
boolean alive;
|
||||
try {
|
||||
|
@ -143,7 +146,8 @@ public class ScreenEncoder implements Device.RotationListener {
|
|||
return MediaCodec.createEncoderByType("video/avc");
|
||||
}
|
||||
|
||||
private static MediaFormat createFormat(int bitRate, int iFrameInterval) throws IOException {
|
||||
@SuppressWarnings("checkstyle:MagicNumber")
|
||||
private static MediaFormat createFormat(int bitRate, int maxFps, int iFrameInterval) {
|
||||
MediaFormat format = new MediaFormat();
|
||||
format.setString(MediaFormat.KEY_MIME, "video/avc");
|
||||
format.setInteger(MediaFormat.KEY_BIT_RATE, bitRate);
|
||||
|
@ -153,6 +157,13 @@ public class ScreenEncoder implements Device.RotationListener {
|
|||
format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, iFrameInterval);
|
||||
// display the very first frame, and recover from bad quality when no new frames
|
||||
format.setLong(MediaFormat.KEY_REPEAT_PREVIOUS_FRAME_AFTER, REPEAT_FRAME_DELAY_US); // µs
|
||||
if (maxFps > 0) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
format.setFloat(MediaFormat.KEY_MAX_FPS_TO_ENCODER, maxFps);
|
||||
} else {
|
||||
Ln.w("Max FPS is only supported since Android 10, the option has been ignored");
|
||||
}
|
||||
}
|
||||
return format;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ public final class Server {
|
|||
final Device device = new Device(options);
|
||||
boolean tunnelForward = options.isTunnelForward();
|
||||
try (DesktopConnection connection = DesktopConnection.open(device, tunnelForward)) {
|
||||
ScreenEncoder screenEncoder = new ScreenEncoder(options.getSendFrameMeta(), options.getBitRate());
|
||||
ScreenEncoder screenEncoder = new ScreenEncoder(options.getSendFrameMeta(), options.getBitRate(), options.getMaxFps());
|
||||
|
||||
if (options.getControl()) {
|
||||
Controller controller = new Controller(device, connection);
|
||||
|
@ -77,8 +77,8 @@ public final class Server {
|
|||
+ "(" + BuildConfig.VERSION_NAME + ")");
|
||||
}
|
||||
|
||||
if (args.length != 7) {
|
||||
throw new IllegalArgumentException("Expecting 7 parameters");
|
||||
if (args.length != 8) {
|
||||
throw new IllegalArgumentException("Expecting 8 parameters");
|
||||
}
|
||||
|
||||
Options options = new Options();
|
||||
|
@ -89,17 +89,20 @@ public final class Server {
|
|||
int bitRate = Integer.parseInt(args[2]);
|
||||
options.setBitRate(bitRate);
|
||||
|
||||
int maxFps = Integer.parseInt(args[3]);
|
||||
options.setMaxFps(maxFps);
|
||||
|
||||
// use "adb forward" instead of "adb tunnel"? (so the server must listen)
|
||||
boolean tunnelForward = Boolean.parseBoolean(args[3]);
|
||||
boolean tunnelForward = Boolean.parseBoolean(args[4]);
|
||||
options.setTunnelForward(tunnelForward);
|
||||
|
||||
Rect crop = parseCrop(args[4]);
|
||||
Rect crop = parseCrop(args[5]);
|
||||
options.setCrop(crop);
|
||||
|
||||
boolean sendFrameMeta = Boolean.parseBoolean(args[5]);
|
||||
boolean sendFrameMeta = Boolean.parseBoolean(args[6]);
|
||||
options.setSendFrameMeta(sendFrameMeta);
|
||||
|
||||
boolean control = Boolean.parseBoolean(args[6]);
|
||||
boolean control = Boolean.parseBoolean(args[7]);
|
||||
options.setControl(control);
|
||||
|
||||
return options;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue