Compare commits

..

1 Commits

Author SHA1 Message Date
Romain Vimont
3f4cb3250b Improve features presentation in README 2018-11-11 21:37:31 +01:00
29 changed files with 158 additions and 229 deletions

View File

@@ -43,7 +43,7 @@ Install the required packages from your package manager.
sudo apt install ffmpeg libsdl2-2.0.0
# client build dependencies
sudo apt install make gcc pkg-config meson ninja-build \
sudo apt install make gcc pkg-config meson \
libavcodec-dev libavformat-dev libavutil-dev \
libsdl2-dev
@@ -199,12 +199,6 @@ cd x
ninja
```
_Note: `ninja` [must][ninja-user] be run as a non-root user (only `ninja
install` must be run as root)._
[ninja-user]: https://github.com/Genymobile/scrcpy/commit/4c49b27e9f6be02b8e63b508b60535426bd0291a
### Run
To run without installing:
@@ -234,10 +228,10 @@ You can then [run](README.md#run) _scrcpy_.
## Prebuilt server
- [`scrcpy-server-v1.6.jar`][direct-scrcpy-server]
_(SHA-256: 08df924bf6d10943df9eaacfff548a99871ebfca4641f8c7ddddb73f27cb905b)_
- [`scrcpy-server-v1.4.jar`][direct-scrcpy-server]
_(SHA-256: 1ff7a72fcfe81dadccfab9d6f86c971cd7c7f38f17196748fe05480e301b443d)_
[direct-scrcpy-server]: https://github.com/Genymobile/scrcpy/releases/download/v1.6/scrcpy-server-v1.6.jar
[direct-scrcpy-server]: https://github.com/Genymobile/scrcpy/releases/download/v1.4/scrcpy-server-v1.4.jar
Download the prebuilt server somewhere, and specify its path during the Meson
configuration:

14
FAQ.md
View File

@@ -24,6 +24,20 @@ If you still encounter problems, please see [issue 9].
[issue 9]: https://github.com/Genymobile/scrcpy/issues/9
### I get a black screen for some applications like Silence
This is expected, they requested to [protect] the screen.
In [Silence], you can disable it in settings → Privacy → Screen security.
[protect]: https://developer.android.com/reference/android/view/Display#FLAG_SECURE
[silence]: https://f-droid.org/en/packages/org.smssecure.smssecure/
See [issue 36].
[issue 36]: https://github.com/Genymobile/scrcpy/issues/36
### Mouse clicks do not work
On some devices, you may need to enable an option to allow [simulating input].

View File

@@ -100,10 +100,10 @@ dist-win32: build-server build-win32 build-win32-noconsole
cp "$(SERVER_BUILD_DIR)"/server/scrcpy-server.jar "$(DIST)/$(WIN32_TARGET_DIR)/"
cp "$(WIN32_BUILD_DIR)"/app/scrcpy.exe "$(DIST)/$(WIN32_TARGET_DIR)/"
cp "$(WIN32_NOCONSOLE_BUILD_DIR)"/app/scrcpy.exe "$(DIST)/$(WIN32_TARGET_DIR)/scrcpy-noconsole.exe"
cp prebuilt-deps/ffmpeg-4.1-win32-shared/bin/avutil-56.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
cp prebuilt-deps/ffmpeg-4.1-win32-shared/bin/avcodec-58.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
cp prebuilt-deps/ffmpeg-4.1-win32-shared/bin/avformat-58.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
cp prebuilt-deps/ffmpeg-4.1-win32-shared/bin/swresample-3.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
cp prebuilt-deps/ffmpeg-4.0.2-win32-shared/bin/avutil-56.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
cp prebuilt-deps/ffmpeg-4.0.2-win32-shared/bin/avcodec-58.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
cp prebuilt-deps/ffmpeg-4.0.2-win32-shared/bin/avformat-58.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
cp prebuilt-deps/ffmpeg-4.0.2-win32-shared/bin/swresample-3.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
cp prebuilt-deps/platform-tools/adb.exe "$(DIST)/$(WIN32_TARGET_DIR)/"
cp prebuilt-deps/platform-tools/AdbWinApi.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
cp prebuilt-deps/platform-tools/AdbWinUsbApi.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
@@ -114,10 +114,10 @@ dist-win64: build-server build-win64 build-win64-noconsole
cp "$(SERVER_BUILD_DIR)"/server/scrcpy-server.jar "$(DIST)/$(WIN64_TARGET_DIR)/"
cp "$(WIN64_BUILD_DIR)"/app/scrcpy.exe "$(DIST)/$(WIN64_TARGET_DIR)/"
cp "$(WIN64_NOCONSOLE_BUILD_DIR)"/app/scrcpy.exe "$(DIST)/$(WIN64_TARGET_DIR)/scrcpy-noconsole.exe"
cp prebuilt-deps/ffmpeg-4.1-win64-shared/bin/avutil-56.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
cp prebuilt-deps/ffmpeg-4.1-win64-shared/bin/avcodec-58.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
cp prebuilt-deps/ffmpeg-4.1-win64-shared/bin/avformat-58.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
cp prebuilt-deps/ffmpeg-4.1-win64-shared/bin/swresample-3.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
cp prebuilt-deps/ffmpeg-4.0.2-win64-shared/bin/avutil-56.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
cp prebuilt-deps/ffmpeg-4.0.2-win64-shared/bin/avcodec-58.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
cp prebuilt-deps/ffmpeg-4.0.2-win64-shared/bin/avformat-58.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
cp prebuilt-deps/ffmpeg-4.0.2-win64-shared/bin/swresample-3.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
cp prebuilt-deps/platform-tools/adb.exe "$(DIST)/$(WIN64_TARGET_DIR)/"
cp prebuilt-deps/platform-tools/AdbWinApi.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
cp prebuilt-deps/platform-tools/AdbWinUsbApi.dll "$(DIST)/$(WIN64_TARGET_DIR)/"

View File

@@ -1,4 +1,4 @@
# scrcpy (v1.6)
# scrcpy (v1.4)
This application provides display and control of Android devices connected on
USB (or [over TCP/IP][article-tcpip]). It does not require any _root_ access.
@@ -15,11 +15,6 @@ Make sure you [enabled adb debugging][enable-adb] on your device(s).
[enable-adb]: https://developer.android.com/studio/command-line/adb.html#Enabling
On some devices, you also need to enable [an additional option][control] to
control it using keyboard and mouse.
[control]: https://github.com/Genymobile/scrcpy/issues/70#issuecomment-373286323
## Get the app
@@ -47,13 +42,13 @@ For Gentoo, an [Ebuild] is available: [`scrcpy/`][ebuild-link].
For Windows, for simplicity, prebuilt archives with all the dependencies
(including `adb`) are available:
- [`scrcpy-win32-v1.6.zip`][direct-win32]
_(SHA-256: 4ca0c5924ab2ebf19b70f6598b2e546f65ba469a72ded2d1b213df3380fb46b1)_
- [`scrcpy-win64-v1.6.zip`][direct-win64]
_(SHA-256: f66b7eace8dd6537a9a27176fd824704a284d8e82077ccc903344396043f90c9)_
- [`scrcpy-win32-v1.4.zip`][direct-win32]
_(SHA-256: 1f72fa520980727e8943b7214b64c66b00b9b5267f7cffefb64fa37c3ca803cf)_
- [`scrcpy-win64-v1.4.zip`][direct-win64]
_(SHA-256: 382f02bd8ed3db2cc7ab15aabdb83674744993b936d602b01e6959a150584a79)_
[direct-win32]: https://github.com/Genymobile/scrcpy/releases/download/v1.6/scrcpy-win32-v1.6.zip
[direct-win64]: https://github.com/Genymobile/scrcpy/releases/download/v1.6/scrcpy-win64-v1.6.zip
[direct-win32]: https://github.com/Genymobile/scrcpy/releases/download/v1.4/scrcpy-win32-v1.4.zip
[direct-win64]: https://github.com/Genymobile/scrcpy/releases/download/v1.4/scrcpy-win64-v1.4.zip
You can also [build the app manually][BUILD].
@@ -196,16 +191,6 @@ scrcpy -f # short version
Fullscreen can then be toggled dynamically with `Ctrl`+`f`.
### Always on top
The window of app can always be above others by:
```bash
scrcpy --always-on-top
scrcpy -T # short version
```
### Show touches
For presentations, it may be useful to show physical touches (on the physical
@@ -223,22 +208,6 @@ scrcpy -t
Note that it only shows _physical_ touches (with the finger on the device).
### Install APK
To install an APK, drag & drop an APK file (ending with `.apk`) to the _scrcpy_
window.
There is no visual feedback, a log is printed to the console.
### Push file to device
To push a file to `/sdcard/` on the device, drag & drop a (non-APK) file to the
_scrcpy_ window.
There is no visual feedback, a log is printed to the console.
### Forward audio
Audio is not forwarded by _scrcpy_.
@@ -269,6 +238,8 @@ you are interested, see [issue 14].
| turn screen on | _Right-click²_ |
| paste computer clipboard to device | `Ctrl`+`v` |
| enable/disable FPS counter (on stdout) | `Ctrl`+`i` |
| install APK from computer | drag & drop APK file |
| push file to `/sdcard/` | drag & drop non-APK file |
_¹Double-click on black borders to remove them._
_²Right-click turns the screen on if it was off, presses BACK otherwise._

View File

@@ -86,7 +86,7 @@ conf = configuration_data()
conf.set('BUILD_DEBUG', get_option('buildtype') == 'debug')
# the version, updated on release
conf.set_quoted('SCRCPY_VERSION', meson.project_version())
conf.set_quoted('SCRCPY_VERSION', '1.4')
# the prefix used during configuration (meson --prefix=PREFIX)
conf.set_quoted('PREFIX', get_option('prefix'))

View File

@@ -135,6 +135,11 @@ process_t adb_install(const char *serial, const char *local) {
return proc;
}
process_t adb_remove_path(const char *serial, const char *path) {
const char *const adb_cmd[] = {"shell", "rm", path};
return adb_execute(serial, adb_cmd, ARRAY_LEN(adb_cmd));
}
SDL_bool process_check_success(process_t proc, const char *name) {
if (proc == PROCESS_NONE) {
LOGE("Could not execute \"%s\"", name);

View File

@@ -49,6 +49,7 @@ process_t adb_reverse(const char *serial, const char *device_socket_name, uint16
process_t adb_reverse_remove(const char *serial, const char *device_socket_name);
process_t adb_push(const char *serial, const char *local, const char *remote);
process_t adb_install(const char *serial, const char *local);
process_t adb_remove_path(const char *serial, const char *path);
// convenience function to wait for a successful process execution
// automatically log process errors with the provided process name

View File

@@ -13,8 +13,8 @@ struct size {
};
struct point {
Sint32 x;
Sint32 y;
Uint16 x;
Uint16 y;
};
struct position {

View File

@@ -8,10 +8,10 @@
#include "log.h"
static void write_position(Uint8 *buf, const struct position *position) {
buffer_write32be(&buf[0], position->point.x);
buffer_write32be(&buf[4], position->point.y);
buffer_write16be(&buf[8], position->screen_size.width);
buffer_write16be(&buf[10], position->screen_size.height);
buffer_write16be(&buf[0], position->point.x);
buffer_write16be(&buf[2], position->point.y);
buffer_write16be(&buf[4], position->screen_size.width);
buffer_write16be(&buf[6], position->screen_size.height);
}
int control_event_serialize(const struct control_event *event, unsigned char *buf) {
@@ -23,7 +23,7 @@ int control_event_serialize(const struct control_event *event, unsigned char *bu
buffer_write32be(&buf[6], event->keycode_event.metastate);
return 10;
case CONTROL_EVENT_TYPE_TEXT: {
// write length (2 bytes) + string (non nul-terminated)
// write length (1 byte) + date (non nul-terminated)
size_t len = strlen(event->text_event.text);
if (len > TEXT_MAX_LENGTH) {
// injecting a text takes time, so limit the text length
@@ -37,12 +37,12 @@ int control_event_serialize(const struct control_event *event, unsigned char *bu
buf[1] = event->mouse_event.action;
buffer_write32be(&buf[2], event->mouse_event.buttons);
write_position(&buf[6], &event->mouse_event.position);
return 18;
return 14;
case CONTROL_EVENT_TYPE_SCROLL:
write_position(&buf[1], &event->scroll_event.position);
buffer_write32be(&buf[13], (Uint32) event->scroll_event.hscroll);
buffer_write32be(&buf[17], (Uint32) event->scroll_event.vscroll);
return 21;
buffer_write32be(&buf[9], (Uint32) event->scroll_event.hscroll);
buffer_write32be(&buf[13], (Uint32) event->scroll_event.vscroll);
return 17;
case CONTROL_EVENT_TYPE_COMMAND:
buf[1] = event->command_event.action;
return 2;

View File

@@ -80,15 +80,12 @@ static int read_packet_with_meta(void *opaque, uint8_t *buf, int buf_size) {
if (!state->remaining) {
#define HEADER_SIZE 12
uint8_t header[HEADER_SIZE];
ssize_t r = net_recv_all(decoder->video_socket, header, HEADER_SIZE);
if (r == -1) {
return AVERROR(errno);
}
if (r == 0) {
return AVERROR_EOF;
ssize_t ret = net_recv_all(decoder->video_socket, header, HEADER_SIZE);
if (ret <= 0) {
return ret;
}
// no partial read (net_recv_all())
SDL_assert_release(r == HEADER_SIZE);
SDL_assert_release(ret == HEADER_SIZE);
uint64_t pts = buffer_read64be(header);
state->remaining = buffer_read32be(&header[8]);
@@ -96,7 +93,7 @@ static int read_packet_with_meta(void *opaque, uint8_t *buf, int buf_size) {
if (pts != NO_PTS && !receiver_state_push_meta(state, pts)) {
LOGE("Could not store PTS for recording");
// we cannot save the PTS, the recording would be broken
return AVERROR(ENOMEM);
return -1;
}
}
@@ -105,30 +102,20 @@ static int read_packet_with_meta(void *opaque, uint8_t *buf, int buf_size) {
if (buf_size > state->remaining)
buf_size = state->remaining;
ssize_t r = net_recv(decoder->video_socket, buf, buf_size);
if (r == -1) {
return AVERROR(errno);
}
if (r == 0) {
return AVERROR_EOF;
ssize_t ret = net_recv(decoder->video_socket, buf, buf_size);
if (ret <= 0) {
return ret;
}
SDL_assert(state->remaining >= r);
state->remaining -= r;
SDL_assert(state->remaining >= ret);
state->remaining -= ret;
return r;
return ret;
}
static int read_raw_packet(void *opaque, uint8_t *buf, int buf_size) {
struct decoder *decoder = opaque;
ssize_t r = net_recv(decoder->video_socket, buf, buf_size);
if (r == -1) {
return AVERROR(errno);
}
if (r == 0) {
return AVERROR_EOF;
}
return r;
return net_recv(decoder->video_socket, buf, buf_size);
}
// set the decoded frame as ready for rendering, and notify
@@ -296,16 +283,11 @@ run_end:
return 0;
}
static void av_log_callback(void *avcl, int level, const char *fmt, va_list vl) {
LOGE(fmt, vl);
}
void decoder_init(struct decoder *decoder, struct frames *frames,
socket_t video_socket, struct recorder *recorder) {
decoder->frames = frames;
decoder->video_socket = video_socket;
decoder->recorder = recorder;
av_log_set_callback(av_log_callback);
}
SDL_bool decoder_start(struct decoder *decoder) {

View File

@@ -23,9 +23,10 @@ static struct point get_mouse_point(struct screen *screen) {
int y;
SDL_GetMouseState(&x, &y);
convert_to_renderer_coordinates(screen->renderer, &x, &y);
SDL_assert_release(x >= 0 && x < 0x10000 && y >= 0 && y < 0x10000);
return (struct point) {
.x = x,
.y = y,
.x = (Uint16) x,
.y = (Uint16) y,
};
}
@@ -270,13 +271,6 @@ void input_manager_process_mouse_motion(struct input_manager *input_manager,
}
}
static SDL_bool is_outside_device_screen(struct input_manager *input_manager,
int x, int y)
{
return x < 0 || x >= input_manager->screen->frame_size.width ||
y < 0 || y >= input_manager->screen->frame_size.height;
}
void input_manager_process_mouse_button(struct input_manager *input_manager,
const SDL_MouseButtonEvent *event) {
if (event->type == SDL_MOUSEBUTTONDOWN) {
@@ -290,17 +284,16 @@ void input_manager_process_mouse_button(struct input_manager *input_manager,
}
// double-click on black borders resize to fit the device screen
if (event->button == SDL_BUTTON_LEFT && event->clicks == 2) {
SDL_bool outside= is_outside_device_screen(input_manager,
event->x,
event->y);
if (outside) {
SDL_bool outside_device_screen =
event->x < 0 || event->x >= input_manager->screen->frame_size.width ||
event->y < 0 || event->y >= input_manager->screen->frame_size.height;
if (outside_device_screen) {
screen_resize_to_fit(input_manager->screen);
return;
}
// otherwise, send the click event to the device
}
// otherwise, send the click event to the device
}
struct control_event control_event;
if (mouse_button_from_sdl_to_android(event, input_manager->screen->frame_size, &control_event)) {
if (!controller_push_event(input_manager->controller, &control_event)) {

View File

@@ -19,7 +19,6 @@ struct args {
Uint16 port;
Uint16 max_size;
Uint32 bit_rate;
SDL_bool always_on_top;
};
static void usage(const char *arg0) {
@@ -66,9 +65,6 @@ static void usage(const char *arg0) {
" Enable \"show touches\" on start, disable on quit.\n"
" It only shows physical touches (not clicks from scrcpy).\n"
"\n"
" -T, --always-on-top\n"
" Make scrcpy window always on top (above other windows).\n"
"\n"
" -v, --version\n"
" Print the version of scrcpy.\n"
"\n"
@@ -128,7 +124,7 @@ static void usage(const char *arg0) {
}
static void print_version(void) {
fprintf(stderr, "scrcpy %s\n\n", SCRCPY_VERSION);
fprintf(stderr, "scrcpy v%s\n\n", SCRCPY_VERSION);
fprintf(stderr, "dependencies:\n");
fprintf(stderr, " - SDL %d.%d.%d\n", SDL_MAJOR_VERSION, SDL_MINOR_VERSION, SDL_PATCHLEVEL);
@@ -210,21 +206,20 @@ static SDL_bool parse_port(char *optarg, Uint16 *port) {
static SDL_bool parse_args(struct args *args, int argc, char *argv[]) {
static const struct option long_options[] = {
{"always-on-top", no_argument, NULL, 'T'},
{"bit-rate", required_argument, NULL, 'b'},
{"crop", required_argument, NULL, 'c'},
{"fullscreen", no_argument, NULL, 'f'},
{"help", no_argument, NULL, 'h'},
{"max-size", required_argument, NULL, 'm'},
{"port", required_argument, NULL, 'p'},
{"record", required_argument, NULL, 'r'},
{"serial", required_argument, NULL, 's'},
{"show-touches", no_argument, NULL, 't'},
{"version", no_argument, NULL, 'v'},
{NULL, 0, NULL, 0 },
{"bit-rate", required_argument, NULL, 'b'},
{"crop", required_argument, NULL, 'c'},
{"fullscreen", no_argument, NULL, 'f'},
{"help", no_argument, NULL, 'h'},
{"max-size", required_argument, NULL, 'm'},
{"port", required_argument, NULL, 'p'},
{"record", required_argument, NULL, 'r'},
{"serial", required_argument, NULL, 's'},
{"show-touches", no_argument, NULL, 't'},
{"version", no_argument, NULL, 'v'},
{NULL, 0, NULL, 0 },
};
int c;
while ((c = getopt_long(argc, argv, "b:c:fhm:p:r:s:tTv", long_options, NULL)) != -1) {
while ((c = getopt_long(argc, argv, "b:c:fhm:p:r:s:tv", long_options, NULL)) != -1) {
switch (c) {
case 'b':
if (!parse_bit_rate(optarg, &args->bit_rate)) {
@@ -259,9 +254,6 @@ static SDL_bool parse_args(struct args *args, int argc, char *argv[]) {
case 't':
args->show_touches = SDL_TRUE;
break;
case 'T':
args->always_on_top = SDL_TRUE;
break;
case 'v':
args->version = SDL_TRUE;
break;
@@ -296,7 +288,6 @@ int main(int argc, char *argv[]) {
.port = DEFAULT_LOCAL_PORT,
.max_size = DEFAULT_MAX_SIZE,
.bit_rate = DEFAULT_BIT_RATE,
.always_on_top = SDL_FALSE,
};
if (!parse_args(&args, argc, argv)) {
return 1;
@@ -333,7 +324,6 @@ int main(int argc, char *argv[]) {
.bit_rate = args.bit_rate,
.show_touches = args.show_touches,
.fullscreen = args.fullscreen,
.always_on_top = args.always_on_top,
};
int res = scrcpy(&options) ? 0 : 1;

View File

@@ -17,7 +17,7 @@ static const AVOutputFormat *find_mp4_muxer(void) {
oformat = av_oformat_next(oformat);
#endif
// until null or with name "mp4"
} while (oformat && strcmp(oformat->name, "matroska"));
} while (oformat && strcmp(oformat->name, "mp4"));
return oformat;
}
@@ -30,7 +30,6 @@ SDL_bool recorder_init(struct recorder *recorder, const char *filename,
}
recorder->declared_frame_size = declared_frame_size;
recorder->header_written = SDL_FALSE;
return SDL_TRUE;
}
@@ -94,6 +93,14 @@ SDL_bool recorder_open(struct recorder *recorder, AVCodec *input_codec) {
return SDL_FALSE;
}
ret = avformat_write_header(recorder->ctx, NULL);
if (ret < 0) {
LOGE("Failed to write header to %s", recorder->filename);
avio_closep(&recorder->ctx->pb);
avformat_free_context(recorder->ctx);
return SDL_FALSE;
}
return SDL_TRUE;
}
@@ -107,33 +114,5 @@ void recorder_close(struct recorder *recorder) {
}
SDL_bool recorder_write(struct recorder *recorder, AVPacket *packet) {
LOGD("recorder_write");
if (recorder->header_written) {
LOGD("pts=%ld", (long) packet->pts);
return av_write_frame(recorder->ctx, packet) >= 0;
}
LOGD("recorder_write header");
//SDL_assert(recorder->ctx->nb_streams == 1);
AVStream *ostream = recorder->ctx->streams[0];
ostream->codecpar->extradata = malloc(packet->size);
memcpy(ostream->codecpar->extradata, packet->data, packet->size);
ostream->codecpar->extradata_size = packet->size;
// write header instead
AVDictionary *opts = NULL;
av_dict_set_int(&opts, "live", 1, 0);
int ret = avformat_write_header(recorder->ctx, &opts);
if (ret < 0) {
LOGE("Failed to write header to %s", recorder->filename);
char err[128];
av_strerror(ret, err, sizeof(err));
LOGE("%s\n", err);
avio_closep(&recorder->ctx->pb);
avformat_free_context(recorder->ctx);
return SDL_FALSE;
}
recorder->header_written = SDL_TRUE;
return SDL_TRUE;
return av_write_frame(recorder->ctx, packet) >= 0;
}

View File

@@ -10,7 +10,6 @@ struct recorder {
char *filename;
AVFormatContext *ctx;
struct size declared_frame_size;
SDL_bool header_written;
};
SDL_bool recorder_init(struct recorder *recoder, const char *filename,

View File

@@ -223,7 +223,7 @@ SDL_bool scrcpy(const struct scrcpy_options *options) {
goto finally_destroy_controller;
}
if (!screen_init_rendering(&screen, device_name, frame_size, options->always_on_top)) {
if (!screen_init_rendering(&screen, device_name, frame_size)) {
ret = SDL_FALSE;
goto finally_stop_and_join_controller;
}

View File

@@ -12,7 +12,6 @@ struct scrcpy_options {
Uint32 bit_rate;
SDL_bool show_touches;
SDL_bool fullscreen;
SDL_bool always_on_top;
};
SDL_bool scrcpy(const struct scrcpy_options *options);

View File

@@ -30,9 +30,6 @@ SDL_bool sdl_init_and_configure(void) {
}
#endif
// Do not disable the screensaver when scrcpy is running
SDL_EnableScreenSaver();
return SDL_TRUE;
}
@@ -144,10 +141,7 @@ static inline SDL_Texture *create_texture(SDL_Renderer *renderer, struct size fr
frame_size.width, frame_size.height);
}
SDL_bool screen_init_rendering(struct screen *screen,
const char *device_name,
struct size frame_size,
SDL_bool always_on_top) {
SDL_bool screen_init_rendering(struct screen *screen, const char *device_name, struct size frame_size) {
screen->frame_size = frame_size;
struct size window_size = get_initial_optimal_size(frame_size);
@@ -155,10 +149,6 @@ SDL_bool screen_init_rendering(struct screen *screen,
#ifdef HIDPI_SUPPORT
window_flags |= SDL_WINDOW_ALLOW_HIGHDPI;
#endif
if (always_on_top) {
window_flags |= SDL_WINDOW_ALWAYS_ON_TOP;
}
screen->window = SDL_CreateWindow(device_name, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
window_size.width, window_size.height, window_flags);
if (!screen->window) {

View File

@@ -43,8 +43,7 @@ void screen_init(struct screen *screen);
// initialize screen, create window, renderer and texture (window is hidden)
SDL_bool screen_init_rendering(struct screen *screen,
const char *device_name,
struct size frame_size,
SDL_bool always_on_top);
struct size frame_size);
// show the window
void screen_show_window(struct screen *screen);

View File

@@ -34,6 +34,11 @@ static SDL_bool push_server(const char *serial) {
return process_check_success(process, "adb push");
}
static SDL_bool remove_server(const char *serial) {
process_t process = adb_remove_path(serial, DEVICE_SERVER_PATH);
return process_check_success(process, "adb shell rm");
}
static SDL_bool enable_tunnel_reverse(const char *serial, Uint16 local_port) {
process_t process = adb_reverse(serial, SOCKET_NAME, local_port);
return process_check_success(process, "adb reverse");
@@ -88,7 +93,7 @@ static process_t execute_server(const char *serial,
max_size_string,
bit_rate_string,
tunnel_forward ? "true" : "false",
crop ? crop : "-",
crop ? crop : "''",
send_frame_meta ? "true" : "false",
};
return adb_execute(serial, cmd, sizeof(cmd) / sizeof(cmd[0]));
@@ -162,6 +167,8 @@ SDL_bool server_start(struct server *server, const char *serial,
return SDL_FALSE;
}
server->server_copied_to_device = SDL_TRUE;
if (!enable_tunnel(server)) {
SDL_free((void *) server->serial);
return SDL_FALSE;
@@ -222,6 +229,10 @@ socket_t server_connect_to(struct server *server) {
close_socket(&server->server_socket);
}
// the server is started, we can clean up the jar from the temporary folder
remove_server(server->serial); // ignore failure
server->server_copied_to_device = SDL_FALSE;
// we don't need the adb tunnel anymore
disable_tunnel(server); // ignore failure
server->tunnel_enabled = SDL_FALSE;
@@ -243,6 +254,10 @@ void server_stop(struct server *server) {
// ignore failure
disable_tunnel(server);
}
if (server->server_copied_to_device) {
remove_server(server->serial); // ignore failure
}
}
void server_destroy(struct server *server) {

View File

@@ -13,6 +13,7 @@ struct server {
SDL_bool tunnel_enabled;
SDL_bool tunnel_forward; // use "adb forward" instead of "adb reverse"
SDL_bool send_frame_meta; // request frame PTS to be able to record properly
SDL_bool server_copied_to_device;
};
#define SERVER_INITIALIZER { \
@@ -24,6 +25,7 @@ struct server {
.tunnel_enabled = SDL_FALSE, \
.tunnel_forward = SDL_FALSE, \
.send_frame_meta = SDL_FALSE, \
.server_copied_to_device = SDL_FALSE, \
}
// init default values

View File

@@ -15,6 +15,6 @@ cpu = 'i686'
endian = 'little'
[properties]
prebuilt_ffmpeg_shared = 'ffmpeg-4.1-win32-shared'
prebuilt_ffmpeg_dev = 'ffmpeg-4.1-win32-dev'
prebuilt_ffmpeg_shared = 'ffmpeg-4.0.2-win32-shared'
prebuilt_ffmpeg_dev = 'ffmpeg-4.0.2-win32-dev'
prebuilt_sdl2 = 'SDL2-2.0.9/i686-w64-mingw32'

View File

@@ -15,6 +15,6 @@ cpu = 'x86_64'
endian = 'little'
[properties]
prebuilt_ffmpeg_shared = 'ffmpeg-4.1-win64-shared'
prebuilt_ffmpeg_dev = 'ffmpeg-4.1-win64-dev'
prebuilt_ffmpeg_shared = 'ffmpeg-4.0.2-win64-shared'
prebuilt_ffmpeg_dev = 'ffmpeg-4.0.2-win64-dev'
prebuilt_sdl2 = 'SDL2-2.0.9/x86_64-w64-mingw32'

View File

@@ -1,7 +1,4 @@
project('scrcpy', 'c',
version: '1.6',
meson_version: '>= 0.37',
default_options: 'c_std=c11')
project('scrcpy', 'c', meson_version: '>= 0.37', default_options : 'c_std=c11')
if get_option('build_app')
subdir('app')

View File

@@ -10,24 +10,24 @@ prepare-win32: prepare-sdl2 prepare-ffmpeg-shared-win32 prepare-ffmpeg-dev-win32
prepare-win64: prepare-sdl2 prepare-ffmpeg-shared-win64 prepare-ffmpeg-dev-win64 prepare-adb
prepare-ffmpeg-shared-win32:
@./prepare-dep https://ffmpeg.zeranoe.com/builds/win32/shared/ffmpeg-4.1-win32-shared.zip \
e692b18c01745d262c03294b382fd64df68fabe3c66aa4546a3ad3935175cde3 \
ffmpeg-4.1-win32-shared
@./prepare-dep https://ffmpeg.zeranoe.com/builds/win32/shared/ffmpeg-4.0.2-win32-shared.zip \
cc190a3a4cf7bfbd4fbaa92609c1501a1de458055e6cfea8b745c1d515013aa8 \
ffmpeg-4.0.2-win32-shared
prepare-ffmpeg-dev-win32:
@./prepare-dep https://ffmpeg.zeranoe.com/builds/win32/dev/ffmpeg-4.1-win32-dev.zip \
34bc5e471fb9160609abd6bc271e361050f3ff7376b1b8a0873cca02b38277c8 \
ffmpeg-4.1-win32-dev
@./prepare-dep https://ffmpeg.zeranoe.com/builds/win32/dev/ffmpeg-4.0.2-win32-dev.zip \
c72c74bad74ac0541f1b43090c26a50017c49041c182a703abd2057bb8cdc238 \
ffmpeg-4.0.2-win32-dev
prepare-ffmpeg-shared-win64:
@./prepare-dep https://ffmpeg.zeranoe.com/builds/win64/shared/ffmpeg-4.1-win64-shared.zip \
c4908c97436c946509dc365e421159274fa4b1e66dce6fb5b63d82a6294d5357 \
ffmpeg-4.1-win64-shared
@./prepare-dep https://ffmpeg.zeranoe.com/builds/win64/shared/ffmpeg-4.0.2-win64-shared.zip \
ede566aca8b5348dff85570f9638c6bad33209f9419f79db7bde7daa37599bff \
ffmpeg-4.0.2-win64-shared
prepare-ffmpeg-dev-win64:
@./prepare-dep https://ffmpeg.zeranoe.com/builds/win64/dev/ffmpeg-4.1-win64-dev.zip \
761ec79aa3dae66698c9791a2f0bb9da8794246f8356cadc741ddc0eabab0471 \
ffmpeg-4.1-win64-dev
@./prepare-dep https://ffmpeg.zeranoe.com/builds/win64/dev/ffmpeg-4.0.2-win64-dev.zip \
23ee994161c51285cb956b98d3caa499d48083dae7b26c1fdf77f22e98df1c5f \
ffmpeg-4.0.2-win64-dev
prepare-sdl2:
@./prepare-dep https://libsdl.org/release/SDL2-devel-2.0.9-mingw.tar.gz \

View File

@@ -55,4 +55,4 @@ get_dep() {
fi
}
get_dep "$url" "$sum" "$dir"
get_dep "$1" "$2" "$3"

View File

@@ -6,8 +6,8 @@ android {
applicationId "com.genymobile.scrcpy"
minSdkVersion 21
targetSdkVersion 27
versionCode 7
versionName "1.6"
versionCode 5
versionName "1.4"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {

View File

@@ -9,8 +9,8 @@ import java.nio.charset.StandardCharsets;
public class ControlEventReader {
private static final int KEYCODE_PAYLOAD_LENGTH = 9;
private static final int MOUSE_PAYLOAD_LENGTH = 17;
private static final int SCROLL_PAYLOAD_LENGTH = 20;
private static final int MOUSE_PAYLOAD_LENGTH = 13;
private static final int SCROLL_PAYLOAD_LENGTH = 16;
private static final int COMMAND_PAYLOAD_LENGTH = 1;
public static final int TEXT_MAX_LENGTH = 300;
@@ -132,8 +132,8 @@ public class ControlEventReader {
}
private static Position readPosition(ByteBuffer buffer) {
int x = buffer.getInt();
int y = buffer.getInt();
int x = toUnsigned(buffer.getShort());
int y = toUnsigned(buffer.getShort());
int screenWidth = toUnsigned(buffer.getShort());
int screenHeight = toUnsigned(buffer.getShort());
return new Position(x, y, screenWidth, screenHeight);

View File

@@ -151,7 +151,7 @@ public class ScreenEncoder implements Device.RotationListener {
}
private static IBinder createDisplay() {
return SurfaceControl.createDisplay("scrcpy", true);
return SurfaceControl.createDisplay("scrcpy", false);
}
private static void configure(MediaCodec codec, MediaFormat format) {

View File

@@ -2,14 +2,11 @@ package com.genymobile.scrcpy;
import android.graphics.Rect;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
public final class Server {
private static final String SERVER_PATH = "/data/local/tmp/scrcpy-server.jar";
private Server() {
// not instantiable
}
@@ -49,24 +46,35 @@ public final class Server {
@SuppressWarnings("checkstyle:MagicNumber")
private static Options createOptions(String... args) {
if (args.length != 5)
throw new IllegalArgumentException("Expecting 5 parameters");
Options options = new Options();
if (args.length < 1) {
return options;
}
int maxSize = Integer.parseInt(args[0]) & ~7; // multiple of 8
options.setMaxSize(maxSize);
if (args.length < 2) {
return options;
}
int bitRate = Integer.parseInt(args[1]);
options.setBitRate(bitRate);
if (args.length < 3) {
return options;
}
// use "adb forward" instead of "adb tunnel"? (so the server must listen)
boolean tunnelForward = Boolean.parseBoolean(args[2]);
options.setTunnelForward(tunnelForward);
if (args.length < 4) {
return options;
}
Rect crop = parseCrop(args[3]);
options.setCrop(crop);
if (args.length < 5) {
return options;
}
boolean sendFrameMeta = Boolean.parseBoolean(args[4]);
options.setSendFrameMeta(sendFrameMeta);
@@ -74,7 +82,7 @@ public final class Server {
}
private static Rect parseCrop(String crop) {
if ("-".equals(crop)) {
if (crop.isEmpty()) {
return null;
}
// input format: "width:height:x:y"
@@ -89,14 +97,6 @@ public final class Server {
return new Rect(x, y, x + width, y + height);
}
private static void unlinkSelf() {
try {
new File(SERVER_PATH).delete();
} catch (Exception e) {
Ln.e("Cannot unlink server", e);
}
}
public static void main(String... args) throws Exception {
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
@@ -105,7 +105,6 @@ public final class Server {
}
});
unlinkSelf();
Options options = createOptions(args);
scrcpy(options);
}