Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9497f39fb4 | ||
|
|
bf056b1fee | ||
|
|
140a49b8be | ||
|
|
4135c411af | ||
|
|
5e061636f6 | ||
|
|
5f3fb843f5 | ||
|
|
ce8126f322 | ||
|
|
d037b02cc2 | ||
|
|
89761213c3 | ||
|
|
8db4e78b34 | ||
|
|
5d4b8a7e6d | ||
|
|
eed06b141a | ||
|
|
825d7f72c0 | ||
|
|
2370298b61 | ||
|
|
67f356f881 | ||
|
|
25e33566f5 |
@@ -1,4 +1,4 @@
|
||||
# scrcpy (v2.2)
|
||||
# scrcpy (v2.3)
|
||||
|
||||
<img src="app/data/icon.svg" width="128" height="128" alt="scrcpy" align="right" />
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ Comment=Display and control your Android device
|
||||
# For some users, the PATH or ADB environment variables are set from the shell
|
||||
# startup file, like .bashrc or .zshrc… Run an interactive shell to get
|
||||
# environment correctly initialized.
|
||||
Exec=/bin/sh -c "\"\\$SHELL\" -i -c scrcpy --pause-on-exit=if-error"
|
||||
Exec=/bin/sh -c "\\$SHELL -i -c 'scrcpy --pause-on-exit=if-error'"
|
||||
Icon=scrcpy
|
||||
Terminal=true
|
||||
Type=Application
|
||||
|
||||
@@ -5,7 +5,7 @@ Comment=Display and control your Android device
|
||||
# For some users, the PATH or ADB environment variables are set from the shell
|
||||
# startup file, like .bashrc or .zshrc… Run an interactive shell to get
|
||||
# environment correctly initialized.
|
||||
Exec=/bin/sh -c "\"\\$SHELL\" -i -c scrcpy"
|
||||
Exec=/bin/sh -c "\\$SHELL -i -c scrcpy"
|
||||
Icon=scrcpy
|
||||
Terminal=false
|
||||
Type=Application
|
||||
|
||||
@@ -98,77 +98,24 @@ endif
|
||||
|
||||
cc = meson.get_compiler('c')
|
||||
|
||||
crossbuild_windows = meson.is_cross_build() and host_machine.system() == 'windows'
|
||||
dependencies = [
|
||||
dependency('libavformat', version: '>= 57.33'),
|
||||
dependency('libavcodec', version: '>= 57.37'),
|
||||
dependency('libavutil'),
|
||||
dependency('libswresample'),
|
||||
dependency('sdl2', version: '>= 2.0.5'),
|
||||
]
|
||||
|
||||
if not crossbuild_windows
|
||||
|
||||
# native build
|
||||
dependencies = [
|
||||
dependency('libavformat', version: '>= 57.33'),
|
||||
dependency('libavcodec', version: '>= 57.37'),
|
||||
dependency('libavutil'),
|
||||
dependency('libswresample'),
|
||||
dependency('sdl2', version: '>= 2.0.5'),
|
||||
]
|
||||
|
||||
if v4l2_support
|
||||
dependencies += dependency('libavdevice')
|
||||
endif
|
||||
|
||||
if usb_support
|
||||
dependencies += dependency('libusb-1.0')
|
||||
endif
|
||||
|
||||
else
|
||||
# cross-compile mingw32 build (from Linux to Windows)
|
||||
prebuilt_sdl2 = meson.get_cross_property('prebuilt_sdl2')
|
||||
sdl2_bin_dir = meson.current_source_dir() + '/prebuilt-deps/data/' + prebuilt_sdl2 + '/bin'
|
||||
sdl2_lib_dir = meson.current_source_dir() + '/prebuilt-deps/data/' + prebuilt_sdl2 + '/lib'
|
||||
sdl2_include_dir = 'prebuilt-deps/data/' + prebuilt_sdl2 + '/include'
|
||||
|
||||
sdl2 = declare_dependency(
|
||||
dependencies: [
|
||||
cc.find_library('SDL2', dirs: sdl2_bin_dir),
|
||||
cc.find_library('SDL2main', dirs: sdl2_lib_dir),
|
||||
],
|
||||
include_directories: include_directories(sdl2_include_dir)
|
||||
)
|
||||
|
||||
prebuilt_ffmpeg = meson.get_cross_property('prebuilt_ffmpeg')
|
||||
ffmpeg_bin_dir = meson.current_source_dir() + '/prebuilt-deps/data/' + prebuilt_ffmpeg + '/bin'
|
||||
ffmpeg_include_dir = 'prebuilt-deps/data/' + prebuilt_ffmpeg + '/include'
|
||||
|
||||
ffmpeg = declare_dependency(
|
||||
dependencies: [
|
||||
cc.find_library('avcodec-60', dirs: ffmpeg_bin_dir),
|
||||
cc.find_library('avformat-60', dirs: ffmpeg_bin_dir),
|
||||
cc.find_library('avutil-58', dirs: ffmpeg_bin_dir),
|
||||
cc.find_library('swresample-4', dirs: ffmpeg_bin_dir),
|
||||
],
|
||||
include_directories: include_directories(ffmpeg_include_dir)
|
||||
)
|
||||
|
||||
prebuilt_libusb = meson.get_cross_property('prebuilt_libusb')
|
||||
libusb_bin_dir = meson.current_source_dir() + '/prebuilt-deps/data/' + prebuilt_libusb + '/bin'
|
||||
libusb_include_dir = 'prebuilt-deps/data/' + prebuilt_libusb + '/include'
|
||||
|
||||
libusb = declare_dependency(
|
||||
dependencies: [
|
||||
cc.find_library('msys-usb-1.0', dirs: libusb_bin_dir),
|
||||
],
|
||||
include_directories: include_directories(libusb_include_dir)
|
||||
)
|
||||
|
||||
dependencies = [
|
||||
ffmpeg,
|
||||
sdl2,
|
||||
libusb,
|
||||
cc.find_library('mingw32')
|
||||
]
|
||||
if v4l2_support
|
||||
dependencies += dependency('libavdevice')
|
||||
endif
|
||||
|
||||
if usb_support
|
||||
dependencies += dependency('libusb-1.0')
|
||||
endif
|
||||
|
||||
if host_machine.system() == 'windows'
|
||||
dependencies += cc.find_library('mingw32')
|
||||
dependencies += cc.find_library('ws2_32')
|
||||
endif
|
||||
|
||||
|
||||
@@ -6,11 +6,11 @@ cd "$DIR"
|
||||
mkdir -p "$PREBUILT_DATA_DIR"
|
||||
cd "$PREBUILT_DATA_DIR"
|
||||
|
||||
VERSION=6.1-scrcpy-2
|
||||
VERSION=6.1-scrcpy-3
|
||||
DEP_DIR="ffmpeg-$VERSION"
|
||||
|
||||
FILENAME="$DEP_DIR".7z
|
||||
SHA256SUM=7f25f638dc24a0f5d4af07a088b6a604cf33548900bbfd2f6ce0bae050b7664d
|
||||
SHA256SUM=b646d18a3d543a4e4c46881568213499f22e4454a464e1552f03f2ac9cc3a05a
|
||||
|
||||
if [[ -d "$DEP_DIR" ]]
|
||||
then
|
||||
|
||||
@@ -6,9 +6,10 @@ cd "$DIR"
|
||||
mkdir -p "$PREBUILT_DATA_DIR"
|
||||
cd "$PREBUILT_DATA_DIR"
|
||||
|
||||
DEP_DIR=libusb-1.0.26
|
||||
VERSION=1.0.26
|
||||
DEP_DIR="libusb-$VERSION"
|
||||
|
||||
FILENAME=libusb-1.0.26-binaries.7z
|
||||
FILENAME="libusb-$VERSION-binaries.7z"
|
||||
SHA256SUM=9c242696342dbde9cdc47239391f71833939bf9f7aa2bbb28cdaabe890465ec5
|
||||
|
||||
if [[ -d "$DEP_DIR" ]]
|
||||
@@ -17,17 +18,22 @@ then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
get_file "https://github.com/libusb/libusb/releases/download/v1.0.26/$FILENAME" "$FILENAME" "$SHA256SUM"
|
||||
get_file "https://github.com/libusb/libusb/releases/download/v$VERSION/$FILENAME" \
|
||||
"$FILENAME" "$SHA256SUM"
|
||||
|
||||
mkdir "$DEP_DIR"
|
||||
cd "$DEP_DIR"
|
||||
|
||||
7z x "../$FILENAME" \
|
||||
libusb-1.0.26-binaries/libusb-MinGW-Win32/bin/msys-usb-1.0.dll \
|
||||
libusb-1.0.26-binaries/libusb-MinGW-Win32/include/ \
|
||||
libusb-1.0.26-binaries/libusb-MinGW-x64/bin/msys-usb-1.0.dll \
|
||||
libusb-1.0.26-binaries/libusb-MinGW-x64/include/
|
||||
"libusb-$VERSION-binaries/libusb-MinGW-Win32/" \
|
||||
"libusb-$VERSION-binaries/libusb-MinGW-Win32/" \
|
||||
"libusb-$VERSION-binaries/libusb-MinGW-x64/" \
|
||||
"libusb-$VERSION-binaries/libusb-MinGW-x64/"
|
||||
|
||||
mv libusb-1.0.26-binaries/libusb-MinGW-Win32 .
|
||||
mv libusb-1.0.26-binaries/libusb-MinGW-x64 .
|
||||
rm -rf libusb-1.0.26-binaries
|
||||
mv "libusb-$VERSION-binaries/libusb-MinGW-Win32" .
|
||||
mv "libusb-$VERSION-binaries/libusb-MinGW-x64" .
|
||||
rm -rf "libusb-$VERSION-binaries"
|
||||
|
||||
# Rename the dll to get the same library name on all platforms
|
||||
mv libusb-MinGW-Win32/bin/msys-usb-1.0.dll libusb-MinGW-Win32/bin/libusb-1.0.dll
|
||||
mv libusb-MinGW-x64/bin/msys-usb-1.0.dll libusb-MinGW-x64/bin/libusb-1.0.dll
|
||||
|
||||
@@ -6,10 +6,11 @@ cd "$DIR"
|
||||
mkdir -p "$PREBUILT_DATA_DIR"
|
||||
cd "$PREBUILT_DATA_DIR"
|
||||
|
||||
DEP_DIR=SDL2-2.28.4
|
||||
VERSION=2.28.5
|
||||
DEP_DIR="SDL2-$VERSION"
|
||||
|
||||
FILENAME=SDL2-devel-2.28.4-mingw.tar.gz
|
||||
SHA256SUM=779d091072cf97291f80030f5232d97aa3d48ab0f2c14fe0b9d9a33c593cdc35
|
||||
FILENAME="SDL2-devel-$VERSION-mingw.tar.gz"
|
||||
SHA256SUM=3c0c655c2ebf67cad48fead72761d1601740ded30808952c3274ba223d226c21
|
||||
|
||||
if [[ -d "$DEP_DIR" ]]
|
||||
then
|
||||
@@ -17,7 +18,8 @@ then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
get_file "https://libsdl.org/release/$FILENAME" "$FILENAME" "$SHA256SUM"
|
||||
get_file "https://github.com/libsdl-org/SDL/releases/download/release-$VERSION/$FILENAME" \
|
||||
"$FILENAME" "$SHA256SUM"
|
||||
|
||||
mkdir "$DEP_DIR"
|
||||
cd "$DEP_DIR"
|
||||
|
||||
@@ -13,7 +13,7 @@ BEGIN
|
||||
VALUE "LegalCopyright", "Romain Vimont, Genymobile"
|
||||
VALUE "OriginalFilename", "scrcpy.exe"
|
||||
VALUE "ProductName", "scrcpy"
|
||||
VALUE "ProductVersion", "v2.2"
|
||||
VALUE "ProductVersion", "2.3"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
@@ -2154,7 +2154,7 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case OPT_ORIENTATION:
|
||||
case OPT_ORIENTATION: {
|
||||
enum sc_orientation orientation;
|
||||
if (!parse_orientation(optarg, &orientation)) {
|
||||
return false;
|
||||
@@ -2162,6 +2162,7 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
|
||||
opts->display_orientation = orientation;
|
||||
opts->record_orientation = orientation;
|
||||
break;
|
||||
}
|
||||
case OPT_RENDER_DRIVER:
|
||||
opts->render_driver = optarg;
|
||||
break;
|
||||
|
||||
@@ -419,12 +419,21 @@ scrcpy(struct scrcpy_options *options) {
|
||||
sdl_set_hints(options->render_driver);
|
||||
}
|
||||
|
||||
// Initialize the video subsystem even if --no-video or --no-video-playback
|
||||
// is passed so that clipboard synchronization still works.
|
||||
// <https://github.com/Genymobile/scrcpy/issues/4418>
|
||||
if (SDL_Init(SDL_INIT_VIDEO)) {
|
||||
LOGE("Could not initialize SDL video: %s", SDL_GetError());
|
||||
goto end;
|
||||
if (options->video_playback ||
|
||||
(options->control && options->clipboard_autosync)) {
|
||||
// Initialize the video subsystem even if --no-video or
|
||||
// --no-video-playback is passed so that clipboard synchronization
|
||||
// still works.
|
||||
// <https://github.com/Genymobile/scrcpy/issues/4418>
|
||||
if (SDL_Init(SDL_INIT_VIDEO)) {
|
||||
// If it fails, it is an error only if video playback is enabled
|
||||
if (options->video_playback) {
|
||||
LOGE("Could not initialize SDL video: %s", SDL_GetError());
|
||||
goto end;
|
||||
} else {
|
||||
LOGW("Could not initialize SDL video: %s", SDL_GetError());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (options->audio_playback) {
|
||||
|
||||
@@ -14,8 +14,3 @@ system = 'windows'
|
||||
cpu_family = 'x86'
|
||||
cpu = 'i686'
|
||||
endian = 'little'
|
||||
|
||||
[properties]
|
||||
prebuilt_ffmpeg = 'ffmpeg-6.1-scrcpy-2/win32'
|
||||
prebuilt_sdl2 = 'SDL2-2.28.4/i686-w64-mingw32'
|
||||
prebuilt_libusb = 'libusb-1.0.26/libusb-MinGW-Win32'
|
||||
|
||||
@@ -14,8 +14,3 @@ system = 'windows'
|
||||
cpu_family = 'x86'
|
||||
cpu = 'x86_64'
|
||||
endian = 'little'
|
||||
|
||||
[properties]
|
||||
prebuilt_ffmpeg = 'ffmpeg-6.1-scrcpy-2/win64'
|
||||
prebuilt_sdl2 = 'SDL2-2.28.4/x86_64-w64-mingw32'
|
||||
prebuilt_libusb = 'libusb-1.0.26/libusb-MinGW-x64'
|
||||
|
||||
@@ -233,10 +233,10 @@ install` must be run as root)._
|
||||
|
||||
#### Option 2: Use prebuilt server
|
||||
|
||||
- [`scrcpy-server-v2.2`][direct-scrcpy-server]
|
||||
<sub>SHA-256: `c85c4aa84305efb69115cd497a120ebdd10258993b4cf123a8245b3d99d49874`</sub>
|
||||
- [`scrcpy-server-v2.3`][direct-scrcpy-server]
|
||||
<sub>SHA-256: `8daed514d7796fca6987dc973e201bd15ba51d0f7258973dec92d9ded00dbd5f`</sub>
|
||||
|
||||
[direct-scrcpy-server]: https://github.com/Genymobile/scrcpy/releases/download/v2.2/scrcpy-server-v2.2
|
||||
[direct-scrcpy-server]: https://github.com/Genymobile/scrcpy/releases/download/v2.3/scrcpy-server-v2.3
|
||||
|
||||
Download the prebuilt server somewhere, and specify its path during the Meson
|
||||
configuration:
|
||||
|
||||
@@ -18,6 +18,17 @@ scrcpy --video-source=display --audio-source=mic # force display AND micropho
|
||||
scrcpy --video-source=camera --audio-source=output # force camera AND device audio output
|
||||
```
|
||||
|
||||
Audio can be disabled:
|
||||
|
||||
```bash
|
||||
# audio not captured at all
|
||||
scrcpy --video-source=camera --no-audio
|
||||
scrcpy --video-source=camera --no-audio --record=file.mp4
|
||||
|
||||
# audio captured and recorded, but not played
|
||||
scrcpy --video-source=camera --no-audio-playback --record=file.mp4
|
||||
```
|
||||
|
||||
|
||||
## List
|
||||
|
||||
|
||||
@@ -4,14 +4,14 @@
|
||||
|
||||
Download the [latest release]:
|
||||
|
||||
- [`scrcpy-win64-v2.2.zip`][direct-win64] (64-bit)
|
||||
<sub>SHA-256: `9f9da88ac4c8319dcb9bf852f2d9bba942bac663413383419cddf64eaa5685bd`</sub>
|
||||
- [`scrcpy-win32-v2.2.zip`][direct-win32] (32-bit)
|
||||
<sub>SHA-256: `cb84269fc847b8b880e320879492a1ae6c017b42175f03e199530f7a53be9d74`</sub>
|
||||
- [`scrcpy-win64-v2.3.zip`][direct-win64] (64-bit)
|
||||
<sub>SHA-256: `a2fdd2733bd337261bb493e77d990078a23e7a40149dd0c0dc45725c929a715f`</sub>
|
||||
- [`scrcpy-win32-v2.3.zip`][direct-win32] (32-bit)
|
||||
<sub>SHA-256: `dfdbb69a872d717aed5bcfe352e571564c357fdb7a9c172d69f450fdf5154a0a`</sub>
|
||||
|
||||
[latest release]: https://github.com/Genymobile/scrcpy/releases/latest
|
||||
[direct-win64]: https://github.com/Genymobile/scrcpy/releases/download/v2.2/scrcpy-win64-v2.2.zip
|
||||
[direct-win32]: https://github.com/Genymobile/scrcpy/releases/download/v2.2/scrcpy-win32-v2.2.zip
|
||||
[direct-win64]: https://github.com/Genymobile/scrcpy/releases/download/v2.3/scrcpy-win64-v2.3.zip
|
||||
[direct-win32]: https://github.com/Genymobile/scrcpy/releases/download/v2.3/scrcpy-win32-v2.3.zip
|
||||
|
||||
and extract it.
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
set -e
|
||||
|
||||
BUILDDIR=build-auto
|
||||
PREBUILT_SERVER_URL=https://github.com/Genymobile/scrcpy/releases/download/v2.2/scrcpy-server-v2.2
|
||||
PREBUILT_SERVER_SHA256=c85c4aa84305efb69115cd497a120ebdd10258993b4cf123a8245b3d99d49874
|
||||
PREBUILT_SERVER_URL=https://github.com/Genymobile/scrcpy/releases/download/v2.3/scrcpy-server-v2.3
|
||||
PREBUILT_SERVER_SHA256=8daed514d7796fca6987dc973e201bd15ba51d0f7258973dec92d9ded00dbd5f
|
||||
|
||||
echo "[scrcpy] Downloading prebuilt server..."
|
||||
wget "$PREBUILT_SERVER_URL" -O scrcpy-server
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
project('scrcpy', 'c',
|
||||
version: 'v2.2',
|
||||
version: '2.3',
|
||||
meson_version: '>= 0.48',
|
||||
default_options: [
|
||||
'c_std=c11',
|
||||
|
||||
68
release.mk
68
release.mk
@@ -69,58 +69,62 @@ prepare-deps:
|
||||
@app/prebuilt-deps/prepare-libusb.sh
|
||||
|
||||
build-win32: prepare-deps
|
||||
[ -d "$(WIN32_BUILD_DIR)" ] || ( mkdir "$(WIN32_BUILD_DIR)" && \
|
||||
meson setup "$(WIN32_BUILD_DIR)" \
|
||||
--cross-file cross_win32.txt \
|
||||
--buildtype release --strip -Db_lto=true \
|
||||
-Dcompile_server=false \
|
||||
-Dportable=true )
|
||||
rm -rf "$(WIN32_BUILD_DIR)"
|
||||
mkdir -p "$(WIN32_BUILD_DIR)/local"
|
||||
cp -r app/prebuilt-deps/data/ffmpeg-6.1-scrcpy-3/win32/. "$(WIN32_BUILD_DIR)/local/"
|
||||
cp -r app/prebuilt-deps/data/SDL2-2.28.5/i686-w64-mingw32/. "$(WIN32_BUILD_DIR)/local/"
|
||||
cp -r app/prebuilt-deps/data/libusb-1.0.26/libusb-MinGW-Win32/. "$(WIN32_BUILD_DIR)/local/"
|
||||
meson setup "$(WIN32_BUILD_DIR)" \
|
||||
--pkg-config-path="$(WIN32_BUILD_DIR)/local/lib/pkgconfig" \
|
||||
-Dc_args="-I$(PWD)/$(WIN32_BUILD_DIR)/local/include" \
|
||||
-Dc_link_args="-L$(PWD)/$(WIN32_BUILD_DIR)/local/lib" \
|
||||
--cross-file=cross_win32.txt \
|
||||
--buildtype=release --strip -Db_lto=true \
|
||||
-Dcompile_server=false \
|
||||
-Dportable=true
|
||||
ninja -C "$(WIN32_BUILD_DIR)"
|
||||
|
||||
build-win64: prepare-deps
|
||||
[ -d "$(WIN64_BUILD_DIR)" ] || ( mkdir "$(WIN64_BUILD_DIR)" && \
|
||||
meson setup "$(WIN64_BUILD_DIR)" \
|
||||
--cross-file cross_win64.txt \
|
||||
--buildtype release --strip -Db_lto=true \
|
||||
-Dcompile_server=false \
|
||||
-Dportable=true )
|
||||
rm -rf "$(WIN64_BUILD_DIR)"
|
||||
mkdir -p "$(WIN64_BUILD_DIR)/local"
|
||||
cp -r app/prebuilt-deps/data/ffmpeg-6.1-scrcpy-3/win64/. "$(WIN64_BUILD_DIR)/local/"
|
||||
cp -r app/prebuilt-deps/data/SDL2-2.28.5/x86_64-w64-mingw32/. "$(WIN64_BUILD_DIR)/local/"
|
||||
cp -r app/prebuilt-deps/data/libusb-1.0.26/libusb-MinGW-x64/. "$(WIN64_BUILD_DIR)/local/"
|
||||
meson setup "$(WIN64_BUILD_DIR)" \
|
||||
--pkg-config-path="$(WIN64_BUILD_DIR)/local/lib/pkgconfig" \
|
||||
-Dc_args="-I$(PWD)/$(WIN64_BUILD_DIR)/local/include" \
|
||||
-Dc_link_args="-L$(PWD)/$(WIN64_BUILD_DIR)/local/lib" \
|
||||
--cross-file=cross_win64.txt \
|
||||
--buildtype=release --strip -Db_lto=true \
|
||||
-Dcompile_server=false \
|
||||
-Dportable=true
|
||||
ninja -C "$(WIN64_BUILD_DIR)"
|
||||
|
||||
dist-win32: build-server build-win32
|
||||
mkdir -p "$(DIST)/$(WIN32_TARGET_DIR)"
|
||||
cp "$(SERVER_BUILD_DIR)"/server/scrcpy-server "$(DIST)/$(WIN32_TARGET_DIR)/"
|
||||
cp "$(WIN32_BUILD_DIR)"/app/scrcpy.exe "$(DIST)/$(WIN32_TARGET_DIR)/"
|
||||
cp app/data/scrcpy-console.bat "$(DIST)/$(WIN32_TARGET_DIR)"
|
||||
cp app/data/scrcpy-noconsole.vbs "$(DIST)/$(WIN32_TARGET_DIR)"
|
||||
cp app/data/icon.png "$(DIST)/$(WIN32_TARGET_DIR)"
|
||||
cp app/data/open_a_terminal_here.bat "$(DIST)/$(WIN32_TARGET_DIR)"
|
||||
cp app/prebuilt-deps/data/ffmpeg-6.1-scrcpy-2/win32/bin/avutil-58.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
|
||||
cp app/prebuilt-deps/data/ffmpeg-6.1-scrcpy-2/win32/bin/avcodec-60.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
|
||||
cp app/prebuilt-deps/data/ffmpeg-6.1-scrcpy-2/win32/bin/avformat-60.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
|
||||
cp app/prebuilt-deps/data/ffmpeg-6.1-scrcpy-2/win32/bin/swresample-4.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
|
||||
cp app/data/scrcpy-console.bat "$(DIST)/$(WIN32_TARGET_DIR)/"
|
||||
cp app/data/scrcpy-noconsole.vbs "$(DIST)/$(WIN32_TARGET_DIR)/"
|
||||
cp app/data/icon.png "$(DIST)/$(WIN32_TARGET_DIR)/"
|
||||
cp app/data/open_a_terminal_here.bat "$(DIST)/$(WIN32_TARGET_DIR)/"
|
||||
cp app/prebuilt-deps/data/platform-tools-34.0.5/adb.exe "$(DIST)/$(WIN32_TARGET_DIR)/"
|
||||
cp app/prebuilt-deps/data/platform-tools-34.0.5/AdbWinApi.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
|
||||
cp app/prebuilt-deps/data/platform-tools-34.0.5/AdbWinUsbApi.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
|
||||
cp app/prebuilt-deps/data/SDL2-2.28.4/i686-w64-mingw32/bin/SDL2.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
|
||||
cp app/prebuilt-deps/data/libusb-1.0.26/libusb-MinGW-Win32/bin/msys-usb-1.0.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
|
||||
cp "$(WIN32_BUILD_DIR)"/local/bin/*.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
|
||||
|
||||
dist-win64: build-server build-win64
|
||||
mkdir -p "$(DIST)/$(WIN64_TARGET_DIR)"
|
||||
cp "$(SERVER_BUILD_DIR)"/server/scrcpy-server "$(DIST)/$(WIN64_TARGET_DIR)/"
|
||||
cp "$(WIN64_BUILD_DIR)"/app/scrcpy.exe "$(DIST)/$(WIN64_TARGET_DIR)/"
|
||||
cp app/data/scrcpy-console.bat "$(DIST)/$(WIN64_TARGET_DIR)"
|
||||
cp app/data/scrcpy-noconsole.vbs "$(DIST)/$(WIN64_TARGET_DIR)"
|
||||
cp app/data/icon.png "$(DIST)/$(WIN64_TARGET_DIR)"
|
||||
cp app/data/open_a_terminal_here.bat "$(DIST)/$(WIN64_TARGET_DIR)"
|
||||
cp app/prebuilt-deps/data/ffmpeg-6.1-scrcpy-2/win64/bin/avutil-58.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
||||
cp app/prebuilt-deps/data/ffmpeg-6.1-scrcpy-2/win64/bin/avcodec-60.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
||||
cp app/prebuilt-deps/data/ffmpeg-6.1-scrcpy-2/win64/bin/avformat-60.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
||||
cp app/prebuilt-deps/data/ffmpeg-6.1-scrcpy-2/win64/bin/swresample-4.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
||||
cp app/data/scrcpy-console.bat "$(DIST)/$(WIN64_TARGET_DIR)/"
|
||||
cp app/data/scrcpy-noconsole.vbs "$(DIST)/$(WIN64_TARGET_DIR)/"
|
||||
cp app/data/icon.png "$(DIST)/$(WIN64_TARGET_DIR)/"
|
||||
cp app/data/open_a_terminal_here.bat "$(DIST)/$(WIN64_TARGET_DIR)/"
|
||||
cp app/prebuilt-deps/data/platform-tools-34.0.5/adb.exe "$(DIST)/$(WIN64_TARGET_DIR)/"
|
||||
cp app/prebuilt-deps/data/platform-tools-34.0.5/AdbWinApi.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
||||
cp app/prebuilt-deps/data/platform-tools-34.0.5/AdbWinUsbApi.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
||||
cp app/prebuilt-deps/data/SDL2-2.28.4/x86_64-w64-mingw32/bin/SDL2.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
||||
cp app/prebuilt-deps/data/libusb-1.0.26/libusb-MinGW-x64/bin/msys-usb-1.0.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
||||
cp "$(WIN64_BUILD_DIR)"/local/bin/*.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
||||
|
||||
zip-win32: dist-win32
|
||||
cd "$(DIST)"; \
|
||||
|
||||
@@ -7,8 +7,8 @@ android {
|
||||
applicationId "com.genymobile.scrcpy"
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 34
|
||||
versionCode 200
|
||||
versionName "v2.2"
|
||||
versionCode 20300
|
||||
versionName "2.3"
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
buildTypes {
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
set -e
|
||||
|
||||
SCRCPY_DEBUG=false
|
||||
SCRCPY_VERSION_NAME=v2.2
|
||||
SCRCPY_VERSION_NAME=2.3
|
||||
|
||||
PLATFORM=${ANDROID_PLATFORM:-34}
|
||||
BUILD_TOOLS=${ANDROID_BUILD_TOOLS:-34.0.0}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.genymobile.scrcpy;
|
||||
|
||||
import com.genymobile.scrcpy.wrappers.ClipboardManager;
|
||||
import com.genymobile.scrcpy.wrappers.DisplayControl;
|
||||
import com.genymobile.scrcpy.wrappers.InputManager;
|
||||
import com.genymobile.scrcpy.wrappers.ServiceManager;
|
||||
import com.genymobile.scrcpy.wrappers.SurfaceControl;
|
||||
@@ -315,8 +316,12 @@ public final class Device {
|
||||
*/
|
||||
public static boolean setScreenPowerMode(int mode) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
// On Android 14, these internal methods have been moved to DisplayControl
|
||||
boolean useDisplayControl =
|
||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE && !SurfaceControl.hasPhysicalDisplayIdsMethod();
|
||||
|
||||
// Change the power mode for all physical displays
|
||||
long[] physicalDisplayIds = SurfaceControl.getPhysicalDisplayIds();
|
||||
long[] physicalDisplayIds = useDisplayControl ? DisplayControl.getPhysicalDisplayIds() : SurfaceControl.getPhysicalDisplayIds();
|
||||
if (physicalDisplayIds == null) {
|
||||
Ln.e("Could not get physical display ids");
|
||||
return false;
|
||||
@@ -324,7 +329,8 @@ public final class Device {
|
||||
|
||||
boolean allOk = true;
|
||||
for (long physicalDisplayId : physicalDisplayIds) {
|
||||
IBinder binder = SurfaceControl.getPhysicalDisplayToken(physicalDisplayId);
|
||||
IBinder binder = useDisplayControl ? DisplayControl.getPhysicalDisplayToken(
|
||||
physicalDisplayId) : SurfaceControl.getPhysicalDisplayToken(physicalDisplayId);
|
||||
allOk &= SurfaceControl.setDisplayPowerMode(binder, mode);
|
||||
}
|
||||
return allOk;
|
||||
|
||||
@@ -49,6 +49,7 @@ public final class Workarounds {
|
||||
}
|
||||
|
||||
public static void apply(boolean audio, boolean camera) {
|
||||
boolean mustFillConfigurationController = false;
|
||||
boolean mustFillAppInfo = false;
|
||||
boolean mustFillAppContext = false;
|
||||
|
||||
@@ -85,11 +86,23 @@ public final class Workarounds {
|
||||
mustFillAppContext = true;
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
// On some Samsung devices, DisplayManagerGlobal.getDisplayInfoLocked() calls ActivityThread.currentActivityThread().getConfiguration(),
|
||||
// which requires a non-null ConfigurationController.
|
||||
// ConfigurationController was introduced in Android 12, so do not attempt to set it on lower versions.
|
||||
// <https://github.com/Genymobile/scrcpy/issues/4467>
|
||||
mustFillConfigurationController = true;
|
||||
}
|
||||
|
||||
if (mustFillConfigurationController) {
|
||||
// Must be call before fillAppContext() because it is necessary to get a valid system context
|
||||
fillConfigurationController();
|
||||
}
|
||||
if (mustFillAppInfo) {
|
||||
Workarounds.fillAppInfo();
|
||||
fillAppInfo();
|
||||
}
|
||||
if (mustFillAppContext) {
|
||||
Workarounds.fillAppContext();
|
||||
fillAppContext();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,6 +162,22 @@ public final class Workarounds {
|
||||
}
|
||||
}
|
||||
|
||||
private static void fillConfigurationController() {
|
||||
try {
|
||||
Class<?> configurationControllerClass = Class.forName("android.app.ConfigurationController");
|
||||
Class<?> activityThreadInternalClass = Class.forName("android.app.ActivityThreadInternal");
|
||||
Constructor<?> configurationControllerConstructor = configurationControllerClass.getDeclaredConstructor(activityThreadInternalClass);
|
||||
configurationControllerConstructor.setAccessible(true);
|
||||
Object configurationController = configurationControllerConstructor.newInstance(ACTIVITY_THREAD);
|
||||
|
||||
Field configurationControllerField = ACTIVITY_THREAD_CLASS.getDeclaredField("mConfigurationController");
|
||||
configurationControllerField.setAccessible(true);
|
||||
configurationControllerField.set(ACTIVITY_THREAD, configurationController);
|
||||
} catch (Throwable throwable) {
|
||||
Ln.d("Could not fill configuration: " + throwable.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
static Context getSystemContext() {
|
||||
try {
|
||||
Method getSystemContextMethod = ACTIVITY_THREAD_CLASS.getDeclaredMethod("getSystemContext");
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
package com.genymobile.scrcpy.wrappers;
|
||||
|
||||
import com.genymobile.scrcpy.Ln;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.annotation.TargetApi;
|
||||
import android.os.Build;
|
||||
import android.os.IBinder;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
@SuppressLint({"PrivateApi", "SoonBlockedPrivateApi", "BlockedPrivateApi"})
|
||||
@TargetApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
|
||||
public final class DisplayControl {
|
||||
|
||||
private static final Class<?> CLASS;
|
||||
|
||||
static {
|
||||
Class<?> displayControlClass = null;
|
||||
try {
|
||||
Class<?> classLoaderFactoryClass = Class.forName("com.android.internal.os.ClassLoaderFactory");
|
||||
Method createClassLoaderMethod = classLoaderFactoryClass.getDeclaredMethod("createClassLoader", String.class, String.class, String.class,
|
||||
ClassLoader.class, int.class, boolean.class, String.class);
|
||||
ClassLoader classLoader = (ClassLoader) createClassLoaderMethod.invoke(null, "/system/framework/services.jar", null, null,
|
||||
ClassLoader.getSystemClassLoader(), 0, true, null);
|
||||
|
||||
displayControlClass = classLoader.loadClass("com.android.server.display.DisplayControl");
|
||||
|
||||
Method loadMethod = Runtime.class.getDeclaredMethod("loadLibrary0", Class.class, String.class);
|
||||
loadMethod.setAccessible(true);
|
||||
loadMethod.invoke(Runtime.getRuntime(), displayControlClass, "android_servers");
|
||||
} catch (Throwable e) {
|
||||
Ln.e("Could not initialize DisplayControl", e);
|
||||
// Do not throw an exception here, the methods will fail when they are called
|
||||
}
|
||||
CLASS = displayControlClass;
|
||||
}
|
||||
|
||||
private static Method getPhysicalDisplayTokenMethod;
|
||||
private static Method getPhysicalDisplayIdsMethod;
|
||||
|
||||
private DisplayControl() {
|
||||
// only static methods
|
||||
}
|
||||
|
||||
private static Method getGetPhysicalDisplayTokenMethod() throws NoSuchMethodException {
|
||||
if (getPhysicalDisplayTokenMethod == null) {
|
||||
getPhysicalDisplayTokenMethod = CLASS.getMethod("getPhysicalDisplayToken", long.class);
|
||||
}
|
||||
return getPhysicalDisplayTokenMethod;
|
||||
}
|
||||
|
||||
public static IBinder getPhysicalDisplayToken(long physicalDisplayId) {
|
||||
try {
|
||||
Method method = getGetPhysicalDisplayTokenMethod();
|
||||
return (IBinder) method.invoke(null, physicalDisplayId);
|
||||
} catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e) {
|
||||
Ln.e("Could not invoke method", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static Method getGetPhysicalDisplayIdsMethod() throws NoSuchMethodException {
|
||||
if (getPhysicalDisplayIdsMethod == null) {
|
||||
getPhysicalDisplayIdsMethod = CLASS.getMethod("getPhysicalDisplayIds");
|
||||
}
|
||||
return getPhysicalDisplayIdsMethod;
|
||||
}
|
||||
|
||||
public static long[] getPhysicalDisplayIds() {
|
||||
try {
|
||||
Method method = getGetPhysicalDisplayIdsMethod();
|
||||
return (long[]) method.invoke(null);
|
||||
} catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e) {
|
||||
Ln.e("Could not invoke method", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -139,6 +139,15 @@ public final class SurfaceControl {
|
||||
return getPhysicalDisplayIdsMethod;
|
||||
}
|
||||
|
||||
public static boolean hasPhysicalDisplayIdsMethod() {
|
||||
try {
|
||||
getGetPhysicalDisplayIdsMethod();
|
||||
return true;
|
||||
} catch (NoSuchMethodException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static long[] getPhysicalDisplayIds() {
|
||||
try {
|
||||
Method method = getGetPhysicalDisplayIdsMethod();
|
||||
|
||||
Reference in New Issue
Block a user