first commit
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
# Screen Cast – Bildschirm auf jeden Smart TV
|
||||
|
||||
Für Android-Geräte, denen der Hersteller kein Screen Mirroring spendiert hat.
|
||||
Die App nimmt den Bildschirm auf, encodiert ihn hardwarebeschleunigt in H.264
|
||||
und streamt ihn ins WLAN. Am Fernseher wird nur der Browser gebraucht.
|
||||
|
||||
## Zwei Wege zum Fernseher
|
||||
|
||||
### 1. Fernseher wartet schon auf eine Verbindung
|
||||
|
||||
Für Geräte im Screen-Mirroring-Modus – etwa Hotelfernseher, an denen sich
|
||||
nichts eintippen lässt. In der App auf **Zum Fernseher verbinden** tippen; die
|
||||
Liste zeigt, was gefunden wurde:
|
||||
|
||||
* **Über den Übertragungsdienst von Android** – vielen Handys fehlt nur die
|
||||
Bedienkachel („Smart View“), nicht die Technik. Steht der Fernseher hier,
|
||||
übernimmt Android die Übertragung selbst, in voller Qualität. Das ist der
|
||||
beste Fall.
|
||||
* **Direktverbindung über Wi-Fi Direct** – die App baut die Verbindung selbst
|
||||
auf und schickt das Bild im Miracast-Format hinüber. Läuft komplett am WLAN
|
||||
vorbei, also auch in Gästenetzen, die Geräte voneinander abschotten.
|
||||
|
||||
Darunter liegt ein Protokoll, das jeden Schritt mitschreibt – falls ein
|
||||
bestimmter Fernseher zickt, steht dort, an welcher Stelle.
|
||||
|
||||
### 2. Fernseher mit Browser
|
||||
|
||||
|
||||
|
||||
1. App öffnen, **Übertragung starten**, Systemabfrage bestätigen
|
||||
2. Am Fernseher den Browser öffnen
|
||||
3. Die angezeigte Adresse eintippen, z. B. `http://192.168.1.42:8080`
|
||||
4. Das Bild läuft im Vollbild. `F` (oder die farbige Taste der Fernbedienung,
|
||||
die als F wirkt) schaltet zwischen *ganzes Bild* und *randlos füllend* um.
|
||||
|
||||
Handy und Fernseher müssen im selben WLAN sein. Die App darf in den
|
||||
Hintergrund – die Übertragung läuft als Vordergrunddienst weiter und lässt sich
|
||||
über die Benachrichtigung beenden.
|
||||
|
||||
## Zweiter Ausgang für Player
|
||||
|
||||
`http://<adresse>:8080/stream.ts` liefert denselben Stream als MPEG-TS – für
|
||||
VLC, mpv oder Kodi („Netzwerkstream öffnen“), falls der Fernseher-Browser
|
||||
streikt oder ein Laptop am Beamer hängt.
|
||||
|
||||
## Was beim Direktweg möglich ist – und was nicht
|
||||
|
||||
Der Miracast-Handshake (M1–M7 nach Wi-Fi-Display-Standard) und der RTP-Versand
|
||||
sind vollständig umgesetzt und gegen einen nachgebauten Fernseher getestet.
|
||||
|
||||
Die Steuerverbindung baut **der Fernseher zu uns** auf, nicht umgekehrt – so
|
||||
sieht es der Standard vor, und so macht es Android intern auch
|
||||
(`RemoteDisplay.listen`). Die App hört deshalb auf Port 7236 und 8554 zu,
|
||||
sobald die Bildschirmfreigabe erteilt ist, und zwar *bevor* die
|
||||
Wi-Fi-Direct-Verbindung aufgebaut wird – der Fernseher meldet sich nämlich
|
||||
sofort, wenn die Gruppe steht. Zusätzlich wird die Gegenrichtung versucht,
|
||||
falls ein Gerät es andersherum erwartet.
|
||||
Eine Einschränkung bleibt: Sich per `setWfdInfo` als Wi-Fi-Display-Quelle
|
||||
anzukündigen, verlangt `CONFIGURE_WIFI_DISPLAY` – eine Signaturberechtigung,
|
||||
die nur Systemapps bekommen. Die App verbindet sich deshalb als gewöhnliches
|
||||
Wi-Fi-Direct-Gerät. Fernseher, die auf dieses Kennzeichen bestehen, lehnen
|
||||
dann ab; tolerante Geräte nehmen die Verbindung an.
|
||||
|
||||
Deshalb steht der Weg über den systemeigenen Übertragungsdienst in der Liste
|
||||
oben: Er nutzt genau den Stack, den auch die Cast-Kachel des Systems benutzt,
|
||||
und hat keine solche Hürde.
|
||||
|
||||
## Technik
|
||||
|
||||
| Baustein | Aufgabe |
|
||||
|---|---|
|
||||
| `ScreenEncoder` | MediaProjection → MediaCodec H.264, auf niedrige Latenz getrimmt |
|
||||
| `Fmp4Muxer` | baut fragmentiertes MP4, das Browser über Media Source Extensions direkt abspielen |
|
||||
| `TsMuxer` | MPEG-TS für VLC/Kodi/mpv |
|
||||
| `WebServer` | HTTP + WebSocket, ohne Fremdbibliothek |
|
||||
| `StreamHub` | verteilt an alle Zuschauer, wirft bei langsamen Geräten Rückstand weg statt zu stauen |
|
||||
|
||||
Ein Fragment pro Bild, Keyframe auf Anforderung bei jedem neuen Zuschauer,
|
||||
Puffer im Player wird aktiv kleingehalten – dadurch liegt die Verzögerung im
|
||||
WLAN typischerweise bei einer knappen halben Sekunde.
|
||||
|
||||
## Bauen
|
||||
|
||||
```bash
|
||||
gradle assembleRelease # Gradle 8.9, JDK 17+, Android SDK 35
|
||||
gradle testDebugUnitTest -DsampleH264=<datei.h264> -DmuxOutDir=<ordner>
|
||||
```
|
||||
|
||||
Die Tests schleusen einen echten H.264-Bitstream durch beide Muxer und holen
|
||||
ihn über echte Sockets wieder ab; das Ergebnis lässt sich anschließend mit
|
||||
`ffprobe` prüfen.
|
||||
Reference in New Issue
Block a user