Compare commits

..

39 Commits
v1.1 ... api19

Author SHA1 Message Date
1de8506a0d Support Android API 19
Since "adb forward" fallback has been implemented, it is easy to support
API 19.

Replace the incompatible calls related to MediaCodec to use
minSdkVersion 19 instead of 21.
2018-03-28 22:13:58 +02:00
71f50fb697 Merge branch 'master' into dev 2018-03-28 10:45:23 +02:00
82efff34e8 Factorize texture creation
SDL_CreateTexture() is called both during initialization and on frame
size change.

To avoid inconsistent changes to arguments value, factorize them to a
single function create_texture().
2018-03-27 11:01:40 +02:00
860006e082 Forward double-click events
Double-clicks were not sent to the device anymore since the
"double-click on black borders" feature.

When a double click occurs inside the device screen, send the event to
the device normally.

Fixes <https://github.com/Genymobile/scrcpy/issues/97>.
2018-03-26 14:49:10 +02:00
57eaf05289 Improve startup time when show_touches is enabled
Enabling "show touches" involves the execution of an adb command, which
takes some time.

In order to parallelize, execute the command as soon as possible, but
reap the process only once everything is initialized.
2018-03-25 16:39:36 +02:00
dd2a5c1ecf Disable "show touches" once window is closed
If --show-touches is set, then the option must be disabled on quit.

Since it executes an adb command, it takes some time, so close the
window beforehand so that the close window button does not seem
unresponsive.
2018-03-25 16:03:02 +02:00
66ec252893 Add an option to enable "show touches"
Add -t/--show-touches option to show physical touches while scrcpy is
running.

See <https://github.com/Genymobile/scrcpy/issues/96>.
2018-03-25 15:43:27 +02:00
b13d25b9f4 Group scrcpy options into a struct
The scrcpy() function accepts as many parameters as there are options.

To simplify, group all options in a separate struct.
2018-03-25 15:16:29 +02:00
b449c09442 Merge branch 'master' into dev 2018-03-25 15:16:19 +02:00
8b84492830 Merge branch 'stek29/macos' (#56)
macOS specific README changes
2018-03-25 14:31:02 +02:00
4d50832f8e Add instructions to install Java 8 on macOS
And remove gcc from the packages list, clang is available by default.
2018-03-25 14:29:22 +02:00
e0e8dfeb3b Merge pull request #94 from pierlon/pierlon-patch-1
Add instructions to run via Docker
2018-03-25 14:12:29 +02:00
f4d6449af7 Merge pull request #95 from Sea-n/patch-1
Update README.md
2018-03-25 14:00:20 +02:00
64963fff62 Update README.md
Fix Typo
2018-03-25 17:51:29 +08:00
b7d9b8739c Add instructions to run via Docker 2018-03-24 23:15:14 -05:00
88f6b43c8f Merge pull request #93 from CampbellOwen/patch-1
Add links to FFmpeg and LibSDL2 dependencies
2018-03-24 09:26:12 +01:00
324a264233 Change links to wikipedia 2018-03-24 01:09:41 -07:00
3bb2cda955 Add links to FFmpeg and LibSDL2 dependencies 2018-03-24 00:55:05 -07:00
35298bb0c6 Process the last video frame
On H.264 stream EOF, the eof_reached flag is set, but av_read_frame()
still provides a frame, so check the flag only afterwards.

As a side-effect, it also fixes a memory leak (the very last packet was
not unref).
2018-03-23 14:01:58 +01:00
73c332e3e4 Unref last packet on exit 2018-03-23 13:57:32 +01:00
15014f2689 Clarify adb requirements
Since _scrcpy_ also supports `adb forward`, remove the part about `adb
reverse`.

Make explicit that _adb_ is included in the prebuilt application for
Windows (many users manually download the platform-tools for no reason).
2018-03-23 10:55:52 +01:00
29b5c5b8f4 Merge branch 'arich/addShake' into dev (#85)
Add support for CTRL+S to send hardware "shake" to device
2018-03-23 10:13:19 +01:00
88ee6bc928 Swap MENU and APP_SWITCH shortcuts
Ctrl+s was mapped to MENU, while Ctrl+m was mapped to APP_SWITCH.

To avoid confusion, swap the shortcuts:
 - Ctrl+m like _M_enu
 - Ctrl+s like _S_witch
2018-03-23 10:10:24 +01:00
35e9a64c34 Rename "shake" to "menu"
The action sends AKEYCODE_MENU, so just name it "menu".

See <https://github.com/Genymobile/scrcpy/pull/85>.
2018-03-23 10:07:48 +01:00
9cac38fe58 Describe workaround to get output on Windows
Since nothing is printed to the console, we need a way to get the output
in case of errors.

Describe how in the README.
2018-03-23 09:57:45 +01:00
301c52b603 Add support for CTRL+S to send hardware "shake" to device w/readme 2018-03-22 16:15:24 -07:00
f00c6c5b13 Disable custom SDL signal handlers
Request SDL not to replace the SIGINT and SIGTERM handlers, so that the
process is immediately terminated on Ctrl+C.

This avoids process hanging on Ctrl+C during network calls on
initialization.

Some of them accepted a timeout, but it was not used since
commit 9b056f5091 anymore.
2018-03-21 21:43:12 +01:00
3b3803da0d Remove useless blocks in switch/case
Remove unnecessary additional blocks.
2018-03-21 11:14:15 +01:00
f5cf6c1b2c Include source root directory
All headers and sources are in src/. To avoid using relative includes
from subdirectories ("../../"), include the source root directory.
2018-03-20 21:32:41 +01:00
2573df9727 Document the step to clone the project
This is not obvious to everyone, especially non-developers.
2018-03-18 12:10:06 +01:00
c65cb36d3b Increase the number of connection attempts
In "adb forward" mode, it may take a while before the server socket is
listening, so increase the number of connection attempts.

See <https://github.com/Genymobile/scrcpy/issues/5#issuecomment-373718551>.
2018-03-16 14:59:08 +01:00
821ec9843c Fix win32 build
The types size_t and ssize_t are defined on Windows (in MSYS2), so there
is no need to typedef SIZE_T and SSIZE_T.

Exit code is "unsigned long" both on Windows 32 and 64 bits.

See <https://github.com/Genymobile/scrcpy/issues/46#issuecomment-373603596>.
2018-03-16 08:58:59 +01:00
f16bd88802 Remove useless cast
For consistency with mouse button events handling, directly assign from
Sint32 to Uint16.
2018-03-15 16:30:51 +01:00
f3e8834a3c Fix warning message
Mouse "wheel button" is meaningless :)
2018-03-15 16:14:40 +01:00
080df5eb5d Fix switch/case code style
For readability and consistency, indent case statatements, and remove
unnecessary additional blocks.
2018-03-15 16:00:40 +01:00
047179f232 Add FAQ section about mouse clicks
On some devices, mouse clicks do not work by default. Enabling an option
is required.
2018-03-15 09:29:14 +01:00
2992dda497 Add link to the article for v1.1 in README 2018-03-14 18:03:34 +01:00
6406f64edc Update FAQ after v1.1 release
Two issues described in the FAQ have been fixed by V1.1. Remove them
from the FAQ.
2018-03-14 09:56:36 +01:00
f3f19d4e1d Update links to v1.1 in README 2018-03-14 09:53:55 +01:00
22 changed files with 220 additions and 118 deletions

39
FAQ.md
View File

@ -15,6 +15,17 @@ When run in `cmd.exe`, the application does not print anything. Even `scrcpy
However, if you run the very same `scrcpy.exe` from
[MSYS2](https://www.msys2.org/) (`mingw64`), then it correctly prints output.
As a workaround, redirect outputs to files, so that you can read the files
afterwards:
```bash
scrcpy >stdout 2>stderr
type stdout
type stderr
```
_Note that all SDL logs are printed to stderr._
### On Windows, when I start the application, nothing happens
@ -34,27 +45,6 @@ If you still encounter problems, please see [issue 9].
[issue 9]: https://github.com/Genymobile/scrcpy/issues/9
### The application does not work over `adb connect`
If the device is connected using `adb connect`, then you'll get this error:
error: more than one device/emulator
ERROR: "adb reverse" returned with value 1
We plan to support it in future versions. See [issue 5].
[issue 5]: https://github.com/Genymobile/scrcpy/issues/5
### Mouse clicks do not work
On many LG devices, [mouse clicks do not work][issue 18]. We're [working][pr27]
on it.
[issue 18]: https://github.com/Genymobile/scrcpy/issues/18
[pr27]: https://github.com/Genymobile/scrcpy/pull/27
### I get a black screen for some applications like Silence
This is expected, they requested to protect the screen.
@ -68,6 +58,13 @@ 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].
[simulating input]: https://github.com/Genymobile/scrcpy/issues/70#issuecomment-373286323
### Mouse clicks at wrong location
On MacOS, with HiDPI support and multiple screens, input location are wrongly

View File

@ -9,27 +9,28 @@ and _MacOS_.
## Requirements
The Android part requires at least API 21 (Android 5.0).
The Android part requires at least API 19 (Android 4.4).
You need [adb] (recent enough so that `adb reverse` is implemented, it works
with 1.0.36). It is available in the [Android SDK platform
tools][platform-tools], on packaged in your distribution (`android-adb-tools`).
You need [adb]. It is available in the [Android SDK platform
tools][platform-tools], or packaged in your distribution (`android-adb-tools`).
On Windows, just download the [platform-tools][platform-tools-windows] and
extract the following files to a directory accessible from your `PATH`:
On Windows, if you use the [prebuilt application](#windows), it is already
included. Otherwise, just download the [platform-tools][platform-tools-windows]
and extract the following files to a directory accessible from your `PATH`:
- `adb.exe`
- `AdbWinApi.dll`
- `AdbWinUsbApi.dll`
Make sure you [enabled adb debugging][enable-adb] on your device(s).
The client requires [FFmpeg] and [LibSDL2].
[adb]: https://developer.android.com/studio/command-line/adb.html
[enable-adb]: https://developer.android.com/studio/command-line/adb.html#Enabling
[platform-tools]: https://developer.android.com/studio/releases/platform-tools.html
[platform-tools-windows]: https://dl.google.com/android/repository/platform-tools-latest-windows.zip
The client requires _FFmpeg_ and _LibSDL2_.
[ffmpeg]: https://en.wikipedia.org/wiki/FFmpeg
[LibSDL2]: https://en.wikipedia.org/wiki/Simple_DirectMedia_Layer
## Build and install
@ -82,10 +83,10 @@ Two [AUR] packages have been created by users:
For Windows, for simplicity, a prebuilt archive with all the dependencies
(including `adb`) is available:
- [`scrcpy-windows-with-deps-v1.0.zip`][direct-windows-with-deps].
_(SHA-256: bc4bf32600e8548cdce490f94bed5dcba0006cdd38aff95748972e5d9877dd62)_
- [`scrcpy-windows-with-deps-v1.1.zip`][direct-windows-with-deps].
_(SHA-256: 27eb36c15937601d1062c1dc0b45faae0e06fefea2019aadeb4fa7f76a07bb4c)_
[direct-windows-with-deps]: https://github.com/Genymobile/scrcpy/releases/download/v1.0/scrcpy-windows-with-deps-v1.0.zip
[direct-windows-with-deps]: https://github.com/Genymobile/scrcpy/releases/download/v1.1/scrcpy-windows-with-deps-v1.1.zip
_(It's just a portable version including _dll_ copied from MSYS2.)_
@ -124,16 +125,23 @@ Use [Homebrew] to install the packages:
brew install sdl2 ffmpeg
# client build dependencies
brew install gcc pkg-config meson
brew install pkg-config meson
```
Java (>= 7) is not available in Homebrew, so if you plan to build the server,
install it manually and make it available from the `PATH`:
Additionally, if you want to build the server, install Java 8 from Caskroom, and
make it avaliable from the `PATH`:
```bash
brew tap caskroom/versions
brew cask install java8
export JAVA_HOME="$(/usr/libexec/java_home --version 1.8)"
export PATH="$JAVA_HOME/bin:$PATH"
```
#### Docker
See [pierlon/scrcpy-docker](https://github.com/pierlon/scrcpy-docker).
### Common steps
Install the [Android SDK] (_Android Studio_), and set `ANDROID_HOME` to
@ -145,7 +153,14 @@ its directory. For example:
export ANDROID_HOME=~/android/sdk
```
Then, build `scrcpy`:
Clone the project:
```bash
git clone https://github.com/Genymobile/scrcpy
cd scrcpy
```
Then, build:
```bash
meson x --buildtype release --strip -Db_lto=true
@ -179,10 +194,10 @@ Since the server binary, that will be pushed to the Android device, does not
depend on your system and architecture, you may want to use the prebuilt binary
instead:
- [`scrcpy-server-v1.0.jar`][direct-scrcpy-server].
_(SHA-256: b573b06a6072476b85b6308e3ad189f2665ad5be4f8ca3a6b9ec81d64df20558)_
- [`scrcpy-server-v1.1.jar`][direct-scrcpy-server].
_(SHA-256: 14826512bf38447ec94adf3b531676ce038d19e7e06757fb4e537882b17e77b3)_
[direct-scrcpy-server]: https://github.com/Genymobile/scrcpy/releases/download/v1.0/scrcpy-server-v1.0.jar
[direct-scrcpy-server]: https://github.com/Genymobile/scrcpy/releases/download/v1.1/scrcpy-server-v1.1.jar
In that case, the build does not require Java or the Android SDK.
@ -232,6 +247,12 @@ If several devices are listed in `adb devices`, you must specify the _serial_:
scrcpy -s 0123456789abcdef
```
To show physical touches while scrcpy is running:
```bash
scrcpy -t
```
To run without installing:
```bash
@ -250,11 +271,12 @@ To run without installing:
| resize window to remove black borders | `Ctrl`+`x` \| _Double-click¹_ |
| click on `HOME` | `Ctrl`+`h` \| _Middle-click_ |
| click on `BACK` | `Ctrl`+`b` \| _Right-click²_ |
| click on `APP_SWITCH` | `Ctrl`+`m` |
| click on `APP_SWITCH` | `Ctrl`+`s` |
| click on `MENU` | `Ctrl`+`m` |
| click on `VOLUME_UP` | `Ctrl`+`+` |
| click on `VOLUME_DOWN` | `Ctrl`+`-` |
| click on `POWER` | `Ctrl`+`p` |
| turn screen on | _Right-click¹_ |
| turn screen on | _Right-click²_ |
| paste computer clipboard to device | `Ctrl`+`v` |
| enable/disable FPS counter (on stdout) | `Ctrl`+`i` |
@ -300,6 +322,7 @@ Read the [developers page].
See the License for the specific language governing permissions and
limitations under the License.
## Article
## Articles
- [Introducing scrcpy](https://blog.rom1v.com/2018/03/introducing-scrcpy/)
- [Scrcpy now works wirelessly](https://www.genymotion.com/blog/open-source-project-scrcpy-now-works-wirelessly/)

View File

@ -85,7 +85,8 @@ conf.set('HIDPI_SUPPORT', get_option('hidpi_support'))
configure_file(configuration: conf, output: 'config.h')
executable('scrcpy', src, dependencies: dependencies, install: true)
src_dir = include_directories('src')
executable('scrcpy', src, dependencies: dependencies, include_directories: src_dir, install: true)
### TESTS
@ -96,8 +97,6 @@ tests = [
['test_strutil', ['tests/test_strutil.c', 'src/strutil.c']],
]
src_dir = include_directories('src')
foreach t : tests
exe = executable(t[0], t[1], include_directories: src_dir, dependencies: dependencies)
test(t[0], exe)

View File

@ -4,10 +4,9 @@
#include <stdlib.h>
#include <string.h>
#include "common.h"
#include "log.h"
#define ARRAY_LEN(a) (sizeof(a) / sizeof(a[0]))
static const char *adb_command;
static inline const char *get_adb_command() {

View File

@ -7,12 +7,11 @@
// <https://stackoverflow.com/a/44383330/1987178>
#ifdef _WIN32
# define PRIexitcode "lu"
# ifdef _WIN64
# define PRIsizet PRIu64
# define PRIexitcode "lu"
# else
# define PRIsizet PRIu32
# define PRIexitcode "u"
# endif
#else
# define PRIsizet "zu"

View File

@ -3,6 +3,7 @@
#include <SDL2/SDL_stdinc.h>
#define ARRAY_LEN(a) (sizeof(a) / sizeof(a[0]))
#define MIN(X,Y) (X) < (Y) ? (X) : (Y)
#define MAX(X,Y) (X) > (Y) ? (X) : (Y)

View File

@ -145,8 +145,8 @@ SDL_bool mouse_button_from_sdl_to_android(const SDL_MouseButtonEvent *from,
to->mouse_event.buttons = convert_mouse_buttons(SDL_BUTTON(from->button));
to->mouse_event.position.screen_size = screen_size;
to->mouse_event.position.point.x = (Uint16) from->x;
to->mouse_event.position.point.y = (Uint16) from->y;
to->mouse_event.position.point.x = from->x;
to->mouse_event.position.point.y = from->y;
return SDL_TRUE;
}

View File

@ -91,7 +91,7 @@ static int run_decoder(void *data) {
packet.data = NULL;
packet.size = 0;
while (!av_read_frame(format_ctx, &packet) && !avio_ctx->eof_reached) {
while (!av_read_frame(format_ctx, &packet)) {
// the new decoding/encoding API has been introduced by:
// <http://git.videolan.org/?p=ffmpeg.git;a=commitdiff;h=7fc329e2dd6226dfecaa4a1d7adf353bf2773726>
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 37, 0)
@ -125,6 +125,10 @@ static int run_decoder(void *data) {
}
#endif
av_packet_unref(&packet);
if (avio_ctx->eof_reached) {
break;
}
}
LOGD("End of frames");

View File

@ -78,6 +78,10 @@ static inline void action_volume_down(struct controller *controller) {
send_keycode(controller, AKEYCODE_VOLUME_DOWN, "VOLUME_DOWN");
}
static inline void action_menu(struct controller *controller) {
send_keycode(controller, AKEYCODE_MENU, "MENU");
}
// turn the screen on if it was off, press BACK otherwise
static void press_back_or_turn_screen_on(struct controller *controller) {
struct control_event control_event;
@ -176,9 +180,12 @@ void input_manager_process_key(struct input_manager *input_manager,
case SDLK_BACKSPACE:
action_back(input_manager->controller);
return;
case SDLK_m:
case SDLK_s:
action_app_switch(input_manager->controller);
return;
case SDLK_m:
action_menu(input_manager->controller);
return;
case SDLK_p:
action_power(input_manager->controller);
return;
@ -240,10 +247,11 @@ void input_manager_process_mouse_button(struct input_manager *input_manager,
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;
if (outside_device_screen) {
screen_resize_to_fit(input_manager->screen);
return;
}
// otherwise, send the click event to the device
}
};
struct control_event control_event;
@ -263,7 +271,7 @@ void input_manager_process_mouse_wheel(struct input_manager *input_manager,
struct control_event control_event;
if (mouse_wheel_from_sdl_to_android(event, position, &control_event)) {
if (!controller_push_event(input_manager->controller, &control_event)) {
LOGW("Cannot send wheel button event");
LOGW("Cannot send mouse wheel event");
}
}
}

View File

@ -12,6 +12,7 @@ struct args {
const char *serial;
SDL_bool help;
SDL_bool version;
SDL_bool show_touches;
Uint16 port;
Uint16 max_size;
Uint32 bit_rate;
@ -45,6 +46,10 @@ static void usage(const char *arg0) {
" The device serial number. Mandatory only if several devices\n"
" are connected to adb.\n"
"\n"
" -t, --show-touches\n"
" Enable \"show touches\" on start, disable on quit.\n"
" It only shows physical touches (not clicks from scrcpy).\n"
"\n"
" -v, --version\n"
" Print the version of scrcpy.\n"
"\n"
@ -70,9 +75,12 @@ static void usage(const char *arg0) {
" Right-click (when screen is on)\n"
" click on BACK\n"
"\n"
" Ctrl+m\n"
" Ctrl+s\n"
" click on APP_SWITCH\n"
"\n"
" Ctrl+m\n"
" click on MENU\n"
"\n"
" Ctrl+'+'\n"
" click on VOLUME_UP\n"
"\n"
@ -180,47 +188,45 @@ 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[] = {
{"bit-rate", required_argument, NULL, 'b'},
{"help", no_argument, NULL, 'h'},
{"max-size", required_argument, NULL, 'm'},
{"port", required_argument, NULL, 'p'},
{"serial", required_argument, NULL, 's'},
{"version", no_argument, NULL, 'v'},
{NULL, 0, NULL, 0 },
{"bit-rate", required_argument, NULL, 'b'},
{"help", no_argument, NULL, 'h'},
{"max-size", required_argument, NULL, 'm'},
{"port", required_argument, NULL, 'p'},
{"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:hm:p:s:v", long_options, NULL)) != -1) {
while ((c = getopt_long(argc, argv, "b:hm:p:s:tv", long_options, NULL)) != -1) {
switch (c) {
case 'b': {
case 'b':
if (!parse_bit_rate(optarg, &args->bit_rate)) {
return SDL_FALSE;
}
break;
}
case 'h': {
case 'h':
args->help = SDL_TRUE;
break;
}
case 'm': {
case 'm':
if (!parse_max_size(optarg, &args->max_size)) {
return SDL_FALSE;
}
break;
}
case 'p': {
case 'p':
if (!parse_port(optarg, &args->port)) {
return SDL_FALSE;
}
break;
}
case 's': {
case 's':
args->serial = optarg;
break;
}
case 'v': {
case 't':
args->show_touches = SDL_TRUE;
break;
case 'v':
args->version = SDL_TRUE;
break;
}
default:
// getopt prints the error message on stderr
return SDL_FALSE;
@ -246,6 +252,7 @@ int main(int argc, char *argv[]) {
.serial = NULL,
.help = SDL_FALSE,
.version = SDL_FALSE,
.show_touches = SDL_FALSE,
.port = DEFAULT_LOCAL_PORT,
.max_size = DEFAULT_MAX_SIZE,
.bit_rate = DEFAULT_BIT_RATE,
@ -274,7 +281,14 @@ int main(int argc, char *argv[]) {
SDL_LogSetAllPriority(SDL_LOG_PRIORITY_DEBUG);
#endif
int res = scrcpy(args.serial, args.port, args.max_size, args.bit_rate) ? 0 : 1;
struct scrcpy_options options = {
.serial = args.serial,
.port = args.port,
.max_size = args.max_size,
.bit_rate = args.bit_rate,
.show_touches = args.show_touches,
};
int res = scrcpy(&options) ? 0 : 1;
avformat_network_deinit(); // ignore failure

View File

@ -9,8 +9,6 @@
#define SHUT_RD SD_RECEIVE
#define SHUT_WR SD_SEND
#define SHUT_RDWR SD_BOTH
typedef SIZE_T size_t;
typedef SSIZE_T ssize_t;
typedef SOCKET socket_t;
#else
# include <sys/socket.h>

View File

@ -79,16 +79,15 @@ static void event_loop(void) {
break;
case SDL_WINDOWEVENT:
switch (event.window.event) {
case SDL_WINDOWEVENT_EXPOSED:
case SDL_WINDOWEVENT_SIZE_CHANGED:
screen_render(&screen);
break;
case SDL_WINDOWEVENT_EXPOSED:
case SDL_WINDOWEVENT_SIZE_CHANGED:
screen_render(&screen);
break;
}
break;
case SDL_TEXTINPUT: {
case SDL_TEXTINPUT:
input_manager_process_text_input(&input_manager, &event.text);
break;
}
case SDL_KEYDOWN:
case SDL_KEYUP:
input_manager_process_key(&input_manager, &event.key);
@ -96,36 +95,56 @@ static void event_loop(void) {
case SDL_MOUSEMOTION:
input_manager_process_mouse_motion(&input_manager, &event.motion);
break;
case SDL_MOUSEWHEEL: {
case SDL_MOUSEWHEEL:
input_manager_process_mouse_wheel(&input_manager, &event.wheel);
break;
}
case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEBUTTONUP: {
case SDL_MOUSEBUTTONUP:
input_manager_process_mouse_button(&input_manager, &event.button);
break;
}
}
}
}
SDL_bool scrcpy(const char *serial, Uint16 local_port, Uint16 max_size, Uint32 bit_rate) {
if (!server_start(&server, serial, local_port, max_size, bit_rate)) {
static process_t set_show_touches_enabled(const char *serial, SDL_bool enabled) {
const char *value = enabled ? "1" : "0";
const char *const adb_cmd[] = {
"shell", "settings", "put", "system", "show_touches", value
};
return adb_execute(serial, adb_cmd, ARRAY_LEN(adb_cmd));
}
static void wait_show_touches(process_t process) {
// reap the process, ignore the result
process_check_success(process, "show_touches");
}
SDL_bool scrcpy(const struct scrcpy_options *options) {
if (!server_start(&server, options->serial, options->port,
options->max_size, options->bit_rate)) {
return SDL_FALSE;
}
process_t proc_show_touches;
SDL_bool show_touches_waited;
if (options->show_touches) {
LOGI("Enable show_touches");
proc_show_touches = set_show_touches_enabled(options->serial, SDL_TRUE);
show_touches_waited = SDL_FALSE;
}
SDL_bool ret = SDL_TRUE;
if (!SDL_SetHint(SDL_HINT_NO_SIGNAL_HANDLERS, "1")) {
LOGW("Cannot request to keep default signal handlers");
}
if (!sdl_init_and_configure()) {
ret = SDL_FALSE;
goto finally_destroy_server;
}
// SDL initialization replace the signal handler for SIGTERM, so Ctrl+C is
// managed by the event loop. This blocking call blocks the event loop, so
// timeout the connection not to block indefinitely in case of SIGTERM.
#define SERVER_CONNECT_TIMEOUT_MS 2000
socket_t device_socket = server_connect_to(&server, SERVER_CONNECT_TIMEOUT_MS);
socket_t device_socket = server_connect_to(&server);
if (device_socket == INVALID_SOCKET) {
server_stop(&server);
ret = SDL_FALSE;
@ -175,10 +194,16 @@ SDL_bool scrcpy(const char *serial, Uint16 local_port, Uint16 max_size, Uint32 b
goto finally_stop_and_join_controller;
}
event_loop();
if (options->show_touches) {
wait_show_touches(proc_show_touches);
show_touches_waited = SDL_TRUE;
}
event_loop();
LOGD("quit...");
screen_destroy(&screen);
finally_stop_and_join_controller:
controller_stop(&controller);
controller_join(&controller);
@ -192,6 +217,16 @@ finally_stop_decoder:
finally_destroy_frames:
frames_destroy(&frames);
finally_destroy_server:
if (options->show_touches) {
if (!show_touches_waited) {
// wait the process which enabled "show touches"
wait_show_touches(proc_show_touches);
}
LOGI("Disable show_touches");
proc_show_touches = set_show_touches_enabled(options->serial, SDL_FALSE);
wait_show_touches(proc_show_touches);
}
server_destroy(&server);
return ret;

View File

@ -3,6 +3,14 @@
#include <SDL2/SDL_stdinc.h>
SDL_bool scrcpy(const char *serial, Uint16 local_port, Uint16 max_size, Uint32 bit_rate);
struct scrcpy_options {
const char *serial;
Uint16 port;
Uint16 max_size;
Uint32 bit_rate;
SDL_bool show_touches;
};
SDL_bool scrcpy(const struct scrcpy_options *options);
#endif

View File

@ -136,6 +136,11 @@ void screen_init(struct screen *screen) {
*screen = (struct screen) SCREEN_INITIALIZER;
}
static inline SDL_Texture *create_texture(SDL_Renderer *renderer, struct size frame_size) {
return SDL_CreateTexture(renderer, SDL_PIXELFORMAT_YV12, SDL_TEXTUREACCESS_STREAMING,
frame_size.width, frame_size.height);
}
SDL_bool screen_init_rendering(struct screen *screen, const char *device_name, struct size frame_size) {
screen->frame_size = frame_size;
@ -174,8 +179,7 @@ SDL_bool screen_init_rendering(struct screen *screen, const char *device_name, s
SDL_FreeSurface(icon);
LOGI("Initial texture: %" PRIu16 "x%" PRIu16, frame_size.width, frame_size.height);
screen->texture = SDL_CreateTexture(screen->renderer, SDL_PIXELFORMAT_YV12, SDL_TEXTUREACCESS_STREAMING,
frame_size.width, frame_size.height);
screen->texture = create_texture(screen->renderer, frame_size);
if (!screen->texture) {
LOGC("Could not create texture: %s", SDL_GetError());
screen_destroy(screen);
@ -224,8 +228,7 @@ static SDL_bool prepare_for_frame(struct screen *screen, struct size new_frame_s
LOGD("New texture: %" PRIu16 "x%" PRIu16,
screen->frame_size.width, screen->frame_size.height);
screen->texture = SDL_CreateTexture(screen->renderer, SDL_PIXELFORMAT_YV12, SDL_TEXTUREACCESS_STREAMING,
new_frame_size.width, new_frame_size.height);
screen->texture = create_texture(screen->renderer, new_frame_size);
if (!screen->texture) {
LOGC("Could not create texture: %s", SDL_GetError());
return SDL_FALSE;

View File

@ -195,11 +195,11 @@ SDL_bool server_start(struct server *server, const char *serial, Uint16 local_po
return SDL_TRUE;
}
socket_t server_connect_to(struct server *server, Uint32 timeout_ms) {
socket_t server_connect_to(struct server *server) {
if (!server->tunnel_forward) {
server->device_socket = net_accept(server->server_socket);
} else {
Uint32 attempts = 10;
Uint32 attempts = 50;
Uint32 delay = 100; // ms
server->device_socket = connect_to_server(server->local_port, attempts, delay);
}

View File

@ -34,7 +34,7 @@ SDL_bool server_start(struct server *server, const char *serial, Uint16 local_po
Uint16 max_size, Uint32 bit_rate);
// block until the communication with the server is established
socket_t server_connect_to(struct server *server, Uint32 timeout_ms);
socket_t server_connect_to(struct server *server);
// disconnect and kill the server process
void server_stop(struct server *server);

View File

@ -1,4 +1,4 @@
#include "../../command.h"
#include "command.h"
#include <signal.h>
#include <sys/types.h>

View File

@ -1,4 +1,4 @@
#include "../../net.h"
#include "net.h"
# include <unistd.h>

View File

@ -1,7 +1,7 @@
#include "../../command.h"
#include "command.h"
#include "../../log.h"
#include "../../strutil.h"
#include "log.h"
#include "strutil.h"
HANDLE cmd_execute(const char *path, const char *const argv[]) {
STARTUPINFO si;

View File

@ -1,6 +1,6 @@
#include "../../net.h"
#include "net.h"
#include "../../log.h"
#include "log.h"
SDL_bool net_init(void) {
WSADATA wsa;

View File

@ -4,7 +4,7 @@ android {
compileSdkVersion 27
defaultConfig {
applicationId "com.genymobile.scrcpy"
minSdkVersion 21
minSdkVersion 19
targetSdkVersion 27
versionCode 2
versionName "1.1"

View File

@ -6,6 +6,7 @@ import android.graphics.Rect;
import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaFormat;
import android.os.Build;
import android.os.IBinder;
import android.view.Surface;
@ -77,11 +78,17 @@ public class ScreenEncoder implements Device.RotationListener {
}
}
@SuppressWarnings("deprecation") // Android API 19 requires to call deprecated methods
private boolean encode(MediaCodec codec, OutputStream outputStream) throws IOException {
@SuppressWarnings("checkstyle:MagicNumber")
byte[] buf = new byte[bitRate / 8]; // may contain up to 1 second of video
boolean eof = false;
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
ByteBuffer[] outputBuffers = null;
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
outputBuffers = codec.getOutputBuffers();
}
while (!consumeRotationChange() && !eof) {
int outputBufferId = codec.dequeueOutputBuffer(bufferInfo, -1);
eof = (bufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0;
@ -91,7 +98,12 @@ public class ScreenEncoder implements Device.RotationListener {
break;
}
if (outputBufferId >= 0) {
ByteBuffer outputBuffer = codec.getOutputBuffer(outputBufferId);
ByteBuffer outputBuffer;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
outputBuffer = codec.getOutputBuffer(outputBufferId);
} else {
outputBuffer = outputBuffers[outputBufferId];
}
while (outputBuffer.hasRemaining()) {
int remaining = outputBuffer.remaining();
int len = Math.min(buf.length, remaining);
@ -100,6 +112,8 @@ public class ScreenEncoder implements Device.RotationListener {
outputBuffer.get(buf, 0, len);
outputStream.write(buf, 0, len);
}
} else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP && outputBufferId == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
outputBuffers = codec.getOutputBuffers();
}
} finally {
if (outputBufferId >= 0) {