17-07-2014, 13:18:09
Bonjour à tous,
Je cherche depuis des semaines à pouvoir diffuser une vidéo issue de la picam vers plusieurs postes sur un réseau local, avec un minimum de lag. Je vous livre ici mes découvertes et questions.
* tous d'abord, j'ai essayé d'établir des connexions en python via les sockets. Cela fonctionne très bien en TCP ou UDP, dès lors que l'on ne transmet que du texte.
* je suis passé à la transmission vidéo, toujours via python et en utilisant les exemples fournis sur le readthedocs/picamera. Cela fonctionne en TCP lorsqu'il n'y a qu'un client.
* j'ai continué dans cette voie en exploitant le multithread, en essayant de lancer une transmission de donnée par client ... sans succès. La caméra n'acceptant qu'une connexion sur son port 0, c'est le premier client connecté qui est servi.
* je suis passé alors en udp pour "arroser" un maximum de client. J'ai utilisé l'adresse 192.168.1.255 afin de garantir que tous les clients sous ce masque puissent être servis. Cette fois encore start_recording me met en défaut, car elle n'accepte qu'un socket avec une adresse IP fixe.
* Dans le cas d'un seul client connecté, les meilleurs résultats ont été obtenus avec mplayer sur le client. Ce soft ayant l'énorme avantage de laisser à l'opérateur la possibilité de "shunter le buffer" et donc de diminuer le lag.
Je suis retourné ensuite à des syntaxes en ligne de commande :
* du côté raspberry pi, j'ai utilisé raspivid + vlc, du côté client, vlc, mplayer ou ffplay. Les résultats sont identiques, trop de décalage pour exploiter du temps réel (entre 2s et 4s)
* j'ai tenté en tout dernier espoir gstreamer qui est censé garantir un décalage mini. Les paramètres de gstreamer sont encore sacrément flous pour moi. Il m'est pour l'instant impossible de générer un flux gstreamer sur le serveur et de le récupérer via un lecteur vidéo sur le client. J'ai bien des paquets qui transitent, mais ils ne sont pas reconnus.
Enfin, la solution actuelle, c'est gstreamer sur le serveur en ligne de commande et gstreamer sur le client. Et là, même avec 2 clients, ça fonctionne nickel, tant que le raspberry n'a pas son occupation processeur au taquet !
Dans la version final, j'aimerais pouvoir intégrer la commande gstreamer dans un programme python dans le but de pouvoir, en live envoyer des ordres à la caméra sans interrompre le flux. Sur le client, cela fonctionne bien, grâce à la librairie subprocess. Cependant, sur le serveur, je souhaite ouvrir la caméra via la librairie picamera et d'ouvrir un flux par start_recording, de récupérer ce flux dans gstreamer qui va s'occuper de l'ouverture des sockets et de l'envoi.
voilà mon code partie serveur :
Je n'arrive pas à faire le lien entre my_stream et fdscr sur gdtreamer. Je ne sais d'ailleurs pas si c'est la bonne méthode et je suis preneur de toute explication
Pour la partie client, pour l'instant, cela donne ceci :
J'espère avoir été clair dans mes explications, pas facile de résumer plusieurs semaines de recherches. D'avance merci pour les retours.
Cordialement,
Cyb
Je cherche depuis des semaines à pouvoir diffuser une vidéo issue de la picam vers plusieurs postes sur un réseau local, avec un minimum de lag. Je vous livre ici mes découvertes et questions.
* tous d'abord, j'ai essayé d'établir des connexions en python via les sockets. Cela fonctionne très bien en TCP ou UDP, dès lors que l'on ne transmet que du texte.
* je suis passé à la transmission vidéo, toujours via python et en utilisant les exemples fournis sur le readthedocs/picamera. Cela fonctionne en TCP lorsqu'il n'y a qu'un client.
* j'ai continué dans cette voie en exploitant le multithread, en essayant de lancer une transmission de donnée par client ... sans succès. La caméra n'acceptant qu'une connexion sur son port 0, c'est le premier client connecté qui est servi.
* je suis passé alors en udp pour "arroser" un maximum de client. J'ai utilisé l'adresse 192.168.1.255 afin de garantir que tous les clients sous ce masque puissent être servis. Cette fois encore start_recording me met en défaut, car elle n'accepte qu'un socket avec une adresse IP fixe.
* Dans le cas d'un seul client connecté, les meilleurs résultats ont été obtenus avec mplayer sur le client. Ce soft ayant l'énorme avantage de laisser à l'opérateur la possibilité de "shunter le buffer" et donc de diminuer le lag.
Je suis retourné ensuite à des syntaxes en ligne de commande :
* du côté raspberry pi, j'ai utilisé raspivid + vlc, du côté client, vlc, mplayer ou ffplay. Les résultats sont identiques, trop de décalage pour exploiter du temps réel (entre 2s et 4s)
* j'ai tenté en tout dernier espoir gstreamer qui est censé garantir un décalage mini. Les paramètres de gstreamer sont encore sacrément flous pour moi. Il m'est pour l'instant impossible de générer un flux gstreamer sur le serveur et de le récupérer via un lecteur vidéo sur le client. J'ai bien des paquets qui transitent, mais ils ne sont pas reconnus.
Enfin, la solution actuelle, c'est gstreamer sur le serveur en ligne de commande et gstreamer sur le client. Et là, même avec 2 clients, ça fonctionne nickel, tant que le raspberry n'a pas son occupation processeur au taquet !
Dans la version final, j'aimerais pouvoir intégrer la commande gstreamer dans un programme python dans le but de pouvoir, en live envoyer des ordres à la caméra sans interrompre le flux. Sur le client, cela fonctionne bien, grâce à la librairie subprocess. Cependant, sur le serveur, je souhaite ouvrir la caméra via la librairie picamera et d'ouvrir un flux par start_recording, de récupérer ce flux dans gstreamer qui va s'occuper de l'ouverture des sockets et de l'envoi.
voilà mon code partie serveur :
Code :
import picamera
import subprocess
import io
cmdline = ['gst-launch-1.0', '-e', 'fdsrc', 'fd=1', '!', 'h264parse', '!', 'rtph264pay',
'config-interval=1', 'pt=96', '!', 'gdppay', '!', 'tcpserversink',
'host=192.168.1.80', 'port=8000']
my_stream = io.BytesIO()
camera = picamera.PiCamera()
camera.resolution = (640, 480)
camera.framerate = 24
# Start a preview and let the camera warm up for 2 seconds
#camera.start_preview()
# Start recording, sending the output to the connection for 60
# seconds, then stop
camera.start_recording(my_stream,format='h264')
player = subprocess.Popen(cmdline, stdin=subprocess.PIPE)
camera.wait_recording(60)
camera.stop_recording()

Pour la partie client, pour l'instant, cela donne ceci :
Code :
import subprocess
cmdline = ['D:/gstreamer/bin/gst-launch-1.0.exe', '-v', 'tcpclientsrc', 'host=192.168.1.80','port=8000', '!', 'gdpdepay',
'!', 'rtph264depay', '!', 'avdec_h264', '!', 'videoconvert', '!', 'autovideosink', 'sync=false']
player = subprocess.Popen(cmdline, stdin=subprocess.PIPE)
J'espère avoir été clair dans mes explications, pas facile de résumer plusieurs semaines de recherches. D'avance merci pour les retours.
Cordialement,
Cyb