Encoder de l’audio avec cURL et des outils open source
Utilisez cURL pour télécharger l’audio et FFmpeg pour l’encoder. Ce guide produit un fichier M4A local à partir d’un véritable échantillon MP3, puis transforme ce flux de travail en script Bash pour une sortie AAC, M4A, MP3 ou Opus. L’envoi du résultat nécessite un destinataire doté de son propre contrat d’API et sort du cadre de cet exemple.
Configurer votre environnement
Utilisez Linux avec Bash, cURL, FFmpeg et ffprobe dans votre PATH. La compilation de FFmpeg doit inclure les encodeurs aac,
libmp3lame et libopus. Installez les paquets maintenus de votre distribution ;
la page de téléchargement de FFmpeg renvoie vers des fournisseurs de paquets.
Les exemples ont été testés avec Bash 5.3.15, cURL 8.22.0 et FFmpeg/ffprobe 9.0.1, avec une
réexécution de compatibilité distincte sous FFmpeg/ffprobe 6.1.1. Il s’agit de versions testées,
et non d’une recommandation d’installer une ancienne version corrective.
Vérifiez les outils et les encodeurs installés :
bash --version &&
curl --version &&
ffmpeg -version &&
ffprobe -version &&
ffmpeg -hide_banner -encoders
Commencez par un enregistrement mono ou stéréo complet et non chiffré à 44,1 ou 48 kHz. Les exemples couvrent les entrées MP3 et WAV PCM, y compris les échantillons entiers et à virgule flottante. Ils ne définissent pas de mappage de canaux surround et n’imposent pas de fréquence d’échantillonnage ; FFmpeg peut rééchantillonner si le codec de sortie l’exige. Utilisez de l’audio que vous avez l’autorisation de traiter.
Encodage audio de base avec FFmpeg et cURL
Collez ceci dans Bash depuis un répertoire où audio-example n’existe pas encore. Le bloc télécharge
viper.mp3 depuis l’exemple Web Audio de MDN,
puis encode son premier flux audio en AAC dans un conteneur M4A. L’échantillon épinglé contient
environ 41 secondes d’audio stéréo à 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
)
En cas de réussite, audio-example contient le MP3 téléchargé et output.m4a. Un échec du téléchargement ou
de l’encodage supprime les fichiers de cette tentative. Si le répertoire existe déjà, le bloc
s’arrête avant d’écrire quoi que ce soit. Les parenthèses confinent les options du shell dans un
sous-shell : le coller ne modifie donc pas votre shell de travail. Exécutez cet exemple de manière
séquentielle dans un répertoire que vous contrôlez.
L’option -map 0:a:0 sélectionne le premier flux
audio, tandis que -n refuse de remplacer une sortie existante et -nostdin désactive la saisie interactive.
Le débit binaire est une cible pour l’encodeur, et non une garantie de taille de fichier ou de
qualité perçue. Réencoder un MP3 ne peut pas restaurer les détails déjà perdus lors de sa
compression d’origine.
Créer un script d’encodage audio
Enregistrez ce qui suit sous encode_audio.sh dans votre répertoire courant. L’argument de format choisit
à la fois un encodeur et un conteneur ; modifier uniquement l’extension d’un nom de fichier ne
convertit pas l’audio.
La documentation des formats FFmpeg décrit ces multiplexeurs.
| Argument | Codec audio | Conteneur | Fichier de sortie |
|---|---|---|---|
aac | AAC | ADTS | output.aac |
m4a | AAC | Audio MPEG-4 | output.m4a |
mp3 | MP3 via libmp3lame | MP3 | output.mp3 |
opus | Opus via 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}"
Exécutez le script enregistré avec Bash ; il n’a pas besoin de permissions d’exécution :
bash ./encode_audio.sh \
https://raw.githubusercontent.com/mdn/webaudio-examples/5af6b7a1545ad572c2dd2ce0443eeb26ab7c3e61/audio-analyser/viper.mp3 \
opus 128k
En cas de réussite, le script affiche un chemin tel que ./audio-encode.A1b2C3/output.opus. Chaque appel crée un nouveau
répertoire de travail : relancer la même URL conserve donc les résultats précédents. Le script
supprime son téléchargement et, en cas d’échec du téléchargement ou de l’encodage, supprime toute
sortie partielle ainsi que le répertoire de travail vide. Les erreurs d’argument surviennent avant
la création de fichiers. Ce nettoyage couvre les échecs ordinaires de commande ; un arrêt forcé du
processus ou l’extinction de la machine peut laisser des fichiers temporaires.
128k désigne une cible de 128 000 bits par seconde. Le script vérifie l’orthographe de l’argument ;
l’encodeur sélectionné décide toujours si ce débit binaire est pris en charge. Le téléchargement se
termine avant l’encodage, ce qui permet à FFmpeg de se déplacer dans le fichier d’entrée.
Traitement par lot de fichiers audio
Enregistrez ceci sous batch_encode.sh à côté de encode_audio.sh. Exécutez-le depuis ce répertoire. Chaque ligne
de la liste d’entrée contient une URL, un format et un débit binaire séparés par des espaces. Les
lignes vides sont ignorées ; encodez en pourcentage les espaces dans les URL. Les commentaires et
les champs supplémentaires ne sont pas pris en charge.
#!/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"
Par exemple, enregistrez ces deux lignes sous 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
Le lot s’exécute séquentiellement et conserve les sorties réussies même lorsqu’une autre ligne échoue. Il poursuit malgré les entrées non valides, les téléchargements échoués et les encodages échoués, puis se termine avec le statut 1 si une tâche a échoué. Le statut 0 signifie que chaque ligne traitée a réussi ; une liste vide n’effectue aucun traitement.
Considérations de sécurité
Utilisez des URL HTTPS provenant de sources de confiance. cURL
vérifie les certificats serveur par défaut ; n’ajoutez pas -k pour
contourner cette vérification. Les
restrictions --proto et --proto-redir du script n’autorisent que
HTTP et HTTPS, y compris pour les redirections. HTTP reste disponible pour un serveur de test
local, mais ne fournit pas de chiffrement du transport.
Ces scripts sont des exemples de conversion locale. Ils n’isolent pas FFmpeg dans un bac à sable, n’imposent pas de limite de taille de téléchargement et ne rendent pas sûre la récupération par un serveur d’URL arbitraires fournies par les utilisateurs. Les délais d’expiration de cURL limitent chaque tentative de transfert, et les nouvelles tentatives peuvent allonger la durée totale du téléchargement. Prévoyez suffisamment d’espace disque pour l’entrée et la sortie complètes.
Gestion des erreurs et validation
Vérifiez la sortie réelle de l’exemple de base avec ce bloc, depuis le répertoire où vous l’avez exécuté :
(
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
)
Attendez-vous à ce que codec_name vaille aac, avec deux canaux et une durée proche de 41 secondes. ffprobe signale le
conteneur M4A comme faisant partie de la famille mov,mp4,m4a,3gp,3g2,mj2. La seconde commande décode
l’intégralité de la sortie sans enregistrer d’autre fichier. Pour un résultat du script, utilisez
dans les deux commandes le chemin exact affiché par cet appel. L’AAC ADTS brut inclut le délai et
le remplissage de l’encodeur, et ffprobe peut estimer sa durée à partir du débit binaire. Vérifiez
l’audio décodé par rapport à la chronologie de la source au lieu de considérer cette estimation
comme une durée exacte.
-xerror demande à FFmpeg de s’arrêter en cas d’erreur.
FFmpeg 6.1.1 peut signaler une erreur tardive du décodeur tout en renvoyant le statut 0. Les blocs
capturent donc aussi stderr au niveau de journalisation error et rejettent un journal d’erreurs non vide, en affichant son diagnostic avant
le nettoyage. Cela détecte les erreurs signalées, mais ne constitue pas une preuve d’intégrité : un
enregistrement tronqué à une limite décodable peut tout de même être encodé ou décodé avec succès,
et certains paquets endommagés peuvent être ignorés silencieusement. Comparez la durée avec une
source connue comme complète et écoutez jusqu’à la fin ;
utilisez une somme de contrôle de confiance fournie par l’éditeur lorsqu’elle est disponible.
L’existence du fichier, un en-tête lisible et un code de sortie nul ne permettent pas d’établir que
tout l’audio attendu est arrivé.
Une erreur HTTP de cURL telle que 404 arrête le téléchargement avant l’encodage. Un encodeur indisponible, un fichier sans flux audio ou un débit binaire refusé par l’encodeur arrête la conversion. Conservez le diagnostic sur stderr lorsque vous analysez un échec. Si le lot se termine avec le statut 1, utilisez ses messages par ligne pour identifier les échecs ; les sorties déjà terminées restent disponibles.
Conclusion
Pour un flux de travail d’encodage hébergé, consultez la documentation du Robot 🤖 /audio/encode (English). Son contrat d’envoi et d’authentification est distinct de ce téléchargement local avec cURL et de cette conversion avec FFmpeg.
