Serveur RSTP avec gstreamer et python

02/09/2014

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

Ça peut vous intéresser aussi


Didacticiel GStreamer

Gstreamer est un framework extrêmement puissant, bien pensé et vraiment utile ...


Utiliser la reconnaissance vocale de Google

Et si on se faisait une petit application de reconnaissance ...


Python map zip lambda et filter

Python est un langage fort de principes de développement permettant ...


OpenOffice en mode serveur

Il est parfois compliqué de créer des documents dignes de ...

Merci de m'aider à financer mes services

Si vous avez apprécié cet article, je vous serai reconnaissant de m'aider à me payer une petite bière :)

Si vous voulez en savoir plus sur l'utilisation de flattr sur mon blog, lisez cette page: Ayez pitié de moi

Commentaires

Ajouter un commentaire

Ajouter un commentaire

(*) Votre e-mail ne sera ni revendu, ni rendu public, ni utilisé pour vous proposer des mails commerciaux. Il n'est utilisé que pour vous contacter en cas de souci avec le contenu du commentaire, ou pour vous prévenir d'un nouveau commentaire si vous avez coché la case prévue à cet effet.