mirror of
https://github.com/Genymobile/scrcpy.git
synced 2026-02-25 15:54:28 +01:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6b4e8e8e59 | ||
|
|
876e42de9b |
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@@ -229,7 +229,7 @@ jobs:
|
||||
path: release/work/build-macos-aarch64/dist-tar/
|
||||
|
||||
build-macos-x86_64:
|
||||
runs-on: macos-15-intel
|
||||
runs-on: macos-13
|
||||
steps:
|
||||
- name: Check architecture
|
||||
run: |
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -188,7 +188,7 @@
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright (C) 2018 Genymobile
|
||||
Copyright (C) 2018-2026 Romain Vimont
|
||||
Copyright (C) 2018-2025 Romain Vimont
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
source for the project. Do not download releases from random websites, even if
|
||||
their name contains `scrcpy`.**
|
||||
|
||||
# scrcpy (v3.3.4)
|
||||
# scrcpy (v3.3.1)
|
||||
|
||||
<img src="app/data/icon.svg" width="128" height="128" alt="scrcpy" align="right" />
|
||||
|
||||
@@ -210,7 +210,7 @@ work][donate]:
|
||||
## License
|
||||
|
||||
Copyright (C) 2018 Genymobile
|
||||
Copyright (C) 2018-2026 Romain Vimont
|
||||
Copyright (C) 2018-2025 Romain Vimont
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
#!/usr/bin/env bash
|
||||
set -ex
|
||||
. $(dirname ${BASH_SOURCE[0]})/_init "$@"
|
||||
DEPS_DIR=$(dirname ${BASH_SOURCE[0]})
|
||||
cd "$DEPS_DIR"
|
||||
. common
|
||||
|
||||
VERSION=36.0.0
|
||||
URL="https://dl.google.com/android/repository/platform-tools_r$VERSION-linux.zip"
|
||||
FILENAME=platform-tools_r$VERSION-linux.zip
|
||||
PROJECT_DIR=platform-tools-$VERSION-linux
|
||||
SHA256SUM=0ead642c943ffe79701fccca8f5f1c69c4ce4f43df2eefee553f6ccb27cbfbe8
|
||||
|
||||
PROJECT_DIR="platform-tools-$VERSION-linux"
|
||||
FILENAME="$PROJECT_DIR.zip"
|
||||
|
||||
cd "$SOURCES_DIR"
|
||||
|
||||
if [[ -d "$PROJECT_DIR" ]]
|
||||
then
|
||||
echo "$PWD/$PROJECT_DIR" found
|
||||
else
|
||||
get_file "$URL" "$FILENAME" "$SHA256SUM"
|
||||
get_file "https://dl.google.com/android/repository/$FILENAME" "$FILENAME" "$SHA256SUM"
|
||||
mkdir -p "$PROJECT_DIR"
|
||||
cd "$PROJECT_DIR"
|
||||
ZIP_PREFIX=platform-tools
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
#!/usr/bin/env bash
|
||||
set -ex
|
||||
. $(dirname ${BASH_SOURCE[0]})/_init "$@"
|
||||
DEPS_DIR=$(dirname ${BASH_SOURCE[0]})
|
||||
cd "$DEPS_DIR"
|
||||
. common
|
||||
|
||||
VERSION=36.0.0
|
||||
URL="https://dl.google.com/android/repository/platform-tools_r$VERSION-darwin.zip"
|
||||
FILENAME=platform-tools_r$VERSION-darwin.zip
|
||||
PROJECT_DIR=platform-tools-$VERSION-darwin
|
||||
SHA256SUM=d3e9fa1df3345cf728586908426615a60863d2632f73f1ce14f0f1349ef000fd
|
||||
|
||||
PROJECT_DIR="platform-tools-$VERSION-darwin"
|
||||
FILENAME="$PROJECT_DIR.zip"
|
||||
|
||||
cd "$SOURCES_DIR"
|
||||
|
||||
if [[ -d "$PROJECT_DIR" ]]
|
||||
then
|
||||
echo "$PWD/$PROJECT_DIR" found
|
||||
else
|
||||
get_file "$URL" "$FILENAME" "$SHA256SUM"
|
||||
get_file "https://dl.google.com/android/repository/$FILENAME" "$FILENAME" "$SHA256SUM"
|
||||
mkdir -p "$PROJECT_DIR"
|
||||
cd "$PROJECT_DIR"
|
||||
ZIP_PREFIX=platform-tools
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
#!/usr/bin/env bash
|
||||
set -ex
|
||||
. $(dirname ${BASH_SOURCE[0]})/_init "$@"
|
||||
DEPS_DIR=$(dirname ${BASH_SOURCE[0]})
|
||||
cd "$DEPS_DIR"
|
||||
. common
|
||||
|
||||
VERSION=36.0.0
|
||||
URL="https://dl.google.com/android/repository/platform-tools_r$VERSION-win.zip"
|
||||
FILENAME=platform-tools_r$VERSION-win.zip
|
||||
PROJECT_DIR=platform-tools-$VERSION-windows
|
||||
SHA256SUM=12c2841f354e92a0eb2fd7bf6f0f9bf8538abce7bd6b060ac8349d6f6a61107c
|
||||
|
||||
PROJECT_DIR="platform-tools-$VERSION-windows"
|
||||
FILENAME="$PROJECT_DIR.zip"
|
||||
|
||||
cd "$SOURCES_DIR"
|
||||
|
||||
if [[ -d "$PROJECT_DIR" ]]
|
||||
then
|
||||
echo "$PWD/$PROJECT_DIR" found
|
||||
else
|
||||
get_file "$URL" "$FILENAME" "$SHA256SUM"
|
||||
get_file "https://dl.google.com/android/repository/$FILENAME" "$FILENAME" "$SHA256SUM"
|
||||
mkdir -p "$PROJECT_DIR"
|
||||
cd "$PROJECT_DIR"
|
||||
ZIP_PREFIX=platform-tools
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
#!/usr/bin/env bash
|
||||
# This file is intended to be sourced by other scripts, not executed
|
||||
|
||||
process_args() {
|
||||
if [[ $# != 3 ]]
|
||||
then
|
||||
# <host>: linux, macos, win32 or win64
|
||||
# <host>: win32 or win64
|
||||
# <build_type>: native or cross
|
||||
# <link_type>: static or shared
|
||||
echo "Syntax: $0 <host> <build_type> <link_type>" >&2
|
||||
@@ -11,8 +12,8 @@ process_args() {
|
||||
fi
|
||||
|
||||
HOST="$1"
|
||||
BUILD_TYPE="$2"
|
||||
LINK_TYPE="$3"
|
||||
BUILD_TYPE="$2" # native or cross
|
||||
LINK_TYPE="$3" # static or shared
|
||||
DIRNAME="$HOST-$BUILD_TYPE-$LINK_TYPE"
|
||||
|
||||
if [[ "$BUILD_TYPE" != native && "$BUILD_TYPE" != cross ]]
|
||||
@@ -1,22 +1,22 @@
|
||||
#!/usr/bin/env bash
|
||||
set -ex
|
||||
. $(dirname ${BASH_SOURCE[0]})/_init
|
||||
DEPS_DIR=$(dirname ${BASH_SOURCE[0]})
|
||||
cd "$DEPS_DIR"
|
||||
. common
|
||||
process_args "$@"
|
||||
|
||||
VERSION=1.5.0
|
||||
URL="https://code.videolan.org/videolan/dav1d/-/archive/$VERSION/dav1d-$VERSION.tar.gz"
|
||||
FILENAME=dav1d-$VERSION.tar.gz
|
||||
PROJECT_DIR=dav1d-$VERSION
|
||||
SHA256SUM=78b15d9954b513ea92d27f39362535ded2243e1b0924fde39f37a31ebed5f76b
|
||||
|
||||
PROJECT_DIR="dav1d-$VERSION"
|
||||
FILENAME="$PROJECT_DIR.tar.gz"
|
||||
|
||||
cd "$SOURCES_DIR"
|
||||
|
||||
if [[ -d "$PROJECT_DIR" ]]
|
||||
then
|
||||
echo "$PWD/$PROJECT_DIR" found
|
||||
else
|
||||
get_file "$URL" "$FILENAME" "$SHA256SUM"
|
||||
get_file "https://code.videolan.org/videolan/dav1d/-/archive/$VERSION/$FILENAME" "$FILENAME" "$SHA256SUM"
|
||||
tar xf "$FILENAME" # First level directory is "$PROJECT_DIR"
|
||||
fi
|
||||
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
#!/usr/bin/env bash
|
||||
set -ex
|
||||
. $(dirname ${BASH_SOURCE[0]})/_init
|
||||
DEPS_DIR=$(dirname ${BASH_SOURCE[0]})
|
||||
cd "$DEPS_DIR"
|
||||
. common
|
||||
process_args "$@"
|
||||
|
||||
VERSION=7.1.1
|
||||
URL="https://ffmpeg.org/releases/ffmpeg-$VERSION.tar.xz"
|
||||
FILENAME=ffmpeg-$VERSION.tar.xz
|
||||
PROJECT_DIR=ffmpeg-$VERSION
|
||||
SHA256SUM=733984395e0dbbe5c046abda2dc49a5544e7e0e1e2366bba849222ae9e3a03b1
|
||||
|
||||
PROJECT_DIR="ffmpeg-$VERSION"
|
||||
FILENAME="$PROJECT_DIR.tar.xz"
|
||||
|
||||
cd "$SOURCES_DIR"
|
||||
|
||||
if [[ -d "$PROJECT_DIR" ]]
|
||||
then
|
||||
echo "$PWD/$PROJECT_DIR" found
|
||||
else
|
||||
get_file "$URL" "$FILENAME" "$SHA256SUM"
|
||||
get_file "https://ffmpeg.org/releases/$FILENAME" "$FILENAME" "$SHA256SUM"
|
||||
tar xf "$FILENAME" # First level directory is "$PROJECT_DIR"
|
||||
fi
|
||||
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
#!/usr/bin/env bash
|
||||
set -ex
|
||||
. $(dirname ${BASH_SOURCE[0]})/_init
|
||||
DEPS_DIR=$(dirname ${BASH_SOURCE[0]})
|
||||
cd "$DEPS_DIR"
|
||||
. common
|
||||
process_args "$@"
|
||||
|
||||
VERSION=1.0.29
|
||||
URL="https://github.com/libusb/libusb/archive/refs/tags/v$VERSION.tar.gz"
|
||||
FILENAME=libusb-$VERSION.tar.gz
|
||||
PROJECT_DIR=libusb-$VERSION
|
||||
SHA256SUM=7c2dd39c0b2589236e48c93247c986ae272e27570942b4163cb00a060fcf1b74
|
||||
|
||||
PROJECT_DIR="libusb-$VERSION"
|
||||
FILENAME="$PROJECT_DIR.tar.gz"
|
||||
|
||||
cd "$SOURCES_DIR"
|
||||
|
||||
if [[ -d "$PROJECT_DIR" ]]
|
||||
then
|
||||
echo "$PWD/$PROJECT_DIR" found
|
||||
else
|
||||
get_file "$URL" "$FILENAME" "$SHA256SUM"
|
||||
get_file "https://github.com/libusb/libusb/archive/refs/tags/v$VERSION.tar.gz" "$FILENAME" "$SHA256SUM"
|
||||
tar xf "$FILENAME" # First level directory is "$PROJECT_DIR"
|
||||
fi
|
||||
|
||||
|
||||
@@ -1,24 +1,23 @@
|
||||
#!/usr/bin/env bash
|
||||
set -ex
|
||||
. $(dirname ${BASH_SOURCE[0]})/_init
|
||||
DEPS_DIR=$(dirname ${BASH_SOURCE[0]})
|
||||
cd "$DEPS_DIR"
|
||||
. common
|
||||
process_args "$@"
|
||||
|
||||
VERSION=2.32.8
|
||||
URL="https://github.com/libsdl-org/SDL/archive/refs/tags/release-$VERSION.tar.gz"
|
||||
FILENAME=SDL-$VERSION.tar.gz
|
||||
PROJECT_DIR=SDL-release-$VERSION
|
||||
SHA256SUM=dd35e05644ae527848d02433bec24dd0ea65db59faecf1a0e5d1880c533dac2c
|
||||
|
||||
PROJECT_DIR="sdl-$VERSION"
|
||||
FILENAME="$PROJECT_DIR.tar.gz"
|
||||
|
||||
cd "$SOURCES_DIR"
|
||||
|
||||
if [[ -d "$PROJECT_DIR" ]]
|
||||
then
|
||||
echo "$PWD/$PROJECT_DIR" found
|
||||
else
|
||||
get_file "$URL" "$FILENAME" "$SHA256SUM"
|
||||
tar xf "$FILENAME" # First level directory is "SDL-release-$VERSION"
|
||||
mv "SDL-release-$VERSION" "$PROJECT_DIR"
|
||||
get_file "https://github.com/libsdl-org/SDL/archive/refs/tags/release-$VERSION.tar.gz" "$FILENAME" "$SHA256SUM"
|
||||
tar xf "$FILENAME" # First level directory is "$PROJECT_DIR"
|
||||
fi
|
||||
|
||||
mkdir -p "$BUILD_DIR/$PROJECT_DIR"
|
||||
|
||||
@@ -13,7 +13,7 @@ BEGIN
|
||||
VALUE "LegalCopyright", "Romain Vimont, Genymobile"
|
||||
VALUE "OriginalFilename", "scrcpy.exe"
|
||||
VALUE "ProductName", "scrcpy"
|
||||
VALUE "ProductVersion", "3.3.4"
|
||||
VALUE "ProductVersion", "3.3.2"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
@@ -852,7 +852,7 @@ Report bugs to <https://github.com/Genymobile/scrcpy/issues>.
|
||||
.SH COPYRIGHT
|
||||
Copyright \(co 2018 Genymobile <https://www.genymobile.com>
|
||||
|
||||
Copyright \(co 2018\-2026 Romain Vimont <rom@rom1v.com>
|
||||
Copyright \(co 2018\-2025 Romain Vimont <rom@rom1v.com>
|
||||
|
||||
Licensed under the Apache License, Version 2.0.
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ sc_device_msg_deserialize(const uint8_t *buf, size_t len,
|
||||
}
|
||||
uint16_t id = sc_read16be(&buf[1]);
|
||||
size_t size = sc_read16be(&buf[3]);
|
||||
if (size > len - 5) {
|
||||
if (size < len - 5) {
|
||||
return 0; // not available
|
||||
}
|
||||
uint8_t *data = malloc(size);
|
||||
|
||||
@@ -170,7 +170,6 @@ sc_display_set_pending_frame(struct sc_display *display, const AVFrame *frame) {
|
||||
}
|
||||
}
|
||||
|
||||
av_frame_unref(display->pending.frame);
|
||||
int r = av_frame_ref(display->pending.frame, frame);
|
||||
if (r) {
|
||||
LOGE("Could not ref frame: %d", r);
|
||||
@@ -182,11 +181,6 @@ sc_display_set_pending_frame(struct sc_display *display, const AVFrame *frame) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Forward declaration
|
||||
static bool
|
||||
sc_display_update_texture_internal(struct sc_display *display,
|
||||
const AVFrame *frame);
|
||||
|
||||
static bool
|
||||
sc_display_apply_pending(struct sc_display *display) {
|
||||
if (display->pending.flags & SC_DISPLAY_PENDING_FLAG_SIZE) {
|
||||
@@ -202,8 +196,7 @@ sc_display_apply_pending(struct sc_display *display) {
|
||||
|
||||
if (display->pending.flags & SC_DISPLAY_PENDING_FLAG_FRAME) {
|
||||
assert(display->pending.frame);
|
||||
bool ok = sc_display_update_texture_internal(display,
|
||||
display->pending.frame);
|
||||
bool ok = sc_display_update_texture(display, display->pending.frame);
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -411,26 +411,6 @@ static void test_serialize_open_hard_keyboard(void) {
|
||||
assert(!memcmp(buf, expected, sizeof(expected)));
|
||||
}
|
||||
|
||||
static void test_serialize_start_app(void) {
|
||||
struct sc_control_msg msg = {
|
||||
.type = SC_CONTROL_MSG_TYPE_START_APP,
|
||||
.start_app = {
|
||||
.name = "firefox",
|
||||
},
|
||||
};
|
||||
|
||||
uint8_t buf[SC_CONTROL_MSG_MAX_SIZE];
|
||||
size_t size = sc_control_msg_serialize(&msg, buf);
|
||||
assert(size == 9);
|
||||
|
||||
const uint8_t expected[] = {
|
||||
SC_CONTROL_MSG_TYPE_START_APP,
|
||||
7, // length
|
||||
'f', 'i', 'r', 'e', 'f', 'o', 'x', // app name
|
||||
};
|
||||
assert(!memcmp(buf, expected, sizeof(expected)));
|
||||
}
|
||||
|
||||
static void test_serialize_reset_video(void) {
|
||||
struct sc_control_msg msg = {
|
||||
.type = SC_CONTROL_MSG_TYPE_RESET_VIDEO,
|
||||
@@ -468,7 +448,6 @@ int main(int argc, char *argv[]) {
|
||||
test_serialize_uhid_input();
|
||||
test_serialize_uhid_destroy();
|
||||
test_serialize_open_hard_keyboard();
|
||||
test_serialize_start_app();
|
||||
test_serialize_reset_video();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ buildscript {
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:8.13.0'
|
||||
classpath 'com.android.tools.build:gradle:8.7.1'
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
|
||||
11
doc/build.md
11
doc/build.md
@@ -172,7 +172,8 @@ Additionally, if you want to build the server, install Java 17 from Caskroom, an
|
||||
make it available from the `PATH`:
|
||||
|
||||
```bash
|
||||
brew install openjdk@17
|
||||
brew tap homebrew/cask-versions
|
||||
brew install adoptopenjdk/openjdk/adoptopenjdk17
|
||||
export JAVA_HOME="$(/usr/libexec/java_home --version 1.17)"
|
||||
export PATH="$JAVA_HOME/bin:$PATH"
|
||||
```
|
||||
@@ -232,10 +233,10 @@ install` must be run as root)._
|
||||
|
||||
#### Option 2: Use prebuilt server
|
||||
|
||||
- [`scrcpy-server-v3.3.4`][direct-scrcpy-server]
|
||||
<sub>SHA-256: `8588238c9a5a00aa542906b6ec7e6d5541d9ffb9b5d0f6e1bc0e365e2303079e`</sub>
|
||||
- [`scrcpy-server-v3.3.1`][direct-scrcpy-server]
|
||||
<sub>SHA-256: `a0f70b20aa4998fbf658c94118cd6c8dab6abbb0647a3bdab344d70bc1ebcbb8`</sub>
|
||||
|
||||
[direct-scrcpy-server]: https://github.com/Genymobile/scrcpy/releases/download/v3.3.4/scrcpy-server-v3.3.4
|
||||
[direct-scrcpy-server]: https://github.com/Genymobile/scrcpy/releases/download/v3.3.1/scrcpy-server-v3.3.1
|
||||
|
||||
Download the prebuilt server somewhere, and specify its path during the Meson
|
||||
configuration:
|
||||
@@ -270,7 +271,7 @@ This installs several files:
|
||||
- `/usr/local/bin/scrcpy` (main app)
|
||||
- `/usr/local/share/scrcpy/scrcpy-server` (server to push to the device)
|
||||
- `/usr/local/share/man/man1/scrcpy.1` (manpage)
|
||||
- `/usr/local/share/icons/hicolor/256x256/apps/scrcpy.png` (app icon)
|
||||
- `/usr/local/share/icons/hicolor/256x256/apps/icon.png` (app icon)
|
||||
- `/usr/local/share/zsh/site-functions/_scrcpy` (zsh completion)
|
||||
- `/usr/local/share/bash-completion/completions/scrcpy` (bash completion)
|
||||
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
|
||||
Download a static build of the [latest release]:
|
||||
|
||||
- [`scrcpy-linux-x86_64-v3.3.4.tar.gz`][direct-linux-x86_64] (x86_64)
|
||||
<sub>SHA-256: `0305d98c06178c67e12427bbf340c436d0d58c9e2a39bf9ffbbf8f54d7ef95a5`</sub>
|
||||
- [`scrcpy-linux-x86_64-v3.3.1.tar.gz`][direct-linux-x86_64] (x86_64)
|
||||
<sub>SHA-256: `bbfe54c6b178adafeaffbbfbbc1548a74486553170c63e63bdd41863ad123422`</sub>
|
||||
|
||||
[latest release]: https://github.com/Genymobile/scrcpy/releases/latest
|
||||
[direct-linux-x86_64]: https://github.com/Genymobile/scrcpy/releases/download/v3.3.4/scrcpy-linux-x86_64-v3.3.4.tar.gz
|
||||
[direct-linux-x86_64]: https://github.com/Genymobile/scrcpy/releases/download/v3.3.1/scrcpy-linux-x86_64-v3.3.1.tar.gz
|
||||
|
||||
and extract it.
|
||||
|
||||
|
||||
13
doc/macos.md
13
doc/macos.md
@@ -6,14 +6,15 @@
|
||||
|
||||
Download a static build of the [latest release]:
|
||||
|
||||
- [`scrcpy-macos-aarch64-v3.3.4.tar.gz`][direct-macos-aarch64] (aarch64)
|
||||
<sub>SHA-256: `8fef43520405dd523c74e1530ac68febcc5a405ea89712c874936675da8513dd`</sub>
|
||||
- [`scrcpy-macos-x86_64-v3.3.4.tar.gz`][direct-macos-x86_64] (x86_64)
|
||||
<sub>SHA-256: `cf9b3453a33279b6009dfb256b1a84c374bd4c30a71edd74bacab28d72a5d929`</sub>
|
||||
- [`scrcpy-macos-aarch64-v3.3.1.tar.gz`][direct-macos-aarch64] (aarch64)
|
||||
<sub>SHA-256: `907b925900ebd8499c1e47acc9689a95bd3a6f9930eb1d7bdfbca8375ae4f139`</sub>
|
||||
|
||||
- [`scrcpy-macos-x86_64-v3.3.1.tar.gz`][direct-macos-x86_64] (x86_64)
|
||||
<sub>SHA-256: `69772491dad718eea82fc65c8e89febff7d41c4ce6faff02f4789a588d10fd7d`</sub>
|
||||
|
||||
[latest release]: https://github.com/Genymobile/scrcpy/releases/latest
|
||||
[direct-macos-aarch64]: https://github.com/Genymobile/scrcpy/releases/download/v3.3.4/scrcpy-macos-aarch64-v3.3.4.tar.gz
|
||||
[direct-macos-x86_64]: https://github.com/Genymobile/scrcpy/releases/download/v3.3.4/scrcpy-macos-x86_64-v3.3.4.tar.gz
|
||||
[direct-macos-aarch64]: https://github.com/Genymobile/scrcpy/releases/download/v3.3.1/scrcpy-macos-aarch64-v3.3.1.tar.gz
|
||||
[direct-macos-x86_64]: https://github.com/Genymobile/scrcpy/releases/download/v3.3.1/scrcpy-macos-x86_64-v3.3.1.tar.gz
|
||||
|
||||
and extract it.
|
||||
|
||||
|
||||
@@ -6,14 +6,14 @@
|
||||
|
||||
Download the [latest release]:
|
||||
|
||||
- [`scrcpy-win64-v3.3.4.zip`][direct-win64] (64-bit)
|
||||
<sub>SHA-256: `d8a155b7c180b7ca4cdadd40712b8750b63f3aab48cb5b8a2a39ac2d0d4c5d38`</sub>
|
||||
- [`scrcpy-win32-v3.3.4.zip`][direct-win32] (32-bit)
|
||||
<sub>SHA-256: `393f7d5379dabd8aacc41184755c3d0df975cd2861353cb7a8d50e0835e2eb72`</sub>
|
||||
- [`scrcpy-win64-v3.3.1.zip`][direct-win64] (64-bit)
|
||||
<sub>SHA-256: `4fcad494772a3ae5de9a133149f8856d2fc429b41795f7cf7c754e0c1bb6fbc0`</sub>
|
||||
- [`scrcpy-win32-v3.3.1.zip`][direct-win32] (32-bit)
|
||||
<sub>SHA-256: `ccdf1b4f5d19dfe760446a107e55b0a010a00e097d46533a161499c9333a20a6`</sub>
|
||||
|
||||
[latest release]: https://github.com/Genymobile/scrcpy/releases/latest
|
||||
[direct-win64]: https://github.com/Genymobile/scrcpy/releases/download/v3.3.4/scrcpy-win64-v3.3.4.zip
|
||||
[direct-win32]: https://github.com/Genymobile/scrcpy/releases/download/v3.3.4/scrcpy-win32-v3.3.4.zip
|
||||
[direct-win64]: https://github.com/Genymobile/scrcpy/releases/download/v3.3.1/scrcpy-win64-v3.3.1.zip
|
||||
[direct-win32]: https://github.com/Genymobile/scrcpy/releases/download/v3.3.1/scrcpy-win32-v3.3.1.zip
|
||||
|
||||
and extract it.
|
||||
|
||||
|
||||
4
gradle/wrapper/gradle-wrapper.properties
vendored
4
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,7 +1,7 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
|
||||
# https://gradle.org/release-checksums/
|
||||
distributionSha256Sum=bd71102213493060956ec229d946beee57158dbd89d0e62b91bca0fa2c5f3531
|
||||
distributionSha256Sum=d725d707bfabd4dfdc958c624003b3c80accc03f7037b5122c4b1d0ef15cecab
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
set -e
|
||||
|
||||
BUILDDIR=build-auto
|
||||
PREBUILT_SERVER_URL=https://github.com/Genymobile/scrcpy/releases/download/v3.3.4/scrcpy-server-v3.3.4
|
||||
PREBUILT_SERVER_SHA256=8588238c9a5a00aa542906b6ec7e6d5541d9ffb9b5d0f6e1bc0e365e2303079e
|
||||
PREBUILT_SERVER_URL=https://github.com/Genymobile/scrcpy/releases/download/v3.3.1/scrcpy-server-v3.3.1
|
||||
PREBUILT_SERVER_SHA256=a0f70b20aa4998fbf658c94118cd6c8dab6abbb0647a3bdab344d70bc1ebcbb8
|
||||
|
||||
echo "[scrcpy] Downloading prebuilt server..."
|
||||
wget "$PREBUILT_SERVER_URL" -O scrcpy-server
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
project('scrcpy', 'c',
|
||||
version: '3.3.4',
|
||||
version: '3.3.2',
|
||||
meson_version: '>= 0.49',
|
||||
default_options: [
|
||||
'c_std=c11',
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
apply plugin: 'com.android.application'
|
||||
|
||||
android {
|
||||
namespace = 'com.genymobile.scrcpy'
|
||||
compileSdk 36
|
||||
namespace 'com.genymobile.scrcpy'
|
||||
compileSdk 35
|
||||
defaultConfig {
|
||||
applicationId = "com.genymobile.scrcpy"
|
||||
applicationId "com.genymobile.scrcpy"
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 36
|
||||
versionCode 30304
|
||||
versionName "3.3.4"
|
||||
testInstrumentationRunner = "android.support.test.runner.AndroidJUnitRunner"
|
||||
targetSdkVersion 35
|
||||
versionCode 30302
|
||||
versionName "3.3.2"
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
@@ -18,11 +18,8 @@ android {
|
||||
}
|
||||
}
|
||||
buildFeatures {
|
||||
buildConfig = true
|
||||
aidl = true
|
||||
}
|
||||
lint {
|
||||
disable 'UseRequiresApi'
|
||||
buildConfig true
|
||||
aidl true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,10 +12,10 @@
|
||||
set -e
|
||||
|
||||
SCRCPY_DEBUG=false
|
||||
SCRCPY_VERSION_NAME=3.3.4
|
||||
SCRCPY_VERSION_NAME=3.3.2
|
||||
|
||||
PLATFORM=${ANDROID_PLATFORM:-36}
|
||||
BUILD_TOOLS=${ANDROID_BUILD_TOOLS:-36.0.0}
|
||||
PLATFORM=${ANDROID_PLATFORM:-35}
|
||||
BUILD_TOOLS=${ANDROID_BUILD_TOOLS:-35.0.0}
|
||||
PLATFORM_TOOLS="$ANDROID_HOME/platforms/android-$PLATFORM"
|
||||
BUILD_TOOLS_DIR="$ANDROID_HOME/build-tools/$BUILD_TOOLS"
|
||||
|
||||
@@ -86,7 +86,7 @@ javac -encoding UTF-8 -bootclasspath "$ANDROID_JAR" \
|
||||
echo "Dexing..."
|
||||
cd "$CLASSES_DIR"
|
||||
|
||||
if [[ "${PLATFORM%%.*}" -lt 31 ]]
|
||||
if [[ $PLATFORM -lt 31 ]]
|
||||
then
|
||||
# use dx
|
||||
"$BUILD_TOOLS_DIR/dx" --dex --output "$BUILD_DIR/classes.dex" \
|
||||
|
||||
@@ -48,4 +48,27 @@ oneway interface IDisplayWindowListener {
|
||||
* Called when a display is removed from the hierarchy.
|
||||
*/
|
||||
void onDisplayRemoved(int displayId);
|
||||
|
||||
/**
|
||||
* Called when fixed rotation is started on a display.
|
||||
*/
|
||||
void onFixedRotationStarted(int displayId, int newRotation);
|
||||
|
||||
/**
|
||||
* Called when the previous fixed rotation on a display is finished.
|
||||
*/
|
||||
void onFixedRotationFinished(int displayId);
|
||||
|
||||
/**
|
||||
* Called when the keep clear ares on a display have changed.
|
||||
*/
|
||||
void onKeepClearAreasChanged(int displayId, in List<Rect> restricted, in List<Rect> unrestricted);
|
||||
|
||||
/**
|
||||
* Called when the eligibility of the desktop mode for a display have changed.
|
||||
*/
|
||||
void onDesktopModeEligibleChanged(int displayId);
|
||||
|
||||
void onDisplayAddSystemDecorations(int displayId);
|
||||
void onDisplayRemoveSystemDecorations(int displayId);
|
||||
}
|
||||
|
||||
@@ -196,7 +196,6 @@ public final class CleanUp {
|
||||
|
||||
// Needed for workarounds
|
||||
prepareMainLooper();
|
||||
Workarounds.apply();
|
||||
|
||||
int displayId = Integer.parseInt(args[0]);
|
||||
int restoreStayOn = Integer.parseInt(args[1]);
|
||||
|
||||
@@ -109,10 +109,8 @@ public final class FakeContext extends ContextWrapper {
|
||||
}
|
||||
|
||||
// "semclipboard" is a Samsung-internal service
|
||||
// See:
|
||||
// - <https://github.com/Genymobile/scrcpy/issues/6224>
|
||||
// - <https://github.com/Genymobile/scrcpy/issues/6523>
|
||||
if (Context.CLIPBOARD_SERVICE.equals(name) || "semclipboard".equals(name) || Context.ACTIVITY_SERVICE.equals(name)) {
|
||||
// See <https://github.com/Genymobile/scrcpy/issues/6224>
|
||||
if (Context.CLIPBOARD_SERVICE.equals(name) || "semclipboard".equals(name)) {
|
||||
try {
|
||||
Field field = service.getClass().getDeclaredField("mContext");
|
||||
field.setAccessible(true);
|
||||
|
||||
@@ -225,12 +225,8 @@ public final class Server {
|
||||
}
|
||||
|
||||
private static void internalMain(String... args) throws Exception {
|
||||
Thread.UncaughtExceptionHandler defaultHandler = Thread.getDefaultUncaughtExceptionHandler();
|
||||
Thread.setDefaultUncaughtExceptionHandler((t, e) -> {
|
||||
Ln.e("Exception on thread " + t, e);
|
||||
if (defaultHandler != null) {
|
||||
defaultHandler.uncaughtException(t, e);
|
||||
}
|
||||
});
|
||||
|
||||
prepareMainLooper();
|
||||
|
||||
@@ -6,9 +6,9 @@ import com.genymobile.scrcpy.util.Ln;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.Application;
|
||||
import android.app.Instrumentation;
|
||||
import android.content.AttributionSource;
|
||||
import android.content.Context;
|
||||
import android.content.ContextWrapper;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.media.AudioAttributes;
|
||||
import android.media.AudioManager;
|
||||
@@ -103,7 +103,10 @@ public final class Workarounds {
|
||||
|
||||
private static void fillAppContext() {
|
||||
try {
|
||||
Application app = Instrumentation.newApplication(Application.class, FakeContext.get());
|
||||
Application app = new Application();
|
||||
Field baseField = ContextWrapper.class.getDeclaredField("mBase");
|
||||
baseField.setAccessible(true);
|
||||
baseField.set(app, FakeContext.get());
|
||||
|
||||
// activityThread.mInitialApplication = app;
|
||||
Field mInitialApplicationField = ACTIVITY_THREAD_CLASS.getDeclaredField("mInitialApplication");
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.genymobile.scrcpy.opengl;
|
||||
|
||||
import com.genymobile.scrcpy.device.Size;
|
||||
import com.genymobile.scrcpy.util.Threads;
|
||||
|
||||
import android.graphics.SurfaceTexture;
|
||||
import android.opengl.EGL14;
|
||||
@@ -16,7 +15,6 @@ import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.view.Surface;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.Semaphore;
|
||||
|
||||
public final class OpenGLRunner {
|
||||
@@ -82,17 +80,31 @@ public final class OpenGLRunner {
|
||||
public Surface start(Size inputSize, Size outputSize, Surface outputSurface) throws OpenGLException {
|
||||
initOnce();
|
||||
|
||||
// Simulate CompletableFuture, but working for all Android versions
|
||||
final Semaphore sem = new Semaphore(0);
|
||||
Throwable[] throwableRef = new Throwable[1];
|
||||
|
||||
// The whole OpenGL execution must be performed on a Handler, so that SurfaceTexture.setOnFrameAvailableListener() works correctly.
|
||||
// See <https://github.com/Genymobile/scrcpy/issues/5444>
|
||||
handler.post(() -> {
|
||||
try {
|
||||
run(inputSize, outputSize, outputSurface);
|
||||
} catch (Throwable throwable) {
|
||||
throwableRef[0] = throwable;
|
||||
} finally {
|
||||
sem.release();
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
Threads.executeSynchronouslyOn(handler, new Callable<Void>() {
|
||||
@Override
|
||||
public Void call() throws Exception {
|
||||
run(inputSize, outputSize, outputSurface);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
} catch (Throwable throwable) {
|
||||
sem.acquire();
|
||||
} catch (InterruptedException e) {
|
||||
// Behave as if this method call was synchronous
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
|
||||
Throwable throwable = throwableRef[0];
|
||||
if (throwable != null) {
|
||||
if (throwable instanceof OpenGLException) {
|
||||
throw (OpenGLException) throwable;
|
||||
}
|
||||
|
||||
@@ -74,11 +74,9 @@ public final class Ln {
|
||||
public static void w(String message, Throwable throwable) {
|
||||
if (isEnabled(Level.WARN)) {
|
||||
Log.w(TAG, message, throwable);
|
||||
synchronized (CONSOLE_ERR) {
|
||||
CONSOLE_ERR.print(PREFIX + "WARN: " + message + '\n');
|
||||
if (throwable != null) {
|
||||
throwable.printStackTrace(CONSOLE_ERR);
|
||||
}
|
||||
CONSOLE_ERR.print(PREFIX + "WARN: " + message + '\n');
|
||||
if (throwable != null) {
|
||||
throwable.printStackTrace(CONSOLE_ERR);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -90,11 +88,9 @@ public final class Ln {
|
||||
public static void e(String message, Throwable throwable) {
|
||||
if (isEnabled(Level.ERROR)) {
|
||||
Log.e(TAG, message, throwable);
|
||||
synchronized (CONSOLE_ERR) {
|
||||
CONSOLE_ERR.print(PREFIX + "ERROR: " + message + '\n');
|
||||
if (throwable != null) {
|
||||
throwable.printStackTrace(CONSOLE_ERR);
|
||||
}
|
||||
CONSOLE_ERR.print(PREFIX + "ERROR: " + message + '\n');
|
||||
if (throwable != null) {
|
||||
throwable.printStackTrace(CONSOLE_ERR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
package com.genymobile.scrcpy.util;
|
||||
|
||||
import android.os.Handler;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.Semaphore;
|
||||
|
||||
public final class Threads {
|
||||
private Threads() {
|
||||
// not instantiable
|
||||
}
|
||||
|
||||
public static <T> T executeSynchronouslyOn(Handler handler, Callable<T> callable) throws Throwable {
|
||||
// Simulate CompletableFuture, but working for all Android versions
|
||||
final Semaphore sem = new Semaphore(0);
|
||||
@SuppressWarnings("unchecked")
|
||||
T[] resultRef = (T[]) new Object[1];
|
||||
Throwable[] throwableRef = new Throwable[1];
|
||||
|
||||
handler.post(() -> {
|
||||
try {
|
||||
resultRef[0] = callable.call();
|
||||
} catch (Throwable throwable) {
|
||||
throwableRef[0] = throwable;
|
||||
} finally {
|
||||
sem.release();
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
sem.acquire();
|
||||
} catch (InterruptedException e) {
|
||||
// Behave as if this method call was synchronous
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
|
||||
if (throwableRef[0] != null) {
|
||||
throw throwableRef[0];
|
||||
}
|
||||
|
||||
return resultRef[0];
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,6 @@ public class NewDisplayCapture extends SurfaceCapture {
|
||||
|
||||
// Internal fields copied from android.hardware.display.DisplayManager
|
||||
private static final int VIRTUAL_DISPLAY_FLAG_PUBLIC = android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC;
|
||||
private static final int VIRTUAL_DISPLAY_FLAG_PRESENTATION = android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION;
|
||||
private static final int VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY = android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY;
|
||||
private static final int VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH = 1 << 6;
|
||||
private static final int VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT = 1 << 7;
|
||||
@@ -170,7 +169,6 @@ public class NewDisplayCapture extends SurfaceCapture {
|
||||
int virtualDisplayId;
|
||||
try {
|
||||
int flags = VIRTUAL_DISPLAY_FLAG_PUBLIC
|
||||
| VIRTUAL_DISPLAY_FLAG_PRESENTATION
|
||||
| VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY
|
||||
| VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH
|
||||
| VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT;
|
||||
|
||||
@@ -139,13 +139,7 @@ public final class DisplayManager {
|
||||
int layerStack = cls.getDeclaredField("layerStack").getInt(displayInfo);
|
||||
int flags = cls.getDeclaredField("flags").getInt(displayInfo);
|
||||
int dpi = cls.getDeclaredField("logicalDensityDpi").getInt(displayInfo);
|
||||
String uniqueId;
|
||||
try {
|
||||
uniqueId = (String) cls.getDeclaredField("uniqueId").get(displayInfo);
|
||||
} catch (NoSuchFieldException e) {
|
||||
// This field might not exist: <https://github.com/Genymobile/scrcpy/issues/6461>
|
||||
uniqueId = null;
|
||||
}
|
||||
String uniqueId = (String) cls.getDeclaredField("uniqueId").get(displayInfo);
|
||||
return new DisplayInfo(displayId, new Size(width, height), rotation, layerStack, flags, dpi, uniqueId);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new AssertionError(e);
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
package com.genymobile.scrcpy.wrappers;
|
||||
|
||||
import com.genymobile.scrcpy.util.Ln;
|
||||
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Parcel;
|
||||
import android.os.RemoteException;
|
||||
import android.graphics.Rect;
|
||||
import android.view.IDisplayWindowListener;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class DisplayWindowListener extends IDisplayWindowListener.Stub {
|
||||
@Override
|
||||
public void onDisplayAdded(int displayId) {
|
||||
@@ -24,14 +23,32 @@ public class DisplayWindowListener extends IDisplayWindowListener.Stub {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
|
||||
try {
|
||||
return super.onTransact(code, data, reply, flags);
|
||||
} catch (AbstractMethodError e) {
|
||||
Ln.v("Ignoring AbstractMethodError: " + e.getMessage());
|
||||
// Ignore unknown methods, write default response to reply parcel
|
||||
reply.writeNoException();
|
||||
return true;
|
||||
}
|
||||
public void onFixedRotationStarted(int displayId, int newRotation) {
|
||||
// empty default implementation
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFixedRotationFinished(int displayId) {
|
||||
// empty default implementation
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onKeepClearAreasChanged(int displayId, List<Rect> restricted, List<Rect> unrestricted) {
|
||||
// empty default implementation
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDesktopModeEligibleChanged(int displayId) {
|
||||
// empty default implementation
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisplayAddSystemDecorations(int displayId) {
|
||||
// empty default implementation
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisplayRemoveSystemDecorations(int displayId) {
|
||||
// empty default implementation
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user