Compare commits

..

6 Commits

Author SHA1 Message Date
c37d455fa2 wip 2021-05-02 18:27:13 +02:00
6e8df74c41 serial in server_params 2021-05-02 17:22:03 +02:00
52f5c6d4c1 server_params_copy 2021-05-02 17:22:03 +02:00
efb531943d reorder server server_params 2021-05-02 17:22:03 +02:00
4dcda82582 ARRAY_LEN 2021-05-02 17:22:03 +02:00
5369c4f754 Serialize clean-up configuration
This avoids to pass each option as individual parameter and parse them
manually (it's still "manual" in the Parcelable implementation).

Refs #824 <https://github.com/Genymobile/scrcpy/pull/824#issuecomment-780319422>

Reviewed-by: Yu-Chen Lin <npes87184@gmail.com>
2021-05-01 14:14:32 +02:00
62 changed files with 1013 additions and 4097 deletions

137
BUILD.md
View File

@ -2,43 +2,11 @@
Here are the instructions to build _scrcpy_ (client and server).
You may want to build only the client: the server binary, which will be pushed
to the Android device, does not depend on your system and architecture. In that
case, use the [prebuilt server] (so you will not need Java or the Android SDK).
## Simple
If you just want to install the latest release from `master`, follow this
simplified process.
First, you need to install the required packages:
```bash
# for Debian/Ubuntu
sudo apt install ffmpeg libsdl2-2.0-0 adb wget \
gcc git pkg-config meson ninja-build libsdl2-dev \
libavcodec-dev libavdevice-dev libavformat-dev libavutil-dev
```
Then clone the repo and execute the installation script
([source](install_release.sh)):
```bash
git clone https://github.com/Genymobile/scrcpy
cd scrcpy
./install_release.sh
```
When a new release is out, update the repo and reinstall:
```bash
git pull
./install_release.sh
```
To uninstall:
```bash
sudo ninja -Cbuild-auto uninstall
```
[prebuilt server]: #prebuilt-server
## Branches
@ -91,11 +59,12 @@ Install the required packages from your package manager.
sudo apt install ffmpeg libsdl2-2.0-0 adb
# client build dependencies
sudo apt install gcc git pkg-config meson ninja-build libsdl2-dev \
libavcodec-dev libavdevice-dev libavformat-dev libavutil-dev
sudo apt install gcc git pkg-config meson ninja-build \
libavcodec-dev libavformat-dev libavutil-dev \
libsdl2-dev
# server build dependencies
sudo apt install openjdk-11-jdk
sudo apt install openjdk-8-jdk
```
On old versions (like Ubuntu 16.04), `meson` is too old. In that case, install
@ -137,13 +106,13 @@ sudo apt install mingw-w64 mingw-w64-tools
You also need the JDK to build the server:
```bash
sudo apt install openjdk-11-jdk
sudo apt install openjdk-8-jdk
```
Then generate the releases:
```bash
./release.sh
make -f Makefile.CrossWindows
```
It will generate win32 and win64 releases into `dist/`.
@ -204,12 +173,12 @@ brew install pkg-config meson
```
Additionally, if you want to build the server, install Java 8 from Caskroom, and
make it available from the `PATH`:
make it avaliable from the `PATH`:
```bash
brew tap homebrew/cask-versions
brew install adoptopenjdk/openjdk/adoptopenjdk11
export JAVA_HOME="$(/usr/libexec/java_home --version 1.11)"
brew cask install adoptopenjdk/openjdk/adoptopenjdk8
export JAVA_HOME="$(/usr/libexec/java_home --version 1.8)"
export PATH="$JAVA_HOME/bin:$PATH"
```
@ -220,27 +189,8 @@ See [pierlon/scrcpy-docker](https://github.com/pierlon/scrcpy-docker).
## Common steps
**As a non-root user**, clone the project:
```bash
git clone https://github.com/Genymobile/scrcpy
cd scrcpy
```
### Build
You may want to build only the client: the server binary, which will be pushed
to the Android device, does not depend on your system and architecture. In that
case, use the [prebuilt server] (so you will not need Java or the Android SDK).
[prebuilt server]: #option-2-use-prebuilt-server
#### Option 1: Build everything from sources
Install the [Android SDK] (_Android Studio_), and set `ANDROID_SDK_ROOT` to its
directory. For example:
If you want to build the server, install the [Android SDK] (_Android Studio_),
and set `ANDROID_SDK_ROOT` to its directory. For example:
[Android SDK]: https://developer.android.com/studio/index.html
@ -253,11 +203,20 @@ export ANDROID_SDK_ROOT=~/Library/Android/sdk
set ANDROID_SDK_ROOT=%LOCALAPPDATA%\Android\sdk
```
If you don't want to build the server, use the [prebuilt server].
Clone the project:
```bash
git clone https://github.com/Genymobile/scrcpy
cd scrcpy
```
Then, build:
```bash
meson x --buildtype release --strip -Db_lto=true
ninja -Cx # DO NOT RUN AS ROOT
ninja -Cx
```
_Note: `ninja` [must][ninja-user] be run as a non-root user (only `ninja
@ -266,27 +225,9 @@ install` must be run as root)._
[ninja-user]: https://github.com/Genymobile/scrcpy/commit/4c49b27e9f6be02b8e63b508b60535426bd0291a
#### Option 2: Use prebuilt server
### Run
- [`scrcpy-server-v1.18`][direct-scrcpy-server]
_(SHA-256: 641c5c6beda9399dfae72d116f5ff43b5ed1059d871c9ebc3f47610fd33c51a3)_
[direct-scrcpy-server]: https://github.com/Genymobile/scrcpy/releases/download/v1.18/scrcpy-server-v1.18
Download the prebuilt server somewhere, and specify its path during the Meson
configuration:
```bash
meson x --buildtype release --strip -Db_lto=true \
-Dprebuilt_server=/path/to/scrcpy-server
ninja -Cx # DO NOT RUN AS ROOT
```
The server only works with a matching client version (this server works with the
`master` branch).
### Run without installing:
To run without installing:
```bash
./run x [options]
@ -301,16 +242,32 @@ After a successful build, you can install _scrcpy_ on the system:
sudo ninja -Cx install # without sudo on Windows
```
This installs three files:
This installs two files:
- `/usr/local/bin/scrcpy`
- `/usr/local/share/scrcpy/scrcpy-server`
- `/usr/local/share/man/man1/scrcpy.1`
Just remove them to "uninstall" the application.
You can then [run](README.md#run) _scrcpy_.
### Uninstall
## Prebuilt server
- [`scrcpy-server-v1.17`][direct-scrcpy-server]
_(SHA-256: 11b5ad2d1bc9b9730fb7254a78efd71a8ff46b1938ff468e47a21b653a1b6725_
[direct-scrcpy-server]: https://github.com/Genymobile/scrcpy/releases/download/v1.17/scrcpy-server-v1.17
Download the prebuilt server somewhere, and specify its path during the Meson
configuration:
```bash
sudo ninja -Cx uninstall # without sudo on Windows
meson x --buildtype release --strip -Db_lto=true \
-Dprebuilt_server=/path/to/scrcpy-server
ninja -Cx
sudo ninja -Cx install
```
The server only works with a matching client version (this server works with the
`master` branch).

View File

@ -211,7 +211,7 @@ There are two [frames][video_buffer] simultaneously in memory:
- the **rendering** frame, rendered in a texture from the main thread.
When a new decoded frame is available, the decoder _swaps_ the decoding and
rendering frame (with proper synchronization). Thus, it immediately starts
rendering frame (with proper synchronization). Thus, it immediatly starts
to decode a new frame while the main thread renders the last one.
If a [recorder] is present (i.e. `--record` is enabled), then it muxes the raw

217
FAQ.it.md
View File

@ -1,217 +0,0 @@
_Apri le [FAQ](FAQ.md) originali e sempre aggiornate._
# Domande Frequenti (FAQ)
Questi sono i problemi più comuni riportati e i loro stati.
## Problemi di `adb`
`scrcpy` esegue comandi `adb` per inizializzare la connessione con il dispositivo. Se `adb` fallisce, scrcpy non funzionerà.
In questo caso sarà stampato questo errore:
> ERROR: "adb push" returned with value 1
Questo solitamente non è un bug di _scrcpy_, ma un problema del tuo ambiente.
Per trovare la causa, esegui:
```bash
adb devices
```
### `adb` not found (`adb` non trovato)
È necessario che `adb` sia accessibile dal tuo `PATH`.
In Windows, la cartella corrente è nel tuo `PATH` e `adb.exe` è incluso nella release, perciò dovrebbe già essere pronto all'uso.
### Device unauthorized (Dispositivo non autorizzato)
Controlla [stackoverflow][device-unauthorized] (in inglese).
[device-unauthorized]: https://stackoverflow.com/questions/23081263/adb-android-device-unauthorized
### Device not detected (Dispositivo non rilevato)
> adb: error: failed to get feature set: no devices/emulators found
Controlla di aver abilitato correttamente il [debug con adb][enable-adb] (link in inglese).
Se il tuo dispositivo non è rilevato, potresti avere bisogno dei [driver][drivers] (link in inglese) (in Windows).
[enable-adb]: https://developer.android.com/studio/command-line/adb.html#Enabling
[drivers]: https://developer.android.com/studio/run/oem-usb.html
### Più dispositivi connessi
Se più dispositivi sono connessi, riscontrerai questo errore:
> adb: error: failed to get feature set: more than one device/emulator
l'identificatore del tuo dispositivo deve essere fornito:
```bash
scrcpy -s 01234567890abcdef
```
Notare che se il tuo dispositivo è connesso mediante TCP/IP, riscontrerai questo messaggio:
> adb: error: more than one device/emulator
> ERROR: "adb reverse" returned with value 1
> WARN: 'adb reverse' failed, fallback to 'adb forward'
Questo è un problema atteso (a causa di un bug di una vecchia versione di Android, vedi [#5] (link in inglese)), ma in quel caso scrcpy ripiega su un metodo differente, il quale dovrebbe funzionare.
[#5]: https://github.com/Genymobile/scrcpy/issues/5
### Conflitti tra versioni di adb
> adb server version (41) doesn't match this client (39); killing...
L'errore compare quando usi più versioni di `adb` simultaneamente. Devi trovare il programma che sta utilizzando una versione differente di `adb` e utilizzare la stessa versione dappertutto.
Puoi sovrascrivere i binari di `adb` nell'altro programma, oppure chiedere a _scrcpy_ di usare un binario specifico di `adb`, impostando la variabile d'ambiente `ADB`:
```bash
set ADB=/path/to/your/adb
scrcpy
```
### Device disconnected (Dispositivo disconnesso)
Se _scrcpy_ si interrompe con l'avviso "Device disconnected", allora la connessione `adb` è stata chiusa.
Prova con un altro cavo USB o inseriscilo in un'altra porta USB. Vedi [#281] (in inglese) e [#283] (in inglese).
[#281]: https://github.com/Genymobile/scrcpy/issues/281
[#283]: https://github.com/Genymobile/scrcpy/issues/283
## Problemi di controllo
### Mouse e tastiera non funzionano
Su alcuni dispositivi potresti dover abilitare un opzione che permette l'[input simulato][simulating input] (link in inglese). Nelle opzioni sviluppatore, abilita:
> **Debug USB (Impostazioni di sicurezza)**
> _Permetti la concessione dei permessi e la simulazione degli input mediante il debug USB_
<!--- Ho tradotto personalmente il testo sopra, non conosco esattamente il testo reale --->
[simulating input]: https://github.com/Genymobile/scrcpy/issues/70#issuecomment-373286323
### I caratteri speciali non funzionano
Iniettare del testo in input è [limitato ai caratteri ASCII][text-input] (link in inglese). Un trucco permette di iniettare dei [caratteri accentati][accented-characters] (link in inglese), ma questo è tutto. Vedi [#37] (link in inglese).
[text-input]: https://github.com/Genymobile/scrcpy/issues?q=is%3Aopen+is%3Aissue+label%3Aunicode
[accented-characters]: https://blog.rom1v.com/2018/03/introducing-scrcpy/#handle-accented-characters
[#37]: https://github.com/Genymobile/scrcpy/issues/37
## Problemi del client
### La qualità è bassa
Se la definizione della finestra del tuo client è minore di quella del tuo dispositivo, allora potresti avere una bassa qualità di visualizzazione, specialmente individuabile nei testi (vedi [#40] (link in inglese)).
[#40]: https://github.com/Genymobile/scrcpy/issues/40
Per migliorare la qualità di ridimensionamento (downscaling), il filtro trilineare è applicato automaticamente se il renderizzatore è OpenGL e se supporta la creazione di mipmap.
In Windows, potresti voler forzare OpenGL:
```
scrcpy --render-driver=opengl
```
Potresti anche dover configurare il [comportamento di ridimensionamento][scaling behavior] (link in inglese):
> `scrcpy.exe` > Propietà > Compatibilità > Modifica impostazioni DPI elevati > Esegui l'override del comportamento di ridimensionamento DPI elevati > Ridimensionamento eseguito per: _Applicazione_.
[scaling behavior]: https://github.com/Genymobile/scrcpy/issues/40#issuecomment-424466723
### Crash del compositore KWin
In Plasma Desktop, il compositore è disabilitato mentre _scrcpy_ è in esecuzione.
Come soluzione alternativa, [disattiva la "composizione dei blocchi"][kwin] (link in inglese).
<!--- Non sono sicuro di aver tradotto correttamente la stringa di testo del pulsante --->
[kwin]: https://github.com/Genymobile/scrcpy/issues/114#issuecomment-378778613
## Crash
### Eccezione
Ci potrebbero essere molte ragioni. Una causa comune è che il codificatore hardware del tuo dispositivo non riesce a codificare alla definizione selezionata:
> ```
> ERROR: Exception on thread Thread[main,5,main]
> android.media.MediaCodec$CodecException: Error 0xfffffc0e
> ...
> Exit due to uncaughtException in main thread:
> ERROR: Could not open video stream
> INFO: Initial texture: 1080x2336
> ```
o
> ```
> ERROR: Exception on thread Thread[main,5,main]
> java.lang.IllegalStateException
> at android.media.MediaCodec.native_dequeueOutputBuffer(Native Method)
> ```
Prova con una definizione inferiore:
```
scrcpy -m 1920
scrcpy -m 1024
scrcpy -m 800
```
Potresti anche provare un altro [codificatore](README.it.md#codificatore).
## Linea di comando in Windows
Alcuni utenti Windows non sono familiari con la riga di comando. Qui è descritto come aprire un terminale ed eseguire `scrcpy` con gli argomenti:
1. Premi <kbd>Windows</kbd>+<kbd>r</kbd>, questo apre una finestra di dialogo.
2. Scrivi `cmd` e premi <kbd>Enter</kbd>, questo apre un terminale.
3. Vai nella tua cartella di _scrcpy_ scrivendo (adatta il percorso):
```bat
cd C:\Users\user\Downloads\scrcpy-win64-xxx
```
e premi <kbd>Enter</kbd>
4. Scrivi il tuo comando. Per esempio:
```bat
scrcpy --record file.mkv
```
Se pianifichi di utilizzare sempre gli stessi argomenti, crea un file `myscrcpy.bat` (abilita mostra [estensioni nomi file][show file extensions] per evitare di far confusione) contenente il tuo comando nella cartella di `scrcpy`. Per esempio:
```bat
scrcpy --prefer-text --turn-screen-off --stay-awake
```
Poi fai doppio click su quel file.
Potresti anche modificare (una copia di) `scrcpy-console.bat` o `scrcpy-noconsole.vbs` per aggiungere alcuni argomenti.
[show file extensions]: https://www.techpedia.it/14-windows/windows-10/171-visualizzare-le-estensioni-nomi-file-con-windows-10

23
FAQ.md
View File

@ -1,7 +1,5 @@
# Frequently Asked Questions
[Read in another language](#translations)
Here are the common reported problems and their status.
@ -41,11 +39,8 @@ Check [stackoverflow][device-unauthorized].
> adb: error: failed to get feature set: no devices/emulators found
Check that you correctly enabled [adb debugging][enable-adb].
If your device is not detected, you may need some [drivers] (on Windows).
[enable-adb]: https://developer.android.com/studio/command-line/adb.html#Enabling
[drivers]: https://developer.android.com/studio/run/oem-usb.html
@ -116,6 +111,16 @@ In developer options, enable:
[simulating input]: https://github.com/Genymobile/scrcpy/issues/70#issuecomment-373286323
### Mouse clicks at wrong location
On MacOS, with HiDPI support and multiple screens, input location are wrongly
scaled. See [#15].
[#15]: https://github.com/Genymobile/scrcpy/issues/15
Open _scrcpy_ directly on the monitor you use it.
### Special characters do not work
Injecting text input is [limited to ASCII characters][text-input]. A trick
@ -232,11 +237,3 @@ You could also edit (a copy of) `scrcpy-console.bat` or `scrcpy-noconsole.vbs`
to add some arguments.
[show file extensions]: https://www.howtogeek.com/205086/beginner-how-to-make-windows-show-file-extensions/
## Translations
This FAQ is available in other languages:
- [Italiano (Italiano, `it`) - v1.17](FAQ.it.md)
- [한국어 (Korean, `ko`) - v1.11](FAQ.ko.md)

View File

@ -69,7 +69,10 @@ Anda juga bisa [membangun aplikasi secara manual][BUILD] (jangan khawatir, tidak
Untuk Windows, untuk kesederhanaan, arsip prebuilt dengan semua dependensi (termasuk `adb`) tersedia :
- [README](README.md#windows)
- [`scrcpy-win64-v1.16.zip`][direct-win64]
_(SHA-256: 3f30dc5db1a2f95c2b40a0f5de91ec1642d9f53799250a8c529bc882bc0918f0)_
[direct-win64]: https://github.com/Genymobile/scrcpy/releases/download/v1.16/scrcpy-win64-v1.16.zip
Ini juga tersedia di [Chocolatey]:

View File

@ -1,742 +0,0 @@
_Apri il [README](README.md) originale e sempre aggiornato._
# scrcpy (v1.17)
Questa applicazione fornisce la visualizzazione e il controllo dei dispositivi Android collegati via USB (o [via TCP/IP][article-tcpip]). Non richiede alcun accesso _root_.
Funziona su _GNU/Linux_, _Windows_ e _macOS_.
![screenshot](assets/screenshot-debian-600.jpg)
Si concentra su:
- **leggerezza** (nativo, mostra solo lo schermo del dispositivo)
- **prestazioni** (30~60fps)
- **qualità** (1920×1080 o superiore)
- **bassa latenza** ([35~70ms][lowlatency])
- **tempo di avvio basso** (~ 1secondo per visualizzare la prima immagine)
- **non invadenza** (nulla viene lasciato installato sul dispositivo)
[lowlatency]: https://github.com/Genymobile/scrcpy/pull/646
## Requisiti
Il dispositivo Android richiede almeno le API 21 (Android 5.0).
Assiucurati di aver [attivato il debug usb][enable-adb] sul(/i) tuo(i) dispositivo(/i).
[enable-adb]: https://developer.android.com/studio/command-line/adb.html#Enabling
In alcuni dispositivi, devi anche abilitare [un'opzione aggiuntiva][control] per controllarli con tastiera e mouse.
[control]: https://github.com/Genymobile/scrcpy/issues/70#issuecomment-373286323
## Ottieni l'app
<a href="https://repology.org/project/scrcpy/versions"><img src="https://repology.org/badge/vertical-allrepos/scrcpy.svg" alt="Packaging status" align="right"></a>
### Sommario
- Linux: `apt install scrcpy`
- Windows: [download](README.md#windows)
- macOS: `brew install scrcpy`
Compila dai sorgenti: [BUILD] (in inglese) ([procedimento semplificato][BUILD_simple] (in inglese))
[BUILD]: BUILD.md
[BUILD_simple]: BUILD.md#simple
### Linux
Su Debian (_testing_ e _sid_ per ora) e Ubuntu (20.04):
```
apt install scrcpy
```
È disponibile anche un pacchetto [Snap]: [`scrcpy`][snap-link].
[snap-link]: https://snapstats.org/snaps/scrcpy
[snap]: https://it.wikipedia.org/wiki/Snappy_(gestore_pacchetti)
Per Fedora, è disponibile un pacchetto [COPR]: [`scrcpy`][copr-link].
[COPR]: https://fedoraproject.org/wiki/Category:Copr
[copr-link]: https://copr.fedorainfracloud.org/coprs/zeno/scrcpy/
Per Arch Linux, è disponibile un pacchetto [AUR]: [`scrcpy`][aur-link].
[AUR]: https://wiki.archlinux.org/index.php/Arch_User_Repository
[aur-link]: https://aur.archlinux.org/packages/scrcpy/
Per Gentoo, è disponibile una [Ebuild]: [`scrcpy/`][ebuild-link].
[Ebuild]: https://wiki.gentoo.org/wiki/Ebuild
[ebuild-link]: https://github.com/maggu2810/maggu2810-overlay/tree/master/app-mobilephone/scrcpy
Puoi anche [compilare l'app manualmente][BUILD] (in inglese) ([procedimento semplificato][BUILD_simple] (in inglese)).
### Windows
Per Windows, per semplicità è disponibile un archivio precompilato con tutte le dipendenze (incluso `adb`):
- [README](README.md#windows) (Link al README originale per l'ultima versione)
È anche disponibile in [Chocolatey]:
[Chocolatey]: https://chocolatey.org/
```bash
choco install scrcpy
choco install adb # se non lo hai già
```
E in [Scoop]:
```bash
scoop install scrcpy
scoop install adb # se non lo hai già
```
[Scoop]: https://scoop.sh
Puoi anche [compilare l'app manualmente][BUILD] (in inglese).
### macOS
L'applicazione è disponibile in [Homebrew]. Basta installarlo:
[Homebrew]: https://brew.sh/
```bash
brew install scrcpy
```
Serve che `adb` sia accessibile dal tuo `PATH`. Se non lo hai già:
```bash
brew install android-platform-tools
```
È anche disponibile in [MacPorts], che imposta adb per te:
```bash
sudo port install scrcpy
```
[MacPorts]: https://www.macports.org/
Puoi anche [compilare l'app manualmente][BUILD] (in inglese).
## Esecuzione
Collega un dispositivo Android ed esegui:
```bash
scrcpy
```
Scrcpy accetta argomenti da riga di comando, essi sono listati con:
```bash
scrcpy --help
```
## Funzionalità
### Configurazione di acquisizione
#### Riduci dimensione
Qualche volta è utile trasmettere un dispositvo Android ad una definizione inferiore per aumentare le prestazioni.
Per limitare sia larghezza che altezza ad un certo valore (ad es. 1024):
```bash
scrcpy --max-size 1024
scrcpy -m 1024 # versione breve
```
L'altra dimensione è calcolata in modo tale che il rapporto di forma del dispositivo sia preservato.
In questo esempio un dispositivo in 1920x1080 viene trasmesso a 1024x576.
#### Cambia bit-rate (velocità di trasmissione)
Il bit-rate predefinito è 8 Mbps. Per cambiare il bitrate video (ad es. a 2 Mbps):
```bash
scrcpy --bit-rate 2M
scrcpy -b 2M # versione breve
```
#### Limitare il frame rate (frequenza di fotogrammi)
Il frame rate di acquisizione può essere limitato:
```bash
scrcpy --max-fps 15
```
Questo è supportato ufficialmente a partire da Android 10, ma potrebbe funzionare in versioni precedenti.
#### Ritaglio
Lo schermo del dispositivo può essere ritagliato per visualizzare solo parte di esso.
Questo può essere utile, per esempio, per trasmettere solo un occhio dell'Oculus Go:
```bash
scrcpy --crop 1224:1440:0:0 # 1224x1440 at offset (0,0)
```
Se anche `--max-size` è specificata, il ridimensionamento è applicato dopo il ritaglio.
#### Blocca orientamento del video
Per bloccare l'orientamento della trasmissione:
```bash
scrcpy --lock-video-orientation 0 # orientamento naturale
scrcpy --lock-video-orientation 1 # 90° antiorario
scrcpy --lock-video-orientation 2 # 180°
scrcpy --lock-video-orientation 3 # 90° orario
```
Questo influisce sull'orientamento della registrazione.
La [finestra può anche essere ruotata](#rotazione) indipendentemente.
#### Codificatore
Alcuni dispositivi hanno più di un codificatore e alcuni di questi possono provocare problemi o crash. È possibile selezionare un encoder diverso:
```bash
scrcpy --encoder OMX.qcom.video.encoder.avc
```
Per elencare i codificatori disponibili puoi immettere un nome di codificatore non valido e l'errore mostrerà i codificatori disponibili:
```bash
scrcpy --encoder _
```
### Registrazione
È possibile registrare lo schermo durante la trasmissione:
```bash
scrcpy --record file.mp4
scrcpy -r file.mkv
```
Per disabilitare la trasmissione durante la registrazione:
```bash
scrcpy --no-display --record file.mp4
scrcpy -Nr file.mkv
# interrompere la registrazione con Ctrl+C
```
I "fotogrammi saltati" sono registrati nonostante non siano mostrati in tempo reale (per motivi di prestazioni). I fotogrammi sono _datati_ sul dispositivo, così una [variazione di latenza dei pacchetti][packet delay variation] non impatta il file registrato.
[packet delay variation]: https://en.wikipedia.org/wiki/Packet_delay_variation
### Connessione
#### Wireless
_Scrcpy_ usa `adb` per comunicare col dispositivo e `adb` può [connettersi][connect] al dispositivo mediante TCP/IP:
1. Connetti il dispositivo alla stessa rete Wi-Fi del tuo computer.
2. Trova l'indirizzo IP del tuo dispositivo in Impostazioni → Informazioni sul telefono → Stato, oppure eseguendo questo comando:
```bash
adb shell ip route | awk '{print $9}'
```
3. Abilita adb via TCP/IP sul tuo dispositivo: `adb tcpip 5555`.
4. Scollega il tuo dispositivo.
5. Connetti il tuo dispositivo: `adb connect IP_DISPOSITVO:5555` _(rimpiazza `IP_DISPOSITIVO`)_.
6. Esegui `scrcpy` come al solito.
Potrebbe essere utile diminuire il bit-rate e la definizione
```bash
scrcpy --bit-rate 2M --max-size 800
scrcpy -b2M -m800 # versione breve
```
[connect]: https://developer.android.com/studio/command-line/adb.html#wireless
#### Multi dispositivo
Se in `adb devices` sono listati più dispositivi, è necessario specificare il _seriale_:
```bash
scrcpy --serial 0123456789abcdef
scrcpy -s 0123456789abcdef # versione breve
```
Se il dispositivo è collegato mediante TCP/IP:
```bash
scrcpy --serial 192.168.0.1:5555
scrcpy -s 192.168.0.1:5555 # versione breve
```
Puoi avviare più istanze di _scrcpy_ per diversi dispositivi.
#### Avvio automativo alla connessione del dispositivo
Potresti usare [AutoAdb]:
```bash
autoadb scrcpy -s '{}'
```
[AutoAdb]: https://github.com/rom1v/autoadb
#### Tunnel SSH
Per connettersi a un dispositivo remoto è possibile collegare un client `adb` locale ad un server `adb` remoto (assunto che entrambi stiano usando la stessa versione del protocollo _adb_):
```bash
adb kill-server # termina il server adb locale su 5037
ssh -CN -L5037:localhost:5037 -R27183:localhost:27183 your_remote_computer
# tieni questo aperto
```
Da un altro terminale:
```bash
scrcpy
```
Per evitare l'abilitazione dell'apertura porte remota potresti invece forzare una "forward connection" (notare il `-L` invece di `-R`)
```bash
adb kill-server # termina il server adb locale su 5037
ssh -CN -L5037:localhost:5037 -L27183:localhost:27183 your_remote_computer
# tieni questo aperto
```
Da un altro terminale:
```bash
scrcpy --force-adb-forward
```
Come per le connessioni wireless potrebbe essere utile ridurre la qualità:
```
scrcpy -b2M -m800 --max-fps 15
```
### Configurazione della finestra
#### Titolo
Il titolo della finestra è il modello del dispositivo per impostazione predefinita. Esso può essere cambiato:
```bash
scrcpy --window-title 'My device'
```
#### Posizione e dimensione
La posizione e la dimensione iniziale della finestra può essere specificata:
```bash
scrcpy --window-x 100 --window-y 100 --window-width 800 --window-height 600
```
#### Senza bordi
Per disabilitare le decorazioni della finestra:
```bash
scrcpy --window-borderless
```
#### Sempre in primo piano
Per tenere scrcpy sempre in primo piano:
```bash
scrcpy --always-on-top
```
#### Schermo intero
L'app può essere avviata direttamente a schermo intero:
```bash
scrcpy --fullscreen
scrcpy -f # versione breve
```
Lo schermo intero può anche essere attivato/disattivato con <kbd>MOD</kbd>+<kbd>f</kbd>.
#### Rotazione
La finestra può essere ruotata:
```bash
scrcpy --rotation 1
```
I valori possibili sono:
- `0`: nessuna rotazione
- `1`: 90 gradi antiorari
- `2`: 180 gradi
- `3`: 90 gradi orari
La rotazione può anche essere cambiata dinamicamente con <kbd>MOD</kbd>+<kbd>←</kbd>
_(sinistra)_ e <kbd>MOD</kbd>+<kbd>→</kbd> _(destra)_.
Notare che _scrcpy_ gestisce 3 diversi tipi di rotazione:
- <kbd>MOD</kbd>+<kbd>r</kbd> richiede al dispositvo di cambiare tra orientamento verticale (portrait) e orizzontale (landscape) (l'app in uso potrebbe rifiutarsi se non supporta l'orientamento richiesto).
- [`--lock-video-orientation`](#blocca-orientamento-del-video) cambia l'orientamento della trasmissione (l'orientamento del video inviato dal dispositivo al computer). Questo influenza la registrazione.
- `--rotation` (o <kbd>MOD</kbd>+<kbd>←</kbd>/<kbd>MOD</kbd>+<kbd>→</kbd>) ruota solo il contenuto della finestra. Questo influenza solo la visualizzazione, non la registrazione.
### Altre opzioni di trasmissione
#### "Sola lettura"
Per disabilitare i controlli (tutto ciò che può interagire col dispositivo: tasti di input, eventi del mouse, trascina e rilascia (drag&drop) file):
```bash
scrcpy --no-control
scrcpy -n
```
#### Schermo
Se sono disponibili più schermi, è possibile selezionare lo schermo da trasmettere:
```bash
scrcpy --display 1
```
La lista degli id schermo può essere ricavata da:
```bash
adb shell dumpsys display # cerca "mDisplayId=" nell'output
```
Lo schermo secondario potrebbe essere possibile controllarlo solo se il dispositivo esegue almeno Android 10 (in caso contrario è trasmesso in modalità sola lettura).
#### Mantenere sbloccato
Per evitare che il dispositivo si blocchi dopo un po' che il dispositivo è collegato:
```bash
scrcpy --stay-awake
scrcpy -w
```
Lo stato iniziale è ripristinato quando scrcpy viene chiuso.
#### Spegnere lo schermo
È possibile spegnere lo schermo del dispositivo durante la trasmissione con un'opzione da riga di comando:
```bash
scrcpy --turn-screen-off
scrcpy -S
```
Oppure premendo <kbd>MOD</kbd>+<kbd>o</kbd> in qualsiasi momento.
Per riaccenderlo premere <kbd>MOD</kbd>+<kbd>Shift</kbd>+<kbd>o</kbd>.
In Android il pulsante `POWER` (tasto di accensione) accende sempre lo schermo. Per comodità, se `POWER` è inviato via scrcpy (con click destro o con <kbd>MOD</kbd>+<kbd>p</kbd>), si forza il dispositivo a spegnere lo schermo dopo un piccolo ritardo (appena possibile).
Il pulsante fisico `POWER` continuerà ad accendere lo schermo normalmente.
Può anche essere utile evitare il blocco del dispositivo:
```bash
scrcpy --turn-screen-off --stay-awake
scrcpy -Sw
```
#### Renderizzare i fotogrammi scaduti
Per minimizzare la latenza _scrcpy_ renderizza sempre l'ultimo fotogramma decodificato disponibile in maniera predefinita e tralascia quelli precedenti.
Per forzare la renderizzazione di tutti i fotogrammi (a costo di una possibile latenza superiore), utilizzare:
```bash
scrcpy --render-expired-frames
```
#### Mostrare i tocchi
Per le presentazioni può essere utile mostrare i tocchi fisici (sul dispositivo fisico).
Android fornisce questa funzionalità nelle _Opzioni sviluppatore_.
_Scrcpy_ fornisce un'opzione per abilitare questa funzionalità all'avvio e ripristinare il valore iniziale alla chiusura:
```bash
scrcpy --show-touches
scrcpy -t
```
Notare che mostra solo i tocchi _fisici_ (con le dita sul dispositivo).
#### Disabilitare il salvaschermo
In maniera predefinita scrcpy non previene l'attivazione del salvaschermo del computer.
Per disabilitarlo:
```bash
scrcpy --disable-screensaver
```
### Input di controlli
#### Rotazione dello schermo del dispostivo
Premere <kbd>MOD</kbd>+<kbd>r</kbd> per cambiare tra le modalità verticale (portrait) e orizzontale (landscape).
Notare che la rotazione avviene solo se l'applicazione in primo piano supporta l'orientamento richiesto.
#### Copia-incolla
Quando gli appunti di Android cambiano, essi vengono automaticamente sincronizzati con gli appunti del computer.
Qualsiasi scorciatoia <kbd>Ctrl</kbd> viene inoltrata al dispositivo. In particolare:
- <kbd>Ctrl</kbd>+<kbd>c</kbd> copia
- <kbd>Ctrl</kbd>+<kbd>x</kbd> taglia
- <kbd>Ctrl</kbd>+<kbd>v</kbd> incolla (dopo la sincronizzazione degli appunti da computer a dispositivo)
Questo solitamente funziona nella maniera più comune.
Il comportamento reale, però, dipende dall'applicazione attiva. Per esempio _Termux_ invia SIGINT con <kbd>Ctrl</kbd>+<kbd>c</kbd>, e _K-9 Mail_ compone un nuovo messaggio.
Per copiare, tagliare e incollare in questi casi (ma è solo supportato in Android >= 7):
- <kbd>MOD</kbd>+<kbd>c</kbd> inietta `COPY`
- <kbd>MOD</kbd>+<kbd>x</kbd> inietta `CUT`
- <kbd>MOD</kbd>+<kbd>v</kbd> inietta `PASTE` (dopo la sincronizzazione degli appunti da computer a dispositivo)
In aggiunta, <kbd>MOD</kbd>+<kbd>Shift</kbd>+<kbd>v</kbd> permette l'iniezione del testo degli appunti del computer come una sequenza di eventi pressione dei tasti. Questo è utile quando il componente non accetta l'incollaggio di testo (per esempio in _Termux_), ma questo può rompere il contenuto non ASCII.
**AVVISO:** Incollare gli appunti del computer nel dispositivo (sia con <kbd>Ctrl</kbd>+<kbd>v</kbd> che con <kbd>MOD</kbd>+<kbd>v</kbd>) copia il contenuto negli appunti del dispositivo. Come conseguenza, qualsiasi applicazione Android potrebbe leggere il suo contenuto. Dovresti evitare di incollare contenuti sensibili (come password) in questa maniera.
Alcuni dispositivi non si comportano come aspettato quando si modificano gli appunti del dispositivo a livello di codice. L'opzione `--legacy-paste` è fornita per cambiare il comportamento di <kbd>Ctrl</kbd>+<kbd>v</kbd> and <kbd>MOD</kbd>+<kbd>v</kbd> in modo tale che anch'essi iniettino il testo gli appunti del computer come una sequenza di eventi pressione dei tasti (nella stessa maniera di <kbd>MOD</kbd>+<kbd>Shift</kbd>+<kbd>v</kbd>).
#### Pizzica per zoomare (pinch-to-zoom)
Per simulare il "pizzica per zoomare": <kbd>Ctrl</kbd>+_click e trascina_.
Più precisamente, tieni premuto <kbd>Ctrl</kbd> mentre premi il pulsante sinistro. Finchè il pulsante non sarà rilasciato, tutti i movimenti del mouse ridimensioneranno e ruoteranno il contenuto (se supportato dall'applicazione) relativamente al centro dello schermo.
Concretamente scrcpy genera degli eventi di tocco addizionali di un "dito virtuale" nella posizione simmetricamente opposta rispetto al centro dello schermo.
#### Preferenze di iniezione del testo
Ci sono due tipi di [eventi][textevents] generati quando si scrive testo:
- _eventi di pressione_, segnalano che tasto è stato premuto o rilasciato;
- _eventi di testo_, segnalano che del testo è stato inserito.
In maniera predefinita le lettere sono "iniettate" usando gli eventi di pressione, in maniera tale che la tastiera si comporti come aspettato nei giochi (come accade solitamente per i tasti WASD).
Questo, però, può [causare problemi][prefertext]. Se incontri un problema del genere, puoi evitarlo con:
```bash
scrcpy --prefer-text
```
(ma questo romperà il normale funzionamento della tastiera nei giochi)
[textevents]: https://blog.rom1v.com/2018/03/introducing-scrcpy/#handle-text-input
[prefertext]: https://github.com/Genymobile/scrcpy/issues/650#issuecomment-512945343
#### Ripetizione di tasti
In maniera predefinita tenere premuto un tasto genera una ripetizione degli eventi di pressione di tale tasto. Questo può creare problemi di performance in alcuni giochi, dove questi eventi sono inutilizzati.
Per prevenire l'inoltro ripetuto degli eventi di pressione:
```bash
scrcpy --no-key-repeat
```
#### Click destro e click centrale
In maniera predefinita, click destro aziona BACK (indietro) e il click centrale aziona HOME. Per disabilitare queste scorciatoie e, invece, inviare i click al dispositivo:
```bash
scrcpy --forward-all-clicks
```
### Rilascio di file
#### Installare APK
Per installare un APK, trascina e rilascia un file APK (finisce con `.apk`) nella finestra di _scrcpy_.
Non c'è alcuna risposta visiva, un log è stampato nella console.
#### Trasferimento di file verso il dispositivo
Per trasferire un file in `/sdcard/` del dispositivo trascina e rilascia un file (non APK) nella finestra di _scrcpy_.
Non c'è alcuna risposta visiva, un log è stampato nella console.
La cartella di destinazione può essere cambiata all'avvio:
```bash
scrcpy --push-target=/sdcard/Download/
```
### Inoltro dell'audio
L'audio non è inoltrato da _scrcpy_. Usa [sndcpy].
Vedi anche la [issue #14].
[sndcpy]: https://github.com/rom1v/sndcpy
[issue #14]: https://github.com/Genymobile/scrcpy/issues/14
## Scociatoie
Nella lista seguente, <kbd>MOD</kbd> è il modificatore delle scorciatoie. In maniera predefinita è <kbd>Alt</kbd> (sinistro) o <kbd>Super</kbd> (sinistro).
Può essere cambiato usando `--shortcut-mod`. I tasti possibili sono `lctrl`, `rctrl`, `lalt`, `ralt`, `lsuper` and `rsuper` (`l` significa sinistro e `r` significa destro). Per esempio:
```bash
# usa ctrl destro per le scorciatoie
scrcpy --shortcut-mod=rctrl
# use sia "ctrl sinistro"+"alt sinistro" che "super sinistro" per le scorciatoie
scrcpy --shortcut-mod=lctrl+lalt,lsuper
```
_<kbd>[Super]</kbd> è il pulsante <kbd>Windows</kbd> o <kbd>Cmd</kbd>._
[Super]: https://it.wikipedia.org/wiki/Tasto_Windows
<!-- https://en.wikipedia.org/wiki/Super_key_(keyboard_button) è la pagina originale di Wikipedia inglese, l'ho sostituita con una simile in quello italiano -->
| Azione | Scorciatoia
| ------------------------------------------- |:-----------------------------
| Schermo intero | <kbd>MOD</kbd>+<kbd>f</kbd>
| Rotazione schermo a sinistra | <kbd>MOD</kbd>+<kbd>←</kbd> _(sinistra)_
| Rotazione schermo a destra | <kbd>MOD</kbd>+<kbd>→</kbd> _(destra)_
| Ridimensiona finestra a 1:1 (pixel-perfect) | <kbd>MOD</kbd>+<kbd>g</kbd>
| Ridimensiona la finestra per rimuovere i bordi neri | <kbd>MOD</kbd>+<kbd>w</kbd> \| _Doppio click¹_
| Premi il tasto `HOME` | <kbd>MOD</kbd>+<kbd>h</kbd> \| _Click centrale_
| Premi il tasto `BACK` | <kbd>MOD</kbd>+<kbd>b</kbd> \| _Click destro²_
| Premi il tasto `APP_SWITCH` | <kbd>MOD</kbd>+<kbd>s</kbd>
| Premi il tasto `MENU` (sblocca lo schermo) | <kbd>MOD</kbd>+<kbd>m</kbd>
| Premi il tasto `VOLUME_UP` | <kbd>MOD</kbd>+<kbd>↑</kbd> _(su)_
| Premi il tasto `VOLUME_DOWN` | <kbd>MOD</kbd>+<kbd>↓</kbd> _(giù)_
| Premi il tasto `POWER` | <kbd>MOD</kbd>+<kbd>p</kbd>
| Accendi | _Click destro²_
| Spegni lo schermo del dispositivo (continua a trasmettere) | <kbd>MOD</kbd>+<kbd>o</kbd>
| Accendi lo schermo del dispositivo | <kbd>MOD</kbd>+<kbd>Shift</kbd>+<kbd>o</kbd>
| Ruota lo schermo del dispositivo | <kbd>MOD</kbd>+<kbd>r</kbd>
| Espandi il pannello delle notifiche | <kbd>MOD</kbd>+<kbd>n</kbd>
| Chiudi il pannello delle notifiche | <kbd>MOD</kbd>+<kbd>Shift</kbd>+<kbd>n</kbd>
| Copia negli appunti³ | <kbd>MOD</kbd>+<kbd>c</kbd>
| Taglia negli appunti³ | <kbd>MOD</kbd>+<kbd>x</kbd>
| Sincronizza gli appunti e incolla³ | <kbd>MOD</kbd>+<kbd>v</kbd>
| Inietta il testo degli appunti del computer | <kbd>MOD</kbd>+<kbd>Shift</kbd>+<kbd>v</kbd>
| Abilita/Disabilita il contatore FPS (su stdout) | <kbd>MOD</kbd>+<kbd>i</kbd>
| Pizzica per zoomare | <kbd>Ctrl</kbd>+_click e trascina_
_¹Doppio click sui bordi neri per rimuoverli._
_²Il tasto destro accende lo schermo se era spento, preme BACK in caso contrario._
_³Solo in Android >= 7._
Tutte le scorciatoie <kbd>Ctrl</kbd>+_tasto_ sono inoltrate al dispositivo, così sono gestite dall'applicazione attiva.
## Path personalizzati
Per utilizzare dei binari _adb_ specifici, configura il suo path nella variabile d'ambente `ADB`:
```bash
ADB=/percorso/per/adb scrcpy
```
Per sovrascrivere il percorso del file `scrcpy-server`, configura il percorso in `SCRCPY_SERVER_PATH`.
## Perchè _scrcpy_?
Un collega mi ha sfidato a trovare un nome tanto impronunciabile quanto [gnirehtet].
[`strcpy`] copia una **str**ing (stringa); `scrcpy` copia uno **scr**een (schermo).
[gnirehtet]: https://github.com/Genymobile/gnirehtet
[`strcpy`]: http://man7.org/linux/man-pages/man3/strcpy.3.html
## Come compilare?
Vedi [BUILD] (in inglese).
## Problemi comuni
Vedi le [FAQ](FAQ.it.md).
## Sviluppatori
Leggi la [pagina per sviluppatori].
[pagina per sviluppatori]: DEVELOP.md
## Licenza (in inglese)
Copyright (C) 2018 Genymobile
Copyright (C) 2018-2021 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.
## Articoli (in inglese)
- [Introducendo scrcpy][article-intro]
- [Scrcpy ora funziona wireless][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/

View File

@ -1,725 +0,0 @@
_Only the original [README](README.md) is guaranteed to be up-to-date._
# scrcpy (v1.17)
このアプリケーションはUSB(もしくは[TCP/IP経由][article-tcpip])で接続されたAndroidデバイスの表示と制御を提供します。このアプリケーションは _root_ でのアクセスを必要としません。このアプリケーションは _GNU/Linux__Windows_ そして _macOS_ 上で動作します。
![screenshot](assets/screenshot-debian-600.jpg)
以下に焦点を当てています:
- **軽量** (ネイティブ、デバイス画面表示のみ)
- **パフォーマンス** (30~60fps)
- **クオリティ** (1920x1080以上)
- **低遅延** ([35~70ms][lowlatency])
- **短い起動時間** (初回画像を1秒以内に表示)
- **非侵入型** (デバイスに何もインストールされていない状態になる)
[lowlatency]: https://github.com/Genymobile/scrcpy/pull/646
## 必要要件
AndroidデバイスはAPI21(Android 5.0)以上。
Androidデバイスで[adbデバッグが有効][enable-adb]であること。
[enable-adb]: https://developer.android.com/studio/command-line/adb.html#Enabling
一部のAndroidデバイスでは、キーボードとマウスを使用して制御する[追加オプション][control]を有効にする必要がある。
[control]: https://github.com/Genymobile/scrcpy/issues/70#issuecomment-373286323
## アプリの取得
<a href="https://repology.org/project/scrcpy/versions"><img src="https://repology.org/badge/vertical-allrepos/scrcpy.svg" alt="Packaging status" align="right"></a>
### Linux
Debian (_testing_ と _sid_) とUbuntu(20.04):
```
apt install scrcpy
```
[Snap]パッケージが利用可能: [`scrcpy`][snap-link]
[snap-link]: https://snapstats.org/snaps/scrcpy
[snap]: https://en.wikipedia.org/wiki/Snappy_(package_manager)
Fedora用[COPR]パッケージが利用可能: [`scrcpy`][copr-link]
[COPR]: https://fedoraproject.org/wiki/Category:Copr
[copr-link]: https://copr.fedorainfracloud.org/coprs/zeno/scrcpy/
Arch Linux用[AUR]パッケージが利用可能: [`scrcpy`][aur-link]
[AUR]: https://wiki.archlinux.org/index.php/Arch_User_Repository
[aur-link]: https://aur.archlinux.org/packages/scrcpy/
Gentoo用[Ebuild]が利用可能: [`scrcpy`][ebuild-link]
[Ebuild]: https://wiki.gentoo.org/wiki/Ebuild
[ebuild-link]: https://github.com/maggu2810/maggu2810-overlay/tree/master/app-mobilephone/scrcpy
[自分でビルド][BUILD]も可能(心配しないでください、それほど難しくはありません。)
### Windows
Windowsでは簡単に、`adb`を含む)すべての依存関係を構築済みのアーカイブを利用可能です。
- [README](README.md#windows)
[Chocolatey]でも利用可能です:
[Chocolatey]: https://chocolatey.org/
```bash
choco install scrcpy
choco install adb # まだ入手していない場合
```
[Scoop]でも利用可能です:
```bash
scoop install scrcpy
scoop install adb # まだ入手していない場合
```
[Scoop]: https://scoop.sh
また、[アプリケーションをビルド][BUILD]することも可能です。
### macOS
アプリケーションは[Homebrew]で利用可能です。ただインストールするだけです。
[Homebrew]: https://brew.sh/
```bash
brew install scrcpy
```
`PATH`から`adb`へのアクセスが必要です。もしまだ持っていない場合:
```bash
# Homebrew >= 2.6.0
brew install --cask android-platform-tools
# Homebrew < 2.6.0
brew cask install android-platform-tools
```
また、[アプリケーションをビルド][BUILD]することも可能です。
## 実行
Androidデバイスを接続し、実行:
```bash
scrcpy
```
次のコマンドでリストされるコマンドライン引数も受け付けます:
```bash
scrcpy --help
```
## 機能
### キャプチャ構成
#### サイズ削減
Androidデバイスを低解像度でミラーリングする場合、パフォーマンス向上に便利な場合があります。
幅と高さをある値(例1024)に制限するには:
```bash
scrcpy --max-size 1024
scrcpy -m 1024 # 短縮版
```
一方のサイズはデバイスのアスペクト比が維持されるように計算されます。この方法では、1920x1080のデバイスでは1024x576にミラーリングされます。
#### ビットレート変更
ビットレートの初期値は8Mbpsです。ビットレートを変更するには(例:2Mbpsに変更):
```bash
scrcpy --bit-rate 2M
scrcpy -b 2M # 短縮版
```
#### フレームレート制限
キャプチャするフレームレートを制限できます:
```bash
scrcpy --max-fps 15
```
この機能はAndroid 10からオフィシャルサポートとなっていますが、以前のバージョンでも動作する可能性があります。
#### トリミング
デバイスの画面は、画面の一部のみをミラーリングするようにトリミングできます。
これは、例えばOculus Goの片方の目をミラーリングする場合に便利です。:
```bash
scrcpy --crop 1224:1440:0:0 # オフセット位置(0,0)で1224x1440
```
もし`--max-size`も指定されている場合、トリミング後にサイズ変更が適用されます。
#### ビデオの向きをロックする
ミラーリングの向きをロックするには:
```bash
scrcpy --lock-video-orientation 0 # 自然な向き
scrcpy --lock-video-orientation 1 # 90°反時計回り
scrcpy --lock-video-orientation 2 # 180°
scrcpy --lock-video-orientation 3 # 90°時計回り
```
この設定は録画の向きに影響します。
[ウィンドウは独立して回転することもできます](#回転)。
#### エンコーダ
いくつかのデバイスでは一つ以上のエンコーダを持ちます。それらのいくつかは、問題やクラッシュを引き起こします。別のエンコーダを選択することが可能です:
```bash
scrcpy --encoder OMX.qcom.video.encoder.avc
```
利用可能なエンコーダをリストするために、無効なエンコーダ名を渡すことができます。エラー表示で利用可能なエンコーダを提供します。
```bash
scrcpy --encoder _
```
### 録画
ミラーリング中に画面の録画をすることが可能です:
```bash
scrcpy --record file.mp4
scrcpy -r file.mkv
```
録画中にミラーリングを無効にするには:
```bash
scrcpy --no-display --record file.mp4
scrcpy -Nr file.mkv
# Ctrl+Cで録画を中断する
```
"スキップされたフレーム"は(パフォーマンス上の理由で)リアルタイムで表示されなくても録画されます。
フレームはデバイス上で _タイムスタンプされる_ ため [パケット遅延のバリエーション] は録画されたファイルに影響を与えません。
[パケット遅延のバリエーション]: https://en.wikipedia.org/wiki/Packet_delay_variation
### 接続
#### ワイヤレス
_Scrcpy_ はデバイスとの通信に`adb`を使用します。そして`adb`はTCP/IPを介しデバイスに[接続]することができます:
1. あなたのコンピュータと同じWi-Fiに接続します。
2. あなたのIPアドレスを取得します。設定 → 端末情報 → ステータス情報、もしくは、このコマンドを実行します:
```bash
adb shell ip route | awk '{print $9}'
```
3. あなたのデバイスでTCP/IPを介したadbを有効にします: `adb tcpip 5555`
4. あなたのデバイスの接続を外します。
5. あなたのデバイスに接続します:
`adb connect DEVICE_IP:5555` _(`DEVICE_IP`は置き換える)_
6. 通常通り`scrcpy`を実行します。
この方法はビットレートと解像度を減らすのにおそらく有用です:
```bash
scrcpy --bit-rate 2M --max-size 800
scrcpy -b2M -m800 # 短縮版
```
[接続]: https://developer.android.com/studio/command-line/adb.html#wireless
#### マルチデバイス
もし`adb devices`でいくつかのデバイスがリストされる場合、 _シリアルナンバー_ を指定する必要があります:
```bash
scrcpy --serial 0123456789abcdef
scrcpy -s 0123456789abcdef # 短縮版
```
デバイスがTCP/IPを介して接続されている場合:
```bash
scrcpy --serial 192.168.0.1:5555
scrcpy -s 192.168.0.1:5555 # 短縮版
```
複数のデバイスに対して、複数の _scrcpy_ インスタンスを開始することができます。
#### デバイス接続での自動起動
[AutoAdb]を使用可能です:
```bash
autoadb scrcpy -s '{}'
```
[AutoAdb]: https://github.com/rom1v/autoadb
#### SSHトンネル
リモートデバイスに接続するため、ローカル`adb`クライアントからリモート`adb`サーバーへ接続することが可能です(同じバージョンの _adb_ プロトコルを使用している場合):
```bash
adb kill-server # 5037ポートのローカルadbサーバーを終了する
ssh -CN -L5037:localhost:5037 -R27183:localhost:27183 your_remote_computer
# オープンしたままにする
```
他の端末から:
```bash
scrcpy
```
リモートポート転送の有効化を回避するためには、代わりに転送接続を強制することができます(`-R`の代わりに`-L`を使用することに注意):
```bash
adb kill-server # 5037ポートのローカルadbサーバーを終了する
ssh -CN -L5037:localhost:5037 -L27183:localhost:27183 your_remote_computer
# オープンしたままにする
```
他の端末から:
```bash
scrcpy --force-adb-forward
```
ワイヤレス接続と同様に、クオリティを下げると便利な場合があります:
```
scrcpy -b2M -m800 --max-fps 15
```
### ウィンドウ構成
#### タイトル
ウィンドウのタイトルはデバイスモデルが初期値です。これは変更できます:
```bash
scrcpy --window-title 'My device'
```
#### 位置とサイズ
ウィンドウの位置とサイズの初期値を指定できます:
```bash
scrcpy --window-x 100 --window-y 100 --window-width 800 --window-height 600
```
#### ボーダーレス
ウィンドウの装飾を無効化するには:
```bash
scrcpy --window-borderless
```
#### 常に画面のトップ
scrcpyの画面を常にトップにするには:
```bash
scrcpy --always-on-top
```
#### フルスクリーン
アプリケーションを直接フルスクリーンで開始できます:
```bash
scrcpy --fullscreen
scrcpy -f # 短縮版
```
フルスクリーンは、次のコマンドで動的に切り替えることができます <kbd>MOD</kbd>+<kbd>f</kbd>
#### 回転
ウィンドウは回転することができます:
```bash
scrcpy --rotation 1
```
設定可能な値:
- `0`: 回転なし
- `1`: 90° 反時計回り
- `2`: 180°
- `3`: 90° 時計回り
回転は次のコマンドで動的に変更することができます。 <kbd>MOD</kbd>+<kbd>←</kbd>_(左)_ 、 <kbd>MOD</kbd>+<kbd>→</kbd>_(右)_
_scrcpy_ は3つの回転を管理することに注意:
- <kbd>MOD</kbd>+<kbd>r</kbd>はデバイスに縦向きと横向きの切り替えを要求する(現在実行中のアプリで要求している向きをサポートしていない場合、拒否することがある)
- [`--lock-video-orientation`](#ビデオの向きをロックする)は、ミラーリングする向きを変更する(デバイスからPCへ送信される向き)。録画に影響します。
- `--rotation` (もしくは<kbd>MOD</kbd>+<kbd>←</kbd>/<kbd>MOD</kbd>+<kbd>→</kbd>)は、ウィンドウのコンテンツのみを回転します。これは表示にのみに影響し、録画には影響しません。
### 他のミラーリングオプション
#### Read-only リードオンリー
制御を無効にするには(デバイスと対話する全てのもの:入力キー、マウスイベント、ファイルのドラッグ&ドロップ):
```bash
scrcpy --no-control
scrcpy -n
```
#### ディスプレイ
いくつか利用可能なディスプレイがある場合、ミラーリングするディスプレイを選択できます:
```bash
scrcpy --display 1
```
ディスプレイIDのリストは次の方法で取得できます:
```
adb shell dumpsys display # search "mDisplayId=" in the output
```
セカンダリディスプレイは、デバイスが少なくともAndroid 10の場合にコントロール可能です。(それ以外ではリードオンリーでミラーリングされます)
#### 起動状態にする
デバイス接続時、少し遅れてからデバイスのスリープを防ぐには:
```bash
scrcpy --stay-awake
scrcpy -w
```
scrcpyが閉じられた時、初期状態に復元されます。
#### 画面OFF
コマンドラインオプションを使用することで、ミラーリングの開始時にデバイスの画面をOFFにすることができます:
```bash
scrcpy --turn-screen-off
scrcpy -S
```
もしくは、<kbd>MOD</kbd>+<kbd>o</kbd>を押すことでいつでもできます。
元に戻すには、<kbd>MOD</kbd>+<kbd>Shift</kbd>+<kbd>o</kbd>を押します。
Androidでは、`POWER`ボタンはいつでも画面を表示します。便宜上、`POWER`がscrcpyを介して(右クリックもしくは<kbd>MOD</kbd>+<kbd>p</kbd>を介して)送信される場合、(ベストエフォートベースで)少し遅れて、強制的に画面を非表示にします。ただし、物理的な`POWER`ボタンを押した場合は、画面は表示されます。
このオプションはデバイスがスリープしないようにすることにも役立ちます:
```bash
scrcpy --turn-screen-off --stay-awake
scrcpy -Sw
```
#### 期限切れフレームをレンダリングする
初期状態では、待ち時間を最小限にするために、_scrcpy_ は最後にデコードされたフレームをレンダリングし、前のフレームを削除します。
全フレームのレンダリングを強制するには(待ち時間が長くなる可能性があります):
```bash
scrcpy --render-expired-frames
```
#### タッチを表示
プレゼンテーションの場合(物理デバイス上で)物理的なタッチを表示すると便利な場合があります。
Androidはこの機能を _開発者オプション_ で提供します。
_Scrcpy_ は開始時にこの機能を有効にし、終了時に初期値を復元するオプションを提供します:
```bash
scrcpy --show-touches
scrcpy -t
```
(デバイス上で指を使った) _物理的な_ タッチのみ表示されることに注意してください。
#### スクリーンセーバー無効
初期状態では、scrcpyはコンピュータ上でスクリーンセーバーが実行される事を妨げません。
これを無効にするには:
```bash
scrcpy --disable-screensaver
```
### 入力制御
#### デバイス画面の回転
<kbd>MOD</kbd>+<kbd>r</kbd>を押すことで、縦向きと横向きを切り替えます。
フォアグラウンドのアプリケーションが要求された向きをサポートしている場合のみ回転することに注意してください。
#### コピー-ペースト
Androidのクリップボードが変更される度に、コンピュータのクリップボードに自動的に同期されます。
<kbd>Ctrl</kbd>のショートカットは全てデバイスに転送されます。特に:
- <kbd>Ctrl</kbd>+<kbd>c</kbd> 通常はコピーします
- <kbd>Ctrl</kbd>+<kbd>x</kbd> 通常はカットします
- <kbd>Ctrl</kbd>+<kbd>v</kbd> 通常はペーストします(コンピュータとデバイスのクリップボードが同期された後)
通常は期待通りに動作します。
しかしながら、実際の動作はアクティブなアプリケーションに依存します。例えば、_Termux_ は代わりに<kbd>Ctrl</kbd>+<kbd>c</kbd>でSIGINTを送信します、そして、_K-9 Mail_ は新しいメッセージを作成します。
このようなケースでコピー、カットそしてペーストをするには(Android 7以上でのサポートのみですが):
- <kbd>MOD</kbd>+<kbd>c</kbd> `COPY`を挿入
- <kbd>MOD</kbd>+<kbd>x</kbd> `CUT`を挿入
- <kbd>MOD</kbd>+<kbd>v</kbd> `PASTE`を挿入(コンピュータとデバイスのクリップボードが同期された後)
加えて、<kbd>MOD</kbd>+<kbd>Shift</kbd>+<kbd>v</kbd>はコンピュータのクリップボードテキストにキーイベントのシーケンスとして挿入することを許可します。これはコンポーネントがテキストのペーストを許可しない場合(例えば _Termux_)に有用ですが、非ASCIIコンテンツを壊す可能性があります。
**警告:** デバイスにコンピュータのクリップボードを(<kbd>Ctrl</kbd>+<kbd>v</kbd>または<kbd>MOD</kbd>+<kbd>v</kbd>を介して)ペーストすることは、デバイスのクリップボードにコンテンツをコピーします。結果としてどのAndoridアプリケーションもそのコンテンツを読み取ることができます。機密性の高いコンテンツ(例えばパスワードなど)をこの方法でペーストすることは避けてください。
プログラムでデバイスのクリップボードを設定した場合、一部のデバイスは期待どおりに動作しません。`--legacy-paste`オプションは、コンピュータのクリップボードテキストをキーイベントのシーケンスとして挿入するため(<kbd>MOD</kbd>+<kbd>Shift</kbd>+<kbd>v</kbd>と同じ方法)、<kbd>Ctrl</kbd>+<kbd>v</kbd>と<kbd>MOD</kbd>+<kbd>v</kbd>の動作の変更を提供します。
#### ピンチしてズームする
"ピンチしてズームする"をシミュレートするには: <kbd>Ctrl</kbd>+_クリック&移動_
より正確にするには、左クリックボタンを押している間、<kbd>Ctrl</kbd>を押したままにします。左クリックボタンを離すまで、全てのマウスの動きは、(アプリでサポートされている場合)画面の中心を基準として、コンテンツを拡大縮小および回転します。
具体的には、scrcpyは画面の中央を反転した位置にある"バーチャルフィンガー"から追加のタッチイベントを生成します。
#### テキストインジェクション環境設定
テキストをタイプした時に生成される2種類の[イベント][textevents]があります:
- _key events_ はキーを押したときと離したことを通知します。
- _text events_ はテキストが入力されたことを通知します。
初期状態で、文字はキーイベントで挿入されるため、キーボードはゲームで期待通りに動作します(通常はWASDキー)。
しかし、これは[問題を引き起こす][prefertext]かもしれません。もしこのような問題が発生した場合は、この方法で回避できます:
```bash
scrcpy --prefer-text
```
(しかしこの方法はゲームのキーボードの動作を壊します)
[textevents]: https://blog.rom1v.com/2018/03/introducing-scrcpy/#handle-text-input
[prefertext]: https://github.com/Genymobile/scrcpy/issues/650#issuecomment-512945343
#### キーの繰り返し
初期状態では、キーの押しっぱなしは繰り返しのキーイベントを生成します。これらのイベントが使われない場合でも、この方法は一部のゲームでパフォーマンスの問題を引き起す可能性があります。
繰り返しのキーイベントの転送を回避するためには:
```bash
scrcpy --no-key-repeat
```
#### 右クリックと真ん中クリック
初期状態では、右クリックはバックの動作(もしくはパワーオン)を起こし、真ん中クリックではホーム画面へ戻ります。このショートカットを無効にし、代わりにデバイスへクリックを転送するには:
```bash
scrcpy --forward-all-clicks
```
### ファイルのドロップ
#### APKのインストール
APKをインストールするには、(`.apk`で終わる)APKファイルを _scrcpy_ の画面にドラッグ&ドロップします。
見た目のフィードバックはありません。コンソールにログが出力されます。
#### デバイスにファイルを送る
デバイスの`/sdcard/`ディレクトリにファイルを送るには、(APKではない)ファイルを _scrcpy_ の画面にドラッグ&ドロップします。
見た目のフィードバックはありません。コンソールにログが出力されます。
転送先ディレクトリを起動時に変更することができます:
```bash
scrcpy --push-target /sdcard/foo/bar/
```
### 音声転送
音声は _scrcpy_ では転送されません。[sndcpy]を使用します。
[issue #14]も参照ください。
[sndcpy]: https://github.com/rom1v/sndcpy
[issue #14]: https://github.com/Genymobile/scrcpy/issues/14
## ショートカット
次のリストでは、<kbd>MOD</kbd>でショートカット変更します。初期状態では、(left)<kbd>Alt</kbd>または(left)<kbd>Super</kbd>です。
これは`--shortcut-mod`で変更することができます。可能なキーは`lctrl`、`rctrl`、`lalt`、 `ralt`、 `lsuper`そして`rsuper`です。例えば:
```bash
# RCtrlをショートカットとして使用します
scrcpy --shortcut-mod=rctrl
# ショートカットにLCtrl+LAltまたはLSuperのいずれかを使用します
scrcpy --shortcut-mod=lctrl+lalt,lsuper
```
_<kbd>[Super]</kbd>は通常<kbd>Windows</kbd>もしくは<kbd>Cmd</kbd>キーです。_
[Super]: https://en.wikipedia.org/wiki/Super_key_(keyboard_button)
| アクション | ショートカット
| ------------------------------------------- |:-----------------------------
| フルスクリーンモードへの切り替え | <kbd>MOD</kbd>+<kbd>f</kbd>
| ディスプレイを左に回転 | <kbd>MOD</kbd>+<kbd>←</kbd> _(左)_
| ディスプレイを右に回転 | <kbd>MOD</kbd>+<kbd>→</kbd> _(右)_
| ウィンドウサイズを変更して1:1に変更(ピクセルパーフェクト) | <kbd>MOD</kbd>+<kbd>g</kbd>
| ウィンドウサイズを変更して黒い境界線を削除 | <kbd>MOD</kbd>+<kbd>w</kbd> \| _ダブルクリック¹_
| `HOME`をクリック | <kbd>MOD</kbd>+<kbd>h</kbd> \| _真ん中クリック_
| `BACK`をクリック | <kbd>MOD</kbd>+<kbd>b</kbd> \| _右クリック²_
| `APP_SWITCH`をクリック | <kbd>MOD</kbd>+<kbd>s</kbd>
| `MENU` (画面のアンロック)をクリック | <kbd>MOD</kbd>+<kbd>m</kbd>
| `VOLUME_UP`をクリック | <kbd>MOD</kbd>+<kbd>↑</kbd> _(上)_
| `VOLUME_DOWN`をクリック | <kbd>MOD</kbd>+<kbd>↓</kbd> _(下)_
| `POWER`をクリック | <kbd>MOD</kbd>+<kbd>p</kbd>
| 電源オン | _右クリック²_
| デバイス画面をオフにする(ミラーリングしたまま) | <kbd>MOD</kbd>+<kbd>o</kbd>
| デバイス画面をオンにする | <kbd>MOD</kbd>+<kbd>Shift</kbd>+<kbd>o</kbd>
| デバイス画面を回転する | <kbd>MOD</kbd>+<kbd>r</kbd>
| 通知パネルを展開する | <kbd>MOD</kbd>+<kbd>n</kbd>
| 通知パネルを折りたたむ | <kbd>MOD</kbd>+<kbd>Shift</kbd>+<kbd>n</kbd>
| クリップボードへのコピー³ | <kbd>MOD</kbd>+<kbd>c</kbd>
| クリップボードへのカット³ | <kbd>MOD</kbd>+<kbd>x</kbd>
| クリップボードの同期とペースト³ | <kbd>MOD</kbd>+<kbd>v</kbd>
| コンピュータのクリップボードテキストの挿入 | <kbd>MOD</kbd>+<kbd>Shift</kbd>+<kbd>v</kbd>
| FPSカウンタ有効/無効(標準入出力上) | <kbd>MOD</kbd>+<kbd>i</kbd>
| ピンチしてズームする | <kbd>Ctrl</kbd>+_クリック&移動_
_¹黒い境界線を削除するため、境界線上でダブルクリック_
_²もしスクリーンがオフの場合、右クリックでスクリーンをオンする。それ以外の場合はBackを押します._
_³Android 7以上のみ._
全ての<kbd>Ctrl</kbd>+_キー_ ショートカットはデバイスに転送されます、そのためアクティブなアプリケーションによって処理されます。
## カスタムパス
特定の _adb_ バイナリを使用する場合、そのパスを環境変数`ADB`で構成します:
ADB=/path/to/adb scrcpy
`scrcpy-server`ファイルのパスを上書きするには、`SCRCPY_SERVER_PATH`でそのパスを構成します。
[useful]: https://github.com/Genymobile/scrcpy/issues/278#issuecomment-429330345
## なぜ _scrcpy_?
同僚が私に、[gnirehtet]のように発音できない名前を見つけるように要求しました。
[`strcpy`]は**str**ingをコピーします。`scrcpy`は**scr**eenをコピーします。
[gnirehtet]: https://github.com/Genymobile/gnirehtet
[`strcpy`]: http://man7.org/linux/man-pages/man3/strcpy.3.html
## ビルド方法は?
[BUILD]を参照してください。
[BUILD]: BUILD.md
## よくある質問
[FAQ](FAQ.md)を参照してください。
## 開発者
[開発者のページ]を読んでください。
[開発者のページ]: DEVELOP.md
## ライセンス
Copyright (C) 2018 Genymobile
Copyright (C) 2018-2021 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.
## 記事
- [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/

View File

@ -68,7 +68,9 @@ Gentoo에서 ,[Ebuild] 가 가능합니다 : [`scrcpy/`][ebuild-link].
윈도우 상에서, 간단하게 설치하기 위해 종속성이 있는 사전 구축된 아카이브가 제공됩니다 (`adb` 포함) :
해당 파일은 Readme원본 링크를 통해서 다운로드가 가능합니다.
- [README](README.md#windows)
- [`scrcpy-win`][direct-win]
[direct-win]: https://github.com/Genymobile/scrcpy/blob/master/README.md#windows
[어플을 직접 설치][BUILD] 할 수도 있습니다.
@ -112,7 +114,7 @@ scrcpy --help
### 캡쳐 환경 설정
### 사이즈 재정의
###사이즈 재정의
가끔씩 성능을 향상시키기위해 안드로이드 디바이스를 낮은 해상도에서 미러링하는 것이 유용할 때도 있습니다.
@ -136,7 +138,7 @@ scrcpy --bit-rate 2M
scrcpy -b 2M # 축약 버전
```
### 프레임 비율 제한
###프레임 비율 제한
안드로이드 버전 10이상의 디바이스에서는, 다음의 명령어로 캡쳐 화면의 프레임 비율을 제한할 수 있습니다:

View File

@ -1,4 +1,4 @@
# scrcpy (v1.18)
# scrcpy (v1.17)
[Read in another language](#translations)
@ -38,18 +38,6 @@ control it using keyboard and mouse.
<a href="https://repology.org/project/scrcpy/versions"><img src="https://repology.org/badge/vertical-allrepos/scrcpy.svg" alt="Packaging status" align="right"></a>
### Summary
- Linux: `apt install scrcpy`
- Windows: [download][direct-win64]
- macOS: `brew install scrcpy`
Build from sources: [BUILD] ([simplified process][BUILD_simple])
[BUILD]: BUILD.md
[BUILD_simple]: BUILD.md#simple
### Linux
On Debian (_testing_ and _sid_ for now) and Ubuntu (20.04):
@ -79,8 +67,9 @@ For Gentoo, an [Ebuild] is available: [`scrcpy/`][ebuild-link].
[Ebuild]: https://wiki.gentoo.org/wiki/Ebuild
[ebuild-link]: https://github.com/maggu2810/maggu2810-overlay/tree/master/app-mobilephone/scrcpy
You could also [build the app manually][BUILD] ([simplified
process][BUILD_simple]).
You could also [build the app manually][BUILD] (don't worry, it's not that
hard).
### Windows
@ -88,10 +77,10 @@ process][BUILD_simple]).
For Windows, for simplicity, a prebuilt archive with all the dependencies
(including `adb`) is available:
- [`scrcpy-win64-v1.18.zip`][direct-win64]
_(SHA-256: 37212f5087fe6f3e258f1d44fa5c02207496b30e1d7ec442cbcf8358910a5c63)_
- [`scrcpy-win64-v1.17.zip`][direct-win64]
_(SHA-256: 8b9e57993c707367ed10ebfe0e1ef563c7a29d9af4a355cd8b6a52a317c73eea)_
[direct-win64]: https://github.com/Genymobile/scrcpy/releases/download/v1.18/scrcpy-win64-v1.18.zip
[direct-win64]: https://github.com/Genymobile/scrcpy/releases/download/v1.17/scrcpy-win64-v1.17.zip
It is also available in [Chocolatey]:
@ -127,18 +116,13 @@ brew install scrcpy
You need `adb`, accessible from your `PATH`. If you don't have it yet:
```bash
brew install android-platform-tools
# Homebrew >= 2.6.0
brew install --cask android-platform-tools
# Homebrew < 2.6.0
brew cask install android-platform-tools
```
It's also available in [MacPorts], which sets up adb for you:
```bash
sudo port install scrcpy
```
[MacPorts]: https://www.macports.org/
You can also [build the app manually][BUILD].
@ -215,10 +199,10 @@ To lock the orientation of the mirroring:
```bash
scrcpy --lock-video-orientation # initial (current) orientation
scrcpy --lock-video-orientation=0 # natural orientation
scrcpy --lock-video-orientation=1 # 90° counterclockwise
scrcpy --lock-video-orientation=2 # 180°
scrcpy --lock-video-orientation=3 # 90° clockwise
scrcpy --lock-video-orientation 0 # natural orientation
scrcpy --lock-video-orientation 1 # 90° counterclockwise
scrcpy --lock-video-orientation 2 # 180°
scrcpy --lock-video-orientation 3 # 90° clockwise
```
This affects recording orientation.
@ -303,8 +287,7 @@ To start scrcpy using a v4l2 sink:
```bash
scrcpy --v4l2-sink=/dev/videoN
scrcpy --v4l2-sink=/dev/videoN --no-display # disable mirroring window
scrcpy --v4l2-sink=/dev/videoN -N # short version
scrcpy --v4l2-sink=/dev/videoN -N # --no-display to disable mirroring window
```
(replace `N` by the device ID, check with `ls /dev/video*`)
@ -483,7 +466,7 @@ _(left)_ and <kbd>MOD</kbd>+<kbd>→</kbd> _(right)_.
Note that _scrcpy_ manages 3 different rotations:
- <kbd>MOD</kbd>+<kbd>r</kbd> requests the device to switch between portrait
and landscape (the current running app may refuse, if it does not support the
and landscape (the current running app may refuse, if it does support the
requested orientation).
- [`--lock-video-orientation`](#lock-video-orientation) changes the mirroring
orientation (the orientation of the video sent from the device to the
@ -516,7 +499,7 @@ scrcpy --display 1
The list of display ids can be retrieved by:
```bash
```
adb shell dumpsys display # search "mDisplayId=" in the output
```
@ -710,15 +693,15 @@ There is no visual feedback, a log is printed to the console.
#### Push file to device
To push a file to `/sdcard/Download/` on the device, drag & drop a (non-APK)
file to the _scrcpy_ window.
To push a file to `/sdcard/` on the device, drag & drop a (non-APK) file to the
_scrcpy_ window.
There is no visual feedback, a log is printed to the console.
The target directory can be changed on start:
```bash
scrcpy --push-target=/sdcard/Movies/
scrcpy --push-target /sdcard/foo/bar/
```
@ -801,9 +784,7 @@ handled by the active application.
To use a specific _adb_ binary, configure its path in the environment variable
`ADB`:
```bash
ADB=/path/to/adb scrcpy
```
ADB=/path/to/adb scrcpy
To override the path of the `scrcpy-server` file, configure its path in
`SCRCPY_SERVER_PATH`.
@ -825,6 +806,8 @@ A colleague challenged me to find a name as unpronounceable as [gnirehtet].
See [BUILD].
[BUILD]: BUILD.md
## Common issues
@ -868,12 +851,9 @@ Read the [developers page].
This README is available in other languages:
- [Indonesian (Indonesia, `id`) - v1.16](README.id.md)
- [Italiano (Italiano, `it`) - v1.17](README.it.md)
- [日本語 (Japanese, `jp`) - v1.17](README.jp.md)
- [한국어 (Korean, `ko`) - v1.11](README.ko.md)
- [português brasileiro (Brazilian Portuguese, `pt-BR`) - v1.17](README.pt-br.md)
- [Español (Spanish, `sp`) - v1.17](README.sp.md)
- [简体中文 (Simplified Chinese, `zh-Hans`) - v1.17](README.zh-Hans.md)
- [português brasileiro (Brazilian Portuguese, `pt-BR`) - v1.12.1](README.pt-br.md)
- [简体中文 (Simplified Chinese, `zh-Hans`) - v1.16](README.zh-Hans.md)
- [繁體中文 (Traditional Chinese, `zh-Hant`) - v1.15](README.zh-Hant.md)
Only this README file is guaranteed to be up-to-date.

View File

@ -1,16 +1,16 @@
_Apenas o [README](README.md) original é garantido estar atualizado._
_Only the original [README](README.md) is guaranteed to be up-to-date._
# scrcpy (v1.17)
# scrcpy (v1.12.1)
Esta aplicação fornece exibição e controle de dispositivos Android conectados via
USB (ou [via TCP/IP][article-tcpip]). Não requer nenhum acesso _root_.
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_.
![screenshot](assets/screenshot-debian-600.jpg)
Foco em:
- **leveza** (nativo, mostra apenas a tela do dispositivo)
- **leveza** (Nativo, mostra apenas a tela do dispositivo)
- **performance** (30~60fps)
- **qualidade** (1920×1080 ou acima)
- **baixa latência** ([35~70ms][lowlatency])
@ -22,41 +22,36 @@ Foco em:
## Requisitos
O dispositivo Android requer pelo menos a API 21 (Android 5.0).
O Dispositivo Android requer pelo menos a API 21 (Android 5.0).
Tenha certeza de ter [ativado a depuração adb][enable-adb] no(s) seu(s) dispositivo(s).
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 precisa ativar [uma opção adicional][control] para
controlá-lo usando teclado e mouse.
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
## Obter o app
## Obtendo o app
<a href="https://repology.org/project/scrcpy/versions"><img src="https://repology.org/badge/vertical-allrepos/scrcpy.svg" alt="Packaging status" align="right"></a>
### Linux
No Debian (_testing_ e _sid_ por enquanto) e Ubuntu (20.04):
No Debian (_em testes_ e _sid_ por enquanto):
```
apt install scrcpy
```
Um pacote [Snap] está disponível: [`scrcpy`][snap-link].
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 Fedora, um pacote [COPR] está disponível: [`scrcpy`][copr-link].
[COPR]: https://fedoraproject.org/wiki/Category:Copr
[copr-link]: https://copr.fedorainfracloud.org/coprs/zeno/scrcpy/
Para Arch Linux, um pacote [AUR] está disponível: [`scrcpy`][aur-link].
[AUR]: https://wiki.archlinux.org/index.php/Arch_User_Repository
@ -67,19 +62,21 @@ 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 o app manualmente][BUILD] (não se preocupe, não é tão
difícil).
Você também pode [compilar a aplicação manualmente][BUILD] (não se preocupe, não é tão difícil).
### Windows
Para Windows, por simplicidade, um arquivo pré-compilado com todas as dependências
Para Windows, para simplicidade, um arquivo pré-compilado com todas as dependências
(incluindo `adb`) está disponível:
- [README](README.md#windows)
- [`scrcpy-win64-v1.12.1.zip`][direct-win64]
_(SHA-256: 57d34b6d16cfd9fe169bc37c4df58ebd256d05c1ea3febc63d9cb0a027ab47c9)_
Também está disponível em [Chocolatey]:
[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/
@ -97,12 +94,12 @@ scoop install adb # se você ainda não o tem
[Scoop]: https://scoop.sh
Você também pode [compilar o app manualmente][BUILD].
Você também pode [compilar a aplicação manualmente][BUILD].
### macOS
A aplicação está disponível em [Homebrew]. Apenas instale-a:
A aplicação está disponível em [Homebrew]. Apenas a instale:
[Homebrew]: https://brew.sh/
@ -110,22 +107,18 @@ A aplicação está disponível em [Homebrew]. Apenas instale-a:
brew install scrcpy
```
Você precisa do `adb`, acessível pelo seu `PATH`. Se você ainda não o tem:
Você precisa do `adb`, acessível através do seu `PATH`. Se você ainda não o tem:
```bash
# Homebrew >= 2.6.0
brew install --cask android-platform-tools
# Homebrew < 2.6.0
brew cask install android-platform-tools
```
Você também pode [compilar o app manualmente][BUILD].
Você também pode [compilar a aplicação manualmente][BUILD].
## Executar
Conecte um dispositivo Android e execute:
Plugue um dispositivo Android e execute:
```bash
scrcpy
@ -141,87 +134,52 @@ scrcpy --help
### Configuração de captura
#### Reduzir tamanho
#### Redução de tamanho
Algumas vezes, é útil espelhar um dispositivo Android em uma resolução menor para
aumentar a performance.
aumentar performance.
Para limitar ambos (largura e altura) para algum valor (ex: 1024):
Para limitar ambos(largura e altura) para algum valor (ex: 1024):
```bash
scrcpy --max-size 1024
scrcpy -m 1024 # versão curta
scrcpy -m 1024 # versão reduzida
```
A outra dimensão é calculada para que a proporção do dispositivo seja preservada.
Dessa forma, um dispositivo de 1920x1080 será espelhado em 1024x576.
Dessa forma, um dispositivo em 1920x1080 será espelhado em 1024x576.
#### Mudar bit-rate
#### Mudanças no bit-rate
O bit-rate padrão é 8 Mbps. Para mudar o bit-rate do vídeo (ex: para 2 Mbps):
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 curta
scrcpy -b 2M # versão reduzida
```
#### Limitar frame rate
#### Limitar frame rates
O frame rate de captura pode ser limitado:
Em dispositivos com Android >= 10, a captura de frame rate pode ser limitada:
```bash
scrcpy --max-fps 15
```
Isso é oficialmente suportado desde o Android 10, mas pode funcionar em versões anteriores.
#### Cortar
A tela do dispositivo pode ser cortada para espelhar apenas uma parte da tela.
Isso é útil por exemplo, para espelhar apenas um olho do Oculus Go:
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, o redimensionamento é aplicado após o corte.
Se `--max-size` também for especificado, redimensionar é aplicado após os cortes.
#### Travar orientação do vídeo
Para travar a orientação do espelhamento:
```bash
scrcpy --lock-video-orientation 0 # orientação natural
scrcpy --lock-video-orientation 1 # 90° sentido anti-horário
scrcpy --lock-video-orientation 2 # 180°
scrcpy --lock-video-orientation 3 # 90° sentido horário
```
Isso afeta a orientação de gravação.
A [janela também pode ser rotacionada](#rotação) independentemente.
#### Encoder
Alguns dispositivos têm mais de um encoder, e alguns deles podem causar problemas ou
travar. É possível selecionar um encoder diferente:
```bash
scrcpy --encoder OMX.qcom.video.encoder.avc
```
Para listar os encoders disponíveis, você pode passar um nome de encoder inválido, o
erro dará os encoders disponíveis:
```bash
scrcpy --encoder _
```
### Gravando
É possível gravar a tela enquanto ocorre o espelhamento:
@ -236,84 +194,65 @@ Para desativar o espelhamento durante a gravação:
```bash
scrcpy --no-display --record file.mp4
scrcpy -Nr file.mkv
# interrompa a gravação com Ctrl+C
# 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 exibidos em tempo real (por
motivos de performance). Frames têm seu _horário carimbado_ no dispositivo, então [variação de atraso nos
pacotes][packet delay variation] não impacta o arquivo gravado.
"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.
[packet delay variation]: https://en.wikipedia.org/wiki/Packet_delay_variation
[Variação de atraso de pacote]: https://en.wikipedia.org/wiki/Packet_delay_variation
### Conexão
#### Sem fio
#### Wireless/Sem fio
_Scrcpy_ usa `adb` para se comunicar com o dispositivo, e `adb` pode [conectar-se][connect] a um
dispositivo via TCP/IP:
1. Conecte o dispositivo no mesmo Wi-Fi do seu computador.
2. Pegue o endereço IP do seu dispositivo, em Configurações → Sobre o telefone → Status, ou
executando este comando:
```bash
adb shell ip route | awk '{print $9}'
```
_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. Desconecte seu dispositivo.
5. Conecte-se ao seu dispositivo: `adb connect DEVICE_IP:5555` _(substitua `DEVICE_IP`)_.
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 curta
scrcpy -b2M -m800 # versão reduzida
```
[connect]: https://developer.android.com/studio/command-line/adb.html#wireless
[conectar-se]: https://developer.android.com/studio/command-line/adb.html#wireless
#### Múltiplos dispositivos
#### N-dispositivos
Se vários dispositivos são listados em `adb devices`, você deve especificar o _serial_:
Se alguns dispositivos estão listados em `adb devices`, você precisa especificar o _serial_:
```bash
scrcpy --serial 0123456789abcdef
scrcpy -s 0123456789abcdef # versão curta
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 curta
scrcpy -s 192.168.0.1:5555 # versão reduzida
```
Você pode iniciar várias instâncias do _scrcpy_ para vários dispositivos.
Você pode iniciar algumas instâncias do _scrcpy_ para alguns dispositivos.
#### Iniciar automaticamente quando dispositivo é conectado
#### Conexão via SSH
Você pode usar [AutoAdb]:
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
autoadb scrcpy -s '{}'
```
[AutoAdb]: https://github.com/rom1v/autoadb
#### Túnel SSH
Para conectar-se a um dispositivo remoto, é possível conectar um cliente `adb` local a
um servidor `adb` remoto (contanto que eles usem a mesma versão do protocolo
_adb_):
```bash
adb kill-server # encerra o servidor adb local em 5037
adb kill-server # encerra o servidor local na 5037
ssh -CN -L5037:localhost:5037 -R27183:localhost:27183 your_remote_computer
# mantenha isso aberto
# mantém isso aberto
```
De outro terminal:
@ -322,33 +261,17 @@ De outro terminal:
scrcpy
```
Para evitar ativar o encaminhamento de porta remota, você pode forçar uma conexão
de encaminhamento (note o `-L` em vez de `-R`):
```bash
adb kill-server # encerra o servidor adb local em 5037
ssh -CN -L5037:localhost:5037 -L27183:localhost:27183 your_remote_computer
# mantenha isso aberto
```
De outro terminal:
```bash
scrcpy --force-adb-forward
```
Igual a conexões sem fio, pode ser útil reduzir a qualidade:
Igual para conexões sem fio, pode ser útil reduzir a qualidade:
```
scrcpy -b2M -m800 --max-fps 15
```
### Configuração de janela
### Configurações de Janela
#### Título
Por padrão, o título da janela é o modelo do dispositivo. Isso pode ser mudado:
Por padrão, o título da janela é o modelo do dispositivo. Isto pode ser mudado:
```bash
scrcpy --window-title 'Meu dispositivo'
@ -364,15 +287,15 @@ scrcpy --window-x 100 --window-y 100 --window-width 800 --window-height 600
#### Sem bordas
Para desativar decorações de janela:
Para desativar decorações da janela:
```bash
scrcpy --window-borderless
```
#### Sempre no topo
#### Sempre visível
Para manter a janela do scrcpy sempre no topo:
Para manter a janela do scrcpy sempre visível:
```bash
scrcpy --always-on-top
@ -384,117 +307,41 @@ A aplicação pode ser iniciada diretamente em tela cheia:
```bash
scrcpy --fullscreen
scrcpy -f # versão curta
scrcpy -f # versão reduzida
```
Tela cheia pode ser alternada dinamicamente com <kbd>MOD</kbd>+<kbd>f</kbd>.
#### Rotação
A janela pode ser rotacionada:
```bash
scrcpy --rotation 1
```
Valores possíveis são:
- `0`: sem rotação
- `1`: 90 graus sentido anti-horário
- `2`: 180 graus
- `3`: 90 graus sentido horário
A rotação também pode ser mudada dinamicamente com <kbd>MOD</kbd>+<kbd>←</kbd>
_(esquerda)_ e <kbd>MOD</kbd>+<kbd>→</kbd> _(direita)_.
Note que _scrcpy_ controla 3 rotações diferentes:
- <kbd>MOD</kbd>+<kbd>r</kbd> requisita ao dispositivo para mudar entre retrato
e paisagem (a aplicação em execução pode se recusar, se ela não suporta a
orientação requisitada).
- [`--lock-video-orientation`](#travar-orientação-do-vídeo) muda a orientação de
espelhamento (a orientação do vídeo enviado pelo dispositivo para o
computador). Isso afeta a gravação.
- `--rotation` (ou <kbd>MOD</kbd>+<kbd>←</kbd>/<kbd>MOD</kbd>+<kbd>→</kbd>)
rotaciona apenas o conteúdo da janela. Isso afeta apenas a exibição, não a
gravação.
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):
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
```
#### Display
#### Desligar a tela
Se vários displays estão disponíveis, é possível selecionar o display para
espelhar:
```bash
scrcpy --display 1
```
A lista de IDs dos displays pode ser obtida por:
```
adb shell dumpsys display # busca "mDisplayId=" na saída
```
O display secundário pode apenas ser controlado se o dispositivo roda pelo menos Android
10 (caso contrário é espelhado como apenas leitura).
#### Permanecer ativo
Para evitar que o dispositivo seja suspenso após um delay quando o dispositivo é conectado:
```bash
scrcpy --stay-awake
scrcpy -w
```
O estado inicial é restaurado quando o scrcpy é fechado.
#### Desligar tela
É possível desligar a tela do dispositivo durante o início do espelhamento com uma
opção de linha de comando:
É 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 <kbd>MOD</kbd>+<kbd>o</kbd> a qualquer momento.
Ou apertando `Ctrl`+`o` durante qualquer momento.
Para ligar novamente, pressione <kbd>MOD</kbd>+<kbd>Shift</kbd>+<kbd>o</kbd>.
Para ligar novamente, pressione `POWER` (ou `Ctrl`+`p`).
No Android, o botão de `POWER` sempre liga a tela. Por conveniência, se
`POWER` é enviado via scrcpy (via clique-direito ou <kbd>MOD</kbd>+<kbd>p</kbd>), ele
forçará a desligar a tela após um delay pequeno (numa base de melhor esforço).
O botão `POWER` físico ainda causará a tela ser ligada.
#### Frames expirados de renderização
Também pode ser útil evitar que o dispositivo seja suspenso:
Por padrão, para minimizar a latência, _scrcpy_ sempre renderiza o último frame decodificado disponível e descarta o anterior.
```bash
scrcpy --turn-screen-off --stay-awake
scrcpy -Sw
```
#### Renderizar frames expirados
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 um possível aumento de
latência), use:
Para forçar a renderização de todos os frames ( com o custo de aumento de latência), use:
```bash
scrcpy --render-expired-frames
@ -502,13 +349,11 @@ scrcpy --render-expired-frames
#### Mostrar toques
Para apresentações, pode ser útil mostrar toques físicos (no dispositivo
físico).
Para apresentações, pode ser útil mostrar toques físicos(dispositivo físico).
Android fornece esta funcionalidade nas _Opções do desenvolvedor_.
Android fornece esta funcionalidade nas _Opções do Desenvolvedor_.
_Scrcpy_ fornece esta opção de ativar esta funcionalidade no início e restaurar o
valor inicial no encerramento:
_Scrcpy_ fornece esta opção de ativar esta funcionalidade no início e desativar no encerramento:
```bash
scrcpy --show-touches
@ -518,137 +363,59 @@ scrcpy -t
Note que isto mostra apenas toques _físicos_ (com o dedo no dispositivo).
#### Desativar descanso de tela
Por padrão, scrcpy não evita que o descanso de tela rode no computador.
Para desativá-lo:
```bash
scrcpy --disable-screensaver
```
### Controle de entrada
#### Rotacionar a tela do dispositivo
Pressione <kbd>MOD</kbd>+<kbd>r</kbd> para mudar entre os modos retrato e
paisagem.
Pressione `Ctrl`+`r` para mudar entre os modos Retrato e Paisagem.
Note que só será rotacionado se a aplicação em primeiro plano suportar a
orientação requisitada.
Note que só será rotacionado se a aplicação em primeiro plano tiver suporte para o modo requisitado.
#### Copiar-colar
#### Copiar-Colar
Sempre que a área de transferência do Android muda, é automaticamente sincronizada com a
área de transferência do computador.
É possível sincronizar áreas de transferência entre computador e o dispositivo,
para ambas direções:
Qualquer atalho com <kbd>Ctrl</kbd> é encaminhado para o dispositivo. Em particular:
- <kbd>Ctrl</kbd>+<kbd>c</kbd> tipicamente copia
- <kbd>Ctrl</kbd>+<kbd>x</kbd> tipicamente recorta
- <kbd>Ctrl</kbd>+<kbd>v</kbd> tipicamente cola (após a sincronização de área de transferência
computador-para-dispositivo)
- `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).
Isso tipicamente funciona como esperado.
#### Preferências de injeção de texto
O comportamento de fato depende da aplicação ativa, no entanto. Por exemplo,
_Termux_ envia SIGINT com <kbd>Ctrl</kbd>+<kbd>c</kbd>, e _K-9 Mail_
compõe uma nova mensagem.
Para copiar, recortar e colar em tais casos (mas apenas suportado no Android >= 7):
- <kbd>MOD</kbd>+<kbd>c</kbd> injeta `COPY`
- <kbd>MOD</kbd>+<kbd>x</kbd> injeta `CUT`
- <kbd>MOD</kbd>+<kbd>v</kbd> injeta `PASTE` (após a sincronização de área de transferência
computador-para-dispositivo)
Em adição, <kbd>MOD</kbd>+<kbd>Shift</kbd>+<kbd>v</kbd> permite injetar o
texto da área de transferência do computador como uma sequência de eventos de tecla. Isso é útil quando o
componente não aceita colar texto (por exemplo no _Termux_), mas pode
quebrar conteúdo não-ASCII.
**ADVERTÊNCIA:** Colar a área de transferência do computador para o dispositivo (tanto via
<kbd>Ctrl</kbd>+<kbd>v</kbd> quanto <kbd>MOD</kbd>+<kbd>v</kbd>) copia o conteúdo
para a área de transferência do dispositivo. Como consequência, qualquer aplicação Android pode ler
o seu conteúdo. Você deve evitar colar conteúdo sensível (como senhas) dessa
forma.
Alguns dispositivos não se comportam como esperado quando a área de transferência é definida
programaticamente. Uma opção `--legacy-paste` é fornecida para mudar o comportamento
de <kbd>Ctrl</kbd>+<kbd>v</kbd> e <kbd>MOD</kbd>+<kbd>v</kbd> para que eles
também injetem o texto da área de transferência do computador como uma sequência de eventos de tecla (da mesma
forma que <kbd>MOD</kbd>+<kbd>Shift</kbd>+<kbd>v</kbd>).
#### Pinçar para dar zoom
Para simular "pinçar para dar zoom": <kbd>Ctrl</kbd>+_clicar-e-mover_.
Mais precisamente, segure <kbd>Ctrl</kbd> enquanto pressiona o botão de clique-esquerdo. Até que
o botão de clique-esquerdo seja liberado, todos os movimentos do mouse ampliar e rotacionam o
conteúdo (se suportado pelo app) relativo ao centro da tela.
Concretamente, scrcpy gera eventos adicionais de toque de um "dedo virtual" em
uma posição invertida em relação ao centro da tela.
#### Preferência de injeção de texto
Existem dois tipos de [eventos][textevents] gerados ao digitar um texto:
- _eventos de tecla_, sinalizando que a tecla foi pressionada ou solta;
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 tecla, assim o teclado comporta-se
como esperado em jogos (normalmente para teclas WASD).
Por padrão, letras são injetadas usando eventos de teclas, assim teclados comportam-se
como esperado em jogos (normalmente para tecladas WASD)
Mas isso pode [causar problemas][prefertext]. Se você encontrar tal problema, você
pode evitá-lo com:
Mas isto pode [causar problemas][prefertext]. Se você encontrar tal problema,
pode evitá-lo usando:
```bash
scrcpy --prefer-text
```
(mas isso vai quebrar o comportamento do teclado em jogos)
(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
#### Repetir tecla
Por padrão, segurar uma tecla gera eventos de tecla repetidos. Isso pode causar
problemas de performance em alguns jogos, onde esses eventos são inúteis de qualquer forma.
Para evitar o encaminhamento eventos de tecla repetidos:
```bash
scrcpy --no-key-repeat
```
#### Clique-direito e clique-do-meio
Por padrão, clique-direito dispara BACK (ou POWER) e clique-do-meio dispara
HOME. Para desabilitar esses atalhos e encaminhar os cliques para o dispositivo:
```bash
scrcpy --forward-all-clicks
```
### Soltar arquivo
### Transferência de arquivo
#### Instalar APK
Para instalar um APK, arraste e solte o arquivo APK (com extensão `.apk`) na janela
_scrcpy_.
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 dispositivo
#### Enviar arquivo para o dispositivo
Para enviar um arquivo para `/sdcard/` no dispositivo, arraste e solte um arquivo (não-APK) para a
janela do _scrcpy_.
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.
@ -661,73 +428,45 @@ scrcpy --push-target /sdcard/foo/bar/
### Encaminhamento de áudio
Áudio não é encaminhado pelo _scrcpy_. Use [sndcpy].
Áudio não é encaminhando pelo _scrcpy_. Use [USBaudio] (Apenas linux).
Também veja [issue #14].
[sndcpy]: https://github.com/rom1v/sndcpy
[USBaudio]: https://github.com/rom1v/usbaudio
[issue #14]: https://github.com/Genymobile/scrcpy/issues/14
## Atalhos
Na lista a seguir, <kbd>MOD</kbd> é o modificador de atalho. Por padrão, é
<kbd>Alt</kbd> (esquerdo) ou <kbd>Super</kbd> (esquerdo).
Ele pode ser mudado usando `--shortcut-mod`. Possíveis teclas são `lctrl`, `rctrl`,
`lalt`, `ralt`, `lsuper` e `rsuper`. Por exemplo:
```bash
# usar RCtrl para atalhos
scrcpy --shortcut-mod=rctrl
# usar tanto LCtrl+LAlt quanto LSuper para atalhos
scrcpy --shortcut-mod=lctrl+lalt,lsuper
```
_<kbd>[Super]</kbd> é tipicamente a tecla <kbd>Windows</kbd> ou <kbd>Cmd</kbd>._
[Super]: https://en.wikipedia.org/wiki/Super_key_(keyboard_button)
| Ação | Atalho
| ------------------------------------------- |:-----------------------------
| Mudar modo de tela cheia | <kbd>MOD</kbd>+<kbd>f</kbd>
| Rotacionar display para esquerda | <kbd>MOD</kbd>+<kbd>←</kbd> _(esquerda)_
| Rotacionar display para direita | <kbd>MOD</kbd>+<kbd>→</kbd> _(direita)_
| Redimensionar janela para 1:1 (pixel-perfect) | <kbd>MOD</kbd>+<kbd>g</kbd>
| Redimensionar janela para remover bordas pretas | <kbd>MOD</kbd>+<kbd>w</kbd> \| _Clique-duplo¹_
| Clicar em `HOME` | <kbd>MOD</kbd>+<kbd>h</kbd> \| _Clique-do-meio_
| Clicar em `BACK` | <kbd>MOD</kbd>+<kbd>b</kbd> \| _Clique-direito²_
| Clicar em `APP_SWITCH` | <kbd>MOD</kbd>+<kbd>s</kbd>
| Clicar em `MENU` (desbloquear tela | <kbd>MOD</kbd>+<kbd>m</kbd>
| Clicar em `VOLUME_UP` | <kbd>MOD</kbd>+<kbd>↑</kbd> _(cima)_
| Clicar em `VOLUME_DOWN` | <kbd>MOD</kbd>+<kbd>↓</kbd> _(baixo)_
| Clicar em `POWER` | <kbd>MOD</kbd>+<kbd>p</kbd>
| Ligar | _Clique-direito²_
| Desligar tela do dispositivo (continuar espelhando) | <kbd>MOD</kbd>+<kbd>o</kbd>
| Ligar tela do dispositivo | <kbd>MOD</kbd>+<kbd>Shift</kbd>+<kbd>o</kbd>
| Rotacionar tela do dispositivo | <kbd>MOD</kbd>+<kbd>r</kbd>
| Expandir painel de notificação | <kbd>MOD</kbd>+<kbd>n</kbd>
| Colapsar painel de notificação | <kbd>MOD</kbd>+<kbd>Shift</kbd>+<kbd>n</kbd>
| Copiar para área de transferência³ | <kbd>MOD</kbd>+<kbd>c</kbd>
| Recortar para área de transferência³ | <kbd>MOD</kbd>+<kbd>x</kbd>
| Sincronizar áreas de transferência e colar³ | <kbd>MOD</kbd>+<kbd>v</kbd>
| Injetar texto da área de transferência do computador | <kbd>MOD</kbd>+<kbd>Shift</kbd>+<kbd>v</kbd>
| Ativar/desativar contador de FPS (em stdout) | <kbd>MOD</kbd>+<kbd>i</kbd>
| Pinçar para dar zoom | <kbd>Ctrl</kbd>+_clicar-e-mover_
| 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._
_²Clique-direito liga a tela se ela estiver desligada, pressiona BACK caso contrário._
_³Apenas em Android >= 7._
Todos os atalhos <kbd>Ctrl</kbd>+_tecla_ são encaminhados para o dispositivo, para que eles sejam
tratados pela aplicação ativa.
_²Botão direito liga a tela se ela estiver desligada, clique BACK para o contrário._
## Caminhos personalizados
Para usar um binário _adb_ específico, configure seu caminho na variável de ambiente
`ADB`:
Para usar um binário específico _adb_, configure seu caminho na variável de ambiente `ADB`:
ADB=/caminho/para/adb scrcpy
@ -739,7 +478,7 @@ Para sobrepor o caminho do arquivo `scrcpy-server`, configure seu caminho em
## Por quê _scrcpy_?
Um colega me desafiou a encontrar um nome tão impronunciável quanto [gnirehtet].
Um colega me desafiou a encontrar um nome impronunciável como [gnirehtet].
[`strcpy`] copia uma **str**ing; `scrcpy` copia uma **scr**een.
@ -756,12 +495,12 @@ Veja [BUILD].
## Problemas comuns
Veja o [FAQ](FAQ.md).
Veja [FAQ](FAQ.md).
## Desenvolvedores
Leia a [página dos desenvolvedores][developers page].
Leia a [developers page].
[developers page]: DEVELOP.md

View File

@ -1,743 +0,0 @@
Solo se garantiza que el archivo [README](README.md) original esté actualizado.
# scrcpy (v1.17)
Esta aplicación proporciona imagen y control de un dispositivo Android conectado
por USB (o [por TCP/IP][article-tcpip]). No requiere acceso _root_.
Compatible con _GNU/Linux_, _Windows_ y _macOS_.
![screenshot](assets/screenshot-debian-600.jpg)
Sus características principales son:
- **ligero** (nativo, solo muestra la imagen del dispositivo)
- **desempeño** (30~60fps)
- **calidad** (1920×1080 o superior)
- **baja latencia** ([35~70ms][lowlatency])
- **corto tiempo de inicio** (~1 segundo para mostrar la primera imagen)
- **no intrusivo** (no se deja nada instalado en el dispositivo)
[lowlatency]: https://github.com/Genymobile/scrcpy/pull/646
## Requisitos
El dispositivo Android requiere como mínimo API 21 (Android 5.0).
Asegurate de [habilitar el adb debugging][enable-adb] en tu(s) dispositivo(s).
[enable-adb]: https://developer.android.com/studio/command-line/adb.html#Enabling
En algunos dispositivos, también necesitas habilitar [una opción adicional][control] para controlarlo con el teclado y ratón.
[control]: https://github.com/Genymobile/scrcpy/issues/70#issuecomment-373286323
## Consigue la app
<a href="https://repology.org/project/scrcpy/versions"><img src="https://repology.org/badge/vertical-allrepos/scrcpy.svg" alt="Packaging status" align="right"></a>
### Resumen
- Linux: `apt install scrcpy`
- Windows: [download](README.md#windows)
- macOS: `brew install scrcpy`
Construir desde la fuente: [BUILD] ([proceso simplificado][BUILD_simple])
[BUILD]: BUILD.md
[BUILD_simple]: BUILD.md#simple
### Linux
En Debian (_test_ y _sid_ por ahora) y Ubuntu (20.04):
```
apt install scrcpy
```
Hay un paquete [Snap]: [`scrcpy`][snap-link].
[snap-link]: https://snapstats.org/snaps/scrcpy
[snap]: https://en.wikipedia.org/wiki/Snappy_(package_manager)
Para Fedora, hay un paquete [COPR]: [`scrcpy`][copr-link].
[COPR]: https://fedoraproject.org/wiki/Category:Copr
[copr-link]: https://copr.fedorainfracloud.org/coprs/zeno/scrcpy/
Para Arch Linux, hay un paquete [AUR]: [`scrcpy`][aur-link].
[AUR]: https://wiki.archlinux.org/index.php/Arch_User_Repository
[aur-link]: https://aur.archlinux.org/packages/scrcpy/
Para Gentoo, hay un paquete [Ebuild]: [`scrcpy/`][ebuild-link].
[Ebuild]: https://wiki.gentoo.org/wiki/Ebuild
[ebuild-link]: https://github.com/maggu2810/maggu2810-overlay/tree/master/app-mobilephone/scrcpy
También puedes [construir la aplicación manualmente][BUILD] ([proceso simplificado][BUILD_simple]).
### Windows
Para Windows, por simplicidad, hay un pre-compilado con todas las dependencias
(incluyendo `adb`):
- [README](README.md#windows)
También está disponible en [Chocolatey]:
[Chocolatey]: https://chocolatey.org/
```bash
choco install scrcpy
choco install adb # si aún no está instalado
```
Y en [Scoop]:
```bash
scoop install scrcpy
scoop install adb # si aún no está instalado
```
[Scoop]: https://scoop.sh
También puedes [construir la aplicación manualmente][BUILD].
### macOS
La aplicación está disponible en [Homebrew]. Solo instalala:
[Homebrew]: https://brew.sh/
```bash
brew install scrcpy
```
Necesitarás `adb`, accesible desde `PATH`. Si aún no lo tienes:
```bash
brew install android-platform-tools
```
También está disponible en [MacPorts], que configurará el adb automáticamente:
```bash
sudo port install scrcpy
```
[MacPorts]: https://www.macports.org/
También puedes [construir la aplicación manualmente][BUILD].
## Ejecutar
Enchufa el dispositivo Android, y ejecuta:
```bash
scrcpy
```
Acepta argumentos desde la línea de comandos, listados en:
```bash
scrcpy --help
```
## Características
### Capturar configuración
#### Reducir la definición
A veces es útil reducir la definición de la imagen del dispositivo Android para aumentar el desempeño.
Para limitar el ancho y la altura a un valor específico (ej. 1024):
```bash
scrcpy --max-size 1024
scrcpy -m 1024 # versión breve
```
La otra dimensión es calculada para conservar el aspect ratio del dispositivo.
De esta forma, un dispositivo en 1920×1080 será transmitido a 1024×576.
#### Cambiar el bit-rate
El bit-rate por defecto es 8 Mbps. Para cambiar el bit-rate del video (ej. a 2 Mbps):
```bash
scrcpy --bit-rate 2M
scrcpy -b 2M # versión breve
```
#### Limitar los fps
El fps puede ser limitado:
```bash
scrcpy --max-fps 15
```
Es oficialmente soportado desde Android 10, pero puede funcionar en versiones anteriores.
#### Recortar
La imagen del dispositivo puede ser recortada para transmitir solo una parte de la pantalla.
Por ejemplo, puede ser útil para transmitir la imagen de un solo ojo del Oculus Go:
```bash
scrcpy --crop 1224:1440:0:0 # 1224x1440 con coordenadas de origen en (0,0)
```
Si `--max-size` también está especificado, el cambio de tamaño es aplicado después de cortar.
#### Fijar la rotación del video
Para fijar la rotación de la transmisión:
```bash
scrcpy --lock-video-orientation 0 # orientación normal
scrcpy --lock-video-orientation 1 # 90° contrarreloj
scrcpy --lock-video-orientation 2 # 180°
scrcpy --lock-video-orientation 3 # 90° sentido de las agujas del reloj
```
Esto afecta la rotación de la grabación.
La [ventana también puede ser rotada](#rotación) independientemente.
#### Codificador
Algunos dispositivos pueden tener más de una rotación, y algunos pueden causar problemas o errores. Es posible seleccionar un codificador diferente:
```bash
scrcpy --encoder OMX.qcom.video.encoder.avc
```
Para listar los codificadores disponibles, puedes pasar un nombre de codificador inválido, el error te dará los codificadores disponibles:
```bash
scrcpy --encoder _
```
### Grabación
Es posible grabar la pantalla mientras se transmite:
```bash
scrcpy --record file.mp4
scrcpy -r file.mkv
```
Para grabar sin transmitir la pantalla:
```bash
scrcpy --no-display --record file.mp4
scrcpy -Nr file.mkv
# interrumpe la grabación con Ctrl+C
```
"Skipped frames" son grabados, incluso si no son mostrados en tiempo real (por razones de desempeño). Los frames tienen _marcas de tiempo_ en el dispositivo, por lo que el "[packet delay
variation]" no impacta el archivo grabado.
[packet delay variation]: https://en.wikipedia.org/wiki/Packet_delay_variation
### Conexión
#### Inalámbrica
_Scrcpy_ usa `adb` para comunicarse con el dispositivo, y `adb` puede [conectarse] vía TCP/IP:
1. Conecta el dispositivo al mismo Wi-Fi que tu computadora.
2. Obtén la dirección IP del dispositivo, en Ajustes → Acerca del dispositivo → Estado, o ejecutando este comando:
```bash
adb shell ip route | awk '{print $9}'
```
3. Habilita adb vía TCP/IP en el dispositivo: `adb tcpip 5555`.
4. Desenchufa el dispositivo.
5. Conéctate a tu dispositivo: `adb connect IP_DEL_DISPOSITIVO:5555` _(reemplaza `IP_DEL_DISPOSITIVO`)_.
6. Ejecuta `scrcpy` con normalidad.
Podría resultar útil reducir el bit-rate y la definición:
```bash
scrcpy --bit-rate 2M --max-size 800
scrcpy -b2M -m800 # versión breve
```
[conectarse]: https://developer.android.com/studio/command-line/adb.html#wireless
#### Múltiples dispositivos
Si hay muchos dispositivos listados en `adb devices`, será necesario especificar el _número de serie_:
```bash
scrcpy --serial 0123456789abcdef
scrcpy -s 0123456789abcdef # versión breve
```
Si el dispositivo está conectado por TCP/IP:
```bash
scrcpy --serial 192.168.0.1:5555
scrcpy -s 192.168.0.1:5555 # versión breve
```
Puedes iniciar múltiples instancias de _scrcpy_ para múltiples dispositivos.
#### Autoiniciar al detectar dispositivo
Puedes utilizar [AutoAdb]:
```bash
autoadb scrcpy -s '{}'
```
[AutoAdb]: https://github.com/rom1v/autoadb
#### Túnel SSH
Para conectarse a un dispositivo remoto, es posible conectar un cliente local de `adb` a un servidor remoto `adb` (siempre y cuando utilicen la misma versión de protocolos _adb_):
```bash
adb kill-server # cierra el servidor local adb en 5037
ssh -CN -L5037:localhost:5037 -R27183:localhost:27183 your_remote_computer
# conserva este servidor abierto
```
Desde otra terminal:
```bash
scrcpy
```
Para evitar habilitar "remote port forwarding", puedes forzar una "forward connection" (nótese el argumento `-L` en vez de `-R`):
```bash
adb kill-server # cierra el servidor local adb en 5037
ssh -CN -L5037:localhost:5037 -L27183:localhost:27183 your_remote_computer
# conserva este servidor abierto
```
Desde otra terminal:
```bash
scrcpy --force-adb-forward
```
Al igual que las conexiones inalámbricas, puede resultar útil reducir la calidad:
```
scrcpy -b2M -m800 --max-fps 15
```
### Configuración de la ventana
#### Título
Por defecto, el título de la ventana es el modelo del dispositivo. Puede ser modificado:
```bash
scrcpy --window-title 'My device'
```
#### Posición y tamaño
La posición y tamaño inicial de la ventana puede ser especificado:
```bash
scrcpy --window-x 100 --window-y 100 --window-width 800 --window-height 600
```
#### Sin bordes
Para deshabilitar el diseño de la ventana:
```bash
scrcpy --window-borderless
```
#### Siempre adelante
Para mantener la ventana de scrcpy siempre adelante:
```bash
scrcpy --always-on-top
```
#### Pantalla completa
La aplicación puede ser iniciada en pantalla completa:
```bash
scrcpy --fullscreen
scrcpy -f # versión breve
```
Puede entrar y salir de la pantalla completa con la combinación <kbd>MOD</kbd>+<kbd>f</kbd>.
#### Rotación
Se puede rotar la ventana:
```bash
scrcpy --rotation 1
```
Los valores posibles son:
- `0`: sin rotación
- `1`: 90 grados contrarreloj
- `2`: 180 grados
- `3`: 90 grados en sentido de las agujas del reloj
La rotación también puede ser modificada con la combinación de teclas <kbd>MOD</kbd>+<kbd>←</kbd> _(izquierda)_ y <kbd>MOD</kbd>+<kbd>→</kbd> _(derecha)_.
Nótese que _scrcpy_ maneja 3 diferentes rotaciones:
- <kbd>MOD</kbd>+<kbd>r</kbd> solicita al dispositivo cambiar entre vertical y horizontal (la aplicación en uso puede rechazarlo si no soporta la orientación solicitada).
- [`--lock-video-orientation`](#fijar-la-rotación-del-video) cambia la rotación de la transmisión (la orientación del video enviado a la PC). Esto afecta a la grabación.
- `--rotation` (o <kbd>MOD</kbd>+<kbd>←</kbd>/<kbd>MOD</kbd>+<kbd>→</kbd>) rota solo el contenido de la imagen. Esto solo afecta a la imagen mostrada, no a la grabación.
### Otras opciones menores
#### Solo lectura ("Read-only")
Para deshabilitar los controles (todo lo que interactúe con el dispositivo: eventos del teclado, eventos del mouse, arrastrar y soltar archivos):
```bash
scrcpy --no-control
scrcpy -n # versión breve
```
#### Pantalla
Si múltiples pantallas están disponibles, es posible elegir cual transmitir:
```bash
scrcpy --display 1
```
Los ids de las pantallas se pueden obtener con el siguiente comando:
```bash
adb shell dumpsys display # busque "mDisplayId=" en la respuesta
```
La segunda pantalla solo puede ser manejada si el dispositivo cuenta con Android 10 (en caso contrario será transmitida en el modo solo lectura).
#### Permanecer activo
Para evitar que el dispositivo descanse después de un tiempo mientras está conectado:
```bash
scrcpy --stay-awake
scrcpy -w # versión breve
```
La configuración original se restaura al cerrar scrcpy.
#### Apagar la pantalla
Es posible apagar la pantalla mientras se transmite al iniciar con el siguiente comando:
```bash
scrcpy --turn-screen-off
scrcpy -S # versión breve
```
O presionando <kbd>MOD</kbd>+<kbd>o</kbd> en cualquier momento.
Para volver a prenderla, presione <kbd>MOD</kbd>+<kbd>Shift</kbd>+<kbd>o</kbd>.
En Android, el botón de `POWER` siempre prende la pantalla. Por conveniencia, si `POWER` es enviado vía scrcpy (con click-derecho o <kbd>MOD</kbd>+<kbd>p</kbd>), esto forzará a apagar la pantalla con un poco de atraso (en la mejor de las situaciones). El botón físico `POWER` seguirá prendiendo la pantalla.
También puede resultar útil para evitar que el dispositivo entre en inactividad:
```bash
scrcpy --turn-screen-off --stay-awake
scrcpy -Sw # versión breve
```
#### Renderizar frames vencidos
Por defecto, para minimizar la latencia, _scrcpy_ siempre renderiza el último frame disponible decodificado, e ignora cualquier frame anterior.
Para forzar el renderizado de todos los frames (a costo de posible aumento de latencia), use:
```bash
scrcpy --render-expired-frames
```
#### Mostrar clicks
Para presentaciones, puede resultar útil mostrar los clicks físicos (en el dispositivo físicamente).
Android provee esta opción en _Opciones para desarrolladores_.
_Scrcpy_ provee una opción para habilitar esta función al iniciar la aplicación y restaurar el valor original al salir:
```bash
scrcpy --show-touches
scrcpy -t # versión breve
```
Nótese que solo muestra los clicks _físicos_ (con el dedo en el dispositivo).
#### Desactivar protector de pantalla
Por defecto, scrcpy no evita que el protector de pantalla se active en la computadora.
Para deshabilitarlo:
```bash
scrcpy --disable-screensaver
```
### Control
#### Rotar pantalla del dispositivo
Presione <kbd>MOD</kbd>+<kbd>r</kbd> para cambiar entre posición vertical y horizontal.
Nótese que solo rotará si la aplicación activa soporta la orientación solicitada.
#### Copiar y pegar
Cuando que el portapapeles de Android cambia, automáticamente se sincroniza al portapapeles de la computadora.
Cualquier shortcut con <kbd>Ctrl</kbd> es enviado al dispositivo. En particular:
- <kbd>Ctrl</kbd>+<kbd>c</kbd> normalmente copia
- <kbd>Ctrl</kbd>+<kbd>x</kbd> normalmente corta
- <kbd>Ctrl</kbd>+<kbd>v</kbd> normalmente pega (después de la sincronización de portapapeles entre la computadora y el dispositivo)
Esto normalmente funciona como es esperado.
Sin embargo, este comportamiento depende de la aplicación en uso. Por ejemplo, _Termux_ envía SIGINT con <kbd>Ctrl</kbd>+<kbd>c</kbd>, y _K-9 Mail_ crea un nuevo mensaje.
Para copiar, cortar y pegar, en tales casos (solo soportado en Android >= 7):
- <kbd>MOD</kbd>+<kbd>c</kbd> inyecta `COPY`
- <kbd>MOD</kbd>+<kbd>x</kbd> inyecta `CUT`
- <kbd>MOD</kbd>+<kbd>v</kbd> inyecta `PASTE` (después de la sincronización de portapapeles entre la computadora y el dispositivo)
Además, <kbd>MOD</kbd>+<kbd>Shift</kbd>+<kbd>v</kbd> permite inyectar el texto en el portapapeles de la computadora como una secuencia de teclas. Esto es útil cuando el componente no acepta pegado de texto (por ejemplo en _Termux_), pero puede romper caracteres no pertenecientes a ASCII.
**AVISO:** Pegar de la computadora al dispositivo (tanto con <kbd>Ctrl</kbd>+<kbd>v</kbd> o <kbd>MOD</kbd>+<kbd>v</kbd>) copia el contenido al portapapeles del dispositivo. Como consecuencia, cualquier aplicación de Android puede leer su contenido. Debería evitar pegar contenido sensible (como contraseñas) de esta forma.
Algunos dispositivos no se comportan como es esperado al establecer el portapapeles programáticamente. La opción `--legacy-paste` está disponible para cambiar el comportamiento de <kbd>Ctrl</kbd>+<kbd>v</kbd> y <kbd>MOD</kbd>+<kbd>v</kbd> para que también inyecten el texto del portapapeles de la computadora como una secuencia de teclas (de la misma forma que <kbd>MOD</kbd>+<kbd>Shift</kbd>+<kbd>v</kbd>).
#### Pellizcar para zoom
Para simular "pinch-to-zoom": <kbd>Ctrl</kbd>+_click-y-mover_.
Más precisamente, mantén <kbd>Ctrl</kbd> mientras presionas botón izquierdo. Hasta que no se suelte el botón, todos los movimientos del mouse cambiarán el tamaño y rotación del contenido (si es soportado por la app en uso) respecto al centro de la pantalla.
Concretamente, scrcpy genera clicks adicionales con un "dedo virtual" en la posición invertida respecto al centro de la pantalla.
#### Preferencias de inyección de texto
Existen dos tipos de [eventos][textevents] generados al escribir texto:
- _key events_, marcando si la tecla es presionada o soltada;
- _text events_, marcando si un texto fue introducido.
Por defecto, las letras son inyectadas usando _key events_, para que el teclado funcione como es esperado en juegos (típicamente las teclas WASD).
Pero esto puede [causar problemas][prefertext]. Si encuentras tales problemas, los puedes evitar con:
```bash
scrcpy --prefer-text
```
(Pero esto romperá el comportamiento del teclado en los juegos)
[textevents]: https://blog.rom1v.com/2018/03/introducing-scrcpy/#handle-text-input
[prefertext]: https://github.com/Genymobile/scrcpy/issues/650#issuecomment-512945343
#### Repetir tecla
Por defecto, mantener una tecla presionada genera múltiples _key events_. Esto puede causar problemas de desempeño en algunos juegos, donde estos eventos no tienen sentido de todos modos.
Para evitar enviar _key events_ repetidos:
```bash
scrcpy --no-key-repeat
```
#### Botón derecho y botón del medio
Por defecto, botón derecho ejecuta RETROCEDER (o ENCENDIDO) y botón del medio INICIO. Para inhabilitar estos atajos y enviar los clicks al dispositivo:
```bash
scrcpy --forward-all-clicks
```
### Arrastrar y soltar archivos
#### Instalar APKs
Para instalar un APK, arrastre y suelte el archivo APK (terminado en `.apk`) a la ventana de _scrcpy_.
No hay respuesta visual, un mensaje se escribirá en la consola.
#### Enviar archivos al dispositivo
Para enviar un archivo a `/sdcard/` en el dispositivo, arrastre y suelte un archivo (no APK) a la ventana de _scrcpy_.
No hay respuesta visual, un mensaje se escribirá en la consola.
El directorio de destino puede ser modificado al iniciar:
```bash
scrcpy --push-target=/sdcard/Download/
```
### Envío de Audio
_Scrcpy_ no envía el audio. Use [sndcpy].
También lea [issue #14].
[sndcpy]: https://github.com/rom1v/sndcpy
[issue #14]: https://github.com/Genymobile/scrcpy/issues/14
## Atajos
En la siguiente lista, <kbd>MOD</kbd> es el atajo modificador. Por defecto es <kbd>Alt</kbd> (izquierdo) o <kbd>Super</kbd> (izquierdo).
Se puede modificar usando `--shortcut-mod`. Las posibles teclas son `lctrl` (izquierdo), `rctrl` (derecho), `lalt` (izquierdo), `ralt` (derecho), `lsuper` (izquierdo) y `rsuper` (derecho). Por ejemplo:
```bash
# use RCtrl para los atajos
scrcpy --shortcut-mod=rctrl
# use tanto LCtrl+LAlt o LSuper para los atajos
scrcpy --shortcut-mod=lctrl+lalt,lsuper
```
_<kbd>[Super]</kbd> es generalmente la tecla <kbd>Windows</kbd> o <kbd>Cmd</kbd>._
[Super]: https://en.wikipedia.org/wiki/Super_key_(keyboard_button)
| Acción | Atajo
| ------------------------------------------- |:-----------------------------
| Alterne entre pantalla compelta | <kbd>MOD</kbd>+<kbd>f</kbd>
| Rotar pantalla hacia la izquierda | <kbd>MOD</kbd>+<kbd>←</kbd> _(izquierda)_
| Rotar pantalla hacia la derecha | <kbd>MOD</kbd>+<kbd>→</kbd> _(derecha)_
| Ajustar ventana a 1:1 ("pixel-perfect") | <kbd>MOD</kbd>+<kbd>g</kbd>
| Ajustar ventana para quitar los bordes negros| <kbd>MOD</kbd>+<kbd>w</kbd> \| _Doble click¹_
| Click en `INICIO` | <kbd>MOD</kbd>+<kbd>h</kbd> \| _Botón del medio_
| Click en `RETROCEDER` | <kbd>MOD</kbd>+<kbd>b</kbd> \| _Botón derecho²_
| Click en `CAMBIAR APLICACIÓN` | <kbd>MOD</kbd>+<kbd>s</kbd>
| Click en `MENÚ` (desbloquear pantalla) | <kbd>MOD</kbd>+<kbd>m</kbd>
| Click en `SUBIR VOLUMEN` | <kbd>MOD</kbd>+<kbd>↑</kbd> _(arriba)_
| Click en `BAJAR VOLUME` | <kbd>MOD</kbd>+<kbd>↓</kbd> _(abajo)_
| Click en `ENCENDIDO` | <kbd>MOD</kbd>+<kbd>p</kbd>
| Encendido | _Botón derecho²_
| Apagar pantalla (manteniendo la transmisión)| <kbd>MOD</kbd>+<kbd>o</kbd>
| Encender pantalla | <kbd>MOD</kbd>+<kbd>Shift</kbd>+<kbd>o</kbd>
| Rotar pantalla del dispositivo | <kbd>MOD</kbd>+<kbd>r</kbd>
| Abrir panel de notificaciones | <kbd>MOD</kbd>+<kbd>n</kbd>
| Cerrar panel de notificaciones | <kbd>MOD</kbd>+<kbd>Shift</kbd>+<kbd>n</kbd>
| Copiar al portapapeles³ | <kbd>MOD</kbd>+<kbd>c</kbd>
| Cortar al portapapeles³ | <kbd>MOD</kbd>+<kbd>x</kbd>
| Synchronizar portapapeles y pegar³ | <kbd>MOD</kbd>+<kbd>v</kbd>
| inyectar texto del portapapeles de la PC | <kbd>MOD</kbd>+<kbd>Shift</kbd>+<kbd>v</kbd>
| Habilitar/Deshabilitar contador de FPS (en stdout) | <kbd>MOD</kbd>+<kbd>i</kbd>
| Pellizcar para zoom | <kbd>Ctrl</kbd>+_click-y-mover_
_¹Doble click en los bordes negros para eliminarlos._
_²Botón derecho enciende la pantalla si estaba apagada, sino ejecuta RETROCEDER._
_³Solo en Android >= 7._
Todos los atajos <kbd>Ctrl</kbd>+_tecla_ son enviados al dispositivo para que sean manejados por la aplicación activa.
## Path personalizado
Para usar un binario de _adb_ en particular, configure el path `ADB` en las variables de entorno:
```bash
ADB=/path/to/adb scrcpy
```
Para sobreescribir el path del archivo `scrcpy-server`, configure el path en `SCRCPY_SERVER_PATH`.
## ¿Por qué _scrcpy_?
Un colega me retó a encontrar un nombre tan impronunciable como [gnirehtet].
[`strcpy`] copia un **str**ing; `scrcpy` copia un **scr**een.
[gnirehtet]: https://github.com/Genymobile/gnirehtet
[`strcpy`]: http://man7.org/linux/man-pages/man3/strcpy.3.html
## ¿Cómo construir (BUILD)?
Véase [BUILD] (en inglés).
## Problemas generales
Vea las [preguntas frecuentes (en inglés)](FAQ.md).
## Desarrolladores
Lea la [hoja de desarrolladores (en inglés)](DEVELOP.md).
## Licencia
Copyright (C) 2018 Genymobile
Copyright (C) 2018-2021 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.
## Artículos
- [Introducing scrcpy][article-intro] (en inglés)
- [Scrcpy now works wirelessly][article-tcpip] (en inglés)
[article-intro]: https://blog.rom1v.com/2018/03/introducing-scrcpy/
[article-tcpip]: https://www.genymotion.com/blog/open-source-project-scrcpy-now-works-wirelessly/

View File

@ -2,108 +2,115 @@ _Only the original [README](README.md) is guaranteed to be up-to-date._
只有原版的[README](README.md)会保持最新。
本文根据[ed130e05]进行翻译。
本文根据[479d10d]进行翻译。
[ed130e05]: https://github.com/Genymobile/scrcpy/blob/ed130e05d55615d6014d93f15cfcb92ad62b01d8/README.md
[479d10d]: https://github.com/Genymobile/scrcpy/commit/479d10dc22b70272187e0963c6ad24d754a669a2#diff-04c6e90faac2675aa89e2176d2eec7d8
# scrcpy (v1.17)
本应用程序可以显示并控制通过 USB (或 [TCP/IP][article-tcpip]) 连接的安卓设备,且不需要任何 _root_ 权限。本程序支持 _GNU/Linux_, _Windows__macOS_
# scrcpy (v1.16)
本应用程序可以通过USB或 [TCP/IP][article-tcpip] )连接用于显示或控制安卓设备。这不需要获取 _root_ 权限。
该应用程序可以在 _GNU/Linux_, _Windows__macOS_ 环境下运行。
[article-tcpip]:https://www.genymotion.com/blog/open-source-project-scrcpy-now-works-wirelessly/
![screenshot](assets/screenshot-debian-600.jpg)
它专注于:
- **轻量** (原生,仅显示设备屏幕)
- **性能** (30~60fps)
- **质量** (分辨率可达 1920×1080 或更高)
- **低延迟** ([35~70ms][lowlatency])
- **快速启动** (最快 1 秒内即可显示第一帧)
- **无侵入性** (不会在设备上遗留任何程序)
[lowlatency]: https://github.com/Genymobile/scrcpy/pull/646
- **轻量** 原生,仅显示设备屏幕
- **性能** 30~60fps
- **质量** 分辨率可达1920x1080或更高
- **低延迟** (35-70ms)
- **快速启动** (数秒内即能开始显示)
- **无侵入性** (不需要在安卓设备上安装任何程序
## 系统要求
## 使用要求
安卓设备最低需要支持 API 21 (Android 5.0)
安卓设备系统版本需要在Android 5.0API 21)或以上
确保设备已[开启 adb 调试][enable-adb]
确保您在设备上开启了[adb调试]。
[enable-adb]: https://developer.android.com/studio/command-line/adb.html#Enabling
[adb调试]: https://developer.android.com/studio/command-line/adb.html#Enabling
在某些设备上,还需要开启[额外的选项][control]以使用鼠标和键盘进行控制。
在某些设备上,还需要开启[额外的选项]用鼠标和键盘进行控制。
[control]: https://github.com/Genymobile/scrcpy/issues/70#issuecomment-373286323
[额外的选项]: https://github.com/Genymobile/scrcpy/issues/70#issuecomment-373286323
## 获取本程序
## 获取scrcpy
<a href="https://repology.org/project/scrcpy/versions"><img src="https://repology.org/badge/vertical-allrepos/scrcpy.svg" alt="Packaging status" align="right"></a>
### Linux
Debian (目前仅支持 _testing__sid_ 分支) 和Ubuntu (20.04) 上:
在Debian目前仅测试版和不稳定版,即 _testing__sid_ 版本)和Ubuntu 20.04上:
```
apt install scrcpy
```
我们也提供 [Snap] 包 [`scrcpy`][snap-link]
[Snap]包也是可用的 [`scrcpy`][snap-link].
[snap-link]: https://snapstats.org/snaps/scrcpy
[snap]: https://en.wikipedia.org/wiki/Snappy_(package_manager)
Fedora 我们提供 [COPR] 包: [`scrcpy`][copr-link]
Fedora用户,我们提供[COPR]包: [`scrcpy`][copr-link].
[COPR]: https://fedoraproject.org/wiki/Category:Copr
[copr-link]: https://copr.fedorainfracloud.org/coprs/zeno/scrcpy/
Arch Linux 我们提供 [AUR] 包: [`scrcpy`][aur-link]
Arch Linux用户,我们提供[AUR]包: [`scrcpy`][aur-link].
[AUR]: https://wiki.archlinux.org/index.php/Arch_User_Repository
[aur-link]: https://aur.archlinux.org/packages/scrcpy/
Gentoo 我们提供 [Ebuild] 包:[`scrcpy/`][ebuild-link]
Gentoo用户,我们提供[Ebuild]包:[`scrcpy/`][ebuild-link].
[Ebuild]: https://wiki.gentoo.org/wiki/Ebuild
[ebuild-link]: https://github.com/maggu2810/maggu2810-overlay/tree/master/app-mobilephone/scrcpy
您也可以[自行构建][BUILD] (不必担心,这并不困难)。
您也可以[自行编译][编译](不必担心,这并不困难)。
### Windows
Windows 上,简便起见,我们提供包含所有依赖 (包括 `adb`) 的预编译包。
在Windows上简便起见我们准备了包含所有依赖包括adb的程序包。
- [README](README.md#windows)
- [`scrcpy-win64-v1.16.zip`][direct-win64]
_(SHA-256: 3f30dc5db1a2f95c2b40a0f5de91ec1642d9f53799250a8c529bc882bc0918f0)_
也可以使用 [Chocolatey]
[direct-win64]: https://github.com/Genymobile/scrcpy/releases/download/v1.16/scrcpy-win64-v1.16.zip
您也可以在[Chocolatey]下载:
[Chocolatey]: https://chocolatey.org/
```bash
choco install scrcpy
choco install adb # 如果没有 adb
choco install adb # 如果没有adb
```
或者 [Scoop]:
也可以使用 [Scoop]:
```bash
scoop install scrcpy
scoop install adb # 如果没有 adb
scoop install adb # 如果没有adb
```
[Scoop]: https://scoop.sh
您也可以[自行构建][BUILD]。
您也可以[自行编译][编译]。
### macOS
本程序已发布到 [Homebrew]。直接安装即可
您可以使用[Homebrew]下载scrcpy。直接安装就可以了
[Homebrew]: https://brew.sh/
@ -111,28 +118,24 @@ scoop install adb # 如果还没有 adb
brew install scrcpy
```
你还需要 `PATH` 内有 `adb`。如果没有:
需要 `adb`以使用scrcpy并且它需要可以通过 `PATH`被访问。如果没有:
```bash
# Homebrew >= 2.6.0
brew install --cask android-platform-tools
# Homebrew < 2.6.0
brew cask install android-platform-tools
```
您也可以[自行构建][BUILD]。
您也可以[自行编译][编译]。
## 运行
## 运行scrcpy
连接安卓设备,然后执行:
用USB链接电脑和安卓设备,执行:
```bash
scrcpy
```
本程序支持命令行参数,查看参数列表:
支持命令行参数执行,查看参数列表:
```bash
scrcpy --help
@ -140,129 +143,111 @@ scrcpy --help
## 功能介绍
### 捕获设置
### 画面设置
#### 降低分辨率
#### 缩小分辨率
有时候,可以通过降低镜像分辨率来提高性能。
有时候,将设备屏幕镜像分辨率降低可以有效地提升性能。
要同时限制宽度和高度到某个值 (例如 1024)
我们可以将高度和宽度都限制在一定大小内(如 1024
```bash
scrcpy --max-size 1024
scrcpy -m 1024 # 简写
scrcpy -m 1024 # short version
```
一边会被按比例缩小以保持设备的显示比例。这样1920×1080 分辨率的设备会以 1024×576 的分辨率进行镜像。
较短的一边会被按比例缩小以保持设备的显示比例。
这样1920x1080 的设备会以 1024x576 的分辨率显示。
#### 修改
#### 修改画面比特
默认率是 8Mbps。要改变视频的码率 (例如改为 2Mbps)
默认的比特率是8Mbps。如果要改变画面的比特率 (比如说改成2Mbps)
```bash
scrcpy --bit-rate 2M
scrcpy -b 2M # 简写
scrcpy -b 2M # short version
```
#### 限制帧率
#### 限制画面帧率
要限制捕获的帧率
画面的帧率可以通过下面的命令被限制
```bash
scrcpy --max-fps 15
```
本功能从 Android 10 开始才被官方支持,但在一些旧版本中也能生效
这个功能仅在Android 10和以后的版本被Android官方支持但也有可能在更早的版本可用
#### 画面裁剪
可以对设备屏幕进行裁剪,只镜像屏幕的一部分
设备画面可在裁切后进行镜像,以显示部分屏幕
例如可以只镜像 Oculus Go 的一只眼睛。
这项功能可以用于,例如,只显示Oculus Go的一只眼睛。
```bash
scrcpy --crop 1224:1440:0:0 # 以 (0,0) 为原点的 1224x1440 像素
scrcpy --crop 1224:1440:0:0 # 1224x1440 at offset (0,0)
```
如果同时指定了 `--max-size`,会先进行裁剪,再进行缩放
如果`--max-size`在同时被指定,分辨率的改变将在画面裁切后进行
#### 锁定屏幕
#### 锁定屏幕
要锁定镜像画面的方向:
可以使用如下命令锁定屏幕朝向:
```bash
scrcpy --lock-video-orientation 0 # 自然
scrcpy --lock-video-orientation 1 # 逆时针旋转 90°
scrcpy --lock-video-orientation 0 # 自然
scrcpy --lock-video-orientation 1 # 90° 逆时针旋转
scrcpy --lock-video-orientation 2 # 180°
scrcpy --lock-video-orientation 3 # 顺时针旋转 90°
scrcpy --lock-video-orientation 3 # 90° 顺时针旋转
```
影响录制的方向
该设定影响录制。
[窗口可以独立旋转](#旋转)。
#### 编码器
一些设备内置了多种编码器,但是有的编码器会导致问题或崩溃。可以手动选择其它编码器:
```bash
scrcpy --encoder OMX.qcom.video.encoder.avc
```
要列出可用的编码器,可以指定一个不存在的编码器名称,错误信息中会包含所有的编码器:
```bash
scrcpy --encoder _
```
### 屏幕录制
可以在镜像的同时录制视频:
可以在屏幕镜像的同时录制视频:
```bash
scrcpy --record file.mp4
scrcpy -r file.mkv
```
仅录制,不显示镜像
在不开启屏幕镜像的同时录制
```bash
scrcpy --no-display --record file.mp4
scrcpy -Nr file.mkv
# 按 Ctrl+C 停止录制
# 按Ctrl+C停止录制
```
录制时会包含“被跳过的帧”,即使它们由于性能原因没有实时显示。设备会为每一帧打上 _时间戳_ ,所以 [包时延抖动][packet delay variation] 不会影响录制的文件。
在显示中“被跳过的帧”会被录制,虽然它们由于性能原因没有实时显示。
在传输中每一帧都有 _时间戳_ ,所以 [包时延变化] 并不影响录制的文件。
[packet delay variation]: https://en.wikipedia.org/wiki/Packet_delay_variation
[包时延变化]: https://en.wikipedia.org/wiki/Packet_delay_variation
### 连接
### 连接方式
#### 无线
_Scrcpy_ 使用 `adb` 与设备通信,并且 `adb` 支持通过 TCP/IP [连接]到设备:
_Scrcpy_ 使用`adb`来与安卓设备连接。同时,`adb`能够通过TCP/IP[连接]到安卓设备:
1. 将设备和电脑连接至同一 Wi-Fi。
2. 打开 设置 → 关于手机状态信息,获取设备的 IP 地址,也可以执行以下的命令:
```bash
adb shell ip route | awk '{print $9}'
```
1.您的安卓设备和电脑连接至同一Wi-Fi。
2. 获取安卓设备的IP地址在设置-关于手机-状态信息)。
3. 打开安卓设备的网络adb功能`adb tcpip 5555`
4. 将您的设备与电脑断开连接。
5. 连接到您的设备:`adb connect DEVICE_IP:5555` _(用设备IP替换 `DEVICE_IP`)_.
6. 运行`scrcpy`
3. 启用设备的网络 adb 功能 `adb tcpip 5555`。
4. 断开设备的 USB 连接。
5. 连接到您的设备:`adb connect DEVICE_IP:5555` _(将 `DEVICE_IP` 替换为设备 IP)_.
6. 正常运行 `scrcpy`。
可能需要降低码率和分辨率:
降低比特率和分辨率可能有助于性能:
```bash
scrcpy --bit-rate 2M --max-size 800
scrcpy -b2M -m800 # 简写
scrcpy -b2M -m800 # short version
```
[连接]: https://developer.android.com/studio/command-line/adb.html#wireless
@ -270,18 +255,18 @@ scrcpy -b2M -m800 # 简写
#### 多设备
如果 `adb devices` 列出了多个设备,您必须指定设备的 _序列号_
如果多个设备在执行`adb devices`后被列出,您必须指定设备的 _序列号_
```bash
scrcpy --serial 0123456789abcdef
scrcpy -s 0123456789abcdef # 简写
scrcpy -s 0123456789abcdef # short version
```
如果设备通过 TCP/IP 连接
如果设备通过TCP/IP方式连接到电脑的
```bash
scrcpy --serial 192.168.0.1:5555
scrcpy -s 192.168.0.1:5555 # 简写
scrcpy -s 192.168.0.1:5555 # short version
```
您可以同时启动多个 _scrcpy_ 实例以同时显示多个设备的画面。
@ -296,38 +281,38 @@ autoadb scrcpy -s '{}'
[AutoAdb]: https://github.com/rom1v/autoadb
#### SSH 隧道
#### SSH 连接
要远程连接到设备,可以将本地的 adb 客户端连接到远程的 adb 服务端 (需要两端的 _adb_ 协议版本相同)
本地的 adb 可以远程连接到另一个 adb 服务器假设两者的adb版本相同来远程连接到设备
```bash
adb kill-server # 关闭本地 5037 端口上的 adb 服务
adb kill-server # 关闭本地5037端口上的adb服务
ssh -CN -L5037:localhost:5037 -R27183:localhost:27183 your_remote_computer
# 保持该窗口开启
```
另一个终端:
另一个终端:
```bash
scrcpy
```
若要不使用远程端口转发,可以强制使用正向连接 (注意 `-L` 和 `-R` 的区别)
为了避免启动远程端口转发,可以强制启动一个转发连接(注意`-L``-R`的区别:
```bash
adb kill-server # 关闭本地 5037 端口上的 adb 服务端
adb kill-server # kill the local adb server on 5037
ssh -CN -L5037:localhost:5037 -L27183:localhost:27183 your_remote_computer
# 保持该窗口开启
```
另一个终端:
另一个终端:
```bash
scrcpy --force-adb-forward
```
类似无线网络连接,可能需要降低画面质量
无线网络连接类似,下列设置可能对改善性能有帮助
```
scrcpy -b2M -m800 --max-fps 15
@ -337,7 +322,7 @@ scrcpy -b2M -m800 --max-fps 15
#### 标题
窗口的标题默认为设备型号。可以通过如下命令修改:
窗口的标题默认为设备型号。可以通过如下命令修改
```bash
scrcpy --window-title 'My device'
@ -373,14 +358,14 @@ scrcpy --always-on-top
```bash
scrcpy --fullscreen
scrcpy -f # 简写
scrcpy -f # short version
```
全屏状态可以通过 <kbd>MOD</kbd>+<kbd>f</kbd> 随时切换
全屏状态可以通过<kbd>MOD</kbd>+<kbd>f</kbd>实时改变
#### 旋转
可以通过下命令旋转窗口
通过下命令,窗口可以旋转:
```bash
scrcpy --rotation 1
@ -388,23 +373,27 @@ scrcpy --rotation 1
可选的值有:
- `0`: 无旋转
- `1`: 逆时针旋转 90°
- `2`: 旋转 180°
- `3`: 顺时针旋转 90°
- `1`: 逆时针旋转90°
- `2`: 旋转180°
- `3`: 顺时针旋转90°
可以使用 <kbd>MOD</kbd>+<kbd>←</kbd> _(左箭头)_ 和 <kbd>MOD</kbd>+<kbd>→</kbd> _(右箭头)_ 随时更改。
这同样可以使用<kbd>MOD</kbd>+<kbd></kbd>
_(左)_<kbd>MOD</kbd>+<kbd></kbd> _(右)_ 的快捷键实时更改。
需要注意的是, _scrcpy_三个不同的向:
- <kbd>MOD</kbd>+<kbd>r</kbd> 请求设备在竖屏和横屏之间切换 (如果前台应用程序不支持请求的朝向,可能会拒绝该请求)
- [`--lock-video-orientation`](#锁定屏幕方向) 改变镜像的朝向 (设备传输到电脑的画面的朝向)。这会影响录制。
- `--rotation` (或 <kbd>MOD</kbd>+<kbd>←</kbd>/<kbd>MOD</kbd>+<kbd>→</kbd>) 只旋转窗口的内容。这只影响显示,不影响录制。
需要注意的是, _scrcpy_ 控制三个不同的向:
- <kbd>MOD</kbd>+<kbd>r</kbd> 请求设备在竖屏和横屏之间切换如果前台应用程序不支持请求的朝向,可能会拒绝该请求
- `--lock-video-orientation` 改变镜像的朝向(设备镜像到电脑的画面朝向)。这会影响录制。
- `--rotation` (或<kbd>MOD</kbd>+<kbd></kbd>/<kbd>MOD</kbd>+<kbd></kbd>
只旋转窗口的画面。这只影响显示,不影响录制。
### 其他镜像设置
#### 只读
禁用电脑对设备的控制 (如键盘输入、鼠标事件和文件拖放)
关闭电脑对设备的控制如键盘输入、鼠标移动和文件传输)
```bash
scrcpy --no-control
@ -413,49 +402,53 @@ scrcpy -n
#### 显示屏
如果设备有多个显示屏,可以选择要镜像的显示屏
如果有多个显示屏可用,您可以选择特定显示屏进行镜像
```bash
scrcpy --display 1
```
可以通过如下命令列出所有显示屏的 id
可以通过如下命令找到显示屏的id
```
adb shell dumpsys display # 在输出中搜索 “mDisplayId=”
adb shell dumpsys display # 在回显中搜索“mDisplayId=”
```
控制第二显示屏需要设备运行 Android 10 或更高版本 (否则将在只读状态下镜像)
第二显示屏可能只能在设备运行Android 10或以上的情况下被控制(它可能会在电脑上显示,但无法通过电脑操作)
#### 保持常亮
止设备在连接休眠:
止设备在连接的状态下休眠:
```bash
scrcpy --stay-awake
scrcpy -w
```
程序关闭时会恢复设备原来的设置
程序关闭后,设备设置会恢复原样
#### 关闭设备屏幕
可以通过以下的命令行参数在关闭设备屏幕的状态下进行镜像
在启动屏幕镜像时,可以通过如下命令关闭设备屏幕:
```bash
scrcpy --turn-screen-off
scrcpy -S
```
或者在任何时候按 <kbd>MOD</kbd>+<kbd>o</kbd>
或者在需要的时候按<kbd>MOD</kbd>+<kbd>o</kbd>
要重新打开屏幕,按下 <kbd>MOD</kbd>+<kbd>Shift</kbd>+<kbd>o</kbd>.
要重新打开屏幕的话,需要按<kbd>MOD</kbd>+<kbd>Shift</kbd>+<kbd>o</kbd>.
在Android上`电源` 按钮始终能把屏幕打开。为了方便,对于在 _scrcpy_ 中发出的 `电源` 事件 (通过鼠标右键或 <kbd>MOD</kbd>+<kbd>p</kbd>),会 (尽最大的努力) 在短暂的延迟后将屏幕关闭。设备上的 `电源` 按钮仍然能打开设备屏幕。
在Android上,`电源`按钮始终能把屏幕打开。
还可以同时阻止设备休眠:
为了方便,如果按下`电源`按钮的事件是通过 _scrcpy_ 发出的(通过点按鼠标右键或<kbd>MOD</kbd>+<kbd>p</kbd>),它会在短暂的延迟后将屏幕关闭。
物理的`电源`按钮仍然能打开设备屏幕。
同时,这项功能还能被用于防止设备休眠:
```bash
scrcpy --turn-screen-off --stay-awake
@ -463,11 +456,11 @@ scrcpy -Sw
```
#### 渲染过期
#### 渲染超时
默认状态下,为了降低延迟, _scrcpy_ 永远渲染解码成功的最近一帧,并跳过前面任意帧。
为了降低延迟, _scrcpy_ 默认渲染解码成功的最近一帧,并跳过前面任意帧。
强制渲染所有帧 (可能导致延迟变高)
强制渲染所有帧可能导致延迟变高
```bash
scrcpy --render-expired-frames
@ -475,9 +468,9 @@ scrcpy --render-expired-frames
#### 显示触摸
在演示时,可能会需要显示物理触摸点 (在物理设备上的触摸点)
在展示时,有些时候可能会用到显示触摸点这项功能(在设备上显示)
Android 在 _开发者选项_ 中提供了这项功能。
Android在 _开发者设置_ 中提供了这项功能。
_Scrcpy_ 提供一个选项可以在启动时开启这项功能并在退出时恢复初始设置:
@ -486,12 +479,12 @@ scrcpy --show-touches
scrcpy -t
```
请注意这项功能只能显示 _物理_ 触摸 (用手在屏幕上触摸)
请注意这项功能只能显示 _物理_ 触摸(要用手在屏幕上触摸
#### 关闭屏保
_Scrcpy_ 默认不会阻止电脑上开启的屏幕保护。
_Scrcpy_ 不会默认关闭屏幕保护。
关闭屏幕保护:
@ -504,58 +497,64 @@ scrcpy --disable-screensaver
#### 旋转设备屏幕
使用 <kbd>MOD</kbd>+<kbd>r</kbd> 在竖屏和横屏模式之间切换。
使用<kbd>MOD</kbd>+<kbd>r</kbd>在竖屏和横屏模式之间切换。
需要注意的是,只有在前台应用程序支持所要求的模式时,才会进行切换。
#### 复制
#### 复制
每次安卓的剪贴板变化时,其内容都会被自动同步到电脑的剪贴板上。
每次Android的剪贴板变化的时候,它都会被自动同步到电脑的剪贴板上。
所有的 <kbd>Ctrl</kbd> 快捷键都会被转发至设备。其中:
- <kbd>Ctrl</kbd>+<kbd>c</kbd> 通常执行复制
- <kbd>Ctrl</kbd>+<kbd>x</kbd> 通常执行剪切
- <kbd>Ctrl</kbd>+<kbd>v</kbd> 通常执行粘(在电脑到设备的剪贴板同步完成之后)
- <kbd>Ctrl</kbd>+<kbd>c</kbd> 复制
- <kbd>Ctrl</kbd>+<kbd>x</kbd> 剪切
- <kbd>Ctrl</kbd>+<kbd>v</kbd>在电脑到设备的剪贴板同步完成之后
大多数时候这些按键都会执行以上的功能
这通常如您所期望的那样运作
但实际的行为取决于设备上的前台程序。例如_Termux_ 会在按下 <kbd>Ctrl</kbd>+<kbd>c</kbd> 时发送 SIGINT又如 _K-9 Mail_ 会新建一封邮件。
但实际的行为取决于设备上的前台程序。
例如 _Termux_<kbd>Ctrl</kbd>+<kbd>c</kbd>被按下时发送 SIGINT
又如 _K-9 Mail_ 会新建一封新邮件。
在这种情况下进行剪切复制和粘贴 (仅支持 Android >= 7)
- <kbd>MOD</kbd>+<kbd>c</kbd> 注入 `COPY` (复制)
- <kbd>MOD</kbd>+<kbd>x</kbd> 注入 `CUT` (剪切)
- <kbd>MOD</kbd>+<kbd>v</kbd> 注入 `PASTE` (粘贴) (在电脑到设备的剪贴板同步完成之后)
在这种情况下剪切复制黏贴(仅在Android >= 7时可用)
- <kbd>MOD</kbd>+<kbd>c</kbd> 注入 `COPY`复制
- <kbd>MOD</kbd>+<kbd>x</kbd> 注入 `CUT`剪切
- <kbd>MOD</kbd>+<kbd>v</kbd> 注入 `PASTE`(黏贴)(在电脑到设备的剪贴板同步完成之后
另外,<kbd>MOD</kbd>+<kbd>Shift</kbd>+<kbd>v</kbd> 会将电脑的剪贴板内容转换为一串按键事件输入到设备。在应用程序不接受粘贴时 (比如 _Termux_),这项功能可以派上一定的用场。不过这项功能可能会导致非 ASCII 编码的内容出现错误
另外,<kbd>MOD</kbd>+<kbd>Shift</kbd>+<kbd>v</kbd>可以将电脑的剪贴板内容转换为一串按键事件输入到设备
在应用程序不接受黏贴时(比如 _Termux_ ),这项功能可以排上一定的用场。
需要注意的是这项功能可能会导致非ASCII编码的内容出现错误。
**警告:** 将电脑剪贴板的内容贴至设备 (无论是通过 <kbd>Ctrl</kbd>+<kbd>v</kbd> 还是 <kbd>MOD</kbd>+<kbd>v</kbd>) 都会将内容复制到设备的剪贴板。如此,任何安卓应用程序都能读取到。您应避免将敏感内容 (如密码) 通过这种方式粘贴。
**警告:** 将电脑剪贴板的内容贴至设备无论是通过<kbd>Ctrl</kbd>+<kbd>v</kbd>还是<kbd>MOD</kbd>+<kbd>v</kbd>
都需要将内容保存至设备的剪贴板。如此,任何一个应用程序都可以读取它。
您应当避免将敏感内容通过这种方式传输(如密码)。
一些设备不支持通过程序设置剪贴板。通过 `--legacy-paste` 选项可以修改 <kbd>Ctrl</kbd>+<kbd>v</kbd> 和 <kbd>MOD</kbd>+<kbd>v</kbd> 的工作方式,使它们通过按键事件 (同 <kbd>MOD</kbd>+<kbd>Shift</kbd>+<kbd>v</kbd>) 来注入电脑剪贴板内容。
#### 双指缩放
#### 捏拉缩放
模拟“双指缩放”:<kbd>Ctrl</kbd>+_按住并移动鼠标_。
模拟 “捏拉缩放”:<kbd>Ctrl</kbd>+_按住并移动鼠标_。
更准确的说,在按住鼠标左键时按住 <kbd>Ctrl</kbd>。直到松开鼠标左键,所有鼠标移动将以屏幕中心为原点,缩放或旋转内容 (如果应用支持)
更准确的说,您需要在按住<kbd>Ctrl</kbd>的同时按住并移动鼠标
在鼠标左键松开之后,光标的任何操作都会相对于屏幕的中央进行。
实际上,_scrcpy_ 会在以屏幕中心对称的位置上生成由“虚拟手指”发出的额外触摸事件。
具体来说, _scrcpy_ 使用“虚拟手指”以在相对于屏幕中央相反的位置产生触摸事件。
#### 文字注入偏好
打字的时候,系统会产生两种[事件][textevents]
- _按键事件_ ,代表一个按键被按下松开。
- _文本事件_ ,代表一个字符被输入。
- _按键事件_ ,代表一个按键被按下/松开。
- _文本事件_ ,代表一个文本被输入。
程序默认使用按键事件来输入字母。只有这样,键盘才会在游戏中正常运作 (例如 WASD 键)
程序默认使用按键事件来输入字母。只有这样,键盘才会在游戏中正常运作(尤其WASD键)
但这也有可能[造成一些问题][prefertext]。如果您遇到了问题,可以通过以下方式避免:
但这也有可能[造成问题][prefertext]。如果您遇到了这样的问题,可以通过下列操作避免
```bash
scrcpy --prefer-text
```
(这会导致键盘在游戏中工作不正常)
这会导致键盘在游戏中工作不正常
[textevents]: https://blog.rom1v.com/2018/03/introducing-scrcpy/#handle-text-input
[prefertext]: https://github.com/Genymobile/scrcpy/issues/650#issuecomment-512945343
@ -563,7 +562,8 @@ scrcpy --prefer-text
#### 按键重复
默认状态下,按住一个按键不放会生成多个重复按键事件。在某些游戏中这可能会导致性能问题
当你一直按着一个按键不放时,程序默认产生多个按键事件
在某些游戏中这可能会导致性能问题。
避免转发重复按键事件:
@ -572,27 +572,18 @@ scrcpy --no-key-repeat
```
#### 右键和中键
默认状态下,右键会触发返回键 (或电源键),中键会触发 HOME 键。要禁用这些快捷键并把所有点击转发到设备:
```bash
scrcpy --forward-all-clicks
```
### 文件拖放
### 文件传输
#### 安装APK
APK 文件 (文件名以 `.apk` 结尾) 拖放到 _scrcpy_ 窗口来安装
如果您要要安装APK请拖放APK文件文件名以`.apk`结尾)_scrcpy_ 窗口。
该操作在屏幕上不会出现任何变化,而会在控制台输出一条日志。
#### 将文件推送至设备
要推送文件到设备的 `/sdcard/`,将 (非 APK) 文件拖放至 _scrcpy_ 窗口。
如果您要推送文件到设备的 `/sdcard/`请拖放文件至不能是APK文件_scrcpy_ 窗口。
该操作没有可见的响应,只会在控制台输出日志。
@ -605,7 +596,7 @@ scrcpy --push-target /sdcard/foo/bar/
### 音频转发
_Scrcpy_ 不支持音频。请使用 [sndcpy].
_scrcpy_ 不支持音频。请使用 [sndcpy].
另外请阅读 [issue #14]。
@ -613,90 +604,93 @@ _Scrcpy_ 不支持音频。请使用 [sndcpy].
[issue #14]: https://github.com/Genymobile/scrcpy/issues/14
## 快捷
##
在以下列表中, <kbd>MOD</kbd> 是快捷键的修饰键。
默认是 (左) <kbd>Alt</kbd> 或 (左) <kbd>Super</kbd>
下列表中, <kbd>MOD</kbd> 是热键的修饰键。
默认是(左)<kbd>Alt</kbd>或者(左)<kbd>Super</kbd>
您可以使用 `--shortcut-mod` 来修改。可选的按键有 `lctrl`、`rctrl`、`lalt`、`ralt`、`lsuper` 和 `rsuper`。例如:
您可以使用 `--shortcut-mod`后缀来修改。可选的按键有`lctrl``rctrl`
`lalt``ralt``lsuper``rsuper`。如下例:
```bash
# 使用右 Ctrl
# 使用右侧的Ctrl键
scrcpy --shortcut-mod=rctrl
# 使用左 Ctrl 键 + 左 Alt 键,或 Super
# 使用左侧的Ctrl键、Alt键或Super键
scrcpy --shortcut-mod=lctrl+lalt,lsuper
```
_<kbd>[Super]</kbd> 键通常是指 <kbd>Windows</kbd><kbd>Cmd</kbd>。_
_一般来说<kbd>[Super]</kbd>就是<kbd>Windows</kbd>或者<kbd>Cmd</kbd>。_
[Super]: https://en.wikipedia.org/wiki/Super_key_(keyboard_button)
| 操作 | 快捷键 |
| --------------------------------- | :------------------------------------------- |
| 全屏 | <kbd>MOD</kbd>+<kbd>f</kbd> |
| 向左旋转屏幕 | <kbd>MOD</kbd>+<kbd>←</kbd> _(左箭头)_ |
| 向右旋转屏幕 | <kbd>MOD</kbd>+<kbd>→</kbd> _(右箭头)_ |
| 将窗口大小重置为1:1 (匹配像素) | <kbd>MOD</kbd>+<kbd>g</kbd> |
| 将窗口大小重置为消除黑边 | <kbd>MOD</kbd>+<kbd>w</kbd> \| _双击¹_ |
| 点按 `主屏幕` | <kbd>MOD</kbd>+<kbd>h</kbd> \| _鼠标中键_ |
| 点按 `返回` | <kbd>MOD</kbd>+<kbd>b</kbd> \| _鼠标右键²_ |
| 点按 `切换应用` | <kbd>MOD</kbd>+<kbd>s</kbd> |
| 点按 `菜单` (解锁屏幕) | <kbd>MOD</kbd>+<kbd>m</kbd> |
| 点按 `音量+` | <kbd>MOD</kbd>+<kbd>↑</kbd> _(上箭头)_ |
| 点按 `音量-` | <kbd>MOD</kbd>+<kbd>↓</kbd> _(下箭头)_ |
| 点按 `电源` | <kbd>MOD</kbd>+<kbd>p</kbd> |
| 打开屏幕 | _鼠标右键²_ |
| 关闭设备屏幕 (但继续在电脑上显示) | <kbd>MOD</kbd>+<kbd>o</kbd> |
| 打开设备屏幕 | <kbd>MOD</kbd>+<kbd>Shift</kbd>+<kbd>o</kbd> |
| 旋转设备屏幕 | <kbd>MOD</kbd>+<kbd>r</kbd> |
| 展开通知面板 | <kbd>MOD</kbd>+<kbd>n</kbd> |
| 收起通知面板 | <kbd>MOD</kbd>+<kbd>Shift</kbd>+<kbd>n</kbd> |
| 复制到剪贴板³ | <kbd>MOD</kbd>+<kbd>c</kbd> |
| 剪切到剪贴板³ | <kbd>MOD</kbd>+<kbd>x</kbd> |
| 同步剪贴板并贴³ | <kbd>MOD</kbd>+<kbd>v</kbd> |
| 入电脑剪贴板文本 | <kbd>MOD</kbd>+<kbd>Shift</kbd>+<kbd>v</kbd> |
| 打开/关闭FPS显示 (在 stdout) | <kbd>MOD</kbd>+<kbd>i</kbd> |
| 捏拉缩放 | <kbd>Ctrl</kbd>+_按住并移动鼠标_ |
| 操作 | 快捷键
| ------------------------------------------- |:-----------------------------
| 全屏 | <kbd>MOD</kbd>+<kbd>f</kbd>
| 向左旋转屏幕 | <kbd>MOD</kbd>+<kbd></kbd> _(左)_
| 向右旋转屏幕 | <kbd>MOD</kbd>+<kbd></kbd> _(右)_
| 将窗口大小重置为1:1 (像素优先) | <kbd>MOD</kbd>+<kbd>g</kbd>
| 将窗口大小重置为消除黑边 | <kbd>MOD</kbd>+<kbd>w</kbd> \| _双击¹_
| 点按 `主屏幕` | <kbd>MOD</kbd>+<kbd>h</kbd> \| _点击鼠标中键_
| 点按 `返回` | <kbd>MOD</kbd>+<kbd>b</kbd> \| _点击鼠标右键²_
| 点按 `切换应用` | <kbd>MOD</kbd>+<kbd>s</kbd>
| 点按 `菜单` (解锁屏幕) | <kbd>MOD</kbd>+<kbd>m</kbd>
| 点按 `音量+` | <kbd>MOD</kbd>+<kbd></kbd> _(up)_
| 点按 `音量-` | <kbd>MOD</kbd>+<kbd></kbd> _(down)_
| 点按 `电源` | <kbd>MOD</kbd>+<kbd>p</kbd>
| 打开屏幕 | _点击鼠标右键²_
| 关闭设备屏幕但继续在电脑上显示 | <kbd>MOD</kbd>+<kbd>o</kbd>
| 打开设备屏幕 | <kbd>MOD</kbd>+<kbd>Shift</kbd>+<kbd>o</kbd>
| 旋转设备屏幕 | <kbd>MOD</kbd>+<kbd>r</kbd>
| 展开通知面板 | <kbd>MOD</kbd>+<kbd>n</kbd>
| 展开快捷操作 | <kbd>MOD</kbd>+<kbd>Shift</kbd>+<kbd>n</kbd>
| 复制到剪贴板³ | <kbd>MOD</kbd>+<kbd>c</kbd>
| 剪切到剪贴板³ | <kbd>MOD</kbd>+<kbd>x</kbd>
| 同步剪贴板并贴³ | <kbd>MOD</kbd>+<kbd>v</kbd>
| 入电脑剪贴板文本 | <kbd>MOD</kbd>+<kbd>Shift</kbd>+<kbd>v</kbd>
| 打开/关闭FPS显示在 stdout) | <kbd>MOD</kbd>+<kbd>i</kbd>
| 捏拉缩放 | <kbd>Ctrl</kbd>+_点按并移动鼠标_
_¹双击黑边可以去除黑边_
_²点击鼠标右键将在屏幕熄灭时点亮屏幕其余情况则视为按下返回键 。_
_¹双击黑色边界以关闭黑色边界_
_²点击鼠标右键将在屏幕熄灭时点亮屏幕其余情况则视为按下 返回键 。_
_³需要安卓版本 Android >= 7。_
所有的 <kbd>Ctrl</kbd>+_按键_ 的快捷键都被转发到设备,所以会由当前应用程序进行处理
所有的 <kbd>Ctrl</kbd>+_按键_ 的键都被转发到设备进行处理的,所以实际上会由当前应用程序对其做出响应
## 自定义路径
要使用指定的 _adb_ 二进制文件,可以设置环境变量 `ADB`
为了使用您想使用_adb_ ,您可以在环境变量
`ADB`中设置它的路径:
ADB=/path/to/adb scrcpy
要覆盖 `scrcpy-server` 的路径,可以设置 `SCRCPY_SERVER_PATH`。
如果需要覆盖`scrcpy-server`的路径,可以
`SCRCPY_SERVER_PATH`中设置它。
[useful]: https://github.com/Genymobile/scrcpy/issues/278#issuecomment-429330345
## 为什么叫 _scrcpy_
一个同事让我找出一个和 [gnirehtet] 一样难以发音的名字。
一个同事让我找出一个和[gnirehtet]一样难以发音的名字。
[`strcpy`] 复制一个 **str**ing `scrcpy` 复制一个 **scr**een。
[`strcpy`] 可以复制**str**ing `scrcpy` 可以复制**scr**een。
[gnirehtet]: https://github.com/Genymobile/gnirehtet
[`strcpy`]: http://man7.org/linux/man-pages/man3/strcpy.3.html
## 如何构建
## 如何编译
请查看[BUILD]。
请查看[编译]。
[BUILD]: BUILD.md
[编译]: BUILD.md
## 常见问题
请查看[FAQ](FAQ.md)
请查看[FAQ](FAQ.md).
## 开发者

View File

@ -80,7 +80,10 @@ apt install scrcpy
為了保持簡單Windows 用戶可以下載一個包含所有必需軟體 (包含 `adb`) 的壓縮包:
- [README](README.md#windows)
- [`scrcpy-win64-v1.15.zip`][direct-win64]
_(SHA-256: dd514bb591e63ef4cd52a53c30f1153a28f59722d64690eb07bd017849edcba2)_
[direct-win64]: https://github.com/Genymobile/scrcpy/releases/download/v1.15/scrcpy-win64-v1.15.zip
[Chocolatey] 上也可以下載:

View File

@ -6,11 +6,11 @@ src = [
'src/control_msg.c',
'src/controller.c',
'src/decoder.c',
'src/device.c',
'src/device_msg.c',
'src/event_converter.c',
'src/file_handler.c',
'src/fps_counter.c',
'src/frame_buffer.c',
'src/input_manager.c',
'src/opengl.c',
'src/receiver.c',
@ -21,7 +21,6 @@ src = [
'src/stream.c',
'src/tiny_xpm.c',
'src/video_buffer.c',
'src/util/log.c',
'src/util/net.c',
'src/util/process.c',
'src/util/str_util.c',

View File

@ -133,7 +133,7 @@ but breaks the expected behavior of alpha keys in games (typically WASD).
.BI "\-\-push\-target " path
Set the target directory for pushing files to the device by drag & drop. It is passed as\-is to "adb push".
Default is "/sdcard/Download/".
Default is "/sdcard/".
.TP
.BI "\-r, \-\-record " file
@ -193,7 +193,7 @@ It requires to lock the video orientation (see --lock-video-orientation).
.TP
.BI "\-V, \-\-verbosity " value
Set the log level ("verbose", "debug", "info", "warn" or "error").
Set the log level ("debug", "info", "warn" or "error").
Default is "info" for release builds, "debug" for debug builds.
@ -217,25 +217,25 @@ Set a custom window title.
.BI "\-\-window\-x " value
Set the initial window horizontal position.
Default is "auto".
Default is "auto".\n
.TP
.BI "\-\-window\-y " value
Set the initial window vertical position.
Default is "auto".
Default is "auto".\n
.TP
.BI "\-\-window\-width " value
Set the initial window width.
Default is 0 (automatic).
Default is 0 (automatic).\n
.TP
.BI "\-\-window\-height " value
Set the initial window height.
Default is 0 (automatic).
Default is 0 (automatic).\n
.SH SHORTCUTS

View File

@ -81,20 +81,14 @@ show_adb_installation_msg() {
static void
show_adb_err_msg(enum process_result err, const char *const argv[]) {
#define MAX_COMMAND_STRING_LEN 1024
char *buf = malloc(MAX_COMMAND_STRING_LEN);
if (!buf) {
LOGE("Failed to execute (could not allocate error message)");
return;
}
char buf[512];
switch (err) {
case PROCESS_ERROR_GENERIC:
argv_to_string(argv, buf, MAX_COMMAND_STRING_LEN);
argv_to_string(argv, buf, sizeof(buf));
LOGE("Failed to execute: %s", buf);
break;
case PROCESS_ERROR_MISSING_BINARY:
argv_to_string(argv, buf, MAX_COMMAND_STRING_LEN);
argv_to_string(argv, buf, sizeof(buf));
LOGE("Command not found: %s", buf);
LOGE("(make 'adb' accessible from your PATH or define its full"
"path in the ADB environment variable)");
@ -104,38 +98,29 @@ show_adb_err_msg(enum process_result err, const char *const argv[]) {
// do nothing
break;
}
free(buf);
}
process_t
adb_execute(const char *serial, const char *const adb_cmd[], size_t len) {
const char *cmd[len + 4];
int i;
process_t process;
const char **argv = malloc((len + 4) * sizeof(*argv));
if (!argv) {
return PROCESS_NONE;
}
argv[0] = get_adb_command();
cmd[0] = get_adb_command();
if (serial) {
argv[1] = "-s";
argv[2] = serial;
cmd[1] = "-s";
cmd[2] = serial;
i = 3;
} else {
i = 1;
}
memcpy(&argv[i], adb_cmd, len * sizeof(const char *));
argv[len + i] = NULL;
enum process_result r = process_execute(argv, &process);
memcpy(&cmd[i], adb_cmd, len * sizeof(const char *));
cmd[len + i] = NULL;
enum process_result r = process_execute(cmd, &process);
if (r != PROCESS_SUCCESS) {
show_adb_err_msg(r, argv);
process = PROCESS_NONE;
show_adb_err_msg(r, cmd);
return PROCESS_NONE;
}
free(argv);
return process;
}

View File

@ -21,7 +21,7 @@
#define _ANDROID_INPUT_H
/**
* Meta key / modifier state.
* Meta key / modifer state.
*/
enum android_metastate {
/** No meta keys are pressed. */

View File

@ -129,7 +129,7 @@ scrcpy_print_usage(const char *arg0) {
" --push-target path\n"
" Set the target directory for pushing files to the device by\n"
" drag & drop. It is passed as-is to \"adb push\".\n"
" Default is \"/sdcard/Download/\".\n"
" Default is \"/sdcard/\".\n"
"\n"
" -r, --record file.mp4\n"
" Record screen to file.\n"
@ -184,7 +184,7 @@ scrcpy_print_usage(const char *arg0) {
"\n"
#endif
" -V, --verbosity value\n"
" Set the log level (verbose, debug, info, warn or error).\n"
" Set the log level (debug, info, warn or error).\n"
#ifndef NDEBUG
" Default is debug.\n"
#else
@ -217,7 +217,7 @@ scrcpy_print_usage(const char *arg0) {
" Default is 0 (automatic).\n"
"\n"
" --window-height value\n"
" Set the initial window height.\n"
" Set the initial window width.\n"
" Default is 0 (automatic).\n"
"\n"
"Shortcuts:\n"
@ -505,11 +505,6 @@ parse_display_id(const char *s, uint32_t *display_id) {
static bool
parse_log_level(const char *s, enum sc_log_level *log_level) {
if (!strcmp(s, "verbose")) {
*log_level = SC_LOG_LEVEL_VERBOSE;
return true;
}
if (!strcmp(s, "debug")) {
*log_level = SC_LOG_LEVEL_DEBUG;
return true;
@ -962,8 +957,7 @@ scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]) {
if (opts->record_filename && !opts->record_format) {
opts->record_format = guess_record_format(opts->record_filename);
if (!opts->record_format) {
LOGE("No format specified for \"%s\" "
"(try with --record-format=mkv)",
LOGE("No format specified for \"%s\" (try with -F mkv)",
opts->record_filename);
return false;
}

View File

@ -22,18 +22,6 @@
# define SCRCPY_LAVF_REQUIRES_REGISTER_ALL
#endif
// In ffmpeg/doc/APIchanges:
// 2018-01-28 - ea3672b7d6 - lavf 58.7.100 - avformat.h
// Deprecate AVFormatContext filename field which had limited length, use the
// new dynamically allocated url field instead.
//
// 2018-01-28 - ea3672b7d6 - lavf 58.7.100 - avformat.h
// Add url field to AVFormatContext and add ff_format_set_url helper function.
#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(58, 7, 100)
# define SCRCPY_LAVF_HAS_AVFORMATCONTEXT_URL
#endif
#if SDL_VERSION_ATLEAST(2, 0, 5)
// <https://wiki.libsdl.org/SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH>
# define SCRCPY_SDL_HAS_HINT_MOUSE_FOCUS_CLICKTHROUGH

View File

@ -1,7 +1,6 @@
#include "control_msg.h"
#include <assert.h>
#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
@ -9,52 +8,6 @@
#include "util/log.h"
#include "util/str_util.h"
/**
* Map an enum value to a string based on an array, without crashing on an
* out-of-bounds index.
*/
#define ENUM_TO_LABEL(labels, value) \
((size_t) (value) < ARRAY_LEN(labels) ? labels[value] : "???")
#define KEYEVENT_ACTION_LABEL(value) \
ENUM_TO_LABEL(android_keyevent_action_labels, value)
#define MOTIONEVENT_ACTION_LABEL(value) \
ENUM_TO_LABEL(android_motionevent_action_labels, value)
#define SCREEN_POWER_MODE_LABEL(value) \
ENUM_TO_LABEL(screen_power_mode_labels, value)
static const char *const android_keyevent_action_labels[] = {
"down",
"up",
"multi",
};
static const char *const android_motionevent_action_labels[] = {
"down",
"up",
"move",
"cancel",
"outside",
"ponter-down",
"pointer-up",
"hover-move",
"scroll",
"hover-enter"
"hover-exit",
"btn-press",
"btn-release",
};
static const char *const screen_power_mode_labels[] = {
"off",
"doze",
"normal",
"doze-suspend",
"suspend",
};
static void
write_position(uint8_t *buf, const struct position *position) {
buffer_write32be(&buf[0], position->point.x);
@ -140,94 +93,6 @@ control_msg_serialize(const struct control_msg *msg, unsigned char *buf) {
}
}
void
control_msg_log(const struct control_msg *msg) {
#define LOG_CMSG(fmt, ...) LOGV("input: " fmt, ## __VA_ARGS__)
switch (msg->type) {
case CONTROL_MSG_TYPE_INJECT_KEYCODE:
LOG_CMSG("key %-4s code=%d repeat=%" PRIu32 " meta=%06lx",
KEYEVENT_ACTION_LABEL(msg->inject_keycode.action),
(int) msg->inject_keycode.keycode,
msg->inject_keycode.repeat,
(long) msg->inject_keycode.metastate);
break;
case CONTROL_MSG_TYPE_INJECT_TEXT:
LOG_CMSG("text \"%s\"", msg->inject_text.text);
break;
case CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT: {
int action = msg->inject_touch_event.action
& AMOTION_EVENT_ACTION_MASK;
uint64_t id = msg->inject_touch_event.pointer_id;
if (id == POINTER_ID_MOUSE || id == POINTER_ID_VIRTUAL_FINGER) {
// string pointer id
LOG_CMSG("touch [id=%s] %-4s position=%" PRIi32 ",%" PRIi32
" pressure=%g buttons=%06lx",
id == POINTER_ID_MOUSE ? "mouse" : "vfinger",
MOTIONEVENT_ACTION_LABEL(action),
msg->inject_touch_event.position.point.x,
msg->inject_touch_event.position.point.y,
msg->inject_touch_event.pressure,
(long) msg->inject_touch_event.buttons);
} else {
// numeric pointer id
#ifndef __WIN32
# define PRIu64_ PRIu64
#else
# define PRIu64_ "I64u" // Windows...
#endif
LOG_CMSG("touch [id=%" PRIu64_ "] %-4s position=%" PRIi32 ",%"
PRIi32 " pressure=%g buttons=%06lx",
id,
MOTIONEVENT_ACTION_LABEL(action),
msg->inject_touch_event.position.point.x,
msg->inject_touch_event.position.point.y,
msg->inject_touch_event.pressure,
(long) msg->inject_touch_event.buttons);
}
break;
}
case CONTROL_MSG_TYPE_INJECT_SCROLL_EVENT:
LOG_CMSG("scroll position=%" PRIi32 ",%" PRIi32 " hscroll=%" PRIi32
" vscroll=%" PRIi32,
msg->inject_scroll_event.position.point.x,
msg->inject_scroll_event.position.point.y,
msg->inject_scroll_event.hscroll,
msg->inject_scroll_event.vscroll);
break;
case CONTROL_MSG_TYPE_BACK_OR_SCREEN_ON:
LOG_CMSG("back-or-screen-on %s",
KEYEVENT_ACTION_LABEL(msg->inject_keycode.action));
break;
case CONTROL_MSG_TYPE_SET_CLIPBOARD:
LOG_CMSG("clipboard %s \"%s\"",
msg->set_clipboard.paste ? "paste" : "copy",
msg->set_clipboard.text);
break;
case CONTROL_MSG_TYPE_SET_SCREEN_POWER_MODE:
LOG_CMSG("power mode %s",
SCREEN_POWER_MODE_LABEL(msg->set_screen_power_mode.mode));
break;
case CONTROL_MSG_TYPE_EXPAND_NOTIFICATION_PANEL:
LOG_CMSG("expand notification panel");
break;
case CONTROL_MSG_TYPE_EXPAND_SETTINGS_PANEL:
LOG_CMSG("expand settings panel");
break;
case CONTROL_MSG_TYPE_COLLAPSE_PANELS:
LOG_CMSG("collapse panels");
break;
case CONTROL_MSG_TYPE_GET_CLIPBOARD:
LOG_CMSG("get clipboard");
break;
case CONTROL_MSG_TYPE_ROTATE_DEVICE:
LOG_CMSG("rotate device");
break;
default:
LOG_CMSG("unknown type: %u", (unsigned) msg->type);
break;
}
}
void
control_msg_destroy(struct control_msg *msg) {
switch (msg->type) {

View File

@ -17,8 +17,8 @@
// type: 1 byte; paste flag: 1 byte; length: 4 bytes
#define CONTROL_MSG_CLIPBOARD_TEXT_MAX_LENGTH (CONTROL_MSG_MAX_SIZE - 6)
#define POINTER_ID_MOUSE UINT64_C(-1)
#define POINTER_ID_VIRTUAL_FINGER UINT64_C(-2)
#define POINTER_ID_MOUSE UINT64_C(-1);
#define POINTER_ID_VIRTUAL_FINGER UINT64_C(-2);
enum control_msg_type {
CONTROL_MSG_TYPE_INJECT_KEYCODE,
@ -84,9 +84,6 @@ struct control_msg {
size_t
control_msg_serialize(const struct control_msg *msg, unsigned char *buf);
void
control_msg_log(const struct control_msg *msg);
void
control_msg_destroy(struct control_msg *msg);

View File

@ -48,10 +48,6 @@ controller_destroy(struct controller *controller) {
bool
controller_push_msg(struct controller *controller,
const struct control_msg *msg) {
if (sc_get_log_level() <= SC_LOG_LEVEL_VERBOSE) {
control_msg_log(msg);
}
sc_mutex_lock(&controller->mutex);
bool was_empty = cbuf_is_empty(&controller->queue);
bool res = cbuf_push(&controller->queue, *msg);

View File

@ -140,8 +140,6 @@ decoder_packet_sink_push(struct sc_packet_sink *sink, const AVPacket *packet) {
void
decoder_init(struct decoder *decoder) {
decoder->sink_count = 0;
static const struct sc_packet_sink_ops ops = {
.open = decoder_packet_sink_open,
.close = decoder_packet_sink_close,

23
app/src/device.c Normal file
View File

@ -0,0 +1,23 @@
#include "device.h"
#include "util/log.h"
bool
device_read_info(socket_t device_socket, char *device_name, struct size *size) {
unsigned char buf[DEVICE_NAME_FIELD_LENGTH + 4];
int r = net_recv_all(device_socket, buf, sizeof(buf));
if (r < DEVICE_NAME_FIELD_LENGTH + 4) {
LOGE("Could not retrieve device information");
return false;
}
// in case the client sends garbage
buf[DEVICE_NAME_FIELD_LENGTH - 1] = '\0';
// strcpy is safe here, since name contains at least
// DEVICE_NAME_FIELD_LENGTH bytes and strlen(buf) < DEVICE_NAME_FIELD_LENGTH
strcpy(device_name, (char *) buf);
size->width = (buf[DEVICE_NAME_FIELD_LENGTH] << 8)
| buf[DEVICE_NAME_FIELD_LENGTH + 1];
size->height = (buf[DEVICE_NAME_FIELD_LENGTH + 2] << 8)
| buf[DEVICE_NAME_FIELD_LENGTH + 3];
return true;
}

17
app/src/device.h Normal file
View File

@ -0,0 +1,17 @@
#ifndef DEVICE_H
#define DEVICE_H
#include "common.h"
#include <stdbool.h>
#include "coords.h"
#include "util/net.h"
#define DEVICE_NAME_FIELD_LENGTH 64
// name must be at least DEVICE_NAME_FIELD_LENGTH bytes
bool
device_read_info(socket_t device_socket, char *device_name, struct size *size);
#endif

View File

@ -14,7 +14,7 @@ convert_keycode_action(SDL_EventType from, enum android_keyevent_action *to) {
static enum android_metastate
autocomplete_metastate(enum android_metastate metastate) {
// fill dependent flags
// fill dependant flags
if (metastate & (AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_RIGHT_ON)) {
metastate |= AMETA_SHIFT_ON;
}

View File

@ -6,7 +6,7 @@
#include "adb.h"
#include "util/log.h"
#define DEFAULT_PUSH_TARGET "/sdcard/Download/"
#define DEFAULT_PUSH_TARGET "/sdcard/"
static void
file_handler_request_destroy(struct file_handler_request *req) {

View File

@ -150,10 +150,6 @@ fps_counter_interrupt(struct fps_counter *counter) {
void
fps_counter_join(struct fps_counter *counter) {
if (counter->thread_started) {
// interrupted must be set by the thread calling join(), so no need to
// lock for the assertion
assert(counter->interrupted);
sc_thread_join(&counter->thread, NULL);
}
}

View File

@ -1,88 +0,0 @@
#include "frame_buffer.h"
#include <assert.h>
#include <libavutil/avutil.h>
#include <libavformat/avformat.h>
#include "util/log.h"
bool
sc_frame_buffer_init(struct sc_frame_buffer *fb) {
fb->pending_frame = av_frame_alloc();
if (!fb->pending_frame) {
return false;
}
fb->tmp_frame = av_frame_alloc();
if (!fb->tmp_frame) {
av_frame_free(&fb->pending_frame);
return false;
}
bool ok = sc_mutex_init(&fb->mutex);
if (!ok) {
av_frame_free(&fb->pending_frame);
av_frame_free(&fb->tmp_frame);
return false;
}
// there is initially no frame, so consider it has already been consumed
fb->pending_frame_consumed = true;
return true;
}
void
sc_frame_buffer_destroy(struct sc_frame_buffer *fb) {
sc_mutex_destroy(&fb->mutex);
av_frame_free(&fb->pending_frame);
av_frame_free(&fb->tmp_frame);
}
static inline void
swap_frames(AVFrame **lhs, AVFrame **rhs) {
AVFrame *tmp = *lhs;
*lhs = *rhs;
*rhs = tmp;
}
bool
sc_frame_buffer_push(struct sc_frame_buffer *fb, const AVFrame *frame,
bool *previous_frame_skipped) {
sc_mutex_lock(&fb->mutex);
// Use a temporary frame to preserve pending_frame in case of error.
// tmp_frame is an empty frame, no need to call av_frame_unref() beforehand.
int r = av_frame_ref(fb->tmp_frame, frame);
if (r) {
LOGE("Could not ref frame: %d", r);
return false;
}
// Now that av_frame_ref() succeeded, we can replace the previous
// pending_frame
swap_frames(&fb->pending_frame, &fb->tmp_frame);
av_frame_unref(fb->tmp_frame);
if (previous_frame_skipped) {
*previous_frame_skipped = !fb->pending_frame_consumed;
}
fb->pending_frame_consumed = false;
sc_mutex_unlock(&fb->mutex);
return true;
}
void
sc_frame_buffer_consume(struct sc_frame_buffer *fb, AVFrame *dst) {
sc_mutex_lock(&fb->mutex);
assert(!fb->pending_frame_consumed);
fb->pending_frame_consumed = true;
av_frame_move_ref(dst, fb->pending_frame);
// av_frame_move_ref() resets its source frame, so no need to call
// av_frame_unref()
sc_mutex_unlock(&fb->mutex);
}

View File

@ -1,44 +0,0 @@
#ifndef SC_FRAME_BUFFER_H
#define SC_FRAME_BUFFER_H
#include "common.h"
#include <stdbool.h>
#include "util/thread.h"
// forward declarations
typedef struct AVFrame AVFrame;
/**
* A frame buffer holds 1 pending frame, which is the last frame received from
* the producer (typically, the decoder).
*
* If a pending frame has not been consumed when the producer pushes a new
* frame, then it is lost. The intent is to always provide access to the very
* last frame to minimize latency.
*/
struct sc_frame_buffer {
AVFrame *pending_frame;
AVFrame *tmp_frame; // To preserve the pending frame on error
sc_mutex mutex;
bool pending_frame_consumed;
};
bool
sc_frame_buffer_init(struct sc_frame_buffer *fb);
void
sc_frame_buffer_destroy(struct sc_frame_buffer *fb);
bool
sc_frame_buffer_push(struct sc_frame_buffer *fb, const AVFrame *frame,
bool *skipped);
void
sc_frame_buffer_consume(struct sc_frame_buffer *fb, AVFrame *dst);
#endif

View File

@ -52,13 +52,9 @@ is_shortcut_mod(struct input_manager *im, uint16_t sdl_mod) {
}
void
input_manager_init(struct input_manager *im, struct controller *controller,
struct screen *screen,
const struct scrcpy_options *options) {
im->controller = controller;
im->screen = screen;
im->repeat = 0;
input_manager_init(struct input_manager *im,
const struct scrcpy_options *options)
{
im->control = options->control;
im->forward_key_repeat = options->forward_key_repeat;
im->prefer_text = options->prefer_text;
@ -521,7 +517,7 @@ input_manager_process_key(struct input_manager *im,
return;
case SDLK_i:
if (!shift && !repeat && down) {
switch_fps_counter_state(&im->screen->fps_counter);
switch_fps_counter_state(im->fps_counter);
}
return;
case SDLK_n:
@ -595,12 +591,8 @@ convert_mouse_motion(const SDL_MouseMotionEvent *from, struct screen *screen,
static void
input_manager_process_mouse_motion(struct input_manager *im,
const SDL_MouseMotionEvent *event) {
uint32_t mask = SDL_BUTTON_LMASK;
if (im->forward_all_clicks) {
mask |= SDL_BUTTON_MMASK | SDL_BUTTON_RMASK;
}
if (!(event->state & mask)) {
// do not send motion events when no click is pressed
if (!event->state) {
// do not send motion events when no button is pressed
return;
}
if (event->which == SDL_TOUCH_MOUSEID) {

View File

@ -14,6 +14,7 @@
struct input_manager {
struct controller *controller;
struct fps_counter *fps_counter;
struct screen *screen;
// SDL reports repeated events as a boolean, but Android expects the actual
@ -42,8 +43,8 @@ struct input_manager {
};
void
input_manager_init(struct input_manager *im, struct controller *controller,
struct screen *screen, const struct scrcpy_options *options);
input_manager_init(struct input_manager *im,
const struct scrcpy_options *options);
bool
input_manager_handle_event(struct input_manager *im, SDL_Event *event);

View File

@ -38,6 +38,24 @@ print_version(void) {
#endif
}
static SDL_LogPriority
convert_log_level_to_sdl(enum sc_log_level level) {
switch (level) {
case SC_LOG_LEVEL_DEBUG:
return SDL_LOG_PRIORITY_DEBUG;
case SC_LOG_LEVEL_INFO:
return SDL_LOG_PRIORITY_INFO;
case SC_LOG_LEVEL_WARN:
return SDL_LOG_PRIORITY_WARN;
case SC_LOG_LEVEL_ERROR:
return SDL_LOG_PRIORITY_ERROR;
default:
assert(!"unexpected log level");
return SDL_LOG_PRIORITY_INFO;
}
}
int
main(int argc, char *argv[]) {
#ifdef __WINDOWS__
@ -61,7 +79,8 @@ main(int argc, char *argv[]) {
return 1;
}
sc_set_log_level(args.opts.log_level);
SDL_LogPriority sdl_log = convert_log_level_to_sdl(args.opts.log_level);
SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, sdl_log);
if (args.help) {
scrcpy_print_usage(argv[0]);

View File

@ -35,14 +35,11 @@ record_packet_new(const AVPacket *packet) {
return NULL;
}
rec->packet = av_packet_alloc();
if (!rec->packet) {
free(rec);
return NULL;
}
// av_packet_ref() does not initialize all fields in old FFmpeg versions
// See <https://github.com/Genymobile/scrcpy/issues/707>
av_init_packet(&rec->packet);
if (av_packet_ref(rec->packet, packet)) {
av_packet_free(&rec->packet);
if (av_packet_ref(&rec->packet, packet)) {
free(rec);
return NULL;
}
@ -51,8 +48,7 @@ record_packet_new(const AVPacket *packet) {
static void
record_packet_delete(struct record_packet *rec) {
av_packet_unref(rec->packet);
av_packet_free(&rec->packet);
av_packet_unref(&rec->packet);
free(rec);
}
@ -148,8 +144,8 @@ run_recorder(void *data) {
struct record_packet *last = recorder->previous;
if (last) {
// assign an arbitrary duration to the last packet
last->packet->duration = 100000;
bool ok = recorder_write(recorder, last->packet);
last->packet.duration = 100000;
bool ok = recorder_write(recorder, &last->packet);
if (!ok) {
// failing to write the last frame is not very serious, no
// future frame may depend on it, so the resulting file
@ -176,14 +172,13 @@ run_recorder(void *data) {
}
// config packets have no PTS, we must ignore them
if (rec->packet->pts != AV_NOPTS_VALUE
&& previous->packet->pts != AV_NOPTS_VALUE) {
if (rec->packet.pts != AV_NOPTS_VALUE
&& previous->packet.pts != AV_NOPTS_VALUE) {
// we now know the duration of the previous packet
previous->packet->duration =
rec->packet->pts - previous->packet->pts;
previous->packet.duration = rec->packet.pts - previous->packet.pts;
}
bool ok = recorder_write(recorder, previous->packet);
bool ok = recorder_write(recorder, &previous->packet);
record_packet_delete(previous);
if (!ok) {
LOGE("Could not record packet");

View File

@ -13,7 +13,7 @@
#include "util/thread.h"
struct record_packet {
AVPacket *packet;
AVPacket packet;
struct record_packet *next;
};

View File

@ -15,8 +15,10 @@
#include "controller.h"
#include "decoder.h"
#include "device.h"
#include "events.h"
#include "file_handler.h"
#include "fps_counter.h"
#include "input_manager.h"
#include "recorder.h"
#include "screen.h"
@ -29,18 +31,30 @@
# include "v4l2_sink.h"
#endif
struct scrcpy {
struct server server;
struct screen screen;
struct stream stream;
struct decoder decoder;
struct recorder recorder;
static struct server server;
static struct screen screen;
static struct fps_counter fps_counter;
static struct stream stream;
static struct decoder decoder;
static struct recorder recorder;
#ifdef HAVE_V4L2
struct sc_v4l2_sink v4l2_sink;
static struct sc_v4l2_sink v4l2_sink;
#endif
struct controller controller;
struct file_handler file_handler;
struct input_manager input_manager;
static struct controller controller;
static struct file_handler file_handler;
static struct input_manager input_manager = {
.controller = &controller,
.fps_counter = &fps_counter,
.screen = &screen,
.repeat = 0,
// initialized later
.prefer_text = false,
.sdl_shortcut_mods = {
.data = {0},
.count = 0,
},
};
#ifdef _WIN32
@ -131,8 +145,7 @@ enum event_result {
};
static enum event_result
handle_event(struct scrcpy *s, const struct scrcpy_options *options,
SDL_Event *event) {
handle_event(SDL_Event *event, const struct scrcpy_options *options) {
switch (event->type) {
case EVENT_STREAM_STOPPED:
LOGD("Video stream stopped");
@ -157,17 +170,17 @@ handle_event(struct scrcpy *s, const struct scrcpy_options *options,
} else {
action = ACTION_PUSH_FILE;
}
file_handler_request(&s->file_handler, action, file);
file_handler_request(&file_handler, action, file);
goto end;
}
}
bool consumed = screen_handle_event(&s->screen, event);
bool consumed = screen_handle_event(&screen, event);
if (consumed) {
goto end;
}
consumed = input_manager_handle_event(&s->input_manager, event);
consumed = input_manager_handle_event(&input_manager, event);
(void) consumed;
end:
@ -175,10 +188,10 @@ end:
}
static bool
event_loop(struct scrcpy *s, const struct scrcpy_options *options) {
event_loop(const struct scrcpy_options *options) {
SDL_Event event;
while (SDL_WaitEvent(&event)) {
enum event_result result = handle_event(s, options, &event);
enum event_result result = handle_event(&event, options);
switch (result) {
case EVENT_RESULT_STOPPED_BY_USER:
return true;
@ -216,41 +229,24 @@ av_log_callback(void *avcl, int level, const char *fmt, va_list vl) {
if (priority == 0) {
return;
}
size_t fmt_len = strlen(fmt);
char *local_fmt = malloc(fmt_len + 10);
char *local_fmt = malloc(strlen(fmt) + 10);
if (!local_fmt) {
LOGC("Could not allocate string");
return;
}
memcpy(local_fmt, "[FFmpeg] ", 9); // do not write the final '\0'
memcpy(local_fmt + 9, fmt, fmt_len + 1); // include '\0'
// strcpy is safe here, the destination is large enough
strcpy(local_fmt, "[FFmpeg] ");
strcpy(local_fmt + 9, fmt);
SDL_LogMessageV(SDL_LOG_CATEGORY_VIDEO, priority, local_fmt, vl);
free(local_fmt);
}
static void
stream_on_eos(struct stream *stream, void *userdata) {
(void) stream;
(void) userdata;
SDL_Event stop_event;
stop_event.type = EVENT_STREAM_STOPPED;
SDL_PushEvent(&stop_event);
}
bool
scrcpy(const struct scrcpy_options *options) {
static struct scrcpy scrcpy;
struct scrcpy *s = &scrcpy;
if (!server_init(&s->server)) {
return false;
}
bool ret = false;
bool server_started = false;
bool fps_counter_initialized = false;
bool file_handler_initialized = false;
bool recorder_initialized = false;
#ifdef HAVE_V4L2
@ -280,7 +276,12 @@ scrcpy(const struct scrcpy_options *options) {
.force_adb_forward = options->force_adb_forward,
.power_off_on_close = options->power_off_on_close,
};
if (!server_start(&s->server, &params)) {
if (!server_init(&server, &params)) {
return false;
}
if (!server_start(&server)) {
goto end;
}
@ -291,19 +292,33 @@ scrcpy(const struct scrcpy_options *options) {
goto end;
}
char device_name[DEVICE_NAME_FIELD_LENGTH];
struct size frame_size;
if (!server_connect_to(&s->server, device_name, &frame_size)) {
if (!server_connect_to(&server)) {
goto end;
}
if (options->display && options->control) {
if (!file_handler_init(&s->file_handler, s->server.serial,
options->push_target)) {
char device_name[DEVICE_NAME_FIELD_LENGTH];
struct size frame_size;
// screenrecord does not send frames when the screen content does not
// change therefore, we transmit the screen size before the video stream,
// to be able to init the window immediately
if (!device_read_info(server.video_socket, device_name, &frame_size)) {
goto end;
}
if (options->display) {
if (!fps_counter_init(&fps_counter)) {
goto end;
}
file_handler_initialized = true;
fps_counter_initialized = true;
if (options->control) {
if (!file_handler_init(&file_handler, options->serial,
options->push_target)) {
goto end;
}
file_handler_initialized = true;
}
}
struct decoder *dec = NULL;
@ -312,60 +327,47 @@ scrcpy(const struct scrcpy_options *options) {
needs_decoder |= !!options->v4l2_device;
#endif
if (needs_decoder) {
decoder_init(&s->decoder);
dec = &s->decoder;
decoder_init(&decoder);
dec = &decoder;
}
struct recorder *rec = NULL;
if (record) {
if (!recorder_init(&s->recorder,
if (!recorder_init(&recorder,
options->record_filename,
options->record_format,
frame_size)) {
goto end;
}
rec = &s->recorder;
rec = &recorder;
recorder_initialized = true;
}
av_log_set_callback(av_log_callback);
const struct stream_callbacks stream_cbs = {
.on_eos = stream_on_eos,
};
stream_init(&s->stream, s->server.video_socket, &stream_cbs, NULL);
stream_init(&stream, server.video_socket);
if (dec) {
stream_add_sink(&s->stream, &dec->packet_sink);
stream_add_sink(&stream, &dec->packet_sink);
}
if (rec) {
stream_add_sink(&s->stream, &rec->packet_sink);
}
if (options->control) {
if (!controller_init(&s->controller, s->server.control_socket)) {
goto end;
}
controller_initialized = true;
if (!controller_start(&s->controller)) {
goto end;
}
controller_started = true;
if (options->turn_screen_off) {
struct control_msg msg;
msg.type = CONTROL_MSG_TYPE_SET_SCREEN_POWER_MODE;
msg.set_screen_power_mode.mode = SCREEN_POWER_MODE_OFF;
if (!controller_push_msg(&s->controller, &msg)) {
LOGW("Could not request 'set screen power mode'");
}
}
stream_add_sink(&stream, &rec->packet_sink);
}
if (options->display) {
if (options->control) {
if (!controller_init(&controller, server.control_socket)) {
goto end;
}
controller_initialized = true;
if (!controller_start(&controller)) {
goto end;
}
controller_started = true;
}
const char *window_title =
options->window_title ? options->window_title : device_name;
@ -383,21 +385,31 @@ scrcpy(const struct scrcpy_options *options) {
.fullscreen = options->fullscreen,
};
if (!screen_init(&s->screen, &screen_params)) {
if (!screen_init(&screen, &fps_counter, &screen_params)) {
goto end;
}
screen_initialized = true;
decoder_add_sink(&s->decoder, &s->screen.frame_sink);
decoder_add_sink(&decoder, &screen.frame_sink);
if (options->turn_screen_off) {
struct control_msg msg;
msg.type = CONTROL_MSG_TYPE_SET_SCREEN_POWER_MODE;
msg.set_screen_power_mode.mode = SCREEN_POWER_MODE_OFF;
if (!controller_push_msg(&controller, &msg)) {
LOGW("Could not request 'set screen power mode'");
}
}
}
#ifdef HAVE_V4L2
if (options->v4l2_device) {
if (!sc_v4l2_sink_init(&s->v4l2_sink, options->v4l2_device, frame_size)) {
if (!sc_v4l2_sink_init(&v4l2_sink, options->v4l2_device, frame_size)) {
goto end;
}
decoder_add_sink(&s->decoder, &s->v4l2_sink.frame_sink);
decoder_add_sink(&decoder, &v4l2_sink.frame_sink);
v4l2_sink_initialized = true;
}
@ -405,74 +417,78 @@ scrcpy(const struct scrcpy_options *options) {
// now we consumed the header values, the socket receives the video stream
// start the stream
if (!stream_start(&s->stream)) {
if (!stream_start(&stream)) {
goto end;
}
stream_started = true;
input_manager_init(&s->input_manager, &s->controller, &s->screen, options);
input_manager_init(&input_manager, options);
ret = event_loop(s, options);
ret = event_loop(options);
LOGD("quit...");
// Close the window immediately on closing, because screen_destroy() may
// only be called once the stream thread is joined (it may take time)
screen_hide_window(&s->screen);
screen_hide_window(&screen);
end:
// The stream is not stopped explicitly, because it will stop by itself on
// end-of-stream
if (controller_started) {
controller_stop(&s->controller);
controller_stop(&controller);
}
if (file_handler_initialized) {
file_handler_stop(&s->file_handler);
file_handler_stop(&file_handler);
}
if (screen_initialized) {
screen_interrupt(&s->screen);
if (fps_counter_initialized) {
fps_counter_interrupt(&fps_counter);
}
if (server_started) {
// shutdown the sockets and kill the server
server_stop(&s->server);
server_stop(&server);
}
// now that the sockets are shutdown, the stream and controller are
// interrupted, we can join them
if (stream_started) {
stream_join(&s->stream);
stream_join(&stream);
}
#ifdef HAVE_V4L2
if (v4l2_sink_initialized) {
sc_v4l2_sink_destroy(&s->v4l2_sink);
sc_v4l2_sink_destroy(&v4l2_sink);
}
#endif
// Destroy the screen only after the stream is guaranteed to be finished,
// because otherwise the screen could receive new frames after destruction
if (screen_initialized) {
screen_join(&s->screen);
screen_destroy(&s->screen);
screen_destroy(&screen);
}
if (controller_started) {
controller_join(&s->controller);
controller_join(&controller);
}
if (controller_initialized) {
controller_destroy(&s->controller);
controller_destroy(&controller);
}
if (recorder_initialized) {
recorder_destroy(&s->recorder);
recorder_destroy(&recorder);
}
if (file_handler_initialized) {
file_handler_join(&s->file_handler);
file_handler_destroy(&s->file_handler);
file_handler_join(&file_handler);
file_handler_destroy(&file_handler);
}
server_destroy(&s->server);
if (fps_counter_initialized) {
fps_counter_join(&fps_counter);
fps_counter_destroy(&fps_counter);
}
server_destroy(&server);
return ret;
}

View File

@ -8,7 +8,6 @@
#include <stdint.h>
enum sc_log_level {
SC_LOG_LEVEL_VERBOSE,
SC_LOG_LEVEL_DEBUG,
SC_LOG_LEVEL_INFO,
SC_LOG_LEVEL_WARN,

View File

@ -41,18 +41,6 @@ get_window_size(const struct screen *screen) {
return size;
}
static struct point
get_window_position(const struct screen *screen) {
int x;
int y;
SDL_GetWindowPosition(screen->window, &x, &y);
struct point point;
point.x = x;
point.y = y;
return point;
}
// set the window size to be applied when fullscreen is disabled
static void
set_window_size(struct screen *screen, struct size new_size) {
@ -134,6 +122,13 @@ get_optimal_size(struct size current_size, struct size content_size) {
return window_size;
}
// same as get_optimal_size(), but read the current size from the window
static inline struct size
get_optimal_window_size(const struct screen *screen, struct size content_size) {
struct size window_size = get_window_size(screen);
return get_optimal_size(window_size, content_size);
}
// initially, there is no current size, so use the frame size as current size
// req_width and req_height, if not 0, are the sizes requested by the user
static inline struct size
@ -276,13 +271,13 @@ screen_frame_sink_push(struct sc_frame_sink *sink, const AVFrame *frame) {
struct screen *screen = DOWNCAST(sink);
bool previous_frame_skipped;
bool ok = sc_video_buffer_push(&screen->vb, frame, &previous_frame_skipped);
bool ok = video_buffer_push(&screen->vb, frame, &previous_frame_skipped);
if (!ok) {
return false;
}
if (previous_frame_skipped) {
fps_counter_add_skipped_frame(&screen->fps_counter);
fps_counter_add_skipped_frame(screen->fps_counter);
// The EVENT_NEW_FRAME triggered for the previous frame will consume
// this new frame instead
} else {
@ -298,23 +293,21 @@ screen_frame_sink_push(struct sc_frame_sink *sink, const AVFrame *frame) {
}
bool
screen_init(struct screen *screen, const struct screen_params *params) {
screen_init(struct screen *screen, struct fps_counter *fps_counter,
const struct screen_params *params) {
screen->fps_counter = fps_counter;
screen->resize_pending = false;
screen->has_frame = false;
screen->fullscreen = false;
screen->maximized = false;
bool ok = sc_video_buffer_init(&screen->vb);
bool ok = video_buffer_init(&screen->vb);
if (!ok) {
LOGE("Could not initialize video buffer");
return false;
}
if (!fps_counter_init(&screen->fps_counter)) {
LOGE("Could not initialize FPS counter");
goto error_destroy_video_buffer;
}
screen->frame_size = params->frame_size;
screen->rotation = params->rotation;
if (screen->rotation) {
@ -351,14 +344,16 @@ screen_init(struct screen *screen, const struct screen_params *params) {
window_flags);
if (!screen->window) {
LOGC("Could not create window: %s", SDL_GetError());
goto error_destroy_fps_counter;
return false;
}
screen->renderer = SDL_CreateRenderer(screen->window, -1,
SDL_RENDERER_ACCELERATED);
if (!screen->renderer) {
LOGC("Could not create renderer: %s", SDL_GetError());
goto error_destroy_window;
SDL_DestroyWindow(screen->window);
video_buffer_destroy(&screen->vb);
return false;
}
SDL_RendererInfo renderer_info;
@ -407,13 +402,20 @@ screen_init(struct screen *screen, const struct screen_params *params) {
screen->texture = create_texture(screen);
if (!screen->texture) {
LOGC("Could not create texture: %s", SDL_GetError());
goto error_destroy_renderer;
SDL_DestroyRenderer(screen->renderer);
SDL_DestroyWindow(screen->window);
video_buffer_destroy(&screen->vb);
return false;
}
screen->frame = av_frame_alloc();
if (!screen->frame) {
LOGC("Could not create screen frame");
goto error_destroy_texture;
SDL_DestroyTexture(screen->texture);
SDL_DestroyRenderer(screen->renderer);
SDL_DestroyWindow(screen->window);
video_buffer_destroy(&screen->vb);
return false;
}
// Reset the window size to trigger a SIZE_CHANGED event, to workaround
@ -444,19 +446,6 @@ screen_init(struct screen *screen, const struct screen_params *params) {
#endif
return true;
error_destroy_texture:
SDL_DestroyTexture(screen->texture);
error_destroy_renderer:
SDL_DestroyRenderer(screen->renderer);
error_destroy_window:
SDL_DestroyWindow(screen->window);
error_destroy_fps_counter:
fps_counter_destroy(&screen->fps_counter);
error_destroy_video_buffer:
sc_video_buffer_destroy(&screen->vb);
return false;
}
static void
@ -469,16 +458,6 @@ screen_hide_window(struct screen *screen) {
SDL_HideWindow(screen->window);
}
void
screen_interrupt(struct screen *screen) {
fps_counter_interrupt(&screen->fps_counter);
}
void
screen_join(struct screen *screen) {
fps_counter_join(&screen->fps_counter);
}
void
screen_destroy(struct screen *screen) {
#ifndef NDEBUG
@ -488,8 +467,7 @@ screen_destroy(struct screen *screen) {
SDL_DestroyTexture(screen->texture);
SDL_DestroyRenderer(screen->renderer);
SDL_DestroyWindow(screen->window);
fps_counter_destroy(&screen->fps_counter);
sc_video_buffer_destroy(&screen->vb);
video_buffer_destroy(&screen->vb);
}
static void
@ -595,10 +573,10 @@ update_texture(struct screen *screen, const AVFrame *frame) {
static bool
screen_update_frame(struct screen *screen) {
av_frame_unref(screen->frame);
sc_video_buffer_consume(&screen->vb, screen->frame);
video_buffer_consume(&screen->vb, screen->frame);
AVFrame *frame = screen->frame;
fps_counter_add_rendered_frame(&screen->fps_counter);
fps_counter_add_rendered_frame(screen->fps_counter);
struct size new_frame_size = {frame->width, frame->height};
if (!prepare_for_frame(screen, new_frame_size)) {
@ -667,20 +645,9 @@ screen_resize_to_fit(struct screen *screen) {
return;
}
struct point point = get_window_position(screen);
struct size window_size = get_window_size(screen);
struct size optimal_size =
get_optimal_size(window_size, screen->content_size);
// Center the window related to the device screen
assert(optimal_size.width <= window_size.width);
assert(optimal_size.height <= window_size.height);
uint32_t new_x = point.x + (window_size.width - optimal_size.width) / 2;
uint32_t new_y = point.y + (window_size.height - optimal_size.height) / 2;
get_optimal_window_size(screen, screen->content_size);
SDL_SetWindowSize(screen->window, optimal_size.width, optimal_size.height);
SDL_SetWindowPosition(screen->window, new_x, new_y);
LOGD("Resized to optimal size: %ux%u", optimal_size.width,
optimal_size.height);
}
@ -742,7 +709,6 @@ screen_handle_event(struct screen *screen, SDL_Event *event) {
}
screen->maximized = false;
apply_pending_resize(screen);
screen_render(screen, true);
break;
}
return true;

View File

@ -8,7 +8,6 @@
#include <libavformat/avformat.h>
#include "coords.h"
#include "fps_counter.h"
#include "opengl.h"
#include "trait/frame_sink.h"
#include "video_buffer.h"
@ -20,8 +19,8 @@ struct screen {
bool open; // track the open/close state to assert correct behavior
#endif
struct sc_video_buffer vb;
struct fps_counter fps_counter;
struct video_buffer vb;
struct fps_counter *fps_counter;
SDL_Window *window;
SDL_Renderer *renderer;
@ -67,16 +66,8 @@ struct screen_params {
// initialize screen, create window, renderer and texture (window is hidden)
bool
screen_init(struct screen *screen, const struct screen_params *params);
// request to interrupt any inner thread
// must be called before screen_join()
void
screen_interrupt(struct screen *screen);
// join any inner thread
void
screen_join(struct screen *screen);
screen_init(struct screen *screen, struct fps_counter *fps_counter,
const struct screen_params *params);
// destroy window, renderer and texture (if any)
void

View File

@ -128,9 +128,10 @@ disable_tunnel_forward(const char *serial, uint16_t local_port) {
static bool
disable_tunnel(struct server *server) {
if (server->tunnel_forward) {
return disable_tunnel_forward(server->serial, server->local_port);
return disable_tunnel_forward(server->params.serial,
server->local_port);
}
return disable_tunnel_reverse(server->serial);
return disable_tunnel_reverse(server->params.serial);
}
static socket_t
@ -144,7 +145,7 @@ enable_tunnel_reverse_any_port(struct server *server,
struct sc_port_range port_range) {
uint16_t port = port_range.first;
for (;;) {
if (!enable_tunnel_reverse(server->serial, port)) {
if (!enable_tunnel_reverse(server->params.serial, port)) {
// the command itself failed, it will fail on any port
return false;
}
@ -163,7 +164,7 @@ enable_tunnel_reverse_any_port(struct server *server,
}
// failure, disable tunnel and try another port
if (!disable_tunnel_reverse(server->serial)) {
if (!disable_tunnel_reverse(server->params.serial)) {
LOGW("Could not remove reverse tunnel on port %" PRIu16, port);
}
@ -191,7 +192,7 @@ enable_tunnel_forward_any_port(struct server *server,
server->tunnel_forward = true;
uint16_t port = port_range.first;
for (;;) {
if (enable_tunnel_forward(server->serial, port)) {
if (enable_tunnel_forward(server->params.serial, port)) {
// success
server->local_port = port;
return true;
@ -235,8 +236,6 @@ enable_tunnel_any_port(struct server *server, struct sc_port_range port_range,
static const char *
log_level_to_server_string(enum sc_log_level level) {
switch (level) {
case SC_LOG_LEVEL_VERBOSE:
return "verbose";
case SC_LOG_LEVEL_DEBUG:
return "debug";
case SC_LOG_LEVEL_INFO:
@ -308,7 +307,7 @@ execute_server(struct server *server, const struct server_params *params) {
// Port: 5005
// Then click on "Debug"
#endif
return adb_execute(server->serial, cmd, ARRAY_LEN(cmd));
return adb_execute(server->params.serial, cmd, ARRAY_LEN(cmd));
}
static socket_t
@ -354,21 +353,75 @@ close_socket(socket_t socket) {
}
}
static void
server_params_destroy(struct server_params *params) {
// The server stores a copy of the params provided by the user
free((char *) params->crop);
free((char *) params->codec_options);
free((char *) params->encoder_name);
}
static bool
server_params_copy(struct server_params *dst, const struct server_params *src) {
// params reference user-allocated memory, so we must copy them to handle
// them from a separate thread
*dst = *src;
dst->crop = NULL;
dst->codec_options = NULL;
dst->encoder_name = NULL;
if (src->crop) {
dst->crop = strdup(src->crop);
if (!dst->crop) {
goto error;
}
}
if (src->codec_options) {
dst->codec_options = strdup(src->codec_options);
if (!dst->codec_options) {
goto error;
}
}
if (src->encoder_name) {
dst->encoder_name = strdup(src->encoder_name);
if (!dst->encoder_name) {
goto error;
}
}
return true;
error:
server_params_destroy(dst);
return false;
};
bool
server_init(struct server *server) {
server->serial = NULL;
server_init(struct server *server, const struct server_params *params) {
if (!server_params_copy(&server->params, params)) {
LOGE("Could not copy server params");
return false;
}
server->process = PROCESS_NONE;
atomic_flag_clear_explicit(&server->server_socket_closed,
memory_order_relaxed);
bool ok = sc_mutex_init(&server->mutex);
if (!ok) {
server_params_destroy(&server->params);
return false;
}
ok = sc_cond_init(&server->process_terminated_cond);
if (!ok) {
sc_mutex_destroy(&server->mutex);
server_params_destroy(&server->params);
return false;
}
@ -408,31 +461,41 @@ run_wait_server(void *data) {
return 0;
}
bool
server_start(struct server *server, const struct server_params *params) {
if (params->serial) {
server->serial = strdup(params->serial);
if (!server->serial) {
return false;
}
}
static int
run_server(void *data) {
struct server *server = data;
const struct server_params *params = &server->params;
const struct server_callbacks *cbs = &server->cbs;
void *userdata = server->userdata;
if (!push_server(params->serial)) {
/* server->serial will be freed on server_destroy() */
return false;
cbs->on_connection_failed(server);
goto end;
}
if (!enable_tunnel_any_port(server, params->port_range,
params->force_adb_forward)) {
return false;
cbs->on_connection_failed(server);
goto end;
}
// server will connect to our server socket
server->process = execute_server(server, params);
if (server->process == PROCESS_NONE) {
goto error;
cbs->on_connection_failed(server);
goto end;
}
process_wait(server->process, false); // ignore exit code
end:
return 0;
}
bool
server_start(struct server *server) {
// If the server process dies before connecting to the server socket, then
// the client will be stuck forever on accept(). To avoid the problem, we
// must be able to wake up the accept() call when the server dies. To keep
@ -465,28 +528,8 @@ error:
return false;
}
static bool
device_read_info(socket_t device_socket, char *device_name, struct size *size) {
unsigned char buf[DEVICE_NAME_FIELD_LENGTH + 4];
int r = net_recv_all(device_socket, buf, sizeof(buf));
if (r < DEVICE_NAME_FIELD_LENGTH + 4) {
LOGE("Could not retrieve device information");
return false;
}
// in case the client sends garbage
buf[DEVICE_NAME_FIELD_LENGTH - 1] = '\0';
// strcpy is safe here, since name contains at least
// DEVICE_NAME_FIELD_LENGTH bytes and strlen(buf) < DEVICE_NAME_FIELD_LENGTH
strcpy(device_name, (char *) buf);
size->width = (buf[DEVICE_NAME_FIELD_LENGTH] << 8)
| buf[DEVICE_NAME_FIELD_LENGTH + 1];
size->height = (buf[DEVICE_NAME_FIELD_LENGTH + 2] << 8)
| buf[DEVICE_NAME_FIELD_LENGTH + 3];
return true;
}
bool
server_connect_to(struct server *server, char *device_name, struct size *size) {
server_connect_to(struct server *server) {
if (!server->tunnel_forward) {
server->video_socket = net_accept(server->server_socket);
if (server->video_socket == INVALID_SOCKET) {
@ -526,8 +569,7 @@ server_connect_to(struct server *server, char *device_name, struct size *size) {
disable_tunnel(server); // ignore failure
server->tunnel_enabled = false;
// The sockets will be closed on stop if device_read_info() fails
return device_read_info(server->video_socket, device_name, size);
return true;
}
void
@ -580,4 +622,5 @@ server_destroy(struct server *server) {
free(server->serial);
sc_cond_destroy(&server->process_terminated_cond);
sc_mutex_destroy(&server->mutex);
server_params_destroy(&server->params);
}

View File

@ -8,12 +8,30 @@
#include <stdint.h>
#include "adb.h"
#include "coords.h"
#include "scrcpy.h"
#include "util/log.h"
#include "util/net.h"
#include "util/thread.h"
struct server_params {
enum sc_log_level log_level;
const char *serial;
const char *crop;
const char *codec_options;
const char *encoder_name;
struct sc_port_range port_range;
uint16_t max_size;
uint32_t bit_rate;
uint16_t max_fps;
int8_t lock_video_orientation;
bool control;
uint32_t display_id;
bool show_touches;
bool stay_awake;
bool force_adb_forward;
bool power_off_on_close;
};
struct server {
char *serial;
process_t process;
@ -30,40 +48,33 @@ struct server {
uint16_t local_port; // selected from port_range
bool tunnel_enabled;
bool tunnel_forward; // use "adb forward" instead of "adb reverse"
// The internal allocated strings are copies owned by the server
struct server_params params;
const struct server_callbacks *cbs;
void *userdata;
};
struct server_params {
const char *serial;
enum sc_log_level log_level;
const char *crop;
const char *codec_options;
const char *encoder_name;
struct sc_port_range port_range;
uint16_t max_size;
uint32_t bit_rate;
uint16_t max_fps;
int8_t lock_video_orientation;
bool control;
uint32_t display_id;
bool show_touches;
bool stay_awake;
bool force_adb_forward;
bool power_off_on_close;
struct server_callbacks {
void (*on_connection_failed)(struct server *server);
void (*on_connected)(struct server *server, const char *name,
struct size size, void *userdata);
void (*on_disconnected)(struct server *server, void *userdata);
};
// init default values
// init server fields
bool
server_init(struct server *server);
server_init(struct server *server, const struct server_params *params);
// push, enable tunnel et start the server
bool
server_start(struct server *server, const struct server_params *params);
server_start(struct server *server, const struct server_callbacks *cbs,
void *userdata);
#define DEVICE_NAME_FIELD_LENGTH 64
// block until the communication with the server is established
// device_name must point to a buffer of at least DEVICE_NAME_FIELD_LENGTH bytes
bool
server_connect_to(struct server *server, char *device_name, struct size *size);
server_connect_to(struct server *server);
// disconnect and kill the server process
void

View File

@ -3,6 +3,7 @@
#include <assert.h>
#include <libavformat/avformat.h>
#include <libavutil/time.h>
#include <SDL2/SDL_events.h>
#include <unistd.h>
#include "decoder.h"
@ -57,6 +58,13 @@ stream_recv_packet(struct stream *stream, AVPacket *packet) {
return true;
}
static void
notify_stopped(void) {
SDL_Event stop_event;
stop_event.type = EVENT_STREAM_STOPPED;
SDL_PushEvent(&stop_event);
}
static bool
push_packet_to_sinks(struct stream *stream, const AVPacket *packet) {
for (unsigned i = 0; i < stream->sink_count; ++i) {
@ -104,38 +112,33 @@ static bool
stream_push_packet(struct stream *stream, AVPacket *packet) {
bool is_config = packet->pts == AV_NOPTS_VALUE;
// A config packet must not be decoded immediately (it contains no
// A config packet must not be decoded immetiately (it contains no
// frame); instead, it must be concatenated with the future data packet.
if (stream->pending || is_config) {
if (stream->has_pending || is_config) {
size_t offset;
if (stream->pending) {
offset = stream->pending->size;
if (av_grow_packet(stream->pending, packet->size)) {
if (stream->has_pending) {
offset = stream->pending.size;
if (av_grow_packet(&stream->pending, packet->size)) {
LOGE("Could not grow packet");
return false;
}
} else {
offset = 0;
stream->pending = av_packet_alloc();
if (!stream->pending) {
LOGE("Could not allocate packet");
return false;
}
if (av_new_packet(stream->pending, packet->size)) {
if (av_new_packet(&stream->pending, packet->size)) {
LOGE("Could not create packet");
av_packet_free(&stream->pending);
return false;
}
stream->has_pending = true;
}
memcpy(stream->pending->data + offset, packet->data, packet->size);
memcpy(stream->pending.data + offset, packet->data, packet->size);
if (!is_config) {
// prepare the concat packet to send to the decoder
stream->pending->pts = packet->pts;
stream->pending->dts = packet->dts;
stream->pending->flags = packet->flags;
packet = stream->pending;
stream->pending.pts = packet->pts;
stream->pending.dts = packet->dts;
stream->pending.flags = packet->flags;
packet = &stream->pending;
}
}
@ -149,10 +152,10 @@ stream_push_packet(struct stream *stream, AVPacket *packet) {
// data packet
bool ok = stream_parse(stream, packet);
if (stream->pending) {
if (stream->has_pending) {
// the pending packet must be discarded (consumed or error)
av_packet_unref(stream->pending);
av_packet_free(&stream->pending);
stream->has_pending = false;
av_packet_unref(&stream->pending);
}
if (!ok) {
@ -220,21 +223,16 @@ run_stream(void *data) {
// It's more complicated, but this allows to reduce the latency by 1 frame!
stream->parser->flags |= PARSER_FLAG_COMPLETE_FRAMES;
AVPacket *packet = av_packet_alloc();
if (!packet) {
LOGE("Could not allocate packet");
goto finally_close_parser;
}
for (;;) {
bool ok = stream_recv_packet(stream, packet);
AVPacket packet;
bool ok = stream_recv_packet(stream, &packet);
if (!ok) {
// end of stream
break;
}
ok = stream_push_packet(stream, packet);
av_packet_unref(packet);
ok = stream_push_packet(stream, &packet);
av_packet_unref(&packet);
if (!ok) {
// cannot process packet (error already logged)
break;
@ -243,35 +241,25 @@ run_stream(void *data) {
LOGD("End of frames");
if (stream->pending) {
av_packet_unref(stream->pending);
av_packet_free(&stream->pending);
if (stream->has_pending) {
av_packet_unref(&stream->pending);
}
av_packet_free(&packet);
finally_close_parser:
av_parser_close(stream->parser);
finally_close_sinks:
stream_close_sinks(stream);
finally_free_codec_ctx:
avcodec_free_context(&stream->codec_ctx);
end:
stream->cbs->on_eos(stream, stream->cbs_userdata);
notify_stopped();
return 0;
}
void
stream_init(struct stream *stream, socket_t socket,
const struct stream_callbacks *cbs, void *cbs_userdata) {
stream_init(struct stream *stream, socket_t socket) {
stream->socket = socket;
stream->pending = NULL;
stream->has_pending = false;
stream->sink_count = 0;
assert(cbs && cbs->on_eos);
stream->cbs = cbs;
stream->cbs_userdata = cbs_userdata;
}
void

View File

@ -6,6 +6,7 @@
#include <stdbool.h>
#include <stdint.h>
#include <libavformat/avformat.h>
#include <SDL2/SDL_atomic.h>
#include "trait/packet_sink.h"
#include "util/net.h"
@ -24,19 +25,12 @@ struct stream {
AVCodecParserContext *parser;
// successive packets may need to be concatenated, until a non-config
// packet is available
AVPacket *pending;
const struct stream_callbacks *cbs;
void *cbs_userdata;
};
struct stream_callbacks {
void (*on_eos)(struct stream *stream, void *userdata);
bool has_pending;
AVPacket pending;
};
void
stream_init(struct stream *stream, socket_t socket,
const struct stream_callbacks *cbs, void *cbs_userdata);
stream_init(struct stream *stream, socket_t socket);
void
stream_add_sink(struct stream *stream, struct sc_packet_sink *sink);

View File

@ -6,9 +6,7 @@
#include "util/log.h"
#include "util/str_util.h"
#define CMD_MAX_LEN 8192
static bool
static int
build_cmd(char *cmd, size_t len, const char *const argv[]) {
// Windows command-line parsing is WTF:
// <http://daviddeley.com/autohotkey/parameters/parameters.htm#WINPASS>
@ -17,9 +15,9 @@ build_cmd(char *cmd, size_t len, const char *const argv[]) {
size_t ret = xstrjoin(cmd, argv, ' ', len);
if (ret >= len) {
LOGE("Command too long (%" PRIsizet " chars)", len - 1);
return false;
return -1;
}
return true;
return 0;
}
enum process_result
@ -29,14 +27,13 @@ process_execute(const char *const argv[], HANDLE *handle) {
memset(&si, 0, sizeof(si));
si.cb = sizeof(si);
char *cmd = malloc(CMD_MAX_LEN);
if (!cmd || !build_cmd(cmd, CMD_MAX_LEN, argv)) {
char cmd[256];
if (build_cmd(cmd, sizeof(cmd), argv)) {
*handle = NULL;
return PROCESS_ERROR_GENERIC;
}
wchar_t *wide = utf8_to_wide_char(cmd);
free(cmd);
if (!wide) {
LOGC("Could not allocate wide char string");
return PROCESS_ERROR_GENERIC;

View File

@ -1,53 +0,0 @@
#include "log.h"
#include <assert.h>
static SDL_LogPriority
log_level_sc_to_sdl(enum sc_log_level level) {
switch (level) {
case SC_LOG_LEVEL_VERBOSE:
return SDL_LOG_PRIORITY_VERBOSE;
case SC_LOG_LEVEL_DEBUG:
return SDL_LOG_PRIORITY_DEBUG;
case SC_LOG_LEVEL_INFO:
return SDL_LOG_PRIORITY_INFO;
case SC_LOG_LEVEL_WARN:
return SDL_LOG_PRIORITY_WARN;
case SC_LOG_LEVEL_ERROR:
return SDL_LOG_PRIORITY_ERROR;
default:
assert(!"unexpected log level");
return SDL_LOG_PRIORITY_INFO;
}
}
static enum sc_log_level
log_level_sdl_to_sc(SDL_LogPriority priority) {
switch (priority) {
case SDL_LOG_PRIORITY_VERBOSE:
return SC_LOG_LEVEL_VERBOSE;
case SDL_LOG_PRIORITY_DEBUG:
return SC_LOG_LEVEL_DEBUG;
case SDL_LOG_PRIORITY_INFO:
return SC_LOG_LEVEL_INFO;
case SDL_LOG_PRIORITY_WARN:
return SC_LOG_LEVEL_WARN;
case SDL_LOG_PRIORITY_ERROR:
return SC_LOG_LEVEL_ERROR;
default:
assert(!"unexpected log level");
return SC_LOG_LEVEL_INFO;
}
}
void
sc_set_log_level(enum sc_log_level level) {
SDL_LogPriority sdl_log = log_level_sc_to_sdl(level);
SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, sdl_log);
}
enum sc_log_level
sc_get_log_level(void) {
SDL_LogPriority sdl_log = SDL_LogGetPriority(SDL_LOG_CATEGORY_APPLICATION);
return log_level_sdl_to_sc(sdl_log);
}

View File

@ -1,12 +1,8 @@
#ifndef SC_LOG_H
#define SC_LOG_H
#include "common.h"
#ifndef LOG_H
#define LOG_H
#include <SDL2/SDL_log.h>
#include "scrcpy.h"
#define LOGV(...) SDL_LogVerbose(SDL_LOG_CATEGORY_APPLICATION, __VA_ARGS__)
#define LOGD(...) SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION, __VA_ARGS__)
#define LOGI(...) SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, __VA_ARGS__)
@ -14,10 +10,4 @@
#define LOGE(...) SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, __VA_ARGS__)
#define LOGC(...) SDL_LogCritical(SDL_LOG_CATEGORY_APPLICATION, __VA_ARGS__)
void
sc_set_log_level(enum sc_log_level level);
enum sc_log_level
sc_get_log_level(void);
#endif

View File

@ -16,7 +16,7 @@ size_t
xstrncpy(char *dest, const char *src, size_t n);
// join tokens by sep into dst
// returns the number of chars actually written (max n-1) if no truncation
// returns the number of chars actually written (max n-1) if no trucation
// occurred, or n if truncated
size_t
xstrjoin(char *dst, const char *const tokens[], char sep, size_t n);

View File

@ -31,7 +31,7 @@ sc_mutex_init(sc_mutex *mutex) {
mutex->mutex = sdl_mutex;
#ifndef NDEBUG
atomic_init(&mutex->locker, 0);
mutex->locker = 0;
#endif
return true;
}
@ -52,8 +52,7 @@ sc_mutex_lock(sc_mutex *mutex) {
abort();
}
atomic_store_explicit(&mutex->locker, sc_thread_get_id(),
memory_order_relaxed);
mutex->locker = sc_thread_get_id();
#else
(void) r;
#endif
@ -63,7 +62,7 @@ void
sc_mutex_unlock(sc_mutex *mutex) {
#ifndef NDEBUG
assert(sc_mutex_held(mutex));
atomic_store_explicit(&mutex->locker, 0, memory_order_relaxed);
mutex->locker = 0;
#endif
int r = SDL_UnlockMutex(mutex->mutex);
#ifndef NDEBUG
@ -84,9 +83,7 @@ sc_thread_get_id(void) {
#ifndef NDEBUG
bool
sc_mutex_held(struct sc_mutex *mutex) {
sc_thread_id locker_id =
atomic_load_explicit(&mutex->locker, memory_order_relaxed);
return locker_id == sc_thread_get_id();
return mutex->locker == sc_thread_get_id();
}
#endif
@ -115,8 +112,7 @@ sc_cond_wait(sc_cond *cond, sc_mutex *mutex) {
abort();
}
atomic_store_explicit(&mutex->locker, sc_thread_get_id(),
memory_order_relaxed);
mutex->locker = sc_thread_get_id();
#else
(void) r;
#endif
@ -131,8 +127,7 @@ sc_cond_timedwait(sc_cond *cond, sc_mutex *mutex, uint32_t ms) {
abort();
}
atomic_store_explicit(&mutex->locker, sc_thread_get_id(),
memory_order_relaxed);
mutex->locker = sc_thread_get_id();
#endif
assert(r == 0 || r == SDL_MUTEX_TIMEDOUT);
return r == 0;

View File

@ -3,7 +3,6 @@
#include "common.h"
#include <stdatomic.h>
#include <stdbool.h>
#include <stdint.h>
@ -13,8 +12,7 @@ typedef struct SDL_mutex SDL_mutex;
typedef struct SDL_cond SDL_cond;
typedef int sc_thread_fn(void *);
typedef unsigned sc_thread_id;
typedef atomic_uint sc_atomic_thread_id;
typedef unsigned int sc_thread_id;
typedef struct sc_thread {
SDL_Thread *thread;
@ -23,7 +21,7 @@ typedef struct sc_thread {
typedef struct sc_mutex {
SDL_mutex *mutex;
#ifndef NDEBUG
sc_atomic_thread_id locker;
sc_thread_id locker;
#endif
} sc_mutex;

View File

@ -86,7 +86,7 @@ encode_and_write_frame(struct sc_v4l2_sink *vs, const AVFrame *frame) {
return false;
}
AVPacket *packet = vs->packet;
AVPacket *packet = &vs->packet;
ret = avcodec_receive_packet(vs->encoder_ctx, packet);
if (ret == 0) {
// A packet was received
@ -112,7 +112,7 @@ run_v4l2_sink(void *data) {
for (;;) {
sc_mutex_lock(&vs->mutex);
while (!vs->stopped && !vs->has_frame) {
while (!vs->stopped && vs->vb.pending_frame_consumed) {
sc_cond_wait(&vs->cond, &vs->mutex);
}
@ -121,11 +121,9 @@ run_v4l2_sink(void *data) {
break;
}
sc_video_buffer_consume(&vs->vb, vs->frame);
vs->has_frame = false;
sc_mutex_unlock(&vs->mutex);
video_buffer_consume(&vs->vb, vs->frame);
bool ok = encode_and_write_frame(vs, vs->frame);
av_frame_unref(vs->frame);
if (!ok) {
@ -141,7 +139,7 @@ run_v4l2_sink(void *data) {
static bool
sc_v4l2_sink_open(struct sc_v4l2_sink *vs) {
bool ok = sc_video_buffer_init(&vs->vb);
bool ok = video_buffer_init(&vs->vb);
if (!ok) {
return false;
}
@ -182,17 +180,12 @@ sc_v4l2_sink_open(struct sc_v4l2_sink *vs) {
// still expects a pointer-to-non-const (it has not be updated accordingly)
// <https://github.com/FFmpeg/FFmpeg/commit/0694d8702421e7aff1340038559c438b61bb30dd>
vs->format_ctx->oformat = (AVOutputFormat *) format;
#ifdef SCRCPY_LAVF_HAS_AVFORMATCONTEXT_URL
vs->format_ctx->url = strdup(vs->device_name);
if (!vs->format_ctx->url) {
LOGE("Could not strdup v4l2 device name");
goto error_avformat_free_context;
return false;
}
#else
strncpy(vs->format_ctx->filename, vs->device_name,
sizeof(vs->format_ctx->filename));
#endif
AVStream *ostream = avformat_new_stream(vs->format_ctx, encoder);
if (!ostream) {
@ -237,29 +230,20 @@ sc_v4l2_sink_open(struct sc_v4l2_sink *vs) {
goto error_avcodec_close;
}
vs->packet = av_packet_alloc();
if (!vs->packet) {
LOGE("Could not allocate packet");
goto error_av_frame_free;
}
vs->has_frame = false;
vs->header_written = false;
vs->stopped = false;
LOGD("Starting v4l2 thread");
ok = sc_thread_create(&vs->thread, run_v4l2_sink, "v4l2", vs);
if (!ok) {
LOGC("Could not start v4l2 thread");
goto error_av_packet_free;
goto error_av_frame_free;
}
vs->header_written = false;
vs->stopped = false;
LOGI("v4l2 sink started to device: %s", vs->device_name);
return true;
error_av_packet_free:
av_packet_free(&vs->packet);
error_av_frame_free:
av_frame_free(&vs->frame);
error_avcodec_close:
@ -275,7 +259,7 @@ error_cond_destroy:
error_mutex_destroy:
sc_mutex_destroy(&vs->mutex);
error_video_buffer_destroy:
sc_video_buffer_destroy(&vs->vb);
video_buffer_destroy(&vs->vb);
return false;
}
@ -289,7 +273,6 @@ sc_v4l2_sink_close(struct sc_v4l2_sink *vs) {
sc_thread_join(&vs->thread, NULL);
av_packet_free(&vs->packet);
av_frame_free(&vs->frame);
avcodec_close(vs->encoder_ctx);
avcodec_free_context(&vs->encoder_ctx);
@ -297,23 +280,19 @@ sc_v4l2_sink_close(struct sc_v4l2_sink *vs) {
avformat_free_context(vs->format_ctx);
sc_cond_destroy(&vs->cond);
sc_mutex_destroy(&vs->mutex);
sc_video_buffer_destroy(&vs->vb);
video_buffer_destroy(&vs->vb);
}
static bool
sc_v4l2_sink_push(struct sc_v4l2_sink *vs, const AVFrame *frame) {
sc_mutex_lock(&vs->mutex);
bool ok = sc_video_buffer_push(&vs->vb, frame, NULL);
bool ok = video_buffer_push(&vs->vb, frame, NULL);
if (!ok) {
return false;
}
vs->has_frame = true;
// signal possible change of vs->vb.pending_frame_consumed
sc_cond_signal(&vs->cond);
sc_mutex_unlock(&vs->mutex);
return true;
}

View File

@ -12,7 +12,7 @@
struct sc_v4l2_sink {
struct sc_frame_sink frame_sink; // frame sink trait
struct sc_video_buffer vb;
struct video_buffer vb;
AVFormatContext *format_ctx;
AVCodecContext *encoder_ctx;
@ -22,12 +22,11 @@ struct sc_v4l2_sink {
sc_thread thread;
sc_mutex mutex;
sc_cond cond;
bool has_frame;
bool stopped;
bool header_written;
AVFrame *frame;
AVPacket *packet;
AVPacket packet;
};
bool

View File

@ -7,22 +7,82 @@
#include "util/log.h"
bool
sc_video_buffer_init(struct sc_video_buffer *vb) {
return sc_frame_buffer_init(&vb->fb);
video_buffer_init(struct video_buffer *vb) {
vb->pending_frame = av_frame_alloc();
if (!vb->pending_frame) {
return false;
}
vb->tmp_frame = av_frame_alloc();
if (!vb->tmp_frame) {
av_frame_free(&vb->pending_frame);
return false;
}
bool ok = sc_mutex_init(&vb->mutex);
if (!ok) {
av_frame_free(&vb->pending_frame);
av_frame_free(&vb->tmp_frame);
return false;
}
// there is initially no frame, so consider it has already been consumed
vb->pending_frame_consumed = true;
return true;
}
void
sc_video_buffer_destroy(struct sc_video_buffer *vb) {
sc_frame_buffer_destroy(&vb->fb);
video_buffer_destroy(struct video_buffer *vb) {
sc_mutex_destroy(&vb->mutex);
av_frame_free(&vb->pending_frame);
av_frame_free(&vb->tmp_frame);
}
static inline void
swap_frames(AVFrame **lhs, AVFrame **rhs) {
AVFrame *tmp = *lhs;
*lhs = *rhs;
*rhs = tmp;
}
bool
sc_video_buffer_push(struct sc_video_buffer *vb, const AVFrame *frame,
video_buffer_push(struct video_buffer *vb, const AVFrame *frame,
bool *previous_frame_skipped) {
return sc_frame_buffer_push(&vb->fb, frame, previous_frame_skipped);
sc_mutex_lock(&vb->mutex);
// Use a temporary frame to preserve pending_frame in case of error.
// tmp_frame is an empty frame, no need to call av_frame_unref() beforehand.
int r = av_frame_ref(vb->tmp_frame, frame);
if (r) {
LOGE("Could not ref frame: %d", r);
return false;
}
// Now that av_frame_ref() succeeded, we can replace the previous
// pending_frame
swap_frames(&vb->pending_frame, &vb->tmp_frame);
av_frame_unref(vb->tmp_frame);
if (previous_frame_skipped) {
*previous_frame_skipped = !vb->pending_frame_consumed;
}
vb->pending_frame_consumed = false;
sc_mutex_unlock(&vb->mutex);
return true;
}
void
sc_video_buffer_consume(struct sc_video_buffer *vb, AVFrame *dst) {
sc_frame_buffer_consume(&vb->fb, dst);
video_buffer_consume(struct video_buffer *vb, AVFrame *dst) {
sc_mutex_lock(&vb->mutex);
assert(!vb->pending_frame_consumed);
vb->pending_frame_consumed = true;
av_frame_move_ref(dst, vb->pending_frame);
// av_frame_move_ref() resets its source frame, so no need to call
// av_frame_unref()
sc_mutex_unlock(&vb->mutex);
}

View File

@ -1,30 +1,50 @@
#ifndef SC_VIDEO_BUFFER_H
#define SC_VIDEO_BUFFER_H
#ifndef VIDEO_BUFFER_H
#define VIDEO_BUFFER_H
#include "common.h"
#include <stdbool.h>
#include "frame_buffer.h"
#include "fps_counter.h"
#include "util/thread.h"
// forward declarations
typedef struct AVFrame AVFrame;
struct sc_video_buffer {
struct sc_frame_buffer fb;
/**
* A video buffer holds 1 pending frame, which is the last frame received from
* the producer (typically, the decoder).
*
* If a pending frame has not been consumed when the producer pushes a new
* frame, then it is lost. The intent is to always provide access to the very
* last frame to minimize latency.
*
* The producer and the consumer typically do not live in the same thread.
* That's the reason why the callback on_frame_available() does not provide the
* frame as parameter: the consumer might post an event to its own thread to
* retrieve the pending frame from there, and that frame may have changed since
* the callback if producer pushed a new one in between.
*/
struct video_buffer {
AVFrame *pending_frame;
AVFrame *tmp_frame; // To preserve the pending frame on error
sc_mutex mutex;
bool pending_frame_consumed;
};
bool
sc_video_buffer_init(struct sc_video_buffer *vb);
video_buffer_init(struct video_buffer *vb);
void
sc_video_buffer_destroy(struct sc_video_buffer *vb);
video_buffer_destroy(struct video_buffer *vb);
bool
sc_video_buffer_push(struct sc_video_buffer *vb, const AVFrame *frame,
bool *skipped);
video_buffer_push(struct video_buffer *vb, const AVFrame *frame, bool *skipped);
void
sc_video_buffer_consume(struct sc_video_buffer *vb, AVFrame *dst);
video_buffer_consume(struct video_buffer *vb, AVFrame *dst);
#endif

View File

@ -51,7 +51,7 @@ static void test_options(void) {
"--fullscreen",
"--max-fps", "30",
"--max-size", "1024",
"--lock-video-orientation=2", // optional arguments require '='
"--lock-video-orientation", "2",
// "--no-control" is not compatible with "--turn-screen-off"
// "--no-display" is not compatible with "--fulscreen"
"--port", "1234:1236",

View File

@ -1,21 +0,0 @@
#!/usr/bin/env bash
set -e
BUILDDIR=build-auto
PREBUILT_SERVER_URL=https://github.com/Genymobile/scrcpy/releases/download/v1.18/scrcpy-server-v1.18
PREBUILT_SERVER_SHA256=641c5c6beda9399dfae72d116f5ff43b5ed1059d871c9ebc3f47610fd33c51a3
echo "[scrcpy] Downloading prebuilt server..."
wget "$PREBUILT_SERVER_URL" -O scrcpy-server
echo "[scrcpy] Verifying prebuilt server..."
echo "$PREBUILT_SERVER_SHA256 scrcpy-server" | sha256sum --check
echo "[scrcpy] Building client..."
rm -rf "$BUILDDIR"
meson "$BUILDDIR" --buildtype release --strip -Db_lto=true \
-Dprebuilt_server=scrcpy-server
cd "$BUILDDIR"
ninja
echo "[scrcpy] Installing (sudo)..."
sudo ninja install

View File

@ -1,5 +1,5 @@
project('scrcpy', 'c',
version: '1.18',
version: '1.17',
meson_version: '>= 0.48',
default_options: [
'c_std=c11',

View File

@ -35,6 +35,6 @@ prepare-sdl2:
SDL2-2.0.14
prepare-adb:
@./prepare-dep https://dl.google.com/android/repository/platform-tools_r31.0.2-windows.zip \
d560cb8ded83ae04763b94632673481f14843a5969256569623cfeac82db4ba5 \
@./prepare-dep https://dl.google.com/android/repository/platform-tools_r30.0.5-windows.zip \
549ba2bdc31f335eb8a504f005f77606a479cc216d6b64a3e8b64c780003661f \
platform-tools

View File

@ -6,8 +6,8 @@ android {
applicationId "com.genymobile.scrcpy"
minSdkVersion 21
targetSdkVersion 30
versionCode 11800
versionName "1.18"
versionCode 20
versionName "1.17"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {

View File

@ -12,7 +12,7 @@
set -e
SCRCPY_DEBUG=false
SCRCPY_VERSION_NAME=1.18
SCRCPY_VERSION_NAME=1.17
PLATFORM=${ANDROID_PLATFORM:-30}
BUILD_TOOLS=${ANDROID_BUILD_TOOLS:-30.0.0}

View File

@ -12,7 +12,7 @@ public final class Ln {
private static final String PREFIX = "[server] ";
enum Level {
VERBOSE, DEBUG, INFO, WARN, ERROR
DEBUG, INFO, WARN, ERROR
}
private static Level threshold = Level.INFO;
@ -36,13 +36,6 @@ public final class Ln {
return level.ordinal() >= threshold.ordinal();
}
public static void v(String message) {
if (isEnabled(Level.VERBOSE)) {
Log.v(TAG, message);
System.out.println(PREFIX + "VERBOSE: " + message);
}
}
public static void d(String message) {
if (isEnabled(Level.DEBUG)) {
Log.d(TAG, message);

View File

@ -7,7 +7,6 @@ import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaCodecList;
import android.media.MediaFormat;
import android.os.Build;
import android.os.IBinder;
import android.view.Surface;
@ -226,11 +225,7 @@ public class ScreenEncoder implements Device.RotationListener {
}
private static IBinder createDisplay() {
// Since Android 12 (preview), secure displays could not be created with shell permissions anymore.
// On Android 12 preview, SDK_INT is still R (not S), but CODENAME is "S".
boolean secure = Build.VERSION.SDK_INT < Build.VERSION_CODES.R || (Build.VERSION.SDK_INT == Build.VERSION_CODES.R && !"S"
.equals(Build.VERSION.CODENAME));
return SurfaceControl.createDisplay("scrcpy", secure);
return SurfaceControl.createDisplay("scrcpy", true);
}
private static void configure(MediaCodec codec, MediaFormat format) {

View File

@ -2,7 +2,6 @@ package com.genymobile.scrcpy.wrappers;
import com.genymobile.scrcpy.Ln;
import android.annotation.SuppressLint;
import android.os.Bundle;
import android.os.IBinder;
@ -38,8 +37,6 @@ public class ContentProvider implements Closeable {
private Method callMethod;
private int callMethodVersion;
private Object attributionSource;
ContentProvider(ActivityManager manager, Object provider, String name, IBinder token) {
this.manager = manager;
this.provider = provider;
@ -47,58 +44,36 @@ public class ContentProvider implements Closeable {
this.token = token;
}
@SuppressLint("PrivateApi")
private Method getCallMethod() throws NoSuchMethodException {
if (callMethod == null) {
try {
Class<?> attributionSourceClass = Class.forName("android.content.AttributionSource");
callMethod = provider.getClass().getMethod("call", attributionSourceClass, String.class, String.class, String.class, Bundle.class);
callMethod = provider.getClass()
.getMethod("call", String.class, String.class, String.class, String.class, String.class, Bundle.class);
callMethodVersion = 0;
} catch (NoSuchMethodException | ClassNotFoundException e0) {
} catch (NoSuchMethodException e) {
// old versions
try {
callMethod = provider.getClass()
.getMethod("call", String.class, String.class, String.class, String.class, String.class, Bundle.class);
callMethod = provider.getClass().getMethod("call", String.class, String.class, String.class, String.class, Bundle.class);
callMethodVersion = 1;
} catch (NoSuchMethodException e1) {
try {
callMethod = provider.getClass().getMethod("call", String.class, String.class, String.class, String.class, Bundle.class);
callMethodVersion = 2;
} catch (NoSuchMethodException e2) {
callMethod = provider.getClass().getMethod("call", String.class, String.class, String.class, Bundle.class);
callMethodVersion = 3;
}
} catch (NoSuchMethodException e2) {
callMethod = provider.getClass().getMethod("call", String.class, String.class, String.class, Bundle.class);
callMethodVersion = 2;
}
}
}
return callMethod;
}
@SuppressLint("PrivateApi")
private Object getAttributionSource()
throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
if (attributionSource == null) {
Class<?> cl = Class.forName("android.content.AttributionSource$Builder");
Object builder = cl.getConstructor(int.class).newInstance(ServiceManager.USER_ID);
cl.getDeclaredMethod("setPackageName", String.class).invoke(builder, ServiceManager.PACKAGE_NAME);
attributionSource = cl.getDeclaredMethod("build").invoke(builder);
}
return attributionSource;
}
private Bundle call(String callMethod, String arg, Bundle extras) {
try {
Method method = getCallMethod();
Object[] args;
switch (callMethodVersion) {
case 0:
args = new Object[]{getAttributionSource(), "settings", callMethod, arg, extras};
break;
case 1:
args = new Object[]{ServiceManager.PACKAGE_NAME, null, "settings", callMethod, arg, extras};
break;
case 2:
case 1:
args = new Object[]{ServiceManager.PACKAGE_NAME, "settings", callMethod, arg, extras};
break;
default:
@ -106,7 +81,7 @@ public class ContentProvider implements Closeable {
break;
}
return (Bundle) method.invoke(provider, args);
} catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException | ClassNotFoundException | InstantiationException e) {
} catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e) {
Ln.e("Could not invoke method", e);
return null;
}