Wie wird ein statisches Bild angezeigt, wenn der Eingabestream mit ffmpeg endet?

Ich empfange einen Stream über das Netzwerk mit dem folgenden ffmpeg-Befehl:

ffmpeg -i rtmp://server:port/input.stream -f flv rtmp://server2:port/output.stream

Wenn der Eingabestrom anhält, möchte ich ein Standbild anzeigen. Wenn der Eingabestream fortgesetzt wird, möchte ich den Eingabestream weiterhin anzeigen. Ich habe das versucht:

ffmpeg -loop 1 -i Error.png -i rtmp://server:port/input.stream -filter_complex "[0:v][1:v] overlay=0:0" -f flv rtmp://server2:port/output.stream

Das funktioniert, außer wenn der Eingangsvideostream anhält, zeigt er weiterhin den letzten vom Stream empfangenen Frame an. Ich möchte, dass die .png-Datei angezeigt wird (dh der Videoeingang wird transparent).

Was passiert, wenn Sie Ihren Filter von „[0:v][1:v] overlay=0:0“ auf „[0:v][1:v] overlay=0:0:repeatlast=0“ ändern? Repeatlast ist eine Option für Overlay. ffmpeg.org/ffmpeg-all.html#overlay-1
Eine Kombination aus mkfifo und rtmp könnte eine Art Lösung sein

Antworten (1)

TL;DR : Nichts Einfaches. Beide Lösungen verwenden ein Relais, und es ist nicht für die reale Produktion geeignet.


Eigentlich hat man nur zwei Möglichkeiten, und beide sind hässlich.

Es gibt absolut keine Open-Source-Software, die einen nicht permanenten Stream verarbeiten kann (GStreamer+Forks, FFmpeg, VLC, MPlayer). Alle haben das gleiche Verhalten: letzter Frame noch sichtbar, und alles wird angehalten, bis wieder Daten kommen.

Option 1 – Tunneling + Cache

Sie benötigen zwei laufende FFmpeg und ein Skript mit FFplay.

Das erste FFmpeg zieht den RTMP-Stream. Der Ausgang ist ein lokaler Port und das Protokoll muss auf MPEG-TS basieren. Es ist besser, wenn der Eingang auf die niedrigste Latenz abgestimmt ist.

Außerdem müssen Sie den Start von FFmpeg optimieren: keine Analyse des Streams (fps in der Befehlszeile festlegen), früher Start usw.

Das zweite FFmpeg zieht den lokalen MPEG-TS-Stream und transkodiert den Stream in ein neues RTMP. Sie müssen es mit x264 neu codieren, da die Videopakete beim ersten Wechsel kaputt gehen (Sie benötigen also eine bessere Qualität für Ihren ursprünglichen Stream). Sie müssen die Eingabelatenz erhöhen: Standard ist 3s für FFmpeg, aber Sie brauchen so etwas wie 8s. Sie kann gesenkt werden, aber erst nachdem Sie wirklich verstanden haben, was vor sich geht und wo Ihre Marge ist.

Die Magie ist mit FFplay.
Sie haben ein Skript ausgeführt, in dem FFmpeg den ursprünglichen RTMP-Stream liest. Wenn der Stream keine Daten mehr enthält, sendet FFplay einen Fehler und stoppt. Dann beendet das Skript die erste FFmpeg-Instanz und startet eine neue. Dieses FFmpeg ist der „Offline“-Stream. Welche Eingabe Sie auch immer möchten, Sie müssen sie in x264 MPEG-TS an den lokalen Port codieren. Und mit der gleichen fps/Größe wie Ihr normaler Stream.

Während dieser Zeit spielt der zweite FFmpeg noch seinen Eingabecache ab. Die 4 oder 5 Sekunden für den Start von „Offline“ FFmpeg sind also kein Problem.

In der eigentlichen Schleife des Skripts benötigen Sie ein neues FFplay. Wenn Ihr Stream zurück ist, wird das Offline-FFmpeg beendet und das normale neu gestartet.

Der Eingabe-Cache erledigt die Aufgabe und die Neucodierung bereinigt die beschädigten Videopakete.

Es funktioniert, aber es ist keine richtige Lösung, wie ein Overlay auf FFmpeg, und FFmpeg stoppt nicht, wenn eine Eingabe nicht reagiert/fehlt/leer ist.

Option 2 – OpenBroadcaster-Software

Wenn ich hier kein vollständiges Skript posten kann, liegt das daran, dass ich eine neue Lösung gefunden habe: Verwenden Sie OBS auf dem Server, erfassen Sie den Originalstream, legen Sie Ihr Offline-Bild dahinter und senden Sie den Stream an Ihren Verteilungsserver.

Aber es gibt einen Haken, OBS benötigt OpenGL 3.1 (2?) und einen Desktop. Sie benötigen also einen echten PC und eine echte GPU oder virtualisieren den Desktop mit ESXI (ich weiß nicht, ob VirtualBox eine virtuelle GPU kompatibel mit OpenGL 3.1 macht).

Die Logik ist die gleiche, aber freundlicher.

Die einzig gute Lösung

FFmpeg ist in der Lage, alles auf einer einzigen Instanz zu verarbeiten. Wenn Sie Overlays verwenden, können Sie die Offlineebene und den Originalstream darüber legen. FFmpeg weiß sogar, wie man einen Stream neu startet, wenn er neu veröffentlicht wird.

Aber eigentlich stoppt FFmpeg alles, wenn eine Eingabe offline / fehlt / leer ist.

Eine Option, um das Verhalten von FFmpeg auf eine Eingabe zu ändern, ist das einzige, was fehlt.

Ich habe die Dev-Mailingliste ausprobiert, keine Antwort. Dasselbe gilt für meine Vorgänger. Die Entwickler-„Community“ von FFmpeg ist nicht freundlich, basiert auf alten Tools (kritisieren Sie besser nicht die Verwendung einer Mailingliste!) und konservativ.

Wenn jemand eine bessere Lösung hat, ein magisches Programm, um einen einfachen Offline-Umschalter zu machen, wird es wirklich benötigt;)