Audio mit cURL und Open-Source-Tools codieren
Laden Sie Audio mit cURL herunter und codieren Sie es mit FFmpeg. Diese Anleitung erstellt aus einer echten MP3-Beispieldatei eine lokale M4A-Datei. Anschließend wird daraus ein Bash-Skript für Ausgaben in AAC, M4A, MP3 oder Opus. Das Hochladen des Ergebnisses erfordert einen Empfänger mit eigenen API-Vorgaben und ist nicht Teil dieses Beispiels.
Umgebung einrichten
Verwenden Sie Linux mit Bash, cURL, FFmpeg und ffprobe in Ihrem PATH.
Der FFmpeg-Build benötigt die Encoder aac,
libmp3lame und libopus. Installieren Sie gepflegte Pakete
für Ihre Distribution; die Download-Seite von FFmpeg verlinkt
Paketquellen. Die Beispiele wurden mit Bash 5.3.15, cURL 8.22.0 und FFmpeg/ffprobe 9.0.1 getestet
und zur Kompatibilitätsprüfung separat mit FFmpeg/ffprobe 6.1.1 erneut ausgeführt. Dies sind
getestete Versionen, keine Empfehlung, eine alte Patch-Version zu installieren.
Prüfen Sie die installierten Tools und Encoder:
bash --version &&
curl --version &&
ffmpeg -version &&
ffprobe -version &&
ffmpeg -hide_banner -encoders
Beginnen Sie mit einer vollständigen, unverschlüsselten Mono- oder Stereoaufnahme mit 44,1 oder 48 kHz. Die Beispiele decken MP3- und PCM-WAV-Eingaben ab, einschließlich Samples mit Ganzzahl- und Gleitkommawerten. Sie legen weder eine Zuordnung für Surround-Kanäle noch eine Abtastrate fest; FFmpeg kann bei Bedarf für den Ausgabecodec ein Resampling durchführen. Verwenden Sie Audio, für dessen Verarbeitung Sie eine Berechtigung haben.
Grundlegendes Audio-Encoding mit FFmpeg und cURL
Fügen Sie diesen Block in Bash ein, und zwar in einem Verzeichnis, in dem
audio-example noch nicht existiert. Er lädt viper.mp3 aus dem
Web-Audio-Beispiel von MDN herunter und codiert anschließend den
ersten Audiostream als AAC in einem M4A-Container. Die festgelegte Beispieldatei enthält etwa
41 Sekunden Stereo-Audio mit 44,1 kHz.
(
set -euo pipefail
mkdir -- audio-example || exit 1
trap 'status=$?; if [ "$status" -ne 0 ]; then
rm -f -- audio-example/input.mp3 audio-example/output.m4a audio-example/ffmpeg-errors.log
rmdir -- audio-example 2>/dev/null || true
fi' EXIT
curl -fsSL --retry 3 --connect-timeout 10 --max-time 60 \
--proto '=https' --proto-redir '=https' \
-o audio-example/input.mp3 \
https://raw.githubusercontent.com/mdn/webaudio-examples/5af6b7a1545ad572c2dd2ce0443eeb26ab7c3e61/audio-analyser/viper.mp3 || exit 1
if ! ffmpeg -nostdin -v error -n -xerror -i audio-example/input.mp3 -map 0:a:0 \
-c:a aac -b:a 192k -f ipod audio-example/output.m4a \
2>audio-example/ffmpeg-errors.log || [ -s audio-example/ffmpeg-errors.log ]; then
cat -- audio-example/ffmpeg-errors.log >&2
exit 1
fi
rm -f -- audio-example/ffmpeg-errors.log
)
Bei Erfolg enthält audio-example die heruntergeladene MP3-Datei und
output.m4a. Schlägt der Download oder das Encoding fehl, werden die Dateien
dieses Versuchs entfernt. Existiert das Verzeichnis bereits, stoppt der Block, bevor er etwas
schreibt. Die Klammern begrenzen die Shell-Optionen auf eine Subshell, sodass das Einfügen Ihre
aktuelle Shell nicht verändert. Führen Sie dieses Beispiel nacheinander in einem Verzeichnis
aus, das Sie kontrollieren.
Die Option -map 0:a:0 wählt den ersten
Audiostream aus. -n verhindert das Ersetzen einer vorhandenen Ausgabe,
und -nostdin deaktiviert interaktive Eingaben. Die Bitrate ist ein Zielwert
für den Encoder, keine Garantie für Dateigröße oder wahrgenommene Qualität. Erneutes Codieren
einer MP3-Datei kann Details, die bei der ursprünglichen Kompression verloren gingen, nicht
wiederherstellen.
Ein Skript zum Audio-Encoding erstellen
Speichern Sie den folgenden Code als encode_audio.sh im aktuellen Verzeichnis.
Das Formatargument wählt sowohl einen Encoder als auch einen Container aus. Nur die Dateiendung
zu ändern, konvertiert kein Audio. Die
Formatdokumentation von FFmpeg beschreibt diese Muxer.
| Argument | Audiocodec | Container | Ausgabedatei |
|---|---|---|---|
aac | AAC | ADTS | output.aac |
m4a | AAC | MPEG-4-Audio | output.m4a |
mp3 | MP3 mit libmp3lame | MP3 | output.mp3 |
opus | Opus mit libopus | Ogg | output.opus |
#!/bin/bash
set -euo pipefail
if [ "$#" -ne 3 ]; then
echo "Usage: $0 <input_url> <output_format> <output_bitrate>" >&2
exit 1
fi
INPUT_URL=$1
OUTPUT_FORMAT=$2
BITRATE=$3
case "$OUTPUT_FORMAT" in
aac) CODEC=aac; CONTAINER=adts ;;
m4a) CODEC=aac; CONTAINER=ipod ;;
mp3) CODEC=libmp3lame; CONTAINER=mp3 ;;
opus) CODEC=libopus; CONTAINER=ogg ;;
*) echo "Unsupported output format: $OUTPUT_FORMAT" >&2; exit 1 ;;
esac
if [[ ! "$BITRATE" =~ ^[1-9][0-9]*k$ ]]; then
echo "Bitrate must be a positive integer followed by k, such as 192k" >&2
exit 1
fi
WORK_DIR=$(mktemp -d ./audio-encode.XXXXXX)
INPUT_FILE="$WORK_DIR/input.audio"
OUTPUT_FILE="$WORK_DIR/output.$OUTPUT_FORMAT"
ERROR_LOG="$WORK_DIR/ffmpeg-errors.log"
# Delete the download; retain the output only after successful encoding.
trap 'status=$?; rm -f -- "$INPUT_FILE" "$ERROR_LOG";
if [ "$status" -ne 0 ]; then rm -f -- "$OUTPUT_FILE"; fi
rmdir -- "$WORK_DIR" 2>/dev/null || true' EXIT
echo "Downloading input file…"
if ! curl -fsSL --retry 3 --connect-timeout 10 --max-time 60 \
--proto '=http,https' --proto-redir '=http,https' \
-o "$INPUT_FILE" -- "$INPUT_URL"; then
echo "Error: Failed to download input file" >&2
exit 1
fi
echo "Encoding to ${OUTPUT_FORMAT} format…"
if ! ffmpeg -nostdin -v error -n -xerror -i "$INPUT_FILE" -map 0:a:0 -vn \
-c:a "$CODEC" -b:a "$BITRATE" -f "$CONTAINER" "$OUTPUT_FILE" \
2>"$ERROR_LOG" || [ -s "$ERROR_LOG" ]; then
cat -- "$ERROR_LOG" >&2
echo "Error: Failed to encode audio" >&2
exit 1
fi
echo "Successfully encoded to: ${OUTPUT_FILE}"
Führen Sie das gespeicherte Skript mit Bash aus; es benötigt keine Ausführungsberechtigung:
bash ./encode_audio.sh \
https://raw.githubusercontent.com/mdn/webaudio-examples/5af6b7a1545ad572c2dd2ce0443eeb26ab7c3e61/audio-analyser/viper.mp3 \
opus 128k
Bei Erfolg wird ein Pfad wie ./audio-encode.A1b2C3/output.opus ausgegeben. Jeder Aufruf erstellt ein
neues Arbeitsverzeichnis, sodass frühere Ergebnisse bei erneutem Aufruf mit derselben URL erhalten
bleiben. Das Skript entfernt die heruntergeladene Datei. Bei einem Download- oder Encoding-Fehler
entfernt es außerdem unvollständige Ausgaben und das leere Arbeitsverzeichnis. Argumentfehler
treten auf, bevor Dateien erstellt werden. Diese Bereinigung deckt gewöhnliche Befehlsfehler ab;
bei einem erzwungenen Prozessabbruch oder Herunterfahren des Rechners können temporäre Dateien
zurückbleiben.
128k bedeutet einen Zielwert von 128.000 Bit pro Sekunde. Das Skript prüft
die Schreibweise des Arguments; ob die Bitrate unterstützt wird, entscheidet weiterhin der
gewählte Encoder. Der Download wird vor dem Encoding abgeschlossen, sodass FFmpeg innerhalb der
Eingabedatei zu anderen Zeitpositionen springen kann.
Audiodateien im Batch verarbeiten
Speichern Sie dies als batch_encode.sh neben encode_audio.sh. Führen
Sie es aus diesem Verzeichnis aus. Jede Zeile der Eingabeliste enthält eine URL, ein Format und
eine Bitrate, jeweils durch Leerzeichen getrennt. Leere Zeilen werden übersprungen. Verwenden Sie
für Leerzeichen innerhalb von URLs die Prozentkodierung. Kommentare und zusätzliche Felder werden
nicht unterstützt.
#!/bin/bash
set -euo pipefail
if [ "$#" -ne 1 ]; then
echo "Usage: $0 <input_file_list.txt>" >&2
echo "File list format: <input_url> <output_format> <bitrate>" >&2
exit 1
fi
INPUT_LIST=$1
failed=0
while IFS=' ' read -r url format bitrate extra || [[ -n "$url" ]]; do
[[ -z "$url" ]] && continue
echo "Processing: ${url}"
if [[ -n "$extra" || -z "$format" || -z "$bitrate" ]]; then
echo "Invalid list entry: $url" >&2
failed=1
elif bash ./encode_audio.sh "$url" "$format" "$bitrate"; then
echo "Success: ${url}"
else
echo "Failed: ${url}" >&2
failed=1
fi
done < "${INPUT_LIST}"
exit "$failed"
Speichern Sie zum Beispiel diese zwei Zeilen als audio-list.txt:
https://raw.githubusercontent.com/mdn/webaudio-examples/5af6b7a1545ad572c2dd2ce0443eeb26ab7c3e61/audio-analyser/viper.mp3 m4a 192k
https://raw.githubusercontent.com/mdn/webaudio-examples/5af6b7a1545ad572c2dd2ce0443eeb26ab7c3e61/audio-analyser/viper.mp3 mp3 128k
bash ./batch_encode.sh audio-list.txt
Die Batch-Verarbeitung läuft sequenziell und behält erfolgreiche Ausgaben auch dann bei, wenn eine andere Zeile fehlschlägt. Sie setzt die Verarbeitung nach ungültigen Einträgen, fehlgeschlagenen Downloads und fehlgeschlagenem Encoding fort. Ist ein Auftrag fehlgeschlagen, endet sie mit Status 1. Status 0 bedeutet, dass jede verarbeitete Zeile erfolgreich war; bei einer leeren Liste wird nichts verarbeitet.
Sicherheitsaspekte
Verwenden Sie HTTPS-URLs aus vertrauenswürdigen Quellen. cURL
prüft Serverzertifikate standardmäßig. Fügen Sie nicht
-k hinzu, um diese Prüfung zu umgehen. Die
Einschränkungen --proto und --proto-redir
des Skripts erlauben nur HTTP und HTTPS, auch bei Weiterleitungen. HTTP bleibt für einen lokalen
Testserver verfügbar, bietet aber keine Transportverschlüsselung.
Diese Skripte sind Beispiele für lokale Konvertierungen. Sie führen FFmpeg nicht in einer Sandbox aus, begrenzen die Downloadgröße nicht und machen den serverseitigen Abruf beliebiger URLs aus Benutzereingaben nicht sicher. Die cURL-Zeitlimits begrenzen jeden Übertragungsversuch; Retries können die Gesamtdauer des Downloads verlängern. Halten Sie genügend Speicherplatz für die vollständige Eingabe und Ausgabe frei.
Fehlerbehandlung und Validierung
Prüfen Sie die tatsächliche Ausgabe des grundlegenden Beispiels mit diesem Block. Führen Sie ihn im selben Verzeichnis aus, in dem Sie das Beispiel ausgeführt haben:
(
set -euo pipefail
VERIFY_LOG=$(mktemp ./audio-verify.XXXXXX)
trap 'rm -f -- "$VERIFY_LOG"' EXIT
ffprobe -v error -select_streams a:0 \
-show_entries stream=codec_name,sample_rate,channels:format=format_name,duration \
-of json audio-example/output.m4a || exit 1
if ! ffmpeg -nostdin -v error -xerror -i audio-example/output.m4a \
-map 0:a:0 -f null - 2>"$VERIFY_LOG" || [ -s "$VERIFY_LOG" ]; then
cat -- "$VERIFY_LOG" >&2
exit 1
fi
)
Erwartet werden codec_name mit dem Wert aac, zwei
Kanäle und eine Dauer von ungefähr 41 Sekunden. ffprobe meldet den M4A-Container als Teil der
Formatfamilie mov,mp4,m4a,3gp,3g2,mj2. Der zweite Befehl decodiert die gesamte Ausgabe, ohne
eine weitere Datei zu speichern. Ersetzen Sie für ein Skriptergebnis den Pfad in beiden Befehlen
durch den exakten Pfad, den der betreffende Aufruf ausgegeben hat. Rohes ADTS-AAC enthält
Encoder-Verzögerung und Padding; ffprobe schätzt seine Dauer möglicherweise anhand der Bitrate.
Vergleichen Sie das decodierte Audio mit der Zeitleiste der Quelle, statt diese Schätzung als
exakte Länge zu behandeln.
-xerror weist FFmpeg an, bei Fehlern
anzuhalten. FFmpeg 6.1.1 kann einen spät auftretenden Decoderfehler melden und dennoch Status 0
zurückgeben. Daher erfassen die Blöcke zusätzlich stderr auf der Protokollierungsstufe
error und werten ein nicht leeres Fehlerprotokoll als Fehler. Die
Diagnosemeldung wird vor der Bereinigung ausgegeben. Dies erkennt gemeldete Fehler, ist aber kein
Integritätsnachweis: Eine Aufnahme, die an einer decodierbaren Grenze abgeschnitten wurde, kann
weiterhin erfolgreich codiert oder decodiert werden. Einige beschädigte Pakete können zudem
unbemerkt verworfen werden. Vergleichen Sie die Dauer mit einer bekanntermaßen vollständigen
Quelle und hören Sie die Aufnahme bis zum Ende an. Verwenden Sie eine vertrauenswürdige Prüfsumme
des Herausgebers, sofern verfügbar. Eine vorhandene Datei, ein lesbarer Header und ein Exit-Status
von null belegen nicht, dass alle erwarteten Audiodaten angekommen sind.
Ein cURL-HTTP-Fehler wie 404 stoppt den Download vor dem Encoding. Ein nicht verfügbarer Encoder, eine Datei ohne Audiostream oder eine vom Encoder abgelehnte Bitrate stoppt die Konvertierung. Bewahren Sie bei der Fehleranalyse die Diagnosemeldung auf stderr auf. Endet die Batch-Verarbeitung mit Status 1, identifizieren Sie die Fehler anhand der Meldungen pro Zeile. Bereits abgeschlossene Ausgaben bleiben verfügbar.
Fazit
Für einen gehosteten Encoding-Workflow lesen Sie die Dokumentation zum Robot 🤖 /audio/encode. Seine Vorgaben für Upload und Authentifizierung sind unabhängig von diesem lokalen Download mit cURL und der Konvertierung mit FFmpeg.
