Respect encoder minimum size constraint

Encoders require a minimum video size.

Use video capabilities to constrain a given size by the declared minimum
size of the selected encoder.

Contrary to the maximum size constraints (but like the alignment
constraint), use the same value in both directions for simplicity and so
that rotating the device does not change the shape of the video.

PR #6766 <https://github.com/Genymobile/scrcpy/pull/6766>
This commit is contained in:
Romain Vimont 2026-04-10 22:48:44 +02:00
parent 33b1bc6209
commit 66005e8889
4 changed files with 42 additions and 3 deletions

View file

@ -72,6 +72,15 @@ public final class Size {
assert w <= maxWidth : "The width cannot exceed maxWidth";
assert h <= maxHeight : "The height cannot exceed maxHeight";
// Minimum codec size must be respected (regardless of requested maxSize)
int minCodecSize = constraints.getMinCodecSize();
if (w < minCodecSize) {
w = minCodecSize;
}
if (h < minCodecSize) {
h = minCodecSize;
}
return new Size(w, h);
}

View file

@ -73,7 +73,11 @@ public class SurfaceEncoder implements AsyncProcessor {
int maxPortraitWidth = caps.getSupportedWidthsFor(maxPortraitHeight).getUpper();
Size maxPortraitSize = new Size(maxPortraitWidth, maxPortraitHeight);
return new VideoConstraints(maxSize, alignment, maxLandscapeSize, maxPortraitSize);
int minWidth = caps.getSupportedWidths().getLower();
int minHeight = caps.getSupportedHeights().getLower();
int minSize = Math.max(minWidth, minHeight);
return new VideoConstraints(maxSize, alignment, maxLandscapeSize, maxPortraitSize, minSize);
}
private void streamCapture() throws IOException, ConfigurationException {

View file

@ -7,8 +7,9 @@ public class VideoConstraints {
private final int alignment;
private final Size maxCodecLandscapeSize;
private final Size maxCodecPortraitSize;
private final int minCodecSize;
public VideoConstraints(int maxSize, int alignment, Size maxCodecLandscapeSize, Size maxCodecPortraitSize) {
public VideoConstraints(int maxSize, int alignment, Size maxCodecLandscapeSize, Size maxCodecPortraitSize, int minCodecSize) {
assert maxSize >= 0 : "Max size must not be negative";
this.maxSize = maxSize;
@ -21,6 +22,9 @@ public class VideoConstraints {
assert maxCodecPortraitSize != null;
this.maxCodecPortraitSize = maxCodecPortraitSize;
assert minCodecSize >= 0;
this.minCodecSize = minCodecSize;
}
/**
@ -60,4 +64,13 @@ public class VideoConstraints {
public Size getMaxCodecPortraitSize() {
return maxCodecPortraitSize;
}
/**
* Return the min size supported by the codec.
*
* @return the min size
*/
public int getMinCodecSize() {
return minCodecSize;
}
}

View file

@ -13,7 +13,11 @@ public class SizeTest {
}
private VideoConstraints createVideoConstraints(int maxSize, int alignment, Size maxCodecSize) {
return new VideoConstraints(maxSize, alignment, maxCodecSize, maxCodecSize);
return new VideoConstraints(maxSize, alignment, maxCodecSize, maxCodecSize, 0);
}
private VideoConstraints createVideoConstraints(int maxSize, int alignment, Size maxCodecSize, int minCodecSize) {
return new VideoConstraints(maxSize, alignment, maxCodecSize, maxCodecSize, minCodecSize);
}
@Test
@ -59,4 +63,13 @@ public class SizeTest {
Assert.assertEquals(new Size(400, 536 * 400 / 512), size.constrain(createVideoConstraints(500, 1, maxCodecSize)));
Assert.assertEquals(new Size(512 * 410 / 536, 410), size.constrain(createVideoConstraints(410, 1, maxCodecSize)));
}
@Test
public void testConstrainMinCodecSize() {
Size maxCodecSize = new Size(1024, 1024);
Size size = new Size(800, 600);
Assert.assertEquals(new Size(800, 600), size.constrain(createVideoConstraints(800, 1, maxCodecSize, 512)));
Assert.assertEquals(new Size(512, 512), size.constrain(createVideoConstraints(400, 1, maxCodecSize, 512)));
}
}