Patrice Ferlet
Patrice Ferlet
Créateur de ce blog.
Publié le sept. 2, 2014 Temps de lecture: 6 min

Me suivre sur Mastodon

Serveur RSTP avec gstreamer et python

Avec mon petit raspberry-pi je me suis lancé le défit de streamer mon bureau sur la télé sans avoir à installer quoique ce soit sur la framboise. Utiliser gstreamer sur mon pc et hop… quelle idée… en fait, c’est pas simple du tout, mais j’ai trouvé la ruse du sioux. Python, gstreamer, et un peu de recherche, voilà ma solution.

Je vous préviens, c’est clairement améliorable. Ce billet de blog va juste vous servir à capter le principe. Et puis ça fait une bonne entrée en matière pour le RSTP via gstreamer :)

Bon, l’idée c’est que la capture du bureau est un flux “temps réel”. Si le client ne lit pas le flux, on a pas envie de garder le tampon. Ca parait bête comme ça, mais c’est pourtant tout le problème. Heureusement pour nous, il existe des protocoles de communication qui servent à ça. Un d’entre eux, assez connu, est le RTP (Real Time Protocol). Et vous savez quoi, avec gstreamer c’est pas si compliqué. Sauf que…

J’ai l’habitude de “gstreamer”, et je me suis dit (connement) qu’un flux via le protocole RTP suffirait. Que nenni mon garçon, c’est pas si simple !

On commence d’abord par le début, comment faire ouvrir une adresse de media au XBMC (ici sur raspberry pi).

La solution la plus “simple” si je puis dire est de créer un répertoire contenant un fichier avec l’extension “strm”. C’est un simple fichier texte qui contien une addresse de flux. Et, pas de bol, xbmc ne connait que 3 protocoles (à ce que je sais…):

  • http - on oublie, pas de flux temps réel
  • mms - mais bien sûr…
  • rtsp - c’est quoi ce “s” en trop ?

On va revenir à ce “S” de RSTP après… d’abord parlons du raspberry (ou tout xbmc…)

J’ai donc créé dans le “home” de mon utilisateur “pi” sur le raspberry, un répertoire “mes_streams”, et un fichier “test.strm” contenant l’adresse d’une vidéo (http). J’ai ajouté la source dans l’interface (le répertoire) et en ouvrant le fichier, Xbmc va bel et bien lire la vidéo.

Donc le fichier “test.strm” contient:

http://une.adresse.vers/un.fichier.avi

Hop, je lance ce fichier strm sur le raspberry et miracle, ça marche.

Maintenant on va parler de RTSP…

Bon je vous l’ai dit, j’ai été idiot de croire que faire du RTSP était facile. RTSP est un protocole de streaming (Real Time Streaming Protocol) qui utilise RTP (Real Time Protocol). Sauf que voilà, ajouter un “S” à RTP ne suffit pas :)

On va détailler, c’est le but de ce ticket.

RTP c’est le protocole qui encapsule les trames de media.

Gstreamer a une chiée de plugins pour créer des “payloads” RTP. Un Payload est un contenu formaté correctement pour définir les type de media transférés et comment les lire. Bref, un gros bouzin compliqué qu’on ne va pas creuser en détail.

Ainsi, pour créer un payload h264, on peut faire ça:

gst-launch videotestsrc ! x26enc ! rtph264pay ! ...

Ce qui va vous intéresser, c’est ce qui suit (les trois petits points que j’ai laissé). Car en définitive, là on crée bien un payload, mais on l’envoit nulle part.

Et c’est là que j’ai déchanté… en fait il n’existe pas de (librement) de plugin RTSP. J’avais commencé à tenter de balancer le payload dans un “udpsink” mais sans succés. Non monsieur, RTSP c’est pas si simple.

Parce que moi, je me suis dit “allez te prend pas la tête, balance ça en udp…”:

gst-launch videotestsrc ! x264enc ! rtph264pay ! udp host=127.0.0.1 port=1234

et je l’ouvrai avec:

gst-launch udpsrc port=1234 ! rtph264depay ! decodebin ! autovideosink

Tu parles ! déjà ça marche pas, car il faut définir le “caps” à lire, en plus le raspberry il comprend rien à “udp://

Et oui, en fait, le RTSP est un protocole de serveur spécifique qui sert justement à tout ça. M’a fallu un moment pour comprendre…

J’ai donc passé des heures à chercher, lire des docs, et je suis tombé sur des exemples en C. C’est donc avec dépis que je me dis “ok, on ne peut pas le faire avec gst-launch, mais on va se le faire en python”

Effectivement, il faut une librairie spécifique pour créer un serveur rtsp. Et heureusement pour nous, c’est en général packagé pour python, C/C++, et autres. Alors comme moi j’adore le python, on va pas se priver.

On commence par installer les packages, sur fedora ça donne:

sudo yum install gstreamer-python gstreamer-rtsp-python

Petite remarque… pas de possibilité avec gstreamer-1.0 apparement, à ce jour.

Bon, on y va… on crée le fichier “rtsp_test.py”

import pygst

pygst.require("0.10")

import gst
import gobject
import sys

from gst import rtspserver

server=rtspserver.Server()

factory = rtspserver.MediaFactory()
factory.set_launch(" videotestsrc ! ffmpegcolorspace ! x264enc ! rtph264pay name=pay0 pt=96 ")

server.get_media_mapping().add_factory('/test', factory)
server.attach()

try:
    gobject.MainLoop().run()
except KeyboardInterrupt :
    print "bye !"
    sys.exit()

J’explique. RTSP nécessiste une factory, c’est une usine à stream. Au moment où un client se connecte, il lance si besoin la création du stream. Ensuite on ajoute cette factory au serveur en lui spécifiant le chemin. Ainsi “/test” correspond au “test vidéo” que je fais (avec la mire videotestsrc)

Si je lance ce script, et que je vais ouvrir (avec vlc, totem, au choix) rtsp://127.0.0.1:8554/test alors je vois cette fameuse mire !

En mettant ce chemin dans le fichier test.strm de mon raspberry:

rtsp://192.168.1.29:8554/test

et bien ça fonctionne ! (192.168.1.29 est l’ip de mon pc, et j’ai ouvert le port 8554).

Ha au fait, pour ouvrir rapidos le port sur le pc:

firewall-cmd --add-port=8554/tcp --zone=public
firewall-cmd --add-port=8554/udp --zone=public

Quand le service de firewall se rechargera (avec reload…) ou au redémarrage du pc, ce port sera fermé. Si vous voulez garder la conf, ajoutez “–permanent” aux deux commandes précédentes.

Rest à ajouter un autre chemin, celui qui capture le bureau.

Ajoutez, juste après la création de la factory de test:

factorydesktop = rtspserver.MediaFactory()
factorydesktop.set_launch(" ximagesrc ! ffmpegcolorspace ! x264enc ! rtph264pay name=pay0 pt=96 ")
server.get_media_mapping().add_factory('/desktop', factorydesktop)

Et relancez le script.

Vous avez donc 2 chemins:

Reste à créer un autre fichier strm sur le raspberry-pi (ou votre XBMC encore une fois) et d’ouvrir ce dernier… attendez quelques secondes (la latence, j’ai pas trouvé comment la réduire) et hop voilà votre bureau sur votre télé :)

Bon voilà, le résultat est sympa, ça ne permet pas de faire grand-chose mais c’est intéressant de comprendre le principe.

Sachez que vous pouvez y mettre ce que vous voulez dans le flux RTP, là on a mis de la vidéo (la capture de bureau ou la mire de test), mais les “payloader” RTP de gstreamer sont nombreux. On peut donc streamer la musique, le son du pc, des images, etc… Il suffit de savoir faire un pipeline gstreamer. J’ai traité ça ici http://metal3d.org/ticket/2012/08/13/didacticiel-gstreamer et là http://metal3d.org/ticket/2012/08/14/gstreamer-la-suite

comments powered by Disqus