Apply filters to camera capture
Apply crop and orientation to camera capture. Fixes #4426 <https://github.com/Genymobile/scrcpy/issues/4426> PR #5455 <https://github.com/Genymobile/scrcpy/pull/5455>
This commit is contained in:
parent
c32e28bc31
commit
aec0939ead
@ -28,6 +28,7 @@ public final class OpenGLRunner {
|
|||||||
private EGLSurface eglSurface;
|
private EGLSurface eglSurface;
|
||||||
|
|
||||||
private final OpenGLFilter filter;
|
private final OpenGLFilter filter;
|
||||||
|
private final float[] overrideTransformMatrix;
|
||||||
|
|
||||||
private SurfaceTexture surfaceTexture;
|
private SurfaceTexture surfaceTexture;
|
||||||
private Surface inputSurface;
|
private Surface inputSurface;
|
||||||
@ -35,8 +36,13 @@ public final class OpenGLRunner {
|
|||||||
|
|
||||||
private boolean stopped;
|
private boolean stopped;
|
||||||
|
|
||||||
public OpenGLRunner(OpenGLFilter filter) {
|
public OpenGLRunner(OpenGLFilter filter, float[] overrideTransformMatrix) {
|
||||||
this.filter = filter;
|
this.filter = filter;
|
||||||
|
this.overrideTransformMatrix = overrideTransformMatrix;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OpenGLRunner(OpenGLFilter filter) {
|
||||||
|
this(filter, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static synchronized void initOnce() {
|
public static synchronized void initOnce() {
|
||||||
@ -202,8 +208,14 @@ public final class OpenGLRunner {
|
|||||||
GLUtils.checkGlError();
|
GLUtils.checkGlError();
|
||||||
|
|
||||||
surfaceTexture.updateTexImage();
|
surfaceTexture.updateTexImage();
|
||||||
float[] matrix = new float[16];
|
|
||||||
surfaceTexture.getTransformMatrix(matrix);
|
float[] matrix;
|
||||||
|
if (overrideTransformMatrix != null) {
|
||||||
|
matrix = overrideTransformMatrix;
|
||||||
|
} else {
|
||||||
|
matrix = new float[16];
|
||||||
|
surfaceTexture.getTransformMatrix(matrix);
|
||||||
|
}
|
||||||
|
|
||||||
filter.draw(textureId, matrix);
|
filter.draw(textureId, matrix);
|
||||||
|
|
||||||
|
@ -3,7 +3,12 @@ package com.genymobile.scrcpy.video;
|
|||||||
import com.genymobile.scrcpy.AndroidVersions;
|
import com.genymobile.scrcpy.AndroidVersions;
|
||||||
import com.genymobile.scrcpy.Options;
|
import com.genymobile.scrcpy.Options;
|
||||||
import com.genymobile.scrcpy.device.ConfigurationException;
|
import com.genymobile.scrcpy.device.ConfigurationException;
|
||||||
|
import com.genymobile.scrcpy.device.Orientation;
|
||||||
import com.genymobile.scrcpy.device.Size;
|
import com.genymobile.scrcpy.device.Size;
|
||||||
|
import com.genymobile.scrcpy.opengl.AffineOpenGLFilter;
|
||||||
|
import com.genymobile.scrcpy.opengl.OpenGLFilter;
|
||||||
|
import com.genymobile.scrcpy.opengl.OpenGLRunner;
|
||||||
|
import com.genymobile.scrcpy.util.AffineMatrix;
|
||||||
import com.genymobile.scrcpy.util.HandlerExecutor;
|
import com.genymobile.scrcpy.util.HandlerExecutor;
|
||||||
import com.genymobile.scrcpy.util.Ln;
|
import com.genymobile.scrcpy.util.Ln;
|
||||||
import com.genymobile.scrcpy.util.LogUtils;
|
import com.genymobile.scrcpy.util.LogUtils;
|
||||||
@ -41,6 +46,13 @@ import java.util.stream.Stream;
|
|||||||
|
|
||||||
public class CameraCapture extends SurfaceCapture {
|
public class CameraCapture extends SurfaceCapture {
|
||||||
|
|
||||||
|
public static final float[] VFLIP_MATRIX = {
|
||||||
|
1, 0, 0, 0, // column 1
|
||||||
|
0, -1, 0, 0, // column 2
|
||||||
|
0, 0, 1, 0, // column 3
|
||||||
|
0, 1, 0, 1, // column 4
|
||||||
|
};
|
||||||
|
|
||||||
private final String explicitCameraId;
|
private final String explicitCameraId;
|
||||||
private final CameraFacing cameraFacing;
|
private final CameraFacing cameraFacing;
|
||||||
private final Size explicitSize;
|
private final Size explicitSize;
|
||||||
@ -48,9 +60,15 @@ public class CameraCapture extends SurfaceCapture {
|
|||||||
private final CameraAspectRatio aspectRatio;
|
private final CameraAspectRatio aspectRatio;
|
||||||
private final int fps;
|
private final int fps;
|
||||||
private final boolean highSpeed;
|
private final boolean highSpeed;
|
||||||
|
private final Rect crop;
|
||||||
|
private final Orientation captureOrientation;
|
||||||
|
|
||||||
private String cameraId;
|
private String cameraId;
|
||||||
private Size size;
|
private Size captureSize;
|
||||||
|
private Size videoSize; // after OpenGL transforms
|
||||||
|
|
||||||
|
private AffineMatrix transform;
|
||||||
|
private OpenGLRunner glRunner;
|
||||||
|
|
||||||
private HandlerThread cameraThread;
|
private HandlerThread cameraThread;
|
||||||
private Handler cameraHandler;
|
private Handler cameraHandler;
|
||||||
@ -67,6 +85,9 @@ public class CameraCapture extends SurfaceCapture {
|
|||||||
this.aspectRatio = options.getCameraAspectRatio();
|
this.aspectRatio = options.getCameraAspectRatio();
|
||||||
this.fps = options.getCameraFps();
|
this.fps = options.getCameraFps();
|
||||||
this.highSpeed = options.getCameraHighSpeed();
|
this.highSpeed = options.getCameraHighSpeed();
|
||||||
|
this.crop = options.getCrop();
|
||||||
|
this.captureOrientation = options.getCaptureOrientation();
|
||||||
|
assert captureOrientation != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -92,13 +113,26 @@ public class CameraCapture extends SurfaceCapture {
|
|||||||
@Override
|
@Override
|
||||||
public void prepare() throws IOException {
|
public void prepare() throws IOException {
|
||||||
try {
|
try {
|
||||||
size = selectSize(cameraId, explicitSize, maxSize, aspectRatio, highSpeed);
|
captureSize = selectSize(cameraId, explicitSize, maxSize, aspectRatio, highSpeed);
|
||||||
if (size == null) {
|
if (captureSize == null) {
|
||||||
throw new IOException("Could not select camera size");
|
throw new IOException("Could not select camera size");
|
||||||
}
|
}
|
||||||
} catch (CameraAccessException e) {
|
} catch (CameraAccessException e) {
|
||||||
throw new IOException(e);
|
throw new IOException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VideoFilter filter = new VideoFilter(captureSize);
|
||||||
|
|
||||||
|
if (crop != null) {
|
||||||
|
filter.addCrop(crop, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (captureOrientation != Orientation.Orient0) {
|
||||||
|
filter.addOrientation(captureOrientation);
|
||||||
|
}
|
||||||
|
|
||||||
|
transform = filter.getInverseTransform();
|
||||||
|
videoSize = filter.getOutputSize().limit(maxSize).round8();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String selectCamera(String explicitCameraId, CameraFacing cameraFacing) throws CameraAccessException, ConfigurationException {
|
private static String selectCamera(String explicitCameraId, CameraFacing cameraFacing) throws CameraAccessException, ConfigurationException {
|
||||||
@ -214,15 +248,33 @@ public class CameraCapture extends SurfaceCapture {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void start(Surface surface) throws IOException {
|
public void start(Surface surface) throws IOException {
|
||||||
|
if (transform != null) {
|
||||||
|
assert glRunner == null;
|
||||||
|
OpenGLFilter glFilter = new AffineOpenGLFilter(transform);
|
||||||
|
// The transform matrix returned by SurfaceTexture is incorrect for camera capture (it often contains an additional unexpected 90°
|
||||||
|
// rotation). Use a vertical flip transform matrix instead.
|
||||||
|
glRunner = new OpenGLRunner(glFilter, VFLIP_MATRIX);
|
||||||
|
surface = glRunner.start(captureSize, videoSize, surface);
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
CameraCaptureSession session = createCaptureSession(cameraDevice, surface);
|
CameraCaptureSession session = createCaptureSession(cameraDevice, surface);
|
||||||
CaptureRequest request = createCaptureRequest(surface);
|
CaptureRequest request = createCaptureRequest(surface);
|
||||||
setRepeatingRequest(session, request);
|
setRepeatingRequest(session, request);
|
||||||
} catch (CameraAccessException | InterruptedException e) {
|
} catch (CameraAccessException | InterruptedException e) {
|
||||||
|
stop();
|
||||||
throw new IOException(e);
|
throw new IOException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stop() {
|
||||||
|
if (glRunner != null) {
|
||||||
|
glRunner.stopAndRelease();
|
||||||
|
glRunner = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void release() {
|
public void release() {
|
||||||
if (cameraDevice != null) {
|
if (cameraDevice != null) {
|
||||||
@ -235,7 +287,7 @@ public class CameraCapture extends SurfaceCapture {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Size getSize() {
|
public Size getSize() {
|
||||||
return size;
|
return videoSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
Loading…
x
Reference in New Issue
Block a user