mirror of
https://github.com/Genymobile/scrcpy.git
synced 2026-04-21 01:33:36 +00:00
Constraint size and alignment simultaneously
Previously, the size was scaled to fit the requested maximum size and then aligned. If the maximum size was not a multiple of the alignment, the resulting size was suboptimal as it preserved the aspect ratio less accurately. This also prepares for additional video constraints. PR #6766 <https://github.com/Genymobile/scrcpy/pull/6766>
This commit is contained in:
parent
4f97e2e30b
commit
3c3cfe8cc6
5 changed files with 61 additions and 54 deletions
|
|
@ -29,59 +29,35 @@ public final class Size {
|
|||
return new Size(height, width);
|
||||
}
|
||||
|
||||
public Size limit(int maxSize) {
|
||||
public Size constrain(int maxSize, int alignment) {
|
||||
assert maxSize >= 0 : "Max size may not be negative";
|
||||
assert alignment > 0 : "Alignment must be positive";
|
||||
assert (alignment & (alignment - 1)) == 0 : "Alignment must be a power-of-two";
|
||||
|
||||
if (maxSize == 0) {
|
||||
// No limit
|
||||
return this;
|
||||
int alignedMaxSize = maxSize / alignment * alignment; // round to a multiple of alignment
|
||||
int w, h;
|
||||
|
||||
if (maxSize > 0 && (width > alignedMaxSize || height > alignedMaxSize)) {
|
||||
if (width > height) {
|
||||
w = alignedMaxSize;
|
||||
h = round(height * alignedMaxSize / width, alignment);
|
||||
} else {
|
||||
w = round(width * alignedMaxSize / height, alignment);
|
||||
h = alignedMaxSize;
|
||||
}
|
||||
} else {
|
||||
w = round(width, alignment);
|
||||
h = round(height, alignment);
|
||||
}
|
||||
|
||||
boolean portrait = height > width;
|
||||
int major = portrait ? height : width;
|
||||
if (major <= maxSize) {
|
||||
return this;
|
||||
}
|
||||
assert maxSize == 0 || w <= maxSize : "The width cannot exceed maxSize if maxSize is aligned";
|
||||
assert maxSize == 0 || h <= maxSize : "The height cannot exceed maxSize if maxSize is aligned";
|
||||
|
||||
int minor = portrait ? width : height;
|
||||
|
||||
int newMajor = maxSize;
|
||||
int newMinor = maxSize * minor / major;
|
||||
|
||||
int w = portrait ? newMinor : newMajor;
|
||||
int h = portrait ? newMajor : newMinor;
|
||||
return new Size(w, h);
|
||||
}
|
||||
|
||||
/**
|
||||
* Round both dimensions of this size to be multiples of {@code alignment}.
|
||||
*
|
||||
* @param alignment the required alignment
|
||||
* @return the current size rounded
|
||||
*/
|
||||
public Size round(int alignment) {
|
||||
if (isMultipleOf(alignment)) {
|
||||
// Already aligned
|
||||
return this;
|
||||
}
|
||||
|
||||
boolean portrait = height > width;
|
||||
int major = portrait ? height : width;
|
||||
int minor = portrait ? width : height;
|
||||
|
||||
major = major / alignment * alignment; // round down to not exceed the initial size
|
||||
minor = (minor + (alignment / 2)) / alignment * alignment; // round to the nearest to minimize aspect ratio distortion
|
||||
if (minor > major) {
|
||||
minor = major;
|
||||
}
|
||||
|
||||
int w = portrait ? minor : major;
|
||||
int h = portrait ? major : minor;
|
||||
return new Size(w, h);
|
||||
}
|
||||
|
||||
public boolean isMultipleOf(int alignment) {
|
||||
return width % alignment == 0 && height % alignment == 0;
|
||||
private static int round(int value, int alignment) {
|
||||
return (value + (alignment / 2)) / alignment * alignment;
|
||||
}
|
||||
|
||||
public Rect toRect() {
|
||||
|
|
|
|||
|
|
@ -149,7 +149,7 @@ public class CameraCapture extends SurfaceCapture {
|
|||
filter.addAngle(angle);
|
||||
|
||||
transform = filter.getInverseTransform();
|
||||
videoSize = filter.getOutputSize().limit(maxSize).round(getAlignment());
|
||||
videoSize = filter.getOutputSize().constrain(maxSize, getAlignment());
|
||||
}
|
||||
|
||||
private static String selectCamera(String explicitCameraId, CameraFacing cameraFacing) throws CameraAccessException, ConfigurationException {
|
||||
|
|
|
|||
|
|
@ -133,13 +133,9 @@ public class NewDisplayCapture extends SurfaceCapture {
|
|||
filter.addOrientation(displayRotation, captureOrientationLocked, captureOrientation);
|
||||
filter.addAngle(angle);
|
||||
|
||||
int alignment = getAlignment();
|
||||
Size filteredSize = filter.getOutputSize();
|
||||
if (!filteredSize.isMultipleOf(alignment) || (maxSize != 0 && filteredSize.getMax() > maxSize)) {
|
||||
if (maxSize != 0) {
|
||||
filteredSize = filteredSize.limit(maxSize);
|
||||
}
|
||||
filteredSize = filteredSize.round(alignment);
|
||||
Size outputSize = filter.getOutputSize();
|
||||
Size filteredSize = outputSize.constrain(maxSize, getAlignment());
|
||||
if (!filteredSize.equals(outputSize)) {
|
||||
filter.addResize(filteredSize);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ public class ScreenCapture extends SurfaceCapture {
|
|||
filter.addAngle(angle);
|
||||
|
||||
transform = filter.getInverseTransform();
|
||||
videoSize = filter.getOutputSize().limit(maxSize).round(getAlignment());
|
||||
videoSize = filter.getOutputSize().constrain(maxSize, getAlignment());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
package com.genymobile.scrcpy.device;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class SizeTest {
|
||||
@Test
|
||||
public void testConstrainSize() {
|
||||
Size size = new Size(207, 209);
|
||||
|
||||
Assert.assertEquals(size, size.constrain(0, 1));
|
||||
Assert.assertEquals(new Size(208, 210), size.constrain(0, 2));
|
||||
Assert.assertEquals(new Size(208, 208), size.constrain(0, 4));
|
||||
|
||||
Size s = size.constrain(208, 2);
|
||||
Assert.assertEquals(208, s.getHeight());
|
||||
Assert.assertTrue(s.getWidth() >= 206 && s.getWidth() <= 208 && s.getWidth() % 2 == 0);
|
||||
|
||||
Assert.assertEquals(new Size(207 * 208 / 209, 208), size.constrain(208, 2));
|
||||
Assert.assertEquals(new Size(208, 208), size.constrain(208, 4));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConstrainSizeUnchanged() {
|
||||
Size size = new Size(256, 512);
|
||||
|
||||
Assert.assertEquals(size, size.constrain(0, 1));
|
||||
Assert.assertEquals(size, size.constrain(512, 1));
|
||||
Assert.assertEquals(size, size.constrain(515, 1));
|
||||
Assert.assertEquals(size, size.constrain(512, 16));
|
||||
Assert.assertEquals(size, size.constrain(515, 16));
|
||||
Assert.assertEquals(size, size.constrain(0, 16));
|
||||
Assert.assertEquals(size, size.constrain(4096, 16));
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue