Accept float values for --max-fps

Android accepts a float value, there is no reason to limit the option
to be an integer.

In particular, it allows to capture at a rate lower than 1 fps. For
example, to capture 1 frame every 5 seconds:

    scrcpy --video-source=camera --max-fps=0.2

It was already possible to pass a float manually:

    scrcpy --video-source=camera \
        --video-codec-options=max-fps-to-encoder:float=0.2

But accepting a float directly for --max-fps is more convenient.

Refs <https://developer.android.com/reference/android/media/MediaFormat#KEY_MAX_FPS_TO_ENCODER>
This commit is contained in:
Romain Vimont
2024-09-13 20:03:50 +02:00
parent 6451ad271a
commit 265a15e0b1
8 changed files with 69 additions and 14 deletions

View File

@@ -29,7 +29,7 @@ public class Options {
private boolean audioDup;
private int videoBitRate = 8000000;
private int audioBitRate = 128000;
private int maxFps;
private float maxFps;
private int lockVideoOrientation = -1;
private boolean tunnelForward;
private Rect crop;
@@ -113,7 +113,7 @@ public class Options {
return audioBitRate;
}
public int getMaxFps() {
public float getMaxFps() {
return maxFps;
}
@@ -321,7 +321,7 @@ public class Options {
options.audioBitRate = Integer.parseInt(value);
break;
case "max_fps":
options.maxFps = Integer.parseInt(value);
options.maxFps = parseFloat("max_fps", value);
break;
case "lock_video_orientation":
options.lockVideoOrientation = Integer.parseInt(value);
@@ -493,4 +493,12 @@ public class Options {
float floatAr = Float.parseFloat(tokens[0]);
return CameraAspectRatio.fromFloat(floatAr);
}
private static float parseFloat(String key, String value) {
try {
return Float.parseFloat(value);
} catch (NumberFormatException e) {
throw new IllegalArgumentException("Invalid float value for " + key + ": \"" + value + "\"");
}
}
}

View File

@@ -39,7 +39,7 @@ public class SurfaceEncoder implements AsyncProcessor {
private final String encoderName;
private final List<CodecOption> codecOptions;
private final int videoBitRate;
private final int maxFps;
private final float maxFps;
private final boolean downsizeOnError;
private boolean firstFrameSent;
@@ -48,8 +48,8 @@ public class SurfaceEncoder implements AsyncProcessor {
private Thread thread;
private final AtomicBoolean stopped = new AtomicBoolean();
public SurfaceEncoder(SurfaceCapture capture, Streamer streamer, int videoBitRate, int maxFps, List<CodecOption> codecOptions, String encoderName,
boolean downsizeOnError) {
public SurfaceEncoder(SurfaceCapture capture, Streamer streamer, int videoBitRate, float maxFps, List<CodecOption> codecOptions,
String encoderName, boolean downsizeOnError) {
this.capture = capture;
this.streamer = streamer;
this.videoBitRate = videoBitRate;
@@ -225,7 +225,7 @@ public class SurfaceEncoder implements AsyncProcessor {
}
}
private static MediaFormat createFormat(String videoMimeType, int bitRate, int maxFps, List<CodecOption> codecOptions) {
private static MediaFormat createFormat(String videoMimeType, int bitRate, float maxFps, List<CodecOption> codecOptions) {
MediaFormat format = new MediaFormat();
format.setString(MediaFormat.KEY_MIME, videoMimeType);
format.setInteger(MediaFormat.KEY_BIT_RATE, bitRate);