Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/data/bash-completion/scrcpy
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ _scrcpy() {
-G
--gamepad=
-h --help
--ignore-video-encoder-constraints
-K
--keep-active
--keyboard=
Expand Down
1 change: 1 addition & 0 deletions app/data/zsh-completion/_scrcpy
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ arguments=(
'-G[Use UHID/AOA gamepad \(same as --gamepad=uhid or --gamepad=aoa, depending on OTG mode\)]'
'--gamepad=[Set the gamepad input mode]:mode:(disabled uhid aoa)'
{-h,--help}'[Print the help]'
'--ignore-video-encoder-constraints[Do not consider video encoder capabilities]'
'-K[Use UHID/AOA keyboard \(same as --keyboard=uhid or --keyboard=aoa, depending on OTG mode\)]'
'--keep-active[Keep the screen on by simulating user activity]'
'--keyboard=[Set the keyboard input mode]:mode:(disabled sdk uhid aoa)'
Expand Down
8 changes: 8 additions & 0 deletions app/scrcpy.1
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,14 @@ Also see \fB\-\-keyboard\fR and R\fB\-\-mouse\fR.
.B \-h, \-\-help
Print this help.

.TP
.B \-\-ignore\-video\-encoder\-constraints
Do not consider video encoder capabilities.

This is useful if the reported capabilities are incorrect.

It may help to force a value for \fB\-\-min\-size\-alignment\fR.

.TP
.B \-K
Same as \fB\-\-keyboard=uhid\fR, or \fB\-\-keyboard=aoa\fR if \fB\-\-otg\fR is set.
Expand Down
11 changes: 11 additions & 0 deletions app/src/cli.c
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ enum {
OPT_KEEP_ACTIVE,
OPT_BACKGROUND_COLOR,
OPT_RENDER_FIT,
OPT_IGNORE_VIDEO_ENCODER_CONSTRAINTS,
};

struct sc_option {
Expand Down Expand Up @@ -428,6 +429,13 @@ static const struct sc_option options[] = {
.longopt = "help",
.text = "Print this help.",
},
{
.longopt_id = OPT_IGNORE_VIDEO_ENCODER_CONSTRAINTS,
.longopt = "ignore-video-encoder-constraints",
.text = "Do not consider video encoder capabilities.\n"
"This is useful if the reported capabilities are incorrect.\n"
"It may help to force a value for --min-size-alignment.",
},
{
.shortopt = 'K',
.text = "Same as --keyboard=uhid, or --keyboard=aoa if --otg is set.",
Expand Down Expand Up @@ -2917,6 +2925,9 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
case 'x':
opts->flex_display = true;
break;
case OPT_IGNORE_VIDEO_ENCODER_CONSTRAINTS:
opts->ignore_video_encoder_constraints = true;
break;
default:
// getopt prints the error message on stderr
return false;
Expand Down
1 change: 1 addition & 0 deletions app/src/options.c
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ const struct scrcpy_options scrcpy_options_default = {
.camera_torch = false,
.keep_active = false,
.flex_display = false,
.ignore_video_encoder_constraints = false,
};

enum sc_orientation
Expand Down
1 change: 1 addition & 0 deletions app/src/options.h
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,7 @@ struct scrcpy_options {
bool camera_torch;
bool keep_active;
bool flex_display;
bool ignore_video_encoder_constraints;
};

extern const struct scrcpy_options scrcpy_options_default;
Expand Down
2 changes: 2 additions & 0 deletions app/src/scrcpy.c
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,8 @@ scrcpy(struct scrcpy_options *options) {
.vd_system_decorations = options->vd_system_decorations,
.keep_active = options->keep_active,
.flex_display = options->flex_display,
.ignore_video_encoder_constraints =
options->ignore_video_encoder_constraints,
.list = options->list,
};

Expand Down
3 changes: 3 additions & 0 deletions app/src/server.c
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,9 @@ execute_server(struct sc_server *server,
if (params->flex_display) {
ADD_PARAM("flex_display=true");
}
if (params->ignore_video_encoder_constraints) {
ADD_PARAM("ignore_video_encoder_constraints=true");
}
if (params->display_ime_policy != SC_DISPLAY_IME_POLICY_UNDEFINED) {
ADD_PARAM("display_ime_policy=%s",
sc_server_get_display_ime_policy_name(params->display_ime_policy));
Expand Down
1 change: 1 addition & 0 deletions app/src/server.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ struct sc_server_params {
bool vd_system_decorations;
bool keep_active;
bool flex_display;
bool ignore_video_encoder_constraints;
uint8_t list;
};

Expand Down
8 changes: 8 additions & 0 deletions server/src/main/java/com/genymobile/scrcpy/Options.java
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ public class Options {
private boolean flexDisplay;

private boolean keepActive;
private boolean ignoreVideoEncoderConstraints;

private Orientation.Lock captureOrientationLock = Orientation.Lock.Unlocked;
private Orientation captureOrientation = Orientation.Orient0;
Expand Down Expand Up @@ -274,6 +275,10 @@ public boolean getFlexDisplay() {
return flexDisplay;
}

public boolean getIgnoreVideoEncoderConstraints() {
return ignoreVideoEncoderConstraints;
}

public boolean getList() {
return listEncoders || listDisplays || listCameras || listCameraSizes || listApps;
}
Expand Down Expand Up @@ -539,6 +544,9 @@ public static Options parse(String... args) {
case "keep_active":
options.keepActive = Boolean.parseBoolean(value);
break;
case "ignore_video_encoder_constraints":
options.ignoreVideoEncoderConstraints = Boolean.parseBoolean(value);
break;
case "send_device_meta":
options.sendDeviceMeta = Boolean.parseBoolean(value);
break;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ public class SurfaceEncoder implements AsyncProcessor {
private final float maxFps;
private final boolean downsizeOnError;
private final int minSizeAlignment;
private final boolean ignoreVideoEncoderConstraints;

private boolean firstFrameSent;
private int consecutiveErrors;
Expand All @@ -64,29 +65,44 @@ public SurfaceEncoder(SurfaceCapture capture, Streamer streamer, Options options
this.encoderName = options.getVideoEncoder();
this.downsizeOnError = options.getDownsizeOnError();
this.minSizeAlignment = options.getMinSizeAlignment();
this.ignoreVideoEncoderConstraints = options.getIgnoreVideoEncoderConstraints();
}

private static VideoConstraints createVideoConstraints(int maxSize, int minSizeAlignment, MediaCodecInfo.VideoCapabilities caps) {
assert caps != null;
int alignment = Math.max(caps.getWidthAlignment(), caps.getHeightAlignment());
Ln.d("Video codec size alignment requirement: " + alignment + "px");
if (alignment < minSizeAlignment) {
int alignment;
Size maxLandscapeSize;
Size maxPortraitSize;
int minSize;
if (caps != null) {
alignment = Math.max(caps.getWidthAlignment(), caps.getHeightAlignment());
Ln.d("Video codec size alignment requirement: " + alignment + "px");
if (alignment < minSizeAlignment) {
alignment = minSizeAlignment;
Ln.d("Actual video size alignment: " + alignment + "px");
}

int maxLandscapeWidth = caps.getSupportedWidths().getUpper();
int maxLandscapeHeight = caps.getSupportedHeightsFor(maxLandscapeWidth).getUpper();
maxLandscapeSize = new Size(maxLandscapeWidth, maxLandscapeHeight);
Ln.d("Maximum landscape size: " + maxLandscapeSize);

int maxPortraitHeight = caps.getSupportedHeights().getUpper();
int maxPortraitWidth = caps.getSupportedWidthsFor(maxPortraitHeight).getUpper();
maxPortraitSize = new Size(maxPortraitWidth, maxPortraitHeight);
Ln.d("Maximum portrait size: " + maxPortraitSize);

int minWidth = caps.getSupportedWidths().getLower();
int minHeight = caps.getSupportedHeights().getLower();
minSize = Math.max(minWidth, minHeight);
Ln.d("Minimum size: " + minSize);
} else {
alignment = minSizeAlignment;
Ln.d("Actual video size alignment: " + alignment + "px");
maxLandscapeSize = new Size(8192, 8192);
maxPortraitSize = maxLandscapeSize;
minSize = 0;
}

int maxLandscapeWidth = caps.getSupportedWidths().getUpper();
int maxLandscapeHeight = caps.getSupportedHeightsFor(maxLandscapeWidth).getUpper();
Size maxLandscapeSize = new Size(maxLandscapeWidth, maxLandscapeHeight);

int maxPortraitHeight = caps.getSupportedHeights().getUpper();
int maxPortraitWidth = caps.getSupportedWidthsFor(maxPortraitHeight).getUpper();
Size maxPortraitSize = new Size(maxPortraitWidth, maxPortraitHeight);

int minWidth = caps.getSupportedWidths().getLower();
int minHeight = caps.getSupportedHeights().getLower();
int minSize = Math.max(minWidth, minHeight);

return new VideoConstraints(maxSize, alignment, maxLandscapeSize, maxPortraitSize, minSize);
}

Expand All @@ -95,8 +111,14 @@ private void streamCapture() throws IOException, ConfigurationException {
MediaCodec mediaCodec = createMediaCodec(codec, encoderName);
MediaFormat format = createFormat(codec.getMimeType(), videoBitRate, maxFps, codecOptions);

MediaCodecInfo.VideoCapabilities caps = mediaCodec.getCodecInfo().getCapabilitiesForType(codec.getMimeType()).getVideoCapabilities();
assert caps != null; // caps cannot be null for a video codec
MediaCodecInfo.VideoCapabilities caps;
if (ignoreVideoEncoderConstraints) {
caps = null;
} else {
caps = mediaCodec.getCodecInfo().getCapabilitiesForType(codec.getMimeType()).getVideoCapabilities();
assert caps != null; // caps cannot be null for a video codec
}

VideoConstraints constraints = createVideoConstraints(maxSize, minSizeAlignment, caps);

capture.init(captureControl, constraints);
Expand Down