URL: https://linuxfr.org/news/conference-gstreamer-2017-oxydation-de-gstreamer Title: Conférence GStreamer 2017 : Oxydation de GStreamer Authors: fengalin bubar🦥, Davy Defaud, palm123, Nÿco et Benoît Sibaud Date: 2017年11月06日T10:42:47+01:00 License: CC By-SA Tags: gstreamer et rust Score: 35 _Rustifiez votre multimédia !_ Voici une traduction de la présentation [_Oxidising GStreamer — Rust out your multimedia!_](https://gstconf.ubicast.tv/videos/oxidising-gstreamer/), qui a eu lieu le 22 octobre 2017 à Prague dans le cadre de la [Conférence GStreamer 2017](https://gstconf.ubicast.tv/channels/#gstreamer-conference-2017). Merci à [Sebastian Dröge](https://github.com/sdroege) pour cette présentation et pour son autorisation de traduction. ![Logo de GStreamer](https://gstreamer.freedesktop.org/data/images/artwork/gstreamer-logo.svg) ![Logo de Rust](https://www.rust-lang.org/logos/rust-logo-blk.svg) ---- [Journal à l’origine de la dépêche](https://linuxfr.org/users/fengalin/journaux/conference-gstreamer-2017-oxydation-de-gstreamer) [Planches de la présentation, au format PDF ](https://coaxion.net/~slomo/talks/gstconf-2017/Rust.pdf) [Projet GStreamer](https://gstreamer.freedesktop.org/) ---- --- # Résumé Dans la suite logique de ma présentation de l’année dernière, je vais vous tenir au courant de ce qu’il s’est passé depuis autour de GStreamer pour le développement d’applications et d’extensions en Rust. C’est maintenant le bon moment pour utiliser Rust dans le cadre de vos développements GStreamer au lieu du C ou du C++ et même à la place de Python ou de C#. Vous bénéficierez ainsi de plus de sûreté, d’une meilleure productivité et pourquoi pas d’un certain plaisir à développer, tout en conservant un haut niveau de performance et un faible surcoût qui ne se rencontrent généralement qu’en utilisant le C ou le C++ et avec en plus la possibilité d’exécuter votre application sur des équipements embarqués. Alors que l’apprentissage d’un nouveau langage peut sembler superflu et qu’il y a trop de langages de nos jours, je vais vous montrer pourquoi vous devriez vous en préoccuper et pourquoi le langage en question semble être un candidat parfait pour les applications multimédias et pour plein d’autres cas d’utilisations sur environnements embarqués. Je vais vous indiquer comment vous mettre le pied à l’étrier et vous présenter quelques courts exemples de code. _Sebastian Dröge est un développeur de logiciels libres et l’un des mainteneurs et développeurs principaux de GStreamer. Il est impliqué dans le projet depuis plus de dix ans. Il contribue également à plusieurs autres projets tels que Debian, GNOME et WebKit. Après son _master_ en sciences des Systèmes d’Information à l’Université de Paderborn en Allemagne, il commence à travailler en tant qu’entrepreneur autour de GStreamer et des technologies connexes. Sebastian est l’un des fondateurs de Centricular, une société proposant des services de conseil. Depuis son nouveau domicile en Grèce, il travaille à l’amélioration de GStreamer et de l’écosystème du logiciel libre en général._ _En plus des sujets relatifs au multimédia, Sebastian s’intéresse au traitement numérique du signal, aux langages de programmation, à l’apprentissage automatique, aux protocoles réseau et aux systèmes distribués._ # Introduction, Qui ? Aujourd’hui, nous allons parler de l’_oxydation de GStreamer_ ou comment _« rustifier » votre multimédia_. Je suis Sebastian Dröge, je participe au développement de GStreamer depuis 2006 environ. Actuellement, je suis en charge de la préparation des versions. J’ai touché à pratiquement tout dans GStreamer. Je suis aussi l’un des cofondateurs de Centricular. Nous proposons du conseil autour de GStreamer et des logiciels libres de cette catégorie. C’est tout ce que j’ai à dire à mon sujet, passons au contenu. # Quoi ? Je vais vous parler de Rust et de GStreamer. Je suppose que certains d’entre vous ne connaissent pas Rust, je vais donc commencer par une courte introduction. Si vous souhaitez approfondir, rendez‐vous sur le [site Web](https://www.rust-lang.org/fr-FR/), la documentation est de très bonne qualité. Je ne vais pas vous expliquer ce qu’est [GStreamer](https://gstreamer.freedesktop.org/), je pense que vous le savez déjà. J’ai déjà eu l’occasion de vous parler de ce sujet l’année dernière, je vais donc évoquer ce qu’il s’est passé depuis, puis entrer un peu plus dans les détails sur la manière de développer des applications et des extensions GStreamer avec Rust. Je vous montrerai aussi quelques exemples de code. Enfin, je vous parlerai de ce à quoi on peut s’attendre pour l’avenir. # Qu’est‐ce que Rust ? ## Définition C’est « un langage de programmation système qui vise à garantir un typage sûr et une gestion sûre de la mémoire ». Les développements ont commencé chez Mozilla. Tout est _open source_. De nos jours, le langage bénéficie d’une large communauté et une bonne proportion des développeurs n’est plus employée par Mozilla. C’est une communauté assez diversifiée. La conception du langage suit les pratiques du développement _open source_. Ils utilisent un [processus d’appel à commentaires](https://github.com/rust-lang/rfcs) (_Request For Comments_) pour toutes les modifications du langage. Chaque membre de la communauté peut apporter des éléments à la discussion, c’est très transparent... ça me plaît bien ! Qu’est‐ce que ces mots signifient au juste et plus particulièrement « gestion sûre de la mémoire » ? En fait, c’est un peu l’argument de vente de Rust. On sait tous ce qui peut arriver en C, si on déréférence le mauvais pointeur ou si l’on dépasse les limites d’un tableau : le truc part à veau‐l’eau. Rust empêche cela. Le typage est aussi beaucoup plus sûr qu’en C. Le C apporte un peu de sécurité pour le typage, mais bon... passons ! Selon moi, la caractéristique la plus importante est qu’il s’agit d’un langage de programmation système. Il travaille vraiment près du matériel, il n’y a pas de gros environnement d’exécution. Tout ce que vous écrivez tourne vraiment sur le processeur. Toutes les abstractions que le langage propose sont sans surcoût, du moins c’est la manière dont ils en font la pub, et je le crois aussi. Mais je dirais que c’est à vous de le vérifier par vous‐même. Une autre caractéristique importante est l’existence d’un système très puissant permettant l’interopérabilité avec des bibliothèques écrites en C. Quel que soit l’existant écrit en C dont vous disposez, vous pouvez l’utiliser depuis votre code écrit en Rust. ## De la programmation bas niveau avec un air de programmation haut niveau Si vous regardez le code, cela ressemble parfois à ce que vous écririez en JavaScript ou en Python ou avec un autre langage d’orchestration (_scripting_). Ça peut sembler de plus haut niveau que ce que vous obtiendriez en C++. Néanmoins, on parle bien de programmation bas niveau : vous conservez le contrôle sur tout si vous le souhaitez. Vous pouvez décider d’où allouer la mémoire — doit‐on utiliser le tas ou la pile — de quand allouer, de quand désallouer. Mais l’important, c’est que vous n’avez pas à vous en soucier. Vous pouvez le faire... vous pouvez aussi, dans une certaine mesure, l’ignorer. Ça n’implique pas une gestion manuelle de la mémoire, c’est le compilateur qui s’assure que vous n’êtes pas en train de faire quelque chose de stupide. Comme je l’ai dit, Rust ressemble un peu à Python ou à d’autres langages d’orchestration. L’une de ses caractéristiques importantes est l’inférence de type : vous n’êtes pas obligés de préciser systématiquement le type des variables. Généralement, le compilateur se débrouille tout seul, tout en vous garantissant un typage sûr. C’est quelque chose dont le C++ dispose aussi aujourd’hui. Vous avez également d’autres caractéristiques que l’on trouve plutôt dans les langages d’orchestration ou les langages fonctionnels, mais qui sont disponibles pour de la programmation système. ## Domaines Rust est actuellement utilisé pour : * du développement d’applications Web. Qui essaierait de développer des applications Web en C aujourd’hui ? Personne ? En revanche, vous pouvez en écrire en Rust ; * on l’utilise aussi pour le développement de jeux, la programmation de serveurs, etc ; en gros, tous les domaines pour lesquels vous utiliseriez le C++ ; * des gens écrivent aussi des systèmes d’exploitation en Rust, il y en a actuellement deux ou trois en cours d’écriture ; * certains l’utilisent pour des développements vraiment très proches du matériel, comme de la programmation de micro‐contrôleurs. Rust couvre tout le spectre des cas d’utilisation pour lesquels vous utiliseriez un langage de programmation système. Par ailleurs, Rust est désormais utilisé et poussé par des acteurs de l’industrie. Vous pouvez consulter [_cette page_](https://www.rust-lang.org/fr-FR/friends.html) pour découvrir les sociétés qui déclarent publiquement utiliser Rust. Il y a des noms tels que Dropbox, npm, Atlassian, Coursera, Canonical et bien d’autres. ## Rust est ce que le C++ aurait dû être Selon moi, Rust est ce que le C++ aurait dû être. Bon, un certain nombre d’années se sont écoulées, les gens ont appris de l’histoire. Aujourd’hui, je l’utiliserais pour n’importe quel projet pour lequel j’aurais utilisé le C++ ou même le C auparavant. # Pourquoi Rust ? ## De la difficulté d’écrire du code sûr en C et en C++ Il est difficile d’écrire du code sûr en C et en C++. Toute personne pouvant dire qu’elle n’a pas subi d’erreur de segmentation durant l’année écoulée n’a probablement programmé ni en C, ni en C++. Vous pouvez facilement faire quelque chose qui fera planter votre système et permettra à un attaquant de prendre le contrôle de la machine de l’utilisateur, sans même vous rendre compte que ce que vous avez écrit n’est pas sûr. La gestion des erreurs est plutôt compliquée avec ces deux langages. En C, on s’arrange généralement avec les valeurs de retour, vous pouvez facilement les ignorer et personne ne s’en offusquera ! Ça va juste échouer à l’exécution avec des symptômes bizarres. En C++, vous avez bien les exceptions, qui bénéficient de leur propre lot de problèmes. En général, ça entraîne une certaine verbosité qui finit par masquer ce que le programme fait vraiment et rend la tâche encore plus difficile pour faire en sorte que le code soit sûr. ## Laissez le compilateur vous aider à écrire du code correct et rapide Il y a un inconvénient à cela : le compilateur risque de beaucoup se plaindre ! Il vous dira des choses comme : « non, tu ne peux pas faire ça, ce n’est pas sûr ». Ça va vous prendre plus de temps avant de pouvoir exécuter votre code. Mais une fois qu’il s’exécute, vous savez qu’un gros paquet de problèmes ne vont pas se présenter parce que le compilateur vous aura déjà prévenu : « ici, ici et là, tu ne peux pas faire ça, tu devrais faire ça autrement ». Avec le C ou le C++, en général, on fait cela à l’exécution et on sait tous combien il est pénible de déboguer des trucs à l’exécution. Rust utilise un modèle très puissant de [possession](https://doc.rust-lang.org/book/second-edition/ch04-00-understanding-ownership.html) et de [mutabilité](https://doc.rust-lang.org/book/second-edition/ch03-01-variables-and-mutability.html). Il identifie en permanence le possesseur d’une variable et trace si celle‐ci est accessible en lecture seule ou en lecture et en écriture. Par défaut, toute variable est accessible en lecture seule. C’est le contraire de ce que font les C et C++. Avec ces langages, vous pouvez préciser qu’une variable est constante, mais par défaut elle est visible en lecture et en écriture. Rien qu’avec cette approche (chaque variable en lecture seule par défaut) le code est déjà plus sûr et il est plus difficile d’introduire des bogues. Par défaut avec Rust, le code doit respecter les contraintes de sûreté. Ce qui veut dire que si vous ne sortez pas du bac à sable, votre programme ne plantera pas... Du moins, il ne produira pas d’erreur de segmentation. Vous pouvez toujours introduire des erreurs de logique qui feront que votre programme ne fera pas ce qu’il était censé faire, mais au moins il ne plantera pas. On bénéficie aussi d’une certaine [sécurité pour les fils d’exécution](https://doc.rust-lang.org/book/second-edition/ch16-00-concurrency.html). Vous indiquez si votre type de donnée est sûr pour le partage entre fils d’exécution et/ou s’il peut être transféré d’un fil d’exécution à l’autre. Le compilateur se chargera ensuite de vérifier que ces contraintes sont bien respectées. Comme je le disais dans la section relative aux erreurs, Rust vérifie la bonne [prise en compte des erreurs](https://doc.rust-lang.org/book/second-edition/ch09-00-error-handling.html). Vous ne pouvez pas ignorer les erreurs, vous devez les gérer. Mais la mécanique qui permet de le faire est telle que ça en devient sympa. Ça n’a rien à voir avec ce que l’on doit faire en C : « si ceci échoue, nettoie ceci et sors, si ceci échoue, nettoie cela et sors »... Dans le cas de Rust, c’est vraiment pratique à utiliser. ## L’issue de secours : _unsafe_ Il y a une issue de secours : le [mot clé `unsafe`](https://doc.rust-lang.org/book/second-edition/ch19-01-unsafe-rust.html). Dès qu’il introduit une section de code, vous pouvez faire ce que vous voulez dans cette section, comme vous le feriez en C. Vous pouvez déréférencer des pointeurs, vous pouvez créer des pointeurs à partir de nombres, tout ce qui vous passe par la tête. L’idée principale est que c’est déclaratif. Vous savez alors que vous avez une petite partie de votre code qui n’est pas sûre. Si ensuite votre programme plante, ça viendra de là ! Et si vous voulez relire votre code, vous saurez que ce sera par là qu’il faudra commencer. ## Un langage de haut niveau qui n’est pas juste une glorification de l’assembleur ... comme c’est le cas pour le C. Une autre différence notable par rapport au C est que Rust dispose d’une bonne [bibliothèque standard](https://doc.rust-lang.org/std/). Elle contient tout un tas de structures de données. On sait tous qu’en C, la bibliothèque standard ne comporte aucune structure de données. Chacun développe ses propres listes chaînées, ses propres tableaux associatifs. La bibliothèque standard de Rust fournit des implémentations très efficaces de toutes les structures de données, d’algorithmes, etc. Avec tous les langages d’orchestration récents, on trouve des petits outils pour récupérer les dépendances. Pour Nodes.js vous avez `npm`, pour Python il y a `pip`. Rust [propose la même chose](http://doc.crates.io/), vous pouvez facilement dire : « je veux telle et telle bibliothèques » et l’outil ira chercher les versions dont vous avez besoin, les compilera et les inclura lors de la construction de votre propre logiciel. Cet outil facilite vraiment l’utilisation des dépendances externes. Ça ne tourne pas au cauchemar comme en C ou en C++ où chaque chose fonctionne à sa manière et où il est très difficile de dépendre de quoi que ce soit. En fin de comptes, ça a poussé pas mal de bibliothèques en C et en C++ à réimplémenter plein d’algorithmes qui existaient déjà partout ailleurs... Mais bon, c’est tellement compliqué de tirer ces dépendances que l’on réimplémente les fonctions nous‐mêmes. # Pourquoi devrait‐on s’en préoccuper ? ## L’analyse syntaxique de formats de médias ... venant de sources non sûres. Je passerai assez vite sur le sujet, nous sommes déjà tous au courant des problèmes. L’analyse syntaxique (_parsing_) des formats multimédias n’est pas chose facile, particulièrement en C ou en C++. Par ailleurs, les données en entrée viennent rarement de sources de confiance. Certaines sources peuvent même proposer des médias qui contiennent intentionnellement quelque chose qui peut nuire à votre machine en exploitant des problèmes dans les logiciels que vous utilisez. C’est pour cela que je pense que, pour nous, Rust serait un bon langage. Il permet d’éviter beaucoup de problèmes de sécurité courants. Tous les problèmes de sécurité que nous avons rencontrés dans GStreamer les années passées auraient pu être évités en utilisant Rust. Je pense que c’est déjà assez éloquent. Et donc, l’analyse syntaxique est compliquée en C. Il n’y a pas beaucoup de moyens d’abstraction, alors qu’avec Rust on dispose de tout un tas de possibilités pour [représenter des abstractions](https://doc.rust-lang.org/book/second-edition/ch17-00-oop.html). Il est même possible d’écrire des grammaires formelles. Du moins, quelque chose qui ressemble à de la grammaire formelle. Le code correspondant est ensuite généré automatiquement, ce qui rend la compréhension de ce que fait ce code vraiment aisée en comparaison à du code écrit à la main. ## La maîtrise des fils d’exécution concurrents est difficile ... surtout en C ! Rust dispose de tout un tas de [fonctionnalités pour nous aider](https://doc.rust-lang.org/book/second-edition/ch16-00-concurrency.html) lorsque l’on développe dans un environnement à plusieurs fils d’exécution. GStreamer exploite massivement les fils d’exécution concurrents, ça pourrait donc être une bonne idée... ## Programmer comme si on était en 2017 Et par‐dessus tout, nous programmerions comme si nous étions en 2017 et non dans les années 60 du siècle dernier : * les langages modernes offrent toute une variété de fonctionnalités et d’outils ; * nous ne sommes plus obligés de réinventer des ustensiles de base comme `GObject` ; * nous pourrions attirer de nouveaux développeurs. Plus personne n’a vraiment envie d’apprendre le C de nos jours et encore moins des choses comme `GObject`, qui entraîne plein de copier‐coller partout. C’est plutôt difficile à prendre en main pour les nouveaux contributeurs. ## Cependant, ce n’est pas la panacée Tout code non trivial comporte des bogues. Mais au moins, une importante classe de bogues peut être évitée. # État, il y a un an ## Les _bindings_ GStreamer L’année dernière, nous disposions d’un [ensemble de _bindings_ Rust pour GStreamer](https://github.com/arturoc/gstreamer1.0-rs). Cet ensemble était écrit à la main et ne s’intégrait pas très bien avec le reste du code Rust. Par ailleurs, il imposait aux utilisateurs d’utiliser des sections avec le mot clé `unsafe`, ce qui est tout simplement rédhibitoire. Il divergeait aussi vis‐à‐vis de certains concepts de GStreamer, ce qui le rendait difficile à appréhender et il était incomplet. Pas mal de gens utilisaient ces _bindings_, mais ce n’était vraiment pas idéal. Nous avions aussi ce dont je vous parlais la dernière fois : une manière expérimentale d’écrire des extensions GStreamer. Ce projet était également écrit à la main, il était très incomplet et difficile à faire évoluer. Oublions tout cela, nous sommes en 2017 maintenant ! # Écrire des applications GStreamer avec Rust ## Les nouveaux _bindings_ GStreamer ### Comparaison par rapport aux anciens _bindings_ Les [nouveaux _bindings_ Rust pour GStreamer](https://github.com/sdroege/gstreamer-rs) sont en grande partie générés à partir des informations d’introspection de `GObject`. Malheureusement, certaines choses ne peuvent pas être générées automatiquement. Mais, globalement, ça facilite bien l’évolutivité. Ils remplacent complètement les anciens _bindings_. Ils ne sont pas compatibles au niveau interface de programmation, mais ça ne devrait pas être difficile de modifier un projet basé sur les anciens _bindings_ pour qu’il utilise les nouveaux. Une évolution importante du point de vue des applications est qu’il n’est plus nécessaire de passer par du code marqué _unsafe_... Sauf si le développeur le veut, bien sûr, ou s’il veut s’intégrer avec X11, qui n’est pas sûr par conception, mais c’est un autre problème ! Les nouveaux _bindings_ couvrent pratiquement tous les composants du cœur de GStreamer, ainsi que ceux des autres bibliothèques. Ils s’intègrent bien avec les bibliothèques des infrastructures [GLib](http://gtk-rs.org/docs/glib/) et [GTK](http://gtk-rs.org/docs/gtk/index.html), ce qui les rend sympas à utiliser ensemble. ### Un style idiomatique _rustien_ (en grande partie) Les _bindings_ sont écrits dans un style idiomatique _rustien_. Ils devraient être faciles à prendre en main par des développeurs habitués à Rust. Ils auront l’impression qu’il s’agit d’une vraie interface de programmation Rust. Et à la fois, les concepts des _bindings_ correspondent pratiquement trait pour trait aux concepts de GStreamer. Ce qui signifie que vous, en tant que développeurs GStreamer, aurez _seulement_ à apprendre un nouveau langage. En revanche, tous les concepts de GStreamer, c’est‐à‐dire comment l’interface de programmation fonctionne, restent les mêmes. ### Les objets Regardons rapidement quelques‐uns des points d’entrée des _bindings_. Dans GStreamer, nous avons tout un tas d’objets : les [`Element`](https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstElement.html)s, les [`Pad`](https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstPad.html)s, le [`Pipeline`](https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstPipeline.html), l’objet [`Clock`](https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstClock.html), etc. La manière dont ils sont représentés dans les _bindings_ est telle que vous retrouvez précisément les mêmes objets. Ils disposent d’une sorte de mécanisme semi‐automatique et sûr de comptage de références. Vous contrôlez toujours quand le compteur d’une référence est incrémenté, mais le compilateur se charge de vérifier que vous l’incrémentez bien quand c’est nécessaire. Ceci vous permet d’être alertés si vous faites des choses bizarres que vous n’auriez pas voulu faire. Donc, ce n’est pas complètement automatique, mais d’un autre côté, vous ne pouvez pas oublier de déréférencer quoi que ce soit. Quand un objet n’est plus dans la portée courante, quand il n’est plus nécessaire, il est automatiquement déréférencé et détruit au moment voulu. Dans GStreamer, nous utilisons l’héritage. Rust ne gère pas l’héritage : il n’y a pas de classes, ni de vraie notion d’héritage. À la place, on peut utiliser des _traits_. Cela peut sembler un peu compliqué, un peu bizarre, mais si vous utilisez l’interface Rust, vous allez vous rendre compte qu’elle fonctionne de la même façon que si vous utilisiez, par exemple, les _bindings_ C++ de GStreamer. Ça donne une sensation de quelque chose de naturel. Comme je l’ai déjà dit, il y a une sorte de sûreté des fils d’exécution (_thread safety_) et elle est contrôlée à la compilation. Par exemple, on sait tous que les `Element`s de GStreamer sont censés être _thread safe_, on peut donc les échanger entre fils d’exécution et on peut les partager entre plusieurs fils d’exécution. Le compilateur n’ira pas se plaindre de tels agissements. En revanche, quelque chose comme [`GstAdapter`](https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer-libs/html/GstAdapter.html) n’est pas _thread safe_. Donc, si vous tentez de l’utiliser dans d’autres fils d’exécution, vous allez devoir le migrer, car vous ne pouvez pas en disposer depuis deux fils d’exécution différents. Si vous faites cela, le compilateur vous dira : « non, tu ne peux pas faire ça ». C’est une caractéristique plutôt sympa. Vous disposez également de toute l’interface standard `GObject` de GStreamer. Vous retrouverez : les propriétés, les signaux, toutes les méthodes... Tout ce dont vous avez besoin. J’aurais dû mentionner ceci auparavant : tout est garanti contre l’utilisation inappropriée de pointeurs `NULL`. Il n’y a aucun pointeur `NULL` caché. Vous devez gérer explicitement tout ce qui peut être `NULL`, vous ne pouvez pas ignorer ce genre de problèmes. Donc, dans toute l’interface, lorsque quelque chose renvoie un `Element`, il y aura bien un `Element` derrière. Il est impossible qu’il ne soit pas disponible. Ça ne peut pas planter ensuite, vous ne pouvez pas vous retrouver face à un pointeur `NULL`. Et, bien sûr, si l’appel est susceptible d’échouer, vous devez gérer ce cas. Le compilateur ne vous laissera pas utiliser la valeur retournée sans avoir vérifié au préalable qu’elle est bien valide. ### Les _[MiniObject](https://gstreamer.freedesktop.org/documentation/design/miniobject.html)s_ Les `MiniObject`s sont probablement le recoin le plus obscur de GStreamer. Ils sont générés automatiquement dans la plupart des autres _bindings_, ce qui les rend un peu inhabituels vis‐à‐vis du langage cible. Avec Rust c’est différent : la plupart des concepts autour des `MiniObject`s correspondent à ce que l’on fait déjà en Rust. Par exemple, le concept de mutabilité des `MiniObject`s est tel que vous ne pouvez modifier un `MiniObject` que s’il n’est utilisé qu’à un seul endroit à un instant donné, sinon vous devez le copier. C’est quelque chose qui trouve un équivalent direct en Rust. Le compilateur vous empêchera de modifier des `MiniObject`s qui ne sont pas en mode écriture. À titre de comparaison, en C on a pas mal de code qui modifie des `MiniObject`s alors qu’ils ne sont pas en mode écriture. L’approche de Rust me semble présenter un avantage significatif. Les types basés sur les `MiniObject`s paraissent aussi typiquement _rustiens_. Ils comprennent les [`Caps`](https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstCaps.html), les [`Structure`](https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstStructure.html)s, même quelque chose comme [`GstFraction`](https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstValue.html#gst-value-set-fraction), qui semblait un peu bizarre à l’utilisation en Python par le passé, ressemble vraiment à quelque chose que vous auriez utilisé en Rust. ### Qu’est‐ce qui manque ? J’ai dit que la plupart du cœur de GStreamer était déjà disponible. Il manque encore : * [`GstMemory`](https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstMemory.html), [`GstAllocator`](https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstAllocator.html), [`GstMeta`](https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstMeta.html) et [`GstCapsFeatures`](https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstCapsFeatures.html), non pas parce qu’ils présentent une difficulté, mais plutôt parce que je n’en ai pas encore eu l’utilité et apparemment personne n’en a eu besoin pour le moment ; donc, si quelqu’un rencontre un problème pour lequel le besoin se fait sentir, criez, on pourra les ajouter à ce moment‐là ; * il manque aussi des trucs mineurs comme les [`TypeFinder`](https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer-plugins/html/gstreamer-plugins-typefind.html)s ; ils sont du même acabit : faciles à ajouter en cas de besoin ; * les objets dans la catégorie des [`GstControlBinding`](https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstControlBinding.html)s ; * à part pour celles du cœur, les bibliothèques des autres modules ne sont pas entièrement couvertes. Mais, par exemple, pour la bibliothèque [`Audio`](https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-libs/html/gst-plugins-base-libs-GstAudio.html), `GstAudioInfo` est disponible, pour la bibliothèque [`Video`](https://gstreamer.freedesktop.org/data/doc/gstreamer/1.8/gst-plugins-base-libs/html/gst-plugins-base-libs-gstvideo.html), vous avez déjà `VideoInfo` et `VideoFrame`. Il y aussi [`GstAdapter`](https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer-libs/html/GstAdapter.html), [`AppSrc`](https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-libs/html/gst-plugins-base-libs-appsrc.html) et [`AppSink`](https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-libs/html/gst-plugins-base-libs-appsink.html). Tout ce dont vous avez habituellement besoin est donc disponible et, pour le reste, criez et on l’ajoutera ! ### Est‐ce utilisable ? Oui ! Selon moi, tout est déjà très utilisable. Je l’utilise moi‐même pour pas mal d’applications de test afin de m’assurer que tout fonctionne correctement ou pour écrire des cas de test quand quelque chose ne marche pas. De part mon expérience, je peux dire que c’est facile et généralement plus rapide à écrire que l’équivalent en C. C’est facile à déboguer, ou du moins aussi facile à déboguer que le C. Vous pouvez toujours utiliser [`gdb`](https://www.gnu.org/software/gdb/), obtenir la pile d’appels, scruter les variables, etc. Ça marche de la même manière qu’avec du C. Et généralement, ça donne plus ou moins le même code machine que ce que vous obtiendriez avec du C. Si vous lisez ce que le compilateur produit, il est assez facile de savoir ce qui se passe, comment les correspondances avec le C se concrétisent. Donc c’est prêt à être utilisé ! ## Quelques exemples de code ### Création d’[`Element`](https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstElement.html)s Voici un exemple de création d’`Element`s. Ça ne devrait pas être trop difficile à lire : ``` Rust let pipeline = gst::Pipeline::new(None); // 1 let src = gst::ElementFactory::make("filesrc", None) .ok_or(MyError::ElementNotFound("filesrc"))?; // 2 let dbin = gst::ElementFactory::make("decodebin", None) .ok_or(MyError::ElementNotFound("decodebin"))?; ``` * En 1, on génère un nouveau `Pipeline`. Ici, on ne lui donne pas de nom particulier. En C, on passerait `NULL`, en Rust on indique `None`. On récupère toujours un `Pipeline`. Si vous regardez l’interface en C, vous verrez que ça ne renvoie jamais `NULL`, donc on récupère vraiment un `Pipeline`. * En 2, on veut construire une variable `src`. On utilise donc `gst::ElementFactory::make`, ce qui est très similaire à ce que vous feriez en C. L’objectif est de créer une source sur un fichier avec l’extension `filesrc`. Bien sûr, il peut arriver que l’extension `filesrc` ne soit pas disponible sur votre machine, cette fonction est donc susceptible d’échouer en renvoyant `None`. Vous pouvez indiquer comment gérer les différents cas avec la fonction `ok_or` : « si tout est `ok`, alors renvoie ce que la fonction `gst::ElementFactory::make` a généré, sinon renvoie un type d’erreur dédié ». Pour cela, vous pouvez créer une sorte d’énumération d’erreurs et préciser les différents cas tels que `ElementNotFound`, à quoi vous pouvez ajouter une variable. Dans notre cas, on a indiqué le nom de l’`Element`. À la fin de la ligne, on trouve un point d’interrogation. Il est là pour indiquer ceci : « en cas d’échec, sors de la fonction et renvoie l’erreur en question ». L’appelant peut donc gérer l’erreur et prendre les mesures appropriées, mais dans la fonction en question on s’arrêtera là en cas d’erreur. Bien sûr, il n’y aura pas de fuite mémoire, tout ce qui doit être déréférencé et détruit le sera automatiquement. ### Création de [`Caps`](https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstCaps.html) Voici maintenant un exemple de création d’un objet `Caps` : ``` Rust let caps = gst::Caps::new_simple( // 1 "video/x-raw", // 2 &[ // 3 ("format", "BGRA"), // 4 ("width", &(1080i32), // 5 ("height", &(720i32)), // 6 ("framerate", &gst::Fraction::new(30, 1)), // 7 ], ); ``` * en 1, vous utilisez `gst::Caps::new_simple` exactement comme en C ; * en 2, vous indiquez le nom, rien de spécial à signaler ici ; * en 3, vous fournissez un tableau de propriétés qui sont en fait des _tuples_ ; * en 5, je pense que ce qu’il faut retenir, c’est que vous n’indiquez pas seulement la valeur pour la propriété, vous devez aussi préciser son type. Assez souvent, c’est quelque chose qui tourne mal en C : les gens fournissent un entier non signé ou un entier sur 64 bits pour une propriété donnée et ça ne fonctionne pas comme prévu ensuite. Ici, vous devez être explicite. En interne, ça ne va pas créer d’objet `GValue`, si vous lisez le code généré, il sera très similaire à ce que vous auriez obtenu avec du C. Question d’un membre du public : > — L’esperluette est nécessaire dans ce cas ?
> — En fait, l’esperluette n’est pas indispensable ici. L’esperluette crée une référence, c’est comme un pointeur dont la valeur ne peut pas être `NULL`.
> — Et donc, elle indique si ta constante est statique ou non ?
> — En fait... Bon, parlons‐en après, cela nécessiterait d’entrer un peu plus dans les détails. En bref, l’esperluette introduit une référence et les références ne peuvent jamais être `NULL`. Le compilateur s’assure que cette valeur est toujours valide au moment où tu l’utilises. Donc, tu ne peux pas libérer ce qui en dépend, sinon ça ne sera pas accepté à la compilation. Mais, la raison exacte pour laquelle nous avons besoin d’une esperluette ici nécessiterait une explication dans laquelle je ne souhaite pas m’engager maintenant. Ça a un rapport avec le fait que chacun des éléments présente un type différent : en 4 il s’agit d’une chaîne de caractères, en 5 et 6 ce sont des entiers signés, en 7 on trouve une fraction. _N. D. L. T. : À ce stade de la présentation, Sebastian commence à être à court de temps. Il décide donc de passer quelques exemples. Vous pouvez les retrouver dans les [planches au format PDF](https://coaxion.net/~slomo/talks/gstconf-2017/Rust.pdf)._ ### Le signal [`pad-added`](https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstElement.html#GstElement-pad-added) Le signal `pad-added` fait partie des choses utilisées fréquemment. Voici un court exemple utilisant ce signal : ``` Rust let pipeline = _; // 1 decodebin.connect_pad_added(move |dbin, src_pad| { // 2 let sink = gst::ElementFactory::make( // 3 "fakesink", // 4 None // 5 ).unwrap(); // 6 pipeline.add(&sink); // 7 let sink_pad = sink.get_static_pad("sink").unwrap(); // 8 src_pad.link(&sink_pad); // 9 sink.sync_state_with_parent(); // 10 }); ``` * En 2, on utilise un [_decodebin_](https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-plugins/html/gst-plugins-base-plugins-decodebin.html) qui a été créé auparavant. On le connecte au signal `pad-added` en lui passant une fermeture (_closure_). En C, vous auriez à définir une nouvelle fonction, sa déclaration, tout cette verbosité... Ici, vous pouvez écrire la fonction directement avec la connexion au signal. Tout ce qui est disponible en amont peut être capturé dans la fermeture. Par exemple, le `pipeline` défini en ligne 1 est utilisé à l’intérieur de la fermeture à la ligne 7. Rust s’assure que tout ce qui est capturé est utilisé en respectant les règles de sûreté. Vous pouvez être amenés à devoir copier les objets pour les utiliser à l’intérieur d’une fermeture parce qu’il peut y avoir des cas pour lesquels l’utilisation du même objet ne serait pas sûre. Mais, généralement, c’est très pratique à utiliser et vous pouvez simplement écrire vos gestionnaires de signaux directement sans code superflu. Vous vous demandez peut‐être à quoi correspond ce truc avec les `|` en ligne 2. C’est la façon dont on définit une fermeture : vous retrouvez les arguments `decodebin` et `src_pad` qui correspondent à ceux passés lors de l’invocation du signal `pad-added`. * À l’intérieur de la fermeture, on crée un `fakesink` (lignes 3 à 6), * que l’on ajoute au `pipeline` (ligne 7). * On récupère ensuite le `pad` « `sink` » (ligne 8), que l’on relie au `pad` « `src` » du `decodebin` (ligne 9). * Finalement en 10, on lance la synchronisation. Toute personne ayant déjà utilisé GStreamer devrait être en mesure de lire cet exemple et de comprendre exactement tout ce qu’il s’y passe. Réaction d’un membre du public :> — _inaudible_
> — Ce n’est pas ton cas ?
> — Est‐ce que Rust permet à `gst_element_sync_state_with_parent` de devenir _thread safe_ ? (_rires_)
> — Bien sûr que non, parce que l’implémentation est en C et que cette fonction est défectueuse par conception. Il faut que l’on trouve une meilleure solution à cela. La fermeture que tu passes ici est marquée comme devant respecter des contraintes de sûreté pour l’exécution en environnement à plusieurs fils d’exécution. Donc, tu ne peux pas simplement utiliser une autre référence vers un `GstAdapter` là‐dedans par exemple, parce que `GstAdapter` ne respecte pas ces contraintes. Tu ne peux rien utiliser qui ne soit pas _thread safe_ dans cette fermeture, à moins de migrer la variable à l’intérieur, ou dit autrement : à moins que l’unique référence restante sur cet objet se trouve à l’intérieur de la fermeture au final. ### _Mapping_ de [`Buffer`](https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstBuffer.html) En Python le _mapping_ de tampon est un peu étrange. En Rust, on peut le faire de façon assez élégante : ``` Rust let mut buffer = gst::Buffer::with_size(320 * 240 * 4).unwrap(); // 1 { // 2 let buffer = buffer.get_mut().unwrap(); // 3 let mut data = buffer.map_writable().unwrap(); // 4 for p in data.as_mut_slice().chunks_mut(4) { // 5 p[0] = b; p[1] = g; // 6 p[2] = r; p[3] = 0; // 7 } // 8 } // 9 ``` * En 1, on crée un nouveau `Buffer`. On a besoin d’un `Buffer` mutable pour pouvoir écrire dedans. * Ensuite de 2 à 9, on est obligé d’écrire un truc un peu moche. Il s’agit d’un nouveau bloc qui limite la validité des variables qu’il contient. Elles seront libérées à la fin du bloc et le destructeur sera exécuté. * En 4, on _mappe_ le `Buffer` en écriture. À la fin du bloc, la fonction `unmap` est exécutée automatiquement. * On peut aussi mentionner que le `Buffer` doit être récupéré sous une forme mutable (ligne 3) avant de pouvoir en extraire une _map_ en écriture. Toutes ces fonctions peuvent échouer, c’est pour cela qu’on utilise `unwrap`. En cas d’échec, cette fonction termine l’application. Bien sûr, il y a des façons plus élégantes de gérer cela. Je ne les ai pas indiquées parce que ça surchargerait la planche. Il faudrait un peu de code pour gérer le cas d’erreur. * De 5 à 8, on itère sur la zone mémoire et on renseigne les valeurs des composantes R, G et B. On peut simplement utiliser les itérateurs de Rust pour parcourir le `Buffer` par tronçons de 4 octets, c’est ce que l’on peut lire en ligne 5. Une fois compilé, ça ressemble pratiquement à ce que vous auriez obtenu si vous l’aviez écrit en C. ## Quelques liens * Les [_bindings_](https://github.com/sdroege/gstreamer-rs) sont actuellement sur mon dépôt GitHub. J’ai l’intention de les déplacer vers _freedesktop_ à un moment donné, mais j’aimerais qu’on migre d’abord vers GitHub_. Je n’ai pas envie de les déplacer deux fois, donc pour le moment ils restent sur GitHub. * Vous pouvez trouver plein d’exemples de code [_ici_](https://github.com/sdroege/gstreamer-rs/tree/master/examples/src/bin). * La plupart des [tutoriels de GStreamer](https://gstreamer.freedesktop.org/documentation/tutorials/index.html) ont aussi été portés [_ici_](https://github.com/sdroege/gstreamer-rs/tree/master/tutorials/src/bin). Je n’en ai écrit qu’un, les autres ont été portés par des contributeurs. Donc, grâce à eux, vous disposez des tutoriels. # Écrire des extensions GStreamer en Rust Je vais vous parler rapidement de la manière d’écrire des extensions GStreamer en Rust. Comme je l’ai dit plus haut, l’année dernière nous disposions d’une infrastructure écrite à la main. La plupart de l’infrastructure pour les extensions est toujours écrite à la main, mais ce qui est important c’est qu’elle s’appuie désormais sur les nouveaux _bindings_ Rust de GStreamer. Toute l’infrastructure hors sous‐classes est générée automatiquement et prise en charge par les _bindings_. Évidemment, toute l’infrastructure pour les sous‐classes, la surcharge des méthodes virtuelles et l’installation des propriétés sont encore écrites à la main. La différence par rapport à l’année dernière, c’est que vous pouvez maintenant utiliser des méthodes virtuelles et vous pouvez définir des propriétés. Par ailleurs, les gens qui implémentent des `Element`s ne sont plus obligés d’écrire du code Rust non sûr (déclaré _unsafe_), ils peuvent le faire, mais ils n’y sont plus contraints. Le but de tout cela est de pouvoir écrire des extensions GStreamer en implémentant simplement des _traits_ Rust, sans utiliser quoi que ce soit qui ne fasse pas partie du langage, de façon à ce que cela soit très facile pour des gens connaissant Rust d’écrire des extensions GStreamer. Comme je l’ai dit, une partie du code est encore écrite à la main. Tout cela va être amélioré. Les gens de GNOME travaillent actuellement sur des solutions à base de macros qui font en gros la même chose que les `GST_DEFINE_...`s, mais d’une manière plus sympa. À l’avenir vous pourrez écrire du code qui ressemblera à du Vala ou du C#, et les macros convertiront cela en quelque chose de similaire à ce que j’ai écrit à la main. Ceci dit, c’est pour plus tard, cela va prendre un peu de temps avant d’en arriver là. ## Classes de base disponibles Actuellement, des classes de base sont disponibles pour : * les [`Element`](https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstElement.html)s ; * [BaseSrc](https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer-libs/html/GstBaseSrc.html), [BasSink](https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer-libs/html/GstBaseSink.html) et [BaseTransform](https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer-libs/html/GstBaseTransform.html) ; * [Thibault](https://github.com/thiblahute), qui est peut‐être parmi nous, travaille actuellement sur le _binding_ [VideoDecoder](https://github.com/thiblahute/gstreamer-rs/tree/videodecoder) et il a aussi l’intention d’écrire un décodeur d’images GIF ; * il y a une chose que je voudrais souligner ici. Chaque fois que vous faites quelque chose que vous n’êtes pas autorisé à faire, par exemple ce que je faisais tout à l’heure avec `unwrap` (la création d’un `Element` pouvant échouer, car il peut ne pas être disponible), et donc si vous utilisez `unwrap`, en cas d’erreur, Rust va paniquer. Ce que l’on entend par là, c’est que la pile va être déroulée et... _N. D. L. T. : l’organisation informe Sebastian qu’il ne lui reste plus beaucoup de temps._ ## `Element`s disponibles Nous disposons des `Element`s suivants : * démultiplexeur FLV ; * source HTTP ; * source et « dissipateur » (`sink`) depuis et vers un fichier ; * source et « dissipateur » (`sink`) depuis et vers Amazon S3 ; * il y a quelques jours, j’ai réécrit en Rust l’`Element` `AudioEcho` qui existait déjà en C ; * et bientôt, si tout va bien, on aura aussi un décodeur d’images GIF (animées). Une anecdote intéressante : lorsque j’ai écrit l’`Element` `AudioEcho` en Rust, il était environ 1,7 fois plus rapide que l’implémentation en C. Ce n’est pas parce que Rust est plus rapide, mais plutôt parce qu’il était plus difficile de faire en sorte que l’équivalent en C soit rapide. J’ai trouvé l’expérience intéressante. Ce n’était pas exactement l’objectif initial lorsque j’ai entrepris la réécriture de cet `Element`, mais ça montre bien que l’on n’a pas affaire à un langage de haut niveau qui ralentirait les choses, c’est vraiment un langage que l’on peut utiliser pour ce genre de développements. ## État actuel * les _bindings_ sont encore assez jeunes ; * ils sont utilisables pour une implémentation nécessitant les classes de base que je mentionnais plus haut ; * les fonctionnalités manquantes seront ajoutées le moment venu. Si vous voulez écrire des extensions GStreamer en Rust maintenant, lancez‐vous, dites‐moi s’il manque des choses et je les ajouterai ou je vous aiderai à les ajouter. Jusqu’à présent, j’ai pris beaucoup de plaisir à écrire des extensions GStreamer en Rust, j’ai beaucoup plus apprécié cela que d’en écrire en C. Donc, essayez et voyez si c’est le cas pour vous aussi ! _N. D. L. T. : Sebastian passe les exemples de code par manque de temps. Vous pouvez les retrouver dans les [planches au format PDF](https://coaxion.net/~slomo/talks/gstconf-2017/Rust.pdf)._ ## Quelques liens Si vous voulez voir à quoi cela ressemble, c’est sur mon [dépôt GitHub](https://github.com/sdroege/gst-plugin-rs). Les extensions sont également dans le dépôt. # À venir... Encore quelques mots à propos de l’avenir : mon objectif est que l’on écrive de plus en plus de code en Rust plutôt qu’en C. Commençons d’abord par les extensions externes. Plus tard, on pourra aussi envisager de remplacer le code du cœur. Mais, ça, c’est pour l’avenir. Il n’y a pas de raison de se faire du souci pour le moment. Nous pouvons faire tout cela de façon itérative en remplaçant des petites portions de code grâce au système [FFI](https://doc.rust-lang.org/book/first-edition/ffi.html) de Rust qui rend les choses vraiment faciles pour s’intégrer dans du code C existant. Vous pouvez remplacer un simple module ou même une simple fonction si vous le souhaitez. Globalement, je voudrais faire en sorte que les _bindings_ soient mieux finis. Que l’infrastructure pour écrire des extensions soit mieux finie aussi, plus complète, mais bon, je suppose que c’est assez évident. Et le plus important, c’est que j’aimerais faire en sorte que plus de personnes s’intéressent et s’impliquent dans l’utilisation de Rust, ce qui était le but principal de cette présentation. J’espère avoir atteint mon objectif. Jetez‐y un œil, essayez‐le, j’espère que vous ne le regretterez pas. Moi, je ne le regrette pas ! Plus généralement, je dirais : n’écrivez plus de projets en C, c’est une mauvaise idée. Regardez tous les [CVE](https://fr.wikipedia.org/wiki/Common_Vulnerabilities_and_Exposures) des projets à base de C... Ce n’est pas une bonne idée ! # Merci / Questions ? On n’a plus le temps pour des questions, donc passez me voir après. Voici encore quelques liens. Il y a pas mal d’informations sur le site Web de Rust, la documentation est de très bonne qualité, vous y trouverez probablement toutes les réponses aux questions que vous vous posez : * * * Merci !

AltStyle によって変換されたページ (->オリジナル) /