Diffuser des médias distants vers FFmpeg avec cURL
Redirigez un téléchargement HTTP de cURL vers FFmpeg pour extraire des vignettes et l’audio sans conserver de copie locale de la vidéo d’entrée. Le MP4 doit permettre une lecture séquentielle. Ce tutoriel crée un clip de test connu, le sert en HTTP et traite cette réponse pour produire des JPEG et un fichier WAV.
Vue d’ensemble
Utilisez Bash sous Linux, cURL, Python 3 et une version de FFmpeg dotée des encodeurs libx264 et AAC.
Les commandes ci-dessous ont été testées avec FFmpeg 6.1.1 et 9.0.1. Python fournit le serveur HTTP
local et n’est pas nécessaire si vous disposez déjà d’une URL distante adaptée.
L’exemple crée un MP4 « faststart » dont les métadonnées moov précèdent les données média. La
documentation MP4 de FFmpeg explique cette
organisation. Un pipe ne peut pas revenir en arrière, si bien qu’un MP4 ordinaire dont les
métadonnées se trouvent à la fin peut échouer même après que cURL a envoyé l’intégralité du fichier.
Lorsque l’organisation est inconnue, utilisez l’exemple ci-dessous qui télécharge d’abord. Ajouter
-f mp4 identifie le format ; cela ne permet pas pour autant de se positionner librement dans l’entrée.
Exécutez chaque bloc dans Bash depuis le même répertoire parent. Les parenthèses confinent les modifications d’options du shell à un sous-shell. Chaque bloc de traitement exige un nouveau répertoire de sortie et refuse d’être réexécuté dans un répertoire existant. Une exécution qui échoue peut laisser des fichiers partiels dans ce nouveau répertoire ; inspectez-les avant de les utiliser et choisissez un nouveau répertoire pour toute nouvelle tentative.
Mise en place du pipeline
Préparer un clip et une origine HTTP
Créez un clip de 6,4 secondes : rouge pendant deux secondes, vert citron pendant deux secondes, puis bleu. Son audio reste silencieux jusqu’à une brève tonalité de 880 Hz durant les 0,2 dernières secondes, ce qui rend audible une extraction audio incomplète.
(
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
)
Dans ce terminal, servez uniquement le répertoire de test sur l’adresse de bouclage :
(
set -eu
test -f curl-media-demo/input.mp4
python3 -m http.server 8765 --bind 127.0.0.1 --directory curl-media-demo
)
Laissez ce serveur tourner et utilisez un second terminal pour les blocs suivants. Si le port 8765 est occupé, choisissez un port disponible et modifiez-le à la fois dans la commande du serveur et dans les URL. Arrêtez le serveur avec Ctrl+C une fois terminé.
Extraire des vignettes et l’audio en un seul téléchargement
Dans le second terminal, revenez au même répertoire parent et exécutez :
(
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
)
Avec ce clip de test, attendez-vous à six JPEG de 160×90, nommés de thumbnail_000.jpg à thumbnail_005.jpg.
Les deux premiers sont rouges, les deux suivants vert citron et les deux derniers bleus. Lisez
outputs/audio.wav : il devrait rester silencieux jusqu’à la tonalité proche de la fin de l’enregistrement de
6,4 secondes. Le décodage AAC peut ajouter un léger remplissage à la fin du WAV.
Explication
pipe:0 lit l’entrée standard. Des options -map explicites sélectionnent les premiers flux vidéo et
audio, avec une sortie pour chacun. Une vidéo sans audio fait échouer le mappage audio obligatoire
au lieu d’omettre silencieusement le WAV. La vérification du nouveau répertoire protège la séquence
d’images des exécutions précédentes. L’option -n de FFmpeg protège les noms de fichiers MP4 et
WAV ; une séquence image2 peut remplacer des JPEG individuels. Conservez la protection du répertoire
et exécutez ces exemples l’un après l’autre.
Le filtre fps supprime ou duplique des images pour produire
une image par seconde. Son arrondi par défaut donne six images pour ce clip de test, de sorte que la
dernière fraction de seconde n’obtient pas de vignette distincte. -frame_pts 1 utilise les horodatages de
présentation de sortie comme numéros de fichiers, dans la base de temps de sortie. Ici, cette base
vaut une seconde, donc les numéros représentent les instants de sortie 0–5 secondes. Ce ne sont ni
les numéros des images d’origine ni une garantie de l’image source exacte retenue. Consultez les
options image2.
L’option -f de cURL fait échouer le transfert en cas d’erreur HTTP telle qu’une 404, tandis que
-sS masque l’indicateur de progression tout en conservant les messages d’erreur. L’option
pipefail de Bash propage l’échec d’un téléchargement même si FFmpeg se termine avec succès. Aucune
de ces options ne prouve que le serveur a envoyé un média intact.
Utilisations avancées
Sélectionner les changements de scène et enregistrer leurs instants
Pour échantillonner les changements de couleur plutôt qu’une fréquence fixe, lancez un téléchargement distinct dans un nouveau répertoire :
(
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
)
Pour ce clip, scene_001.jpg devrait être vert citron et scene_002.jpg bleu. Les entrées pts_time
correspondantes dans scenes/time.txt valent 2 et 4 secondes. Ce sont les horodatages des images
sélectionnées sur la chronologie d’entrée de FFmpeg, qui commence à zéro pour ce clip de test. Il ne
s’agit pas d’heures de capture réelles, et les numéros séquentiels des JPEG ne sont pas des
horodatages.
Le filtre select compare un score de scène
au seuil. Un score supérieur à 0,3 est une heuristique de changement visuel, pas une frontière de
scène sémantique. Un clip peut ne produire aucune image sélectionnée. -fps_mode vfr évite de combler les
intervalles entre les images sélectionnées par des doublons.
Dépannage
Si le pipe signale un fichier partiel ou ne trouve pas de paquets exploitables, FFmpeg doit peut-être se positionner librement dans le MP4. Téléchargez-le dans un nouveau répertoire, puis traitez le fichier réellement téléchargé. Cela sépare aussi les échecs réseau des échecs de décodage :
(
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
)
Avec l’URL de test, ce bloc produit les mêmes vignettes et le même audio que le pipe. Utilisez les
nouvelles tentatives de cURL avec -o pour le téléchargement d’un fichier, plutôt qu’avec un pipe
vers un décodeur. cURL ne peut pas annuler les octets déjà écrits dans un pipe avant de réessayer ;
sa documentation sur les nouvelles tentatives
décrit cette distinction. Le bloc s’arrête avant le décodage si le téléchargement échoue.
Une réponse HTTP 200 et un code de sortie nul n’établissent toujours pas que le média est complet. FFmpeg peut signaler des dommages de décodage tout en renvoyant zéro, ou récupérer des images et des échantillons endommagés. Lisez ses avertissements, comparez le nombre et les couleurs des vignettes attendues, et vérifiez la durée de l’audio ainsi que la tonalité finale. Pour vos propres médias, appuyez-vous sur une durée et un contenu attendus connus ou sur une somme de contrôle fiable fournie par l’éditeur ; ces exemples n’effectuent aucun contrôle d’intégrité. Télécharger d’abord résout le problème du positionnement, pas celui de la corruption.
Considérations de performance
Le pipe évite de stocker le MP4 d’entrée, mais les JPEG et le WAV non compressé occupent tout de même de l’espace disque. FFmpeg traite les données au fur et à mesure de leur arrivée ; la vitesse du réseau et celle du décodage déterminent la rapidité de ce traitement. Il s’agit d’un téléchargement de fichier HTTP, pas d’une garantie de comportement en temps réel ou de diffusion en direct. Réduire la fréquence des vignettes diminue le nombre d’images enregistrées, tandis que la détection de scène examine toujours les images décodées.
Pour un autre conteneur d’entrée, consultez la documentation du protocole pipe de FFmpeg et vérifiez si le démultiplexeur peut le consommer de manière séquentielle. Gardez à disposition la méthode qui télécharge d’abord lorsque vous ne pouvez pas contrôler l’organisation du MP4.
