Compare commits

..

1 Commits
pr4373 ... doc

Author SHA1 Message Date
Romain Vimont
d25f38266d Extract device connection to a separate doc page
Create a new "Connection" documentation page.
2023-07-14 23:21:14 +02:00
33 changed files with 96 additions and 250 deletions

View File

@@ -5,7 +5,7 @@
_pronounced "**scr**een **c**o**py**"_
This application mirrors Android devices (video and audio) connected via
USB or [over TCP/IP](doc/connection.md#tcpip-wireless), and allows to control the
USB or [over TCP/IP](doc/device.md#tcpip-wireless), and allows to control the
device with the keyboard and the mouse of the computer. It does not require any
_root_ access. It works on _Linux_, _Windows_ and _macOS_.

View File

@@ -44,8 +44,6 @@ _scrcpy() {
--no-video-playback
--otg
-p --port=
--pause-on-exit
--pause-on-exit=
--power-off-on-close
--prefer-text
--print-fps
@@ -99,10 +97,6 @@ _scrcpy() {
COMPREPLY=($(compgen -W 'unlocked initial 0 1 2 3' -- "$cur"))
return
;;
--pause-on-exit)
COMPREPLY=($(compgen -W 'true false if-error' -- "$cur"))
return
;;
-r|--record)
COMPREPLY=($(compgen -f -- "$cur"))
return

View File

@@ -1,2 +1,4 @@
@echo off
scrcpy.exe --pause-on-exit=if-error %*
scrcpy.exe %*
:: if the exit code is >= 1, then pause
if errorlevel 1 pause

View File

@@ -5,7 +5,7 @@ Comment=Display and control your Android device
# For some users, the PATH or ADB environment variables are set from the shell
# startup file, like .bashrc or .zshrc… Run an interactive shell to get
# environment correctly initialized.
Exec=/bin/sh -c "\"\\$SHELL\" -i -c scrcpy --pause-on-exit=if-error"
Exec=/bin/bash --norc --noprofile -i -c "\"\\$SHELL\" -i -c scrcpy || read -p 'Press Enter to quit...'"
Icon=scrcpy
Terminal=true
Type=Application

View File

@@ -50,7 +50,6 @@ arguments=(
'--no-video-playback[Disable video playback]'
'--otg[Run in OTG mode \(simulating physical keyboard and mouse\)]'
{-p,--port=}'[\[port\[\:port\]\] Set the TCP port \(range\) used by the client to listen]'
'--pause-on-exit=[Make scrcpy pause before exiting]:mode:(true false if-error)'
'--power-off-on-close[Turn the device screen off when closing scrcpy]'
'--prefer-text[Inject alpha characters and space as text events instead of key events]'
'--print-fps[Start FPS counter, to print frame logs to the console]'

View File

@@ -267,16 +267,6 @@ Set the TCP port (range) used by the client to listen.
Default is 27183:27199.
.TP
\fB\-\-pause\-on\-exit\fR[=\fImode\fR]
Configure pause on exit. Possible values are "true" (always pause on exit), "false" (never pause on exit) and "if-error" (pause only if an error occured).
This is useful to prevent the terminal window from automatically closing, so that error messages can be read.
Default is "false".
Passing the option without argument is equivalent to passing "true".
.TP
.B \-\-power\-off\-on\-close
Turn the device screen off when closing scrcpy.

View File

@@ -70,7 +70,7 @@ argv_to_string(const char *const *argv, char *buf, size_t bufsize) {
}
static void
show_adb_installation_msg(void) {
show_adb_installation_msg() {
#ifndef __WINDOWS__
static const struct {
const char *binary;
@@ -216,44 +216,30 @@ sc_adb_kill_server(struct sc_intr *intr, unsigned flags) {
bool
sc_adb_forward(struct sc_intr *intr, const char *serial, uint16_t local_port,
const char *device_socket_name, unsigned flags) {
char *local;
if (asprintf(&local, "tcp:%" PRIu16, local_port) == -1) {
LOG_OOM();
return false;
}
char *remote;
if (asprintf(&remote, "localabstract:%s", device_socket_name) == -1) {
LOG_OOM();
free(local);
return false;
}
char local[4 + 5 + 1]; // tcp:PORT
char remote[108 + 14 + 1]; // localabstract:NAME
sprintf(local, "tcp:%" PRIu16, local_port);
snprintf(remote, sizeof(remote), "localabstract:%s", device_socket_name);
assert(serial);
const char *const argv[] =
SC_ADB_COMMAND("-s", serial, "forward", local, remote);
sc_pid pid = sc_adb_execute(argv, flags);
free(remote);
free(local);
return process_check_success_intr(intr, pid, "adb forward", flags);
}
bool
sc_adb_forward_remove(struct sc_intr *intr, const char *serial,
uint16_t local_port, unsigned flags) {
char *local;
if (asprintf(&local, "tcp:%" PRIu16, local_port) == -1) {
LOG_OOM();
return false;
}
char local[4 + 5 + 1]; // tcp:PORT
sprintf(local, "tcp:%" PRIu16, local_port);
assert(serial);
const char *const argv[] =
SC_ADB_COMMAND("-s", serial, "forward", "--remove", local);
sc_pid pid = sc_adb_execute(argv, flags);
free(local);
return process_check_success_intr(intr, pid, "adb forward --remove", flags);
}
@@ -261,45 +247,29 @@ bool
sc_adb_reverse(struct sc_intr *intr, const char *serial,
const char *device_socket_name, uint16_t local_port,
unsigned flags) {
char local[4 + 5 + 1]; // tcp:PORT
char remote[108 + 14 + 1]; // localabstract:NAME
sprintf(local, "tcp:%" PRIu16, local_port);
snprintf(remote, sizeof(remote), "localabstract:%s", device_socket_name);
assert(serial);
char *local;
if (asprintf(&local, "tcp:%" PRIu16, local_port) == -1) {
LOG_OOM();
return false;
}
char *remote;
if (asprintf(&remote, "localabstract:%s", device_socket_name) == -1) {
LOG_OOM();
free(local);
return false;
}
const char *const argv[] =
SC_ADB_COMMAND("-s", serial, "reverse", remote, local);
sc_pid pid = sc_adb_execute(argv, flags);
free(remote);
free(local);
return process_check_success_intr(intr, pid, "adb reverse", flags);
}
bool
sc_adb_reverse_remove(struct sc_intr *intr, const char *serial,
const char *device_socket_name, unsigned flags) {
char *remote;
if (asprintf(&remote, "localabstract:%s", device_socket_name) == -1) {
LOG_OOM();
return false;
}
char remote[108 + 14 + 1]; // localabstract:NAME
snprintf(remote, sizeof(remote), "localabstract:%s", device_socket_name);
assert(serial);
const char *const argv[] =
SC_ADB_COMMAND("-s", serial, "reverse", "--remove", remote);
sc_pid pid = sc_adb_execute(argv, flags);
free(remote);
return process_check_success_intr(intr, pid, "adb reverse --remove", flags);
}
@@ -362,18 +332,14 @@ sc_adb_install(struct sc_intr *intr, const char *serial, const char *local,
bool
sc_adb_tcpip(struct sc_intr *intr, const char *serial, uint16_t port,
unsigned flags) {
char *port_string;
if (asprintf(&port_string, "%" PRIu16, port) == -1) {
LOG_OOM();
return false;
}
char port_string[5 + 1];
sprintf(port_string, "%" PRIu16, port);
assert(serial);
const char *const argv[] =
SC_ADB_COMMAND("-s", serial, "tcpip", port_string);
sc_pid pid = sc_adb_execute(argv, flags);
free(port_string);
return process_check_success_intr(intr, pid, "adb tcpip", flags);
}

View File

@@ -7,7 +7,7 @@
#include "util/log.h"
#include "util/str.h"
static bool
bool
sc_adb_parse_device(char *line, struct sc_adb_device *device) {
// One device line looks like:
// "0123456789abcdef device usb:2-1 product:MyProduct model:MyModel "

View File

@@ -79,7 +79,6 @@ enum {
OPT_AUDIO_SOURCE,
OPT_KILL_ADB_ON_CLOSE,
OPT_TIME_LIMIT,
OPT_PAUSE_ON_EXIT,
};
struct sc_option {
@@ -464,20 +463,6 @@ static const struct sc_option options[] = {
"Default is " STR(DEFAULT_LOCAL_PORT_RANGE_FIRST) ":"
STR(DEFAULT_LOCAL_PORT_RANGE_LAST) ".",
},
{
.longopt_id = OPT_PAUSE_ON_EXIT,
.longopt = "pause-on-exit",
.argdesc = "mode",
.optional_arg = true,
.text = "Configure pause on exit. Possible values are \"true\" (always "
"pause on exit), \"false\" (never pause on exit) and "
"\"if-error\" (pause only if an error occured).\n"
"This is useful to prevent the terminal window from "
"automatically closing, so that error messages can be read.\n"
"Default is \"false\".\n"
"Passing the option without argument is equivalent to passing "
"\"true\".",
},
{
.longopt_id = OPT_POWER_OFF_ON_CLOSE,
.longopt = "power-off-on-close",
@@ -1085,7 +1070,7 @@ print_shortcut(const struct sc_shortcut *shortcut, unsigned cols) {
while (shortcut->shortcuts[i]) {
printf(" %s\n", shortcut->shortcuts[i]);
++i;
}
};
char *text = sc_str_wrap_lines(shortcut->text, cols, 8);
if (!text) {
@@ -1652,29 +1637,6 @@ parse_time_limit(const char *s, sc_tick *tick) {
return true;
}
static bool
parse_pause_on_exit(const char *s, enum sc_pause_on_exit *pause_on_exit) {
if (!s || !strcmp(s, "true")) {
*pause_on_exit = SC_PAUSE_ON_EXIT_TRUE;
return true;
}
if (!strcmp(s, "false")) {
*pause_on_exit = SC_PAUSE_ON_EXIT_FALSE;
return true;
}
if (!strcmp(s, "if-error")) {
*pause_on_exit = SC_PAUSE_ON_EXIT_IF_ERROR;
return true;
}
LOGE("Unsupported pause on exit mode: %s "
"(expected true, false or if-error)", optarg);
return false;
}
static bool
parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
const char *optstring, const struct option *longopts) {
@@ -2015,11 +1977,6 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
return false;
}
break;
case OPT_PAUSE_ON_EXIT:
if (!parse_pause_on_exit(optarg, &args->pause_on_exit)) {
return false;
}
break;
default:
// getopt prints the error message on stderr
return false;
@@ -2065,6 +2022,12 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
opts->audio_playback = false;
}
if (!opts->video_playback && !otg) {
// If video playback is disabled and OTG are disabled, then there is
// no way to control the device.
opts->control = false;
}
if (opts->video && !opts->video_playback && !opts->record_filename
&& !v4l2) {
LOGI("No video playback, no recording, no V4L2 sink: video disabled");
@@ -2233,37 +2196,6 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
return true;
}
static enum sc_pause_on_exit
sc_get_pause_on_exit(int argc, char *argv[]) {
// Read arguments backwards so that the last --pause-on-exit is considered
// (same behavior as getopt())
for (int i = argc - 1; i >= 1; --i) {
const char *arg = argv[i];
// Starts with "--pause-on-exit"
if (!strncmp("--pause-on-exit", arg, 15)) {
if (arg[15] == '\0') {
// No argument
return SC_PAUSE_ON_EXIT_TRUE;
}
if (arg[15] != '=') {
// Invalid parameter, ignore
return SC_PAUSE_ON_EXIT_FALSE;
}
const char *value = &arg[16];
if (!strcmp(value, "true")) {
return SC_PAUSE_ON_EXIT_TRUE;
}
if (!strcmp(value, "if-error")) {
return SC_PAUSE_ON_EXIT_IF_ERROR;
}
// Set to false, inclusing when the value is invalid
return SC_PAUSE_ON_EXIT_FALSE;
}
}
return SC_PAUSE_ON_EXIT_FALSE;
}
bool
scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]) {
struct sc_getopt_adapter adapter;
@@ -2277,11 +2209,5 @@ scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]) {
sc_getopt_adapter_destroy(&adapter);
if (!ret && args->pause_on_exit == SC_PAUSE_ON_EXIT_FALSE) {
// Check if "--pause-on-exit" is present in the arguments list, because
// it must be taken into account even if command line parsing failed
args->pause_on_exit = sc_get_pause_on_exit(argc, argv);
}
return ret;
}

View File

@@ -7,17 +7,10 @@
#include "options.h"
enum sc_pause_on_exit {
SC_PAUSE_ON_EXIT_TRUE,
SC_PAUSE_ON_EXIT_FALSE,
SC_PAUSE_ON_EXIT_IF_ERROR,
};
struct scrcpy_cli_args {
struct scrcpy_options opts;
bool help;
bool version;
enum sc_pause_on_exit pause_on_exit;
};
void

View File

@@ -53,7 +53,7 @@ sc_display_init(struct sc_display *display, SDL_Window *window, bool mipmaps) {
display->mipmaps = true;
} else {
LOGW("Trilinear filtering disabled "
"(OpenGL 3.0+ or ES 2.0+ required)");
"(OpenGL 3.0+ or ES 2.0+ required");
}
} else {
LOGI("Trilinear filtering disabled");

View File

@@ -271,7 +271,7 @@ error:
}
SDL_Surface *
scrcpy_icon_load(void) {
scrcpy_icon_load() {
char *icon_path = get_icon_path();
if (!icon_path) {
return NULL;

View File

@@ -23,7 +23,7 @@
#include "util/str.h"
#endif
static int
int
main_scrcpy(int argc, char *argv[]) {
#ifdef _WIN32
// disable buffering, we want logs immediately
@@ -39,32 +39,26 @@ main_scrcpy(int argc, char *argv[]) {
.opts = scrcpy_options_default,
.help = false,
.version = false,
.pause_on_exit = SC_PAUSE_ON_EXIT_FALSE,
};
#ifndef NDEBUG
args.opts.log_level = SC_LOG_LEVEL_DEBUG;
#endif
enum scrcpy_exit_code ret;
if (!scrcpy_parse_args(&args, argc, argv)) {
ret = SCRCPY_EXIT_FAILURE;
goto end;
return SCRCPY_EXIT_FAILURE;
}
sc_set_log_level(args.opts.log_level);
if (args.help) {
scrcpy_print_usage(argv[0]);
ret = SCRCPY_EXIT_SUCCESS;
goto end;
return SCRCPY_EXIT_SUCCESS;
}
if (args.version) {
scrcpy_print_version();
ret = SCRCPY_EXIT_SUCCESS;
goto end;
return SCRCPY_EXIT_SUCCESS;
}
#ifdef SCRCPY_LAVF_REQUIRES_REGISTER_ALL
@@ -78,26 +72,18 @@ main_scrcpy(int argc, char *argv[]) {
#endif
if (!net_init()) {
ret = SCRCPY_EXIT_FAILURE;
goto end;
return SCRCPY_EXIT_FAILURE;
}
sc_log_configure();
#ifdef HAVE_USB
ret = args.opts.otg ? scrcpy_otg(&args.opts) : scrcpy(&args.opts);
enum scrcpy_exit_code ret = args.opts.otg ? scrcpy_otg(&args.opts)
: scrcpy(&args.opts);
#else
ret = scrcpy(&args.opts);
enum scrcpy_exit_code ret = scrcpy(&args.opts);
#endif
end:
if (args.pause_on_exit == SC_PAUSE_ON_EXIT_TRUE ||
(args.pause_on_exit == SC_PAUSE_ON_EXIT_IF_ERROR &&
ret != SCRCPY_EXIT_SUCCESS)) {
printf("Press Enter to continue...\n");
getchar();
}
return ret;
}

View File

@@ -90,7 +90,7 @@ push_event(uint32_t type, const char *name) {
#define PUSH_EVENT(TYPE) push_event(TYPE, # TYPE)
#ifdef _WIN32
static BOOL WINAPI windows_ctrl_handler(DWORD ctrl_type) {
BOOL WINAPI windows_ctrl_handler(DWORD ctrl_type) {
if (ctrl_type == CTRL_C_EVENT) {
PUSH_EVENT(SDL_QUIT);
return TRUE;
@@ -252,9 +252,7 @@ sc_audio_demuxer_on_ended(struct sc_demuxer *demuxer,
// Contrary to the video demuxer, keep mirroring if only the audio fails
// (unless --require-audio is set).
if (status == SC_DEMUXER_STATUS_EOS) {
PUSH_EVENT(SC_EVENT_DEVICE_DISCONNECTED);
} else if (status == SC_DEMUXER_STATUS_ERROR
if (status == SC_DEMUXER_STATUS_ERROR
|| (status == SC_DEMUXER_STATUS_DISABLED
&& options->require_audio)) {
PUSH_EVENT(SC_EVENT_DEMUXER_ERROR);
@@ -297,7 +295,7 @@ sc_timeout_on_timeout(struct sc_timeout *timeout, void *userdata) {
// Generate a scrcpy id to differentiate multiple running scrcpy instances
static uint32_t
scrcpy_generate_scid(void) {
scrcpy_generate_scid() {
struct sc_rand rand;
sc_rand_init(&rand);
// Only use 31 bits to avoid issues with signed values on the Java-side
@@ -450,7 +448,9 @@ scrcpy(struct scrcpy_options *options) {
struct sc_file_pusher *fp = NULL;
if (options->video_playback && options->control) {
// control implies video playback
assert(!options->control || options->video_playback);
if (options->control) {
if (!sc_file_pusher_init(&s->file_pusher, serial,
options->push_target)) {
goto end;

View File

@@ -86,15 +86,14 @@ sc_server_params_copy(struct sc_server_params *dst,
// The params reference user-allocated memory, so we must copy them to
// handle them from another thread
#define COPY(FIELD) do { \
#define COPY(FIELD) \
dst->FIELD = NULL; \
if (src->FIELD) { \
dst->FIELD = strdup(src->FIELD); \
if (!dst->FIELD) { \
goto error; \
} \
} \
} while(0)
}
COPY(req_serial);
COPY(crop);
@@ -216,13 +215,13 @@ execute_server(struct sc_server *server,
cmd[count++] = SCRCPY_VERSION;
unsigned dyn_idx = count; // from there, the strings are allocated
#define ADD_PARAM(fmt, ...) do { \
#define ADD_PARAM(fmt, ...) { \
char *p; \
if (asprintf(&p, fmt, ## __VA_ARGS__) == -1) { \
goto end; \
} \
cmd[count++] = p; \
} while(0)
}
ADD_PARAM("scid=%08x", params->scid);
ADD_PARAM("log_level=%s", log_level_to_server_string(params->log_level));

View File

@@ -27,7 +27,7 @@
// keyboard support, though OS could support more keys via modifying the report
// desc. 6 should be enough for scrcpy.
#define HID_KEYBOARD_MAX_KEYS 6
#define HID_KEYBOARD_EVENT_SIZE (HID_KEYBOARD_INDEX_KEYS + HID_KEYBOARD_MAX_KEYS)
#define HID_KEYBOARD_EVENT_SIZE (2 + HID_KEYBOARD_MAX_KEYS)
#define HID_RESERVED 0x00
#define HID_ERROR_ROLL_OVER 0x01

View File

@@ -93,7 +93,7 @@ sc_usb_device_move(struct sc_usb_device *dst, struct sc_usb_device *src) {
src->product = NULL;
}
static void
void
sc_usb_devices_destroy(struct sc_vec_usb_devices *usb_devices) {
for (size_t i = 0; i < usb_devices->size; ++i) {
sc_usb_device_destroy(&usb_devices->data[i]);

View File

@@ -147,7 +147,7 @@ sc_sdl_log_print(void *userdata, int category, SDL_LogPriority priority,
}
void
sc_log_configure(void) {
sc_log_configure() {
SDL_LogSetOutputFunction(sc_sdl_log_print, NULL);
// Redirect FFmpeg logs to SDL logs
av_log_set_callback(sc_av_log_callback);

View File

@@ -36,6 +36,6 @@ sc_log_windows_error(const char *prefix, int error);
#endif
void
sc_log_configure(void);
sc_log_configure();
#endif

View File

@@ -190,10 +190,10 @@ sc_vecdeque_reallocdata_(void *ptr, size_t newcap, size_t item_size,
size_t right_len = MIN(size, oldcap - oldorigin);
assert(right_len);
memcpy(newptr, (char *) ptr + (oldorigin * item_size), right_len * item_size);
memcpy(newptr, ptr + (oldorigin * item_size), right_len * item_size);
if (size > right_len) {
memcpy((char *) newptr + (right_len * item_size), ptr,
memcpy(newptr + (right_len * item_size), ptr,
(size - right_len) * item_size);
}

View File

@@ -5,7 +5,7 @@
#include "util/bytebuf.h"
static void test_bytebuf_simple(void) {
void test_bytebuf_simple(void) {
struct sc_bytebuf buf;
uint8_t data[20];
@@ -34,7 +34,7 @@ static void test_bytebuf_simple(void) {
sc_bytebuf_destroy(&buf);
}
static void test_bytebuf_boundaries(void) {
void test_bytebuf_boundaries(void) {
struct sc_bytebuf buf;
uint8_t data[20];
@@ -71,7 +71,7 @@ static void test_bytebuf_boundaries(void) {
sc_bytebuf_destroy(&buf);
}
static void test_bytebuf_two_steps_write(void) {
void test_bytebuf_two_steps_write(void) {
struct sc_bytebuf buf;
uint8_t data[20];

View File

@@ -358,7 +358,7 @@ static void test_index_of_column(void) {
assert(sc_str_index_of_column(" a bc d", 1, " ") == 2);
}
static void test_remove_trailing_cr(void) {
static void test_remove_trailing_cr() {
char s[] = "abc\r";
sc_str_remove_trailing_cr(s, sizeof(s) - 1);
assert(!strcmp(s, "abc"));

View File

@@ -102,7 +102,7 @@ static void test_vecdeque_reserve(void) {
sc_vecdeque_destroy(&vdq);
}
static void test_vecdeque_grow(void) {
static void test_vecdeque_grow() {
struct SC_VECDEQUE(int) vdq = SC_VECDEQUE_INITIALIZER;
bool ok = sc_vecdeque_reserve(&vdq, 20);
@@ -142,7 +142,7 @@ static void test_vecdeque_grow(void) {
sc_vecdeque_destroy(&vdq);
}
static void test_vecdeque_push_hole(void) {
static void test_vecdeque_push_hole() {
struct SC_VECDEQUE(int) vdq = SC_VECDEQUE_INITIALIZER;
bool ok = sc_vecdeque_reserve(&vdq, 20);

View File

@@ -187,7 +187,7 @@ static void test_vector_index_of(void) {
sc_vector_destroy(&vec);
}
static void test_vector_grow(void) {
static void test_vector_grow() {
struct SC_VECTOR(int) vec = SC_VECTOR_INITIALIZER;
bool ok;

View File

@@ -77,13 +77,6 @@ In particular, if you get the following error:
then your device has no Opus encoder: try `scrcpy --audio-codec=aac`.
For advanced usage, to pass arbitrary parameters to the [`MediaFormat`],
check `--audio-codec-options` in the manpage or in `scrcpy --help`.
[`MediaFormat`]: https://developer.android.com/reference/android/media/MediaFormat
## Encoder
Several encoders may be available on the device. They can be listed by:
@@ -93,10 +86,15 @@ scrcpy --list-encoders
To select a specific encoder:
```bash
```
scrcpy --audio-codec=opus --audio-encoder='c2.android.opus.encoder'
```
For advanced usage, to pass arbitrary parameters to the [`MediaFormat`],
check `--audio-codec-options` in the manpage or in `scrcpy --help`.
[`MediaFormat`]: https://developer.android.com/reference/android/media/MediaFormat
## Bit rate

View File

@@ -1,7 +1,23 @@
# Device
Some command line arguments perform actions on the device itself while scrcpy is
running.
## Display
If several displays are available on the Android device, it is possible to
select the display to mirror:
```bash
scrcpy --display=1
```
The list of display ids can be retrieved by:
```bash
scrcpy --list-displays
```
A secondary display may only be controlled if the device runs at least Android
10 (otherwise it is mirrored as read-only).
## Stay awake
@@ -78,3 +94,4 @@ By default, on start, the device is powered on. To prevent this behavior:
```bash
scrcpy --no-power-on
```

View File

@@ -66,14 +66,6 @@ scrcpy --video-codec=av1
H265 may provide better quality, but H264 should provide lower latency.
AV1 encoders are not common on current Android devices.
For advanced usage, to pass arbitrary parameters to the [`MediaFormat`],
check `--video-codec-options` in the manpage or in `scrcpy --help`.
[`MediaFormat`]: https://developer.android.com/reference/android/media/MediaFormat
## Encoder
Several encoders may be available on the device. They can be listed by:
```bash
@@ -87,6 +79,11 @@ try another one:
scrcpy --video-codec=h264 --video-encoder='OMX.qcom.video.encoder.avc'
```
For advanced usage, to pass arbitrary parameters to the [`MediaFormat`],
check `--video-codec-options` in the manpage or in `scrcpy --help`.
[`MediaFormat`]: https://developer.android.com/reference/android/media/MediaFormat
## Rotation
@@ -137,25 +134,6 @@ phone, landscape for a tablet).
If `--max-size` is also specified, resizing is applied after cropping.
## Display
If several displays are available on the Android device, it is possible to
select the display to mirror:
```bash
scrcpy --display=1
```
The list of display ids can be retrieved by:
```bash
scrcpy --list-displays
```
A secondary display may only be controlled if the device runs at least Android
10 (otherwise it is mirrored as read-only).
## Buffering
By default, there is no video buffering, to get the lowest possible latency.

View File

@@ -7,8 +7,6 @@ project('scrcpy', 'c',
'b_ndebug=if-release',
])
add_project_arguments('-Wmissing-prototypes', language: 'c')
if get_option('compile_app')
subdir('app')
endif

View File

@@ -154,7 +154,7 @@ public final class Workarounds {
}
}
private static void fillBaseContext() {
public static void fillBaseContext() {
try {
fillActivityThread();

View File

@@ -17,7 +17,7 @@ import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@SuppressLint("PrivateApi,DiscouragedPrivateApi")
public final class ActivityManager {
public class ActivityManager {
private final IInterface manager;
private Method getContentProviderExternalMethod;

View File

@@ -11,7 +11,7 @@ import android.os.IInterface;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public final class ClipboardManager {
public class ClipboardManager {
private final IInterface manager;
private Method getPrimaryClipMethod;
private Method setPrimaryClipMethod;

View File

@@ -14,7 +14,7 @@ import java.io.Closeable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public final class ContentProvider implements Closeable {
public class ContentProvider implements Closeable {
public static final String TABLE_SYSTEM = "system";
public static final String TABLE_SECURE = "secure";

View File

@@ -7,7 +7,7 @@ import android.os.IInterface;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public final class StatusBarManager {
public class StatusBarManager {
private final IInterface manager;
private Method expandNotificationsPanelMethod;