mirror of
https://github.com/Genymobile/scrcpy.git
synced 2025-04-20 11:35:57 +00:00
commit
0d3145db4b
8 changed files with 105 additions and 46 deletions
12
BUILD.md
12
BUILD.md
|
@ -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 \
|
||||
sudo apt install make gcc pkg-config meson ninja-build \
|
||||
libavcodec-dev libavformat-dev libavutil-dev \
|
||||
libsdl2-dev
|
||||
|
||||
|
@ -199,6 +199,12 @@ 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:
|
||||
|
@ -229,9 +235,9 @@ You can then [run](README.md#run) _scrcpy_.
|
|||
## Prebuilt server
|
||||
|
||||
- [`scrcpy-server-v1.5.jar`][direct-scrcpy-server]
|
||||
_(SHA-256: c827f566172a5c5946e63b8378ac93d374dff9e229083e5cd9980df57536947b)_
|
||||
_(SHA-256: d97aab6f60294e33e7ff79c2856ad3e01f912892395131f4f337e9ece03c24de)_
|
||||
|
||||
[direct-scrcpy-server]: https://github.com/Genymobile/scrcpy/releases/download/v1.5/scrcpy-server-v1.5.jar
|
||||
[direct-scrcpy-server]: https://github.com/Genymobile/scrcpy/releases/download/v1.5-fixversion/scrcpy-server-v1.5.jar
|
||||
|
||||
Download the prebuilt server somewhere, and specify its path during the Meson
|
||||
configuration:
|
||||
|
|
31
README.md
31
README.md
|
@ -15,6 +15,11 @@ 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
|
||||
|
||||
|
@ -43,12 +48,12 @@ For Windows, for simplicity, prebuilt archives with all the dependencies
|
|||
(including `adb`) are available:
|
||||
|
||||
- [`scrcpy-win32-v1.5.zip`][direct-win32]
|
||||
_(SHA-256: 9118d74655a3e2daf9c1db37caf578f0b5239ccb078dbcbdb451e8a0becfe19f)_
|
||||
_(SHA-256: 46ae0d4c1c6bd049ec4a30080d2ad91a32b31d3f758afdca2c3a915ecabf02c1)_
|
||||
- [`scrcpy-win64-v1.5.zip`][direct-win64]
|
||||
_(SHA-256: fcaf7d596e8829cbcc119d67ec055eef2ee14ee204f28b33b7794f225ce16463)_
|
||||
_(SHA-256: 89daa07325129617cf943a84bc4e304ee5e57118416fe265b9b5d4a1bf87c501)_
|
||||
|
||||
[direct-win32]: https://github.com/Genymobile/scrcpy/releases/download/v1.5/scrcpy-win32-v1.5.zip
|
||||
[direct-win64]: https://github.com/Genymobile/scrcpy/releases/download/v1.5/scrcpy-win64-v1.5.zip
|
||||
[direct-win32]: https://github.com/Genymobile/scrcpy/releases/download/v1.5-fixversion/scrcpy-win32-v1.5.zip
|
||||
[direct-win64]: https://github.com/Genymobile/scrcpy/releases/download/v1.5-fixversion/scrcpy-win64-v1.5.zip
|
||||
|
||||
You can also [build the app manually][BUILD].
|
||||
|
||||
|
@ -208,6 +213,22 @@ 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_.
|
||||
|
@ -238,8 +259,6 @@ 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._
|
||||
|
|
|
@ -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', '1.4')
|
||||
conf.set_quoted('SCRCPY_VERSION', meson.project_version())
|
||||
|
||||
# the prefix used during configuration (meson --prefix=PREFIX)
|
||||
conf.set_quoted('PREFIX', get_option('prefix'))
|
||||
|
|
|
@ -80,12 +80,15 @@ 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 ret = net_recv_all(decoder->video_socket, header, HEADER_SIZE);
|
||||
if (ret <= 0) {
|
||||
return ret;
|
||||
ssize_t r = net_recv_all(decoder->video_socket, header, HEADER_SIZE);
|
||||
if (r == -1) {
|
||||
return AVERROR(errno);
|
||||
}
|
||||
if (r == 0) {
|
||||
return AVERROR_EOF;
|
||||
}
|
||||
// no partial read (net_recv_all())
|
||||
SDL_assert_release(ret == HEADER_SIZE);
|
||||
SDL_assert_release(r == HEADER_SIZE);
|
||||
|
||||
uint64_t pts = buffer_read64be(header);
|
||||
state->remaining = buffer_read32be(&header[8]);
|
||||
|
@ -93,7 +96,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 -1;
|
||||
return AVERROR(ENOMEM);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -102,20 +105,30 @@ 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 ret = net_recv(decoder->video_socket, buf, buf_size);
|
||||
if (ret <= 0) {
|
||||
return ret;
|
||||
ssize_t r = net_recv(decoder->video_socket, buf, buf_size);
|
||||
if (r == -1) {
|
||||
return AVERROR(errno);
|
||||
}
|
||||
if (r == 0) {
|
||||
return AVERROR_EOF;
|
||||
}
|
||||
|
||||
SDL_assert(state->remaining >= ret);
|
||||
state->remaining -= ret;
|
||||
SDL_assert(state->remaining >= r);
|
||||
state->remaining -= r;
|
||||
|
||||
return ret;
|
||||
return r;
|
||||
}
|
||||
|
||||
static int read_raw_packet(void *opaque, uint8_t *buf, int buf_size) {
|
||||
struct decoder *decoder = opaque;
|
||||
return net_recv(decoder->video_socket, buf, buf_size);
|
||||
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;
|
||||
}
|
||||
|
||||
// set the decoded frame as ready for rendering, and notify
|
||||
|
|
|
@ -18,16 +18,9 @@ static void convert_to_renderer_coordinates(SDL_Renderer *renderer, int *x, int
|
|||
*y = (int) (*y / scale_y) - viewport.y;
|
||||
}
|
||||
|
||||
static struct point get_mouse_point(struct screen *screen) {
|
||||
int x;
|
||||
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 = (Uint16) x,
|
||||
.y = (Uint16) y,
|
||||
};
|
||||
static void get_mouse_point(struct screen *screen, int *x, int *y) {
|
||||
SDL_GetMouseState(x, y);
|
||||
convert_to_renderer_coordinates(screen->renderer, x, y);
|
||||
}
|
||||
|
||||
static const int ACTION_DOWN = 1;
|
||||
|
@ -271,8 +264,18 @@ 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) {
|
||||
SDL_bool outside_device_screen = is_outside_device_screen(input_manager,
|
||||
event->x,
|
||||
event->y);
|
||||
if (event->type == SDL_MOUSEBUTTONDOWN) {
|
||||
if (event->button == SDL_BUTTON_RIGHT) {
|
||||
press_back_or_turn_screen_on(input_manager->controller);
|
||||
|
@ -283,17 +286,19 @@ void input_manager_process_mouse_button(struct input_manager *input_manager,
|
|||
return;
|
||||
}
|
||||
// double-click on black borders resize to fit the device screen
|
||||
if (event->button == SDL_BUTTON_LEFT && event->clicks == 2) {
|
||||
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
|
||||
if (event->button == SDL_BUTTON_LEFT && event->clicks == 2
|
||||
&& outside_device_screen) {
|
||||
screen_resize_to_fit(input_manager->screen);
|
||||
return;
|
||||
}
|
||||
// otherwise, send the click event to the device
|
||||
}
|
||||
|
||||
if (outside_device_screen) {
|
||||
// ignore
|
||||
return;
|
||||
}
|
||||
|
||||
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)) {
|
||||
|
@ -304,9 +309,22 @@ void input_manager_process_mouse_button(struct input_manager *input_manager,
|
|||
|
||||
void input_manager_process_mouse_wheel(struct input_manager *input_manager,
|
||||
const SDL_MouseWheelEvent *event) {
|
||||
int x;
|
||||
int y;
|
||||
get_mouse_point(input_manager->screen, &x, &y);
|
||||
if (is_outside_device_screen(input_manager, x, y)) {
|
||||
// ignore
|
||||
return;
|
||||
}
|
||||
|
||||
SDL_assert_release(x >= 0 && x < 0x10000 && y >= 0 && y < 0x10000);
|
||||
|
||||
struct position position = {
|
||||
.screen_size = input_manager->screen->frame_size,
|
||||
.point = get_mouse_point(input_manager->screen),
|
||||
.point = {
|
||||
.x = (Uint16) x,
|
||||
.y = (Uint16) y,
|
||||
},
|
||||
};
|
||||
struct control_event control_event;
|
||||
if (mouse_wheel_from_sdl_to_android(event, position, &control_event)) {
|
||||
|
|
|
@ -124,7 +124,7 @@ static void usage(const char *arg0) {
|
|||
}
|
||||
|
||||
static void print_version(void) {
|
||||
fprintf(stderr, "scrcpy v%s\n\n", SCRCPY_VERSION);
|
||||
fprintf(stderr, "scrcpy %s\n\n", SCRCPY_VERSION);
|
||||
|
||||
fprintf(stderr, "dependencies:\n");
|
||||
fprintf(stderr, " - SDL %d.%d.%d\n", SDL_MAJOR_VERSION, SDL_MINOR_VERSION, SDL_PATCHLEVEL);
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
project('scrcpy', 'c', meson_version: '>= 0.37', default_options : 'c_std=c11')
|
||||
project('scrcpy', 'c',
|
||||
version: '1.5',
|
||||
meson_version: '>= 0.37',
|
||||
default_options: 'c_std=c11')
|
||||
|
||||
if get_option('build_app')
|
||||
subdir('app')
|
||||
|
|
|
@ -6,8 +6,8 @@ android {
|
|||
applicationId "com.genymobile.scrcpy"
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 27
|
||||
versionCode 5
|
||||
versionName "1.4"
|
||||
versionCode 6
|
||||
versionName "1.5"
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
buildTypes {
|
||||
|
|
Loading…
Add table
Reference in a new issue