J’ai streamé avec GStreamer

Date: 4/02/2009 | Catégories: Gstreamer,Open-source | Tags: ,,

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=352
WEBCAM_HEIGHT=288
WEBCAM_FPS=24
SERVER_IP=$1
SEND_RTP_PORT=5000
SEND_BUFFER=0
X264_BITRATE=600
X264_PARAM="byte-stream=true bframes=4 ref=4 me=hex subme=4 weightb=true threads=0 sliced-threads=1 vbv-buf-capacity=300"
# With RTCP
SEND_RTCP_PORT=5001
RECV_RTCP_PORT=5002
gst-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=5000
RECV_BUFFER=300
CLIENT_IP=$1
RECV_RTCP_PORT=5001
SEND_RTCP_PORT=5002
gst-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

gst-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 !