mirror of
https://github.com/Genymobile/scrcpy.git
synced 2026-04-21 01:33:36 +00:00
Use optimal size alignment
The video was always constrained to use a size that is a multiple of 8. This was sometimes not necessary (recent codecs only require a video size that is a multiple of 2 or even 1) and sometimes insufficient (some codecs require a size that is multiple of 16). Use the size alignment required by the codec. Fixes #4949 <https://github.com/Genymobile/scrcpy/issues/4949> Fixes #6236 <https://github.com/Genymobile/scrcpy/issues/6236> PR #6746 <https://github.com/Genymobile/scrcpy/pull/6746>
This commit is contained in:
parent
5fedc79530
commit
ae8ecb1d0e
7 changed files with 37 additions and 17 deletions
|
|
@ -369,7 +369,7 @@ public class Options {
|
|||
options.audioDup = Boolean.parseBoolean(value);
|
||||
break;
|
||||
case "max_size":
|
||||
options.maxSize = Integer.parseInt(value) & ~7; // multiple of 8
|
||||
options.maxSize = Integer.parseInt(value);
|
||||
break;
|
||||
case "video_bit_rate":
|
||||
options.videoBitRate = Integer.parseInt(value);
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@ public final class Size {
|
|||
|
||||
public Size limit(int maxSize) {
|
||||
assert maxSize >= 0 : "Max size may not be negative";
|
||||
assert maxSize % 8 == 0 : "Max size must be a multiple of 8";
|
||||
|
||||
if (maxSize == 0) {
|
||||
// No limit
|
||||
|
|
@ -55,13 +54,14 @@ public final class Size {
|
|||
}
|
||||
|
||||
/**
|
||||
* Round both dimensions of this size to be a multiple of 8 (as required by many encoders).
|
||||
* Round both dimensions of this size to be multiples of {@code alignment}.
|
||||
*
|
||||
* @return The current size rounded.
|
||||
* @param alignment the required alignment
|
||||
* @return the current size rounded
|
||||
*/
|
||||
public Size round8() {
|
||||
if (isMultipleOf8()) {
|
||||
// Already a multiple of 8
|
||||
public Size round(int alignment) {
|
||||
if (isMultipleOf(alignment)) {
|
||||
// Already aligned
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
@ -69,8 +69,8 @@ public final class Size {
|
|||
int major = portrait ? height : width;
|
||||
int minor = portrait ? width : height;
|
||||
|
||||
major &= ~7; // round down to not exceed the initial size
|
||||
minor = (minor + 4) & ~7; // round to the nearest to minimize aspect ratio distortion
|
||||
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;
|
||||
}
|
||||
|
|
@ -80,8 +80,8 @@ public final class Size {
|
|||
return new Size(w, h);
|
||||
}
|
||||
|
||||
public boolean isMultipleOf8() {
|
||||
return (width & 7) == 0 && (height & 7) == 0;
|
||||
public boolean isMultipleOf(int alignment) {
|
||||
return width % alignment == 0 && height % alignment == 0;
|
||||
}
|
||||
|
||||
public Rect toRect() {
|
||||
|
|
|
|||
|
|
@ -149,7 +149,7 @@ public class CameraCapture extends SurfaceCapture {
|
|||
filter.addAngle(angle);
|
||||
|
||||
transform = filter.getInverseTransform();
|
||||
videoSize = filter.getOutputSize().limit(maxSize).round8();
|
||||
videoSize = filter.getOutputSize().limit(maxSize).round(getAlignment());
|
||||
}
|
||||
|
||||
private static String selectCamera(String explicitCameraId, CameraFacing cameraFacing) throws CameraAccessException, ConfigurationException {
|
||||
|
|
|
|||
|
|
@ -133,12 +133,13 @@ public class NewDisplayCapture extends SurfaceCapture {
|
|||
filter.addOrientation(displayRotation, captureOrientationLocked, captureOrientation);
|
||||
filter.addAngle(angle);
|
||||
|
||||
int alignment = getAlignment();
|
||||
Size filteredSize = filter.getOutputSize();
|
||||
if (!filteredSize.isMultipleOf8() || (maxSize != 0 && filteredSize.getMax() > maxSize)) {
|
||||
if (!filteredSize.isMultipleOf(alignment) || (maxSize != 0 && filteredSize.getMax() > maxSize)) {
|
||||
if (maxSize != 0) {
|
||||
filteredSize = filteredSize.limit(maxSize);
|
||||
}
|
||||
filteredSize = filteredSize.round8();
|
||||
filteredSize = filteredSize.round(alignment);
|
||||
filter.addResize(filteredSize);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ public class ScreenCapture extends SurfaceCapture {
|
|||
filter.addAngle(angle);
|
||||
|
||||
transform = filter.getInverseTransform();
|
||||
videoSize = filter.getOutputSize().limit(maxSize).round8();
|
||||
videoSize = filter.getOutputSize().limit(maxSize).round(getAlignment());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ public abstract class SurfaceCapture {
|
|||
}
|
||||
|
||||
private CaptureListener listener;
|
||||
private int alignment;
|
||||
|
||||
/**
|
||||
* Notify the listener that the capture has been invalidated (for example, because its size changed, or due to a manual user request).
|
||||
|
|
@ -28,8 +29,9 @@ public abstract class SurfaceCapture {
|
|||
/**
|
||||
* Called once before the first capture starts.
|
||||
*/
|
||||
public final void init(CaptureListener listener) throws ConfigurationException, IOException {
|
||||
public final void init(CaptureListener listener, int alignment) throws ConfigurationException, IOException {
|
||||
this.listener = listener;
|
||||
this.alignment = alignment;
|
||||
init();
|
||||
}
|
||||
|
||||
|
|
@ -86,4 +88,15 @@ public abstract class SurfaceCapture {
|
|||
public boolean isClosed() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
protected int getAlignment() {
|
||||
return alignment;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65,9 +65,15 @@ public class SurfaceEncoder implements AsyncProcessor {
|
|||
private void streamCapture() throws IOException, ConfigurationException {
|
||||
Codec codec = streamer.getCodec();
|
||||
MediaCodec mediaCodec = createMediaCodec(codec, encoderName);
|
||||
|
||||
MediaCodecInfo.VideoCapabilities caps = mediaCodec.getCodecInfo().getCapabilitiesForType(codec.getMimeType())
|
||||
.getVideoCapabilities();
|
||||
int alignment = caps != null ? Math.max(caps.getWidthAlignment(), caps.getHeightAlignment()) : 8;
|
||||
Ln.d("Video codec size alignment requirement: " + alignment + "px");
|
||||
|
||||
MediaFormat format = createFormat(codec.getMimeType(), videoBitRate, maxFps, codecOptions);
|
||||
|
||||
capture.init(reset);
|
||||
capture.init(reset, alignment);
|
||||
|
||||
try {
|
||||
boolean alive;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue