Aujourd’hui, je donne la vue à mon PiRobot. Ce n’a pas été aisé. Pour se faire j’utilise les technologies GStreamer ainsi que les librairies de VLC Media Player. Une partie se couronne de succès, tandis que la seconde partie ouvre sur de nouvelles problématiques. Wait&See…

 

 

 

1. Côté RPi – Installation de GStreamer

Tout d’abord, il est important d’étendre le système de fichier à l’ensemble de la carte SD et d’activer la caméra du Raspberry Pi. Pour se faire, on se rends dans raspi-config et on réalise un extend filesystem. Ensuite, dans les périphériques, on vérifie que la camera module soit bien activée.

sudo raspi-config

Après avoir finis ces opérations, le Raspberry Pi nécessitera un redémarrage du système pour que cette nouvelle configuration soit prise en compte.

Après le redémarrage du Raspberry Pi, on peut tester la PiCaméra grâce à la commande suivante :

raspivid -t 10000 -p 0,0,640,480 -o mavideo.h264

 

Une fois la capture vidéo testée, je peux enfin passer à l’installation de GStreamer. GStreamer est un framework permettant de rediffuser des flux audio et vidéo dans un système de « pipelines » d’encodage et de décodage de flux. Cela permet entre autre d’encoder un flux vidéo à la volée afin de la streamer sur un autre support réseau. C’est extrêmement bien optimisé sur Raspberry, car le CPU n’est que très peu utilisé lors d’une diffusion (environ 2%), l’encodage étant principalement réalisé par la partie GPU du Raspberry (à 25% de sa capacité en mode console). L’image est donc encodée, envoyée sur le réseau, puis décodée par notre client :-).

Exemple d’un pipeline GStreamer (src : Wikipedia GStreamer, ScotXW)

Exemple d’un pipeline GStreamer (src : Wikipedia GStreamer, ScotXW)

GStreamer repose sur de nombreux outils (encodeurs, décodeurs, filtres, protocole réseaux) ce qui nécessite l’installation de nombreux paquets.

Composition de l’environnement GStreamer (src : Wikipedia GStreamer, ScotXW)

Composition de l’environnement GStreamer (src : Wikipedia GStreamer, ScotXW)

Bon, trêve de bavardages, installons tout ça grâce aux commandes toutes préparées pour l’occasion :

sudo apt-get install gstreamer-1.0
sudo apt-get install gstreamer1.0-tools

 

Bon, l’installation va être longue… très longue… Ça m’a pris plus de 2h à tout installer sur le PiRobot !

Après ça, je redémarre le Raspberry Pi.

Je lance le flux streamé grâce à la commande suivante :

~ raspivid -n -w 1280 -h 720 -b 1000000 -fps 15 -t 0 -o – | gst-launch-1.0 -v fdsrc ! h264parse ! rtph264pay config-interval=10 pt=96 ! udpsink host=<remote_ip> port=<listen_port>

 

Les personnes qui ont lu cet article ont aussi lu :  5 minutes pour créer son hotspot Wifi sur Raspberry Pi !

Avec remote_ip : IP du PC qui va recevoir le flux vidéo.
Et listen_port : Port d’écoute du flux vidéo.

2. Côté Windows – Installation de GStreamer et premiers tests !

Pour Windows, c’est bien plus simple et rapide !

On télécharge et on installe GStreamer pour Windows.

On ouvre l’invite de commande Windows (CMD), on se place dans le répertoire GStreamer. Pour ma part, j’ai installé GStreamer directement dans un dossier C:\gstreamer\. Donc dans l’invite aux commandes Windows, je fais un :

cd C:\gstreamer\1.0\x86_x64\bin\

Je me retrouve donc dans le dossier applicatif de GStreamer. D’ici on peut lancer la commande :

gst-launch-1.0 -v udpsrc port=9000 caps=”application/x-rtp, media=(string)video, clock-rate=(int)90000, encoding-name=(string)H264″ ! rtph264depay ! avdec_h264 ! videoconvert ! autovideosink sync=f

 

Si tout fonctionne bien, le pipeline vidéo s’ouvre, le cache vidéo est créé et une nouvelle fenêtre s’ouvre.

Hello PiRobot ! :-)

Hello PiRobot ! 🙂 (j’ai fait un GIF, mais en vrai, c’est fluide pareil ^-^)

La retransmission en wifi s’effectue via mon réseau local (je ne suis pas encore en ad hoc à ce stade du projet). J’ai testé la retransmission sur deux soirs. Un soir, le wifi de ma box était sollicité par quelques appareils, j’ai pu voir quelques lags. En temps calme, la retransmission est fluide. Le décalage image retransmise/réalité est très faible (inférieur à 1 seconde !), ce qui est parfait pour mon application ! Donc en ad-hoc, je serais forcément performant sur la retransmission vidéo ! Et le tout en 720p bien évidemment ! 🙂

Parlons maintenant intégration dans l’application PiRobot Client… (autant partir sur du full embedded :-D).

3. Intégration dans le PiRobot Client

L’objectif ici est d’intégrer la vidéo dans cet espace :

En plein milieu, ici :-)

En plein milieu, ici 🙂

Ma première stratégie étant de passer par la librairie Vlc.DotNet, qui permet d’utiliser les bibliothèques de VLC Media Player. J’ai déjà utilisé ce contrôle auparavant dans une autre application, d’où mon choix d’opter pour cette technologie.

3.1. Passage par la librairie Vlc.DotNet

Le package et les dépendances de Vlc.DotNet sont trouvables dans le gestionnaire de paquets NuGet inclus dans Visual Studio :

J’ai juste installé Vlc.DotNet.Wpf dans le projet. Les dépendances se sont rajoutées automatiquement.

J’ai juste installé Vlc.DotNet.Wpf dans le projet. Les dépendances se sont rajoutées automatiquement.

Dans la description de la page Xaml, j’ajoute ce descripteur :

xmlns:wpf=”clr-namespace:Vlc.DotNet.Wpf;assembly=Vlc.DotNet.Wpf”

 

Et j’insère le contrôle WPF directement dans le code XAML :

<wpf:VlcControl x:Name=”video”/>

Côté code behind, plusieurs morceaux de code sont à ajouter :

Lignes à ajouter pour composant VLC
//constructeur de ma classe
		public Pilotage()
        {
            InitializeComponent();
            this.sliderCtrlG.ValueChanged += new EventHandler(SliderCtrlG_ValueChanged);
            this.sliderCtrlD.ValueChanged += new EventHandler(SliderCtrlD_ValueChanged);

			//On ajoute ces 2 lignes :
            video.MediaPlayer.VlcLibDirectoryNeeded += OnVlcControlNeedsLibDirectory;
            video.MediaPlayer.EndInit();
        }

//On ajoute ensuite ces méthodes :

		private void OnVlcControlNeedsLibDirectory(object sender, Vlc.DotNet.Forms.VlcLibDirectoryNeededEventArgs e)
        {
            var currentAssembly = Assembly.GetEntryAssembly();
            var currentDirectory = new FileInfo(currentAssembly.Location).DirectoryName;
            if (currentDirectory == null)
                return;
            if (AssemblyName.GetAssemblyName(currentAssembly.Location).ProcessorArchitecture == ProcessorArchitecture.X86)
                e.VlcLibDirectory = new DirectoryInfo(System.IO.Path.Combine(currentDirectory, @"lib\x86\"));
            else
                e.VlcLibDirectory = new DirectoryInfo(System.IO.Path.Combine(currentDirectory, @"lib\x64\"));
        }

		//Evenement suite à appui sur bouton Play.
        private void OnPlayButtonClick(object sender, RoutedEventArgs e)
        {
            video.MediaPlayer.Play(new Uri("rtsp://mpv.cdn3.bigCDN.com:554/bigCDN/definst/mp4:bigbuckbunnyiphone_400.mp4"));
        }

Je compile et je fais un essai avec une vidéo de démo qui est chargée grâce à une URL.

Cette animation sert de base à beaucoup de testeurs de stream vidéo :-)

Cette animation sert de base à beaucoup de testeurs de stream vidéo 🙂

La vidéo est chargée, mise en cache et lue par notre contrôle Vlc.DotNet.

Les personnes qui ont lu cet article ont aussi lu :  [PiRobot] Partie 7.5 - Retour caméra dans l'application !

Idée : Charger un fichier .sdp (Session Description Protocol) disponible dans le dossier de l’application. Ce fichier contient l’ensemble des paramètres nécessaires à VLC pour décoder un flux streamé : l’adresse IP du flux, le port d’écoute, le type de décodage, etc…

Pour se faire, je réalise un test avec les paramètres recommandé pour un flux vidéo h264 dans le fichier .sdp :

v=0
m=video <port d’écoute> RTP/AVP 96
c=IN IP4 <IP de la source vidéo>
a=rtpmap:96 H264/90000

 

Problème : VLC ne « capte » que la première image du flux réceptionné. La retransmission du flux reste bloquée à cette première image. Cette image est parfaitement réceptionnée, ce qui m’indique qu’elle a bien été décodée. Cependant, le flux ne suit pas.

Après de nombreuses recherches sur le thème, il s’avère qu’un bug dans les librairies Live555 utilisées par VLC empêcherait la lecture d’un flux réseau décodée en h264… J’utilise la dernière version de VLC Media Player : 2.2.4.

J’ai donc réalisé des essais avec plusieurs profils .sdp. Cela n’a guère arrangé les choses. Le bon profil semble être celui que j’ai choisi (je me suis même tapé la documentation pour le profil SDP du flux H264 disponible ici : https://tools.ietf.org/html/rfc6184#section-8.2).

Ensuite j’ai réalisé les mêmes essais avec une version Nightly de VLC Media Player. VLC Media Player Beta 3.0.0. Toujours sans aucun succès. Il me faut donc me rabattre sur d’autres stratégies pour intégrer la vidéo à mon application.

3.2. Stratégies à venir

Je ne pensais pas rester bloqué aussi longtemps sur la partie vidéo du projet. Elle me donne du fil à retordre ! Comme disais Thomas Edison, le meilleur moyen de réussir, c’est toujours d’essayer encore une fois !

Pour ce faire plusieurs possibilités :

  • Passer par la librairie GStreamer-Sharp dans PiRobot Client
    • Technologie Mono (.NET) développée à la base pour Linux mais devrait être compatible Windows.
    • Technologie que je ne connais pas.
    • Ne possède pas de contrôle natif en WPF.
  • Monter un serveur RTSP sur le Raspberry Pi pour ouvrir nativement le flux en MPEG sur VLC et Vlc.DotNet
    • Nécessite beaucoup de bande passante car vidéo non compressée => conséquence : grande baisse de la qualité pour un débit vidéo potable.
  • Utiliser un wrapper C++ OpenCV en C# pour tenter d’ouvrir le flux streamé en h264
    • Idée de dernière minute
    • Quelques exemples sur le net
    • Ouvre aux possibilités offertes par OpenCV : reconnaissance de formes, de personnes, etc…

 

Ressources

BenTek.

Pin It on Pinterest

Shares
Share This