Im dritten Teil dieser kleinen Serie schauen wir uns mal das Zusammenspiel von GStreamer und einer TV-Karte oder Webcam an.
GStreamer ist ein Multimedia-Framework, das in vielen Programmen Anwendung findet – etwa in Totem, Exaile, Banshee, OGG Convert oder Ubuntus zukünftigem Standard-Videoeditor PiTiVi. Sogar in meinem Pyjama . Gerade unter GNOME ist GStreamer das Media-Framework schlechthin.
Entsprechend sollte es eigentlich nicht wundern, dass GStreamer ohne Probleme auf die V4L2-Schnittstelle zugreifen kann. Im Rahmen dieses Eintrages werde ich auch versuchen, ein paar Grundlegende Fähigkeiten von GStreamer zu beschreiben – es ist anfangs gar nicht so leicht, sich in dieses Gebiet einzuarbeiten.
Videowiedergabe
Grundsätzlich kann man bei GStreamer 3 Arten von Elementen unterscheiden: Source-Elemente kümmen sich um die Eingabe und lesen beispielsweise eine Datei. Filter-Elemente verarbeiten diese Daten, indem sie diese etwa kodieren. Die sogenannten Sink-Elemente kümmern sich schließlich um die Ausgabe und schreiben die Daten beispielsweise in eine Datei. Schauen wir uns einfach mal diesen Befehl zur Videowiedergabe an:
gst-launch-0.10 v4l2src device=/dev/video0 ! video/x-raw-rgb,width=640,height=480 ! ffmpegcolorspace ! xvimagesink
Hier wird schon deutlich, dass GStreamer in Pipes organisiert ist. Das Programm gst-launch-0.10 erlaubt es dabei, selbst komplexe GStreamer-Pipes zu testen, ohne tatsächlich irgendwelchen Code schreiben zu müssen. Hier werden die einzelnen Elemente mit Rufzeichen miteinander verbunden. Eigentlich ist dieser Befehl aber nur zum Testen gedacht: Für richtige Programme bietet GStreamer andere Schnittstellen, so dass auch Laufzeit-Interaktion möglich ist.
Im obigen Beispiel liest das Plugin v4l2src Daten aus der angegebenen Quelle. Diese werden dann an das nachfolgende Element weitergegeben – und in diesem Fall auf 640×480 Pixel skaliert. Das nächste Element ffmpegcolorspace konvertiert die Videodaten in den richtigen Farbraum und xvimagesink gibt schließlich das Bild aus.
Das Ganze mit Ton
Bisher haben wir leider nur Video und keinen Ton. Mit folgendem Befehl lässt sich das ändern:
gst-launch-0.10 v4l2src device=/dev/video0 ! video/x-raw-rgb,width=640,height=480 ! ffmpegcolorspace ! xvimagesink osssrc device=/dev/dsp ! osssink
Hier wird eine zweite Pipe eingerichtet, die sich um die Audioausgabe kümmert. Das Element osssrc liest nun Audiodaten vom Geät /dev/dsp. In diesem Fall haben wir keine Filter-Elemente zwischengeschaltet – die Daten werden sofort an den osssink weiter- und damit ausgegeben. Die beiden Abschnitte dieses Befehls sind dabei voneinander völlig unabhängig. Sowohl die Pipe
v4l2src device=/dev/video0 ! video/x-raw-rgb,width=640,height=480 ! ffmpegcolorspace ! xvimagesink
als auch die Pipe
osssrc device=/dev/dsp ! osssink
sind vollständig lauffähig. Nicht unterschlagen werden soll, dass es sei bei dem “video/x-raw-rgb…”-Element nicht im strengen Sinne um ein Element handelt: Intern wird es erst zu einem Capsfilter-Element umgewandelt. Für uns ist das hier aber zunächst nicht weiter wichtig.
Einmal speichern bitte!
Wer die Audio- und Videodaten nun speichern möchte, sollte sich folgenden Befehl einmal näher ansehen:
gst-launch-0.10 v4l2src device=/dev/video0 ! queue ! video/x-raw-rgb,width=640,height=480 ! ffmpegcolorspace ! theoraenc ! queue ! oggmux name=mux osssrc device=/dev/dsp ! queue ! audioconvert ! vorbisenc ! queue ! mux. mux. ! queue ! filesink location=video.ogg
Wie gehabt werden hier zunächst Videodaten ausgelesen, skaliert und farbkonvertiert. Das neue Element theoraenc kodiert die Daten. Wie wir später noch sehen werden, kann hier genauer spezifiziert werden, in welcher Qualität die Kodierung erfolgen soll. Das Element oggmux packt die kodierten Daten schließlich in einen OGG-Datenstrom, der den Namen “mux” erhält.
Der zweite Abschnitt dieser Pipeline wird durch das Source-Element osssrc eingeleitet. audioconvert wandelt die Raw-Audiodaten zur Weiterverarbeitung um, vorbisenc komprimiert das Ganze mit dem OGG-Vorbis-Encoder. Die Daten aus diesem Vorgang fließen über ein Queue-Element in den OGG-Muxer, den wir zuvor ja “mux” getauft haben. Das war der zweite Abschnitt unserer Pipeline.
Im letzten Teil werden nun die Daten aus “mux” – wieder über einen Queue – an filesink übergeben. Wie der Name schon andeutet, kümmert sich dieser Sink darum, die Daten in eine Datei zu gießen. Das etwas irritierende Element “! mux. mux. !” besteht also tatsächlich aus zwei Elementen: Das erste “mux” fungiert als Ziel für die komprimierten Audiodaten. Da “mux” ja der Name des OGG-Muxers ist, werden diese Audiodaten hier also mit den Videodaten “gemultiplext” – sprich: Zusammen in einen Datenstrom gepackt. Das zweite “mux” leitet einen neuen Abschnitt unserer Pipeline ein: Es fungiert hier also als Source-Element und gibt die Daten an das filesink weiter.
Die Queues sind übrigens immer da gefordert, wo ein nachfolgendes Element potenziell “langsamer” ist, das aktuelle: Um Aussetzer in Ton und Bild zu vermeiden, wird so schlicht ein Puffer zwischengeschaltet. Besonders, wenn ihr feststellt, dass eine GStreamer-Pipeline in eurer Programm-Implementierung stuckt und springt, fehlen sehr wahrscheinlich Queues an der richtigen Stelle.
Sehen, hören und speichern
Jetzt wollen wir die ganzen Einzelschritte einmal zusammenbringen. Folgender Aufruf sieht schon wirklich mächtig aus:
gst-launch-0.10 v4l2src device=/dev/video0 ! tee name=videoout ! queue ! video/x-raw-yuv,width=640,height=480 ! queue ! theoraenc quality=30 ! muxout.
osssrc device=/dev/dsp ! tee name=audioout ! queue ! audio/x-raw-int,rate=44000 ! queue ! audioconvert ! vorbisenc ! muxout.
oggmux name=muxout ! filesink location=media2.ogg
videoout. ! queue ! ffmpegcolorspace ! xvimagesink
audioout. ! queue ! osssink
Zur besseren Übersicht habe ich die jeweiligen Abschnitte einmal voneinander getrennt. Eigentlich ist das aber eine zusammenhängende Befehlszeile!
Der erste Abschnitt ähnelt den bisher besprochenen Abschnitten. Neu ist das Element tee: Es dupliziert den Stream – wie das tee in der Linux-Konsole. So können wir später über den Namen “videoout” auf eine Kopie des Videostreams zurückgreifen. Nach einem tee-Element ist immer ein Queue-Element erforderlich. Es folgen weitere bekannte Elemente und schließlich wird der Stream an ein Element mit dem Namen “muxout” übergeben. Das es sich dabei nur um den Namen eines anderen Elementes handelt, erkennt man an dem nachgestellten Punkt. Für uns ist hier erstmal nur wichtig, dass wir den Stream gewissermaßen “zwischengeparkt” haben.
Im zweiten Abschnitt wird parallel für den Audiostream verfahren. Die meisten Elemente sind bekannt, auch hier wird eine “Kopie” mit tee erstellt und auch dieser Stream wird in “muxout” zwischengeparkt.
Der dritte Abschnitt bringt Licht ins Dunkel: “muxout” ist der OGG-Mixer. Er multiplexiert Audio- und Videodaten und gibt das Resultat an den filesink weiter, der das Ganze speichert. Bis hierher ähnelt das Beispiel sehr dem vorherigen Beispiel in “Einmal speichern bitte!”. Neu ist lediglich das Element tee und die Verwendung des Multiplexers. Wann und wo man den Multiplexer “definiert”, ist hier aber eigentlich egal: Man kann auch – wie hier – zunächst einen Stream an einen Element-Namen leiten und diesen erst später einem Element zuweisen.
In Abschnitt 4 wird der Video-Stream wie gewohnt ausgegeben. Neu ist lediglich, dass hier nicht eine Datei oder ein Gerät als Source dient, sondern eben das Element “videout.“, das wir zuvor mit tee definiert als Kopie des Streams definiert haben.
Im Abschnitt 5 wird mit “audioout.” parallel verfahren.
Fazit
GStreamer stellt Einsteiger meines Erachtens zunächst vor große Hürden. Das einfache Wiedergeben eines schnöden Videos kann dabei durchaus schon einige Kopfschmerzen bereiten. Was aber wirklich begeistert, ist die Vielzahl an Möglichkeiten, die man mit GStreamer hat. So ist es sogar ohne große Probleme möglich, Bluebox-Effekte mit GStreamer zu erzeugen – und das finde ich schon recht imposant. Weiterhin profitiert man als Programmierer von der Vielzahl der unterstützten Codecs. So ist es sicher nicht verwunderlich, dass unter GNOME so viele Programme auf GStreamer zurückgreifen.