Remote-Medien mit cURL an FFmpeg streamen
Leiten Sie einen HTTP-Download von cURL per Pipe an FFmpeg, um Thumbnails und Audio zu extrahieren, ohne eine lokale Kopie des Eingabevideos zu speichern. Die MP4-Datei muss sequenzielles Lesen unterstützen. Diese Anleitung erstellt einen definierten Testclip, stellt ihn über HTTP bereit und verarbeitet die Antwort zu JPEGs und einer WAV-Datei.
Überblick
Verwenden Sie Bash unter Linux, cURL, Python 3 und einen FFmpeg-Build mit den Encodern
libx264 und AAC. Die folgenden Befehle wurden mit FFmpeg 6.1.1 und 9.0.1 getestet.
Python stellt den lokalen HTTP-Server bereit und ist unnötig, wenn Sie bereits eine geeignete
Remote-URL haben.
Das Beispiel erstellt eine „faststart“-MP4-Datei, deren Metadaten
moov vor den Mediendaten liegen. Die
MP4-Dokumentation von FFmpeg erläutert diese Anordnung.
Eine Pipe kann nicht rückwärts positionieren. Daher kann eine gewöhnliche MP4-Datei mit Metadaten
am Ende scheitern, selbst nachdem cURL die gesamte Datei gesendet hat. Ist die Anordnung unbekannt,
verwenden Sie das folgende Beispiel mit vorherigem Download. Die Angabe
-f mp4 kennzeichnet das Format; sie ermöglicht keine freie Positionierung in
der Eingabe.
Führen Sie jeden Block in Bash aus demselben übergeordneten Verzeichnis aus. Die Klammern begrenzen Änderungen an Shell-Optionen auf eine Subshell. Jeder Verarbeitungsblock erfordert ein neues Ausgabeverzeichnis und verweigert eine erneute Ausführung mit einem vorhandenen Verzeichnis. Fehlgeschlagene Ausführungen können unvollständige Dateien im neuen Verzeichnis hinterlassen. Prüfen Sie diese vor der Verwendung und wählen Sie für einen weiteren Versuch ein neues Verzeichnis.
Pipeline einrichten
Clip und HTTP-Ursprung vorbereiten
Erstellen Sie einen 6,4 Sekunden langen Clip: zwei Sekunden Rot, zwei Sekunden Limettengrün, dann Blau. Seine Audiospur bleibt bis zu einem kurzen 880-Hz-Ton in den letzten 0,2 Sekunden stumm. So wird eine unvollständige Audioextraktion hörbar.
(
set -euo pipefail
mkdir curl-media-demo
ffmpeg -nostdin -n -hide_banner -loglevel warning -filter_threads 1 \
-f lavfi -i "color=c=red:s=160x90:r=10:d=6.4" \
-f lavfi -i "aevalsrc='if(gte(t,6.2),0.25*sin(2*PI*880*t),0)':s=48000:d=6.4" \
-vf "drawbox=c=lime:t=fill:enable='gte(t,2)',drawbox=c=blue:t=fill:enable='gte(t,4)'" \
-map 0:v:0 -map 1:a:0 -c:v libx264 -pix_fmt yuv420p -threads 1 \
-c:a aac -movflags +faststart curl-media-demo/input.mp4
)
Stellen Sie in diesem Terminal nur das Fixtures-Verzeichnis über die Loopback-Adresse bereit:
(
set -eu
test -f curl-media-demo/input.mp4
python3 -m http.server 8765 --bind 127.0.0.1 --directory curl-media-demo
)
Lassen Sie den Server laufen und verwenden Sie für die nächsten Blöcke ein zweites Terminal. Falls Port 8765 belegt ist, wählen Sie einen verfügbaren Port und ändern Sie ihn sowohl im Serverbefehl als auch in den URLs. Beenden Sie den Server anschließend mit Strg+C.
Thumbnails und Audio aus einem einzigen Download extrahieren
Wechseln Sie im zweiten Terminal zurück in dasselbe übergeordnete Verzeichnis und führen Sie Folgendes aus:
(
set -euo pipefail
mkdir outputs
curl -fsSL "http://127.0.0.1:8765/input.mp4" | \
ffmpeg -nostdin -n -hide_banner -loglevel warning -filter_threads 1 -i pipe:0 \
-map 0:v:0 -vf "fps=1" -c:v mjpeg -q:v 2 -threads 1 -frame_pts 1 \
outputs/thumbnail_%03d.jpg \
-map 0:a:0 -c:a pcm_s16le outputs/audio.wav
)
Für diese Fixtures sind sechs JPEGs mit 160×90 zu erwarten, benannt von
thumbnail_000.jpg bis thumbnail_005.jpg.
Die ersten beiden sind rot, die nächsten beiden limettengrün und die letzten beiden blau.
Spielen Sie outputs/audio.wav ab: Die 6,4 Sekunden lange Aufnahme sollte bis zum Ton
kurz vor ihrem Ende stumm bleiben. Beim Decodieren von AAC kann am Ende der WAV-Datei ein kleiner
zusätzlicher Füllbereich entstehen.
Erläuterung
pipe:0 liest die Standardeingabe. Explizite Optionen
-map wählen den ersten Video- und Audiostream mit jeweils einer Ausgabe.
Bei einem Video ohne Audio schlägt die erforderliche Audiozuordnung fehl, statt die WAV-Datei
stillschweigend wegzulassen. Die Prüfung auf ein neues Verzeichnis schützt die Bildsequenz vor
vorherigen Ausführungen. Die Option -n von FFmpeg schützt MP4- und
WAV-Dateinamen; eine image2-Sequenz kann einzelne JPEGs ersetzen. Behalten Sie die
Verzeichnisprüfung bei und führen Sie diese Beispiele nacheinander aus.
Der fps-Filter verwirft oder dupliziert Frames, um einen Frame
pro Sekunde zu erzeugen. Seine Standardrundung ergibt für diese Fixtures sechs Frames, sodass der
letzte Sekundenbruchteil kein eigenes Thumbnail erhält. -frame_pts 1 verwendet
Präsentationszeitstempel der Ausgabe als Dateinummern in der Ausgabezeitbasis. Hier beträgt diese
Basis eine Sekunde, die Nummern stehen also für Ausgabezeiten von 0–5 Sekunden. Sie sind weder
ursprüngliche Framenummern noch eine Garantie dafür, welcher Quellframe genau ausgewählt wird.
Siehe die image2-Optionen.
Mit -f lässt cURL die Übertragung bei einem HTTP-Fehler wie 404
fehlschlagen, während -sS die Fortschrittsanzeige ausblendet und
Fehlermeldungen beibehält. Die Bash-Option pipefail reicht einen
fehlgeschlagenen Download weiter, selbst wenn FFmpeg erfolgreich endet. Keine dieser Optionen
belegt, dass der Server unbeschädigte Medien gesendet hat.
Erweiterte Anwendungen
Szenenwechsel auswählen und ihre Zeiten erfassen
Um Farbwechsel statt einer festen Rate abzutasten, starten Sie einen separaten Download in ein neues Verzeichnis:
(
set -euo pipefail
mkdir scenes
curl -fsSL "http://127.0.0.1:8765/input.mp4" | \
ffmpeg -nostdin -n -hide_banner -loglevel warning -filter_threads 1 -i pipe:0 \
-map 0:v:0 \
-vf "select='gt(scene,0.3)',metadata=print:key=lavfi.scene_score:file=scenes/time.txt" \
-fps_mode vfr -c:v mjpeg -q:v 2 -threads 1 scenes/scene_%03d.jpg
)
Bei diesem Clip sollte scene_001.jpg limettengrün und
scene_002.jpg blau sein. Die zugehörigen Einträge
pts_time in scenes/time.txt betragen 2 und 4 Sekunden.
Dies sind die Zeitstempel der ausgewählten Frames auf der Eingabezeitleiste von FFmpeg, die für
diese Fixtures bei null beginnt. Es sind keine Aufnahmezeiten nach der Uhrzeit, und die
fortlaufenden JPEG-Nummern sind keine Zeitstempel.
Der select-Filter vergleicht einen Szenenwert mit dem Schwellenwert.
Ein Wert über 0,3 ist eine Heuristik für eine visuelle Änderung, keine semantische Szenengrenze.
Bei einem Clip werden möglicherweise keine Frames ausgewählt. -fps_mode vfr
verhindert, dass Lücken zwischen ausgewählten Frames mit Duplikaten gefüllt werden.
Fehlerbehebung
Wenn die Pipe eine unvollständige Datei meldet oder keine nutzbaren Pakete findet, erfordert die MP4-Datei möglicherweise freie Positionierung. Laden Sie sie in ein neues Verzeichnis herunter und verarbeiten Sie dann die tatsächlich heruntergeladene Datei. So lassen sich auch Netzwerkfehler von Fehlern beim Decodieren trennen:
(
set -euo pipefail
mkdir download
curl -fsSL --retry 3 "http://127.0.0.1:8765/input.mp4" -o download/input.mp4
ffmpeg -nostdin -n -hide_banner -loglevel warning -filter_threads 1 -i download/input.mp4 \
-map 0:v:0 -vf "fps=1" -c:v mjpeg -q:v 2 -threads 1 -frame_pts 1 \
download/thumbnail_%03d.jpg \
-map 0:a:0 -c:a pcm_s16le download/audio.wav
)
Mit der Test-URL entstehen dieselben Thumbnails und Audiodaten wie mit der Pipe. Verwenden Sie
cURL-Retries mit -o für einen Dateidownload statt mit einer Decoder-Pipe.
cURL kann Bytes, die bereits in eine Pipe geschrieben wurden, vor einem erneuten Versuch nicht
zurücksetzen. Die Dokumentation zu Retries beschreibt diesen
Unterschied. Der Block stoppt vor dem Decodieren, wenn der Download fehlschlägt.
Eine HTTP-200-Antwort und ein Exit-Status von null belegen noch keine vollständigen Medien. FFmpeg kann Schäden beim Decodieren melden und dennoch null zurückgeben oder beschädigte Frames und Samples wiederherstellen. Lesen Sie die Warnungen, vergleichen Sie Anzahl und Farben der Thumbnails mit den Erwartungen und prüfen Sie die Audiodauer sowie den abschließenden Ton. Verwenden Sie bei eigenen Medien bekannte Erwartungen zu Dauer und Inhalt oder eine vertrauenswürdige Prüfsumme des Herausgebers; diese Beispiele führen keine Integritätsprüfung durch. Ein vorheriger Download löst das Problem der freien Positionierung, nicht das beschädigter Daten.
Hinweise zur Leistung
Die Pipe vermeidet das Speichern der Eingabe-MP4-Datei, doch JPEGs und die unkomprimierte WAV-Datei belegen weiterhin Speicherplatz auf dem Datenträger. FFmpeg verarbeitet Daten, sobald sie eintreffen. Netzwerkgeschwindigkeit und Decodiergeschwindigkeit bestimmen, wie schnell das geschieht. Dies ist ein HTTP-Dateidownload, keine Garantie für Echtzeit- oder Livestream-Verhalten. Eine geringere Thumbnail-Rate reduziert die Anzahl gespeicherter Bilder, während die Szenenerkennung weiterhin decodierte Frames untersucht.
Prüfen Sie für einen anderen Eingabecontainer die Dokumentation zum Pipe-Protokoll von FFmpeg und ob der Demuxer ihn sequenziell verarbeiten kann. Halten Sie den Weg über einen vorherigen Download offen, wenn Sie die Anordnung der MP4-Daten nicht steuern können.
