FFmpeg-Text-Overlay fügt Sensorwerte in den Videostream ein

Ich verwende eine externe Kamera mit ffmpeg, um einen Unterwasser-Livestream zu erfassen. Jetzt möchte ich einige dynamische Werte (Textüberlagerung) über den Videostream hinzufügen und diese an einen externen Anbieter wie YouTube Live übertragen ... Meine Werte stammen von verschiedenen Sensoren (Temperatur, Sauerstoff, Salzgehalt usw.) und diese Werte müssen eingebettet werden in den Videostream.

Was ist der richtige oder "beste" oder "richtige" Weg, dies zu tun?

Da dies in einem Live-Stream erfolgen muss, verwenden Sie mehrere Drawtext-Filter, die aus einzelnen (aktualisierten) Textdateien lesen, wobei der Filter gesetzt ist, um diese Dateien neu zu laden.
Warum es auf die harte Tour machen "Ich habe diese Methode noch nicht getestet", aber Sie können .m3u8Dateikontinuitäten verwenden, sagen wir zwei Bilder, die ffmpegdas kontinuierliche Laden dieser Bilder erzwingen, sodass Sie diese Bilddatei ändern/ersetzen/aktualisieren und ffpmegladen können sie schnell

Antworten (1)

Diese Frage ist ein bisschen ähnlich wie Ich versuche, Gitarrentabulaturen zu einem Musikvideo hinzuzufügen, kennen Sie eine Software, die das macht?

Zunächst einmal, in welchem ​​Format Ihre Daten, welches Protokoll von Ihren Sensoren verwendet? Ich denke, hier eine Closed-Source-Software und ein proprietäres Protokoll für ihre Sensoren? Offensichtlich benötigen Sie eine Software, die dieses Datenformat/Protokoll lesen kann. Wenn Sie ein eigenes System mit Mikrocontrollern erstellen, versuchen Sie, ein verwendbares und offenes Protokoll für Daten zu finden. Es ist sehr schwierig, offene Protokolle mit der erforderlichen Funktionalität zu finden.

An diesem Punkt haben Sie wohl ein geeignetes Protokoll gefunden. Beispiel: JSON mit benutzerdefinierten Feldern. Versuchen Sie nun, Software zu finden/schreiben, die sie verwenden wird.

Ein möglicher Weg: Schreiben Sie eine Webanwendung, die einen Videostream in Ihrem Browser anzeigt, Daten von Sensoren lädt und lustige Overlays anzeigt. Nehmen Sie dann einfach ein Video von Ihrem Bildschirm und übertragen Sie es an YouTube oder einen anderen Dienst. Dies ist ein "schmutziger" Weg, aber es wird funktionieren.

Andere Möglichkeit: Schreiben Sie einen benutzerdefinierten Filter in ffmpeg. Sie können ass-renderer als Referenz verwenden, um Text zu einem Bild hinzuzufügen. Fügen Sie einfach Lesedaten von Ihren Sensoren hinzu und Ihre Aufgabe ist erledigt.


Schreiben von schnellen und schmutzigen Videofiltern

Manchmal müssen wir das Video irgendwie filtern, vielleicht etwas Text oder eine Grafik darüber legen. Schreiben Sie eine vollständige Anwendung, die den Videostream dekomprimiert, das Bild mit neuen Elementen durchdringt oder das Bild selbst ändert und den Stream dann erneut komprimiert, etwas schwierig. Heute werden wir lernen, wie man solche Anwendungen schnell und schmutzig macht, ohne zu wissen, wie man das Video im Allgemeinen codiert.

Denken Sie zunächst daran, dass die Bilder aus Reihen und Spalten von Punkten bestehen, die als Pixel bezeichnet werden. Jeder Punkt besteht aus 3 oder 4 Komponenten, normalerweise rote, grüne und blaue Signale, und manchmal gibt es einen Alphakanal. Um 1 Punkt des Bildes zu ändern, müssen wir daher 3-4 Komponenten ändern (dies sind normalerweise 3-4 Bytes). Um also das gesamte Bild zu ändern, müssen wir alle Zeilen und Spalten in jedem der 3-4 Elemente ändern und sie irgendwie modifizieren, zurückspeichern. Wenn wir beispielsweise ein Bild mit 256 x 192 Pixeln im RGB24-Format haben, dann hat es 49152 Pixel und 147456 Farbkomponenten (Bytes).

Daher müssen wir nur Teile von 147456 Bytes lesen, irgendwie modifizieren und zurückschreiben! Es ist alles! Es sind keine komplizierten Bibliotheken oder Algorithmen erforderlich! Woher bekommen wir diese Bytes? Und wir können sie mit dem wunderbaren Dienstprogramm ffmpeg und seinem ebenso wunderbaren Rawvideo-Modus erhalten, dessen Erschöpfung wir an stdout weitergeben und in stdin Ihrer Anwendung erhalten!

Lassen Sie uns die einfachste Anwendung schreiben, die das Bild leicht verändert:

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>

int main () {

// allocate variables and buffer

uint8_t *pixels = malloc (147456);
uint8_t *pix;
int q;

while (1) {

// read frame
if (fread (pixels, 1,147456, stdin) <= 0) {break;}

// process image
pix = pixels;
for (q = 0; q <49152; q ++) {
*pix++ = *pix * 2; // multiple red to 2
*pix++ = *pix + 120; // shift green channel
*pix++ = *pix + q / 10; // lines in blue channel
}

// write frame back
fwrite (pixels, 1,147456, stdout);
}

return EXIT_SUCCESS;
}

Ja, das ist alles! Natürlich sind hier alle Konstanten fest codiert, niemals in echten Projekten!

Führen Sie dies jetzt aus und laden Sie hier ein Video hoch:

ffmpeg -i video.mp4 -s 256x192 -f rawvideo -pix_fmt rgb24 - | ./a.out | ffmpeg -s 256x192 -f rawvideo -pix_fmt rgb24 -i - -y out.mp4

Und wir erhalten folgendes Ergebnis:

Geben Sie hier die Bildbeschreibung ein 2.gif

Lassen Sie uns analysieren, welche Parameter in dieser Zeile beteiligt waren:

ffmpeg -i video.mp4 -s 256x192 -f rawvideo -pix_fmt rgb24 -

Hier lesen wir die Datei aus video.mp4, skalieren das Bild um 256x192(wenn dein Video schon 256x192 groß ist, dann geht das nicht), dann geben wir an, dass es in rgb24Farbraum konvertiert werden soll (wenn es nicht schon drin ist, was denn kann ziemlich viel Ressourcen verbrauchen), und das Ergebnis, das wir in Form von unkomprimiertem Video benötigen rawvideo, das Ergebnis, das wir in aufnehmen -, dh in stdout.

| ./a.out |

Und das ist unsere Anwendung. Vertikale "Röhren" bedeuten, dass Daten von der vorherigen Anwendung übernommen und an die nächste übertragen werden

ffmpeg -s 256x192 -f rawvideo -pix_fmt rgb24 -i - -y out.mp4

Hier geben wir an, dass die Eingabe dieses ffmpeg unkomprimiertes Video in rawvideoFormat, Größe 256x192und im rgb24Farbraum sein wird. Es ist möglicherweise auch erforderlich, fps anzugeben, da es bei einer solchen Konvertierung verloren geht. Wir schreiben die Ausgabe in out.mp4, und selbst wenn eine solche Datei bereits existiert, ist der -yParameter dafür verantwortlich

Hier ist ein sehr einfaches Beispiel für das Ändern des Bildes, aber Sie können Text, andere Bilder und alles andere überlagern. Natürlich ist es besser, eine vollwertige Anwendung zu schreiben oder zumindest den bereits vorhandenen Filter auf den gewünschten Zustand zu patchen, dies ist eine korrektere Lösung. Aber wenn Sie eine funktionierende Lösung brauchen, aber nicht viel Code schreiben möchten, ist dies die Lösung für Sie.

Ich kann JSON oder XML verwenden, um meine Sensordaten zu übergeben ... oder jedes andere Format. Das Problem, das ich habe, ist nur, wie ich Daten an ffmpeg übergebe.
habe hier das Beispiel gefunden: s55ma.radioamater.si/2017/08/04/…
Hier müssen Sie Ihren Text jeden... Frame in die Datei schreiben! Ja, das kann funktionieren, aber es ist ziemlich schmutzig für mich. Ich mag solche tmp-Dateien und CPU-Verschwendung nicht. Also schlage ich vor, einen einfachen Filter dafür zu schreiben.
Habe mit Java getestet. Habe einen einfachen Thread-Prozess erstellt, der einige Werte in die Datei schreibt. Wenn die Datei geschlossen wird, führe ich die Files.move-Methode mit StandardCopyOption.ATOMIC_MOVE aus Einige gute Referenzen (Links), bitte helfen Sie mir. Die andere Option ist die Verwendung von OBS Studio, aber ich muss überprüfen, ob sie von der Befehlszeile (Terminal) (ohne GUI) ausgeführt werden kann.
Sie haben Erfahrung mit C oder C++? Sie können eigene Filter auf Pipes schreiben, wie ffmpeg -i _SOURCE_ -f rawvideo -pix_fmt rgb32 - | ./your_app | ffmpeg -f rawvideo -pix_fmt rgb32 -i - rtmp://broadcast.to.server/. Dadurch werden Frames über stdin an Ihre App übergeben, dann können Sie darauf zeichnen und Bitmaps an stdout übergeben, wo eine neue Instanz von ffmpeg sie codiert und in Datei/Broadcast speichert.
Will es gerne versuchen, muss aber zuerst ein Beispiel sehen oder darüber bloggen. (Habe einige Projekte auch in C/C++ (vergangen) gemacht).. ;)
Heute-morgen werde ich einen schreiben
Danke dir! Bitte informieren Sie mich, damit ich Ihren Code überprüfen kann. Im Moment habe ich nur die Möglichkeit, FFmpeg mit Drawtext aus einer Datei zu verwenden, die von Java aktualisiert wird Ich kann es vom Terminalfenster aus ausführen (ohne GUI).
Ich habe Beispiel mit C erstellt, es ist sehr einfach.