FPV and VR Android App MyMediaCodecFPVPlayer Wifibradcast OpenSource

Constantin

Erfahrener Benutzer
#1
Funktionsweise:
Diese App funktioniert nicht nur wie ein Video Player,sie hat auch eine ganze Menge Extras .

1)Video: empfängt einen raw h.264 Stream auf UDP Port 5000 (oder TestFile), parst diesen in 'Nalu-Units', und- das ist das wichtigste- decodiert ihn mit kleinstmöglichster Latenz mithilfe Android's MediaCodec API in HW , und rendert den Stream
a) auf ein Android SurfaceView
b) auf ein Android TextureView
c) Side by Side als Textur mit OpenGL ES 2.0.
Und hier ist,wo das VR beginnt: Mit OpenGL und einer Cardboard-Style VideoBrille lässt sich Side by Side nicht nur ein
Stereoskopischer Effekt erzeugen, auch Head Tracking Real Time am Boden ,und sogar die Integration des FPV Videos in eine 3D-Welt, sind möglich.

Voraussetzung: ein Digitaler HD VideoLink, bspw. mit RPI und Wifibroadcast:
http://fpv-community.de/showthread....eo-Thread-zum-Raspberry-HD-Videolink-fon-Befi
Ein modernes Android-Smartphone mit midestens Full HD Resolution

Github Account: https://github.com/Consti10/myMediaCodecPlayer-for-FPV






Tutorial für FPV (beta)

1)Test,ob der VideoPlayer HW-Accelerated funktioniert:
Step1: Downloade das raw h.264 test file "rpi960mal810" von https://github.com/Consti10/myMedia...ree/master/DecoderTestApp-and test video clip und speichere es auf dem internen Speicher.
Step2: Settings->DecoderSettings -> Data Sorce: receive from raw h.264 file
FileName 1: rpi960mal810
ListPreference: select HW decoder
Step3: wähle eine der Activities. Wenn das Video in x-facher Geschwindigkeit läuft,dann passt alles.
Wenn nicht: multiThread on/off , und/oder SW Decoder wählen.



OPTION A:
Vorteile:schnell&easy, Nachteile: KEIN "wifibroadcast" ! ,sondern ein direkter wlan link - reicht nur für ~200m herumcruisen
Benötigt: rpi mit camera und wlan Stick,handy mit neuester app
Weg der Daten: Licht->rpi cam->rpi h.264 encoder->wlan(raw h.264 data byte-stream over udp)->handy->hw h.264 decoder des Handy's->Screen

Stepp 1) Herstellen der Verbindung Pi-Handy
Auf dem Handy einen wlan Hotspot starten,und den rpi mit dem Hotspot verbinden.
Test:Der rpi sollte nun bspw. google öffnen können

Stepp 2) Ip Adresse des Handy's finden & aufschreiben
Entweder findet man die ip des Handy's in den Einstellungen, oder man startet "TestActivity"; dort stehen die ip adressen des Handy's. Ich sage Adressen- das Handy kann mehrere ip's haben (bspw. 1 für das Heim-Wlan, 1 für den Hotspot), von denen nur 1 die gesuchte ist.
In der App muss man in diesem fall das richtige interface suchen; diese haben leider keine "gewohnten" trivialnamen.

Bei mir:"wlan0"= home wlan
"rmnet0"= wlan hotspot
"xxx"= usb hotspot
Zur not hilft jedoch google schnell weiter.
In meinem fall ist das Handy per wlan Hotspot mit dem pi verbunden; Ich schreibe mir also 10.69.47.45 als ip Adresse auf.
Test: auf dem pi sollte die ip mit "ping 10.69.47.45" ereichbar sein; Achtung: es sind alle ip's des Handy's "ping-bar",aber nur die vom richtigen Interface funktioniert später.
Achtung: erhöhte Latenz durch Eigenschaften der WIFI verbindung

Stepp 3) Camera starten & daten an's handy senden
Auf dem pi folgendes Kommando eingeben "raspivid -w 960 -h 810 -b 3000000 -fps 49 -t 0 -pf baseline -ih -g 49 -o - | socat -b 1024 - udp4-datagram:10.69.47.45:5000 ";
dabei nun natürlich anstatt 10.69.47.45 die aufgeschriebene ip verwenden.
Test: In "testActivity" sollte nun nicht mehr das toast "couldn't receive any bytes" erscheinen,sondern die empfangenen frames&bytes:

Wenn nicht: die pipeline nochmal überprüfen.

Stepp 4) Decodiertes video anzeigen:
Eine Anzeigeart auswählen & das video checken.
Wenn kein Video angezeigt wird: es kann bis zu 10 sec. dauern,bis der decoder initialisiert ist & ein key-frame empfangen hat.
Wenn der parameter -ih fehlt: die raspivid pipeline auf dem pi nach dem Player starten.
Wenn nicht: mal in den Einstellungen -> Latency file schauen, ob der decoder wirklich frames decodiert.
es kann jedoch auch sein,dass der decoder mit dem rpi cam byte-stream nicht kompatibel ist - dann mal im thread schreiben, ich versuche dann,eine Lösung zu finden.




OPTION B:
Vorteile:Reichweite,"wifibroadcast" übertragung
Nachteile: komplizierter
Benötigt: "normalen" tx und rx pi, Handy, app, USB kabel
Weg der Daten: Licht->rpi cam->rpi h.264 encoder->wifibroadcast tx-> air(wifibradcast packets)->wifibradcast rx->usb-kabel->handy-app->hw h.264 decoder des Handy's->Screen

Vorgehensweise: wie bei Option A); wir verbinden das Handy aber mit dem rx pi,und verändern die rx pipeline:
1)Für die,die keines von den "prebuild" images nehmen:
./rx -b 4 -r 2 -f 1024 wlan2 | socat -b 1024 - udp4-sendto:10.69.47.45:5000" ( parameter -b , -r ,und die ip müssen natürlich angepasst werden )
2)Für die mit den prebuild images:
ungefähr so: $WBC_PATH/rx -p $PORT -b $BLOCK_SIZE -r $FECS -f $PACKET_LENGTH $NICS | socat -b 1024 - udp4-sendto:192.168.0.104:5000;
die "raspivid pipeline" durch die "socat pipeline" ersetzen

Ich persönlich verbinde das Handy am liebsten per usb hotspot mit dem rx pi; wenn sich die channels nicht stören, ist jedoch auch eine wlan hotspot verbindung möglich & angenehm (fatshark like -kein kabel am boden )

----------------------------------------------------------------------------------------------------
Settings:



1)OpenGL Settings (Settings for playing video and OSD)
1.1)Overall

1.1.1)Video Format: wenn die Auflösung bspw. 800*600 beträgt,so ist das Format 800/600=1.333.
1.1.2)video Distance: Abstand Auge-Video Leinwand
1.1.3)interpupilarryDistance: Augenabstand für 3D
1.1.4)swapIntervallZero: improves lag
1.1.5)Extension: Experimental
1.1.6) Head Tracking on/off
1.1.7) OSD on/off

1.2))OSD specific settings: Achtung: noch in Entwicklung

1.2.1)model Distance: Abstand Virtual Kopter-Auge
2),3),4),... Ob man die jeweilige funktion vom OSD an/ausschalten möchte

2)Decoder Settings
1)Data Source: die app kann die raw h.264 streams entweder auf dem udp port 5000 empfangen,oder ein raw .h264 file(wie es die rpi cam erzeugt) parsen
Praktisch zum testen; man muss nur aufpassen,wenn die app ein File parst,wird der encoder so schnell wie möglich gefüttert, und es besteht
keine time-synchronisation
2)File Name 1: receiving data from file; das file muss auf demselben ort gespeichert sein,wo auch das "GroundRecording" file liegt;
3)Decoder MultiThread: empfohlen: an
4)Select your decoder: HW decoder unterscheiden sich sehr stark von Chipsatz zu Chipsatz. der SW decoder funktioniert auf allen Geräten,ist jedoch langsammer;
wenn der HW decoder nicht funktioniert,bitte im Thread schreiben

3)Ground recording Settings:
1)Ground Recording on/off. Kann bei langsammen Geräten Latenz erhöhen,muss aber nicht;
2)File Name 2: ground recording file

4)Debug Settings:
1)Latency: zeigt die messbare Latenz der app an; wie viele frames android buffert,ist schwer zu sagen, und hängt auch vom hersteller ab; mein huawei hat einen input lag von ~60ms (getestet,wer will kann mal die App OpenGLLagTest ausprobieren) ; angenommen der touchscreen hat 12ms verzögerung,dann buffert android wohl 3 frames (48ms); der Lag 'Info zu Pixel' ist dann "measured App latency+48ms)
2)UserDebug: disable for FPV flying !
3)DebugFile: klappt noch nicht ganz; Android Studio gibt deutlich mehr Informationen aus

-----------------------------------------------------------------------------------------------------
OSD: in Developement

FAQ:
1)warum kann ich nicht das wlan vom handy für wifibroadcast benutzen,und brauche den rx pi ?
-Android unterstützt keinen "Monitor mode" und auch wifibradcast hat noch niemand auf Android portiert; für die technisch versierten: Es geht schon,ist jedoch kompliziert; info's hier: https://befinitiv.wordpress.com/2015/04/18/porting-wifibroadcast-to-android/

2)wie hoch ist der Lag der App ?
Bei meinem Handy (Huawei ascend p7 , mali 450 mp gpu) gehen bei 49 fps von 130ms end-to-end latency etwa 60ms auf die app.
In den Einstellungen findet ihr ein "Latency file".

Der "overall measured lag of the app" sollte nicht höher als 20ms sein (bei mir: ~12ms); wenn er größer ist,dann Buffert der hw decoder vermutlich frames (ein feature von manchen herstellern,das für real-time streaming jedoch nur von Nachteil ist).
Achtung: Da das TestFile mit der max. Geschwindigkeit abgespielt wird,ist die "measured app Latency" nur beim Abspielen des udp Streams aussagekräftig.
Der restliche Lag (etwa 48 ms) entsteht durch "Android's SurfaceFlinger",welcher bis zu 3 "display-frames (16ms)" latency erzeugt.
Generell: Lag of App in ms=((3/OpenGlfps*1000)+measuredAppLatency);
Lag of Stream=EncoderLag+AppLag.
Die App ist schon so weit,wie es für einen "nicht-breadcom-hw-engineerer" geht, auf real-time optimiert. Und ich sage nicht ohne Stolz,dass ich mit dem "Software x264 encoder" und avconv auf meinem linux pc den Bildschirm bei 120fps unter 70ms auf mein Handy spiegeln kann - das ist mindestens genau so gut,wie die "GameStream" Angebote von nVidia oder steam ( https://youtu.be/a9-bdXUC0j0 ).
*UPDATE 29.03.2016: Setting swap intervall to zero reduces lag by 1 more frame on my device,and increases OpenGL fps*

3) Die usb Verbindung handy-rpi trennt sich nach kurzer Zeit:
Wenn das Handy angeschlossen wird,lädt der rpi es natürlich auf;
https://www.raspberrypi.org/forums/viewtopic.php?f=29&t=100244
Bei einem guten PowerSupply am rx Pi.

4) Warum ist die App nicht direkt eine "Cardboard-App" ?
Der "Disortion renderer" von Google Cardboard erzeugt noch einmal einen Lag von etwa 30ms, weshalb ich zwar Die Cardboard-API "HeadTracker" in meiner App benutze,den Stereoskopischen Effekt(leftEyeViewM,...) jedoch selber erzeuge.
Einziger Nachteil: Die VR brille sollte nicht zu sehr "verzerren".
 
Zuletzt bearbeitet:

just_different

Erfahrener Benutzer
#2
erst mal.. klasse gemacht.. und danke für die Mühe und die Anleitung.

Noch eien Frage: für den testfile und auch Groundrecording, kann ich ein beliebiges Verzeichnis erstellen auf dem internen Speicher?
Für beides kann ich dann die Parameter auswählen.. bzw. angeben?

Ist, was die Latenz angeht, USB-Kabel genauso schnell wie BT, oder gar WLAN, wenn man die Variante B wählt?

Mich würde nämlich die ohnehin problematische Power Versorgung beim PI, mit der Ladefunktion stören (Kabel-USB).
 

stxShadow

Erfahrener Benutzer
#3
Mal als Erweiterung zu den Leistungswerten: Hardware Decoder fps sind 129 und App Latency 49 ms. Wieso ist denn die App Latenz bei Dir so deutlich geringer? Handy: s6 edge+
 

Constantin

Erfahrener Benutzer
#4
erst mal.. klasse gemacht.. und danke für die Mühe und die Anleitung.

Noch eien Frage: für den testfile und auch Groundrecording, kann ich ein beliebiges Verzeichnis erstellen auf dem internen Speicher?
Für beides kann ich dann die Parameter auswählen.. bzw. angeben?

Ist, was die Latenz angeht, USB-Kabel genauso schnell wie BT, oder gar WLAN, wenn man die Variante B wählt?

Mich würde nämlich die ohnehin problematische Power Versorgung beim PI, mit der Ladefunktion stören (Kabel-USB).
1)Das Ground Recording File muss ohne Ordner direkt auf dem externen Speicher liegen. Du kannst auch einmal per udp empfangen& Ground recording wählen,dann erstellt er dir das GroundRecording File,und du weisst,wo das TestFile hingehört.
Zugegeben: nicht user-freundlich,ich überlege mir gerade etwas anderes.
2) edited faq with link
3) was meinst du mit BT ? Ich empfehle mit Wifibroadcast wegen Interferenz den usb Hotspot.
 
Zuletzt bearbeitet:

Constantin

Erfahrener Benutzer
#5
Mal als Erweiterung zu den Leistungswerten: Hardware Decoder fps sind 129 und App Latency 49 ms. Wieso ist denn die App Latenz bei Dir so deutlich geringer? Handy: s6 edge+
Ich vermute,du hast das TestFile abgespielt,da kann bei 130fps die Latenz vom Decoder deutlich höher sein,da die Software/Hardware ja an der max. Fps Grenze ist. Wenn du den rpi Stream empfängst (bspw. 49fps) ,sollte die Latenz geringer sein.
 

juli112

Erfahrener Benutzer
#6
Habe die Tage mal versucht eine Alternative zu socat / USB-Tethering zu bauen und per libusb und dem Android-Gerät im Android Accessory-Modus die Pakete direkt per USB zu übertragen. Funktioniert auch, die Übertragung ist aber wohl zu langsam.

Ich sende die Pakete in process_payload() (rx.c) bei jedem stdout (meist 1020 Bytes) asynchron an das Androidgerät ( libusb_alloc_transfer -> libusb_fill_bulk_transfer -> libusb_submit_transfer) und lese sie über den FileInputStream in dem UdpReceiverDecoderThread ein:

PHP:
while (running) {
    try {
        //FileInputStream fIn = USBHandler.getInput();
        if (USBHandler.mFin != null) {
            numBytes = USBHandler.mFin.read(stream);
            if(numBytes > 0) {
                parseDatagram(stream, numBytes);
                numBytes = -1;
            }
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}
Der USB-Out-Buffer auf dem Raspberry Pi füllt sich dabei immer mehr, bis der RAM voll ist. Ich weiß nicht ob die Performance besser wird, wenn man größere Pakete sendet, oder ob man direkt den Empfang per Android NDK in C schreiben sollte..
Ich kann den Code gerne mal auf Github stellen, wenn jemand daran weiter probieren möchte...
 

sandmen

Erfahrener Benutzer
#7
Ich hab's direkt im wbc gemacht.
Also UDP socket im wbc aufmachen, und auf die Client IP senden.
Ist aber nicht so, das man hier große Unterschiede in der Latenz sieht....
 

Constantin

Erfahrener Benutzer
#9
Habe die Tage mal versucht eine Alternative zu socat / USB-Tethering zu bauen und per libusb und dem Android-Gerät im Android Accessory-Modus die Pakete direkt per USB zu übertragen. Funktioniert auch, die Übertragung ist aber wohl zu langsam.

Ich sende die Pakete in process_payload() (rx.c) bei jedem stdout (meist 1020 Bytes) asynchron an das Androidgerät ( libusb_alloc_transfer -> libusb_fill_bulk_transfer -> libusb_submit_transfer) und lese sie über den FileInputStream in dem UdpReceiverDecoderThread ein:

PHP:
while (running) {
    try {
        //FileInputStream fIn = USBHandler.getInput();
        if (USBHandler.mFin != null) {
            numBytes = USBHandler.mFin.read(stream);
            if(numBytes > 0) {
                parseDatagram(stream, numBytes);
                numBytes = -1;
            }
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}
Der USB-Out-Buffer auf dem Raspberry Pi füllt sich dabei immer mehr, bis der RAM voll ist. Ich weiß nicht ob die Performance besser wird, wenn man größere Pakete sendet, oder ob man direkt den Empfang per Android NDK in C schreiben sollte..
Ich kann den Code gerne mal auf Github stellen, wenn jemand daran weiter probieren möchte...
Da die Übertragung per socat/udp so gut klappt (ping 1ms,da geht echt nichts verloren) bleibe ich erst einmal dabei;
Erzeugst du den FileInputStream vor oder im "while()" loop ?
 

Constantin

Erfahrener Benutzer
#10
Ich hab's direkt im wbc gemacht.
Also UDP socket im wbc aufmachen, und auf die Client IP senden.
Ist aber nicht so, das man hier große Unterschiede in der Latenz sieht....
Das ist cool,dadurch spart man sich die 1024 bit buffer in der linux pipeline.
Kannst du mir nen link schicken ? Ich wollte eh die app in eine der "prebuild" images integrieren,etwas wie "rpi fährt hoch -> schauen,ob nen Handy mit hotspot am usb hängt -> wenn ja,daten aufs handy,wenn nein,daten per raspivid aufn screen,oder beides"
Kann aber derzeit leider nicht an der app arbeiten,zu viele Klausuren.
 

Scumbag

Neuer Benutzer
#12
Hallo,
erstmal vielen Dank für die klasse APP!
habe ein kleines Problem, wegen mangelnden Linux kentnissen benutze ich die vorgefertigten Images von Befi v0.4
ich habe die rx.sh und die settings.sh entsprechend abgeändert.
Das video wird auch erfolgreich aufs Handy gestreamt nur ist es von Bildfehlern überseht.
Sieht für mich sieht das nach einem decodierungsfehler aus, da das video ohne handyapp problemlos übertragen wird.
Ich benutze ein xiaomi redmi note 2.
Das testvideo läuft bei mir ohne Probleme.
Ich habe auch schon im handy den 2 ten codec ausprobiert dann sehe ich nur ein graues Bild. Multithreading habe ich auch schon an und ab geschaltet macht kein unterschied.
Habe die aktuellste miui rom drauf basiert noch auf android 5.02.
Die App startet aber problemlos und laeuft "stabil" bis auf das sie abkackt wenn ich usb tethering anschalte während die app laeuft. Mit der version 4.4 empfange ich leider kein video.
Meine Frage wär nun: muss ich beim image auch die tx.sh abändern steht ja was von raspivid pipline durch socat ersetzen in der beschreibung, raspivid habe ich aber nur in der tx.sh gefunden, wenn nein gibt es irgend eine möglichkeit den gestreamten codec zu ändern?
Mein nächster schritt wär nen sudo apt-get upgrade/update über beide images rennen zu lassen, habe ich bisher nur für den rx pi gemacht.

vielen Dank im vorraus!
 

Constantin

Erfahrener Benutzer
#13
Hallo,
erstmal vielen Dank für die klasse APP!
habe ein kleines Problem, wegen mangelnden Linux kentnissen benutze ich die vorgefertigten Images von Befi v0.4
ich habe die rx.sh und die settings.sh entsprechend abgeändert.
Das video wird auch erfolgreich aufs Handy gestreamt nur ist es von Bildfehlern überseht.
Sieht für mich sieht das nach einem decodierungsfehler aus, da das video ohne handyapp problemlos übertragen wird.
Ich benutze ein xiaomi redmi note 2.
Das testvideo läuft bei mir ohne Probleme.
Ich habe auch schon im handy den 2 ten codec ausprobiert dann sehe ich nur ein graues Bild. Multithreading habe ich auch schon an und ab geschaltet macht kein unterschied.
Habe die aktuellste miui rom drauf basiert noch auf android 5.02.
Die App startet aber problemlos und laeuft "stabil" bis auf das sie abkackt wenn ich usb tethering anschalte während die app laeuft. Mit der version 4.4 empfange ich leider kein video.
Meine Frage wär nun: muss ich beim image auch die tx.sh abändern steht ja was von raspivid pipline durch socat ersetzen in der beschreibung, raspivid habe ich aber nur in der tx.sh gefunden, wenn nein gibt es irgend eine möglichkeit den gestreamten codec zu ändern?
Mein nächster schritt wär nen sudo apt-get upgrade/update über beide images rennen zu lassen, habe ich bisher nur für den rx pi gemacht.

vielen Dank im vorraus!
Hallo,
das erste was mir einfällt: Hast du schon einmal versucht,erst den renderer der app,und dann raspivid zu starten ?
Der decoder braucht einen "Key-frame" ,um den h.264 stream richtig anzuzeigen (wie auch am rpi).
Welche key-frames und wie viele,das ist leider nicht dokumentiert. Derzeit initialisiere ich den hw-decoder am anfang mit extrahierten rpivid parametern, (deshalb kann man wenigstens sagen,er "rendert irgendwas), doch sobald ein parameter geändert wurde,braucht man wieder ein key-frame. Deshalb: wenn nicht schon in der raspivid pipeline der parameter -ih gesetzt ist,muss man erst eine Activity der app (bspw. SurfaceView), dann raspivid starten.
Ich hoffe,dies löst dein Problem.
Lg
Consti
 

Scumbag

Neuer Benutzer
#14
Hi Constantin,
danke für die schnelle Antwort, hat leider nicht funktioniert, werde als nächstes das TX Image updaten wer weiss wie alt der Codec auf dem Image ist.
Hoffe das es dann rennt. Benutzt den ausser mir noch jemand das befi Image?
 

Scumbag

Neuer Benutzer
#15
Hatte die settings.sh beim TX pi angepasst dann liefs kurzzeitig leider nur einmal... Liegt wohl doch irgendwie an den Keyframes da er dabei den stream neu empfangen hat während er aufm Handy bereits am decoden war. Lässt sich nur derzeit leider nicht wiederholen.
In den Parametern ist -ih aktiviert. Nur anschließend kein Wert gesetzt muss ich da noch was Eintragen?
 
Zuletzt bearbeitet:

K Quist

Neuer Benutzer
#16
First of all: I hope it is okay I write in english in here. You all can answer me in german and I will manage to understand it based on what I learned in school :D

I would like to thank Constantin for sharing this cool app, it works great. I would like to give something back, so I will try to implement the following into the app.
* Java USB WIFI card(requires RTL8187 chipset) interface from Android PCAP
* JNI implementation of the RX code from Befinitiv

This should make it possible to get rid of the Rx Raspberry Pi in the setup, and connect the USB wifi card directly to the OTG power of your phone. And maybe thereby further reduce the latency.
 

just_different

Erfahrener Benutzer
#17
K Quist: You know to get it working it´s neccassery to work with WiFi in monitormode..
Do you get this working at Android??

If this work.. and you´r able to receive good packages from TX... great.

Where do you store this Code for us?

I would use it at a Samsung note 4.
 

moritzz06

Erfahrener Benutzer
#18
Hey,

Ich nutze die App mitlerweile in Verbindung mit Linux Deploy und einem angepassten Kernel für das LG G3. Funktioniert auch soweit, bis auf gelegentliche Freezes der App. Dann hilft nur ein Beenden der App und erneutes starten. Hat das noch jemand beobachtet? finde das ein wenig beunruhigend ;)
Das andere Problem sind Ruckler und Fragmente im Bild. Daher die Frage, mit welchen Einstellungen nutzt ihr euer System (sowohl RX als auch TX)? An der Leistung des G3 sollte es eigentlich nicht liegen. Habe die Bitrate schon von 5500000 auf 4500000 reduziert und die Auflösung von 1280*960 auf 960*810. Hat aber beides nicht geholfen.
Jemand eine Idee?

Gruß,
Moritz
 
#19
Wow, tolles Projekt! Habe mir heute die Hardware für Variante A bestellt, wenn es gut läuft, rüste ich später auf B auf. Danke für die App, obwohl ich noch nicht weiss, ob es überhaupt klappen wird :).

Und @moritzz06: woher hast du den angepassten Kernel für das G3? Ich habe es nämlich ebenfalls vor zu nutzen.
 
RCLogger

FPV1

Banggood

Banggood

Oben