mirror of
https://github.com/Genymobile/scrcpy.git
synced 2025-04-20 19:45:00 +00:00
Changing codec-profile -> codec-options
This commit is contained in:
parent
eaef1c1f47
commit
c265d6306e
5 changed files with 86 additions and 25 deletions
25
server/src/main/java/com/genymobile/scrcpy/CodecOptions.java
Normal file
25
server/src/main/java/com/genymobile/scrcpy/CodecOptions.java
Normal file
|
@ -0,0 +1,25 @@
|
|||
package com.genymobile.scrcpy;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
public class CodecOptions {
|
||||
static final String PROFILE_OPTION = "profile";
|
||||
static final String LEVEL_OPTION = "level";
|
||||
|
||||
private HashMap<String, String> options;
|
||||
|
||||
CodecOptions(HashMap<String, String> options) {
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
Object parseValue(String profileOption) {
|
||||
String value = options.get(profileOption);
|
||||
switch (profileOption) {
|
||||
case PROFILE_OPTION:
|
||||
case LEVEL_OPTION:
|
||||
return NumberUtils.tryParseInt(value);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
16
server/src/main/java/com/genymobile/scrcpy/NumberUtils.java
Normal file
16
server/src/main/java/com/genymobile/scrcpy/NumberUtils.java
Normal file
|
@ -0,0 +1,16 @@
|
|||
package com.genymobile.scrcpy;
|
||||
|
||||
public class NumberUtils {
|
||||
|
||||
public static int tryParseInt(final String str) {
|
||||
return tryParseInt(str, 0);
|
||||
}
|
||||
|
||||
public static int tryParseInt(final String str, int defaultValue) {
|
||||
try {
|
||||
return Integer.parseInt(str);
|
||||
} catch (NumberFormatException e) {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,7 +11,7 @@ public class Options {
|
|||
private Rect crop;
|
||||
private boolean sendFrameMeta; // send PTS so that the client may record properly
|
||||
private boolean control;
|
||||
private int codecProfile;
|
||||
private CodecOptions codecOptions;
|
||||
|
||||
public int getMaxSize() {
|
||||
return maxSize;
|
||||
|
@ -77,11 +77,11 @@ public class Options {
|
|||
this.control = control;
|
||||
}
|
||||
|
||||
public int getCodecProfile() {
|
||||
return codecProfile;
|
||||
public CodecOptions getCodecOptions() {
|
||||
return codecOptions;
|
||||
}
|
||||
|
||||
public void setCodecProfile(int codecProfile) {
|
||||
this.codecProfile = codecProfile;
|
||||
public void setCodecOptions(CodecOptions codecOptions) {
|
||||
this.codecOptions = codecOptions;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,8 @@ import java.io.IOException;
|
|||
import java.nio.ByteBuffer;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import static android.media.MediaFormat.MIMETYPE_VIDEO_AVC;
|
||||
|
||||
public class ScreenEncoder implements Device.RotationListener {
|
||||
|
||||
private static final int DEFAULT_I_FRAME_INTERVAL = 10; // seconds
|
||||
|
@ -30,21 +32,21 @@ public class ScreenEncoder implements Device.RotationListener {
|
|||
private int maxFps;
|
||||
private int lockedVideoOrientation;
|
||||
private int iFrameInterval;
|
||||
private int codecProfile;
|
||||
private boolean sendFrameMeta;
|
||||
private long ptsOrigin;
|
||||
private CodecOptions codecOptions;
|
||||
|
||||
public ScreenEncoder(boolean sendFrameMeta, int bitRate, int maxFps, int lockedVideoOrientation, int codecProfile, int iFrameInterval) {
|
||||
public ScreenEncoder(boolean sendFrameMeta, int bitRate, int maxFps, int lockedVideoOrientation, CodecOptions codecOptions, int iFrameInterval) {
|
||||
this.sendFrameMeta = sendFrameMeta;
|
||||
this.bitRate = bitRate;
|
||||
this.maxFps = maxFps;
|
||||
this.lockedVideoOrientation = lockedVideoOrientation;
|
||||
this.codecProfile = codecProfile;
|
||||
this.codecOptions = codecOptions;
|
||||
this.iFrameInterval = iFrameInterval;
|
||||
}
|
||||
|
||||
public ScreenEncoder(boolean sendFrameMeta, int bitRate, int maxFps, int lockedVideoOrientation, int codecProfile) {
|
||||
this(sendFrameMeta, bitRate, maxFps, lockedVideoOrientation, codecProfile, DEFAULT_I_FRAME_INTERVAL);
|
||||
public ScreenEncoder(boolean sendFrameMeta, int bitRate, int maxFps, int lockedVideoOrientation, CodecOptions codecOptions) {
|
||||
this(sendFrameMeta, bitRate, maxFps, lockedVideoOrientation, codecOptions, DEFAULT_I_FRAME_INTERVAL);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -142,30 +144,35 @@ public class ScreenEncoder implements Device.RotationListener {
|
|||
IO.writeFully(fd, headerBuffer);
|
||||
}
|
||||
|
||||
private void setCodecProfile(MediaCodec codec, MediaFormat format) throws IOException {
|
||||
if(codecProfile == 0) return;
|
||||
int level = 0;
|
||||
for (MediaCodecInfo.CodecProfileLevel profileLevel : codec.getCodecInfo().getCapabilitiesForType("video/avc").profileLevels) {
|
||||
if(profileLevel.profile == codecProfile) {
|
||||
private void setCodecProfile(MediaCodec codec, MediaFormat format) {
|
||||
int profile = (int)codecOptions.parseValue(CodecOptions.PROFILE_OPTION);
|
||||
int level = (int)codecOptions.parseValue(CodecOptions.LEVEL_OPTION);
|
||||
if(profile == 0) return;
|
||||
for (MediaCodecInfo.CodecProfileLevel profileLevel : codec.getCodecInfo().getCapabilitiesForType(MIMETYPE_VIDEO_AVC).profileLevels) {
|
||||
if(profileLevel.profile == profile) {
|
||||
level = Math.max(level, profileLevel.level);
|
||||
}
|
||||
}
|
||||
if(level == 0) throw new IOException("Device doesn't support the requested codec profile.");
|
||||
// Profile (SDK Level 21) and Level (SDK Level 23).
|
||||
format.setInteger(MediaFormat.KEY_PROFILE, codecProfile);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
format.setInteger(MediaFormat.KEY_LEVEL, level);
|
||||
if(level == 0) {
|
||||
Ln.w("Device doesn't support the requested codec profile.\n" +
|
||||
"Profile and level will be chosen automatically.");
|
||||
} else {
|
||||
// Profile (SDK Level 21) and Level (SDK Level 23).
|
||||
format.setInteger(MediaFormat.KEY_PROFILE, profile);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
format.setInteger(MediaFormat.KEY_LEVEL, level);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static MediaCodec createCodec() throws IOException {
|
||||
return MediaCodec.createEncoderByType("video/avc");
|
||||
return MediaCodec.createEncoderByType(MIMETYPE_VIDEO_AVC);
|
||||
}
|
||||
|
||||
@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.setString(MediaFormat.KEY_MIME, MIMETYPE_VIDEO_AVC);
|
||||
format.setInteger(MediaFormat.KEY_BIT_RATE, bitRate);
|
||||
// must be present to configure the encoder, but does not impact the actual frame rate, which is variable
|
||||
format.setInteger(MediaFormat.KEY_FRAME_RATE, 60);
|
||||
|
|
|
@ -6,6 +6,7 @@ import android.os.Build;
|
|||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
|
||||
public final class Server {
|
||||
|
||||
|
@ -20,7 +21,7 @@ public final class Server {
|
|||
boolean tunnelForward = options.isTunnelForward();
|
||||
try (DesktopConnection connection = DesktopConnection.open(device, tunnelForward)) {
|
||||
ScreenEncoder screenEncoder = new ScreenEncoder(options.getSendFrameMeta(), options.getBitRate(), options.getMaxFps(),
|
||||
options.getLockedVideoOrientation(), options.getCodecProfile());
|
||||
options.getLockedVideoOrientation(), options.getCodecOptions());
|
||||
|
||||
if (options.getControl()) {
|
||||
Controller controller = new Controller(device, connection);
|
||||
|
@ -98,8 +99,8 @@ public final class Server {
|
|||
int lockedVideoOrientation = Integer.parseInt(args[4]);
|
||||
options.setLockedVideoOrientation(lockedVideoOrientation);
|
||||
|
||||
int codecProfile = Integer.parseInt(args[5]);
|
||||
options.setCodecProfile(codecProfile);
|
||||
CodecOptions codecOptions = parseCodecOptions(args[5]);
|
||||
options.setCodecOptions(codecOptions);
|
||||
|
||||
// use "adb forward" instead of "adb tunnel"? (so the server must listen)
|
||||
boolean tunnelForward = Boolean.parseBoolean(args[6]);
|
||||
|
@ -134,6 +135,18 @@ public final class Server {
|
|||
return new Rect(x, y, x + width, y + height);
|
||||
}
|
||||
|
||||
private static CodecOptions parseCodecOptions(String codecOptions) {
|
||||
HashMap<String, String> codecOptionsMap = new HashMap<>();
|
||||
if (!"-".equals(codecOptions)) {
|
||||
String[] pairs = codecOptions.split(",");
|
||||
for (String pair : pairs) {
|
||||
String[] option = pair.split("=");
|
||||
codecOptionsMap.put(option[0], option.length > 1 ? option[1] : null);
|
||||
}
|
||||
}
|
||||
return new CodecOptions(codecOptionsMap);
|
||||
}
|
||||
|
||||
private static void unlinkSelf() {
|
||||
try {
|
||||
new File(SERVER_PATH).delete();
|
||||
|
|
Loading…
Add table
Reference in a new issue