Compare commits

..

21 Commits

Author SHA1 Message Date
Romain Vimont
26ee63d9e9 Build on Windows with libusb support 2022-02-07 13:24:10 +01:00
Romain Vimont
0d3ed2f669 Fix libusb callback for Windows
Add LIBUSB_CALL so that the callback has the correct signature on
Windows (including __attribute__((stdcall))).
2022-02-07 13:24:10 +01:00
Romain Vimont
0480581789 Avoid PRIx16 printf format on Windows
Convert uint16_t to unsigned to avoid using PRIx16, which may not exist
on Windows.
2022-02-07 13:24:09 +01:00
Romain Vimont
c0bc183157 Log device opening errors during listing
Without this log, the user would have no way to know that a USB device
is rejected because it could not be opened (typically due to
insufficient permissions).
2022-02-07 13:21:31 +01:00
Romain Vimont
dddd960a9e Mention --select-usb and --select-tcpip in README 2022-02-07 13:11:37 +01:00
Romain Vimont
5b05936093 Add option to select USB or TCP/IP devices
If several devices are connected (as listed by `adb devices`), it was
necessary to provide the explicit serial via -s/--serial.

If only one device is connected via USB (respectively, via TCP/IP), it
might be convenient to select it automatically. For this purpose, two
new options are introduced:
 - -U/--select-usb: select the single device connected over USB
 - -T/--select-tcpip: select the single device connected over TCP/IP
2022-02-07 13:11:37 +01:00
Romain Vimont
14b608dbcc Introduce adb device selector
Currently, a device is selected either from a specific serial, or if it
is the only one connected.

In order to support selecting the only device connected via USB or via
TCP/IP separately, introduce a new selection structure.
2022-02-07 13:11:37 +01:00
Romain Vimont
1718bfe00e Execute adb start-server
This does nothing if the adb daemon is already started, but allows to
print any output/errors in the console.

Otherwise, the daemon starting would occur during `adb devices`, which
does not output to the console because the result is parsed.
2022-02-07 13:11:37 +01:00
Romain Vimont
4ad12755da Remove sc_adb_get_serialno()
The device serial is now retrieved from `adb devices -l`, `adb
get-serialno` is not called anymore.
2022-02-07 13:11:37 +01:00
Romain Vimont
a6bedb4301 Allow selecting a device from IP without port
Since the previous commit, if a serial is given via -s/--serial (either
a real USB serial or an IP:port), a device is selected if its serial
matches exactly.

In addition, if the user pass an IP without a port, then select any
device with this IP, regardless of the port (so that "192.168.1.1"
matches any "192.168.1.1:port"). This is also the default behavior of
adb.
2022-02-07 13:11:37 +01:00
Romain Vimont
a432134685 Expose simple API to select a single adb device
Select an adb device from the output of `adb device -l`.
2022-02-07 13:11:37 +01:00
Romain Vimont
e78eb83cb9 Expose function to test if a serial is TCP/IP
In practice, it just tests if the serial contains a ':', which is
sufficient to distinguish ip:port from a real USB serial.
2022-02-07 13:11:37 +01:00
Romain Vimont
f5b737857f Add adb devices parser
Add a parser of `adb device -l` output, to extract a list of devices
with their serial, state and model.
2022-02-07 13:11:37 +01:00
Romain Vimont
4a759f9b55 Refactor device configuration
Depending on the parameters passed to scrcpy, either the initial device
serial is necessary or not. Reorganize to simplify the logic.
2022-02-07 13:11:37 +01:00
Romain Vimont
c28e616a44 List and select USB devices separately
List all USB devices in a first step, then select the matching one(s).

This allows to report a user-friendly log message containing the list of
devices, with the matching one(s) highlighted.
2022-02-07 13:11:37 +01:00
Romain Vimont
70a0d9cc37 Expose simple API to select a single USB device
The caller just wants a single device. Handle all cases and error
messages internally.
2022-02-07 13:11:37 +01:00
Romain Vimont
b11c6550c7 Add move-function for sc_usb_device
Add a function to "move" a sc_usb_device into another instance.

This will avoid unnecessary copies.
2022-02-07 13:11:37 +01:00
Romain Vimont
7d7953e278 Move SC_PRIsizet to compat.h
Define the printf format macro for size_t in compat.h so that it can be
used from anywhere.
2022-02-07 13:11:37 +01:00
Romain Vimont
54d48321fd Rename function to destroy a list of USB devices
Rename from "usb_device_" to "usb_devices_".
2022-02-07 13:11:37 +01:00
Romain Vimont
3456ca19c7 Add generic LOG() macro with level parameter
One log macro was provided for each log level (LOGV(), LOGD(), LOGI(),
LOGW(), LOGE()).

Add a generic macro LOG(LEVEL, ...) taking a log level as parameter, so
that it is possible to write logging wrappers.
2022-02-07 13:11:37 +01:00
Romain Vimont
79eb78a9e8 Remove LOGC()
It is not clear when to use LOGC() rather than LOGE(). Always use
LOGE().

Moreover, enum sc_log_level has no "critical" log level.
2022-02-07 13:11:37 +01:00
47 changed files with 339 additions and 477 deletions

View File

@@ -199,7 +199,7 @@ Install the packages with [Homebrew]:
```bash ```bash
# runtime dependencies # runtime dependencies
brew install sdl2 ffmpeg libusb brew install sdl2 ffmpeg
# client build dependencies # client build dependencies
brew install pkg-config meson brew install pkg-config meson
@@ -258,7 +258,7 @@ set ANDROID_SDK_ROOT=%LOCALAPPDATA%\Android\sdk
Then, build: Then, build:
```bash ```bash
meson x --buildtype=release --strip -Db_lto=true meson x --buildtype release --strip -Db_lto=true
ninja -Cx # DO NOT RUN AS ROOT ninja -Cx # DO NOT RUN AS ROOT
``` ```
@@ -279,7 +279,7 @@ Download the prebuilt server somewhere, and specify its path during the Meson
configuration: configuration:
```bash ```bash
meson x --buildtype=release --strip -Db_lto=true \ meson x --buildtype release --strip -Db_lto=true \
-Dprebuilt_server=/path/to/scrcpy-server -Dprebuilt_server=/path/to/scrcpy-server
ninja -Cx # DO NOT RUN AS ROOT ninja -Cx # DO NOT RUN AS ROOT
``` ```

View File

@@ -215,15 +215,6 @@ scrcpy --max-fps 15
This is officially supported since Android 10, but may work on earlier versions. This is officially supported since Android 10, but may work on earlier versions.
The actual capture framerate may be printed to the console:
```
scrcpy --print-fps
```
It may also be enabled or disabled at any time with <kbd>MOD</kbd>+<kbd>i</kbd>.
#### Crop #### Crop
The device screen may be cropped to mirror only part of the screen. The device screen may be cropped to mirror only part of the screen.
@@ -450,12 +441,12 @@ select it automatically:
```bash ```bash
# Select the only device connected via USB # Select the only device connected via USB
scrcpy -d # like adb -d scrcpy --select-usb
scrcpy --select-usb # long version scrcpy -U # short version
# Select the only device connected via TCP/IP # Select the only device connected via TCP/IP
scrcpy -e # like adb -e scrcpy --select-tcpip
scrcpy --select-tcpip # long version scrcpy -T # short version
``` ```
You can start several instances of _scrcpy_ for several devices. You can start several instances of _scrcpy_ for several devices.

View File

@@ -26,7 +26,6 @@ src = [
'src/scrcpy.c', 'src/scrcpy.c',
'src/screen.c', 'src/screen.c',
'src/server.c', 'src/server.c',
'src/version.c',
'src/video_buffer.c', 'src/video_buffer.c',
'src/util/acksync.c', 'src/util/acksync.c',
'src/util/file.c', 'src/util/file.c',
@@ -69,12 +68,12 @@ else
endif endif
endif endif
v4l2_support = get_option('v4l2') and host_machine.system() == 'linux' v4l2_support = host_machine.system() == 'linux'
if v4l2_support if v4l2_support
src += [ 'src/v4l2_sink.c' ] src += [ 'src/v4l2_sink.c' ]
endif endif
usb_support = get_option('usb') and host_machine.system() != 'windows' usb_support = host_machine.system() == 'linux' or host_machine.system() == 'windows'
if usb_support if usb_support
src += [ src += [
'src/usb/aoa_hid.c', 'src/usb/aoa_hid.c',
@@ -111,9 +110,9 @@ if not crossbuild_windows
else else
# cross-compile mingw32 build (from Linux to Windows) # cross-compile mingw32 build (from Linux to Windows)
prebuilt_sdl2 = meson.get_cross_property('prebuilt_sdl2') prebuilt_sdl2 = meson.get_cross_property('prebuilt_sdl2')
sdl2_bin_dir = meson.current_source_dir() + '/prebuilt-deps/data/' + prebuilt_sdl2 + '/bin' sdl2_bin_dir = meson.current_source_dir() + '/../prebuilt-deps/data/' + prebuilt_sdl2 + '/bin'
sdl2_lib_dir = meson.current_source_dir() + '/prebuilt-deps/data/' + prebuilt_sdl2 + '/lib' sdl2_lib_dir = meson.current_source_dir() + '/../prebuilt-deps/data/' + prebuilt_sdl2 + '/lib'
sdl2_include_dir = 'prebuilt-deps/data/' + prebuilt_sdl2 + '/include' sdl2_include_dir = '../prebuilt-deps/data/' + prebuilt_sdl2 + '/include'
sdl2 = declare_dependency( sdl2 = declare_dependency(
dependencies: [ dependencies: [
@@ -124,8 +123,8 @@ else
) )
prebuilt_ffmpeg = meson.get_cross_property('prebuilt_ffmpeg') prebuilt_ffmpeg = meson.get_cross_property('prebuilt_ffmpeg')
ffmpeg_bin_dir = meson.current_source_dir() + '/prebuilt-deps/data/' + prebuilt_ffmpeg + '/bin' ffmpeg_bin_dir = meson.current_source_dir() + '/../prebuilt-deps/data/' + prebuilt_ffmpeg + '/bin'
ffmpeg_include_dir = 'prebuilt-deps/data/' + prebuilt_ffmpeg + '/include' ffmpeg_include_dir = '../prebuilt-deps/data/' + prebuilt_ffmpeg + '/include'
# ffmpeg versions are different for win32 and win64 builds # ffmpeg versions are different for win32 and win64 builds
ffmpeg_avcodec = meson.get_cross_property('ffmpeg_avcodec') ffmpeg_avcodec = meson.get_cross_property('ffmpeg_avcodec')
@@ -141,9 +140,22 @@ else
include_directories: include_directories(ffmpeg_include_dir) include_directories: include_directories(ffmpeg_include_dir)
) )
prebuilt_libusb = meson.get_cross_property('prebuilt_libusb')
prebuilt_libusb_root = meson.get_cross_property('prebuilt_libusb_root')
libusb_bin_dir = meson.current_source_dir() + '/../prebuilt-deps/data/' + prebuilt_libusb + '/dll'
libusb_include_dir = '../prebuilt-deps/data/' + prebuilt_libusb_root + '/include'
libusb = declare_dependency(
dependencies: [
cc.find_library('libusb-1.0', dirs: libusb_bin_dir),
],
include_directories: include_directories(libusb_include_dir)
)
dependencies = [ dependencies = [
ffmpeg, ffmpeg,
sdl2, sdl2,
libusb,
cc.find_library('mingw32') cc.find_library('mingw32')
] ]

View File

@@ -43,12 +43,6 @@ The values are expressed in the device natural orientation (typically, portrait
.B \-\-max\-size .B \-\-max\-size
value is computed on the cropped size. value is computed on the cropped size.
.TP
.B \-d, \-\-select\-usb
Use USB device (if there is exactly one, like adb -d).
Also see \fB\-e\fR (\fB\-\-select\-tcpip\fR).
.TP .TP
.BI "\-\-disable-screensaver" .BI "\-\-disable-screensaver"
Disable screensaver while scrcpy is running. Disable screensaver while scrcpy is running.
@@ -68,12 +62,6 @@ Add a buffering delay (in milliseconds) before displaying. This increases latenc
Default is 0 (no buffering). Default is 0 (no buffering).
.TP
.B \-e, \-\-select\-tcpip
Use TCP/IP device (if there is exactly one, like adb -e).
Also see \fB\-d\fR (\fB\-\-select\-usb\fR).
.TP .TP
.BI "\-\-encoder " name .BI "\-\-encoder " name
Use a specific MediaCodec encoder (must be a H.264 encoder). Use a specific MediaCodec encoder (must be a H.264 encoder).
@@ -100,7 +88,7 @@ Simulate a physical keyboard by using HID over AOAv2.
This provides a better experience for IME users, and allows to generate non-ASCII characters, contrary to the default injection method. This provides a better experience for IME users, and allows to generate non-ASCII characters, contrary to the default injection method.
It may only work over USB. It may only work over USB, and is currently only supported on Linux.
The keyboard layout must be configured (once and for all) on the device, via Settings -> System -> Languages and input -> Physical keyboard. This settings page can be started directly: The keyboard layout must be configured (once and for all) on the device, via Settings -> System -> Languages and input -> Physical keyboard. This settings page can be started directly:
@@ -142,16 +130,10 @@ In this mode, the computer mouse is captured to control the device directly (rel
LAlt, LSuper or RSuper toggle the capture mode, to give control of the mouse back to the computer. LAlt, LSuper or RSuper toggle the capture mode, to give control of the mouse back to the computer.
It may only work over USB. It may only work over USB, and is currently only supported on Linux.
Also see \fB\-\-hid\-keyboard\fR. Also see \fB\-\-hid\-keyboard\fR.
.TP
.B \-\-no\-cleanup
By default, scrcpy removes the server binary from the device and restores the device state (show touches, stay awake and power mode) on exit.
This option disables this cleanup.
.TP .TP
.B \-\-no\-clipboard\-autosync .B \-\-no\-clipboard\-autosync
By default, scrcpy automatically synchronizes the computer clipboard to the device clipboard before injecting Ctrl+v, and the device clipboard to the computer clipboard whenever it changes. By default, scrcpy automatically synchronizes the computer clipboard to the device clipboard before injecting Ctrl+v, and the device clipboard to the computer clipboard whenever it changes.
@@ -190,7 +172,7 @@ LAlt, LSuper or RSuper toggle the mouse capture mode, to give control of the mou
If any of \fB\-\-hid\-keyboard\fR or \fB\-\-hid\-mouse\fR is set, only enable keyboard or mouse respectively, otherwise enable both. If any of \fB\-\-hid\-keyboard\fR or \fB\-\-hid\-mouse\fR is set, only enable keyboard or mouse respectively, otherwise enable both.
It may only work over USB. It may only work over USB, and is currently only supported on Linux.
See \fB\-\-hid\-keyboard\fR and \fB\-\-hid\-mouse\fR. See \fB\-\-hid\-keyboard\fR and \fB\-\-hid\-mouse\fR.
@@ -211,10 +193,6 @@ Inject alpha characters and space as text events instead of key events.
This avoids issues when combining multiple keys to enter special characters, This avoids issues when combining multiple keys to enter special characters,
but breaks the expected behavior of alpha keys in games (typically WASD). but breaks the expected behavior of alpha keys in games (typically WASD).
.TP
.B "\-\-print\-fps
Start FPS counter, to print framerate logs to the console. It can be started or stopped at any time with MOD+i.
.TP .TP
.BI "\-\-push\-target " path .BI "\-\-push\-target " path
Set the target directory for pushing files to the device by drag & drop. It is passed as\-is to "adb push". Set the target directory for pushing files to the device by drag & drop. It is passed as\-is to "adb push".
@@ -295,6 +273,14 @@ Set the TCP port of the adb tunnel to reach the scrcpy server. This option autom
Default is 0 (not forced): the local port used for establishing the tunnel will be used. Default is 0 (not forced): the local port used for establishing the tunnel will be used.
.TP
.B \-T, \-\-select\-tcpip
Use TCP/IP device (if there is exactly one).
.TP
.B \-U, \-\-select\-usb
Use USB device (if there is exactly one).
.TP .TP
.BI "\-\-v4l2-sink " /dev/videoN .BI "\-\-v4l2-sink " /dev/videoN
Output to v4l2loopback device. Output to v4l2loopback device.

View File

@@ -412,7 +412,7 @@ sc_adb_list_devices(struct sc_intr *intr, unsigned flags,
// The implementation assumes that the output of "adb devices -l" fits // The implementation assumes that the output of "adb devices -l" fits
// in the buffer in a single pass // in the buffer in a single pass
LOGW("Result of \"adb devices -l\" does not fit in 4Kb. " LOGW("Result of \"adb devices -l\" does not fit in 4Kb. "
"Please report an issue."); "Please report an issue.\n");
return -1; return -1;
} }
@@ -585,8 +585,9 @@ sc_adb_select_device(struct sc_intr *intr,
break; break;
} }
sc_adb_devices_log(SC_LOG_LEVEL_ERROR, devices, count); sc_adb_devices_log(SC_LOG_LEVEL_ERROR, devices, count);
LOGE("Select a device via -s (--serial), -d (--select-usb) or -e " if (selector->type != SC_ADB_DEVICE_SELECT_ALL) {
"(--select-tcpip)"); LOGE("Specify the device via -s or --serial");
}
sc_adb_devices_destroy_all(devices, count); sc_adb_devices_destroy_all(devices, count);
return false; return false;
} }
@@ -676,7 +677,7 @@ sc_adb_get_device_ip(struct sc_intr *intr, const char *serial, unsigned flags) {
// The implementation assumes that the output of "ip route" fits in the // The implementation assumes that the output of "ip route" fits in the
// buffer in a single pass // buffer in a single pass
LOGW("Result of \"ip route\" does not fit in 1Kb. " LOGW("Result of \"ip route\" does not fit in 1Kb. "
"Please report an issue."); "Please report an issue.\n");
return NULL; return NULL;
} }

View File

@@ -17,7 +17,7 @@ void
sc_adb_device_destroy(struct sc_adb_device *device); sc_adb_device_destroy(struct sc_adb_device *device);
/** /**
* Move src to dst * Move src to dest
* *
* After this call, the content of src is undefined, except that * After this call, the content of src is undefined, except that
* sc_adb_device_destroy() can be called. * sc_adb_device_destroy() can be called.

View File

@@ -54,8 +54,6 @@
#define OPT_RAW_KEY_EVENTS 1034 #define OPT_RAW_KEY_EVENTS 1034
#define OPT_NO_DOWNSIZE_ON_ERROR 1035 #define OPT_NO_DOWNSIZE_ON_ERROR 1035
#define OPT_OTG 1036 #define OPT_OTG 1036
#define OPT_NO_CLEANUP 1037
#define OPT_PRINT_FPS 1038
struct sc_option { struct sc_option {
char shortopt; char shortopt;
@@ -118,13 +116,7 @@ static const struct sc_option options[] = {
.text = "Crop the device screen on the server.\n" .text = "Crop the device screen on the server.\n"
"The values are expressed in the device natural orientation " "The values are expressed in the device natural orientation "
"(typically, portrait for a phone, landscape for a tablet). " "(typically, portrait for a phone, landscape for a tablet). "
"Any --max-size value is computed on the cropped size.", "Any --max-size value is cmoputed on the cropped size.",
},
{
.shortopt = 'd',
.longopt = "select-usb",
.text = "Use USB device (if there is exactly one, like adb -d).\n"
"Also see -e (--select-tcpip).",
}, },
{ {
.longopt_id = OPT_DISABLE_SCREENSAVER, .longopt_id = OPT_DISABLE_SCREENSAVER,
@@ -149,12 +141,6 @@ static const struct sc_option options[] = {
"This increases latency to compensate for jitter.\n" "This increases latency to compensate for jitter.\n"
"Default is 0 (no buffering).", "Default is 0 (no buffering).",
}, },
{
.shortopt = 'e',
.longopt = "select-tcpip",
.text = "Use TCP/IP device (if there is exactly one, like adb -e).\n"
"Also see -d (--select-usb).",
},
{ {
.longopt_id = OPT_ENCODER_NAME, .longopt_id = OPT_ENCODER_NAME,
.longopt = "encoder", .longopt = "encoder",
@@ -186,7 +172,8 @@ static const struct sc_option options[] = {
"It provides a better experience for IME users, and allows to " "It provides a better experience for IME users, and allows to "
"generate non-ASCII characters, contrary to the default " "generate non-ASCII characters, contrary to the default "
"injection method.\n" "injection method.\n"
"It may only work over USB.\n" "It may only work over USB, and is currently only supported "
"on Linux.\n"
"The keyboard layout must be configured (once and for all) on " "The keyboard layout must be configured (once and for all) on "
"the device, via Settings -> System -> Languages and input -> " "the device, via Settings -> System -> Languages and input -> "
"Physical keyboard. This settings page can be started " "Physical keyboard. This settings page can be started "
@@ -238,7 +225,8 @@ static const struct sc_option options[] = {
"device directly (relative mouse mode).\n" "device directly (relative mouse mode).\n"
"LAlt, LSuper or RSuper toggle the capture mode, to give " "LAlt, LSuper or RSuper toggle the capture mode, to give "
"control of the mouse back to the computer.\n" "control of the mouse back to the computer.\n"
"It may only work over USB.\n" "It may only work over USB, and is currently only supported "
"on Linux.\n"
"Also see --hid-keyboard.", "Also see --hid-keyboard.",
}, },
{ {
@@ -251,12 +239,11 @@ static const struct sc_option options[] = {
"Default is 0 (unlimited).", "Default is 0 (unlimited).",
}, },
{ {
.longopt_id = OPT_NO_CLEANUP, .longopt_id = OPT_NO_DOWNSIZE_ON_ERROR,
.longopt = "no-cleanup", .longopt = "no-downsize-on-error",
.text = "By default, scrcpy removes the server binary from the device " .text = "By default, on MediaCodec error, scrcpy automatically tries "
"and restores the device state (show touches, stay awake and " "again with a lower definition.\n"
"power mode) on exit.\n" "This option disables this behavior.",
"This option disables this cleanup."
}, },
{ {
.longopt_id = OPT_NO_CLIPBOARD_AUTOSYNC, .longopt_id = OPT_NO_CLIPBOARD_AUTOSYNC,
@@ -267,13 +254,6 @@ static const struct sc_option options[] = {
"it changes.\n" "it changes.\n"
"This option disables this automatic synchronization." "This option disables this automatic synchronization."
}, },
{
.longopt_id = OPT_NO_DOWNSIZE_ON_ERROR,
.longopt = "no-downsize-on-error",
.text = "By default, on MediaCodec error, scrcpy automatically tries "
"again with a lower definition.\n"
"This option disables this behavior.",
},
{ {
.shortopt = 'n', .shortopt = 'n',
.longopt = "no-control", .longopt = "no-control",
@@ -309,7 +289,8 @@ static const struct sc_option options[] = {
"control of the mouse back to the computer.\n" "control of the mouse back to the computer.\n"
"If any of --hid-keyboard or --hid-mouse is set, only enable " "If any of --hid-keyboard or --hid-mouse is set, only enable "
"keyboard or mouse respectively, otherwise enable both.\n" "keyboard or mouse respectively, otherwise enable both.\n"
"It may only work over USB.\n" "It may only work over USB, and is currently only supported "
"on Linux.\n"
"See --hid-keyboard and --hid-mouse.", "See --hid-keyboard and --hid-mouse.",
}, },
{ {
@@ -334,12 +315,6 @@ static const struct sc_option options[] = {
"special character, but breaks the expected behavior of alpha " "special character, but breaks the expected behavior of alpha "
"keys in games (typically WASD).", "keys in games (typically WASD).",
}, },
{
.longopt_id = OPT_PRINT_FPS,
.longopt = "print-fps",
.text = "Start FPS counter, to print framerate logs to the console. "
"It can be started or stopped at any time with MOD+i.",
},
{ {
.longopt_id = OPT_PUSH_TARGET, .longopt_id = OPT_PUSH_TARGET,
.longopt = "push-target", .longopt = "push-target",
@@ -441,6 +416,16 @@ static const struct sc_option options[] = {
"Default is 0 (not forced): the local port used for " "Default is 0 (not forced): the local port used for "
"establishing the tunnel will be used.", "establishing the tunnel will be used.",
}, },
{
.shortopt = 'T',
.longopt = "select-tcpip",
.text = "Use TCP/IP device (if there is exactly one).",
},
{
.shortopt = 'U',
.longopt = "select-usb",
.text = "Use USB device (if there is exactly one).",
},
{ {
.longopt_id = OPT_V4L2_SINK, .longopt_id = OPT_V4L2_SINK,
.longopt = "v4l2-sink", .longopt = "v4l2-sink",
@@ -1345,12 +1330,6 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
return false; return false;
} }
break; break;
case 'd':
opts->select_usb = true;
break;
case 'e':
opts->select_tcpip = true;
break;
case 'f': case 'f':
opts->fullscreen = true; opts->fullscreen = true;
break; break;
@@ -1370,8 +1349,8 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
opts->keyboard_input_mode = SC_KEYBOARD_INPUT_MODE_HID; opts->keyboard_input_mode = SC_KEYBOARD_INPUT_MODE_HID;
break; break;
#else #else
LOGE("HID over AOA (-K/--hid-keyboard) is disabled (or " LOGE("HID over AOA (-K/--hid-keyboard) is not supported on "
"unsupported on this platform)."); "this platform. It is only available on Linux.");
return false; return false;
#endif #endif
case OPT_MAX_FPS: case OPT_MAX_FPS:
@@ -1389,8 +1368,8 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
opts->mouse_input_mode = SC_MOUSE_INPUT_MODE_HID; opts->mouse_input_mode = SC_MOUSE_INPUT_MODE_HID;
break; break;
#else #else
LOGE("HID over AOA (-M/--hid-mouse) is disabled (or " LOGE("HID over AOA (-M/--hid-mouse) is not supported on this"
"unsupported on this platform)."); "platform. It is only available on Linux.");
return false; return false;
#endif #endif
case OPT_LOCK_VIDEO_ORIENTATION: case OPT_LOCK_VIDEO_ORIENTATION:
@@ -1432,6 +1411,12 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
case 't': case 't':
opts->show_touches = true; opts->show_touches = true;
break; break;
case 'T':
opts->select_tcpip = true;
break;
case 'U':
opts->select_usb = true;
break;
case OPT_ALWAYS_ON_TOP: case OPT_ALWAYS_ON_TOP:
opts->always_on_top = true; opts->always_on_top = true;
break; break;
@@ -1548,19 +1533,13 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
case OPT_NO_DOWNSIZE_ON_ERROR: case OPT_NO_DOWNSIZE_ON_ERROR:
opts->downsize_on_error = false; opts->downsize_on_error = false;
break; break;
case OPT_NO_CLEANUP:
opts->cleanup = false;
break;
case OPT_PRINT_FPS:
opts->start_fps_counter = true;
break;
case OPT_OTG: case OPT_OTG:
#ifdef HAVE_USB #ifdef HAVE_USB
opts->otg = true; opts->otg = true;
break; break;
#else #else
LOGE("OTG mode (--otg) is disabled (or unsupported on this " LOGE("OTG mode (--otg) is not supported on this platform. It "
"platform)."); "is only available on Linux.");
return false; return false;
#endif #endif
case OPT_V4L2_SINK: case OPT_V4L2_SINK:
@@ -1568,8 +1547,7 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
opts->v4l2_device = optarg; opts->v4l2_device = optarg;
break; break;
#else #else
LOGE("V4L2 (--v4l2-sink) is disabled (or unsupported on this " LOGE("V4L2 (--v4l2-sink) is only available on Linux.");
"platform).");
return false; return false;
#endif #endif
case OPT_V4L2_BUFFER: case OPT_V4L2_BUFFER:
@@ -1604,8 +1582,8 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
if (selectors > 1) { if (selectors > 1) {
LOGE("At most one device selector option may be passed, among:\n" LOGE("At most one device selector option may be passed, among:\n"
" --serial (-s)\n" " --serial (-s)\n"
" --select-usb (-d)\n" " --select-usb (-U)\n"
" --select-tcpip (-e)\n" " --select-tcpip (-T)\n"
" --tcpip=<addr> (with an argument)"); " --tcpip=<addr> (with an argument)");
return false; return false;
} }
@@ -1710,12 +1688,12 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
LOGE("OTG mode: could not select display"); LOGE("OTG mode: could not select display");
return false; return false;
} }
# ifdef HAVE_V4L2 #ifdef HAVE_V4L2
if (opts->v4l2_device) { if (opts->v4l2_device) {
LOGE("OTG mode: could not sink to V4L2 device"); LOGE("OTG mode: could not sink to V4L2 device");
return false; return false;
} }
# endif #endif
} }
#endif #endif

View File

@@ -63,17 +63,17 @@ static const char *const copy_key_labels[] = {
static void static void
write_position(uint8_t *buf, const struct sc_position *position) { write_position(uint8_t *buf, const struct sc_position *position) {
sc_write32be(&buf[0], position->point.x); buffer_write32be(&buf[0], position->point.x);
sc_write32be(&buf[4], position->point.y); buffer_write32be(&buf[4], position->point.y);
sc_write16be(&buf[8], position->screen_size.width); buffer_write16be(&buf[8], position->screen_size.width);
sc_write16be(&buf[10], position->screen_size.height); buffer_write16be(&buf[10], position->screen_size.height);
} }
// write length (4 bytes) + string (non null-terminated) // write length (4 bytes) + string (non null-terminated)
static size_t static size_t
write_string(const char *utf8, size_t max_len, unsigned char *buf) { write_string(const char *utf8, size_t max_len, unsigned char *buf) {
size_t len = sc_str_utf8_truncation_index(utf8, max_len); size_t len = sc_str_utf8_truncation_index(utf8, max_len);
sc_write32be(buf, len); buffer_write32be(buf, len);
memcpy(&buf[4], utf8, len); memcpy(&buf[4], utf8, len);
return 4 + len; return 4 + len;
} }
@@ -94,9 +94,9 @@ sc_control_msg_serialize(const struct sc_control_msg *msg, unsigned char *buf) {
switch (msg->type) { switch (msg->type) {
case SC_CONTROL_MSG_TYPE_INJECT_KEYCODE: case SC_CONTROL_MSG_TYPE_INJECT_KEYCODE:
buf[1] = msg->inject_keycode.action; buf[1] = msg->inject_keycode.action;
sc_write32be(&buf[2], msg->inject_keycode.keycode); buffer_write32be(&buf[2], msg->inject_keycode.keycode);
sc_write32be(&buf[6], msg->inject_keycode.repeat); buffer_write32be(&buf[6], msg->inject_keycode.repeat);
sc_write32be(&buf[10], msg->inject_keycode.metastate); buffer_write32be(&buf[10], msg->inject_keycode.metastate);
return 14; return 14;
case SC_CONTROL_MSG_TYPE_INJECT_TEXT: { case SC_CONTROL_MSG_TYPE_INJECT_TEXT: {
size_t len = size_t len =
@@ -106,20 +106,20 @@ sc_control_msg_serialize(const struct sc_control_msg *msg, unsigned char *buf) {
} }
case SC_CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT: case SC_CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT:
buf[1] = msg->inject_touch_event.action; buf[1] = msg->inject_touch_event.action;
sc_write64be(&buf[2], msg->inject_touch_event.pointer_id); buffer_write64be(&buf[2], msg->inject_touch_event.pointer_id);
write_position(&buf[10], &msg->inject_touch_event.position); write_position(&buf[10], &msg->inject_touch_event.position);
uint16_t pressure = uint16_t pressure =
to_fixed_point_16(msg->inject_touch_event.pressure); to_fixed_point_16(msg->inject_touch_event.pressure);
sc_write16be(&buf[22], pressure); buffer_write16be(&buf[22], pressure);
sc_write32be(&buf[24], msg->inject_touch_event.buttons); buffer_write32be(&buf[24], msg->inject_touch_event.buttons);
return 28; return 28;
case SC_CONTROL_MSG_TYPE_INJECT_SCROLL_EVENT: case SC_CONTROL_MSG_TYPE_INJECT_SCROLL_EVENT:
write_position(&buf[1], &msg->inject_scroll_event.position); write_position(&buf[1], &msg->inject_scroll_event.position);
sc_write32be(&buf[13], buffer_write32be(&buf[13],
(uint32_t) msg->inject_scroll_event.hscroll); (uint32_t) msg->inject_scroll_event.hscroll);
sc_write32be(&buf[17], buffer_write32be(&buf[17],
(uint32_t) msg->inject_scroll_event.vscroll); (uint32_t) msg->inject_scroll_event.vscroll);
sc_write32be(&buf[21], msg->inject_scroll_event.buttons); buffer_write32be(&buf[21], msg->inject_scroll_event.buttons);
return 25; return 25;
case SC_CONTROL_MSG_TYPE_BACK_OR_SCREEN_ON: case SC_CONTROL_MSG_TYPE_BACK_OR_SCREEN_ON:
buf[1] = msg->inject_keycode.action; buf[1] = msg->inject_keycode.action;
@@ -128,7 +128,7 @@ sc_control_msg_serialize(const struct sc_control_msg *msg, unsigned char *buf) {
buf[1] = msg->get_clipboard.copy_key; buf[1] = msg->get_clipboard.copy_key;
return 2; return 2;
case SC_CONTROL_MSG_TYPE_SET_CLIPBOARD: case SC_CONTROL_MSG_TYPE_SET_CLIPBOARD:
sc_write64be(&buf[1], msg->set_clipboard.sequence); buffer_write64be(&buf[1], msg->set_clipboard.sequence);
buf[9] = !!msg->set_clipboard.paste; buf[9] = !!msg->set_clipboard.paste;
size_t len = write_string(msg->set_clipboard.text, size_t len = write_string(msg->set_clipboard.text,
SC_CONTROL_MSG_CLIPBOARD_TEXT_MAX_LENGTH, SC_CONTROL_MSG_CLIPBOARD_TEXT_MAX_LENGTH,

View File

@@ -10,12 +10,10 @@
#include "util/buffer_util.h" #include "util/buffer_util.h"
#include "util/log.h" #include "util/log.h"
#define SC_PACKET_HEADER_SIZE 12 #define BUFSIZE 0x10000
#define SC_PACKET_FLAG_CONFIG (UINT64_C(1) << 63) #define HEADER_SIZE 12
#define SC_PACKET_FLAG_KEY_FRAME (UINT64_C(1) << 62) #define NO_PTS UINT64_C(-1)
#define SC_PACKET_PTS_MASK (SC_PACKET_FLAG_KEY_FRAME - 1)
static bool static bool
sc_demuxer_recv_packet(struct sc_demuxer *demuxer, AVPacket *packet) { sc_demuxer_recv_packet(struct sc_demuxer *demuxer, AVPacket *packet) {
@@ -30,24 +28,16 @@ sc_demuxer_recv_packet(struct sc_demuxer *demuxer, AVPacket *packet) {
// size // size
// //
// It is followed by <packet_size> bytes containing the packet/frame. // It is followed by <packet_size> bytes containing the packet/frame.
//
// The most significant bits of the PTS are used for packet flags:
//
// byte 7 byte 6 byte 5 byte 4 byte 3 byte 2 byte 1 byte 0
// CK...... ........ ........ ........ ........ ........ ........ ........
// ^^<------------------------------------------------------------------->
// || PTS
// | `- config packet
// `-- key frame
uint8_t header[SC_PACKET_HEADER_SIZE]; uint8_t header[HEADER_SIZE];
ssize_t r = net_recv_all(demuxer->socket, header, SC_PACKET_HEADER_SIZE); ssize_t r = net_recv_all(demuxer->socket, header, HEADER_SIZE);
if (r < SC_PACKET_HEADER_SIZE) { if (r < HEADER_SIZE) {
return false; return false;
} }
uint64_t pts_flags = sc_read64be(header); uint64_t pts = buffer_read64be(header);
uint32_t len = sc_read32be(&header[8]); uint32_t len = buffer_read32be(&header[8]);
assert(pts == NO_PTS || (pts & 0x8000000000000000) == 0);
assert(len); assert(len);
if (av_new_packet(packet, len)) { if (av_new_packet(packet, len)) {
@@ -61,17 +51,8 @@ sc_demuxer_recv_packet(struct sc_demuxer *demuxer, AVPacket *packet) {
return false; return false;
} }
if (pts_flags & SC_PACKET_FLAG_CONFIG) { packet->pts = pts != NO_PTS ? (int64_t) pts : AV_NOPTS_VALUE;
packet->pts = AV_NOPTS_VALUE;
} else {
packet->pts = pts_flags & SC_PACKET_PTS_MASK;
}
if (pts_flags & SC_PACKET_FLAG_KEY_FRAME) {
packet->flags |= AV_PKT_FLAG_KEY;
}
packet->dts = packet->pts;
return true; return true;
} }
@@ -88,6 +69,28 @@ push_packet_to_sinks(struct sc_demuxer *demuxer, const AVPacket *packet) {
return true; return true;
} }
static void
sc_demuxer_parse(struct sc_demuxer *demuxer, AVPacket *packet) {
uint8_t *in_data = packet->data;
int in_len = packet->size;
uint8_t *out_data = NULL;
int out_len = 0;
int r = av_parser_parse2(demuxer->parser, demuxer->codec_ctx,
&out_data, &out_len, in_data, in_len,
AV_NOPTS_VALUE, AV_NOPTS_VALUE, -1);
// PARSER_FLAG_COMPLETE_FRAMES is set
assert(r == in_len);
(void) r;
assert(out_len == in_len);
if (demuxer->parser->key_frame == 1) {
packet->flags |= AV_PKT_FLAG_KEY;
}
packet->dts = packet->pts;
}
static bool static bool
sc_demuxer_push_packet(struct sc_demuxer *demuxer, AVPacket *packet) { sc_demuxer_push_packet(struct sc_demuxer *demuxer, AVPacket *packet) {
bool is_config = packet->pts == AV_NOPTS_VALUE; bool is_config = packet->pts == AV_NOPTS_VALUE;
@@ -127,6 +130,11 @@ sc_demuxer_push_packet(struct sc_demuxer *demuxer, AVPacket *packet) {
} }
} }
if (!is_config) {
// data packet
sc_demuxer_parse(demuxer, packet);
}
bool ok = push_packet_to_sinks(demuxer, packet); bool ok = push_packet_to_sinks(demuxer, packet);
if (!is_config && demuxer->pending) { if (!is_config && demuxer->pending) {

View File

@@ -18,7 +18,7 @@ device_msg_deserialize(const unsigned char *buf, size_t len,
msg->type = buf[0]; msg->type = buf[0];
switch (msg->type) { switch (msg->type) {
case DEVICE_MSG_TYPE_CLIPBOARD: { case DEVICE_MSG_TYPE_CLIPBOARD: {
size_t clipboard_len = sc_read32be(&buf[1]); size_t clipboard_len = buffer_read32be(&buf[1]);
if (clipboard_len > len - 5) { if (clipboard_len > len - 5) {
return 0; // not available return 0; // not available
} }
@@ -36,7 +36,7 @@ device_msg_deserialize(const unsigned char *buf, size_t len,
return 5 + clipboard_len; return 5 + clipboard_len;
} }
case DEVICE_MSG_TYPE_ACK_CLIPBOARD: { case DEVICE_MSG_TYPE_ACK_CLIPBOARD: {
uint64_t sequence = sc_read64be(&buf[1]); uint64_t sequence = buffer_read64be(&buf[1]);
msg->ack_clipboard.sequence = sequence; msg->ack_clipboard.sequence = sequence;
return 9; return 9;
} }

View File

@@ -4,10 +4,10 @@
#include "util/log.h" #include "util/log.h"
#define SC_FPS_COUNTER_INTERVAL SC_TICK_FROM_SEC(1) #define FPS_COUNTER_INTERVAL SC_TICK_FROM_SEC(1)
bool bool
sc_fps_counter_init(struct sc_fps_counter *counter) { fps_counter_init(struct fps_counter *counter) {
bool ok = sc_mutex_init(&counter->mutex); bool ok = sc_mutex_init(&counter->mutex);
if (!ok) { if (!ok) {
return false; return false;
@@ -27,26 +27,26 @@ sc_fps_counter_init(struct sc_fps_counter *counter) {
} }
void void
sc_fps_counter_destroy(struct sc_fps_counter *counter) { fps_counter_destroy(struct fps_counter *counter) {
sc_cond_destroy(&counter->state_cond); sc_cond_destroy(&counter->state_cond);
sc_mutex_destroy(&counter->mutex); sc_mutex_destroy(&counter->mutex);
} }
static inline bool static inline bool
is_started(struct sc_fps_counter *counter) { is_started(struct fps_counter *counter) {
return atomic_load_explicit(&counter->started, memory_order_acquire); return atomic_load_explicit(&counter->started, memory_order_acquire);
} }
static inline void static inline void
set_started(struct sc_fps_counter *counter, bool started) { set_started(struct fps_counter *counter, bool started) {
atomic_store_explicit(&counter->started, started, memory_order_release); atomic_store_explicit(&counter->started, started, memory_order_release);
} }
// must be called with mutex locked // must be called with mutex locked
static void static void
display_fps(struct sc_fps_counter *counter) { display_fps(struct fps_counter *counter) {
unsigned rendered_per_second = unsigned rendered_per_second =
counter->nr_rendered * SC_TICK_FREQ / SC_FPS_COUNTER_INTERVAL; counter->nr_rendered * SC_TICK_FREQ / FPS_COUNTER_INTERVAL;
if (counter->nr_skipped) { if (counter->nr_skipped) {
LOGI("%u fps (+%u frames skipped)", rendered_per_second, LOGI("%u fps (+%u frames skipped)", rendered_per_second,
counter->nr_skipped); counter->nr_skipped);
@@ -57,7 +57,7 @@ display_fps(struct sc_fps_counter *counter) {
// must be called with mutex locked // must be called with mutex locked
static void static void
check_interval_expired(struct sc_fps_counter *counter, sc_tick now) { check_interval_expired(struct fps_counter *counter, uint32_t now) {
if (now < counter->next_timestamp) { if (now < counter->next_timestamp) {
return; return;
} }
@@ -67,13 +67,13 @@ check_interval_expired(struct sc_fps_counter *counter, sc_tick now) {
counter->nr_skipped = 0; counter->nr_skipped = 0;
// add a multiple of the interval // add a multiple of the interval
uint32_t elapsed_slices = uint32_t elapsed_slices =
(now - counter->next_timestamp) / SC_FPS_COUNTER_INTERVAL + 1; (now - counter->next_timestamp) / FPS_COUNTER_INTERVAL + 1;
counter->next_timestamp += SC_FPS_COUNTER_INTERVAL * elapsed_slices; counter->next_timestamp += FPS_COUNTER_INTERVAL * elapsed_slices;
} }
static int static int
run_fps_counter(void *data) { run_fps_counter(void *data) {
struct sc_fps_counter *counter = data; struct fps_counter *counter = data;
sc_mutex_lock(&counter->mutex); sc_mutex_lock(&counter->mutex);
while (!counter->interrupted) { while (!counter->interrupted) {
@@ -94,9 +94,9 @@ run_fps_counter(void *data) {
} }
bool bool
sc_fps_counter_start(struct sc_fps_counter *counter) { fps_counter_start(struct fps_counter *counter) {
sc_mutex_lock(&counter->mutex); sc_mutex_lock(&counter->mutex);
counter->next_timestamp = sc_tick_now() + SC_FPS_COUNTER_INTERVAL; counter->next_timestamp = sc_tick_now() + FPS_COUNTER_INTERVAL;
counter->nr_rendered = 0; counter->nr_rendered = 0;
counter->nr_skipped = 0; counter->nr_skipped = 0;
sc_mutex_unlock(&counter->mutex); sc_mutex_unlock(&counter->mutex);
@@ -117,24 +117,22 @@ sc_fps_counter_start(struct sc_fps_counter *counter) {
counter->thread_started = true; counter->thread_started = true;
} }
LOGI("FPS counter started");
return true; return true;
} }
void void
sc_fps_counter_stop(struct sc_fps_counter *counter) { fps_counter_stop(struct fps_counter *counter) {
set_started(counter, false); set_started(counter, false);
sc_cond_signal(&counter->state_cond); sc_cond_signal(&counter->state_cond);
LOGI("FPS counter stopped");
} }
bool bool
sc_fps_counter_is_started(struct sc_fps_counter *counter) { fps_counter_is_started(struct fps_counter *counter) {
return is_started(counter); return is_started(counter);
} }
void void
sc_fps_counter_interrupt(struct sc_fps_counter *counter) { fps_counter_interrupt(struct fps_counter *counter) {
if (!counter->thread_started) { if (!counter->thread_started) {
return; return;
} }
@@ -147,7 +145,7 @@ sc_fps_counter_interrupt(struct sc_fps_counter *counter) {
} }
void void
sc_fps_counter_join(struct sc_fps_counter *counter) { fps_counter_join(struct fps_counter *counter) {
if (counter->thread_started) { if (counter->thread_started) {
// interrupted must be set by the thread calling join(), so no need to // interrupted must be set by the thread calling join(), so no need to
// lock for the assertion // lock for the assertion
@@ -158,7 +156,7 @@ sc_fps_counter_join(struct sc_fps_counter *counter) {
} }
void void
sc_fps_counter_add_rendered_frame(struct sc_fps_counter *counter) { fps_counter_add_rendered_frame(struct fps_counter *counter) {
if (!is_started(counter)) { if (!is_started(counter)) {
return; return;
} }
@@ -171,7 +169,7 @@ sc_fps_counter_add_rendered_frame(struct sc_fps_counter *counter) {
} }
void void
sc_fps_counter_add_skipped_frame(struct sc_fps_counter *counter) { fps_counter_add_skipped_frame(struct fps_counter *counter) {
if (!is_started(counter)) { if (!is_started(counter)) {
return; return;
} }

View File

@@ -9,7 +9,7 @@
#include "util/thread.h" #include "util/thread.h"
struct sc_fps_counter { struct fps_counter {
sc_thread thread; sc_thread thread;
sc_mutex mutex; sc_mutex mutex;
sc_cond state_cond; sc_cond state_cond;
@@ -28,32 +28,32 @@ struct sc_fps_counter {
}; };
bool bool
sc_fps_counter_init(struct sc_fps_counter *counter); fps_counter_init(struct fps_counter *counter);
void void
sc_fps_counter_destroy(struct sc_fps_counter *counter); fps_counter_destroy(struct fps_counter *counter);
bool bool
sc_fps_counter_start(struct sc_fps_counter *counter); fps_counter_start(struct fps_counter *counter);
void void
sc_fps_counter_stop(struct sc_fps_counter *counter); fps_counter_stop(struct fps_counter *counter);
bool bool
sc_fps_counter_is_started(struct sc_fps_counter *counter); fps_counter_is_started(struct fps_counter *counter);
// request to stop the thread (on quit) // request to stop the thread (on quit)
// must be called before sc_fps_counter_join() // must be called before fps_counter_join()
void void
sc_fps_counter_interrupt(struct sc_fps_counter *counter); fps_counter_interrupt(struct fps_counter *counter);
void void
sc_fps_counter_join(struct sc_fps_counter *counter); fps_counter_join(struct fps_counter *counter);
void void
sc_fps_counter_add_rendered_frame(struct sc_fps_counter *counter); fps_counter_add_rendered_frame(struct fps_counter *counter);
void void
sc_fps_counter_add_skipped_frame(struct sc_fps_counter *counter); fps_counter_add_skipped_frame(struct fps_counter *counter);
#endif #endif

View File

@@ -242,14 +242,18 @@ set_screen_power_mode(struct sc_controller *controller,
} }
static void static void
switch_fps_counter_state(struct sc_fps_counter *fps_counter) { switch_fps_counter_state(struct fps_counter *fps_counter) {
// the started state can only be written from the current thread, so there // the started state can only be written from the current thread, so there
// is no ToCToU issue // is no ToCToU issue
if (sc_fps_counter_is_started(fps_counter)) { if (fps_counter_is_started(fps_counter)) {
sc_fps_counter_stop(fps_counter); fps_counter_stop(fps_counter);
LOGI("FPS counter stopped");
} else { } else {
sc_fps_counter_start(fps_counter); if (fps_counter_start(fps_counter)) {
// Any error is already logged LOGI("FPS counter started");
} else {
LOGE("FPS counter starting failed");
}
} }
} }

View File

@@ -15,7 +15,27 @@
#include "scrcpy.h" #include "scrcpy.h"
#include "usb/scrcpy_otg.h" #include "usb/scrcpy_otg.h"
#include "util/log.h" #include "util/log.h"
#include "version.h"
static void
print_version(void) {
printf("\ndependencies:\n");
printf(" - SDL %d.%d.%d\n", SDL_MAJOR_VERSION, SDL_MINOR_VERSION,
SDL_PATCHLEVEL);
printf(" - libavcodec %d.%d.%d\n", LIBAVCODEC_VERSION_MAJOR,
LIBAVCODEC_VERSION_MINOR,
LIBAVCODEC_VERSION_MICRO);
printf(" - libavformat %d.%d.%d\n", LIBAVFORMAT_VERSION_MAJOR,
LIBAVFORMAT_VERSION_MINOR,
LIBAVFORMAT_VERSION_MICRO);
printf(" - libavutil %d.%d.%d\n", LIBAVUTIL_VERSION_MAJOR,
LIBAVUTIL_VERSION_MINOR,
LIBAVUTIL_VERSION_MICRO);
#ifdef HAVE_V4L2
printf(" - libavdevice %d.%d.%d\n", LIBAVDEVICE_VERSION_MAJOR,
LIBAVDEVICE_VERSION_MINOR,
LIBAVDEVICE_VERSION_MICRO);
#endif
}
int int
main(int argc, char *argv[]) { main(int argc, char *argv[]) {
@@ -51,7 +71,7 @@ main(int argc, char *argv[]) {
} }
if (args.version) { if (args.version) {
scrcpy_print_version(); print_version();
return 0; return 0;
} }

View File

@@ -62,6 +62,4 @@ const struct scrcpy_options scrcpy_options_default = {
.tcpip_dst = NULL, .tcpip_dst = NULL,
.select_tcpip = false, .select_tcpip = false,
.select_usb = false, .select_usb = false,
.cleanup = true,
.start_fps_counter = false,
}; };

View File

@@ -137,8 +137,6 @@ struct scrcpy_options {
const char *tcpip_dst; const char *tcpip_dst;
bool select_usb; bool select_usb;
bool select_tcpip; bool select_tcpip;
bool cleanup;
bool start_fps_counter;
}; };
extern const struct scrcpy_options scrcpy_options_default; extern const struct scrcpy_options scrcpy_options_default;

View File

@@ -320,7 +320,6 @@ scrcpy(struct scrcpy_options *options) {
.downsize_on_error = options->downsize_on_error, .downsize_on_error = options->downsize_on_error,
.tcpip = options->tcpip, .tcpip = options->tcpip,
.tcpip_dst = options->tcpip_dst, .tcpip_dst = options->tcpip_dst,
.cleanup = options->cleanup,
}; };
static const struct sc_server_callbacks cbs = { static const struct sc_server_callbacks cbs = {
@@ -588,7 +587,6 @@ aoa_hid_end:
.rotation = options->rotation, .rotation = options->rotation,
.mipmaps = options->mipmaps, .mipmaps = options->mipmaps,
.fullscreen = options->fullscreen, .fullscreen = options->fullscreen,
.start_fps_counter = options->start_fps_counter,
.buffering_time = options->display_buffer, .buffering_time = options->display_buffer,
}; };

View File

@@ -163,44 +163,14 @@ sc_screen_is_relative_mode(struct sc_screen *screen) {
} }
static void static void
sc_screen_set_mouse_capture(struct sc_screen *screen, bool capture) { sc_screen_capture_mouse(struct sc_screen *screen, bool capture) {
#ifdef __APPLE__
// Workaround for SDL bug on macOS:
// <https://github.com/libsdl-org/SDL/issues/5340>
if (capture) {
int mouse_x, mouse_y;
SDL_GetGlobalMouseState(&mouse_x, &mouse_y);
int x, y, w, h;
SDL_GetWindowPosition(screen->window, &x, &y);
SDL_GetWindowSize(screen->window, &w, &h);
bool outside_window = mouse_x < x || mouse_x >= x + w
|| mouse_y < y || mouse_y >= y + h;
if (outside_window) {
SDL_WarpMouseInWindow(screen->window, w / 2, h / 2);
}
}
#else
(void) screen;
#endif
if (SDL_SetRelativeMouseMode(capture)) { if (SDL_SetRelativeMouseMode(capture)) {
LOGE("Could not set relative mouse mode to %s: %s", LOGE("Could not set relative mouse mode to %s: %s",
capture ? "true" : "false", SDL_GetError()); capture ? "true" : "false", SDL_GetError());
return;
} }
}
static inline bool screen->mouse_captured = capture;
sc_screen_get_mouse_capture(struct sc_screen *screen) {
(void) screen;
return SDL_GetRelativeMouseMode();
}
static inline void
sc_screen_toggle_mouse_capture(struct sc_screen *screen) {
(void) screen;
bool new_value = !sc_screen_get_mouse_capture(screen);
sc_screen_set_mouse_capture(screen, new_value);
} }
static void static void
@@ -370,7 +340,7 @@ sc_video_buffer_on_new_frame(struct sc_video_buffer *vb, bool previous_skipped,
bool need_new_event; bool need_new_event;
if (previous_skipped) { if (previous_skipped) {
sc_fps_counter_add_skipped_frame(&screen->fps_counter); fps_counter_add_skipped_frame(&screen->fps_counter);
// The EVENT_NEW_FRAME triggered for the previous frame will consume // The EVENT_NEW_FRAME triggered for the previous frame will consume
// this new frame instead, unless the previous event failed // this new frame instead, unless the previous event failed
need_new_event = screen->event_failed; need_new_event = screen->event_failed;
@@ -402,6 +372,7 @@ sc_screen_init(struct sc_screen *screen,
screen->fullscreen = false; screen->fullscreen = false;
screen->maximized = false; screen->maximized = false;
screen->event_failed = false; screen->event_failed = false;
screen->mouse_captured = false;
screen->mouse_capture_key_pressed = 0; screen->mouse_capture_key_pressed = 0;
screen->req.x = params->window_x; screen->req.x = params->window_x;
@@ -409,7 +380,6 @@ sc_screen_init(struct sc_screen *screen,
screen->req.width = params->window_width; screen->req.width = params->window_width;
screen->req.height = params->window_height; screen->req.height = params->window_height;
screen->req.fullscreen = params->fullscreen; screen->req.fullscreen = params->fullscreen;
screen->req.start_fps_counter = params->start_fps_counter;
static const struct sc_video_buffer_callbacks cbs = { static const struct sc_video_buffer_callbacks cbs = {
.on_new_frame = sc_video_buffer_on_new_frame, .on_new_frame = sc_video_buffer_on_new_frame,
@@ -426,7 +396,7 @@ sc_screen_init(struct sc_screen *screen,
goto error_destroy_video_buffer; goto error_destroy_video_buffer;
} }
if (!sc_fps_counter_init(&screen->fps_counter)) { if (!fps_counter_init(&screen->fps_counter)) {
goto error_stop_and_join_video_buffer; goto error_stop_and_join_video_buffer;
} }
@@ -558,7 +528,7 @@ error_destroy_renderer:
error_destroy_window: error_destroy_window:
SDL_DestroyWindow(screen->window); SDL_DestroyWindow(screen->window);
error_destroy_fps_counter: error_destroy_fps_counter:
sc_fps_counter_destroy(&screen->fps_counter); fps_counter_destroy(&screen->fps_counter);
error_stop_and_join_video_buffer: error_stop_and_join_video_buffer:
sc_video_buffer_stop(&screen->vb); sc_video_buffer_stop(&screen->vb);
sc_video_buffer_join(&screen->vb); sc_video_buffer_join(&screen->vb);
@@ -586,10 +556,6 @@ sc_screen_show_initial_window(struct sc_screen *screen) {
sc_screen_switch_fullscreen(screen); sc_screen_switch_fullscreen(screen);
} }
if (screen->req.start_fps_counter) {
sc_fps_counter_start(&screen->fps_counter);
}
SDL_ShowWindow(screen->window); SDL_ShowWindow(screen->window);
} }
@@ -601,13 +567,13 @@ sc_screen_hide_window(struct sc_screen *screen) {
void void
sc_screen_interrupt(struct sc_screen *screen) { sc_screen_interrupt(struct sc_screen *screen) {
sc_video_buffer_stop(&screen->vb); sc_video_buffer_stop(&screen->vb);
sc_fps_counter_interrupt(&screen->fps_counter); fps_counter_interrupt(&screen->fps_counter);
} }
void void
sc_screen_join(struct sc_screen *screen) { sc_screen_join(struct sc_screen *screen) {
sc_video_buffer_join(&screen->vb); sc_video_buffer_join(&screen->vb);
sc_fps_counter_join(&screen->fps_counter); fps_counter_join(&screen->fps_counter);
} }
void void
@@ -619,7 +585,7 @@ sc_screen_destroy(struct sc_screen *screen) {
SDL_DestroyTexture(screen->texture); SDL_DestroyTexture(screen->texture);
SDL_DestroyRenderer(screen->renderer); SDL_DestroyRenderer(screen->renderer);
SDL_DestroyWindow(screen->window); SDL_DestroyWindow(screen->window);
sc_fps_counter_destroy(&screen->fps_counter); fps_counter_destroy(&screen->fps_counter);
sc_video_buffer_destroy(&screen->vb); sc_video_buffer_destroy(&screen->vb);
} }
@@ -729,7 +695,7 @@ sc_screen_update_frame(struct sc_screen *screen) {
sc_video_buffer_consume(&screen->vb, screen->frame); sc_video_buffer_consume(&screen->vb, screen->frame);
AVFrame *frame = screen->frame; AVFrame *frame = screen->frame;
sc_fps_counter_add_rendered_frame(&screen->fps_counter); fps_counter_add_rendered_frame(&screen->fps_counter);
struct sc_size new_frame_size = {frame->width, frame->height}; struct sc_size new_frame_size = {frame->width, frame->height};
if (!prepare_for_frame(screen, new_frame_size)) { if (!prepare_for_frame(screen, new_frame_size)) {
@@ -744,7 +710,7 @@ sc_screen_update_frame(struct sc_screen *screen) {
if (sc_screen_is_relative_mode(screen)) { if (sc_screen_is_relative_mode(screen)) {
// Capture mouse on start // Capture mouse on start
sc_screen_set_mouse_capture(screen, true); sc_screen_capture_mouse(screen, true);
} }
} }
@@ -857,7 +823,7 @@ sc_screen_handle_event(struct sc_screen *screen, SDL_Event *event) {
break; break;
case SDL_WINDOWEVENT_FOCUS_LOST: case SDL_WINDOWEVENT_FOCUS_LOST:
if (relative_mode) { if (relative_mode) {
sc_screen_set_mouse_capture(screen, false); sc_screen_capture_mouse(screen, false);
} }
break; break;
} }
@@ -887,7 +853,8 @@ sc_screen_handle_event(struct sc_screen *screen, SDL_Event *event) {
if (key == cap) { if (key == cap) {
// A mouse capture key has been pressed then released: // A mouse capture key has been pressed then released:
// toggle the capture mouse mode // toggle the capture mouse mode
sc_screen_toggle_mouse_capture(screen); sc_screen_capture_mouse(screen,
!screen->mouse_captured);
} }
// Mouse capture keys are never forwarded to the device // Mouse capture keys are never forwarded to the device
return; return;
@@ -897,7 +864,7 @@ sc_screen_handle_event(struct sc_screen *screen, SDL_Event *event) {
case SDL_MOUSEWHEEL: case SDL_MOUSEWHEEL:
case SDL_MOUSEMOTION: case SDL_MOUSEMOTION:
case SDL_MOUSEBUTTONDOWN: case SDL_MOUSEBUTTONDOWN:
if (relative_mode && !sc_screen_get_mouse_capture(screen)) { if (relative_mode && !screen->mouse_captured) {
// Do not forward to input manager, the mouse will be captured // Do not forward to input manager, the mouse will be captured
// on SDL_MOUSEBUTTONUP // on SDL_MOUSEBUTTONUP
return; return;
@@ -913,8 +880,8 @@ sc_screen_handle_event(struct sc_screen *screen, SDL_Event *event) {
} }
break; break;
case SDL_MOUSEBUTTONUP: case SDL_MOUSEBUTTONUP:
if (relative_mode && !sc_screen_get_mouse_capture(screen)) { if (relative_mode && !screen->mouse_captured) {
sc_screen_set_mouse_capture(screen, true); sc_screen_capture_mouse(screen, true);
return; return;
} }
break; break;

View File

@@ -26,7 +26,7 @@ struct sc_screen {
struct sc_input_manager im; struct sc_input_manager im;
struct sc_video_buffer vb; struct sc_video_buffer vb;
struct sc_fps_counter fps_counter; struct fps_counter fps_counter;
// The initial requested window properties // The initial requested window properties
struct { struct {
@@ -35,7 +35,6 @@ struct sc_screen {
uint16_t width; uint16_t width;
uint16_t height; uint16_t height;
bool fullscreen; bool fullscreen;
bool start_fps_counter;
} req; } req;
SDL_Window *window; SDL_Window *window;
@@ -61,6 +60,7 @@ struct sc_screen {
bool event_failed; // in case SDL_PushEvent() returned an error bool event_failed; // in case SDL_PushEvent() returned an error
bool mouse_captured; // only relevant in relative mouse mode
// To enable/disable mouse capture, a mouse capture key (LALT, LGUI or // To enable/disable mouse capture, a mouse capture key (LALT, LGUI or
// RGUI) must be pressed. This variable tracks the pressed capture key. // RGUI) must be pressed. This variable tracks the pressed capture key.
SDL_Keycode mouse_capture_key_pressed; SDL_Keycode mouse_capture_key_pressed;
@@ -94,7 +94,6 @@ struct sc_screen_params {
bool mipmaps; bool mipmaps;
bool fullscreen; bool fullscreen;
bool start_fps_counter;
sc_tick buffering_time; sc_tick buffering_time;
}; };

View File

@@ -244,10 +244,6 @@ execute_server(struct sc_server *server,
// By default, downsize_on_error is true // By default, downsize_on_error is true
ADD_PARAM("downsize_on_error=false"); ADD_PARAM("downsize_on_error=false");
} }
if (!params->cleanup) {
// By default, cleanup is true
ADD_PARAM("cleanup=false");
}
#undef ADD_PARAM #undef ADD_PARAM
@@ -486,10 +482,8 @@ fail:
} }
} }
if (tunnel->enabled) { // Always leave this function with tunnel disabled
// Always leave this function with tunnel disabled sc_adb_tunnel_close(tunnel, &server->intr, serial);
sc_adb_tunnel_close(tunnel, &server->intr, serial);
}
return false; return false;
} }

View File

@@ -46,7 +46,6 @@ struct sc_server_params {
const char *tcpip_dst; const char *tcpip_dst;
bool select_usb; bool select_usb;
bool select_tcpip; bool select_tcpip;
bool cleanup;
}; };
struct sc_server { struct sc_server {

View File

@@ -89,10 +89,8 @@ scrcpy_otg(struct scrcpy_options *options) {
goto end; goto end;
} }
usb_device_initialized = true; LOGI("USB device: %s (%04x:%04x) %s %s", usb_device.serial,
(unsigned) usb_device.vid, (unsigned) usb_device.pid,
LOGI("USB device: %s (%04" PRIx16 ":%04" PRIx16 ") %s %s",
usb_device.serial, usb_device.vid, usb_device.pid,
usb_device.manufacturer, usb_device.product); usb_device.manufacturer, usb_device.product);
ok = sc_usb_connect(&s->usb, usb_device.device, &cbs, NULL); ok = sc_usb_connect(&s->usb, usb_device.device, &cbs, NULL);

View File

@@ -5,44 +5,15 @@
#include "util/log.h" #include "util/log.h"
static void static void
sc_screen_otg_set_mouse_capture(struct sc_screen_otg *screen, bool capture) { sc_screen_otg_capture_mouse(struct sc_screen_otg *screen, bool capture) {
#ifdef __APPLE__ assert(screen->mouse);
// Workaround for SDL bug on macOS:
// <https://github.com/libsdl-org/SDL/issues/5340>
if (capture) {
int mouse_x, mouse_y;
SDL_GetGlobalMouseState(&mouse_x, &mouse_y);
int x, y, w, h;
SDL_GetWindowPosition(screen->window, &x, &y);
SDL_GetWindowSize(screen->window, &w, &h);
bool outside_window = mouse_x < x || mouse_x >= x + w
|| mouse_y < y || mouse_y >= y + h;
if (outside_window) {
SDL_WarpMouseInWindow(screen->window, w / 2, h / 2);
}
}
#else
(void) screen;
#endif
if (SDL_SetRelativeMouseMode(capture)) { if (SDL_SetRelativeMouseMode(capture)) {
LOGE("Could not set relative mouse mode to %s: %s", LOGE("Could not set relative mouse mode to %s: %s",
capture ? "true" : "false", SDL_GetError()); capture ? "true" : "false", SDL_GetError());
return;
} }
}
static inline bool screen->mouse_captured = capture;
sc_screen_otg_get_mouse_capture(struct sc_screen_otg *screen) {
(void) screen;
return SDL_GetRelativeMouseMode();
}
static inline void
sc_screen_otg_toggle_mouse_capture(struct sc_screen_otg *screen) {
(void) screen;
bool new_value = !sc_screen_otg_get_mouse_capture(screen);
sc_screen_otg_set_mouse_capture(screen, new_value);
} }
static void static void
@@ -60,6 +31,7 @@ sc_screen_otg_init(struct sc_screen_otg *screen,
screen->keyboard = params->keyboard; screen->keyboard = params->keyboard;
screen->mouse = params->mouse; screen->mouse = params->mouse;
screen->mouse_captured = false;
screen->mouse_capture_key_pressed = 0; screen->mouse_capture_key_pressed = 0;
const char *title = params->window_title; const char *title = params->window_title;
@@ -109,7 +81,7 @@ sc_screen_otg_init(struct sc_screen_otg *screen,
if (screen->mouse) { if (screen->mouse) {
// Capture mouse on start // Capture mouse on start
sc_screen_otg_set_mouse_capture(screen, true); sc_screen_otg_capture_mouse(screen, true);
} }
return true; return true;
@@ -221,7 +193,7 @@ sc_screen_otg_handle_event(struct sc_screen_otg *screen, SDL_Event *event) {
break; break;
case SDL_WINDOWEVENT_FOCUS_LOST: case SDL_WINDOWEVENT_FOCUS_LOST:
if (screen->mouse) { if (screen->mouse) {
sc_screen_otg_set_mouse_capture(screen, false); sc_screen_otg_capture_mouse(screen, false);
} }
break; break;
} }
@@ -255,7 +227,8 @@ sc_screen_otg_handle_event(struct sc_screen_otg *screen, SDL_Event *event) {
if (key == cap) { if (key == cap) {
// A mouse capture key has been pressed then released: // A mouse capture key has been pressed then released:
// toggle the capture mouse mode // toggle the capture mouse mode
sc_screen_otg_toggle_mouse_capture(screen); sc_screen_otg_capture_mouse(screen,
!screen->mouse_captured);
} }
// Mouse capture keys are never forwarded to the device // Mouse capture keys are never forwarded to the device
return; return;
@@ -267,26 +240,26 @@ sc_screen_otg_handle_event(struct sc_screen_otg *screen, SDL_Event *event) {
} }
break; break;
case SDL_MOUSEMOTION: case SDL_MOUSEMOTION:
if (screen->mouse && sc_screen_otg_get_mouse_capture(screen)) { if (screen->mouse && screen->mouse_captured) {
sc_screen_otg_process_mouse_motion(screen, &event->motion); sc_screen_otg_process_mouse_motion(screen, &event->motion);
} }
break; break;
case SDL_MOUSEBUTTONDOWN: case SDL_MOUSEBUTTONDOWN:
if (screen->mouse && sc_screen_otg_get_mouse_capture(screen)) { if (screen->mouse && screen->mouse_captured) {
sc_screen_otg_process_mouse_button(screen, &event->button); sc_screen_otg_process_mouse_button(screen, &event->button);
} }
break; break;
case SDL_MOUSEBUTTONUP: case SDL_MOUSEBUTTONUP:
if (screen->mouse) { if (screen->mouse) {
if (sc_screen_otg_get_mouse_capture(screen)) { if (screen->mouse_captured) {
sc_screen_otg_process_mouse_button(screen, &event->button); sc_screen_otg_process_mouse_button(screen, &event->button);
} else { } else {
sc_screen_otg_set_mouse_capture(screen, true); sc_screen_otg_capture_mouse(screen, true);
} }
} }
break; break;
case SDL_MOUSEWHEEL: case SDL_MOUSEWHEEL:
if (screen->mouse && sc_screen_otg_get_mouse_capture(screen)) { if (screen->mouse && screen->mouse_captured) {
sc_screen_otg_process_mouse_wheel(screen, &event->wheel); sc_screen_otg_process_mouse_wheel(screen, &event->wheel);
} }
break; break;

View File

@@ -18,6 +18,7 @@ struct sc_screen_otg {
SDL_Texture *texture; SDL_Texture *texture;
// See equivalent mechanism in screen.h // See equivalent mechanism in screen.h
bool mouse_captured;
SDL_Keycode mouse_capture_key_pressed; SDL_Keycode mouse_capture_key_pressed;
}; };

View File

@@ -40,8 +40,9 @@ sc_usb_read_device(libusb_device *device, struct sc_usb_device *out) {
if (result < 0) { if (result < 0) {
// Log at debug level because it is expected that some non-Android USB // Log at debug level because it is expected that some non-Android USB
// devices present on the computer require special permissions // devices present on the computer require special permissions
LOGD("Open USB device %04" PRIx16 ":%04" PRIx16 ": libusb error: %s", LOGD("Open USB device %04x:%04x: libusb error: %s",
desc.idVendor, desc.idProduct, libusb_strerror(result)); (unsigned) desc.idVendor, (unsigned) desc.idProduct,
libusb_strerror(result));
return false; return false;
} }
@@ -146,8 +147,10 @@ sc_usb_devices_log(enum sc_log_level level, struct sc_usb_device *devices,
for (size_t i = 0; i < count; ++i) { for (size_t i = 0; i < count; ++i) {
struct sc_usb_device *d = &devices[i]; struct sc_usb_device *d = &devices[i];
const char *selection = d->selected ? "-->" : " "; const char *selection = d->selected ? "-->" : " ";
LOG(level, " %s %-18s (%04" PRIx16 ":%04" PRIx16 ") %s %s", // Convert uint16_t to unsigned because PRIx16 may not exist on Windows
selection, d->serial, d->vid, d->pid, d->manufacturer, d->product); LOG(level, " %s %-18s (%04x:%04x) %s %s",
selection, d->serial, (unsigned) d->vid, (unsigned) d->pid,
d->manufacturer, d->product);
} }
} }
@@ -188,7 +191,9 @@ sc_usb_select_device(struct sc_usb *usb, const char *serial,
LOGE("Multiple (%" SC_PRIsizet ") USB devices:", sel_count); LOGE("Multiple (%" SC_PRIsizet ") USB devices:", sel_count);
} }
sc_usb_devices_log(SC_LOG_LEVEL_ERROR, usb_devices, count); sc_usb_devices_log(SC_LOG_LEVEL_ERROR, usb_devices, count);
LOGE("Select a device via -s (--serial)"); if (!serial) {
LOGE("Specify the device via -s or --serial");
}
sc_usb_devices_destroy_all(usb_devices, count); sc_usb_devices_destroy_all(usb_devices, count);
return false; return false;
} }
@@ -216,7 +221,7 @@ sc_usb_destroy(struct sc_usb *usb) {
libusb_exit(usb->context); libusb_exit(usb->context);
} }
static int static LIBUSB_CALL int
sc_usb_libusb_callback(libusb_context *ctx, libusb_device *device, sc_usb_libusb_callback(libusb_context *ctx, libusb_device *device,
libusb_hotplug_event event, void *userdata) { libusb_hotplug_event event, void *userdata) {
(void) ctx; (void) ctx;
@@ -254,8 +259,7 @@ run_libusb_event_handler(void *data) {
static bool static bool
sc_usb_register_callback(struct sc_usb *usb) { sc_usb_register_callback(struct sc_usb *usb) {
if (!libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)) { if (!libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)) {
LOGW("On this platform, libusb does not have hotplug capability; " LOGW("libusb does not have hotplug capability");
"device disconnection will not be detected properly");
return false; return false;
} }

View File

@@ -42,7 +42,7 @@ void
sc_usb_device_destroy(struct sc_usb_device *usb_device); sc_usb_device_destroy(struct sc_usb_device *usb_device);
/** /**
* Move src to dst * Move src to dest
* *
* After this call, the content of src is undefined, except that * After this call, the content of src is undefined, except that
* sc_usb_device_destroy() can be called. * sc_usb_device_destroy() can be called.

View File

@@ -1,5 +1,5 @@
#ifndef SC_BUFFER_UTIL_H #ifndef BUFFER_UTIL_H
#define SC_BUFFER_UTIL_H #define BUFFER_UTIL_H
#include "common.h" #include "common.h"
@@ -7,13 +7,13 @@
#include <stdint.h> #include <stdint.h>
static inline void static inline void
sc_write16be(uint8_t *buf, uint16_t value) { buffer_write16be(uint8_t *buf, uint16_t value) {
buf[0] = value >> 8; buf[0] = value >> 8;
buf[1] = value; buf[1] = value;
} }
static inline void static inline void
sc_write32be(uint8_t *buf, uint32_t value) { buffer_write32be(uint8_t *buf, uint32_t value) {
buf[0] = value >> 24; buf[0] = value >> 24;
buf[1] = value >> 16; buf[1] = value >> 16;
buf[2] = value >> 8; buf[2] = value >> 8;
@@ -21,25 +21,25 @@ sc_write32be(uint8_t *buf, uint32_t value) {
} }
static inline void static inline void
sc_write64be(uint8_t *buf, uint64_t value) { buffer_write64be(uint8_t *buf, uint64_t value) {
sc_write32be(buf, value >> 32); buffer_write32be(buf, value >> 32);
sc_write32be(&buf[4], (uint32_t) value); buffer_write32be(&buf[4], (uint32_t) value);
} }
static inline uint16_t static inline uint16_t
sc_read16be(const uint8_t *buf) { buffer_read16be(const uint8_t *buf) {
return (buf[0] << 8) | buf[1]; return (buf[0] << 8) | buf[1];
} }
static inline uint32_t static inline uint32_t
sc_read32be(const uint8_t *buf) { buffer_read32be(const uint8_t *buf) {
return ((uint32_t) buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; return ((uint32_t) buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
} }
static inline uint64_t static inline uint64_t
sc_read64be(const uint8_t *buf) { buffer_read64be(const uint8_t *buf) {
uint32_t msb = sc_read32be(buf); uint32_t msb = buffer_read32be(buf);
uint32_t lsb = sc_read32be(&buf[4]); uint32_t lsb = buffer_read32be(&buf[4]);
return ((uint64_t) msb << 32) | lsb; return ((uint64_t) msb << 32) | lsb;
} }

View File

@@ -136,9 +136,7 @@ sc_cond_timedwait(sc_cond *cond, sc_mutex *mutex, sc_tick deadline) {
return false; // timeout return false; // timeout
} }
// Round up to the next millisecond to guarantee that the deadline is uint32_t ms = SC_TICK_TO_MS(deadline - now);
// reached when returning due to timeout
uint32_t ms = SC_TICK_TO_MS(deadline - now + SC_TICK_FROM_MS(1) - 1);
int r = SDL_CondWaitTimeout(cond->cond, mutex->mutex, ms); int r = SDL_CondWaitTimeout(cond->cond, mutex->mutex, ms);
#ifndef NDEBUG #ifndef NDEBUG
if (r < 0) { if (r < 0) {
@@ -150,8 +148,6 @@ sc_cond_timedwait(sc_cond *cond, sc_mutex *mutex, sc_tick deadline) {
memory_order_relaxed); memory_order_relaxed);
#endif #endif
assert(r == 0 || r == SDL_MUTEX_TIMEDOUT); assert(r == 0 || r == SDL_MUTEX_TIMEDOUT);
// The deadline is reached on timeout
assert(r != SDL_MUTEX_TIMEDOUT || sc_tick_now() >= deadline);
return r == 0; return r == 0;
} }

View File

@@ -1,67 +0,0 @@
#include "version.h"
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/avutil.h>
#ifdef HAVE_V4L2
# include <libavdevice/avdevice.h>
#endif
#ifdef HAVE_USB
# include <libusb-1.0/libusb.h>
#endif
void
scrcpy_print_version(void) {
printf("\nDependencies (compiled / linked):\n");
SDL_version sdl;
SDL_GetVersion(&sdl);
printf(" - SDL: %u.%u.%u / %u.%u.%u\n",
SDL_MAJOR_VERSION, SDL_MINOR_VERSION, SDL_PATCHLEVEL,
(unsigned) sdl.major, (unsigned) sdl.minor, (unsigned) sdl.patch);
unsigned avcodec = avcodec_version();
printf(" - libavcodec: %u.%u.%u / %u.%u.%u\n",
LIBAVCODEC_VERSION_MAJOR,
LIBAVCODEC_VERSION_MINOR,
LIBAVCODEC_VERSION_MICRO,
AV_VERSION_MAJOR(avcodec),
AV_VERSION_MINOR(avcodec),
AV_VERSION_MICRO(avcodec));
unsigned avformat = avformat_version();
printf(" - libavformat: %u.%u.%u / %u.%u.%u\n",
LIBAVFORMAT_VERSION_MAJOR,
LIBAVFORMAT_VERSION_MINOR,
LIBAVFORMAT_VERSION_MICRO,
AV_VERSION_MAJOR(avformat),
AV_VERSION_MINOR(avformat),
AV_VERSION_MICRO(avformat));
unsigned avutil = avutil_version();
printf(" - libavutil: %u.%u.%u / %u.%u.%u\n",
LIBAVUTIL_VERSION_MAJOR,
LIBAVUTIL_VERSION_MINOR,
LIBAVUTIL_VERSION_MICRO,
AV_VERSION_MAJOR(avutil),
AV_VERSION_MINOR(avutil),
AV_VERSION_MICRO(avutil));
#ifdef HAVE_V4L2
unsigned avdevice = avdevice_version();
printf(" - libavdevice: %u.%u.%u / %u.%u.%u\n",
LIBAVDEVICE_VERSION_MAJOR,
LIBAVDEVICE_VERSION_MINOR,
LIBAVDEVICE_VERSION_MICRO,
AV_VERSION_MAJOR(avdevice),
AV_VERSION_MINOR(avdevice),
AV_VERSION_MICRO(avdevice));
#endif
#ifdef HAVE_USB
const struct libusb_version *usb = libusb_get_version();
// The compiled version may not be known
printf(" - libusb: - / %u.%u.%u\n",
(unsigned) usb->major, (unsigned) usb->minor, (unsigned) usb->micro);
#endif
}

View File

@@ -1,9 +0,0 @@
#ifndef SC_VERSION_H
#define SC_VERSION_H
#include "common.h"
void
scrcpy_print_version(void);
#endif

View File

@@ -91,6 +91,7 @@ static void test_adb_devices_daemon_start_mixed() {
struct sc_adb_device *device = &devices[0]; struct sc_adb_device *device = &devices[0];
assert(!strcmp("0123456789abcdef", device->serial)); assert(!strcmp("0123456789abcdef", device->serial));
assert(!strcmp("unauthorized", device->state)); assert(!strcmp("unauthorized", device->state));
fprintf(stderr, "==== [%s]\n", device->model);
assert(!device->model); assert(!device->model);
device = &devices[1]; device = &devices[1];

View File

@@ -8,7 +8,7 @@ static void test_buffer_write16be(void) {
uint16_t val = 0xABCD; uint16_t val = 0xABCD;
uint8_t buf[2]; uint8_t buf[2];
sc_write16be(buf, val); buffer_write16be(buf, val);
assert(buf[0] == 0xAB); assert(buf[0] == 0xAB);
assert(buf[1] == 0xCD); assert(buf[1] == 0xCD);
@@ -18,7 +18,7 @@ static void test_buffer_write32be(void) {
uint32_t val = 0xABCD1234; uint32_t val = 0xABCD1234;
uint8_t buf[4]; uint8_t buf[4];
sc_write32be(buf, val); buffer_write32be(buf, val);
assert(buf[0] == 0xAB); assert(buf[0] == 0xAB);
assert(buf[1] == 0xCD); assert(buf[1] == 0xCD);
@@ -30,7 +30,7 @@ static void test_buffer_write64be(void) {
uint64_t val = 0xABCD1234567890EF; uint64_t val = 0xABCD1234567890EF;
uint8_t buf[8]; uint8_t buf[8];
sc_write64be(buf, val); buffer_write64be(buf, val);
assert(buf[0] == 0xAB); assert(buf[0] == 0xAB);
assert(buf[1] == 0xCD); assert(buf[1] == 0xCD);
@@ -45,7 +45,7 @@ static void test_buffer_write64be(void) {
static void test_buffer_read16be(void) { static void test_buffer_read16be(void) {
uint8_t buf[2] = {0xAB, 0xCD}; uint8_t buf[2] = {0xAB, 0xCD};
uint16_t val = sc_read16be(buf); uint16_t val = buffer_read16be(buf);
assert(val == 0xABCD); assert(val == 0xABCD);
} }
@@ -53,7 +53,7 @@ static void test_buffer_read16be(void) {
static void test_buffer_read32be(void) { static void test_buffer_read32be(void) {
uint8_t buf[4] = {0xAB, 0xCD, 0x12, 0x34}; uint8_t buf[4] = {0xAB, 0xCD, 0x12, 0x34};
uint32_t val = sc_read32be(buf); uint32_t val = buffer_read32be(buf);
assert(val == 0xABCD1234); assert(val == 0xABCD1234);
} }
@@ -62,7 +62,7 @@ static void test_buffer_read64be(void) {
uint8_t buf[8] = {0xAB, 0xCD, 0x12, 0x34, uint8_t buf[8] = {0xAB, 0xCD, 0x12, 0x34,
0x56, 0x78, 0x90, 0xEF}; 0x56, 0x78, 0x90, 0xEF};
uint64_t val = sc_read64be(buf); uint64_t val = buffer_read64be(buf);
assert(val == 0xABCD1234567890EF); assert(val == 0xABCD1234567890EF);
} }

View File

@@ -21,3 +21,5 @@ ffmpeg_avformat = 'avformat-58'
ffmpeg_avutil = 'avutil-56' ffmpeg_avutil = 'avutil-56'
prebuilt_ffmpeg = 'ffmpeg-win32-4.3.1' prebuilt_ffmpeg = 'ffmpeg-win32-4.3.1'
prebuilt_sdl2 = 'SDL2-2.0.20/i686-w64-mingw32' prebuilt_sdl2 = 'SDL2-2.0.20/i686-w64-mingw32'
prebuilt_libusb_root = 'libusb-1.0.25'
prebuilt_libusb = prebuilt_libusb_root + '/MinGW32'

View File

@@ -21,3 +21,5 @@ ffmpeg_avformat = 'avformat-59'
ffmpeg_avutil = 'avutil-57' ffmpeg_avutil = 'avutil-57'
prebuilt_ffmpeg = 'ffmpeg-win64-5.0' prebuilt_ffmpeg = 'ffmpeg-win64-5.0'
prebuilt_sdl2 = 'SDL2-2.0.20/x86_64-w64-mingw32' prebuilt_sdl2 = 'SDL2-2.0.20/x86_64-w64-mingw32'
prebuilt_libusb_root = 'libusb-1.0.25'
prebuilt_libusb = prebuilt_libusb_root + '/MinGW64'

View File

@@ -12,7 +12,7 @@ echo "$PREBUILT_SERVER_SHA256 scrcpy-server" | sha256sum --check
echo "[scrcpy] Building client..." echo "[scrcpy] Building client..."
rm -rf "$BUILDDIR" rm -rf "$BUILDDIR"
meson "$BUILDDIR" --buildtype=release --strip -Db_lto=true \ meson "$BUILDDIR" --buildtype release --strip -Db_lto=true \
-Dprebuilt_server=scrcpy-server -Dprebuilt_server=scrcpy-server
cd "$BUILDDIR" cd "$BUILDDIR"
ninja ninja

View File

@@ -4,5 +4,3 @@ option('prebuilt_server', type: 'string', description: 'Path of the prebuilt ser
option('portable', type: 'boolean', value: false, description: 'Use scrcpy-server from the same directory as the scrcpy executable') 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', 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('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')

28
prebuilt-deps/prepare-libusb.sh Executable file
View File

@@ -0,0 +1,28 @@
#!/usr/bin/env bash
set -e
DIR=$(dirname ${BASH_SOURCE[0]})
cd "$DIR"
. common
mkdir -p "$PREBUILT_DATA_DIR"
cd "$PREBUILT_DATA_DIR"
DEP_DIR=libusb-1.0.25
FILENAME=libusb-1.0.25.7z
SHA256SUM=3d1c98416f454026034b2b5d67f8a294053898cb70a8b489874e75b136c6674d
if [[ -d "$DEP_DIR" ]]
then
echo "$DEP_DIR" found
exit 0
fi
get_file "https://github.com/libusb/libusb/releases/download/v1.0.25/$FILENAME" "$FILENAME" "$SHA256SUM"
mkdir "$DEP_DIR"
cd "$DEP_DIR"
7z x "../$FILENAME" \
MinGW32/dll/libusb-1.0.dll \
MinGW64/dll/libusb-1.0.dll \
include /

View File

@@ -63,14 +63,10 @@ build-server:
ninja -C "$(SERVER_BUILD_DIR)" ninja -C "$(SERVER_BUILD_DIR)"
prepare-deps-win32: prepare-deps-win32:
@app/prebuilt-deps/prepare-adb.sh @prebuilt-deps/prepare-adb.sh
@app/prebuilt-deps/prepare-sdl.sh @prebuilt-deps/prepare-sdl.sh
@app/prebuilt-deps/prepare-ffmpeg-win32.sh @prebuilt-deps/prepare-ffmpeg-win32.sh
@prebuilt-deps/prepare-libusb.sh
prepare-deps-win64:
@app/prebuilt-deps/prepare-adb.sh
@app/prebuilt-deps/prepare-sdl.sh
@app/prebuilt-deps/prepare-ffmpeg-win64.sh
build-win32: prepare-deps-win32 build-win32: prepare-deps-win32
[ -d "$(WIN32_BUILD_DIR)" ] || ( mkdir "$(WIN32_BUILD_DIR)" && \ [ -d "$(WIN32_BUILD_DIR)" ] || ( mkdir "$(WIN32_BUILD_DIR)" && \
@@ -81,6 +77,11 @@ build-win32: prepare-deps-win32
-Dportable=true ) -Dportable=true )
ninja -C "$(WIN32_BUILD_DIR)" ninja -C "$(WIN32_BUILD_DIR)"
prepare-deps-win64:
@prebuilt-deps/prepare-adb.sh
@prebuilt-deps/prepare-sdl.sh
@prebuilt-deps/prepare-ffmpeg-win64.sh
build-win64: prepare-deps-win64 build-win64: prepare-deps-win64
[ -d "$(WIN64_BUILD_DIR)" ] || ( mkdir "$(WIN64_BUILD_DIR)" && \ [ -d "$(WIN64_BUILD_DIR)" ] || ( mkdir "$(WIN64_BUILD_DIR)" && \
meson "$(WIN64_BUILD_DIR)" \ meson "$(WIN64_BUILD_DIR)" \
@@ -98,15 +99,16 @@ dist-win32: build-server build-win32
cp data/scrcpy-noconsole.vbs "$(DIST)/$(WIN32_TARGET_DIR)" cp data/scrcpy-noconsole.vbs "$(DIST)/$(WIN32_TARGET_DIR)"
cp data/icon.png "$(DIST)/$(WIN32_TARGET_DIR)" cp data/icon.png "$(DIST)/$(WIN32_TARGET_DIR)"
cp data/open_a_terminal_here.bat "$(DIST)/$(WIN32_TARGET_DIR)" cp data/open_a_terminal_here.bat "$(DIST)/$(WIN32_TARGET_DIR)"
cp app/prebuilt-deps/data/ffmpeg-win32-4.3.1/bin/avutil-56.dll "$(DIST)/$(WIN32_TARGET_DIR)/" cp prebuilt-deps/data/ffmpeg-win32-4.3.1/bin/avutil-56.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
cp app/prebuilt-deps/data/ffmpeg-win32-4.3.1/bin/avcodec-58.dll "$(DIST)/$(WIN32_TARGET_DIR)/" cp prebuilt-deps/data/ffmpeg-win32-4.3.1/bin/avcodec-58.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
cp app/prebuilt-deps/data/ffmpeg-win32-4.3.1/bin/avformat-58.dll "$(DIST)/$(WIN32_TARGET_DIR)/" cp prebuilt-deps/data/ffmpeg-win32-4.3.1/bin/avformat-58.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
cp app/prebuilt-deps/data/ffmpeg-win32-4.3.1/bin/swresample-3.dll "$(DIST)/$(WIN32_TARGET_DIR)/" cp prebuilt-deps/data/ffmpeg-win32-4.3.1/bin/swresample-3.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
cp app/prebuilt-deps/data/ffmpeg-win32-4.3.1/bin/swscale-5.dll "$(DIST)/$(WIN32_TARGET_DIR)/" cp prebuilt-deps/data/ffmpeg-win32-4.3.1/bin/swscale-5.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
cp app/prebuilt-deps/data/platform-tools-31.0.3/adb.exe "$(DIST)/$(WIN32_TARGET_DIR)/" cp prebuilt-deps/data/platform-tools-31.0.3/adb.exe "$(DIST)/$(WIN32_TARGET_DIR)/"
cp app/prebuilt-deps/data/platform-tools-31.0.3/AdbWinApi.dll "$(DIST)/$(WIN32_TARGET_DIR)/" cp prebuilt-deps/data/platform-tools-31.0.3/AdbWinApi.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
cp app/prebuilt-deps/data/platform-tools-31.0.3/AdbWinUsbApi.dll "$(DIST)/$(WIN32_TARGET_DIR)/" cp prebuilt-deps/data/platform-tools-31.0.3/AdbWinUsbApi.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
cp app/prebuilt-deps/data/SDL2-2.0.20/i686-w64-mingw32/bin/SDL2.dll "$(DIST)/$(WIN32_TARGET_DIR)/" cp prebuilt-deps/data/SDL2-2.0.20/i686-w64-mingw32/bin/SDL2.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
cp prebuilt-deps/data/libusb-1.0.25/MinGW32/dll/libusb-1.0.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
dist-win64: build-server build-win64 dist-win64: build-server build-win64
mkdir -p "$(DIST)/$(WIN64_TARGET_DIR)" mkdir -p "$(DIST)/$(WIN64_TARGET_DIR)"
@@ -116,15 +118,16 @@ dist-win64: build-server build-win64
cp data/scrcpy-noconsole.vbs "$(DIST)/$(WIN64_TARGET_DIR)" cp data/scrcpy-noconsole.vbs "$(DIST)/$(WIN64_TARGET_DIR)"
cp data/icon.png "$(DIST)/$(WIN64_TARGET_DIR)" cp data/icon.png "$(DIST)/$(WIN64_TARGET_DIR)"
cp data/open_a_terminal_here.bat "$(DIST)/$(WIN64_TARGET_DIR)" cp data/open_a_terminal_here.bat "$(DIST)/$(WIN64_TARGET_DIR)"
cp app/prebuilt-deps/data/ffmpeg-win64-5.0/bin/avutil-57.dll "$(DIST)/$(WIN64_TARGET_DIR)/" cp prebuilt-deps/data/ffmpeg-win64-5.0/bin/avutil-57.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
cp app/prebuilt-deps/data/ffmpeg-win64-5.0/bin/avcodec-59.dll "$(DIST)/$(WIN64_TARGET_DIR)/" cp prebuilt-deps/data/ffmpeg-win64-5.0/bin/avcodec-59.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
cp app/prebuilt-deps/data/ffmpeg-win64-5.0/bin/avformat-59.dll "$(DIST)/$(WIN64_TARGET_DIR)/" cp prebuilt-deps/data/ffmpeg-win64-5.0/bin/avformat-59.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
cp app/prebuilt-deps/data/ffmpeg-win64-5.0/bin/swresample-4.dll "$(DIST)/$(WIN64_TARGET_DIR)/" cp prebuilt-deps/data/ffmpeg-win64-5.0/bin/swresample-4.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
cp app/prebuilt-deps/data/ffmpeg-win64-5.0/bin/swscale-6.dll "$(DIST)/$(WIN64_TARGET_DIR)/" cp prebuilt-deps/data/ffmpeg-win64-5.0/bin/swscale-6.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
cp app/prebuilt-deps/data/platform-tools-31.0.3/adb.exe "$(DIST)/$(WIN64_TARGET_DIR)/" cp prebuilt-deps/data/platform-tools-31.0.3/adb.exe "$(DIST)/$(WIN64_TARGET_DIR)/"
cp app/prebuilt-deps/data/platform-tools-31.0.3/AdbWinApi.dll "$(DIST)/$(WIN64_TARGET_DIR)/" cp prebuilt-deps/data/platform-tools-31.0.3/AdbWinApi.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
cp app/prebuilt-deps/data/platform-tools-31.0.3/AdbWinUsbApi.dll "$(DIST)/$(WIN64_TARGET_DIR)/" cp prebuilt-deps/data/platform-tools-31.0.3/AdbWinUsbApi.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
cp app/prebuilt-deps/data/SDL2-2.0.20/x86_64-w64-mingw32/bin/SDL2.dll "$(DIST)/$(WIN64_TARGET_DIR)/" cp prebuilt-deps/data/SDL2-2.0.20/x86_64-w64-mingw32/bin/SDL2.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
cp prebuilt-deps/data/libusb-1.0.25/MinGW64/dll/libusb-1.0.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
zip-win32: dist-win32 zip-win32: dist-win32
cd "$(DIST)/$(WIN32_TARGET_DIR)"; \ cd "$(DIST)/$(WIN32_TARGET_DIR)"; \

View File

@@ -21,7 +21,6 @@ public class Options {
private boolean powerOffScreenOnClose; private boolean powerOffScreenOnClose;
private boolean clipboardAutosync = true; private boolean clipboardAutosync = true;
private boolean downsizeOnError = true; private boolean downsizeOnError = true;
private boolean cleanup = true;
// Options not used by the scrcpy client, but useful to use scrcpy-server directly // Options not used by the scrcpy client, but useful to use scrcpy-server directly
private boolean sendDeviceMeta = true; // send device name and size private boolean sendDeviceMeta = true; // send device name and size
@@ -156,14 +155,6 @@ public class Options {
this.downsizeOnError = downsizeOnError; this.downsizeOnError = downsizeOnError;
} }
public boolean getCleanup() {
return cleanup;
}
public void setCleanup(boolean cleanup) {
this.cleanup = cleanup;
}
public boolean getSendDeviceMeta() { public boolean getSendDeviceMeta() {
return sendDeviceMeta; return sendDeviceMeta;
} }

View File

@@ -28,8 +28,7 @@ public class ScreenEncoder implements Device.RotationListener {
// Keep the values in descending order // Keep the values in descending order
private static final int[] MAX_SIZE_FALLBACK = {2560, 1920, 1600, 1280, 1024, 800}; private static final int[] MAX_SIZE_FALLBACK = {2560, 1920, 1600, 1280, 1024, 800};
private static final long PACKET_FLAG_CONFIG = 1L << 63; private static final int NO_PTS = -1;
private static final long PACKET_FLAG_KEY_FRAME = 1L << 62;
private final AtomicBoolean rotationChanged = new AtomicBoolean(); private final AtomicBoolean rotationChanged = new AtomicBoolean();
private final ByteBuffer headerBuffer = ByteBuffer.allocate(12); private final ByteBuffer headerBuffer = ByteBuffer.allocate(12);
@@ -184,15 +183,12 @@ public class ScreenEncoder implements Device.RotationListener {
long pts; long pts;
if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) { if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {
pts = PACKET_FLAG_CONFIG; // non-media data packet pts = NO_PTS; // non-media data packet
} else { } else {
if (ptsOrigin == 0) { if (ptsOrigin == 0) {
ptsOrigin = bufferInfo.presentationTimeUs; ptsOrigin = bufferInfo.presentationTimeUs;
} }
pts = bufferInfo.presentationTimeUs - ptsOrigin; pts = bufferInfo.presentationTimeUs - ptsOrigin;
if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_KEY_FRAME) != 0) {
pts |= PACKET_FLAG_KEY_FRAME;
}
} }
headerBuffer.putLong(pts); headerBuffer.putLong(pts);

View File

@@ -51,13 +51,11 @@ public final class Server {
} }
} }
if (options.getCleanup()) { try {
try { CleanUp.configure(options.getDisplayId(), restoreStayOn, mustDisableShowTouchesOnCleanUp, restoreNormalPowerMode,
CleanUp.configure(options.getDisplayId(), restoreStayOn, mustDisableShowTouchesOnCleanUp, restoreNormalPowerMode, options.getPowerOffScreenOnClose());
options.getPowerOffScreenOnClose()); } catch (IOException e) {
} catch (IOException e) { Ln.e("Could not configure cleanup", e);
Ln.e("Could not configure cleanup", e);
}
} }
} }
@@ -245,10 +243,6 @@ public final class Server {
boolean downsizeOnError = Boolean.parseBoolean(value); boolean downsizeOnError = Boolean.parseBoolean(value);
options.setDownsizeOnError(downsizeOnError); options.setDownsizeOnError(downsizeOnError);
break; break;
case "cleanup":
boolean cleanup = Boolean.parseBoolean(value);
options.setCleanup(cleanup);
break;
case "send_device_meta": case "send_device_meta":
boolean sendDeviceMeta = Boolean.parseBoolean(value); boolean sendDeviceMeta = Boolean.parseBoolean(value);
options.setSendDeviceMeta(sendDeviceMeta); options.setSendDeviceMeta(sendDeviceMeta);