Compare commits
3 Commits
pr1313
...
logical_si
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
09564e167a | ||
|
|
20cde79980 | ||
|
|
2ed8f5009b |
6
.github/ISSUE_TEMPLATE/bug_report.md
vendored
6
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -21,9 +21,5 @@ assignees: ''
|
|||||||
A clear and concise description of what the bug is.
|
A clear and concise description of what the bug is.
|
||||||
|
|
||||||
On errors, please provide the output of the console (and `adb logcat` if relevant).
|
On errors, please provide the output of the console (and `adb logcat` if relevant).
|
||||||
|
Format them between code blocks (delimited by ```).
|
||||||
```
|
|
||||||
Please paste terminal output in a code block.
|
|
||||||
```
|
|
||||||
|
|
||||||
Please do not post screenshots of your terminal, just post the content as text instead.
|
Please do not post screenshots of your terminal, just post the content as text instead.
|
||||||
|
|||||||
6
BUILD.md
6
BUILD.md
@@ -249,10 +249,10 @@ You can then [run](README.md#run) _scrcpy_.
|
|||||||
|
|
||||||
## Prebuilt server
|
## Prebuilt server
|
||||||
|
|
||||||
- [`scrcpy-server-v1.13`][direct-scrcpy-server]
|
- [`scrcpy-server-v1.12.1`][direct-scrcpy-server]
|
||||||
_(SHA-256: 5fee64ca1ccdc2f38550f31f5353c66de3de30c2e929a964e30fa2d005d5f885)_
|
_(SHA-256: 63e569c8a1d0c1df31d48c4214871c479a601782945fed50c1e61167d78266ea)_
|
||||||
|
|
||||||
[direct-scrcpy-server]: https://github.com/Genymobile/scrcpy/releases/download/v1.13/scrcpy-server-v1.13
|
[direct-scrcpy-server]: https://github.com/Genymobile/scrcpy/releases/download/v1.12.1/scrcpy-server-v1.12.1
|
||||||
|
|
||||||
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:
|
||||||
|
|||||||
@@ -100,30 +100,30 @@ dist-win32: build-server build-win32 build-win32-noconsole
|
|||||||
cp "$(SERVER_BUILD_DIR)"/server/scrcpy-server "$(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 "$(WIN32_BUILD_DIR)"/app/scrcpy.exe "$(DIST)/$(WIN32_TARGET_DIR)/"
|
||||||
cp "$(WIN32_NOCONSOLE_BUILD_DIR)"/app/scrcpy.exe "$(DIST)/$(WIN32_TARGET_DIR)/scrcpy-noconsole.exe"
|
cp "$(WIN32_NOCONSOLE_BUILD_DIR)"/app/scrcpy.exe "$(DIST)/$(WIN32_TARGET_DIR)/scrcpy-noconsole.exe"
|
||||||
cp prebuilt-deps/ffmpeg-4.2.2-win32-shared/bin/avutil-56.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
|
cp prebuilt-deps/ffmpeg-4.2.1-win32-shared/bin/avutil-56.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
|
||||||
cp prebuilt-deps/ffmpeg-4.2.2-win32-shared/bin/avcodec-58.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
|
cp prebuilt-deps/ffmpeg-4.2.1-win32-shared/bin/avcodec-58.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
|
||||||
cp prebuilt-deps/ffmpeg-4.2.2-win32-shared/bin/avformat-58.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
|
cp prebuilt-deps/ffmpeg-4.2.1-win32-shared/bin/avformat-58.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
|
||||||
cp prebuilt-deps/ffmpeg-4.2.2-win32-shared/bin/swresample-3.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
|
cp prebuilt-deps/ffmpeg-4.2.1-win32-shared/bin/swresample-3.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
|
||||||
cp prebuilt-deps/ffmpeg-4.2.2-win32-shared/bin/swscale-5.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
|
cp prebuilt-deps/ffmpeg-4.2.1-win32-shared/bin/swscale-5.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
|
||||||
cp prebuilt-deps/platform-tools/adb.exe "$(DIST)/$(WIN32_TARGET_DIR)/"
|
cp prebuilt-deps/platform-tools/adb.exe "$(DIST)/$(WIN32_TARGET_DIR)/"
|
||||||
cp prebuilt-deps/platform-tools/AdbWinApi.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
|
cp prebuilt-deps/platform-tools/AdbWinApi.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
|
||||||
cp prebuilt-deps/platform-tools/AdbWinUsbApi.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
|
cp prebuilt-deps/platform-tools/AdbWinUsbApi.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
|
||||||
cp prebuilt-deps/SDL2-2.0.12/i686-w64-mingw32/bin/SDL2.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
|
cp prebuilt-deps/SDL2-2.0.10/i686-w64-mingw32/bin/SDL2.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
|
||||||
|
|
||||||
dist-win64: build-server build-win64 build-win64-noconsole
|
dist-win64: build-server build-win64 build-win64-noconsole
|
||||||
mkdir -p "$(DIST)/$(WIN64_TARGET_DIR)"
|
mkdir -p "$(DIST)/$(WIN64_TARGET_DIR)"
|
||||||
cp "$(SERVER_BUILD_DIR)"/server/scrcpy-server "$(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 "$(WIN64_BUILD_DIR)"/app/scrcpy.exe "$(DIST)/$(WIN64_TARGET_DIR)/"
|
||||||
cp "$(WIN64_NOCONSOLE_BUILD_DIR)"/app/scrcpy.exe "$(DIST)/$(WIN64_TARGET_DIR)/scrcpy-noconsole.exe"
|
cp "$(WIN64_NOCONSOLE_BUILD_DIR)"/app/scrcpy.exe "$(DIST)/$(WIN64_TARGET_DIR)/scrcpy-noconsole.exe"
|
||||||
cp prebuilt-deps/ffmpeg-4.2.2-win64-shared/bin/avutil-56.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
cp prebuilt-deps/ffmpeg-4.2.1-win64-shared/bin/avutil-56.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
||||||
cp prebuilt-deps/ffmpeg-4.2.2-win64-shared/bin/avcodec-58.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
cp prebuilt-deps/ffmpeg-4.2.1-win64-shared/bin/avcodec-58.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
||||||
cp prebuilt-deps/ffmpeg-4.2.2-win64-shared/bin/avformat-58.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
cp prebuilt-deps/ffmpeg-4.2.1-win64-shared/bin/avformat-58.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
||||||
cp prebuilt-deps/ffmpeg-4.2.2-win64-shared/bin/swresample-3.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
cp prebuilt-deps/ffmpeg-4.2.1-win64-shared/bin/swresample-3.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
||||||
cp prebuilt-deps/ffmpeg-4.2.2-win64-shared/bin/swscale-5.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
cp prebuilt-deps/ffmpeg-4.2.1-win64-shared/bin/swscale-5.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
||||||
cp prebuilt-deps/platform-tools/adb.exe "$(DIST)/$(WIN64_TARGET_DIR)/"
|
cp prebuilt-deps/platform-tools/adb.exe "$(DIST)/$(WIN64_TARGET_DIR)/"
|
||||||
cp prebuilt-deps/platform-tools/AdbWinApi.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
cp prebuilt-deps/platform-tools/AdbWinApi.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
||||||
cp prebuilt-deps/platform-tools/AdbWinUsbApi.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
cp prebuilt-deps/platform-tools/AdbWinUsbApi.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
||||||
cp prebuilt-deps/SDL2-2.0.12/x86_64-w64-mingw32/bin/SDL2.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
cp prebuilt-deps/SDL2-2.0.10/x86_64-w64-mingw32/bin/SDL2.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
||||||
|
|
||||||
zip-win32: dist-win32
|
zip-win32: dist-win32
|
||||||
cd "$(DIST)/$(WIN32_TARGET_DIR)"; \
|
cd "$(DIST)/$(WIN32_TARGET_DIR)"; \
|
||||||
|
|||||||
16
README.md
16
README.md
@@ -1,4 +1,4 @@
|
|||||||
# scrcpy (v1.13)
|
# scrcpy (v1.12.1)
|
||||||
|
|
||||||
This application provides display and control of Android devices connected on
|
This application provides display and control of Android devices connected on
|
||||||
USB (or [over TCP/IP][article-tcpip]). It does not require any _root_ access.
|
USB (or [over TCP/IP][article-tcpip]). It does not require any _root_ access.
|
||||||
@@ -37,7 +37,7 @@ control it using keyboard and mouse.
|
|||||||
|
|
||||||
### Linux
|
### Linux
|
||||||
|
|
||||||
On Debian (_testing_ and _sid_ for now) and Ubuntu (20.04):
|
In Debian (_testing_ and _sid_ for now):
|
||||||
|
|
||||||
```
|
```
|
||||||
apt install scrcpy
|
apt install scrcpy
|
||||||
@@ -69,10 +69,10 @@ hard).
|
|||||||
For Windows, for simplicity, a prebuilt archive with all the dependencies
|
For Windows, for simplicity, a prebuilt archive with all the dependencies
|
||||||
(including `adb`) is available:
|
(including `adb`) is available:
|
||||||
|
|
||||||
- [`scrcpy-win64-v1.13.zip`][direct-win64]
|
- [`scrcpy-win64-v1.12.1.zip`][direct-win64]
|
||||||
_(SHA-256: 806aafc00d4db01513193addaa24f47858893ba5efe75770bfef6ae1ea987d27)_
|
_(SHA-256: 57d34b6d16cfd9fe169bc37c4df58ebd256d05c1ea3febc63d9cb0a027ab47c9)_
|
||||||
|
|
||||||
[direct-win64]: https://github.com/Genymobile/scrcpy/releases/download/v1.13/scrcpy-win64-v1.13.zip
|
[direct-win64]: https://github.com/Genymobile/scrcpy/releases/download/v1.12.1/scrcpy-win64-v1.12.1.zip
|
||||||
|
|
||||||
It is also available in [Chocolatey]:
|
It is also available in [Chocolatey]:
|
||||||
|
|
||||||
@@ -270,7 +270,7 @@ You could use [AutoAdb]:
|
|||||||
autoadb scrcpy -s '{}'
|
autoadb scrcpy -s '{}'
|
||||||
```
|
```
|
||||||
|
|
||||||
[AutoAdb]: https://github.com/rom1v/autoadb
|
[AutoAdb]: https://github.com/rom1v/usbaudio
|
||||||
|
|
||||||
#### SSH tunnel
|
#### SSH tunnel
|
||||||
|
|
||||||
@@ -396,10 +396,6 @@ The list of display ids can be retrieved by:
|
|||||||
adb shell dumpsys display # search "mDisplayId=" in the output
|
adb shell dumpsys display # search "mDisplayId=" in the output
|
||||||
```
|
```
|
||||||
|
|
||||||
The secondary display may only be controlled if the device runs at least Android
|
|
||||||
10 (otherwise it is mirrored in read-only).
|
|
||||||
|
|
||||||
|
|
||||||
#### Turn screen off
|
#### Turn screen off
|
||||||
|
|
||||||
It is possible to turn the device screen off while mirroring on start with a
|
It is possible to turn the device screen off while mirroring on start with a
|
||||||
|
|||||||
529
README.pt_BR.md
529
README.pt_BR.md
@@ -1,529 +0,0 @@
|
|||||||
# scrcpy (v1.12.1)
|
|
||||||
|
|
||||||
Esta aplicação fornece visualização e controle de dispositivos Android conectados via
|
|
||||||
USB (ou [via TCP/IP][article-tcpip]). Não requer nenhum acesso root.
|
|
||||||
Funciona em _GNU/Linux_, _Windows_ e _macOS_.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
Foco em:
|
|
||||||
|
|
||||||
- **leveza** (Nativo, mostra apenas a tela do dispositivo)
|
|
||||||
- **performance** (30~60fps)
|
|
||||||
- **qualidade** (1920×1080 ou acima)
|
|
||||||
- **baixa latência** ([35~70ms][lowlatency])
|
|
||||||
- **baixo tempo de inicialização** (~1 segundo para mostrar a primeira imagem)
|
|
||||||
- **não intrusivo** (nada é deixado instalado no dispositivo)
|
|
||||||
|
|
||||||
[lowlatency]: https://github.com/Genymobile/scrcpy/pull/646
|
|
||||||
|
|
||||||
|
|
||||||
## Requisitos
|
|
||||||
|
|
||||||
O Dispositivo Android requer pelo menos a API 21 (Android 5.0).
|
|
||||||
|
|
||||||
|
|
||||||
Tenha certeza de ter [ativado a depuração USB][enable-adb] no(s) seu(s) dispositivo(s).
|
|
||||||
|
|
||||||
[enable-adb]: https://developer.android.com/studio/command-line/adb.html#Enabling
|
|
||||||
|
|
||||||
|
|
||||||
Em alguns dispositivos, você também precisará ativar [uma opção adicional][control] para controlá-lo usando o teclado e mouse.
|
|
||||||
|
|
||||||
[control]: https://github.com/Genymobile/scrcpy/issues/70#issuecomment-373286323
|
|
||||||
|
|
||||||
|
|
||||||
## Obtendo o app
|
|
||||||
|
|
||||||
|
|
||||||
### Linux
|
|
||||||
|
|
||||||
No Debian (_em testes_ e _sid_ por enquanto):
|
|
||||||
|
|
||||||
```
|
|
||||||
apt install scrcpy
|
|
||||||
```
|
|
||||||
|
|
||||||
O pacote [Snap] está disponível: [`scrcpy`][snap-link].
|
|
||||||
|
|
||||||
[snap-link]: https://snapstats.org/snaps/scrcpy
|
|
||||||
|
|
||||||
[snap]: https://en.wikipedia.org/wiki/Snappy_(package_manager)
|
|
||||||
|
|
||||||
Para Arch Linux, um pacote [AUR] está disponível: [`scrcpy`][aur-link].
|
|
||||||
|
|
||||||
[AUR]: https://wiki.archlinux.org/index.php/Arch_User_Repository
|
|
||||||
[aur-link]: https://aur.archlinux.org/packages/scrcpy/
|
|
||||||
|
|
||||||
Para Gentoo, uma [Ebuild] está disponível: [`scrcpy/`][ebuild-link].
|
|
||||||
|
|
||||||
[Ebuild]: https://wiki.gentoo.org/wiki/Ebuild
|
|
||||||
[ebuild-link]: https://github.com/maggu2810/maggu2810-overlay/tree/master/app-mobilephone/scrcpy
|
|
||||||
|
|
||||||
|
|
||||||
Você também pode [compilar a aplicação manualmente][BUILD] (não se preocupe, não é tão difícil).
|
|
||||||
|
|
||||||
|
|
||||||
### Windows
|
|
||||||
|
|
||||||
Para Windows, para simplicidade, um arquivo pré-compilado com todas as dependências
|
|
||||||
(incluindo `adb`) está disponível:
|
|
||||||
|
|
||||||
- [`scrcpy-win64-v1.12.1.zip`][direct-win64]
|
|
||||||
_(SHA-256: 57d34b6d16cfd9fe169bc37c4df58ebd256d05c1ea3febc63d9cb0a027ab47c9)_
|
|
||||||
|
|
||||||
[direct-win64]: https://github.com/Genymobile/scrcpy/releases/download/v1.12.1/scrcpy-win64-v1.12.1.zip
|
|
||||||
|
|
||||||
Também disponível em [Chocolatey]:
|
|
||||||
|
|
||||||
[Chocolatey]: https://chocolatey.org/
|
|
||||||
|
|
||||||
```bash
|
|
||||||
choco install scrcpy
|
|
||||||
choco install adb # se você ainda não o tem
|
|
||||||
```
|
|
||||||
|
|
||||||
E no [Scoop]:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
scoop install scrcpy
|
|
||||||
scoop install adb # se você ainda não o tem
|
|
||||||
```
|
|
||||||
|
|
||||||
[Scoop]: https://scoop.sh
|
|
||||||
|
|
||||||
Você também pode [compilar a aplicação manualmente][BUILD].
|
|
||||||
|
|
||||||
|
|
||||||
### macOS
|
|
||||||
|
|
||||||
A aplicação está disponível em [Homebrew]. Apenas a instale:
|
|
||||||
|
|
||||||
[Homebrew]: https://brew.sh/
|
|
||||||
|
|
||||||
```bash
|
|
||||||
brew install scrcpy
|
|
||||||
```
|
|
||||||
|
|
||||||
Você precisa do `adb`, acessível através do seu `PATH`. Se você ainda não o tem:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
brew cask install android-platform-tools
|
|
||||||
```
|
|
||||||
|
|
||||||
Você também pode [compilar a aplicação manualmente][BUILD].
|
|
||||||
|
|
||||||
|
|
||||||
## Executar
|
|
||||||
|
|
||||||
Plugue um dispositivo Android e execute:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
scrcpy
|
|
||||||
```
|
|
||||||
|
|
||||||
Também aceita argumentos de linha de comando, listados por:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
scrcpy --help
|
|
||||||
```
|
|
||||||
|
|
||||||
## Funcionalidades
|
|
||||||
|
|
||||||
### Configuração de captura
|
|
||||||
|
|
||||||
#### Redução de tamanho
|
|
||||||
|
|
||||||
Algumas vezes, é útil espelhar um dispositivo Android em uma resolução menor para
|
|
||||||
aumentar performance.
|
|
||||||
|
|
||||||
Para limitar ambos(largura e altura) para algum valor (ex: 1024):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
scrcpy --max-size 1024
|
|
||||||
scrcpy -m 1024 # versão reduzida
|
|
||||||
```
|
|
||||||
|
|
||||||
A outra dimensão é calculada para que a proporção do dispositivo seja preservada.
|
|
||||||
Dessa forma, um dispositivo em 1920x1080 será espelhado em 1024x576.
|
|
||||||
|
|
||||||
|
|
||||||
#### Mudanças no bit-rate
|
|
||||||
|
|
||||||
O Padrão de bit-rate é 8 mbps. Para mudar o bitrate do vídeo (ex: para 2 Mbps):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
scrcpy --bit-rate 2M
|
|
||||||
scrcpy -b 2M # versão reduzida
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Limitar frame rates
|
|
||||||
|
|
||||||
Em dispositivos com Android >= 10, a captura de frame rate pode ser limitada:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
scrcpy --max-fps 15
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Cortar
|
|
||||||
|
|
||||||
A tela do dispositivo pode ser cortada para espelhar apenas uma parte da tela.
|
|
||||||
|
|
||||||
Isso é útil por exemplo, ao espelhar apenas um olho do Oculus Go:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
scrcpy --crop 1224:1440:0:0 # 1224x1440 no deslocamento (0,0)
|
|
||||||
```
|
|
||||||
|
|
||||||
Se `--max-size` também for especificado, redimensionar é aplicado após os cortes.
|
|
||||||
|
|
||||||
|
|
||||||
### Gravando
|
|
||||||
|
|
||||||
É possível gravar a tela enquanto ocorre o espelhamento:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
scrcpy --record file.mp4
|
|
||||||
scrcpy -r file.mkv
|
|
||||||
```
|
|
||||||
|
|
||||||
Para desativar o espelhamento durante a gravação:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
scrcpy --no-display --record file.mp4
|
|
||||||
scrcpy -Nr file.mkv
|
|
||||||
# interrompe a gravação com Ctrl+C
|
|
||||||
# Ctrl+C não encerrar propriamente no Windows, então desconecte o dispositivo
|
|
||||||
```
|
|
||||||
|
|
||||||
"Frames pulados" são gravados, mesmo que não sejam mostrado em tempo real (por motivos de performance).
|
|
||||||
Frames tem seu _horário_ _carimbado_ no dispositivo, então [Variação de atraso nos pacotes] não impacta na gravação do arquivo.
|
|
||||||
|
|
||||||
[Variação de atraso de pacote]: https://en.wikipedia.org/wiki/Packet_delay_variation
|
|
||||||
|
|
||||||
|
|
||||||
### Conexão
|
|
||||||
|
|
||||||
#### Wireless/Sem fio
|
|
||||||
|
|
||||||
_Scrcpy_ usa `adb` para se comunicar com o dispositivo, e `adb` pode [conectar-se] à um dispositivo via TCP/IP:
|
|
||||||
|
|
||||||
1. Conecte o dispositivo a mesma rede Wi-Fi do seu computador.
|
|
||||||
2. Pegue o endereço de IP do seu dispositivo (Em Configurações → Sobre o Telefone → Status).
|
|
||||||
3. Ative o adb via TCP/IP no seu dispositivo: `adb tcpip 5555`.
|
|
||||||
4. Desplugue seu dispositivo.
|
|
||||||
5. Conecte-se ao seu dispositivo: `adb connect DEVICE_IP:5555` _(substitua o `DEVICE_IP`)_.
|
|
||||||
6. Execute `scrcpy` como de costume.
|
|
||||||
|
|
||||||
Pode ser útil diminuir o bit-rate e a resolução:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
scrcpy --bit-rate 2M --max-size 800
|
|
||||||
scrcpy -b2M -m800 # versão reduzida
|
|
||||||
```
|
|
||||||
|
|
||||||
[conectar-se]: https://developer.android.com/studio/command-line/adb.html#wireless
|
|
||||||
|
|
||||||
|
|
||||||
#### N-dispositivos
|
|
||||||
|
|
||||||
Se alguns dispositivos estão listados em `adb devices`, você precisa especificar o _serial_:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
scrcpy --serial 0123456789abcdef
|
|
||||||
scrcpy -s 0123456789abcdef # versão reduzida
|
|
||||||
```
|
|
||||||
|
|
||||||
Se o dispositivo está conectado via TCP/IP:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
scrcpy --serial 192.168.0.1:5555
|
|
||||||
scrcpy -s 192.168.0.1:5555 # versão reduzida
|
|
||||||
```
|
|
||||||
|
|
||||||
Você pode iniciar algumas instâncias do _scrcpy_ para alguns dispositivos.
|
|
||||||
|
|
||||||
#### Conexão via SSH
|
|
||||||
|
|
||||||
Para conectar-se à um dispositivo remoto, é possível se conectar um cliente local `adb` à um servidor `adb` remoto (contanto que eles usem a mesma versão do protocolo _adb_):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
adb kill-server # encerra o servidor local na 5037
|
|
||||||
ssh -CN -L5037:localhost:5037 -R27183:localhost:27183 your_remote_computer
|
|
||||||
# mantém isso aberto
|
|
||||||
```
|
|
||||||
|
|
||||||
De outro terminal:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
scrcpy
|
|
||||||
```
|
|
||||||
|
|
||||||
Igual para conexões sem fio, pode ser útil reduzir a qualidade:
|
|
||||||
|
|
||||||
```
|
|
||||||
scrcpy -b2M -m800 --max-fps 15
|
|
||||||
```
|
|
||||||
|
|
||||||
### Configurações de Janela
|
|
||||||
|
|
||||||
#### Título
|
|
||||||
|
|
||||||
Por padrão, o título da janela é o modelo do dispositivo. Isto pode ser mudado:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
scrcpy --window-title 'Meu dispositivo'
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Posição e tamanho
|
|
||||||
|
|
||||||
A posição e tamanho iniciais da janela podem ser especificados:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
scrcpy --window-x 100 --window-y 100 --window-width 800 --window-height 600
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Sem bordas
|
|
||||||
|
|
||||||
Para desativar decorações da janela:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
scrcpy --window-borderless
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Sempre visível
|
|
||||||
|
|
||||||
Para manter a janela do scrcpy sempre visível:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
scrcpy --always-on-top
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Tela cheia
|
|
||||||
|
|
||||||
A aplicação pode ser iniciada diretamente em tela cheia:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
scrcpy --fullscreen
|
|
||||||
scrcpy -f # versão reduzida
|
|
||||||
```
|
|
||||||
|
|
||||||
Tela cheia pode ser alternada dinamicamente com `Ctrl`+`f`.
|
|
||||||
|
|
||||||
|
|
||||||
### Outras opções de espelhamento
|
|
||||||
|
|
||||||
#### Apenas leitura
|
|
||||||
|
|
||||||
Para desativar controles (tudo que possa interagir com o dispositivo: teclas de entrada, eventos de mouse, arrastar e soltar arquivos):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
scrcpy --no-control
|
|
||||||
scrcpy -n
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Desligar a tela
|
|
||||||
|
|
||||||
É possível desligar a tela do dispositivo durante o início do espelhamento com uma opção de linha de comando:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
scrcpy --turn-screen-off
|
|
||||||
scrcpy -S
|
|
||||||
```
|
|
||||||
|
|
||||||
Ou apertando `Ctrl`+`o` durante qualquer momento.
|
|
||||||
|
|
||||||
Para ligar novamente, pressione `POWER` (ou `Ctrl`+`p`).
|
|
||||||
|
|
||||||
#### Frames expirados de renderização
|
|
||||||
|
|
||||||
Por padrão, para minimizar a latência, _scrcpy_ sempre renderiza o último frame decodificado disponível e descarta o anterior.
|
|
||||||
|
|
||||||
Para forçar a renderização de todos os frames ( com o custo de aumento de latência), use:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
scrcpy --render-expired-frames
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Mostrar toques
|
|
||||||
|
|
||||||
Para apresentações, pode ser útil mostrar toques físicos(dispositivo físico).
|
|
||||||
|
|
||||||
Android fornece esta funcionalidade nas _Opções do Desenvolvedor_.
|
|
||||||
|
|
||||||
_Scrcpy_ fornece esta opção de ativar esta funcionalidade no início e desativar no encerramento:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
scrcpy --show-touches
|
|
||||||
scrcpy -t
|
|
||||||
```
|
|
||||||
|
|
||||||
Note que isto mostra apenas toques _físicos_ (com o dedo no dispositivo).
|
|
||||||
|
|
||||||
|
|
||||||
### Controle de entrada
|
|
||||||
|
|
||||||
#### Rotacionar a tela do dispositivo
|
|
||||||
|
|
||||||
Pressione `Ctrl`+`r` para mudar entre os modos Retrato e Paisagem.
|
|
||||||
|
|
||||||
Note que só será rotacionado se a aplicação em primeiro plano tiver suporte para o modo requisitado.
|
|
||||||
|
|
||||||
#### Copiar-Colar
|
|
||||||
|
|
||||||
É possível sincronizar áreas de transferência entre computador e o dispositivo,
|
|
||||||
para ambas direções:
|
|
||||||
|
|
||||||
- `Ctrl`+`c` copia a área de transferência do dispositivo para a área de trasferência do computador;
|
|
||||||
- `Ctrl`+`Shift`+`v` copia a área de transferência do computador para a área de transferência do dispositivo;
|
|
||||||
- `Ctrl`+`v` _cola_ a área de transferência do computador como uma sequência de eventos de texto (mas
|
|
||||||
quebra caracteres não-ASCII).
|
|
||||||
|
|
||||||
#### Preferências de injeção de texto
|
|
||||||
|
|
||||||
Existe dois tipos de [eventos][textevents] gerados ao digitar um texto:
|
|
||||||
- _eventos de teclas_, sinalizando que a tecla foi pressionada ou solta;
|
|
||||||
- _eventos de texto_, sinalizando que o texto foi inserido.
|
|
||||||
|
|
||||||
Por padrão, letras são injetadas usando eventos de teclas, assim teclados comportam-se
|
|
||||||
como esperado em jogos (normalmente para tecladas WASD)
|
|
||||||
|
|
||||||
Mas isto pode [causar problemas][prefertext]. Se você encontrar tal problema,
|
|
||||||
pode evitá-lo usando:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
scrcpy --prefer-text
|
|
||||||
```
|
|
||||||
|
|
||||||
(mas isto vai quebrar o comportamento do teclado em jogos)
|
|
||||||
|
|
||||||
[textevents]: https://blog.rom1v.com/2018/03/introducing-scrcpy/#handle-text-input
|
|
||||||
[prefertext]: https://github.com/Genymobile/scrcpy/issues/650#issuecomment-512945343
|
|
||||||
|
|
||||||
|
|
||||||
### Transferência de arquivo
|
|
||||||
|
|
||||||
#### Instalar APK
|
|
||||||
|
|
||||||
Para instalar um APK, arraste e solte o arquivo APK(com extensão `.apk`) na janela _scrcpy_.
|
|
||||||
|
|
||||||
Não existe feedback visual, um log é imprimido no console.
|
|
||||||
|
|
||||||
|
|
||||||
#### Enviar arquivo para o dispositivo
|
|
||||||
|
|
||||||
Para enviar um arquivo para o diretório `/sdcard/` no dispositivo, arraste e solte um arquivo não APK para a janela do
|
|
||||||
_scrcpy_.
|
|
||||||
|
|
||||||
Não existe feedback visual, um log é imprimido no console.
|
|
||||||
|
|
||||||
O diretório alvo pode ser mudado ao iniciar:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
scrcpy --push-target /sdcard/foo/bar/
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
### Encaminhamento de áudio
|
|
||||||
|
|
||||||
Áudio não é encaminhando pelo _scrcpy_. Use [USBaudio] (Apenas linux).
|
|
||||||
|
|
||||||
Também veja [issue #14].
|
|
||||||
|
|
||||||
[USBaudio]: https://github.com/rom1v/usbaudio
|
|
||||||
[issue #14]: https://github.com/Genymobile/scrcpy/issues/14
|
|
||||||
|
|
||||||
|
|
||||||
## Atalhos
|
|
||||||
|
|
||||||
| Ação | Atalho | Atalho (macOS)
|
|
||||||
| ------------------------------------------------------------- |:------------------------------- |:-----------------------------
|
|
||||||
| Alternar para modo de tela cheia | `Ctrl`+`f` | `Cmd`+`f`
|
|
||||||
| Redimensionar janela para pixel-perfect(Escala 1:1) | `Ctrl`+`g` | `Cmd`+`g`
|
|
||||||
| Redimensionar janela para tirar as bordas pretas | `Ctrl`+`x` \| _Clique-duplo¹_ | `Cmd`+`x` \| _Clique-duplo¹_
|
|
||||||
| Clicar em `HOME` | `Ctrl`+`h` \| _Clique-central_ | `Ctrl`+`h` \| _Clique-central_
|
|
||||||
| Clicar em `BACK` | `Ctrl`+`b` \| _Clique-direito²_ | `Cmd`+`b` \| _Clique-direito²_
|
|
||||||
| Clicar em `APP_SWITCH` | `Ctrl`+`s` | `Cmd`+`s`
|
|
||||||
| Clicar em `MENU` | `Ctrl`+`m` | `Ctrl`+`m`
|
|
||||||
| Clicar em `VOLUME_UP` | `Ctrl`+`↑` _(cima)_ | `Cmd`+`↑` _(cima)_
|
|
||||||
| Clicar em `VOLUME_DOWN` | `Ctrl`+`↓` _(baixo)_ | `Cmd`+`↓` _(baixo)_
|
|
||||||
| Clicar em `POWER` | `Ctrl`+`p` | `Cmd`+`p`
|
|
||||||
| Ligar | _Clique-direito²_ | _Clique-direito²_
|
|
||||||
| Desligar a tela do dispositivo | `Ctrl`+`o` | `Cmd`+`o`
|
|
||||||
| Rotacionar tela do dispositivo | `Ctrl`+`r` | `Cmd`+`r`
|
|
||||||
| Expandir painel de notificação | `Ctrl`+`n` | `Cmd`+`n`
|
|
||||||
| Esconder painel de notificação | `Ctrl`+`Shift`+`n` | `Cmd`+`Shift`+`n`
|
|
||||||
| Copiar área de transferência do dispositivo para o computador | `Ctrl`+`c` | `Cmd`+`c`
|
|
||||||
| Colar área de transferência do computador para o dispositivo | `Ctrl`+`v` | `Cmd`+`v`
|
|
||||||
| Copiar área de transferência do computador para dispositivo | `Ctrl`+`Shift`+`v` | `Cmd`+`Shift`+`v`
|
|
||||||
| Ativar/desativar contador de FPS(Frames por segundo) | `Ctrl`+`i` | `Cmd`+`i`
|
|
||||||
|
|
||||||
_¹Clique-duplo em bordas pretas para removê-las._
|
|
||||||
_²Botão direito liga a tela se ela estiver desligada, clique BACK para o contrário._
|
|
||||||
|
|
||||||
|
|
||||||
## Caminhos personalizados
|
|
||||||
|
|
||||||
Para usar um binário específico _adb_, configure seu caminho na variável de ambiente `ADB`:
|
|
||||||
|
|
||||||
ADB=/caminho/para/adb scrcpy
|
|
||||||
|
|
||||||
Para sobrepor o caminho do arquivo `scrcpy-server`, configure seu caminho em
|
|
||||||
`SCRCPY_SERVER_PATH`.
|
|
||||||
|
|
||||||
[useful]: https://github.com/Genymobile/scrcpy/issues/278#issuecomment-429330345
|
|
||||||
|
|
||||||
|
|
||||||
## Por quê _scrcpy_?
|
|
||||||
|
|
||||||
Um colega me desafiou a encontrar um nome impronunciável como [gnirehtet].
|
|
||||||
|
|
||||||
[`strcpy`] copia uma **str**ing; `scrcpy` copia uma **scr**een.
|
|
||||||
|
|
||||||
[gnirehtet]: https://github.com/Genymobile/gnirehtet
|
|
||||||
[`strcpy`]: http://man7.org/linux/man-pages/man3/strcpy.3.html
|
|
||||||
|
|
||||||
|
|
||||||
## Como compilar?
|
|
||||||
|
|
||||||
Veja [BUILD].
|
|
||||||
|
|
||||||
[BUILD]: BUILD.md
|
|
||||||
|
|
||||||
|
|
||||||
## Problemas comuns
|
|
||||||
|
|
||||||
Veja [FAQ](FAQ.md).
|
|
||||||
|
|
||||||
|
|
||||||
## Desenvolvedores
|
|
||||||
|
|
||||||
Leia a [developers page].
|
|
||||||
|
|
||||||
[developers page]: DEVELOP.md
|
|
||||||
|
|
||||||
|
|
||||||
## Licença
|
|
||||||
|
|
||||||
Copyright (C) 2018 Genymobile
|
|
||||||
Copyright (C) 2018-2020 Romain Vimont
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
|
|
||||||
## Artigos
|
|
||||||
|
|
||||||
- [Introducing scrcpy][article-intro]
|
|
||||||
- [Scrcpy now works wirelessly][article-tcpip]
|
|
||||||
|
|
||||||
[article-intro]: https://blog.rom1v.com/2018/03/introducing-scrcpy/
|
|
||||||
[article-tcpip]: https://www.genymotion.com/blog/open-source-project-scrcpy-now-works-wirelessly/
|
|
||||||
@@ -7,33 +7,6 @@
|
|||||||
#include "util/lock.h"
|
#include "util/lock.h"
|
||||||
#include "util/log.h"
|
#include "util/log.h"
|
||||||
|
|
||||||
// Convert window coordinates (as provided by SDL_GetMouseState() to renderer
|
|
||||||
// coordinates (as provided in SDL mouse events)
|
|
||||||
//
|
|
||||||
// See my question:
|
|
||||||
// <https://stackoverflow.com/questions/49111054/how-to-get-mouse-position-on-mouse-wheel-event>
|
|
||||||
static void
|
|
||||||
convert_to_renderer_coordinates(SDL_Renderer *renderer, int *x, int *y) {
|
|
||||||
SDL_Rect viewport;
|
|
||||||
float scale_x, scale_y;
|
|
||||||
SDL_RenderGetViewport(renderer, &viewport);
|
|
||||||
SDL_RenderGetScale(renderer, &scale_x, &scale_y);
|
|
||||||
*x = (int) (*x / scale_x) - viewport.x;
|
|
||||||
*y = (int) (*y / scale_y) - viewport.y;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct point
|
|
||||||
get_mouse_point(struct screen *screen) {
|
|
||||||
int x;
|
|
||||||
int y;
|
|
||||||
SDL_GetMouseState(&x, &y);
|
|
||||||
convert_to_renderer_coordinates(screen->renderer, &x, &y);
|
|
||||||
return (struct point) {
|
|
||||||
.x = x,
|
|
||||||
.y = y,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
static const int ACTION_DOWN = 1;
|
static const int ACTION_DOWN = 1;
|
||||||
static const int ACTION_UP = 1 << 1;
|
static const int ACTION_UP = 1 << 1;
|
||||||
|
|
||||||
@@ -487,11 +460,17 @@ convert_touch(const SDL_TouchFingerEvent *from, struct screen *screen,
|
|||||||
|
|
||||||
to->inject_touch_event.pointer_id = from->fingerId;
|
to->inject_touch_event.pointer_id = from->fingerId;
|
||||||
to->inject_touch_event.position.screen_size = screen->frame_size;
|
to->inject_touch_event.position.screen_size = screen->frame_size;
|
||||||
|
|
||||||
|
int ww;
|
||||||
|
int wh;
|
||||||
|
SDL_GL_GetDrawableSize(screen->window, &ww, &wh);
|
||||||
|
|
||||||
// SDL touch event coordinates are normalized in the range [0; 1]
|
// SDL touch event coordinates are normalized in the range [0; 1]
|
||||||
float x = from->x * screen->content_size.width;
|
int32_t x = from->x * ww;
|
||||||
float y = from->y * screen->content_size.height;
|
int32_t y = from->y * wh;
|
||||||
to->inject_touch_event.position.point =
|
to->inject_touch_event.position.point =
|
||||||
screen_convert_to_frame_coords(screen, x, y);
|
screen_convert_to_frame_coords(screen, x, y);
|
||||||
|
|
||||||
to->inject_touch_event.pressure = from->pressure;
|
to->inject_touch_event.pressure = from->pressure;
|
||||||
to->inject_touch_event.buttons = 0;
|
to->inject_touch_event.buttons = 0;
|
||||||
return true;
|
return true;
|
||||||
@@ -508,13 +487,6 @@ input_manager_process_touch(struct input_manager *im,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
|
||||||
is_outside_device_screen(struct input_manager *im, int x, int y)
|
|
||||||
{
|
|
||||||
return x < 0 || x >= im->screen->content_size.width ||
|
|
||||||
y < 0 || y >= im->screen->content_size.height;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
convert_mouse_button(const SDL_MouseButtonEvent *from, struct screen *screen,
|
convert_mouse_button(const SDL_MouseButtonEvent *from, struct screen *screen,
|
||||||
struct control_msg *to) {
|
struct control_msg *to) {
|
||||||
@@ -552,10 +524,14 @@ input_manager_process_mouse_button(struct input_manager *im,
|
|||||||
action_home(im->controller, ACTION_DOWN | ACTION_UP);
|
action_home(im->controller, ACTION_DOWN | ACTION_UP);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// double-click on black borders resize to fit the device screen
|
// double-click on black borders resize to fit the device screen
|
||||||
if (event->button == SDL_BUTTON_LEFT && event->clicks == 2) {
|
if (event->button == SDL_BUTTON_LEFT && event->clicks == 2) {
|
||||||
bool outside =
|
int x = event->x;
|
||||||
is_outside_device_screen(im, event->x, event->y);
|
int y = event->y;
|
||||||
|
SDL_Rect *r = &im->screen->rect;
|
||||||
|
bool outside = x < r->x || x >= r->x + r->w
|
||||||
|
|| y < r->y || y >= r->y + r->h;
|
||||||
if (outside) {
|
if (outside) {
|
||||||
screen_resize_to_fit(im->screen);
|
screen_resize_to_fit(im->screen);
|
||||||
return;
|
return;
|
||||||
@@ -579,9 +555,15 @@ input_manager_process_mouse_button(struct input_manager *im,
|
|||||||
static bool
|
static bool
|
||||||
convert_mouse_wheel(const SDL_MouseWheelEvent *from, struct screen *screen,
|
convert_mouse_wheel(const SDL_MouseWheelEvent *from, struct screen *screen,
|
||||||
struct control_msg *to) {
|
struct control_msg *to) {
|
||||||
|
|
||||||
|
// mouse_x and mouse_y are expressed in pixels relative to the window
|
||||||
|
int mouse_x;
|
||||||
|
int mouse_y;
|
||||||
|
SDL_GetMouseState(&mouse_x, &mouse_y);
|
||||||
|
|
||||||
struct position position = {
|
struct position position = {
|
||||||
.screen_size = screen->frame_size,
|
.screen_size = screen->frame_size,
|
||||||
.point = get_mouse_point(screen),
|
.point = screen_convert_to_frame_coords(screen, mouse_x, mouse_y),
|
||||||
};
|
};
|
||||||
|
|
||||||
to->type = CONTROL_MSG_TYPE_INJECT_SCROLL_EVENT;
|
to->type = CONTROL_MSG_TYPE_INJECT_SCROLL_EVENT;
|
||||||
|
|||||||
@@ -109,10 +109,9 @@ static int
|
|||||||
event_watcher(void *data, SDL_Event *event) {
|
event_watcher(void *data, SDL_Event *event) {
|
||||||
(void) data;
|
(void) data;
|
||||||
if (event->type == SDL_WINDOWEVENT
|
if (event->type == SDL_WINDOWEVENT
|
||||||
&& event->window.event == SDL_WINDOWEVENT_SIZE_CHANGED) {
|
&& event->window.event == SDL_WINDOWEVENT_RESIZED) {
|
||||||
// In practice, it seems to always be called from the same thread in
|
// called from another thread, not very safe, but it's a workaround!
|
||||||
// that specific case. Anyway, it's just a workaround.
|
screen_render(&screen);
|
||||||
screen_handle_window_event(&screen, &event->window);
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
140
app/src/screen.c
140
app/src/screen.c
@@ -87,6 +87,26 @@ get_preferred_display_bounds(struct size *bounds) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Indicate if the width should be kept on computing the optimal rectangle size
|
||||||
|
// to display the content in the window.
|
||||||
|
// Return true if the width should be kept, false if the height should be kept.
|
||||||
|
static bool
|
||||||
|
should_keep_width(struct size window_size, struct size content_size) {
|
||||||
|
// 32 bits because we need to multiply two 16 bits values
|
||||||
|
uint32_t ww = window_size.width;
|
||||||
|
uint32_t wh = window_size.height;
|
||||||
|
uint32_t cw = content_size.width;
|
||||||
|
uint32_t ch = content_size.height;
|
||||||
|
|
||||||
|
// To avoid keeping alternatively width and height on successive resizes
|
||||||
|
// due to rounding to integer, always prefer height (arbitrarily) if in the
|
||||||
|
// error range.
|
||||||
|
|
||||||
|
// err = ceil of content aspect ratio
|
||||||
|
unsigned err = (cw + ch - 1) / ch;
|
||||||
|
return cw * wh > ch * (ww + err);
|
||||||
|
}
|
||||||
|
|
||||||
// return the optimal size of the window, with the following constraints:
|
// return the optimal size of the window, with the following constraints:
|
||||||
// - it attempts to keep at least one dimension of the current_size (i.e. it
|
// - it attempts to keep at least one dimension of the current_size (i.e. it
|
||||||
// crops the black borders)
|
// crops the black borders)
|
||||||
@@ -99,40 +119,33 @@ get_optimal_size(struct size current_size, struct size content_size) {
|
|||||||
return current_size;
|
return current_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct size display_size;
|
struct size window_size;
|
||||||
// 32 bits because we need to multiply two 16 bits values
|
|
||||||
uint32_t w;
|
|
||||||
uint32_t h;
|
|
||||||
|
|
||||||
|
struct size display_size;
|
||||||
if (!get_preferred_display_bounds(&display_size)) {
|
if (!get_preferred_display_bounds(&display_size)) {
|
||||||
// could not get display bounds, do not constraint the size
|
// could not get display bounds, do not constraint the size
|
||||||
w = current_size.width;
|
window_size.width = current_size.width;
|
||||||
h = current_size.height;
|
window_size.height = current_size.height;
|
||||||
} else {
|
} else {
|
||||||
w = MIN(current_size.width, display_size.width);
|
window_size.width = MIN(current_size.width, display_size.width);
|
||||||
h = MIN(current_size.height, display_size.height);
|
window_size.height = MIN(current_size.height, display_size.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (h == w * content_size.height / content_size.width
|
bool keep_width = should_keep_width(window_size, content_size);
|
||||||
|| w == h * content_size.width / content_size.height) {
|
|
||||||
// The size is already optimal, if we ignore rounding errors due to
|
|
||||||
// integer window dimensions
|
|
||||||
return (struct size) {w, h};
|
|
||||||
}
|
|
||||||
|
|
||||||
bool keep_width = content_size.width * h > content_size.height * w;
|
|
||||||
if (keep_width) {
|
if (keep_width) {
|
||||||
// remove black borders on top and bottom
|
// remove black borders on top and bottom
|
||||||
h = content_size.height * w / content_size.width;
|
window_size.height = content_size.height * window_size.width
|
||||||
|
/ content_size.width;
|
||||||
} else {
|
} else {
|
||||||
// remove black borders on left and right (or none at all if it already
|
// remove black borders on left and right (or none at all if it already
|
||||||
// fits)
|
// fits)
|
||||||
w = content_size.width * h / content_size.height;
|
window_size.width = content_size.width * window_size.height
|
||||||
|
/ content_size.height;
|
||||||
}
|
}
|
||||||
|
|
||||||
// w and h must fit into 16 bits
|
// width and height must fit into 16 bits
|
||||||
assert(w < 0x10000 && h < 0x10000);
|
assert(window_size.width < 0x10000 && window_size.height < 0x10000);
|
||||||
return (struct size) {w, h};
|
return window_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
// same as get_optimal_size(), but read the current size from the window
|
// same as get_optimal_size(), but read the current size from the window
|
||||||
@@ -169,6 +182,34 @@ get_initial_optimal_size(struct size content_size, uint16_t req_width,
|
|||||||
return window_size;
|
return window_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
update_content_rect(struct screen *screen) {
|
||||||
|
int w;
|
||||||
|
int h;
|
||||||
|
SDL_GL_GetDrawableSize(screen->window, &w, &h);
|
||||||
|
|
||||||
|
struct size window_size = {w, h};
|
||||||
|
uint16_t ww = window_size.width;
|
||||||
|
uint16_t wh = window_size.height;
|
||||||
|
uint16_t cw = screen->content_size.width;
|
||||||
|
uint16_t ch = screen->content_size.height;
|
||||||
|
|
||||||
|
SDL_Rect *rect = &screen->rect;
|
||||||
|
|
||||||
|
bool keep_width = should_keep_width(window_size, screen->content_size);
|
||||||
|
if (keep_width) {
|
||||||
|
rect->x = 0;
|
||||||
|
rect->w = ww;
|
||||||
|
rect->h = ww * ch / cw;
|
||||||
|
rect->y = (wh - rect->h) / 2;
|
||||||
|
} else {
|
||||||
|
rect->y = 0;
|
||||||
|
rect->h = wh;
|
||||||
|
rect->w = wh * cw / ch;
|
||||||
|
rect->x = (ww - rect->w) / 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
screen_init(struct screen *screen) {
|
screen_init(struct screen *screen) {
|
||||||
*screen = (struct screen) SCREEN_INITIALIZER;
|
*screen = (struct screen) SCREEN_INITIALIZER;
|
||||||
@@ -258,14 +299,7 @@ screen_init_rendering(struct screen *screen, const char *window_title,
|
|||||||
const char *renderer_name = r ? NULL : renderer_info.name;
|
const char *renderer_name = r ? NULL : renderer_info.name;
|
||||||
LOGI("Renderer: %s", renderer_name ? renderer_name : "(unknown)");
|
LOGI("Renderer: %s", renderer_name ? renderer_name : "(unknown)");
|
||||||
|
|
||||||
if (SDL_RenderSetLogicalSize(screen->renderer, content_size.width,
|
// stats with "opengl"
|
||||||
content_size.height)) {
|
|
||||||
LOGE("Could not set renderer logical size: %s", SDL_GetError());
|
|
||||||
screen_destroy(screen);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// starts with "opengl"
|
|
||||||
screen->use_opengl = renderer_name && !strncmp(renderer_name, "opengl", 6);
|
screen->use_opengl = renderer_name && !strncmp(renderer_name, "opengl", 6);
|
||||||
if (screen->use_opengl) {
|
if (screen->use_opengl) {
|
||||||
struct sc_opengl *gl = &screen->gl;
|
struct sc_opengl *gl = &screen->gl;
|
||||||
@@ -342,13 +376,6 @@ screen_set_rotation(struct screen *screen, unsigned rotation) {
|
|||||||
struct size new_content_size =
|
struct size new_content_size =
|
||||||
get_rotated_size(screen->frame_size, rotation);
|
get_rotated_size(screen->frame_size, rotation);
|
||||||
|
|
||||||
if (SDL_RenderSetLogicalSize(screen->renderer,
|
|
||||||
new_content_size.width,
|
|
||||||
new_content_size.height)) {
|
|
||||||
LOGE("Could not set renderer logical size: %s", SDL_GetError());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct size windowed_size = get_windowed_window_size(screen);
|
struct size windowed_size = get_windowed_window_size(screen);
|
||||||
struct size target_size = {
|
struct size target_size = {
|
||||||
.width = (uint32_t) windowed_size.width * new_content_size.width
|
.width = (uint32_t) windowed_size.width * new_content_size.width
|
||||||
@@ -363,6 +390,7 @@ screen_set_rotation(struct screen *screen, unsigned rotation) {
|
|||||||
screen->rotation = rotation;
|
screen->rotation = rotation;
|
||||||
LOGI("Display rotation set to %u", rotation);
|
LOGI("Display rotation set to %u", rotation);
|
||||||
|
|
||||||
|
update_content_rect(screen);
|
||||||
screen_render(screen);
|
screen_render(screen);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -371,18 +399,11 @@ static bool
|
|||||||
prepare_for_frame(struct screen *screen, struct size new_frame_size) {
|
prepare_for_frame(struct screen *screen, struct size new_frame_size) {
|
||||||
if (screen->frame_size.width != new_frame_size.width
|
if (screen->frame_size.width != new_frame_size.width
|
||||||
|| screen->frame_size.height != new_frame_size.height) {
|
|| screen->frame_size.height != new_frame_size.height) {
|
||||||
struct size new_content_size =
|
|
||||||
get_rotated_size(new_frame_size, screen->rotation);
|
|
||||||
if (SDL_RenderSetLogicalSize(screen->renderer,
|
|
||||||
new_content_size.width,
|
|
||||||
new_content_size.height)) {
|
|
||||||
LOGE("Could not set renderer logical size: %s", SDL_GetError());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// frame dimension changed, destroy texture
|
// frame dimension changed, destroy texture
|
||||||
SDL_DestroyTexture(screen->texture);
|
SDL_DestroyTexture(screen->texture);
|
||||||
|
|
||||||
|
struct size new_content_size =
|
||||||
|
get_rotated_size(new_frame_size, screen->rotation);
|
||||||
struct size content_size = screen->content_size;
|
struct size content_size = screen->content_size;
|
||||||
struct size windowed_size = get_windowed_window_size(screen);
|
struct size windowed_size = get_windowed_window_size(screen);
|
||||||
struct size target_size = {
|
struct size target_size = {
|
||||||
@@ -434,6 +455,7 @@ screen_update_frame(struct screen *screen, struct video_buffer *vb) {
|
|||||||
mutex_unlock(vb->mutex);
|
mutex_unlock(vb->mutex);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
update_content_rect(screen);
|
||||||
update_texture(screen, frame);
|
update_texture(screen, frame);
|
||||||
mutex_unlock(vb->mutex);
|
mutex_unlock(vb->mutex);
|
||||||
|
|
||||||
@@ -441,11 +463,17 @@ screen_update_frame(struct screen *screen, struct video_buffer *vb) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
screen_window_resized(struct screen *screen) {
|
||||||
|
update_content_rect(screen);
|
||||||
|
screen_render(screen);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
screen_render(struct screen *screen) {
|
screen_render(struct screen *screen) {
|
||||||
SDL_RenderClear(screen->renderer);
|
SDL_RenderClear(screen->renderer);
|
||||||
if (screen->rotation == 0) {
|
if (screen->rotation == 0) {
|
||||||
SDL_RenderCopy(screen->renderer, screen->texture, NULL, NULL);
|
SDL_RenderCopy(screen->renderer, screen->texture, NULL, &screen->rect);
|
||||||
} else {
|
} else {
|
||||||
// rotation in RenderCopyEx() is clockwise, while screen->rotation is
|
// rotation in RenderCopyEx() is clockwise, while screen->rotation is
|
||||||
// counterclockwise (to be consistent with --lock-video-orientation)
|
// counterclockwise (to be consistent with --lock-video-orientation)
|
||||||
@@ -455,12 +483,14 @@ screen_render(struct screen *screen) {
|
|||||||
SDL_Rect *dstrect = NULL;
|
SDL_Rect *dstrect = NULL;
|
||||||
SDL_Rect rect;
|
SDL_Rect rect;
|
||||||
if (screen->rotation & 1) {
|
if (screen->rotation & 1) {
|
||||||
struct size size = screen->content_size;
|
rect.x = screen->rect.x + (screen->rect.w - screen->rect.h) / 2;
|
||||||
rect.x = (size.width - size.height) / 2;
|
rect.y = screen->rect.y + (screen->rect.h - screen->rect.w) / 2;
|
||||||
rect.y = (size.height - size.width) / 2;
|
rect.w = screen->rect.h;
|
||||||
rect.w = size.height;
|
rect.h = screen->rect.w;
|
||||||
rect.h = size.width;
|
|
||||||
dstrect = ▭
|
dstrect = ▭
|
||||||
|
} else {
|
||||||
|
assert(screen->rotation == 2);
|
||||||
|
dstrect = &screen->rect;
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_RenderCopyEx(screen->renderer, screen->texture, NULL, dstrect,
|
SDL_RenderCopyEx(screen->renderer, screen->texture, NULL, dstrect,
|
||||||
@@ -539,7 +569,7 @@ screen_handle_window_event(struct screen *screen,
|
|||||||
// window is maximized or fullscreen is enabled.
|
// window is maximized or fullscreen is enabled.
|
||||||
screen->windowed_window_size = get_window_size(screen->window);
|
screen->windowed_window_size = get_window_size(screen->window);
|
||||||
}
|
}
|
||||||
screen_render(screen);
|
screen_window_resized(screen);
|
||||||
break;
|
break;
|
||||||
case SDL_WINDOWEVENT_MAXIMIZED:
|
case SDL_WINDOWEVENT_MAXIMIZED:
|
||||||
// The backup size must be non-nul.
|
// The backup size must be non-nul.
|
||||||
@@ -568,6 +598,12 @@ screen_convert_to_frame_coords(struct screen *screen, int32_t x, int32_t y) {
|
|||||||
|
|
||||||
int32_t w = screen->content_size.width;
|
int32_t w = screen->content_size.width;
|
||||||
int32_t h = screen->content_size.height;
|
int32_t h = screen->content_size.height;
|
||||||
|
|
||||||
|
// scale
|
||||||
|
x = (x - screen->rect.x) * w / screen->rect.w;
|
||||||
|
y = (y - screen->rect.y) * h / screen->rect.h;
|
||||||
|
|
||||||
|
// rotate
|
||||||
struct point result;
|
struct point result;
|
||||||
switch (rotation) {
|
switch (rotation) {
|
||||||
case 0:
|
case 0:
|
||||||
|
|||||||
@@ -28,6 +28,8 @@ struct screen {
|
|||||||
struct size windowed_window_size_backup;
|
struct size windowed_window_size_backup;
|
||||||
// client rotation: 0, 1, 2 or 3 (x90 degrees counterclockwise)
|
// client rotation: 0, 1, 2 or 3 (x90 degrees counterclockwise)
|
||||||
unsigned rotation;
|
unsigned rotation;
|
||||||
|
// rectangle of the content (excluding black borders)
|
||||||
|
struct SDL_Rect rect;
|
||||||
bool has_frame;
|
bool has_frame;
|
||||||
bool fullscreen;
|
bool fullscreen;
|
||||||
bool maximized;
|
bool maximized;
|
||||||
@@ -58,6 +60,12 @@ struct screen {
|
|||||||
.height = 0, \
|
.height = 0, \
|
||||||
}, \
|
}, \
|
||||||
.rotation = 0, \
|
.rotation = 0, \
|
||||||
|
.rect = { \
|
||||||
|
.x = 0, \
|
||||||
|
.y = 0, \
|
||||||
|
.w = 0, \
|
||||||
|
.h = 0, \
|
||||||
|
}, \
|
||||||
.has_frame = false, \
|
.has_frame = false, \
|
||||||
.fullscreen = false, \
|
.fullscreen = false, \
|
||||||
.maximized = false, \
|
.maximized = false, \
|
||||||
@@ -90,6 +98,10 @@ screen_destroy(struct screen *screen);
|
|||||||
bool
|
bool
|
||||||
screen_update_frame(struct screen *screen, struct video_buffer *vb);
|
screen_update_frame(struct screen *screen, struct video_buffer *vb);
|
||||||
|
|
||||||
|
// update content after window resizing
|
||||||
|
void
|
||||||
|
screen_window_resized(struct screen *screen);
|
||||||
|
|
||||||
// render the texture to the renderer
|
// render the texture to the renderer
|
||||||
void
|
void
|
||||||
screen_render(struct screen *screen);
|
screen_render(struct screen *screen);
|
||||||
|
|||||||
@@ -15,6 +15,6 @@ cpu = 'i686'
|
|||||||
endian = 'little'
|
endian = 'little'
|
||||||
|
|
||||||
[properties]
|
[properties]
|
||||||
prebuilt_ffmpeg_shared = 'ffmpeg-4.2.2-win32-shared'
|
prebuilt_ffmpeg_shared = 'ffmpeg-4.2.1-win32-shared'
|
||||||
prebuilt_ffmpeg_dev = 'ffmpeg-4.2.2-win32-dev'
|
prebuilt_ffmpeg_dev = 'ffmpeg-4.2.1-win32-dev'
|
||||||
prebuilt_sdl2 = 'SDL2-2.0.12/i686-w64-mingw32'
|
prebuilt_sdl2 = 'SDL2-2.0.10/i686-w64-mingw32'
|
||||||
|
|||||||
@@ -15,6 +15,6 @@ cpu = 'x86_64'
|
|||||||
endian = 'little'
|
endian = 'little'
|
||||||
|
|
||||||
[properties]
|
[properties]
|
||||||
prebuilt_ffmpeg_shared = 'ffmpeg-4.2.2-win64-shared'
|
prebuilt_ffmpeg_shared = 'ffmpeg-4.2.1-win64-shared'
|
||||||
prebuilt_ffmpeg_dev = 'ffmpeg-4.2.2-win64-dev'
|
prebuilt_ffmpeg_dev = 'ffmpeg-4.2.1-win64-dev'
|
||||||
prebuilt_sdl2 = 'SDL2-2.0.12/x86_64-w64-mingw32'
|
prebuilt_sdl2 = 'SDL2-2.0.10/x86_64-w64-mingw32'
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
project('scrcpy', 'c',
|
project('scrcpy', 'c',
|
||||||
version: '1.13',
|
version: '1.12.1',
|
||||||
meson_version: '>= 0.48',
|
meson_version: '>= 0.48',
|
||||||
default_options: [
|
default_options: [
|
||||||
'c_std=c11',
|
'c_std=c11',
|
||||||
|
|||||||
@@ -10,29 +10,29 @@ prepare-win32: prepare-sdl2 prepare-ffmpeg-shared-win32 prepare-ffmpeg-dev-win32
|
|||||||
prepare-win64: prepare-sdl2 prepare-ffmpeg-shared-win64 prepare-ffmpeg-dev-win64 prepare-adb
|
prepare-win64: prepare-sdl2 prepare-ffmpeg-shared-win64 prepare-ffmpeg-dev-win64 prepare-adb
|
||||||
|
|
||||||
prepare-ffmpeg-shared-win32:
|
prepare-ffmpeg-shared-win32:
|
||||||
@./prepare-dep https://ffmpeg.zeranoe.com/builds/win32/shared/ffmpeg-4.2.2-win32-shared.zip \
|
@./prepare-dep https://ffmpeg.zeranoe.com/builds/win32/shared/ffmpeg-4.2.1-win32-shared.zip \
|
||||||
ab5d603aaa54de360db2c2ffe378c82376b9343ea1175421dd644639aa07ee31 \
|
9208255f409410d95147151d7e829b5699bf8d91bfe1e81c3f470f47c2fa66d2 \
|
||||||
ffmpeg-4.2.2-win32-shared
|
ffmpeg-4.2.1-win32-shared
|
||||||
|
|
||||||
prepare-ffmpeg-dev-win32:
|
prepare-ffmpeg-dev-win32:
|
||||||
@./prepare-dep https://ffmpeg.zeranoe.com/builds/win32/dev/ffmpeg-4.2.2-win32-dev.zip \
|
@./prepare-dep https://ffmpeg.zeranoe.com/builds/win32/dev/ffmpeg-4.2.1-win32-dev.zip \
|
||||||
8d224be567a2950cad4be86f4aabdd045bfa52ad758e87c72cedd278613bc6c8 \
|
c3469e6c5f031cbcc8cba88dee92d6548c5c6b6ff14f4097f18f72a92d0d70c4 \
|
||||||
ffmpeg-4.2.2-win32-dev
|
ffmpeg-4.2.1-win32-dev
|
||||||
|
|
||||||
prepare-ffmpeg-shared-win64:
|
prepare-ffmpeg-shared-win64:
|
||||||
@./prepare-dep https://ffmpeg.zeranoe.com/builds/win64/shared/ffmpeg-4.2.2-win64-shared.zip \
|
@./prepare-dep https://ffmpeg.zeranoe.com/builds/win64/shared/ffmpeg-4.2.1-win64-shared.zip \
|
||||||
5aedf268952b7d9f6541dbfcb47cd86a7e7881a3b7ba482fd3bc4ca33bda7bf5 \
|
55063d3cf750a75485c7bf196031773d81a1b25d0980c7db48ecfc7701a42331 \
|
||||||
ffmpeg-4.2.2-win64-shared
|
ffmpeg-4.2.1-win64-shared
|
||||||
|
|
||||||
prepare-ffmpeg-dev-win64:
|
prepare-ffmpeg-dev-win64:
|
||||||
@./prepare-dep https://ffmpeg.zeranoe.com/builds/win64/dev/ffmpeg-4.2.2-win64-dev.zip \
|
@./prepare-dep https://ffmpeg.zeranoe.com/builds/win64/dev/ffmpeg-4.2.1-win64-dev.zip \
|
||||||
f4885f859c5b0d6663c2a0a4c1cf035b1c60b146402790b796bd3ad84f4f3ca2 \
|
5af393be5f25c0a71aa29efce768e477c35347f7f8e0d9696767d5b9d405b74e \
|
||||||
ffmpeg-4.2.2-win64-dev
|
ffmpeg-4.2.1-win64-dev
|
||||||
|
|
||||||
prepare-sdl2:
|
prepare-sdl2:
|
||||||
@./prepare-dep https://libsdl.org/release/SDL2-devel-2.0.12-mingw.tar.gz \
|
@./prepare-dep https://libsdl.org/release/SDL2-devel-2.0.10-mingw.tar.gz \
|
||||||
e614a60f797e35ef9f3f96aef3dc6a1d786de3cc7ca6216f97e435c0b6aafc46 \
|
a90a7cddaec4996f4d7be6d80c57ec69b062e132bffc513965f99217f603274a \
|
||||||
SDL2-2.0.12
|
SDL2-2.0.10
|
||||||
|
|
||||||
prepare-adb:
|
prepare-adb:
|
||||||
@./prepare-dep https://dl.google.com/android/repository/platform-tools_r29.0.5-windows.zip \
|
@./prepare-dep https://dl.google.com/android/repository/platform-tools_r29.0.5-windows.zip \
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ android {
|
|||||||
applicationId "com.genymobile.scrcpy"
|
applicationId "com.genymobile.scrcpy"
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 29
|
targetSdkVersion 29
|
||||||
versionCode 15
|
versionCode 14
|
||||||
versionName "1.13"
|
versionName "1.12.1"
|
||||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||||
}
|
}
|
||||||
buildTypes {
|
buildTypes {
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
set -e
|
set -e
|
||||||
|
|
||||||
SCRCPY_DEBUG=false
|
SCRCPY_DEBUG=false
|
||||||
SCRCPY_VERSION_NAME=1.13
|
SCRCPY_VERSION_NAME=1.12.1
|
||||||
|
|
||||||
PLATFORM=${ANDROID_PLATFORM:-29}
|
PLATFORM=${ANDROID_PLATFORM:-29}
|
||||||
BUILD_TOOLS=${ANDROID_BUILD_TOOLS:-29.0.2}
|
BUILD_TOOLS=${ANDROID_BUILD_TOOLS:-29.0.2}
|
||||||
|
|||||||
Reference in New Issue
Block a user