Günstiges Livestreaming mit Raspberry Pi & Gstreamer

Wir wollen rasend schnelles Livestreaming. Wir wollen stechend scharfe Bildqualität. Das wollen wir billig und einfach. Mit einem Raspberry Pi und den Gstreamer ist das möglich und ich zeig euch wie.

Wir hier bei Codeflügel forschen derzeit an einem mobilen Telepräsenzsystem, einsetzbar an jeglichen Örtlichkeiten, Jederzeit, von Jedermann und ganz wichtig, mit jeglicher Internetverbindung. Leider kann ich in diesem Blog nicht alles ausplaudern, was wir uns hier in den letzten Jahren „zusammengereimt“ haben, aber ich werde euch Einiges mit geben damit ihr einen schnellen, günstigen Livestream basteln könnt’s.

it is a secret and if i told you it wouldn't be a secret

Das Ziel

Nun… Die Aufgabe die unter anderem zu lösen war lautete folgendermaßen: Streame ein Videosignal mit möglichst geringer Latenz von Ort A nach Ort B. Die geographische Position der beiden Orte sollte dabei möglichst egal sein. Die Kamera sollte mobil sein, der Betrachter darf am PC sitzen. Der Videostream darf eine Latenz unter 1 Sekunde aufweisen. Da man aufgrund der Mobilität der Kamera nicht immer von bester Internetverbindung ausgehen kann mussten einige Überlegungen getroffen werden.

Der Weg

Vor der Übertragung sollten die Videodaten komprimiert werden. Natürlich… Diese komprimierten Videodaten müssen für die Übertragung in ein Streaming Protokoll oder auch Container Format verpackt werden.

Zuerst erschien uns WebRTC als die richtige Lösung, wird es doch als heiliger Gral des Livestreamings angepriesen. Zum damaligen Zeitpunkt wurde die Technologie jedoch nur spärlich unterstützt und auch heute sind die Implementierung nicht flächendeckend. Also entschieden wir uns für RTP (Realtime Transport Protocol). RTP ist alt, robust, schmal und getestet. Darüber hinaus kann man es über UDP streamen, was uns eine geringe Latenz verspricht, weil nicht auf Pakete gewartet wird, die zu spät ankommen.

i know a great udp joke but you might not get it

Der Server

Dieser Videostream sollte dann auf einem Server im Internet landen, wo er den Benutzern zugänglich gemacht wird. Per Webbrowser, weil sowas jeder besitzt. Ein RTSP Server erschien uns als passend, da keine allzu große Transkodierung am Server benötigt wird. Jedoch wird für RTSP im Browser entweder VLC, Quicktime oder Realplayer benötigt. Realplayer und Quicktime weisen eine zu hohe Latenz auf. VLC wäre akzeptabel. Die Installation einer zusätzlichen Software ist für unsere Zwecke jedoch nicht optimal. Wir entschieden uns schlussendlich für RTMP. Jetzt werden einige sagen, „Hey, da muss ich doch auch den Flash Player installieren, damit das rennt.“ Stimmt. Das haben aber die meisten bereits gemacht. Erschreckend viele sogar. Andere werden sagen „Warum nicht MPEG-DASH oder HLS?“. Man erinnere sich an die Vorgabe der geringen Latenz. Die Kodierung auf diverse HTTP-Streaming Geschichten dauert einfach zu lange.

Der Codec

Als Videokomprimierung kommt eigentlich nur H.264 in Frage. Dieser Videocodec ist zwar sehr rechenintensiv, dafür verkleinert er die zu übertragbaren Videodaten ungemein. Die untenstehende Grafik zeigt den Vergleich zu anderen gängigen Videocodes.

 

Es wäre doch schön, wenn wir die rechenintensive Videokompression nicht selbst, also per Software durchführen müssten. Gibt es Geräte, ich meine damit Kameras die uns diese Aufgabe bereits abnehmen? Die Antwort ist JA. Einen ganzen Berg gibt es davon. Vor allem im IP Kamera – Überwachungsbereich ist eine Hardware H264 Komprimierung eigentlich standardmäßig mit dabei. Für Webcams gibt es das leider nur vereinzelt. Creative und Logitech gehören hier zu den Vorreitern und Ansprechpersonen. Wir haben für unsere Zwecke die Logitech C920 gewählt. Diese schmucke Webcam ist eine H.264 UVC (Usb Video Device Class) Kamera. Kann also H.264 über USB streamen. Bingo!

Der Gerät

Nun brauchen wir ein Gerät das wir per USB an die Kamera stecken können und dass uns das Verpacken der Videodaten in RTP Pakete übernimmt. Die Spannung ist begrenzt, weil der Titel dieses Blogs bereits Raspberry Pi 2 enthält. Also, wir nehmen dafür einen Raspberry Pi 2.

livestream with raspberry pi and gstreamer

Das Ganze

Nochmal alles zusammen: Wir nehmen eine Logitech C920, schließen sie an einen Raspberry Pi 2 an, hängen das per WLAN Stick ins Netzwerk und schießen die H264 Videodaten mit RTP und UDP auf unseren Server und raus ins weite Internet. Auf dem Server wartet Gstreamer und verpackt uns das Ganze von RTP in RTMP. Dann weiter auf einen nginx Mediaserver fürs Mulitcasten und schlussendlich per TCP in einen Webbrowser.

Die Codeschnipsel

Wie versprochen gibt es jetzt einige Gstreamer Pipelines.  Die Installation der benötigten Software wird hier nicht erwähnt.

Zuerst eine Pipeline mit der man den H.264 Stream aus der C920 ausliest und mit RTP und UDP auf den Server schickt:

gst-launch-1.0 uvch264src average-bitrate=1000000 iframe-period=1000 device=/dev/video0 name=src auto-start=true src.vidsrc ! video/x-h264,width=1920,height=1080,framerate=30/1,profile=constrained-baseline ! h264parse ! rtph264pay pt=127 config-interval=2 ! udpsink sync=false host= your.server.ip port=5000 

Man beachte: Es wird hier uvch264src verwendet um die Kamera auszulesen. Die Parameter für die Bitrate, die Auflösung, Framerate und vieles mehr wird beim Start der Kamera, durch das ausführen der obigen Pipeline übergeben. Die Parameter können erst wieder durch einen Neustart der Kamera geändert werden, also nicht zur Laufzeit.

Würde man 2 Server besitzen, auf die man streamen möchte, so kann man den Stream auch aufteilen.

gst-launch-1.0 uvch264src average-bitrate=1000000 iframe-period=1000 device=/dev/video0 name=src auto-start=true src.vidsrc ! video/x-h264,width=1920,height=1080,framerate=30/1,profile=constrained-baseline ! h264parse ! rtph264pay pt=127 config-interval=2 ! tee name=t ! queue max-size-time=10000000 ! udpsink sync=false host= your.server.ip port=5000 t. ! queue max-size-time=10000000 ! udpsink sync=false host=your.other.server.ip port=5000

Auf unserem Server wird RTP dann auf RTMP konvertiert. Da wir es zuvor per UDP übertragen haben muss hier als source udpsrc verwendet werden. Das Ziel ist ein lokaler nginx RTMP Mediaserver.

gst-launch-1.0 udpsrc caps="application/x-rtp,payload=127" port=5000 ! rtph264depay ! capsfilter caps="video/x-h264,width=1920,height=1080" ! flvmux streamable=true ! rtmpsink location='rtmp://127.0.0.1:1935/live1/sers'

Zuletzt noch eine Pipeline, die wir auch im Einsatz haben, aber nicht ganz zum Rest passt. Sie extrahiert 30 JPEGs pro Sekunde aus dem C920 stream und speichert diese Bilder im Arbeitsspeicher ab. Es ist zu beachten, dass der Pi eine SD Karte besitzt und diese nicht besonders viele Schreibzyklen verträgt. Deswegen wird eine Ramdisk erstellt, die wie der Name schon sagt, im Arbeitsspeicher liegt.

gst-launch-1.0 uvch264src device=/dev/video0 ! image/jpeg,width=1920,height=1080,framerate=30/1 ! multifilesink location=/home/pi/ramdisk/snap%d.jpeg max-files=60

Die Blumen

Gstreamer bietet neben den Pipelines auch die Möglichkeit in C zu programmieren. Damit können komplexere Aufgaben, wie zum Beispiel die Erstellung eigener Protokolle oder eines RTSP Servers, gelöst werden. Eine Alternative zu Gstreamer wäre FFMPEG gewesen, konnte aber mit H.264 UVC Kameras nicht umgehen. Ich denke das ist ein guter Zeitpunkt sich zumindest einmal öffentlich für all das Open Source Zeugs zu bedanken. Auch wenn es oft zu Marketingzwecken missbraucht wird so weckt es in mir meist das Gefühl von Güte und Zuversicht.

 

Weiterführende Links