mirror of
https://github.com/Genymobile/scrcpy.git
synced 2026-04-21 01:33:36 +00:00
Compare commits
32 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4671927c34 | ||
|
|
cbc5917050 | ||
|
|
db013aa7a7 | ||
|
|
0abee2d01e | ||
|
|
158cae3237 | ||
|
|
247a37d57b | ||
|
|
3fcc177da5 | ||
|
|
c8c1316db9 | ||
|
|
db2f72a58a | ||
|
|
fb6381f5b9 | ||
|
|
06fd3b4786 | ||
|
|
1d1a4103cc | ||
|
|
5b51396a8c | ||
|
|
7e66062086 | ||
|
|
6f9eb31d52 | ||
|
|
9cfa5b197a | ||
|
|
b08093d1c0 | ||
|
|
7dd9bcaf60 | ||
|
|
3530851071 | ||
|
|
d0047b2110 | ||
|
|
3281fda6ef | ||
|
|
925949d54a | ||
|
|
f3d4fde15b | ||
|
|
eee3f24739 | ||
|
|
3e40b24737 | ||
|
|
9d7a4c88e0 | ||
|
|
e5e58b1b30 | ||
|
|
10a0974f43 | ||
|
|
be21e43be5 | ||
|
|
bfb0872493 | ||
|
|
e11399aff0 | ||
|
|
9d56d26d45 |
40 changed files with 240 additions and 192 deletions
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/
|
path: release/work/build-macos-aarch64/dist-tar/
|
||||||
|
|
||||||
build-macos-x86_64:
|
build-macos-x86_64:
|
||||||
runs-on: macos-13
|
runs-on: macos-15-intel
|
||||||
steps:
|
steps:
|
||||||
- name: Check architecture
|
- name: Check architecture
|
||||||
run: |
|
run: |
|
||||||
|
|
|
||||||
5
FAQ.md
5
FAQ.md
|
|
@ -141,12 +141,13 @@ On Windows, if `scrcpy --otg` (or `--keyboard=aoa`/`--mouse=aoa`) results in:
|
||||||
|
|
||||||
(or if only unrelated USB devices are detected), there might be drivers issues.
|
(or if only unrelated USB devices are detected), there might be drivers issues.
|
||||||
|
|
||||||
Please read [#3654], in particular [this comment][#3654-comment1] and [the next
|
Please read [#3654], in particular [this comment][#3654-comment1], [the next
|
||||||
one][#3654-comment2].
|
one][#3654-comment2] and [this one][#3654-comment3].
|
||||||
|
|
||||||
[#3654]: https://github.com/Genymobile/scrcpy/issues/3654
|
[#3654]: https://github.com/Genymobile/scrcpy/issues/3654
|
||||||
[#3654-comment1]: https://github.com/Genymobile/scrcpy/issues/3654#issuecomment-1369278232
|
[#3654-comment1]: https://github.com/Genymobile/scrcpy/issues/3654#issuecomment-1369278232
|
||||||
[#3654-comment2]: https://github.com/Genymobile/scrcpy/issues/3654#issuecomment-1369295011
|
[#3654-comment2]: https://github.com/Genymobile/scrcpy/issues/3654#issuecomment-1369295011
|
||||||
|
[#3654-comment3]: https://github.com/Genymobile/scrcpy/issues/3654#issuecomment-2613219725
|
||||||
|
|
||||||
|
|
||||||
## Control issues
|
## Control issues
|
||||||
|
|
|
||||||
2
LICENSE
2
LICENSE
|
|
@ -188,7 +188,7 @@
|
||||||
identification within third-party archives.
|
identification within third-party archives.
|
||||||
|
|
||||||
Copyright (C) 2018 Genymobile
|
Copyright (C) 2018 Genymobile
|
||||||
Copyright (C) 2018-2025 Romain Vimont
|
Copyright (C) 2018-2026 Romain Vimont
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with 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
|
source for the project. Do not download releases from random websites, even if
|
||||||
their name contains `scrcpy`.**
|
their name contains `scrcpy`.**
|
||||||
|
|
||||||
# scrcpy (v3.3.2)
|
# scrcpy (v3.3.4)
|
||||||
|
|
||||||
<img src="app/data/icon.svg" width="128" height="128" alt="scrcpy" align="right" />
|
<img src="app/data/icon.svg" width="128" height="128" alt="scrcpy" align="right" />
|
||||||
|
|
||||||
|
|
@ -210,7 +210,7 @@ work][donate]:
|
||||||
## License
|
## License
|
||||||
|
|
||||||
Copyright (C) 2018 Genymobile
|
Copyright (C) 2018 Genymobile
|
||||||
Copyright (C) 2018-2025 Romain Vimont
|
Copyright (C) 2018-2026 Romain Vimont
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,9 @@
|
||||||
#!/usr/bin/env bash
|
|
||||||
# This file is intended to be sourced by other scripts, not executed
|
# This file is intended to be sourced by other scripts, not executed
|
||||||
|
|
||||||
process_args() {
|
process_args() {
|
||||||
if [[ $# != 3 ]]
|
if [[ $# != 3 ]]
|
||||||
then
|
then
|
||||||
# <host>: win32 or win64
|
# <host>: linux, macos, win32 or win64
|
||||||
# <build_type>: native or cross
|
# <build_type>: native or cross
|
||||||
# <link_type>: static or shared
|
# <link_type>: static or shared
|
||||||
echo "Syntax: $0 <host> <build_type> <link_type>" >&2
|
echo "Syntax: $0 <host> <build_type> <link_type>" >&2
|
||||||
|
|
@ -12,8 +11,8 @@ process_args() {
|
||||||
fi
|
fi
|
||||||
|
|
||||||
HOST="$1"
|
HOST="$1"
|
||||||
BUILD_TYPE="$2" # native or cross
|
BUILD_TYPE="$2"
|
||||||
LINK_TYPE="$3" # static or shared
|
LINK_TYPE="$3"
|
||||||
DIRNAME="$HOST-$BUILD_TYPE-$LINK_TYPE"
|
DIRNAME="$HOST-$BUILD_TYPE-$LINK_TYPE"
|
||||||
|
|
||||||
if [[ "$BUILD_TYPE" != native && "$BUILD_TYPE" != cross ]]
|
if [[ "$BUILD_TYPE" != native && "$BUILD_TYPE" != cross ]]
|
||||||
|
|
@ -1,21 +1,21 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -ex
|
set -ex
|
||||||
DEPS_DIR=$(dirname ${BASH_SOURCE[0]})
|
. $(dirname ${BASH_SOURCE[0]})/_init "$@"
|
||||||
cd "$DEPS_DIR"
|
|
||||||
. common
|
|
||||||
|
|
||||||
VERSION=36.0.0
|
VERSION=36.0.0
|
||||||
FILENAME=platform-tools_r$VERSION-linux.zip
|
URL="https://dl.google.com/android/repository/platform-tools_r$VERSION-linux.zip"
|
||||||
PROJECT_DIR=platform-tools-$VERSION-linux
|
|
||||||
SHA256SUM=0ead642c943ffe79701fccca8f5f1c69c4ce4f43df2eefee553f6ccb27cbfbe8
|
SHA256SUM=0ead642c943ffe79701fccca8f5f1c69c4ce4f43df2eefee553f6ccb27cbfbe8
|
||||||
|
|
||||||
|
PROJECT_DIR="platform-tools-$VERSION-linux"
|
||||||
|
FILENAME="$PROJECT_DIR.zip"
|
||||||
|
|
||||||
cd "$SOURCES_DIR"
|
cd "$SOURCES_DIR"
|
||||||
|
|
||||||
if [[ -d "$PROJECT_DIR" ]]
|
if [[ -d "$PROJECT_DIR" ]]
|
||||||
then
|
then
|
||||||
echo "$PWD/$PROJECT_DIR" found
|
echo "$PWD/$PROJECT_DIR" found
|
||||||
else
|
else
|
||||||
get_file "https://dl.google.com/android/repository/$FILENAME" "$FILENAME" "$SHA256SUM"
|
get_file "$URL" "$FILENAME" "$SHA256SUM"
|
||||||
mkdir -p "$PROJECT_DIR"
|
mkdir -p "$PROJECT_DIR"
|
||||||
cd "$PROJECT_DIR"
|
cd "$PROJECT_DIR"
|
||||||
ZIP_PREFIX=platform-tools
|
ZIP_PREFIX=platform-tools
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,21 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -ex
|
set -ex
|
||||||
DEPS_DIR=$(dirname ${BASH_SOURCE[0]})
|
. $(dirname ${BASH_SOURCE[0]})/_init "$@"
|
||||||
cd "$DEPS_DIR"
|
|
||||||
. common
|
|
||||||
|
|
||||||
VERSION=36.0.0
|
VERSION=36.0.0
|
||||||
FILENAME=platform-tools_r$VERSION-darwin.zip
|
URL="https://dl.google.com/android/repository/platform-tools_r$VERSION-darwin.zip"
|
||||||
PROJECT_DIR=platform-tools-$VERSION-darwin
|
|
||||||
SHA256SUM=d3e9fa1df3345cf728586908426615a60863d2632f73f1ce14f0f1349ef000fd
|
SHA256SUM=d3e9fa1df3345cf728586908426615a60863d2632f73f1ce14f0f1349ef000fd
|
||||||
|
|
||||||
|
PROJECT_DIR="platform-tools-$VERSION-darwin"
|
||||||
|
FILENAME="$PROJECT_DIR.zip"
|
||||||
|
|
||||||
cd "$SOURCES_DIR"
|
cd "$SOURCES_DIR"
|
||||||
|
|
||||||
if [[ -d "$PROJECT_DIR" ]]
|
if [[ -d "$PROJECT_DIR" ]]
|
||||||
then
|
then
|
||||||
echo "$PWD/$PROJECT_DIR" found
|
echo "$PWD/$PROJECT_DIR" found
|
||||||
else
|
else
|
||||||
get_file "https://dl.google.com/android/repository/$FILENAME" "$FILENAME" "$SHA256SUM"
|
get_file "$URL" "$FILENAME" "$SHA256SUM"
|
||||||
mkdir -p "$PROJECT_DIR"
|
mkdir -p "$PROJECT_DIR"
|
||||||
cd "$PROJECT_DIR"
|
cd "$PROJECT_DIR"
|
||||||
ZIP_PREFIX=platform-tools
|
ZIP_PREFIX=platform-tools
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,21 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -ex
|
set -ex
|
||||||
DEPS_DIR=$(dirname ${BASH_SOURCE[0]})
|
. $(dirname ${BASH_SOURCE[0]})/_init "$@"
|
||||||
cd "$DEPS_DIR"
|
|
||||||
. common
|
|
||||||
|
|
||||||
VERSION=36.0.0
|
VERSION=36.0.0
|
||||||
FILENAME=platform-tools_r$VERSION-win.zip
|
URL="https://dl.google.com/android/repository/platform-tools_r$VERSION-win.zip"
|
||||||
PROJECT_DIR=platform-tools-$VERSION-windows
|
|
||||||
SHA256SUM=12c2841f354e92a0eb2fd7bf6f0f9bf8538abce7bd6b060ac8349d6f6a61107c
|
SHA256SUM=12c2841f354e92a0eb2fd7bf6f0f9bf8538abce7bd6b060ac8349d6f6a61107c
|
||||||
|
|
||||||
|
PROJECT_DIR="platform-tools-$VERSION-windows"
|
||||||
|
FILENAME="$PROJECT_DIR.zip"
|
||||||
|
|
||||||
cd "$SOURCES_DIR"
|
cd "$SOURCES_DIR"
|
||||||
|
|
||||||
if [[ -d "$PROJECT_DIR" ]]
|
if [[ -d "$PROJECT_DIR" ]]
|
||||||
then
|
then
|
||||||
echo "$PWD/$PROJECT_DIR" found
|
echo "$PWD/$PROJECT_DIR" found
|
||||||
else
|
else
|
||||||
get_file "https://dl.google.com/android/repository/$FILENAME" "$FILENAME" "$SHA256SUM"
|
get_file "$URL" "$FILENAME" "$SHA256SUM"
|
||||||
mkdir -p "$PROJECT_DIR"
|
mkdir -p "$PROJECT_DIR"
|
||||||
cd "$PROJECT_DIR"
|
cd "$PROJECT_DIR"
|
||||||
ZIP_PREFIX=platform-tools
|
ZIP_PREFIX=platform-tools
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,22 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -ex
|
set -ex
|
||||||
DEPS_DIR=$(dirname ${BASH_SOURCE[0]})
|
. $(dirname ${BASH_SOURCE[0]})/_init
|
||||||
cd "$DEPS_DIR"
|
|
||||||
. common
|
|
||||||
process_args "$@"
|
process_args "$@"
|
||||||
|
|
||||||
VERSION=1.5.0
|
VERSION=1.5.0
|
||||||
FILENAME=dav1d-$VERSION.tar.gz
|
URL="https://code.videolan.org/videolan/dav1d/-/archive/$VERSION/dav1d-$VERSION.tar.gz"
|
||||||
PROJECT_DIR=dav1d-$VERSION
|
|
||||||
SHA256SUM=78b15d9954b513ea92d27f39362535ded2243e1b0924fde39f37a31ebed5f76b
|
SHA256SUM=78b15d9954b513ea92d27f39362535ded2243e1b0924fde39f37a31ebed5f76b
|
||||||
|
|
||||||
|
PROJECT_DIR="dav1d-$VERSION"
|
||||||
|
FILENAME="$PROJECT_DIR.tar.gz"
|
||||||
|
|
||||||
cd "$SOURCES_DIR"
|
cd "$SOURCES_DIR"
|
||||||
|
|
||||||
if [[ -d "$PROJECT_DIR" ]]
|
if [[ -d "$PROJECT_DIR" ]]
|
||||||
then
|
then
|
||||||
echo "$PWD/$PROJECT_DIR" found
|
echo "$PWD/$PROJECT_DIR" found
|
||||||
else
|
else
|
||||||
get_file "https://code.videolan.org/videolan/dav1d/-/archive/$VERSION/$FILENAME" "$FILENAME" "$SHA256SUM"
|
get_file "$URL" "$FILENAME" "$SHA256SUM"
|
||||||
tar xf "$FILENAME" # First level directory is "$PROJECT_DIR"
|
tar xf "$FILENAME" # First level directory is "$PROJECT_DIR"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,22 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -ex
|
set -ex
|
||||||
DEPS_DIR=$(dirname ${BASH_SOURCE[0]})
|
. $(dirname ${BASH_SOURCE[0]})/_init
|
||||||
cd "$DEPS_DIR"
|
|
||||||
. common
|
|
||||||
process_args "$@"
|
process_args "$@"
|
||||||
|
|
||||||
VERSION=7.1.1
|
VERSION=7.1.1
|
||||||
FILENAME=ffmpeg-$VERSION.tar.xz
|
URL="https://ffmpeg.org/releases/ffmpeg-$VERSION.tar.xz"
|
||||||
PROJECT_DIR=ffmpeg-$VERSION
|
|
||||||
SHA256SUM=733984395e0dbbe5c046abda2dc49a5544e7e0e1e2366bba849222ae9e3a03b1
|
SHA256SUM=733984395e0dbbe5c046abda2dc49a5544e7e0e1e2366bba849222ae9e3a03b1
|
||||||
|
|
||||||
|
PROJECT_DIR="ffmpeg-$VERSION"
|
||||||
|
FILENAME="$PROJECT_DIR.tar.xz"
|
||||||
|
|
||||||
cd "$SOURCES_DIR"
|
cd "$SOURCES_DIR"
|
||||||
|
|
||||||
if [[ -d "$PROJECT_DIR" ]]
|
if [[ -d "$PROJECT_DIR" ]]
|
||||||
then
|
then
|
||||||
echo "$PWD/$PROJECT_DIR" found
|
echo "$PWD/$PROJECT_DIR" found
|
||||||
else
|
else
|
||||||
get_file "https://ffmpeg.org/releases/$FILENAME" "$FILENAME" "$SHA256SUM"
|
get_file "$URL" "$FILENAME" "$SHA256SUM"
|
||||||
tar xf "$FILENAME" # First level directory is "$PROJECT_DIR"
|
tar xf "$FILENAME" # First level directory is "$PROJECT_DIR"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,22 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -ex
|
set -ex
|
||||||
DEPS_DIR=$(dirname ${BASH_SOURCE[0]})
|
. $(dirname ${BASH_SOURCE[0]})/_init
|
||||||
cd "$DEPS_DIR"
|
|
||||||
. common
|
|
||||||
process_args "$@"
|
process_args "$@"
|
||||||
|
|
||||||
VERSION=1.0.29
|
VERSION=1.0.29
|
||||||
FILENAME=libusb-$VERSION.tar.gz
|
URL="https://github.com/libusb/libusb/archive/refs/tags/v$VERSION.tar.gz"
|
||||||
PROJECT_DIR=libusb-$VERSION
|
|
||||||
SHA256SUM=7c2dd39c0b2589236e48c93247c986ae272e27570942b4163cb00a060fcf1b74
|
SHA256SUM=7c2dd39c0b2589236e48c93247c986ae272e27570942b4163cb00a060fcf1b74
|
||||||
|
|
||||||
|
PROJECT_DIR="libusb-$VERSION"
|
||||||
|
FILENAME="$PROJECT_DIR.tar.gz"
|
||||||
|
|
||||||
cd "$SOURCES_DIR"
|
cd "$SOURCES_DIR"
|
||||||
|
|
||||||
if [[ -d "$PROJECT_DIR" ]]
|
if [[ -d "$PROJECT_DIR" ]]
|
||||||
then
|
then
|
||||||
echo "$PWD/$PROJECT_DIR" found
|
echo "$PWD/$PROJECT_DIR" found
|
||||||
else
|
else
|
||||||
get_file "https://github.com/libusb/libusb/archive/refs/tags/v$VERSION.tar.gz" "$FILENAME" "$SHA256SUM"
|
get_file "$URL" "$FILENAME" "$SHA256SUM"
|
||||||
tar xf "$FILENAME" # First level directory is "$PROJECT_DIR"
|
tar xf "$FILENAME" # First level directory is "$PROJECT_DIR"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,24 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -ex
|
set -ex
|
||||||
DEPS_DIR=$(dirname ${BASH_SOURCE[0]})
|
. $(dirname ${BASH_SOURCE[0]})/_init
|
||||||
cd "$DEPS_DIR"
|
|
||||||
. common
|
|
||||||
process_args "$@"
|
process_args "$@"
|
||||||
|
|
||||||
VERSION=2.32.8
|
VERSION=2.32.8
|
||||||
FILENAME=SDL-$VERSION.tar.gz
|
URL="https://github.com/libsdl-org/SDL/archive/refs/tags/release-$VERSION.tar.gz"
|
||||||
PROJECT_DIR=SDL-release-$VERSION
|
|
||||||
SHA256SUM=dd35e05644ae527848d02433bec24dd0ea65db59faecf1a0e5d1880c533dac2c
|
SHA256SUM=dd35e05644ae527848d02433bec24dd0ea65db59faecf1a0e5d1880c533dac2c
|
||||||
|
|
||||||
|
PROJECT_DIR="sdl-$VERSION"
|
||||||
|
FILENAME="$PROJECT_DIR.tar.gz"
|
||||||
|
|
||||||
cd "$SOURCES_DIR"
|
cd "$SOURCES_DIR"
|
||||||
|
|
||||||
if [[ -d "$PROJECT_DIR" ]]
|
if [[ -d "$PROJECT_DIR" ]]
|
||||||
then
|
then
|
||||||
echo "$PWD/$PROJECT_DIR" found
|
echo "$PWD/$PROJECT_DIR" found
|
||||||
else
|
else
|
||||||
get_file "https://github.com/libsdl-org/SDL/archive/refs/tags/release-$VERSION.tar.gz" "$FILENAME" "$SHA256SUM"
|
get_file "$URL" "$FILENAME" "$SHA256SUM"
|
||||||
tar xf "$FILENAME" # First level directory is "$PROJECT_DIR"
|
tar xf "$FILENAME" # First level directory is "SDL-release-$VERSION"
|
||||||
|
mv "SDL-release-$VERSION" "$PROJECT_DIR"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
mkdir -p "$BUILD_DIR/$PROJECT_DIR"
|
mkdir -p "$BUILD_DIR/$PROJECT_DIR"
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ BEGIN
|
||||||
VALUE "LegalCopyright", "Romain Vimont, Genymobile"
|
VALUE "LegalCopyright", "Romain Vimont, Genymobile"
|
||||||
VALUE "OriginalFilename", "scrcpy.exe"
|
VALUE "OriginalFilename", "scrcpy.exe"
|
||||||
VALUE "ProductName", "scrcpy"
|
VALUE "ProductName", "scrcpy"
|
||||||
VALUE "ProductVersion", "3.3.2"
|
VALUE "ProductVersion", "3.3.4"
|
||||||
END
|
END
|
||||||
END
|
END
|
||||||
BLOCK "VarFileInfo"
|
BLOCK "VarFileInfo"
|
||||||
|
|
|
||||||
|
|
@ -852,7 +852,7 @@ Report bugs to <https://github.com/Genymobile/scrcpy/issues>.
|
||||||
.SH COPYRIGHT
|
.SH COPYRIGHT
|
||||||
Copyright \(co 2018 Genymobile <https://www.genymobile.com>
|
Copyright \(co 2018 Genymobile <https://www.genymobile.com>
|
||||||
|
|
||||||
Copyright \(co 2018\-2025 Romain Vimont <rom@rom1v.com>
|
Copyright \(co 2018\-2026 Romain Vimont <rom@rom1v.com>
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0.
|
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]);
|
uint16_t id = sc_read16be(&buf[1]);
|
||||||
size_t size = sc_read16be(&buf[3]);
|
size_t size = sc_read16be(&buf[3]);
|
||||||
if (size < len - 5) {
|
if (size > len - 5) {
|
||||||
return 0; // not available
|
return 0; // not available
|
||||||
}
|
}
|
||||||
uint8_t *data = malloc(size);
|
uint8_t *data = malloc(size);
|
||||||
|
|
|
||||||
|
|
@ -170,6 +170,7 @@ 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);
|
int r = av_frame_ref(display->pending.frame, frame);
|
||||||
if (r) {
|
if (r) {
|
||||||
LOGE("Could not ref frame: %d", r);
|
LOGE("Could not ref frame: %d", r);
|
||||||
|
|
@ -181,6 +182,11 @@ sc_display_set_pending_frame(struct sc_display *display, const AVFrame *frame) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Forward declaration
|
||||||
|
static bool
|
||||||
|
sc_display_update_texture_internal(struct sc_display *display,
|
||||||
|
const AVFrame *frame);
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
sc_display_apply_pending(struct sc_display *display) {
|
sc_display_apply_pending(struct sc_display *display) {
|
||||||
if (display->pending.flags & SC_DISPLAY_PENDING_FLAG_SIZE) {
|
if (display->pending.flags & SC_DISPLAY_PENDING_FLAG_SIZE) {
|
||||||
|
|
@ -196,7 +202,8 @@ sc_display_apply_pending(struct sc_display *display) {
|
||||||
|
|
||||||
if (display->pending.flags & SC_DISPLAY_PENDING_FLAG_FRAME) {
|
if (display->pending.flags & SC_DISPLAY_PENDING_FLAG_FRAME) {
|
||||||
assert(display->pending.frame);
|
assert(display->pending.frame);
|
||||||
bool ok = sc_display_update_texture(display, display->pending.frame);
|
bool ok = sc_display_update_texture_internal(display,
|
||||||
|
display->pending.frame);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -411,6 +411,26 @@ static void test_serialize_open_hard_keyboard(void) {
|
||||||
assert(!memcmp(buf, expected, sizeof(expected)));
|
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) {
|
static void test_serialize_reset_video(void) {
|
||||||
struct sc_control_msg msg = {
|
struct sc_control_msg msg = {
|
||||||
.type = SC_CONTROL_MSG_TYPE_RESET_VIDEO,
|
.type = SC_CONTROL_MSG_TYPE_RESET_VIDEO,
|
||||||
|
|
@ -448,6 +468,7 @@ int main(int argc, char *argv[]) {
|
||||||
test_serialize_uhid_input();
|
test_serialize_uhid_input();
|
||||||
test_serialize_uhid_destroy();
|
test_serialize_uhid_destroy();
|
||||||
test_serialize_open_hard_keyboard();
|
test_serialize_open_hard_keyboard();
|
||||||
|
test_serialize_start_app();
|
||||||
test_serialize_reset_video();
|
test_serialize_reset_video();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ buildscript {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:8.7.1'
|
classpath 'com.android.tools.build:gradle:8.13.0'
|
||||||
|
|
||||||
// NOTE: Do not place your application dependencies here; they belong
|
// NOTE: Do not place your application dependencies here; they belong
|
||||||
// in the individual module build.gradle files
|
// in the individual module build.gradle files
|
||||||
|
|
|
||||||
17
doc/build.md
17
doc/build.md
|
|
@ -154,7 +154,11 @@ install it manually and make it available from the `PATH`:
|
||||||
export PATH="$JAVA_HOME/bin:$PATH"
|
export PATH="$JAVA_HOME/bin:$PATH"
|
||||||
```
|
```
|
||||||
|
|
||||||
### Mac OS
|
When following the rest of the build instructions below, make sure you use the
|
||||||
|
MinGW terminal within MSYS2.
|
||||||
|
|
||||||
|
|
||||||
|
### macOS
|
||||||
|
|
||||||
Install the packages with [Homebrew]:
|
Install the packages with [Homebrew]:
|
||||||
|
|
||||||
|
|
@ -172,8 +176,7 @@ Additionally, if you want to build the server, install Java 17 from Caskroom, an
|
||||||
make it available from the `PATH`:
|
make it available from the `PATH`:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
brew tap homebrew/cask-versions
|
brew install openjdk@17
|
||||||
brew install adoptopenjdk/openjdk/adoptopenjdk17
|
|
||||||
export JAVA_HOME="$(/usr/libexec/java_home --version 1.17)"
|
export JAVA_HOME="$(/usr/libexec/java_home --version 1.17)"
|
||||||
export PATH="$JAVA_HOME/bin:$PATH"
|
export PATH="$JAVA_HOME/bin:$PATH"
|
||||||
```
|
```
|
||||||
|
|
@ -233,10 +236,10 @@ install` must be run as root)._
|
||||||
|
|
||||||
#### Option 2: Use prebuilt server
|
#### Option 2: Use prebuilt server
|
||||||
|
|
||||||
- [`scrcpy-server-v3.3.2`][direct-scrcpy-server]
|
- [`scrcpy-server-v3.3.4`][direct-scrcpy-server]
|
||||||
<sub>SHA-256: `2ee5ca0863ef440f5b7c75856bb475c5283d0a8359cb370b1c161314fd29dfd9`</sub>
|
<sub>SHA-256: `8588238c9a5a00aa542906b6ec7e6d5541d9ffb9b5d0f6e1bc0e365e2303079e`</sub>
|
||||||
|
|
||||||
[direct-scrcpy-server]: https://github.com/Genymobile/scrcpy/releases/download/v3.3.2/scrcpy-server-v3.3.2
|
[direct-scrcpy-server]: https://github.com/Genymobile/scrcpy/releases/download/v3.3.4/scrcpy-server-v3.3.4
|
||||||
|
|
||||||
Download the prebuilt server somewhere, and specify its path during the Meson
|
Download the prebuilt server somewhere, and specify its path during the Meson
|
||||||
configuration:
|
configuration:
|
||||||
|
|
@ -271,7 +274,7 @@ This installs several files:
|
||||||
- `/usr/local/bin/scrcpy` (main app)
|
- `/usr/local/bin/scrcpy` (main app)
|
||||||
- `/usr/local/share/scrcpy/scrcpy-server` (server to push to the device)
|
- `/usr/local/share/scrcpy/scrcpy-server` (server to push to the device)
|
||||||
- `/usr/local/share/man/man1/scrcpy.1` (manpage)
|
- `/usr/local/share/man/man1/scrcpy.1` (manpage)
|
||||||
- `/usr/local/share/icons/hicolor/256x256/apps/icon.png` (app icon)
|
- `/usr/local/share/icons/hicolor/256x256/apps/scrcpy.png` (app icon)
|
||||||
- `/usr/local/share/zsh/site-functions/_scrcpy` (zsh completion)
|
- `/usr/local/share/zsh/site-functions/_scrcpy` (zsh completion)
|
||||||
- `/usr/local/share/bash-completion/completions/scrcpy` (bash completion)
|
- `/usr/local/share/bash-completion/completions/scrcpy` (bash completion)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -409,8 +409,8 @@ with any client which uses the same protocol.
|
||||||
|
|
||||||
For simplicity, some [server-specific options] have been added to produce raw
|
For simplicity, some [server-specific options] have been added to produce raw
|
||||||
streams easily:
|
streams easily:
|
||||||
- `send_device_meta=false`: disable the device metata (in practice, the device
|
- `send_device_meta=false`: disable the device metadata (in practice, the
|
||||||
name) sent on the _first_ socket
|
device name) sent on the _first_ socket
|
||||||
- `send_frame_meta=false`: disable the 12-byte header for each packet
|
- `send_frame_meta=false`: disable the 12-byte header for each packet
|
||||||
- `send_dummy_byte`: disable the dummy byte sent on forward connections
|
- `send_dummy_byte`: disable the dummy byte sent on forward connections
|
||||||
- `send_codec_meta`: disable the codec information (and initial device size for
|
- `send_codec_meta`: disable the codec information (and initial device size for
|
||||||
|
|
|
||||||
|
|
@ -6,11 +6,11 @@
|
||||||
|
|
||||||
Download a static build of the [latest release]:
|
Download a static build of the [latest release]:
|
||||||
|
|
||||||
- [`scrcpy-linux-x86_64-v3.3.2.tar.gz`][direct-linux-x86_64] (x86_64)
|
- [`scrcpy-linux-x86_64-v3.3.4.tar.gz`][direct-linux-x86_64] (x86_64)
|
||||||
<sub>SHA-256: `92bed0fa274b9165eb8740e07cf2e2692ebe09ad6911175b0ee42e08799dc51c`</sub>
|
<sub>SHA-256: `0305d98c06178c67e12427bbf340c436d0d58c9e2a39bf9ffbbf8f54d7ef95a5`</sub>
|
||||||
|
|
||||||
[latest release]: https://github.com/Genymobile/scrcpy/releases/latest
|
[latest release]: https://github.com/Genymobile/scrcpy/releases/latest
|
||||||
[direct-linux-x86_64]: https://github.com/Genymobile/scrcpy/releases/download/v3.3.2/scrcpy-linux-x86_64-v3.3.2.tar.gz
|
[direct-linux-x86_64]: https://github.com/Genymobile/scrcpy/releases/download/v3.3.4/scrcpy-linux-x86_64-v3.3.4.tar.gz
|
||||||
|
|
||||||
and extract it.
|
and extract it.
|
||||||
|
|
||||||
|
|
|
||||||
13
doc/macos.md
13
doc/macos.md
|
|
@ -6,15 +6,14 @@
|
||||||
|
|
||||||
Download a static build of the [latest release]:
|
Download a static build of the [latest release]:
|
||||||
|
|
||||||
- [`scrcpy-macos-aarch64-v3.3.2.tar.gz`][direct-macos-aarch64] (aarch64)
|
- [`scrcpy-macos-aarch64-v3.3.4.tar.gz`][direct-macos-aarch64] (aarch64)
|
||||||
<sub>SHA-256: `a213eeff8ac95893e69c4bc6a001a402c6680dbfcb74cb353c0124184ed88e8d`</sub>
|
<sub>SHA-256: `8fef43520405dd523c74e1530ac68febcc5a405ea89712c874936675da8513dd`</sub>
|
||||||
|
- [`scrcpy-macos-x86_64-v3.3.4.tar.gz`][direct-macos-x86_64] (x86_64)
|
||||||
- [`scrcpy-macos-x86_64-v3.3.2.tar.gz`][direct-macos-x86_64] (x86_64)
|
<sub>SHA-256: `cf9b3453a33279b6009dfb256b1a84c374bd4c30a71edd74bacab28d72a5d929`</sub>
|
||||||
<sub>SHA-256: `2a1b27fbb67821a886c7e8dea641899836c0abbe7afd37905584b99bcd21bc04`</sub>
|
|
||||||
|
|
||||||
[latest release]: https://github.com/Genymobile/scrcpy/releases/latest
|
[latest release]: https://github.com/Genymobile/scrcpy/releases/latest
|
||||||
[direct-macos-aarch64]: https://github.com/Genymobile/scrcpy/releases/download/v3.3.2/scrcpy-macos-aarch64-v3.3.2.tar.gz
|
[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.2/scrcpy-macos-x86_64-v3.3.2.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
|
||||||
|
|
||||||
and extract it.
|
and extract it.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ to create several devices or devices with specific IDs).
|
||||||
If you encounter problems detecting your device with Chrome/WebRTC, you can try
|
If you encounter problems detecting your device with Chrome/WebRTC, you can try
|
||||||
`exclusive_caps` mode:
|
`exclusive_caps` mode:
|
||||||
|
|
||||||
```
|
```bash
|
||||||
sudo modprobe v4l2loopback exclusive_caps=1
|
sudo modprobe v4l2loopback exclusive_caps=1
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -38,6 +38,13 @@ v4l2-ctl --list-devices
|
||||||
ls /dev/video*
|
ls /dev/video*
|
||||||
```
|
```
|
||||||
|
|
||||||
|
If a loopback device was not created automatically, you can make a new one:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# requires v4l2loopback-utils package
|
||||||
|
sudo v4l2loopback-ctl add
|
||||||
|
```
|
||||||
|
|
||||||
To start `scrcpy` using a v4l2 sink:
|
To start `scrcpy` using a v4l2 sink:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|
|
||||||
|
|
@ -6,14 +6,14 @@
|
||||||
|
|
||||||
Download the [latest release]:
|
Download the [latest release]:
|
||||||
|
|
||||||
- [`scrcpy-win64-v3.3.2.zip`][direct-win64] (64-bit)
|
- [`scrcpy-win64-v3.3.4.zip`][direct-win64] (64-bit)
|
||||||
<sub>SHA-256: `8f7b19371657b872e271e6b02a0c758c61c6e31e032e9df55a83aa3aab960bfa`</sub>
|
<sub>SHA-256: `d8a155b7c180b7ca4cdadd40712b8750b63f3aab48cb5b8a2a39ac2d0d4c5d38`</sub>
|
||||||
- [`scrcpy-win32-v3.3.2.zip`][direct-win32] (32-bit)
|
- [`scrcpy-win32-v3.3.4.zip`][direct-win32] (32-bit)
|
||||||
<sub>SHA-256: `cff2bbebdcfe14a023b77cd601fc4420b5631b19bd4b09ce4dcd4e5bf8e63244`</sub>
|
<sub>SHA-256: `393f7d5379dabd8aacc41184755c3d0df975cd2861353cb7a8d50e0835e2eb72`</sub>
|
||||||
|
|
||||||
[latest release]: https://github.com/Genymobile/scrcpy/releases/latest
|
[latest release]: https://github.com/Genymobile/scrcpy/releases/latest
|
||||||
[direct-win64]: https://github.com/Genymobile/scrcpy/releases/download/v3.3.2/scrcpy-win64-v3.3.2.zip
|
[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.2/scrcpy-win32-v3.3.2.zip
|
[direct-win32]: https://github.com/Genymobile/scrcpy/releases/download/v3.3.4/scrcpy-win32-v3.3.4.zip
|
||||||
|
|
||||||
and extract it.
|
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
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip
|
||||||
# https://gradle.org/release-checksums/
|
# https://gradle.org/release-checksums/
|
||||||
distributionSha256Sum=d725d707bfabd4dfdc958c624003b3c80accc03f7037b5122c4b1d0ef15cecab
|
distributionSha256Sum=bd71102213493060956ec229d946beee57158dbd89d0e62b91bca0fa2c5f3531
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,8 @@
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
BUILDDIR=build-auto
|
BUILDDIR=build-auto
|
||||||
PREBUILT_SERVER_URL=https://github.com/Genymobile/scrcpy/releases/download/v3.3.2/scrcpy-server-v3.3.2
|
PREBUILT_SERVER_URL=https://github.com/Genymobile/scrcpy/releases/download/v3.3.4/scrcpy-server-v3.3.4
|
||||||
PREBUILT_SERVER_SHA256=2ee5ca0863ef440f5b7c75856bb475c5283d0a8359cb370b1c161314fd29dfd9
|
PREBUILT_SERVER_SHA256=8588238c9a5a00aa542906b6ec7e6d5541d9ffb9b5d0f6e1bc0e365e2303079e
|
||||||
|
|
||||||
echo "[scrcpy] Downloading prebuilt server..."
|
echo "[scrcpy] Downloading prebuilt server..."
|
||||||
wget "$PREBUILT_SERVER_URL" -O scrcpy-server
|
wget "$PREBUILT_SERVER_URL" -O scrcpy-server
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
project('scrcpy', 'c',
|
project('scrcpy', 'c',
|
||||||
version: '3.3.2',
|
version: '3.3.4',
|
||||||
meson_version: '>= 0.49',
|
meson_version: '>= 0.49',
|
||||||
default_options: [
|
default_options: [
|
||||||
'c_std=c11',
|
'c_std=c11',
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,15 @@
|
||||||
apply plugin: 'com.android.application'
|
apply plugin: 'com.android.application'
|
||||||
|
|
||||||
android {
|
android {
|
||||||
namespace 'com.genymobile.scrcpy'
|
namespace = 'com.genymobile.scrcpy'
|
||||||
compileSdk 35
|
compileSdk 36
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "com.genymobile.scrcpy"
|
applicationId = "com.genymobile.scrcpy"
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 35
|
targetSdkVersion 36
|
||||||
versionCode 30302
|
versionCode 30304
|
||||||
versionName "3.3.2"
|
versionName "3.3.4"
|
||||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner = "android.support.test.runner.AndroidJUnitRunner"
|
||||||
}
|
}
|
||||||
buildTypes {
|
buildTypes {
|
||||||
release {
|
release {
|
||||||
|
|
@ -18,8 +18,11 @@ android {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
buildFeatures {
|
buildFeatures {
|
||||||
buildConfig true
|
buildConfig = true
|
||||||
aidl true
|
aidl = true
|
||||||
|
}
|
||||||
|
lint {
|
||||||
|
disable 'UseRequiresApi'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,10 +12,10 @@
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
SCRCPY_DEBUG=false
|
SCRCPY_DEBUG=false
|
||||||
SCRCPY_VERSION_NAME=3.3.2
|
SCRCPY_VERSION_NAME=3.3.4
|
||||||
|
|
||||||
PLATFORM=${ANDROID_PLATFORM:-35}
|
PLATFORM=${ANDROID_PLATFORM:-36}
|
||||||
BUILD_TOOLS=${ANDROID_BUILD_TOOLS:-35.0.0}
|
BUILD_TOOLS=${ANDROID_BUILD_TOOLS:-36.0.0}
|
||||||
PLATFORM_TOOLS="$ANDROID_HOME/platforms/android-$PLATFORM"
|
PLATFORM_TOOLS="$ANDROID_HOME/platforms/android-$PLATFORM"
|
||||||
BUILD_TOOLS_DIR="$ANDROID_HOME/build-tools/$BUILD_TOOLS"
|
BUILD_TOOLS_DIR="$ANDROID_HOME/build-tools/$BUILD_TOOLS"
|
||||||
|
|
||||||
|
|
@ -86,7 +86,7 @@ javac -encoding UTF-8 -bootclasspath "$ANDROID_JAR" \
|
||||||
echo "Dexing..."
|
echo "Dexing..."
|
||||||
cd "$CLASSES_DIR"
|
cd "$CLASSES_DIR"
|
||||||
|
|
||||||
if [[ $PLATFORM -lt 31 ]]
|
if [[ "${PLATFORM%%.*}" -lt 31 ]]
|
||||||
then
|
then
|
||||||
# use dx
|
# use dx
|
||||||
"$BUILD_TOOLS_DIR/dx" --dex --output "$BUILD_DIR/classes.dex" \
|
"$BUILD_TOOLS_DIR/dx" --dex --output "$BUILD_DIR/classes.dex" \
|
||||||
|
|
|
||||||
|
|
@ -48,27 +48,4 @@ oneway interface IDisplayWindowListener {
|
||||||
* Called when a display is removed from the hierarchy.
|
* Called when a display is removed from the hierarchy.
|
||||||
*/
|
*/
|
||||||
void onDisplayRemoved(int displayId);
|
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,6 +196,7 @@ public final class CleanUp {
|
||||||
|
|
||||||
// Needed for workarounds
|
// Needed for workarounds
|
||||||
prepareMainLooper();
|
prepareMainLooper();
|
||||||
|
Workarounds.apply();
|
||||||
|
|
||||||
int displayId = Integer.parseInt(args[0]);
|
int displayId = Integer.parseInt(args[0]);
|
||||||
int restoreStayOn = Integer.parseInt(args[1]);
|
int restoreStayOn = Integer.parseInt(args[1]);
|
||||||
|
|
|
||||||
|
|
@ -109,8 +109,10 @@ public final class FakeContext extends ContextWrapper {
|
||||||
}
|
}
|
||||||
|
|
||||||
// "semclipboard" is a Samsung-internal service
|
// "semclipboard" is a Samsung-internal service
|
||||||
// See <https://github.com/Genymobile/scrcpy/issues/6224>
|
// See:
|
||||||
if (Context.CLIPBOARD_SERVICE.equals(name) || "semclipboard".equals(name)) {
|
// - <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)) {
|
||||||
try {
|
try {
|
||||||
Field field = service.getClass().getDeclaredField("mContext");
|
Field field = service.getClass().getDeclaredField("mContext");
|
||||||
field.setAccessible(true);
|
field.setAccessible(true);
|
||||||
|
|
|
||||||
|
|
@ -225,8 +225,12 @@ public final class Server {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void internalMain(String... args) throws Exception {
|
private static void internalMain(String... args) throws Exception {
|
||||||
|
Thread.UncaughtExceptionHandler defaultHandler = Thread.getDefaultUncaughtExceptionHandler();
|
||||||
Thread.setDefaultUncaughtExceptionHandler((t, e) -> {
|
Thread.setDefaultUncaughtExceptionHandler((t, e) -> {
|
||||||
Ln.e("Exception on thread " + t, e);
|
Ln.e("Exception on thread " + t, e);
|
||||||
|
if (defaultHandler != null) {
|
||||||
|
defaultHandler.uncaughtException(t, e);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
prepareMainLooper();
|
prepareMainLooper();
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,9 @@ import com.genymobile.scrcpy.util.Ln;
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.annotation.TargetApi;
|
import android.annotation.TargetApi;
|
||||||
import android.app.Application;
|
import android.app.Application;
|
||||||
|
import android.app.Instrumentation;
|
||||||
import android.content.AttributionSource;
|
import android.content.AttributionSource;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.ContextWrapper;
|
|
||||||
import android.content.pm.ApplicationInfo;
|
import android.content.pm.ApplicationInfo;
|
||||||
import android.media.AudioAttributes;
|
import android.media.AudioAttributes;
|
||||||
import android.media.AudioManager;
|
import android.media.AudioManager;
|
||||||
|
|
@ -103,10 +103,7 @@ public final class Workarounds {
|
||||||
|
|
||||||
private static void fillAppContext() {
|
private static void fillAppContext() {
|
||||||
try {
|
try {
|
||||||
Application app = new Application();
|
Application app = Instrumentation.newApplication(Application.class, FakeContext.get());
|
||||||
Field baseField = ContextWrapper.class.getDeclaredField("mBase");
|
|
||||||
baseField.setAccessible(true);
|
|
||||||
baseField.set(app, FakeContext.get());
|
|
||||||
|
|
||||||
// activityThread.mInitialApplication = app;
|
// activityThread.mInitialApplication = app;
|
||||||
Field mInitialApplicationField = ACTIVITY_THREAD_CLASS.getDeclaredField("mInitialApplication");
|
Field mInitialApplicationField = ACTIVITY_THREAD_CLASS.getDeclaredField("mInitialApplication");
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package com.genymobile.scrcpy.opengl;
|
package com.genymobile.scrcpy.opengl;
|
||||||
|
|
||||||
import com.genymobile.scrcpy.device.Size;
|
import com.genymobile.scrcpy.device.Size;
|
||||||
|
import com.genymobile.scrcpy.util.Threads;
|
||||||
|
|
||||||
import android.graphics.SurfaceTexture;
|
import android.graphics.SurfaceTexture;
|
||||||
import android.opengl.EGL14;
|
import android.opengl.EGL14;
|
||||||
|
|
@ -15,6 +16,7 @@ import android.os.Handler;
|
||||||
import android.os.HandlerThread;
|
import android.os.HandlerThread;
|
||||||
import android.view.Surface;
|
import android.view.Surface;
|
||||||
|
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
import java.util.concurrent.Semaphore;
|
import java.util.concurrent.Semaphore;
|
||||||
|
|
||||||
public final class OpenGLRunner {
|
public final class OpenGLRunner {
|
||||||
|
|
@ -80,31 +82,17 @@ public final class OpenGLRunner {
|
||||||
public Surface start(Size inputSize, Size outputSize, Surface outputSurface) throws OpenGLException {
|
public Surface start(Size inputSize, Size outputSize, Surface outputSurface) throws OpenGLException {
|
||||||
initOnce();
|
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.
|
// The whole OpenGL execution must be performed on a Handler, so that SurfaceTexture.setOnFrameAvailableListener() works correctly.
|
||||||
// See <https://github.com/Genymobile/scrcpy/issues/5444>
|
// See <https://github.com/Genymobile/scrcpy/issues/5444>
|
||||||
handler.post(() -> {
|
|
||||||
try {
|
try {
|
||||||
|
Threads.executeSynchronouslyOn(handler, new Callable<Void>() {
|
||||||
|
@Override
|
||||||
|
public Void call() throws Exception {
|
||||||
run(inputSize, outputSize, outputSurface);
|
run(inputSize, outputSize, outputSurface);
|
||||||
} catch (Throwable throwable) {
|
return null;
|
||||||
throwableRef[0] = throwable;
|
|
||||||
} finally {
|
|
||||||
sem.release();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
} catch (Throwable throwable) {
|
||||||
try {
|
|
||||||
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) {
|
if (throwable instanceof OpenGLException) {
|
||||||
throw (OpenGLException) throwable;
|
throw (OpenGLException) throwable;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -74,12 +74,14 @@ public final class Ln {
|
||||||
public static void w(String message, Throwable throwable) {
|
public static void w(String message, Throwable throwable) {
|
||||||
if (isEnabled(Level.WARN)) {
|
if (isEnabled(Level.WARN)) {
|
||||||
Log.w(TAG, message, throwable);
|
Log.w(TAG, message, throwable);
|
||||||
|
synchronized (CONSOLE_ERR) {
|
||||||
CONSOLE_ERR.print(PREFIX + "WARN: " + message + '\n');
|
CONSOLE_ERR.print(PREFIX + "WARN: " + message + '\n');
|
||||||
if (throwable != null) {
|
if (throwable != null) {
|
||||||
throwable.printStackTrace(CONSOLE_ERR);
|
throwable.printStackTrace(CONSOLE_ERR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void w(String message) {
|
public static void w(String message) {
|
||||||
w(message, null);
|
w(message, null);
|
||||||
|
|
@ -88,12 +90,14 @@ public final class Ln {
|
||||||
public static void e(String message, Throwable throwable) {
|
public static void e(String message, Throwable throwable) {
|
||||||
if (isEnabled(Level.ERROR)) {
|
if (isEnabled(Level.ERROR)) {
|
||||||
Log.e(TAG, message, throwable);
|
Log.e(TAG, message, throwable);
|
||||||
|
synchronized (CONSOLE_ERR) {
|
||||||
CONSOLE_ERR.print(PREFIX + "ERROR: " + message + '\n');
|
CONSOLE_ERR.print(PREFIX + "ERROR: " + message + '\n');
|
||||||
if (throwable != null) {
|
if (throwable != null) {
|
||||||
throwable.printStackTrace(CONSOLE_ERR);
|
throwable.printStackTrace(CONSOLE_ERR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void e(String message) {
|
public static void e(String message) {
|
||||||
e(message, null);
|
e(message, null);
|
||||||
|
|
|
||||||
43
server/src/main/java/com/genymobile/scrcpy/util/Threads.java
Normal file
43
server/src/main/java/com/genymobile/scrcpy/util/Threads.java
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
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,6 +25,7 @@ public class NewDisplayCapture extends SurfaceCapture {
|
||||||
|
|
||||||
// Internal fields copied from android.hardware.display.DisplayManager
|
// 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_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_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_SUPPORTS_TOUCH = 1 << 6;
|
||||||
private static final int VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT = 1 << 7;
|
private static final int VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT = 1 << 7;
|
||||||
|
|
@ -169,6 +170,7 @@ public class NewDisplayCapture extends SurfaceCapture {
|
||||||
int virtualDisplayId;
|
int virtualDisplayId;
|
||||||
try {
|
try {
|
||||||
int flags = VIRTUAL_DISPLAY_FLAG_PUBLIC
|
int flags = VIRTUAL_DISPLAY_FLAG_PUBLIC
|
||||||
|
| VIRTUAL_DISPLAY_FLAG_PRESENTATION
|
||||||
| VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY
|
| VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY
|
||||||
| VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH
|
| VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH
|
||||||
| VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT;
|
| VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT;
|
||||||
|
|
|
||||||
|
|
@ -139,7 +139,13 @@ public final class DisplayManager {
|
||||||
int layerStack = cls.getDeclaredField("layerStack").getInt(displayInfo);
|
int layerStack = cls.getDeclaredField("layerStack").getInt(displayInfo);
|
||||||
int flags = cls.getDeclaredField("flags").getInt(displayInfo);
|
int flags = cls.getDeclaredField("flags").getInt(displayInfo);
|
||||||
int dpi = cls.getDeclaredField("logicalDensityDpi").getInt(displayInfo);
|
int dpi = cls.getDeclaredField("logicalDensityDpi").getInt(displayInfo);
|
||||||
String uniqueId = (String) cls.getDeclaredField("uniqueId").get(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;
|
||||||
|
}
|
||||||
return new DisplayInfo(displayId, new Size(width, height), rotation, layerStack, flags, dpi, uniqueId);
|
return new DisplayInfo(displayId, new Size(width, height), rotation, layerStack, flags, dpi, uniqueId);
|
||||||
} catch (ReflectiveOperationException e) {
|
} catch (ReflectiveOperationException e) {
|
||||||
throw new AssertionError(e);
|
throw new AssertionError(e);
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
package com.genymobile.scrcpy.wrappers;
|
package com.genymobile.scrcpy.wrappers;
|
||||||
|
|
||||||
import android.content.res.Configuration;
|
import com.genymobile.scrcpy.util.Ln;
|
||||||
import android.graphics.Rect;
|
|
||||||
import android.view.IDisplayWindowListener;
|
|
||||||
|
|
||||||
import java.util.List;
|
import android.content.res.Configuration;
|
||||||
|
import android.os.Parcel;
|
||||||
|
import android.os.RemoteException;
|
||||||
|
import android.view.IDisplayWindowListener;
|
||||||
|
|
||||||
public class DisplayWindowListener extends IDisplayWindowListener.Stub {
|
public class DisplayWindowListener extends IDisplayWindowListener.Stub {
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -23,32 +24,14 @@ public class DisplayWindowListener extends IDisplayWindowListener.Stub {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onFixedRotationStarted(int displayId, int newRotation) {
|
public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
|
||||||
// empty default implementation
|
try {
|
||||||
}
|
return super.onTransact(code, data, reply, flags);
|
||||||
|
} catch (AbstractMethodError e) {
|
||||||
@Override
|
Ln.v("Ignoring AbstractMethodError: " + e.getMessage());
|
||||||
public void onFixedRotationFinished(int displayId) {
|
// Ignore unknown methods, write default response to reply parcel
|
||||||
// empty default implementation
|
reply.writeNoException();
|
||||||
}
|
return true;
|
||||||
|
}
|
||||||
@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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue