From 76c2c6e69dc074031a81c4e050347e374cbfb776 Mon Sep 17 00:00:00 2001 From: Tzah Mazuz Date: Mon, 12 Oct 2020 12:23:06 +0300 Subject: [PATCH] Adding new option --encoder Some devices have more than one encoder, and some encoders may cause issues or crash. With this option we can specify which encoder we want the device to use. PR #1827 Fixes #1810 Signed-off-by: Romain Vimont --- app/src/cli.c | 8 ++++++++ app/src/scrcpy.c | 1 + app/src/scrcpy.h | 2 ++ app/src/server.c | 1 + app/src/server.h | 1 + .../src/main/java/com/genymobile/scrcpy/Options.java | 9 +++++++++ .../java/com/genymobile/scrcpy/ScreenEncoder.java | 12 +++++++++--- .../src/main/java/com/genymobile/scrcpy/Server.java | 8 ++++++-- 8 files changed, 37 insertions(+), 5 deletions(-) diff --git a/app/src/cli.c b/app/src/cli.c index 4f15f2e8d5..f01b7941f8 100644 --- a/app/src/cli.c +++ b/app/src/cli.c @@ -53,6 +53,9 @@ scrcpy_print_usage(const char *arg0) { "\n" " Default is 0.\n" "\n" + " --encoder name\n" + " Use a specific MediaCodec encoder (must be a H.264 encoder).\n" + "\n" " --force-adb-forward\n" " Do not attempt to use \"adb reverse\" to connect to the\n" " the device.\n" @@ -664,6 +667,7 @@ guess_record_format(const char *filename) { #define OPT_NO_KEY_REPEAT 1022 #define OPT_FORWARD_ALL_CLICKS 1023 #define OPT_LEGACY_PASTE 1024 +#define OPT_ENCODER_NAME 1025 bool scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]) { @@ -675,6 +679,7 @@ scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]) { {"disable-screensaver", no_argument, NULL, OPT_DISABLE_SCREENSAVER}, {"display", required_argument, NULL, OPT_DISPLAY_ID}, + {"encoder", required_argument, NULL, OPT_ENCODER_NAME}, {"force-adb-forward", no_argument, NULL, OPT_FORCE_ADB_FORWARD}, {"forward-all-clicks", no_argument, NULL, @@ -861,6 +866,9 @@ scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]) { case OPT_CODEC_OPTIONS: opts->codec_options = optarg; break; + case OPT_ENCODER_NAME: + opts->encoder_name = optarg; + break; case OPT_FORCE_ADB_FORWARD: opts->force_adb_forward = true; break; diff --git a/app/src/scrcpy.c b/app/src/scrcpy.c index eae9a1eb8a..a543e11c77 100644 --- a/app/src/scrcpy.c +++ b/app/src/scrcpy.c @@ -318,6 +318,7 @@ scrcpy(const struct scrcpy_options *options) { .show_touches = options->show_touches, .stay_awake = options->stay_awake, .codec_options = options->codec_options, + .encoder_name = options->encoder_name, .force_adb_forward = options->force_adb_forward, }; if (!server_start(&server, options->serial, ¶ms)) { diff --git a/app/src/scrcpy.h b/app/src/scrcpy.h index 5f761f75e5..8548d1f708 100644 --- a/app/src/scrcpy.h +++ b/app/src/scrcpy.h @@ -51,6 +51,7 @@ struct scrcpy_options { const char *push_target; const char *render_driver; const char *codec_options; + const char *encoder_name; enum sc_log_level log_level; enum sc_record_format record_format; struct sc_port_range port_range; @@ -91,6 +92,7 @@ struct scrcpy_options { .push_target = NULL, \ .render_driver = NULL, \ .codec_options = NULL, \ + .encoder_name = NULL, \ .log_level = SC_LOG_LEVEL_INFO, \ .record_format = SC_RECORD_FORMAT_AUTO, \ .port_range = { \ diff --git a/app/src/server.c b/app/src/server.c index 422bbfa58a..9267356b28 100644 --- a/app/src/server.c +++ b/app/src/server.c @@ -294,6 +294,7 @@ execute_server(struct server *server, const struct server_params *params) { params->show_touches ? "true" : "false", params->stay_awake ? "true" : "false", params->codec_options ? params->codec_options : "-", + params->encoder_name ? params->encoder_name : "-", }; #ifdef SERVER_DEBUGGER LOGI("Server debugger waiting for a client on device port " diff --git a/app/src/server.h b/app/src/server.h index 254afe30e1..30ce09bc58 100644 --- a/app/src/server.h +++ b/app/src/server.h @@ -48,6 +48,7 @@ struct server_params { enum sc_log_level log_level; const char *crop; const char *codec_options; + const char *encoder_name; struct sc_port_range port_range; uint16_t max_size; uint32_t bit_rate; diff --git a/server/src/main/java/com/genymobile/scrcpy/Options.java b/server/src/main/java/com/genymobile/scrcpy/Options.java index 06312a37a5..150d06a83d 100644 --- a/server/src/main/java/com/genymobile/scrcpy/Options.java +++ b/server/src/main/java/com/genymobile/scrcpy/Options.java @@ -16,6 +16,7 @@ public class Options { private boolean showTouches; private boolean stayAwake; private String codecOptions; + private String encoderName; public Ln.Level getLogLevel() { return logLevel; @@ -120,4 +121,12 @@ public String getCodecOptions() { public void setCodecOptions(String codecOptions) { this.codecOptions = codecOptions; } + + public String getEncoderName() { + return encoderName; + } + + public void setEncoderName(String encoderName) { + this.encoderName = encoderName; + } } diff --git a/server/src/main/java/com/genymobile/scrcpy/ScreenEncoder.java b/server/src/main/java/com/genymobile/scrcpy/ScreenEncoder.java index d722388c85..ee9ea93506 100644 --- a/server/src/main/java/com/genymobile/scrcpy/ScreenEncoder.java +++ b/server/src/main/java/com/genymobile/scrcpy/ScreenEncoder.java @@ -26,17 +26,19 @@ public class ScreenEncoder implements Device.RotationListener { private final AtomicBoolean rotationChanged = new AtomicBoolean(); private final ByteBuffer headerBuffer = ByteBuffer.allocate(12); + private String encoderName; private List codecOptions; private int bitRate; private int maxFps; private boolean sendFrameMeta; private long ptsOrigin; - public ScreenEncoder(boolean sendFrameMeta, int bitRate, int maxFps, List codecOptions) { + public ScreenEncoder(boolean sendFrameMeta, int bitRate, int maxFps, List codecOptions, String encoderName) { this.sendFrameMeta = sendFrameMeta; this.bitRate = bitRate; this.maxFps = maxFps; this.codecOptions = codecOptions; + this.encoderName = encoderName; } @Override @@ -69,7 +71,7 @@ private void internalStreamScreen(Device device, FileDescriptor fd) throws IOExc boolean alive; try { do { - MediaCodec codec = createCodec(); + MediaCodec codec = createCodec(encoderName); IBinder display = createDisplay(); ScreenInfo screenInfo = device.getScreenInfo(); Rect contentRect = screenInfo.getContentRect(); @@ -150,7 +152,11 @@ private void writeFrameMeta(FileDescriptor fd, MediaCodec.BufferInfo bufferInfo, IO.writeFully(fd, headerBuffer); } - private static MediaCodec createCodec() throws IOException { + private static MediaCodec createCodec(String encoderName) throws IOException { + if (encoderName != null) { + Ln.d("Creating encoder by name: '" + encoderName + "'"); + return MediaCodec.createByCodecName(encoderName); + } return MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_VIDEO_AVC); } diff --git a/server/src/main/java/com/genymobile/scrcpy/Server.java b/server/src/main/java/com/genymobile/scrcpy/Server.java index 9b7f9de8f7..0e7bd244bd 100644 --- a/server/src/main/java/com/genymobile/scrcpy/Server.java +++ b/server/src/main/java/com/genymobile/scrcpy/Server.java @@ -54,7 +54,8 @@ private static void scrcpy(Options options) throws IOException { boolean tunnelForward = options.isTunnelForward(); try (DesktopConnection connection = DesktopConnection.open(device, tunnelForward)) { - ScreenEncoder screenEncoder = new ScreenEncoder(options.getSendFrameMeta(), options.getBitRate(), options.getMaxFps(), codecOptions); + ScreenEncoder screenEncoder = new ScreenEncoder(options.getSendFrameMeta(), options.getBitRate(), options.getMaxFps(), codecOptions, + options.getEncoderName()); if (options.getControl()) { final Controller controller = new Controller(device, connection); @@ -120,7 +121,7 @@ private static Options createOptions(String... args) { "The server version (" + BuildConfig.VERSION_NAME + ") does not match the client " + "(" + clientVersion + ")"); } - final int expectedParameters = 14; + final int expectedParameters = 15; if (args.length != expectedParameters) { throw new IllegalArgumentException("Expecting " + expectedParameters + " parameters"); } @@ -167,6 +168,9 @@ private static Options createOptions(String... args) { String codecOptions = args[13]; options.setCodecOptions(codecOptions); + String encoderName = "-".equals(args[14]) ? null : args[14]; + options.setEncoderName(encoderName); + return options; }