Compare commits
7 Commits
content-re
...
server_deb
Author | SHA1 | Date | |
---|---|---|---|
0200760f87 | |||
bd9d93194b | |||
794595e3f0 | |||
5e10c37f02 | |||
0e399b65bd | |||
2337f524d1 | |||
df74cceb6f |
@ -167,9 +167,6 @@ conf.set('DEFAULT_LOCAL_PORT_RANGE_LAST', '27199')
|
||||
# run a server debugger and wait for a client to be attached
|
||||
conf.set('SERVER_DEBUGGER', get_option('server_debugger'))
|
||||
|
||||
# select the debugger method ('old' for Android < 9, 'new' for Android >= 9)
|
||||
conf.set('SERVER_DEBUGGER_METHOD_NEW', get_option('server_debugger_method') == 'new')
|
||||
|
||||
# enable V4L2 support (linux only)
|
||||
conf.set('HAVE_V4L2', v4l2_support)
|
||||
|
||||
|
@ -183,6 +183,27 @@ validate_string(const char *s) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static uint16_t
|
||||
get_device_sdk_version(struct sc_server *server) {
|
||||
struct sc_intr *intr = &server->intr;
|
||||
|
||||
char *sdk_version =
|
||||
sc_adb_getprop(intr, server->serial, "ro.build.version.sdk",
|
||||
SC_ADB_SILENT);
|
||||
if (!sdk_version) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
long value;
|
||||
bool ok = sc_str_parse_integer(sdk_version, &value);
|
||||
free(sdk_version);
|
||||
if (!ok || value < 0 || value > 0xFFFF) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static sc_pid
|
||||
execute_server(struct sc_server *server,
|
||||
const struct sc_server_params *params) {
|
||||
@ -201,18 +222,26 @@ execute_server(struct sc_server *server,
|
||||
cmd[count++] = "app_process";
|
||||
|
||||
#ifdef SERVER_DEBUGGER
|
||||
uint16_t sdk_version = get_device_sdk_version(server);
|
||||
if (!sdk_version) {
|
||||
LOGE("Could not determine SDK version");
|
||||
return 0;
|
||||
}
|
||||
|
||||
# define SERVER_DEBUGGER_PORT "5005"
|
||||
cmd[count++] =
|
||||
# ifdef SERVER_DEBUGGER_METHOD_NEW
|
||||
/* Android 9 and above */
|
||||
"-XjdwpProvider:internal -XjdwpOptions:transport=dt_socket,suspend=y,"
|
||||
"server=y,address="
|
||||
# else
|
||||
/* Android 8 and below */
|
||||
"-agentlib:jdwp=transport=dt_socket,suspend=y,server=y,address="
|
||||
# endif
|
||||
SERVER_DEBUGGER_PORT;
|
||||
const char *dbg;
|
||||
if (sdk_version < 28) {
|
||||
// Android < 9
|
||||
dbg = "-agentlib:jdwp=transport=dt_socket,suspend=y,server=y,address="
|
||||
SERVER_DEBUGGER_PORT;
|
||||
} else {
|
||||
// Android >= 9
|
||||
dbg = "-XjdwpProvider:internal -XjdwpOptions:transport=dt_socket,"
|
||||
"suspend=y,server=y,address=" SERVER_DEBUGGER_PORT;
|
||||
}
|
||||
cmd[count++] = dbg;
|
||||
#endif
|
||||
|
||||
cmd[count++] = "/"; // unused
|
||||
cmd[count++] = "com.genymobile.scrcpy.Server";
|
||||
cmd[count++] = SCRCPY_VERSION;
|
||||
|
@ -3,6 +3,5 @@ option('compile_server', type: 'boolean', value: true, description: 'Build the s
|
||||
option('prebuilt_server', type: 'string', description: 'Path of the prebuilt server')
|
||||
option('portable', type: 'boolean', value: false, description: 'Use scrcpy-server from the same directory as the scrcpy executable')
|
||||
option('server_debugger', type: 'boolean', value: false, description: 'Run a server debugger and wait for a client to be attached')
|
||||
option('server_debugger_method', type: 'combo', choices: ['old', 'new'], value: 'new', description: 'Select the debugger method (Android < 9: "old", Android >= 9: "new")')
|
||||
option('v4l2', type: 'boolean', value: true, description: 'Enable V4L2 feature when supported')
|
||||
option('usb', type: 'boolean', value: true, description: 'Enable HID/OTG features when supported')
|
||||
|
@ -25,13 +25,13 @@ public final class CleanUp {
|
||||
|
||||
private Thread thread;
|
||||
|
||||
private CleanUp(int displayId, Options options) {
|
||||
thread = new Thread(() -> runCleanUp(displayId, options), "cleanup");
|
||||
private CleanUp(Options options) {
|
||||
thread = new Thread(() -> runCleanUp(options), "cleanup");
|
||||
thread.start();
|
||||
}
|
||||
|
||||
public static CleanUp start(int displayId, Options options) {
|
||||
return new CleanUp(displayId, options);
|
||||
public static CleanUp start(Options options) {
|
||||
return new CleanUp(options);
|
||||
}
|
||||
|
||||
public void interrupt() {
|
||||
@ -42,7 +42,7 @@ public final class CleanUp {
|
||||
thread.join();
|
||||
}
|
||||
|
||||
private void runCleanUp(int displayId, Options options) {
|
||||
private void runCleanUp(Options options) {
|
||||
boolean disableShowTouches = false;
|
||||
if (options.getShowTouches()) {
|
||||
try {
|
||||
@ -93,6 +93,7 @@ public final class CleanUp {
|
||||
}
|
||||
|
||||
boolean powerOffScreen = options.getPowerOffScreenOnClose();
|
||||
int displayId = options.getDisplayId();
|
||||
|
||||
try {
|
||||
run(displayId, restoreStayOn, disableShowTouches, powerOffScreen, restoreScreenOffTimeout);
|
||||
|
@ -479,6 +479,11 @@ public class Options {
|
||||
}
|
||||
}
|
||||
|
||||
if (options.newDisplay != null) {
|
||||
assert options.displayId == 0 : "Must not set both displayId and newDisplay";
|
||||
options.displayId = Device.DISPLAY_ID_NONE;
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
|
@ -103,11 +103,8 @@ public final class Server {
|
||||
|
||||
CleanUp cleanUp = null;
|
||||
|
||||
NewDisplay newDisplay = options.getNewDisplay();
|
||||
int displayId = newDisplay == null ? options.getDisplayId() : Device.DISPLAY_ID_NONE;
|
||||
|
||||
if (options.getCleanup()) {
|
||||
cleanUp = CleanUp.start(displayId, options);
|
||||
cleanUp = CleanUp.start(options);
|
||||
}
|
||||
|
||||
int scid = options.getScid();
|
||||
@ -131,7 +128,7 @@ public final class Server {
|
||||
|
||||
if (control) {
|
||||
ControlChannel controlChannel = connection.getControlChannel();
|
||||
controller = new Controller(displayId, controlChannel, cleanUp, options.getClipboardAutosync(), options.getPowerOn());
|
||||
controller = new Controller(controlChannel, cleanUp, options);
|
||||
asyncProcessors.add(controller);
|
||||
}
|
||||
|
||||
@ -150,8 +147,7 @@ public final class Server {
|
||||
if (audioCodec == AudioCodec.RAW) {
|
||||
audioRecorder = new AudioRawRecorder(audioCapture, audioStreamer);
|
||||
} else {
|
||||
audioRecorder = new AudioEncoder(audioCapture, audioStreamer, options.getAudioBitRate(), options.getAudioCodecOptions(),
|
||||
options.getAudioEncoder());
|
||||
audioRecorder = new AudioEncoder(audioCapture, audioStreamer, options);
|
||||
}
|
||||
asyncProcessors.add(audioRecorder);
|
||||
}
|
||||
@ -161,19 +157,17 @@ public final class Server {
|
||||
options.getSendFrameMeta());
|
||||
SurfaceCapture surfaceCapture;
|
||||
if (options.getVideoSource() == VideoSource.DISPLAY) {
|
||||
NewDisplay newDisplay = options.getNewDisplay();
|
||||
if (newDisplay != null) {
|
||||
surfaceCapture = new NewDisplayCapture(controller, newDisplay, options.getMaxSize());
|
||||
surfaceCapture = new NewDisplayCapture(controller, options);
|
||||
} else {
|
||||
assert displayId != Device.DISPLAY_ID_NONE;
|
||||
surfaceCapture = new ScreenCapture(controller, displayId, options.getMaxSize(), options.getCrop(),
|
||||
options.getLockVideoOrientation());
|
||||
assert options.getDisplayId() != Device.DISPLAY_ID_NONE;
|
||||
surfaceCapture = new ScreenCapture(controller, options);
|
||||
}
|
||||
} else {
|
||||
surfaceCapture = new CameraCapture(options.getCameraId(), options.getCameraFacing(), options.getCameraSize(),
|
||||
options.getMaxSize(), options.getCameraAspectRatio(), options.getCameraFps(), options.getCameraHighSpeed());
|
||||
surfaceCapture = new CameraCapture(options);
|
||||
}
|
||||
SurfaceEncoder surfaceEncoder = new SurfaceEncoder(surfaceCapture, videoStreamer, options.getVideoBitRate(), options.getMaxFps(),
|
||||
options.getVideoCodecOptions(), options.getVideoEncoder(), options.getDownsizeOnError());
|
||||
SurfaceEncoder surfaceEncoder = new SurfaceEncoder(surfaceCapture, videoStreamer, options);
|
||||
asyncProcessors.add(surfaceEncoder);
|
||||
|
||||
if (controller != null) {
|
||||
|
@ -2,6 +2,7 @@ package com.genymobile.scrcpy.audio;
|
||||
|
||||
import com.genymobile.scrcpy.AndroidVersions;
|
||||
import com.genymobile.scrcpy.AsyncProcessor;
|
||||
import com.genymobile.scrcpy.Options;
|
||||
import com.genymobile.scrcpy.device.ConfigurationException;
|
||||
import com.genymobile.scrcpy.device.Streamer;
|
||||
import com.genymobile.scrcpy.util.Codec;
|
||||
@ -67,12 +68,12 @@ public final class AudioEncoder implements AsyncProcessor {
|
||||
|
||||
private boolean ended;
|
||||
|
||||
public AudioEncoder(AudioCapture capture, Streamer streamer, int bitRate, List<CodecOption> codecOptions, String encoderName) {
|
||||
public AudioEncoder(AudioCapture capture, Streamer streamer, Options options) {
|
||||
this.capture = capture;
|
||||
this.streamer = streamer;
|
||||
this.bitRate = bitRate;
|
||||
this.codecOptions = codecOptions;
|
||||
this.encoderName = encoderName;
|
||||
this.bitRate = options.getAudioBitRate();
|
||||
this.codecOptions = options.getAudioCodecOptions();
|
||||
this.encoderName = options.getAudioEncoder();
|
||||
}
|
||||
|
||||
private static MediaFormat createFormat(String mimeType, int bitRate, List<CodecOption> codecOptions) {
|
||||
|
@ -3,6 +3,7 @@ package com.genymobile.scrcpy.control;
|
||||
import com.genymobile.scrcpy.AndroidVersions;
|
||||
import com.genymobile.scrcpy.AsyncProcessor;
|
||||
import com.genymobile.scrcpy.CleanUp;
|
||||
import com.genymobile.scrcpy.Options;
|
||||
import com.genymobile.scrcpy.device.Device;
|
||||
import com.genymobile.scrcpy.device.DeviceApp;
|
||||
import com.genymobile.scrcpy.device.Point;
|
||||
@ -97,12 +98,12 @@ public class Controller implements AsyncProcessor, VirtualDisplayListener {
|
||||
// Used for resetting video encoding on RESET_VIDEO message
|
||||
private SurfaceCapture surfaceCapture;
|
||||
|
||||
public Controller(int displayId, ControlChannel controlChannel, CleanUp cleanUp, boolean clipboardAutosync, boolean powerOn) {
|
||||
this.displayId = displayId;
|
||||
public Controller(ControlChannel controlChannel, CleanUp cleanUp, Options options) {
|
||||
this.displayId = options.getDisplayId();
|
||||
this.controlChannel = controlChannel;
|
||||
this.cleanUp = cleanUp;
|
||||
this.clipboardAutosync = clipboardAutosync;
|
||||
this.powerOn = powerOn;
|
||||
this.clipboardAutosync = options.getClipboardAutosync();
|
||||
this.powerOn = options.getPowerOn();
|
||||
initPointers();
|
||||
sender = new DeviceMessageSender(controlChannel);
|
||||
|
||||
|
@ -236,7 +236,7 @@ public final class LogUtils {
|
||||
} else {
|
||||
builder.append("\n ").append(String.format("%" + column + "s", " "));
|
||||
}
|
||||
builder.append(" [").append(app.getPackageName()).append(']');
|
||||
builder.append(" ").append(app.getPackageName());
|
||||
}
|
||||
|
||||
return builder.toString();
|
||||
|
@ -1,9 +1,12 @@
|
||||
package com.genymobile.scrcpy.video;
|
||||
|
||||
import com.genymobile.scrcpy.AndroidVersions;
|
||||
import com.genymobile.scrcpy.Options;
|
||||
import com.genymobile.scrcpy.device.ConfigurationException;
|
||||
import com.genymobile.scrcpy.device.Size;
|
||||
import com.genymobile.scrcpy.util.HandlerExecutor;
|
||||
import com.genymobile.scrcpy.util.Ln;
|
||||
import com.genymobile.scrcpy.util.LogUtils;
|
||||
import com.genymobile.scrcpy.wrappers.ServiceManager;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
@ -56,19 +59,18 @@ public class CameraCapture extends SurfaceCapture {
|
||||
|
||||
private final AtomicBoolean disconnected = new AtomicBoolean();
|
||||
|
||||
public CameraCapture(String explicitCameraId, CameraFacing cameraFacing, Size explicitSize, int maxSize, CameraAspectRatio aspectRatio, int fps,
|
||||
boolean highSpeed) {
|
||||
this.explicitCameraId = explicitCameraId;
|
||||
this.cameraFacing = cameraFacing;
|
||||
this.explicitSize = explicitSize;
|
||||
this.maxSize = maxSize;
|
||||
this.aspectRatio = aspectRatio;
|
||||
this.fps = fps;
|
||||
this.highSpeed = highSpeed;
|
||||
public CameraCapture(Options options) {
|
||||
this.explicitCameraId = options.getCameraId();
|
||||
this.cameraFacing = options.getCameraFacing();
|
||||
this.explicitSize = options.getCameraSize();
|
||||
this.maxSize = options.getMaxSize();
|
||||
this.aspectRatio = options.getCameraAspectRatio();
|
||||
this.fps = options.getCameraFps();
|
||||
this.highSpeed = options.getCameraHighSpeed();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init() throws IOException {
|
||||
protected void init() throws ConfigurationException, IOException {
|
||||
cameraThread = new HandlerThread("camera");
|
||||
cameraThread.start();
|
||||
cameraHandler = new Handler(cameraThread.getLooper());
|
||||
@ -77,12 +79,7 @@ public class CameraCapture extends SurfaceCapture {
|
||||
try {
|
||||
cameraId = selectCamera(explicitCameraId, cameraFacing);
|
||||
if (cameraId == null) {
|
||||
throw new IOException("No matching camera found");
|
||||
}
|
||||
|
||||
size = selectSize(cameraId, explicitSize, maxSize, aspectRatio, highSpeed);
|
||||
if (size == null) {
|
||||
throw new IOException("Could not select camera size");
|
||||
throw new ConfigurationException("No matching camera found");
|
||||
}
|
||||
|
||||
Ln.i("Using camera '" + cameraId + "'");
|
||||
@ -92,14 +89,30 @@ public class CameraCapture extends SurfaceCapture {
|
||||
}
|
||||
}
|
||||
|
||||
private static String selectCamera(String explicitCameraId, CameraFacing cameraFacing) throws CameraAccessException {
|
||||
if (explicitCameraId != null) {
|
||||
return explicitCameraId;
|
||||
@Override
|
||||
public void prepare() throws IOException {
|
||||
try {
|
||||
size = selectSize(cameraId, explicitSize, maxSize, aspectRatio, highSpeed);
|
||||
if (size == null) {
|
||||
throw new IOException("Could not select camera size");
|
||||
}
|
||||
} catch (CameraAccessException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static String selectCamera(String explicitCameraId, CameraFacing cameraFacing) throws CameraAccessException, ConfigurationException {
|
||||
CameraManager cameraManager = ServiceManager.getCameraManager();
|
||||
|
||||
String[] cameraIds = cameraManager.getCameraIdList();
|
||||
if (explicitCameraId != null) {
|
||||
if (!Arrays.asList(cameraIds).contains(explicitCameraId)) {
|
||||
Ln.e("Camera with id " + explicitCameraId + " not found\n" + LogUtils.buildCameraListMessage(false));
|
||||
throw new ConfigurationException("Camera id not found");
|
||||
}
|
||||
return explicitCameraId;
|
||||
}
|
||||
|
||||
if (cameraFacing == null) {
|
||||
// Use the first one
|
||||
return cameraIds.length > 0 ? cameraIds[0] : null;
|
||||
@ -232,13 +245,7 @@ public class CameraCapture extends SurfaceCapture {
|
||||
}
|
||||
|
||||
this.maxSize = maxSize;
|
||||
try {
|
||||
size = selectSize(cameraId, null, maxSize, aspectRatio, highSpeed);
|
||||
return size != null;
|
||||
} catch (CameraAccessException e) {
|
||||
Ln.w("Could not select camera size", e);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
|
@ -1,6 +1,7 @@
|
||||
package com.genymobile.scrcpy.video;
|
||||
|
||||
import com.genymobile.scrcpy.AndroidVersions;
|
||||
import com.genymobile.scrcpy.Options;
|
||||
import com.genymobile.scrcpy.control.PositionMapper;
|
||||
import com.genymobile.scrcpy.device.DisplayInfo;
|
||||
import com.genymobile.scrcpy.device.NewDisplay;
|
||||
@ -19,6 +20,8 @@ import java.io.IOException;
|
||||
public class NewDisplayCapture extends SurfaceCapture {
|
||||
|
||||
// Internal fields copied from android.hardware.display.DisplayManager
|
||||
private static final int VIRTUAL_DISPLAY_FLAG_PUBLIC = DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC;
|
||||
private static final int VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY = DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY;
|
||||
private static final int VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH = 1 << 6;
|
||||
private static final int VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT = 1 << 7;
|
||||
private static final int VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_REMOVAL = 1 << 8;
|
||||
@ -41,10 +44,11 @@ public class NewDisplayCapture extends SurfaceCapture {
|
||||
private Size size;
|
||||
private int dpi;
|
||||
|
||||
public NewDisplayCapture(VirtualDisplayListener vdListener, NewDisplay newDisplay, int maxSize) {
|
||||
public NewDisplayCapture(VirtualDisplayListener vdListener, Options options) {
|
||||
this.vdListener = vdListener;
|
||||
this.newDisplay = newDisplay;
|
||||
this.maxSize = maxSize;
|
||||
this.newDisplay = options.getNewDisplay();
|
||||
assert newDisplay != null;
|
||||
this.maxSize = options.getMaxSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -74,12 +78,11 @@ public class NewDisplayCapture extends SurfaceCapture {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void startNew(Surface surface) {
|
||||
int virtualDisplayId;
|
||||
try {
|
||||
int flags = DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC
|
||||
| DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY
|
||||
int flags = VIRTUAL_DISPLAY_FLAG_PUBLIC
|
||||
| VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY
|
||||
| VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH
|
||||
| VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT
|
||||
| VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_REMOVAL
|
||||
|
@ -1,8 +1,10 @@
|
||||
package com.genymobile.scrcpy.video;
|
||||
|
||||
import com.genymobile.scrcpy.AndroidVersions;
|
||||
import com.genymobile.scrcpy.Options;
|
||||
import com.genymobile.scrcpy.control.PositionMapper;
|
||||
import com.genymobile.scrcpy.device.ConfigurationException;
|
||||
import com.genymobile.scrcpy.device.Device;
|
||||
import com.genymobile.scrcpy.device.DisplayInfo;
|
||||
import com.genymobile.scrcpy.device.Size;
|
||||
import com.genymobile.scrcpy.util.Ln;
|
||||
@ -48,12 +50,13 @@ public class ScreenCapture extends SurfaceCapture {
|
||||
private IRotationWatcher rotationWatcher;
|
||||
private IDisplayFoldListener displayFoldListener;
|
||||
|
||||
public ScreenCapture(VirtualDisplayListener vdListener, int displayId, int maxSize, Rect crop, int lockVideoOrientation) {
|
||||
public ScreenCapture(VirtualDisplayListener vdListener, Options options) {
|
||||
this.vdListener = vdListener;
|
||||
this.displayId = displayId;
|
||||
this.maxSize = maxSize;
|
||||
this.crop = crop;
|
||||
this.lockVideoOrientation = lockVideoOrientation;
|
||||
this.displayId = options.getDisplayId();
|
||||
assert displayId != Device.DISPLAY_ID_NONE;
|
||||
this.maxSize = options.getMaxSize();
|
||||
this.crop = options.getCrop();
|
||||
this.lockVideoOrientation = options.getLockVideoOrientation();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -46,7 +46,7 @@ public abstract class SurfaceCapture {
|
||||
/**
|
||||
* Called once before each capture starts, before {@link #getSize()}.
|
||||
*/
|
||||
public void prepare() throws ConfigurationException {
|
||||
public void prepare() throws ConfigurationException, IOException {
|
||||
// empty by default
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@ package com.genymobile.scrcpy.video;
|
||||
|
||||
import com.genymobile.scrcpy.AndroidVersions;
|
||||
import com.genymobile.scrcpy.AsyncProcessor;
|
||||
import com.genymobile.scrcpy.Options;
|
||||
import com.genymobile.scrcpy.device.ConfigurationException;
|
||||
import com.genymobile.scrcpy.device.Size;
|
||||
import com.genymobile.scrcpy.device.Streamer;
|
||||
@ -51,15 +52,14 @@ public class SurfaceEncoder implements AsyncProcessor {
|
||||
|
||||
private final CaptureReset reset = new CaptureReset();
|
||||
|
||||
public SurfaceEncoder(SurfaceCapture capture, Streamer streamer, int videoBitRate, float maxFps, List<CodecOption> codecOptions,
|
||||
String encoderName, boolean downsizeOnError) {
|
||||
public SurfaceEncoder(SurfaceCapture capture, Streamer streamer, Options options) {
|
||||
this.capture = capture;
|
||||
this.streamer = streamer;
|
||||
this.videoBitRate = videoBitRate;
|
||||
this.maxFps = maxFps;
|
||||
this.codecOptions = codecOptions;
|
||||
this.encoderName = encoderName;
|
||||
this.downsizeOnError = downsizeOnError;
|
||||
this.videoBitRate = options.getVideoBitRate();
|
||||
this.maxFps = options.getMaxFps();
|
||||
this.codecOptions = options.getVideoCodecOptions();
|
||||
this.encoderName = options.getVideoEncoder();
|
||||
this.downsizeOnError = options.getDownsizeOnError();
|
||||
}
|
||||
|
||||
private void streamCapture() throws IOException, ConfigurationException {
|
||||
|
Reference in New Issue
Block a user