Add a command-line parameter to pass custom options to the device encoder (as a comma-separated list of "key[:type]=value"). The list of possible codec options is available in the Android documentation: <https://d.android.com/reference/android/media/MediaFormat> PR #1325 <https://github.com/Genymobile/scrcpy/pull/1325> Refs #1226 <https://github.com/Genymobile/scrcpy/pull/1226> Co-authored-by: Romain Vimont <rom@rom1v.com>master
parent
c7155a1954
commit
080a4ee365
@ -0,0 +1,112 @@
|
|||||||
|
package com.genymobile.scrcpy;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class CodecOption {
|
||||||
|
private String key;
|
||||||
|
private Object value;
|
||||||
|
|
||||||
|
public CodecOption(String key, Object value) {
|
||||||
|
this.key = key;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getKey() {
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<CodecOption> parse(String codecOptions) {
|
||||||
|
if ("-".equals(codecOptions)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<CodecOption> result = new ArrayList<>();
|
||||||
|
|
||||||
|
boolean escape = false;
|
||||||
|
StringBuilder buf = new StringBuilder();
|
||||||
|
|
||||||
|
for (char c : codecOptions.toCharArray()) {
|
||||||
|
switch (c) {
|
||||||
|
case '\\':
|
||||||
|
if (escape) {
|
||||||
|
buf.append('\\');
|
||||||
|
escape = false;
|
||||||
|
} else {
|
||||||
|
escape = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ',':
|
||||||
|
if (escape) {
|
||||||
|
buf.append(',');
|
||||||
|
escape = false;
|
||||||
|
} else {
|
||||||
|
// This comma is a separator between codec options
|
||||||
|
String codecOption = buf.toString();
|
||||||
|
result.add(parseOption(codecOption));
|
||||||
|
// Clear buf
|
||||||
|
buf.setLength(0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
buf.append(c);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buf.length() > 0) {
|
||||||
|
String codecOption = buf.toString();
|
||||||
|
result.add(parseOption(codecOption));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static CodecOption parseOption(String option) {
|
||||||
|
int equalSignIndex = option.indexOf('=');
|
||||||
|
if (equalSignIndex == -1) {
|
||||||
|
throw new IllegalArgumentException("'=' expected");
|
||||||
|
}
|
||||||
|
String keyAndType = option.substring(0, equalSignIndex);
|
||||||
|
if (keyAndType.length() == 0) {
|
||||||
|
throw new IllegalArgumentException("Key may not be null");
|
||||||
|
}
|
||||||
|
|
||||||
|
String key;
|
||||||
|
String type;
|
||||||
|
|
||||||
|
int colonIndex = keyAndType.indexOf(':');
|
||||||
|
if (colonIndex != -1) {
|
||||||
|
key = keyAndType.substring(0, colonIndex);
|
||||||
|
type = keyAndType.substring(colonIndex + 1);
|
||||||
|
} else {
|
||||||
|
key = keyAndType;
|
||||||
|
type = "int"; // assume int by default
|
||||||
|
}
|
||||||
|
|
||||||
|
Object value;
|
||||||
|
String valueString = option.substring(equalSignIndex + 1);
|
||||||
|
switch (type) {
|
||||||
|
case "int":
|
||||||
|
value = Integer.parseInt(valueString);
|
||||||
|
break;
|
||||||
|
case "long":
|
||||||
|
value = Long.parseLong(valueString);
|
||||||
|
break;
|
||||||
|
case "float":
|
||||||
|
value = Float.parseFloat(valueString);
|
||||||
|
break;
|
||||||
|
case "string":
|
||||||
|
value = valueString;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("Invalid codec option type (int, long, float, str): " + type);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new CodecOption(key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,114 @@
|
|||||||
|
package com.genymobile.scrcpy;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class CodecOptionsTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIntegerImplicit() {
|
||||||
|
List<CodecOption> codecOptions = CodecOption.parse("some_key=5");
|
||||||
|
|
||||||
|
Assert.assertEquals(1, codecOptions.size());
|
||||||
|
|
||||||
|
CodecOption option = codecOptions.get(0);
|
||||||
|
Assert.assertEquals("some_key", option.getKey());
|
||||||
|
Assert.assertEquals(5, option.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInteger() {
|
||||||
|
List<CodecOption> codecOptions = CodecOption.parse("some_key:int=5");
|
||||||
|
|
||||||
|
Assert.assertEquals(1, codecOptions.size());
|
||||||
|
|
||||||
|
CodecOption option = codecOptions.get(0);
|
||||||
|
Assert.assertEquals("some_key", option.getKey());
|
||||||
|
Assert.assertTrue(option.getValue() instanceof Integer);
|
||||||
|
Assert.assertEquals(5, option.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLong() {
|
||||||
|
List<CodecOption> codecOptions = CodecOption.parse("some_key:long=5");
|
||||||
|
|
||||||
|
Assert.assertEquals(1, codecOptions.size());
|
||||||
|
|
||||||
|
CodecOption option = codecOptions.get(0);
|
||||||
|
Assert.assertEquals("some_key", option.getKey());
|
||||||
|
Assert.assertTrue(option.getValue() instanceof Long);
|
||||||
|
Assert.assertEquals(5L, option.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFloat() {
|
||||||
|
List<CodecOption> codecOptions = CodecOption.parse("some_key:float=4.5");
|
||||||
|
|
||||||
|
Assert.assertEquals(1, codecOptions.size());
|
||||||
|
|
||||||
|
CodecOption option = codecOptions.get(0);
|
||||||
|
Assert.assertEquals("some_key", option.getKey());
|
||||||
|
Assert.assertTrue(option.getValue() instanceof Float);
|
||||||
|
Assert.assertEquals(4.5f, option.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testString() {
|
||||||
|
List<CodecOption> codecOptions = CodecOption.parse("some_key:string=some_value");
|
||||||
|
|
||||||
|
Assert.assertEquals(1, codecOptions.size());
|
||||||
|
|
||||||
|
CodecOption option = codecOptions.get(0);
|
||||||
|
Assert.assertEquals("some_key", option.getKey());
|
||||||
|
Assert.assertTrue(option.getValue() instanceof String);
|
||||||
|
Assert.assertEquals("some_value", option.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testStringEscaped() {
|
||||||
|
List<CodecOption> codecOptions = CodecOption.parse("some_key:string=warning\\,this_is_not=a_new_key");
|
||||||
|
|
||||||
|
Assert.assertEquals(1, codecOptions.size());
|
||||||
|
|
||||||
|
CodecOption option = codecOptions.get(0);
|
||||||
|
Assert.assertEquals("some_key", option.getKey());
|
||||||
|
Assert.assertTrue(option.getValue() instanceof String);
|
||||||
|
Assert.assertEquals("warning,this_is_not=a_new_key", option.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testList() {
|
||||||
|
List<CodecOption> codecOptions = CodecOption.parse("a=1,b:int=2,c:long=3,d:float=4.5,e:string=a\\,b=c");
|
||||||
|
|
||||||
|
Assert.assertEquals(5, codecOptions.size());
|
||||||
|
|
||||||
|
CodecOption option;
|
||||||
|
|
||||||
|
option = codecOptions.get(0);
|
||||||
|
Assert.assertEquals("a", option.getKey());
|
||||||
|
Assert.assertTrue(option.getValue() instanceof Integer);
|
||||||
|
Assert.assertEquals(1, option.getValue());
|
||||||
|
|
||||||
|
option = codecOptions.get(1);
|
||||||
|
Assert.assertEquals("b", option.getKey());
|
||||||
|
Assert.assertTrue(option.getValue() instanceof Integer);
|
||||||
|
Assert.assertEquals(2, option.getValue());
|
||||||
|
|
||||||
|
option = codecOptions.get(2);
|
||||||
|
Assert.assertEquals("c", option.getKey());
|
||||||
|
Assert.assertTrue(option.getValue() instanceof Long);
|
||||||
|
Assert.assertEquals(3L, option.getValue());
|
||||||
|
|
||||||
|
option = codecOptions.get(3);
|
||||||
|
Assert.assertEquals("d", option.getKey());
|
||||||
|
Assert.assertTrue(option.getValue() instanceof Float);
|
||||||
|
Assert.assertEquals(4.5f, option.getValue());
|
||||||
|
|
||||||
|
option = codecOptions.get(4);
|
||||||
|
Assert.assertEquals("e", option.getKey());
|
||||||
|
Assert.assertTrue(option.getValue() instanceof String);
|
||||||
|
Assert.assertEquals("a,b=c", option.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in new issue