J’ai streamé avec GStreamer

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 !

  • chicha

    Super intéressants tes posts sur Gstreamer, merci beaucoup tu me fais découvrir ce framework : j’avais tendance à n’utiliser que vlc pour la diffusion ou avidemux pour bidouiller une vidéo. J’espère qu’on verra un jour un équivalent à avidemux avec Gstreamer.

    J’ai une petite question : quid de la communication avec vlc ?
    Est-ce qu’un flux diffusé avec vlc peut être lu avec gstreamer ?
    Exemple pratique : est-ce qu’il est envisageable de coder un plugin pour totem qui permettrait de lire les flux TV provenant d’une Freebox ? Réciproquement est-ce qu’on pourrait envisager de streamer une vidéo depuis son PC vers la Freebox/freeplayer ?

    Merci encore !
    ++
    Chicha

  • http://blog.nicolargo.com NicoLargo

    @chicha: il est tout à fait possible de récupérer un flux “streamé” avec Gstreamer sur un client VLC. Par exemple pour récupéré le flux vidéo RTP + H.264, il faut créer un fichier .sdp et ouvrir ce fichier avec VLC.

    test.sdp:
    ———–

    v=0
    o=- 1188340656180883 1 IN IP4 127.0.0.1
    s=Session streamed by GStreamer
    i=server.sh
    t=0 0
    a=tool:GStreamer
    a=type:broadcast
    m=video 5000 RTP/AVP 96
    c=IN IP4 127.0.0.1
    a=rtpmap:96 H264/90000

    Je vais créer de ce pas une nouvelle catégorie GStreamer dans le forum pour en discuter (http://forum.nicolargo.com).

  • chicha

    Merci beaucoup !

    En revanche je me demande s’il est possible de streamer depuis Gstreamer vers une freebox/freeplayer (vlc inside) ? j’ai peur que le stream doit contenir des informations propres à vlc …

  • http://blog.nicolargo.com NicoLargo

    @chicha: j’avoue ne pas avoir essayé. Mais je suis intéressé par le résultat.

  • chicha

    Je te tiendrais au courant de mes essais :-)

  • Cenwen

    Superbe tous ces articles sur gstreamer qui montre les possibilités de ce framework multimedia de gnome et maintenant de xfce hors norme et d’ailleurs sous-exploité.
    Personnellement, je connaissais ce blog pour toutes ces informations concernant le réseau (qui en passant n’est pas du tout ma tasse de thé contrairement au multimedia et à la vidéo + precisemment) mais pas pour le multimedia. C’est certainement la raison qui m’a fait “plonger” dans les entrailles de gstreamer et j’ai découvert ses possibilités d’acquisition (dvb;1394;v4l2,..) et de decodage/d’encodage. Pour le prochain article pourrait-il traiter de l’acquisiton / enregistrement d’un flux (1394 ou dvb si possible) et/ou encodage d’un flux. Plus généralement, traiterat-il des possibilités (pad, cap, property et autres détails) et des messages d’erreurs et de leurs causes ainsi que le “liage” de gstreamer avec un language, python par exemple…?????
    Merci de m’avoir fait découvrir tout cela et vivement la suite.La je suis accroché et je me demande si je ne vais pas m’inscrire sur le forum…;

  • http://blog.nicolargo.com NicoLargo

    @cenwen: merci pour le message, je suis loin d’être un spécialiste sur ce superbe framework libre qu’est gstreamer. J’ai l’occasion de l’utiliser dans le cadre de mon boulot et comme j’aime bien comprendre de quoi je parle, j’ai écris ces qq tutos (et d’autres à venir). Un des gars de mon équipe fait son stage sue le sujet. Tu peux suivre son travail sur ce blog:

    http://lorenzocam.wordpress.com/

    A+ et à bientôt sur le forum (qu’il faut faire vivre coté GStreamer…).

  • Julien

    Tous ces articles sont très intéressants pour la prise en main de Gstreamer.

    Je me pose une question : Est-il possible d’encoder en MPEG4 sans utiliser “ffenc_mpeg4″ ?

  • http://blog.nicolargo.com NicoLargo

    @Julien: oui, en utilisant le x264enc.

  • Ouerteni Ahmed

    Merci, Tous ces articles sont très intéressants

    Mais j’ai essayé de streamé la voix à partir d’un microphone avec les commandes suivantes:

    SERVEUR: gst-launch -v osssrc ! audio/x-raw-int, endianness=1234, signed=true, width=16, depth=16, rate=44100, channels=2 ! tee name=t ! queue ! faac ! mp4mux ! udpsink port=5000 host=10.1.1.43 t.

    CLIENT : gst-launch -v udpsrc port=5000 ! ffdemux_mov_mp4_m4a_3gp_3g2_mj2 ! faad ! osssink

    En tant que client j’ai eu ce message d’erreur:

    gst-launch -v udpsrc port=5000 ! ffdemux_mov_mp4_m4a_3gp_3g2_mj2 ! faad ! osssink
    Définition du pipeline à PAUSED…
    Le pipeline est actif et n’a pas besoin de phase PREROLL…
    Passage du pipeline à la phase PLAYING…
    New clock: GstSystemClock
    ERREUR : de l’élément /GstPipeline:pipeline0/ffdemux_mov_mp4_m4a_3gp_3g2_mj2:ffdemux_mov_mp4_m4a_3gp_3g2_mj20 : GStreamer a rencontré une erreur générale de bibliothèque de prise en charge.
    Information de débogage supplémentaire :
    gstffmpegdemux.c(1243): gst_ffmpegdemux_open (): /GstPipeline:pipeline0/ffdemux_mov_mp4_m4a_3gp_3g2_mj2:ffdemux_mov_mp4_m4a_3gp_3g2_mj20:
    Unhandled error code received
    Execution ended after 21482342886 ns.
    Définition du pipeline à PAUSED…
    Définition du pipeline à READY (prêt)…
    Définition du pipeline à NULL…
    Libération du pipeline…

    Par contre j’ai essayé d’enregistrer la voix dans un fichier et ça bien marcher avec ces commandes:

    COMMANDE D’ENREGISTREMENT:
    gst-launch -v osssrc num-buffers=2000 ! audio/x-raw-int, endianness=1234, signed=true, width=16, depth=16, rate=44100, channels=2 ! tee name=t ! queue ! faac ! mp4mux ! filesink location=mm.aac t. ! queue ! alsasink sync=false

    COMMANDE D’ECOUTE:
    gst-launch-0.10 -v filesrc location=mm.aac ! ffdemux_mov_mp4_m4a_3gp_3g2_mj2 ! faad ! osssink

    Pouvez vous m’aidez dans ce probleme.
    Cordialement

  • Vincent

    Merci pour ce Tutorial !

    Une question concernant la gestion du débit (par le serveur RTP) dans le cas d’un flux MPEG2 TS sur RTP:

    les éléments gst exploitent-ils les timestamps PCR contenus dans les paquets TS ?

    Si ce n’est pas le cas, comment gst cadence l’envoi des paquets RTP sur le réseau ?

  • http://blog.info16.fr Bartounet

    J’ai mis en place aussi il y à peu dans ma boite un serveur phpmotion et un serveur clipbucket, tous les 2 de très bon outils de streaming videos à la youtube :)

  • CptWacko

    Est-ce que quelqu’un sait s’il est possible de créer et d’envoyer un fichier vidéo OGG du stream sur un serveur distant comme le fait VLC ?

    …Mon but serait de lire le stream sur un serveur web avec le HTML5. Merci!

  • sam

    do you have a english version of this??

    • http://www.nicolargo.com NicoLargo

      No sorry, did you try the (lame) Google Translator ?

      http://bit.ly/hrSTbR

      Nicolas

      • sam

        No i haven’t.. But it seems like you have included everything which helps me in my project.. In my project i am going to stream a video/audio.. I will try to run code later.. I will ask if i have any question.. is that alryt with you?? thank you so much for the quick response.. btw is this Espanol??

  • http://www.rtlinfo.com Richard

    Bonjour et merci pour cet excellent article

    Depuis longtemps, je cherche à afficher sur mon site web distant (hébergé chez ouvaton), dans une page html donc, le flux vidéo généré par ma webcam à mon domicile (connexion internet via freebox v6, avec ip publique fixe, et box en mode routeur)

    Je pense que cela doit être possible avec gstreamer mais je ne sais pas trop comment faire :
    commande gstreamer à lancer
    ouverture des ports (sur freebox)
    et commande html à mettre dans ma page web.

    Si quelqu’un peut m’aider à mettre en place ceci…

  • momed

    bnj tt le monde.
    j’aime bien affiche mon flux dans une autre application (IHM).
    est il possible d’integré le flux recu par gstreamer dans une fenetre (par exemple Window GTK)?

    et merci

    • Jean-Charles Quantin

      Bonjour,

      Tout ce qui est expliqué ici repose sur l’utilisation de l’utilitaire gst-launch… en ligne de commande.
      Pour ton besoin, il faut programmer en C/C++ en intégrant la librairie lib-gstreamer et la librairie lib-gtk. Une petite compile avec gcc, et si t’es trop fort tu peux aussi t’amuser à “porter” ton application sous windows.

      Pour t’aider, tu peut regarder le code source de gst-launch. C’est ça l’openSource !

      Bon courage.

  • mawwa

    est ce que gstreamer est capable de lire les flux MMS?

  • Charles Loisy

    Bonjour,

    Voila, je tente de récupérer un streaming envoyé depuis un VLC sur un PC sur un raspberry.

    Pour l’instant, j’ai créer mon flux UDP avec VLC, pas de problème.

    Pour le lire j’utilise :

    gst-launch-0.10 -v udpsrc port=1234 ! ffdec_h264 ! autovideosink

    Seulement, j’ai cela en retour :

    AVERTISSEMENT : pipeline erroné : pas d’élément « ffdec_h264 »

    je me dis donc que je n’ai pas le codec h264. J’installe toutes les librairies (good bad, ugly), les outils gstreamer-tools, et gstreamer-ffmpeg

    Quand je fais une verif de mes codecs : gst-inspect-0.10 | egrep ‘encoder|decoder’

    J’obtiens ça :

    kate: kateenc: Kate stream encoder
    speex: speexenc: Speex audio encoder
    mulaw: mulawenc: Mu Law audio encoder
    pnm: pnmenc: PNM image encoder
    twolame: twolame: TwoLAME mp2 encoder
    vorbis: vorbisenc: Vorbis audio encoder
    bz2: bz2enc: BZ2 encoder
    y4menc: y4menc: YUV4MPEG video encoder
    flac: flacenc: FLAC audio encoder
    adpcmenc: adpcmenc: ADPCM encoder
    wavpack: wavpackenc: Wavpack audio encoder
    subenc: srtenc: Srt encoder
    subenc: webvttenc: WebVTT encoder
    voamrwbenc: voamrwbenc: AMR-WB audio encoder
    opus: opusenc: Opus audio encoder
    voaacenc: voaacenc: AAC audio encoder
    lame: lamemp3enc: L.A.M.E. mp3 encoder
    lame: lame: L.A.M.E. mp3 encoder
    xvid: xvidenc: XviD video encoder
    annodex: cmmlenc: CMML streams encoder
    gsm: gsmenc: GSM audio encoder
    alaw: alawenc: A Law audio encoder
    amrnb: amrnbenc: AMR-NB audio encoder

    Les codecs ne sont pas installés.

    Quelqu’un peut-il m’aider?

    Merci