Introduce VideoConstraints

Group video constraints into a dedicated class. For now it only contains
the `alignment` field; additional constraints will be added in further
commits.

PR #6766 <https://github.com/Genymobile/scrcpy/pull/6766>
This commit is contained in:
Romain Vimont 2026-04-11 18:06:29 +02:00
parent 3c3cfe8cc6
commit 5b6e2cfdd4
8 changed files with 59 additions and 27 deletions

View file

@ -1,5 +1,7 @@
package com.genymobile.scrcpy.device;
import com.genymobile.scrcpy.video.VideoConstraints;
import android.graphics.Rect;
import java.util.Objects;
@ -29,7 +31,9 @@ public final class Size {
return new Size(height, width);
}
public Size constrain(int maxSize, int alignment) {
public Size constrain(int maxSize, VideoConstraints constraints) {
int alignment = constraints.getAlignment();
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";

View file

@ -149,7 +149,7 @@ public class CameraCapture extends SurfaceCapture {
filter.addAngle(angle);
transform = filter.getInverseTransform();
videoSize = filter.getOutputSize().constrain(maxSize, getAlignment());
videoSize = filter.getOutputSize().constrain(maxSize, getVideoConstraints());
}
private static String selectCamera(String explicitCameraId, CameraFacing cameraFacing) throws CameraAccessException, ConfigurationException {

View file

@ -134,7 +134,7 @@ public class NewDisplayCapture extends SurfaceCapture {
filter.addAngle(angle);
Size outputSize = filter.getOutputSize();
Size filteredSize = outputSize.constrain(maxSize, getAlignment());
Size filteredSize = outputSize.constrain(maxSize, getVideoConstraints());
if (!filteredSize.equals(outputSize)) {
filter.addResize(filteredSize);
}

View file

@ -97,7 +97,7 @@ public class ScreenCapture extends SurfaceCapture {
filter.addAngle(angle);
transform = filter.getInverseTransform();
videoSize = filter.getOutputSize().constrain(maxSize, getAlignment());
videoSize = filter.getOutputSize().constrain(maxSize, getVideoConstraints());
}
@Override

View file

@ -17,7 +17,7 @@ public abstract class SurfaceCapture {
}
private CaptureListener listener;
private int alignment;
private VideoConstraints constraints;
/**
* Notify the listener that the capture has been invalidated (for example, because its size changed, or due to a manual user request).
@ -29,9 +29,9 @@ public abstract class SurfaceCapture {
/**
* Called once before the first capture starts.
*/
public final void init(CaptureListener listener, int alignment) throws ConfigurationException, IOException {
public final void init(CaptureListener listener, VideoConstraints constraints) throws ConfigurationException, IOException {
this.listener = listener;
this.alignment = alignment;
this.constraints = constraints;
init();
}
@ -83,13 +83,11 @@ public abstract class SurfaceCapture {
}
/**
* Return the video alignment
* <p>
* This a power-of-2 value that the video width and height must be multiples of.
* Return the video constraints.
*
* @return the video alignment
* @return the video constraints
*/
protected int getAlignment() {
return alignment;
protected VideoConstraints getVideoConstraints() {
return constraints;
}
}

View file

@ -67,8 +67,9 @@ public class SurfaceEncoder implements AsyncProcessor {
alignment = minSizeAlignment;
Ln.d("Actual video size alignment: " + alignment + "px");
}
VideoConstraints constraints = new VideoConstraints(alignment);
capture.init(reset, alignment);
capture.init(reset, constraints);
try {
boolean alive;

View file

@ -0,0 +1,22 @@
package com.genymobile.scrcpy.video;
public class VideoConstraints {
private final int alignment;
public VideoConstraints(int alignment) {
assert alignment > 0 : "Alignment must be positive";
assert (alignment & (alignment - 1)) == 0 : "Alignment must be a power-of-two";
this.alignment = alignment;
}
/**
* Return the video alignment.
* <p>
* This a power-of-2 value that the video width and height must be multiples of.
*
* @return the video alignment
*/
public int getAlignment() {
return alignment;
}
}

View file

@ -1,35 +1,42 @@
package com.genymobile.scrcpy.device;
import com.genymobile.scrcpy.video.VideoConstraints;
import org.junit.Assert;
import org.junit.Test;
public class SizeTest {
private VideoConstraints createVideoConstraints(int alignment) {
return new VideoConstraints(alignment);
}
@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));
Assert.assertEquals(size, size.constrain(0, createVideoConstraints(1)));
Assert.assertEquals(new Size(208, 210), size.constrain(0, createVideoConstraints(2)));
Assert.assertEquals(new Size(208, 208), size.constrain(0, createVideoConstraints(4)));
Size s = size.constrain(208, 2);
Size s = size.constrain(208, createVideoConstraints(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));
Assert.assertEquals(new Size(207 * 208 / 209, 208), size.constrain(208, createVideoConstraints(2)));
Assert.assertEquals(new Size(208, 208), size.constrain(208, createVideoConstraints(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));
Assert.assertEquals(size, size.constrain(0, createVideoConstraints(1)));
Assert.assertEquals(size, size.constrain(512, createVideoConstraints(1)));
Assert.assertEquals(size, size.constrain(515, createVideoConstraints(1)));
Assert.assertEquals(size, size.constrain(512, createVideoConstraints(16)));
Assert.assertEquals(size, size.constrain(515, createVideoConstraints(16)));
Assert.assertEquals(size, size.constrain(0, createVideoConstraints(16)));
Assert.assertEquals(size, size.constrain(4096, createVideoConstraints(16)));
}
}