Audio-Wellenformvideos mit FFmpeg & Node.js erstellen

Es ist kein Geheimnis, dass wir bei Transloadit Open-Source-Projekte lieben. Wir haben mehrere ambitionierte Projekte wie Uppy und tus veröffentlicht. Unsere Gründer haben sich sogar durch ihre Mitarbeit an einem Open-Source-Projekt kennengelernt. Auch hinter den Kulissen nutzen wir viele Open-Source-Tools wie FFmpeg, das den Kern unseres Video-Encodings bildet.
FFmpeg (Fast Forward MPEG) ist ein Kommandozeilenprogramm zum Transkodieren von Audio- und Videodateien. Es kann Formate konvertieren, Abtastraten und Auflösungen ändern und vieles mehr. FFmpeg bildet die Grundlage unserer Dienste für Video- und Audio-Encoding, die jeweils über mehrere Robots verfügen.
Standardmäßig konfiguriert und skaliert Transloadit FFmpeg im Hintergrund und bietet eine
leistungsfähige Abstraktion für gängige Anwendungsfälle. Sie können aber auch eigene Wege gehen.
Die Robots in diesen Kategorien stellen den Parameter
ffmpeg bereit. Damit können Sie FFmpeg direkt ansprechen und Funktionen
umsetzen, die über unsere Standardfunktionen hinausgehen.
Unser heutiges Ziel
In diesem Beitrag möchten wir kreativere Möglichkeiten zum Transkodieren mit Transloadit vorstellen. Dazu nutzen wir unseren FFmpeg-Parameter und unser Node.js SDK. Wir haben bereits Demos, die zeigen, wie Sie mit FFmpeg einen Videostream entfernen (English), eine Abtastrate ändern (English) und eigene Encoding-Voreinstellungen erstellen (English) können. Heute zeigen wir Ihnen, wie Sie eine Assembly erstellen, die Audio-Wellenformbilder erzeugt, die sich synchron zu einer eingegebenen Audiospur horizontal bewegen.
Die Anleitung dafür schreiben wir als JSON-Dokument. Dieses speichern wir zur späteren Verwendung als Template.
Erstellen wir unser Template. Öffnen Sie in Ihrem Transloadit-Konto den Bereich für Templates, klicken Sie auf „Neues Template“ und speichern Sie darin das folgende JSON.
Erstellen Sie zunächst einen Eintrag für Amazon-S3-Template-Zugangsdaten
und ersetzen Sie unten MY_S3_CREDENTIALS durch dessen gespeicherten Namen. Die
S3-Einrichtungsanleitung erläutert die erforderlichen
Bucket-Berechtigungen. Verwenden Sie einen privaten Bucket mit aktiviertem S3 Block Public Access
und geben Sie keine ACL- oder Grant-Header an. Die Einstellung bucket-default lässt
den generierten ACL-Header weg. Sie macht einen Bucket weder privat noch setzt sie dessen Richtlinie
oder angegebene ACL-/Grant-Header außer Kraft.
{
"steps": {
":original": {
"robot": "/upload/handle"
},
"waveformed": {
"robot": "/audio/waveform",
"use": ":original",
"result": true,
"width": 8000,
"height": 600,
"background_color": "ffffffff",
"outer_color": "1974c7aa",
"center_color": "1974c7aa",
"format": "image"
},
"merged": {
"robot": "/video/merge",
"use": {
"steps": [
{
"name": "waveformed",
"as": "image"
},
{
"name": ":original",
"as": "audio"
}
]
},
"result": true,
"ffmpeg_stack": "v7",
"preset": "ipad-high",
"width": "${file.meta.width}",
"height": "${file.meta.height}"
},
"encode_effect": {
"robot": "/video/encode",
"use": "merged",
"ffmpeg_stack": "v7",
"preset": "empty",
"ffmpeg": {
"vf": "crop=w=800:h=${file.meta.height}:x='(${file.meta.width}-800)*t/${file.meta.duration}':y=0",
"t": "${file.meta.duration}"
}
},
"exported": {
"use": "encode_effect",
"robot": "/s3/store",
"credentials": "MY_S3_CREDENTIALS",
"acl": "bucket-default"
}
}
}
Sehen wir uns nun die einzelnen Abläufe an. Unser erster
Step, oben ":original" genannt,
empfängt unsere Datei, die wir in diesem Fall mit dem Node.js SDK hochladen. Das ist wenig
überraschend.
In unserem zweiten Step,
"waveformed", erzeugen wir unser Wellenformbild. Wir können Optionen wie
background_color und outer_color (Außenfarbe der Wellenform)
festlegen. Wir halten es einfach und verwenden einen weißen Hintergrund mit blauer Wellenform.
Bei diesem Step fällt Ihnen vielleicht auf, dass wir
width für die erzeugte Wellenform viel größer als üblich eingestellt haben.
Darauf gehen wir weiter unten genauer ein. Entscheidend ist, dass die Scrollbewegung mit zunehmender
Breite flüssiger wird.
Weiter geht es mit unserem dritten Step,
"merged". Wie der Name des Steps
andeutet, führen wir die neu erzeugten Wellenformbilder und unsere ursprüngliche Audio-Eingabedatei
zu einer neuen mp4-Videodatei zusammen. Verwenden Sie im Parameter die Namenskonvention
"name", "as"; der Parameter heißt
use. Anschließend verwenden wir
Assembly Variables, um die Parameterwerte für
width und height auf dieselben Abmessungen wie bei
unserem Eingabebild zu setzen.
Jetzt kommt der spannende Teil. Bei "encode_effect" handelt es sich um unseren
Step, in dem es etwas ungewöhnlich wird.
Hier leiten wir unsere vollständig zusammengeführte Wellenform-Videodatei an den
Robot /video/encode weiter.
Mit dem FFmpeg-Parameter können wir das Kommandozeilenprogramm FFmpeg direkt ansprechen. Wir
verwenden das Flag "vf", um unseren Videoeffekt zu erzeugen. Sehen wir
uns das genauer an!
"crop=w=800:h=${file.meta.height}:x='(${file.meta.width}-800)*t/${file.meta.duration}':y=0"
Wir verwenden hier den Filter crop, um die Größe unseres Endergebnisses
anzupassen. Bei waveformed haben wir im
Step die Gesamtbreite auf 8000 gesetzt. Beim Scrollen
möchten wir nur 10 % des gesamten Bildes zeigen. Deshalb geben wir als Zielbreite
800 ein. Wieder verwenden wir eine der
Assembly Variables, um die Zielhöhe auf die Höhe der Eingabedatei
zu setzen. Da wir uns nur von links nach rechts bewegen, setzen wir y
auf 0. Für x steuert unser Ausdruck die
horizontale Position des Bildausschnitts und lässt unser Video am linken Bildrand beginnen. Mit
t berechnen wir, wie lange es dauert, bis der Bildausschnitt den
gegenüberliegenden Bildrand erreicht. Dieser Wert ist für jede Audiodatei anders, die wir unserer
Assembly übergeben. Deshalb verwenden wir erneut eine
Assembly Variable, um stets den richtigen Zeitwert aus den
Metadaten unserer Eingabedatei zu erhalten.
Das ist aber nicht das einzige Flag in unserem FFmpeg-Parameter. Zusätzlich verwenden wir das Flag
t. Es legt lediglich die Länge der Ergebnisdatei fest. Dafür verwenden
wir denselben Wert wie oben beim Flag vf.
Zum Schluss exportieren wir unser Ergebnis mit dem Robot /s3/store. Damit sind wir fertig!
Erste Schritte
Jetzt haben wir unser Template und können die SDK-Integration einrichten. Für diese Demonstration haben wir Node.js gewählt. Das Beispiel lässt sich aber leicht auf unsere anderen verfügbaren SDKs übertragen. Bevor wir beginnen, müssen wir das Node.js SDK von Transloadit installieren. Initialisieren Sie npm in Ihrem Projektordner und führen Sie anschließend den folgenden Befehl aus.
npm i transloadit@4 --save
Verwenden Sie Node.js 20 oder neuer und speichern Sie das vollständige Programm als
waveform-video.mjs, damit Node es als ES-Modul lädt. Führen Sie es mit
node waveform-video.mjs aus, nachdem Sie die unten genannten Zugangsdaten gesetzt haben.
Im Folgenden haben wir unseren Code in mehrere Codefragmente aufgeteilt. Damit Sie nicht jedes Codefragment einzeln kopieren müssen, finden Sie am Ende eine vollständige Version zum Kopieren und Einfügen.
Zunächst importieren wir die Transloadit-Bibliothek.
import { Transloadit } from 'transloadit'
Als Nächstes richten wir unseren Transloadit-Client ein. Setzen Sie TRANSLOADIT_AUTH_KEY
und TRANSLOADIT_SECRET_KEY in Ihrer Serverumgebung mit dem Auth Key und dem Auth Secret
Ihres Workspaces. Das sind keine Template-Zugangsdaten für die Speicherung. Führen Sie diesen Code
auf Ihrem eigenen Computer oder einem vertrauenswürdigen Server aus, niemals in einem Browser.
const transloadit = new Transloadit({
authKey: process.env.TRANSLOADIT_AUTH_KEY,
authSecret: process.env.TRANSLOADIT_SECRET_KEY,
})
Nun legen wir die Audiodatei fest, die wir in unserer
Assembly verwenden möchten. Legen Sie die gewünschte
Audiodatei im Arbeitsverzeichnis ab und deklarieren Sie sowohl eine Variable
filePath als auch eine Variable fieldName.
Wir übergeben beide an createAssembly in dessen Option
files.
const filePath = './joakim_karud-rock_angel.mp3'
const fieldName = 'my_file'
Anschließend erstellen wir unsere Assembly mit der
gespeicherten Template ID. Das SDK gibt ein Promise zurück; waitForCompletion wartet
auf die Verarbeitung, nicht nur auf den Upload. Der folgende Ausschnitt gehört in eine asynchrone
Funktion, wie im vollständigen Programm unten gezeigt.
const opts = {
files: { [fieldName]: filePath },
waitForCompletion: true,
params: {
template_id: 'YOUR_TEMPLATE_ID',
},
}
const result = await transloadit.createAssembly(opts)
console.log(result)
Jetzt ist unser Code vollständig und wir können das Programm ausführen. Hier noch einmal das gesamte Programm:
import { Transloadit } from 'transloadit'
async function main() {
const transloadit = new Transloadit({
authKey: process.env.TRANSLOADIT_AUTH_KEY,
authSecret: process.env.TRANSLOADIT_SECRET_KEY,
})
const filePath = './joakim_karud-rock_angel.mp3'
const fieldName = 'my_file'
const result = await transloadit.createAssembly({
files: { [fieldName]: filePath },
waitForCompletion: true,
params: { template_id: 'YOUR_TEMPLATE_ID' },
})
console.log(result)
}
main().catch(() => {
console.error('Waveform video generation failed.')
process.exitCode = 1
})
Als Audiodatei haben wir den Titel „Joakim karud-rock angel“ gewählt, den wir bereits häufig in unseren Demos (English) verwendet haben. Wenn Sie dieselbe Datei nutzen möchten, finden Sie sie im unten verlinkten GitHub-Repository.
Sobald unser Programm vollständig durchgelaufen ist, können wir uns bei S3 anmelden und unser Endergebnis ansehen.
Wie Sie sehen, hat alles wie geplant funktioniert. Jetzt wird es aber noch interessanter: Mit FFmpeg sind die Möglichkeiten Ihrer Assemblies nahezu unbegrenzt. Probieren Sie doch, die Wellenform vertikal zu scrollen oder das Video so zu transkodieren, dass es rückwärts abgespielt wird.
Oder verwenden Sie den Parameter ffmpeg, um
völlig unterschiedliche
Filter anzuwenden.
Wir hoffen, dieser Beitrag hat Ihnen gezeigt, wie vielseitig die Transloadit API sein kann und wie
nützlich der Parameter ffmpeg bei der Umsetzung kreativer Projekte sein
kann, die Spaß machen.
Wenn Sie Dateien aus diesem Projekt herunterladen möchten, besuchen Sie das folgende GitHub-Repository!