J’ai streamé avec GStreamer
Date: 4/02/2009 | Catégories: Gstreamer,Open-source | Tags: gstreamer,live,streaming
Après une introduction à GStreamer qui vous, je l'espère, donné l'eau à la bouche, nous allons poursuivre la découverte de ce superbe framework en nous focalisant sur les fonctions de streaming audio et vidéo.
Avant de commencer à jouer, il faut installer GStreamer et ses composants sur votre machine. Je vous conseille d'installer GStreamer en suivant ce tutoriel. Vous disposerez ainsi des dernières versions des codecs.
Premier streaming vidéo: Theora et UDP
Nous allons dans ce premier exemple diffuser un flux vidéo (venant d'une Webcam) en utilisant le protocole UDP. Nous utiliserons le codec libre Theora (wiki) pour compresser la vidéo.
Sur la machine cliente (celle qui va recevoir et afficher le flux vidéo), il faut saisir la ligne suivante:
# gst-launch -v udpsrc port=1234 ! theoradec ! autovideosink
En clair, GStreamer va écouter le flux vidéo sur le port UDP/1234 (avec udpsrc) puis décompressé le flux Theora (theoradec) et enfin l'afficher sur l'écran (autovideosink).
Sur le serveur (la machine sur laquelle la Webcam est connectée et accessible par /dev/video1), nous allons saisir:
# gst-launch -v v4l2src device=/dev/video1 ! ffmpegcolorspace \
! videoscale method=1 ! video/x-raw-yuv,width=320,height=240,framerate=\(fraction\)15/1 \
! theoraenc bitrate=150 ! udpsink host=127.0.0.1 port=1234
Plusieurs remarques sur cette ligne de commande. On utilise la fonction videoscale pour redimensionner le format d'entrée de la vidéo (en taille et en nombre d'images par seconde) afin de limiter la bande passante. Je force ainsi dans ce cas le codec Theora à 150 Kbps. Enfin, la fonction udpsink permet de diffuser en UDP sur le réseau (port 1234 et adresse destination 127.0.0.1 - celle du client).
Remarque importante: il faut que le client soit lancé avant le serveur.
Streaming vidéo: Theora et TCP
Nous allons modifier légèrement notre premier exemple pour utiliser le protocole TCP en lieu et place du protocole UDP.
Le framework au niveau du client (le poste qui va recevoir le flux vidéo) est:
gst-launch -v tcpserversrc host=127.0.0.1 port=1234 ! decodebin ! autovideosink
GStreamer lance un serveur TCP (en écoute sur le port 1234 de l'adresse 127.0.0.1) et affiche le résultat (on peut utiliser decodebin à la place de theoradec) sur l'écran.
Sur le serveur (la machine avec la WebCam) on lance la commande:
gst-launch -v v4l2src device=/dev/video1 ! ffmpegcolorspace \
! video/x-raw-yuv,width=320,height=240,framerate=\(fraction\)10/1 \
! theoraenc bitrate=200 ! oggmux \
! tcpclientsink host=127.0.0.1 port=1234
On utilise la fonction
videoscale pour redimensionner le format d'entrée de la vidéo (en
taille et en nombre d'images par seconde) afin de limiter la bande
passante. Je force ainsi dans ce cas le codec Theora à 150 Kbps. Enfin,
la fonction tcpclientsink permet de diffuser en TCP sur le réseau (port 1234 et adresse destination 127.0.0.1 - celle du client).
Remarque importante: il faut que le client soit lancé avant le serveur.
Streaming vidéo: Theora et RTP/RTCP
On va compliquer encore un peu plus notre système de streaming en utilisant les protocoles RTP (pour les données) et RTCP (pour les flux de contrôle de ces données).
Contrairement aux deux premiers exemples, il faut lancer le client après le serveur. En effet, il est nécessaire de renseigner, au niveau du client, une chaine de configuration (caps) généré par le serveur.
gst-launch -v v4l2src \
! videoscale method=1 ! video/x-raw-yuv,width=320,height=240,framerate=\(fraction\)15/2 \
! theoraenc ! rtptheorapay \
! .send_rtp_sink gstrtpsession name=session .send_rtp_src ! udpsink port=5000 host=127.0.0.1 \
session.send_rtcp_src ! udpsink port=5001 host=127.0.0.1
Le serveur va encoder le flux vidéo avec le codec Theora, ajouter les entêtes RTP Theora (rtptheorapay) puis diffuser le flux en UDP (RTP/UDP sur le port 5000) grâce aux plugins gstrtpsession et udpsink. En parallèle, un serveur RTCP (RTCP/UDP) est lancé. Il envoie les information RTCP vers le port 5001 de la machine cliente (127.0.0.1).
Notez le paramètre -v passé à gst-launch. Il est nécessaire pour l'obtention de la chaine de configuration (caps).
Lors du lancement de cette commande, un grand nombre de messages va s'afficher. Il faut récupérer la dernière occurence du type:
caps = application/x-rtp, media=(string) video ... seqnum-base=(guint)39194
Nous pouvons alors lancer notre client:
gst-launch udpsrc port=5000 caps="application/x-rtp, media=(string) video ... seqnum-base=(guint)39194" \
! .recv_rtp_sink gstrtpsession name=session .recv_rtp_src \
! rtptheoradepay ! theoradec ! xvimagesink \
udpsrc port=5001 caps="application/x-rtcp" ! session.recv_rtcp_sink
Le client écoute le flux de donnée vidéo sur le port UDP/5000. Grâce aux informations fournies dans le champs caps, il peut décoder le flux. On enlève l'entête RTP (rtptheoradepay) puis on décode le flux théora (theoradec) et on affiche. En parallèle, on écoute les flux de contrôle de ces données (RTCP) sur le port 5001 et on les injectent dans le gestionnaire RTP (gstrtpsession).
Streaming vidéo: H.264 et RTP/RTCP
Nous allons modifier l'exemple précedant en remplacant le codec H.264 au lieu de Theora. Pour celà, nous allons utiliser le plugins X.264 (développé par l'équipe VideoLAN).
Contrairement au codec Theora, il n'est pas nécessaire de passer la chaine de configuration "caps" du serveur vers le client.
On a donc la configuration suivante au niveau du serveur (à lancer en premier). Vous pouvez récupérer le script shell correspondant à ici:
WEBCAM_DEV="/dev/video0"WEBCAM_WIDTH=352WEBCAM_HEIGHT=288WEBCAM_FPS=24SERVER_IP=$1SEND_RTP_PORT=5000SEND_BUFFER=0X264_BITRATE=600X264_PARAM="byte-stream=true bframes=4 ref=4 me=hex subme=4 weightb=true threads=0 sliced-threads=1 vbv-buf-capacity=300"# With RTCPSEND_RTCP_PORT=5001RECV_RTCP_PORT=5002gst-launch -v gstrtpbin name=rtpbin \v4l2src device=$WEBCAM_DEV \! queue ! videoscale method=1 ! video/x-raw-yuv,width=\(int\)$WEBCAM_WIDTH,height=\(int\)$WEBCAM_HEIGHT \! queue ! videorate ! video/x-raw-yuv,framerate=\(fraction\)$WEBCAM_FPS/1 \! queue ! x264enc bitrate=$X264_BITRATE $X264_PARAM ! rtph264pay \! rtpbin.send_rtp_sink_0 \rtpbin.send_rtp_src_0 ! udpsink port=$SEND_RTP_PORT host=$SERVER_IP \rtpbin.send_rtcp_src_0 ! udpsink port=$SEND_RTCP_PORT host=$SERVER_IP sync=false async=false \udpsrc port=$RECV_RTCP_PORT ! rtpbin.recv_rtcp_sink_0
La seule différence avec l'exemple du chapitre précedant est l'utilisation de l'encodeur X.264 (x264enc qui génére un flux H.264). Pour une description des nombreux paramètres de ce plugin, je vous conseille la lecture de la documentation:
gst-inspect x264enc
La ligne de commande du client est la suivante (la encore vous pouvez récupérer le script shell ici):
RECV_RTP_PORT=5000RECV_BUFFER=300CLIENT_IP=$1RECV_RTCP_PORT=5001SEND_RTCP_PORT=5002gst-launch -tv gstrtpbin name=rtpbin latency=$RECV_BUFFER \udpsrc caps="application/x-rtp, media=(string)video, clock-rate=(int)90000, encoding-name=(string)H264, payload=(int)96" port=$RECV_RTP_PORT \! rtpbin.recv_rtp_sink_0 \rtpbin. ! rtph264depay ! ffdec_h264 ! ffmpegcolorspace ! autovideosink \udpsrc port=$RECV_RTCP_PORT ! rtpbin.recv_rtcp_sink_0 \rtpbin.send_rtcp_src_0 ! udpsink port=$SEND_RTCP_PORT host=$CLIENT_IP sync=false async=falsegst-launch -tv gstrtpbin name=rtpbin latency=$RECV_BUFFER \ udpsrc caps="application/x-rtp, media=(string)video, clock-rate=(int)90000, encoding-name=(string)H264, payload=(int)96" port=$RECV_RTP_PORT \ ! rtpbin.recv_rtp_sink_0 \ rtpbin. ! rtph264depay ! ffdec_h264 ! ffmpegcolorspace ! autovideosink \ udpsrc port=$RECV_RTCP_PORT ! rtpbin.recv_rtcp_sink_0 \ rtpbin.send_rtcp_src_0 ! udpsink port=$SEND_RTCP_PORT host=$CLIENT_IP sync=false async=false
On utilise le décodeur H.264 fourni par FFMpeg (ffdec_h264).
Streaming audio et vidéo: H.264, Speex et RTP/RTCP
Dernier exemple de ce billet qui va streamer un flux vidéo et un flux audio (venant du périphérique de capture standard de votre système). La vidéo sera encodé en H.264 et la vidéo en Speex. Le tout en utilisant le protocole RTP/RTCP.
Le serveur (à lancer en premier). Il faut récupérer la chaine "caps" pour la partie audio Speex.
gst-launch -v gstrtpbin name=rtpbin \
v4l2src ! videoscale method=1 ! video/x-raw-yuv,width=640,height=480,framerate=\(fraction\)15/2 \
! queue ! x264enc byte-stream=true bitrate=300 vbv-buf-capacity=300 me=0 subme=3 ! rtph264pay \
! rtpbin.send_rtp_sink_0 \
rtpbin.send_rtp_src_0 ! udpsink port=5000 host=127.0.0.1 \
rtpbin.send_rtcp_src_0 ! udpsink port=5001 host=127.0.0.1 sync=false async=false \
udpsrc port=5002 ! rtpbin.recv_rtcp_sink_0 \
alsasrc \
! queue ! speexenc ! rtpspeexpay \
! rtpbin.send_rtp_sink_1 \
rtpbin.send_rtp_src_1 ! udpsink port=5003 host=127.0.0.1 \
rtpbin.send_rtcp_src_1 ! udpsink port=5004 host=127.0.0.1 sync=false async=false \
udpsrc port=5005 ! rtpbin.recv_rtcp_sink_1
Et le client:
gst-launch-0.10 -v gstrtpbin name=rtpbin latency=200 \
udpsrc caps="application/x-rtp, media=(string)video, clock-rate=(int)90000, encoding-name=(string)H264, profile-level-id=(string)4d4033, sprop-parameter-sets=(string)Z01AM6tAUB7YCIAAAAMBAAADAA9HjBlQ, ssrc=(guint)614294178, payload=(int)96, clock-base=(guint)3718899905, seqnum-base=(guint)59615" port=5000 \
! rtpbin.recv_rtp_sink_0 \
rtpbin. ! rtph264depay ! ffdec_h264 ! xvimagesink \
udpsrc port=5001 ! rtpbin.recv_rtcp_sink_0 \
rtpbin.send_rtcp_src_0 ! udpsink port=5002 host=127.0.0.1 sync=false async=false \
udpsrc caps="application/x-rtp, media=(string)audio, clock-rate=(int)44100, encoding-name=(string)SPEEX, encoding-params=(string)1, ssrc=(guint)419764010, payload=(int)110, clock-base=(guint)3478167082, seqnum-base=(guint)57894" port=5003 \
! rtpbin.recv_rtp_sink_1 \
rtpbin. ! rtpspeexdepay ! decodebin ! alsasink \
udpsrc port=5004 ! rtpbin.recv_rtcp_sink_1 \
rtpbin.send_rtcp_src_1 ! udpsink port=5005 host=127.0.0.1 sync=false async=false
Bon stream à vous !