mirror of https://github.com/Genymobile/scrcpy
Dissociate virtual display size and capture size
Allow capturing virtual displays at a lower resolution using -m/--max-size. In the original implementation in #5370, the virtual display size was necessarily the same as the capture size. The --max-size value was only allowed to determine the virtual display size when no explicit size was provided. Since the dpi was scaled down accordingly, it is often better to create a virtual display at the target capture size directly. However, not everything is rendered according to the virtual display DPI. For example, a page in Firefox is rendered too big on small virtual displays. Thus, it makes sense to be able create a virtual display at a given size, and capture it at a lower resolution with --max-size. This is now possible using OpenGL filters. Therefore, change the behavior of --max-size for virtual displays: - it does not impact --new-display without size argument anymore (the virtual display size is the main display size); - it is used to limit the capture size (whether an explicit size is provided or not). This new behavior is consistent with main display capture. Refs #5370 comment <https://github.com/Genymobile/scrcpy/pull/5370#issuecomment-2438944401> Refs <https://github.com/Genymobile/scrcpy/pull/5370>
This commit is contained in:
parent
4608a19a13
commit
daba00a819
|
@ -318,14 +318,13 @@ Disable video and audio playback on the computer (equivalent to \fB\-\-no\-video
|
|||
|
||||
.TP
|
||||
\fB\-\-new\-display\fR[=[\fIwidth\fRx\fIheight\fR][/\fIdpi\fR]]
|
||||
Create a new display with the specified resolution and density. If not provided, they default to the main display dimensions and DPI, and \fB\-\-max\-size\fR is considered.
|
||||
Create a new display with the specified resolution and density. If not provided, they default to the main display dimensions and DPI.
|
||||
|
||||
Examples:
|
||||
|
||||
\-\-new\-display=1920x1080
|
||||
\-\-new\-display=1920x1080/420
|
||||
\-\-new\-display # main display size and density
|
||||
\-\-new\-display -m1920 # scaled to fit a max size of 1920
|
||||
\-\-new\-display=/240 # main display size and 240 dpi
|
||||
|
||||
.TP
|
||||
|
|
|
@ -590,12 +590,11 @@ static const struct sc_option options[] = {
|
|||
.optional_arg = true,
|
||||
.text = "Create a new display with the specified resolution and "
|
||||
"density. If not provided, they default to the main display "
|
||||
"dimensions and DPI, and --max-size is considered.\n"
|
||||
"dimensions and DPI.\n"
|
||||
"Examples:\n"
|
||||
" --new-display=1920x1080\n"
|
||||
" --new-display=1920x1080/420 # force 420 dpi\n"
|
||||
" --new-display # main display size and density\n"
|
||||
" --new-display -m1920 # scaled to fit a max size of 1920\n"
|
||||
" --new-display=/240 # main display size and 240 dpi",
|
||||
},
|
||||
{
|
||||
|
@ -2891,13 +2890,6 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
|
|||
LOGE("--new-display is incompatible with --no-video");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (opts->max_size && opts->new_display[0] != '\0'
|
||||
&& opts->new_display[0] != '/') {
|
||||
// An explicit size is defined (not "" nor "/<dpi>")
|
||||
LOGE("Cannot specify both --new-display size and -m/--max-size");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (otg) {
|
||||
|
|
|
@ -193,9 +193,9 @@ phone, landscape for a tablet).
|
|||
|
||||
Cropping is performed before `--capture-orientation` and `--angle`.
|
||||
|
||||
For screen mirroring, `--max-size` is applied after cropping. For camera and
|
||||
virtual display mirroring, `--max-size` is applied first (because it selects the
|
||||
source size rather than resizing it).
|
||||
For display mirroring, `--max-size` is applied after cropping. For camera,
|
||||
`--max-size` is applied first (because it selects the source size rather than
|
||||
resizing the content).
|
||||
|
||||
|
||||
## Display
|
||||
|
|
|
@ -8,7 +8,6 @@ To mirror a new virtual display instead of the device screen:
|
|||
scrcpy --new-display=1920x1080
|
||||
scrcpy --new-display=1920x1080/420 # force 420 dpi
|
||||
scrcpy --new-display # use the main display size and density
|
||||
scrcpy --new-display -m1920 # ... scaled to fit a max size of 1920
|
||||
scrcpy --new-display=/240 # use the main display size and 240 dpi
|
||||
```
|
||||
|
||||
|
|
|
@ -60,7 +60,7 @@ public final class Size {
|
|||
* @return The current size rounded.
|
||||
*/
|
||||
public Size round8() {
|
||||
if ((width & 7) == 0 && (height & 7) == 0) {
|
||||
if (isMultipleOf8()) {
|
||||
// Already a multiple of 8
|
||||
return this;
|
||||
}
|
||||
|
@ -80,6 +80,10 @@ public final class Size {
|
|||
return new Size(w, h);
|
||||
}
|
||||
|
||||
public boolean isMultipleOf8() {
|
||||
return (width & 7) == 0 && (height & 7) == 0;
|
||||
}
|
||||
|
||||
public Rect toRect() {
|
||||
return new Rect(0, 0, width, height);
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ public class NewDisplayCapture extends SurfaceCapture {
|
|||
|
||||
private Size mainDisplaySize;
|
||||
private int mainDisplayDpi;
|
||||
private int maxSize; // only used if newDisplay.getSize() != null
|
||||
private int maxSize;
|
||||
private final Rect crop;
|
||||
private final boolean captureOrientationLocked;
|
||||
private final Orientation captureOrientation;
|
||||
|
@ -101,7 +101,7 @@ public class NewDisplayCapture extends SurfaceCapture {
|
|||
int displayRotation;
|
||||
if (virtualDisplay == null) {
|
||||
if (!newDisplay.hasExplicitSize()) {
|
||||
displaySize = mainDisplaySize.limit(maxSize).round8();
|
||||
displaySize = mainDisplaySize;
|
||||
}
|
||||
if (!newDisplay.hasExplicitDpi()) {
|
||||
dpi = scaleDpi(mainDisplaySize, mainDisplayDpi, displaySize);
|
||||
|
@ -128,10 +128,19 @@ public class NewDisplayCapture extends SurfaceCapture {
|
|||
filter.addOrientation(displayRotation, captureOrientationLocked, captureOrientation);
|
||||
filter.addAngle(angle);
|
||||
|
||||
Size filteredSize = filter.getOutputSize();
|
||||
if (!filteredSize.isMultipleOf8() || (maxSize != 0 && filteredSize.getMax() > maxSize)) {
|
||||
if (maxSize != 0) {
|
||||
filteredSize = filteredSize.limit(maxSize);
|
||||
}
|
||||
filteredSize = filteredSize.round8();
|
||||
filter.addResize(filteredSize);
|
||||
}
|
||||
|
||||
eventTransform = filter.getInverseTransform();
|
||||
|
||||
// DisplayInfo gives the oriented size (so videoSize includes the display rotation)
|
||||
videoSize = filter.getOutputSize().limit(maxSize).round8();
|
||||
videoSize = filter.getOutputSize();
|
||||
|
||||
// But the virtual display video always remains in the origin orientation (the video itself is not rotated, so it must rotated manually).
|
||||
// This additional display rotation must not be included in the input events transform (the expected coordinates are already in the
|
||||
|
@ -231,11 +240,6 @@ public class NewDisplayCapture extends SurfaceCapture {
|
|||
|
||||
@Override
|
||||
public synchronized boolean setMaxSize(int newMaxSize) {
|
||||
if (newDisplay.hasExplicitSize()) {
|
||||
// Cannot retry with a different size if the display size was explicitly provided
|
||||
return false;
|
||||
}
|
||||
|
||||
maxSize = newMaxSize;
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -103,4 +103,17 @@ public class VideoFilter {
|
|||
double ccwAngle = -cwAngle;
|
||||
transform = AffineMatrix.rotate(ccwAngle).withAspectRatio(size).fromCenter().multiply(transform);
|
||||
}
|
||||
|
||||
public void addResize(Size targetSize) {
|
||||
if (size.equals(targetSize)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (transform == null) {
|
||||
// The requested scaling is performed by the viewport (by changing the output size), but the OpenGL filter must still run, even if
|
||||
// resizing is not performed by the shader. So transform MUST NOT be null.
|
||||
transform = AffineMatrix.IDENTITY;
|
||||
}
|
||||
size = targetSize;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue