Nous allons voir dans ce tutoriel, comment envoyer un stream vidéo d’une machine à une autre à l’aide de FFMPEG. Envoyer des données entre deux appareils, quelle qu’elles soient, est un des problèmes majeurs dans les objets connectés (IoT). Si vous souhaitez créer une caméra connectée qui envoie des vidéos à une machine distante, cet article devrait vous intéresser.
Installation de ffmpeg
Sur une machine Linux
sudo apt-get install ffmpeg
Sur une machine Windows, veuillez suivre cette procédure.
N.B.: si besoin sur une machine linux sudo apt-get install v4l-utils
Obtenir les informations nécessaire au streaming Vidéo
Pour créer un flux vidéo d’une machine à une autre, les machines doivent être connectées sur le même réseau (Wifi ou Ethernet)
Dans un premier temps, vous devez obtenir l’adresse IP de la machine cliente (qui reçoit le flux)
Entrez dans un terminal de commande
ifconfig #pour une machine linux
ip addr # si ifconfig n'est pas disponible
ou
ipconfig #pour une machine windows
Vous devriez obtenir une adresse de la forme 192.168.X.X (dans notre cas 192.168.1.67)
Ensuite récupérer la source vidéo. Pour lister toutes les entrées vidéo sur une machine linux
ls -l /dev/video*
lsusb #list usb devices
v4l2-ctl --list-devices #list video devices
Ces commandes devrait vous aider à identifier la source vidéo. Dans notre cas, /dev/video5
Pour lister les sources vidéo sur une machine Windows, vous pouvez utiliser ffmpeg
ffmpeg -list_devices true -f dshow -i dummy
Dans notre cas, video= »USB2.0 HD UVC WebCam »
Récupérer les options et vérifier les formats et résolutions acceptés par la caméra
sous Linux
v4l2-ctl -d /dev/video0 --list-formats
sous Windows
ffmpeg -f dshow -list_options true -i video="USB2.0 HD UVC WebCam"
Une fois ces données enregistrées, nous allons pouvoir configurer le streaming.
Créer un stream vidéo avec ffmpeg
Pour créer un flux vidéo, il vous faut un émetteur (server) et un récepteur (client) qui seront joués par deux terminaux lancer sur deux ordinateurs différents.
- côté serveur linux
ffmpeg -re -f v4l2 -i /dev/video5 -r 10 -f mpegts udp://192.168.1.67:8554?pkt_size=1316
- côté serveur windows
ffmpeg -f dshow -i video="USB2.0 HD UVC WebCam" -r 10 -f mpegts udp://192.168.1.67:8554?pkt_size=1316
- côté client
ffplay udp://127.0.0.1:8554
ou
ffplay udp://0.0.0.0:8554
N.B.: Vous pouvez tester le streaming sur une seule machine en utilisant l’adresse IP de la machine sur laquelle vous travaillez et en utilisant deux terminaux un pour le serveur et un pour le client
Pour récupérer les statistiques vidéo vous pouvez utiliser la commande ffprobe
ffprobe udp://127.0.0.1:8554
ou, pour plus de détails,
ffprobe -show_format -show_streams udp://127.0.0.1:8554
Réduire le délai de réception du flux vidéo entre deux machines
Nous pouvons observer un délai de 15 secondes environ entre l’émission vidéo et la réception. Il peut être intéressant de réduire ce délai selon les applications.
Côté serveur les paramètre qui jouent sur la vitesse de transmission sont:
- la taille de l’image (ex: -s 800×600)
- la conversion de format codec (ex: -c:v libx264)
- le nombre d’image à la seconde ou framerate (ex: -r 10)
Essayez de jouer avec ces paramètres pour réduire le délai tout en conservant une qualité suffisante.
ffmpeg -re -thread_queue_size 64 -s800x600 -i /dev/video5 -r 5 -f mpegts udp://192.168.1.67:8554?pkt_size=1316
Côté client, il y a différentes options que vous pouvez tester de la documentation repris dans cette discussion.
ffplay -fflags nobuffer -probesize 32 -sync ext -vf setpts=0 udp://127.0.0.1:8554
Ces modifications d’options des commandes ffmpeg et ffplay permet de réduire le délai de 15 à 2 secondes environ le stream video.
Créer un stream HTTP avec ffmpeg
Il est possible de créer un serveur vidéo HTTP en passant par VLC. L’intérêt de cette méthode est qu’on peut transmettre le flux vidéo à n’importe quel appareil.
- côté serveur linux
ffmpeg -input_format h264 -video_size 1280x720 -framerate 30 -i /dev/video0 -vcodec copy -f mpegts -|vlc -I dummy - --sout='#std{access=http,mux=ts,dst=:8554}'
- côté client, vous devez spécifier l’adresse IP du serveur
ffplay http://192.168.1.9:8554
Créer un stream RTSP avec ffmpeg
Il est possible de créer un serveur vidéo HTTP en passant par VLC. L’intérêt de cette méthode est qu’on peut transmettre le flux vidéo à n’importe quel appareil.
- côté serveur linux
ffmpeg -input_format h264 -video_size 1280x720 -framerate 30 -i /dev/video0 -vcodec copy -f mpegts -|vlc -I dummy - --sout='#rtp{sdp=rtsp://:8554/} --sout-all --sout-keep'
- côté client, vous devez spécifier l’adresse IP du serveur
ffplay rtsp://192.168.1.9:8554/
Script Python pour lancer le streaming
Voici un script Python qui vous permettra de tester les différentes méthodes de streaming ainsi que les paramètre ffmpeg
import subprocess #UDP #input client ip address here 192.168.1.9 stream_video="ffmpeg -input_format h264 -video_size 1280x720 -framerate 30 -i /dev/video0 -vcodec copy -f mpegts udp://192.168.1.9:8554?pkt_size=1316" #on client side ffplay udp://127.0.0.1:8554 #HTTP stream_video="ffmpeg -input_format h264 -video_size 1280x720 -framerate 30 -i /dev/video0 -vcodec copy -f mpegts -|vlc -I dummy - --sout='#std{access=http,mux=ts,dst=:8554}'" #on client side ffplay http://192.168.1.73:8554 #RSTP stream_video="ffmpeg -input_format h264 -video_size 1280x720 -framerate 30 -i /dev/video0 -vcodec copy -f mpegts -|vlc -I dummy - --sout='#rtp{sdp=rtsp://:8554/} --sout-all --sout-keep'" #on client side ffplay rtsp://192.168.1.73:8554/ # don't forget / at the end try: subprocess.call(stream_video,shell=True) except: pass print("Done")
Bonus : Afficher le stream vidéo de FFMPEG avec OpenCV
Une fois le flux vidéo établi entre les deux machines, il est possible d’utiliser OpenCV afin de lire et afficher les images provenant du stream UDP.
import cv2 def main(args): #cap = cv2.VideoCapture(0) #default camera cap = cv2.VideoCapture('udp://127.0.0.1:8554') #cap = cv2.VideoCapture('http://192.168.1.9:8554') #cap = cv2.VideoCapture('rtsp://192.168.1.9:8554/') while(True): ret, frame = cap.read() if ret: #necessary if packet is lost frame=cv2.resize(frame, (800, 600)) cv2.imshow('Capturing',frame) if cv2.waitKey(1) & 0xFF == ord('q'): #click q to stop capturing break cap.release() cv2.destroyAllWindows() return 0 if __name__ == '__main__': import sys sys.exit(main(sys.argv))
Bonus2 : Afficher l’heure sur la vidéo
Pour afficher l’heure sur la vidéo, nous allons utiliser le filtre drawtext de ffmpeg qui utilise certain paramètre de texte
- fontfile: police utilisée
- fontsize: taille du texte
- fontcolor: couleur du texte
"drawtext=fontfile=/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans-Bold.ttf: text='%{localtime\:%T}': fontsize=24: fontcolor=white@0.8: x=7: y=460"
Le filtre est appliqué avec le tag -vf. Voici la commande complète
ffmpeg -input_format h264 -video_size 1280x720 -framerate 30 -i /dev/video0 -vf "drawtext=fontfile=/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans-Bold.ttf: text='%{localtime\:%T}': fontsize=24: fontcolor=white@0.8: x=7: y=460" -vcodec copy -f mpegts udp://192.168.1.9:8554?pkt_size=1316
En python
stream_cmd="""ffmpeg -input_format h264 -video_size 1280x720 -framerate 30 -i /dev/video0 -vf "drawtext=fontfile=/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans-Bold.ttf: text='%{localtime\:%T}': fontsize=24: fontcolor=white@0.8: x=7: y=460" -vcodec copy -f mpegts udp://192.168.1.9:8554?pkt_size=1316"""
Pratique pour imiter une caméra CCTV ou pour comparer les temps provenant de différentes caméra