Journal media-toc ou un prétexte pour prendre des technologies en main

Posté par  (site web personnel) . Licence CC By‑SA.
41
16
oct.
2017

Sommaire

Nal,

Cela fait quelques temps que je pense à te parler de mon projet media-toc, une application écrite en Rust qui vise à définir une table des matières pour un fichier audio-vidéo ou à scinder un fichier audio-vidéo en chapitres.

Tu me diras que le nom fait pitié, surtout en Français, et tu auras raison.

IMH de media-toc : fichier vidéo
IHM de media-toc : fichier vidéo.

La génèse

Tout a commencé il y a 5 ans avec la captation audio-vidéo d'un concert. Je voulais en extraire le flux audio et le découper en pistes, une piste par chanson. L'extraction du flux audio ne posait aucun souci : un bon vieux terminal, FFmpeg et le tour était joué. Cependant, le fichier obtenu dépassait le Go(*), trop lourd pour être découpé par Audacity qui cherchait à tout charger en RAM et ramait avant de s'effondrer sous le poids des Go. J'ai aussi sorti l'Ardourie lourde, mais ce n'était pas probant. Ne me demande pas pourquoi : je ne m'en souviens plus et ce n'est pas le sujet ! Par ailleurs, que demander de plus qu'une idée de développement apparemment non couverte par des outils existants ?

Je lançai donc Glade pour ébaucher une IHM et jetai un œil du côté de Vala. Tu te demandes sûrement pourquoi ces technologies et je te dirai que ce n'est pas le sujet non plus. En deux mots tout de même : à l'époque, j'étais déjà sur un autre prototype un peu plus avancé en Python et GTK et j'aimais bien l'idée d'un langage « récent » qui produisait du code natif. (Si tu es allé voir quel était ce prototype, tu as sans doute été amusé/horrifié par l'hébergeur qui était encore populaire à l'époque. Aujourd'hui, le-dit prototype continue sa vie dans un espace plus à la mode).

Ma vie

À cette époque encore troublée par les conséquences de la crise des subprimes, la vie me mobilisait sur d'autres préoccupations. Tu auras compris que ce n'était pas vraiment dû aux subprimes, mais je ne suis pas là pour te raconter ma vie ici-bas, Nal.

Le retour

Récemment, des circonstances plus clémentes m'ont permis de consacrer plus de temps libre aux développements de mon choix. Rust me faisait de l'œil. Je décidai de lui répondre avec ce projet non assouvi.

Le timing était presque parfait : le binding Rust de GTK et celui de Cairo, bien que non encore stabilisés étaient déjà bien avancés et un binding pour FFmpeg paraissait déjà assez complet. Au bout de quelque temps, j'obtins un prototype capable de charger un fichier audio-vidéo et ses chapitres, d'afficher la première trame vidéo et de dessiner les premiers samples audio. Ce prototype fut aussi l'occasion d'ajouter la lecture et l'écriture des chapitres dans le binding FFmpeg.

media-toc : prototype basé sur FFmpeg
Ce prototype basé sur FFmpeg peut sembler très semblable à la version actuelle. Il n'en est rien : il était alors beaucoup plus proche d'une démo PauvrePoint™ puisqu'il ne permettait ni la lecture, ni la recherche dans le flux vidéo, ni le zoom sur la waveform.

Variation sur le même thème

C'est en me penchant sur les modifications à apporter pour gérer la lecture, la mise en pause et la recherche dans le flux audio que l'évidence m'apparut : il me fallait tester GStreamer. Je modifiai donc mon prototype pour intégrer la toute nouvelle version du binding de GStreamer pour Rust.

GStreamer, GLib & co.

Tout comme GTK, GStreamer repose sur GLib, une bibliothèque portable écrite en C qui inclut GObject, un système de typage objet introspectif, et des fonctions pour le développement de fondations logicielles : gestion de la mémoire, entrées/sorties, multithreading, signaux, structures de données, internationalisation… GLib facilite aussi la génération de bindings. C'était d'ailleurs grâce à GLib que j'utilisais déjà GTK3 en Python dans le cadre du projet dont je te parlais plus haut.

Comment ça marche pour Rust ?

Les développeurs de GLib & co. ont créé Gir, un outil permettant de générer un binding Rust idiomatique à partir d'un projet basé sur GLib. Prenons l'exemple du binding GStreamer :

  • Une première moulinette utilise les métadonnées issues de l'introspection de GObject pour créer des équivalents Rust pour les constantes, énumérations, types et des interfaces pour les différentes fonctions de la bibliothèque (FFI - à une époque, on appelait ça un stub). Pour le cœur de GStreamer, cela donne ce fichier pas tout à fait pratique pour les êtres humains, mais ce n'est pas son but.
  • Une deuxième moulinette permet de générer les implémentations Rust. Toujours pour le cœur de GStreamer, tout ceci est généré automatiquement. Quelques subtilités nécessitent encore des retouches à la main, mais même dans ce cas, la génération automatique apporte une base appréciable aux ajustements.

Ce n'est pas vraiment une surprise : les modèles de partage d'objets ou de transfert de responsabilité de gestion de la mémoire de GLib trouvent des équivalents directs en Rust.

Adopté !

Tout comme pour le binding FFmpeg, la gestion des chapitres n'était pas sur le haut de la pile du projet gstreamer-rs. En revanche, pour media-toc, c'était fondamental. Ma modeste contribution a été récompensée par des conseils avisés du développeur du binding Rust, qui est aussi l'un des développeurs principaux de GStreamer et une progression significative de la partie audio du binding.

Ajoute à cela une intégration sans effort de la vidéo dans mon IHM grâce au plugin GTK, je décidai de basculer définitivement la gestion multimédia de media-toc sur gstreamer-rs.

Et Rust sinon ?

Ça déchire, grave !

Bien sûr, chacun observe ses propres critères pour apprécier un langage de programmation et un langage de programmation correspond nécessairement à des cas d'utilisation spécifiques. Rom1v a déjà rédigé un journal sur sa prise en main de Rust, je ne m'étendrai pas sur le sujet.

J'apprécie les garde-fous de Rust à la compilation. Je ne sais pas pour toi Nal, mais après toutes ces années, je n'ai toujours pas la certitude que mon code C sera garanti sans failles de sécurité. Parfois je me demande aussi ce qu'aurait donné Rust sur des projets pour lesquels la mise au point a été assez laborieuse. Je me revois débugger des problèmes de multithreading en C++ sur un système cryptographique communiquant avec 6 cartes à puce en parallèle sur un équipement que je n'avais jamais vu et auquel je n'avais pas accès, tout ça à 3 000 km de distance. C'est peut-être aussi pour cela que j'apprécie les contraintes qui limitent les data-races et autres race-conditions. J'aurais bien passé quelques minutes de plus à me gratter la tête devant les messages du compilateur plutôt que ces quelques jours « intéressants ».

L'écosystème est très agréable à utiliser aussi. Je veux parler de cargo en particulier. Il gère les dépendances, lance la compilation, lance les tests unitaires, exécute le binaire, etc. et tout cela avec une facilité déconcertante.

C'est pas un peu fini ?!

Attends, j'avais aussi envie de te parler de mon mécanisme de double buffering, vite fait. Lorsque j'ai cliqué sur play pour tester mon rendu de waveform à 60fps, le défilement était saccadé ! Mazette ! Rust ne tenait donc pas ses promesses… Et puis ça a fait ch'boom là-dedans : il fallait séparer le rendu de l'affichage. Une excellente occasion de mettre les mains dans les primitives de synchronisation de Rust. Note aussi la possibilité d'utiliser des canaux, mais je ne peux pas parler de tous les recoins du projet.

Je voulais aussi que le mécanisme reste conforme à la séparation IHM / média que j'avais adoptée depuis le début. C'était le moment de sortir les traits, en gros l'équivalent des interfaces dans d'autres langages, le polymorphisme ou le dynamic dispatch. Le mécanisme de double buffering ne sait pas qu'il est utilisé pour un rendu de waveform, il sait juste qu'il devra invoquer les traits d'un extracteur de samples à la réception des nouveaux buffers du flux audio. En nimage, ça donne ça :

Diagramme de classes du mécanisme de _double buffering_
Diagramme de classes du mécanisme de double buffering. Il est parfois nécessaire de forcer le rafraîchissement depuis l'IHM, d'où la méthode refresh qui peut être invoquée par l'IHM.

D'ailleurs, on me suggère une représentation spectrale, une nouvelle implémentation de l'extracteur de samples en somme.

Bon en réalité, j'ai encore quelques soucis de fluidité, mais au moins ça ne vient plus du temps passé au rendu de la waveform.

Sinon, pour répondre à ta question, le projet n'est pas fini…

Reste à faire

À ce jour, media-toc sait ouvrir un média (audio ou audio-vidéo), afficher quelques informations dont les chapitres et l'image de couverture, démarrer la lecture, mettre le flux en pause, naviguer dans le flux, représenter les différents canaux audios, zoomer sur l'axe temporel à la précision du sample audio.

media-toc : _waveforms_ pour 5.1 canaux audios
Waveforms pour 5.1 canaux audios.

Il me reste à implémenter l'édition des chapitres et l'export à proprement parler et bien sûr les 80% de finissions.

Et après ?

Quand l'application sera fonctionnelle, j'envisage d'extraire le mécanisme de double buffering et les rendu / interaction avec la waveform, voire la représentation spectrale, vers un plugin GStreamer.

Et puis, j'ai d'autres idées rustiennes pour la suite, j'espère t'en parler une prochaine fois.


(*) 2h10 en PCM stéréo

  • # Cet outil m'a l'air intéressant, quid de l'existant ?

    Posté par  . Évalué à 8.

    Tu n'as qu'assez peu parlé de l'existant, je ne connais pas du tout le domaine et il me paraît assez bizarre qu'aucune alternative n'existe à celles citées.

    Sinon à part ça : ARRÊTE DE ME DONNER ENVIE DE FAIRE DU RUST J'AI PAS LE TEMPS. :'(

    • [^] # Re: Cet outil m'a l'air intéressant, quid de l'existant ?

      Posté par  (site web personnel) . Évalué à 2.

      En effet, et j'ai assez peu cherché à vrai dire. En fait, ce n'était pas si important pour moi. Souviens-toi que ce projet n'est qu'un prétexte ! ;)

      Pour être un peu plus précis, j'ai eu l'occasion d'utiliser rapidement mkvtoolnix récemment. C'est un peu le couteau suisse pour le conteneur Matroska. C'est grâce à lui que j'ai créé les 3 chapitres pour ma vidéo d'exemple (celle avec mon fidèle Ernest). Pour l'édition des chapitres, je cherche néanmoins quelque chose de plus ergonomique et interactif. Par ailleurs, media-toc pourrait servir pour d'autres formats.

      • [^] # Re: Cet outil m'a l'air intéressant, quid de l'existant ?

        Posté par  . Évalué à 2.

        Les logiciels de montage vidéo peut-être…

        Projet sympa et journal très intéressnt.

        • [^] # Re: Cet outil m'a l'air intéressant, quid de l'existant ?

          Posté par  (site web personnel) . Évalué à 2.

          Oui, les logiciels de montage vidéo ou les multi-pistes audio devraient pouvoir exporter des pistes, moyennant quelques opérations manuelles. J'ai tenté avec Ardour, mais j'ai fini par lâcher l'affaire.

          Pour l'export de tables de matières avec ce type de logiciels, après une recherche rapide, je n'ai rien trouvé de probant. Cinelerra sait créer un menu pour DVD à l'aide d'une description XML et un outil en ligne de commande. Je n'ai rien vu pour d'autres conteneurs audio-vidéos.

          Note aussi que des commentaires plus bas suggèrent d'autres cas d'utilisation qui semblent pouvoir être couverts sur la base de l'interface existante. On devrait pouvoir aboutir à un logiciel simple d'utilisation et répondant à des besoins que je n'avais pas imaginés initialement.

          Merci pour tes retours !

  • # Rust n'est pas infaillible

    Posté par  (site web personnel) . Évalué à 8.

    Je ne sais pas pour toi Nal, mais après toutes ces années, je n'ai toujours pas la certitude que mon code C sera garanti sans failles de sécurité.

    Ne t'inquiète pas, avec Rust tu n'as pas cette certitude non plus.
    Si Rust vérifie un certain nombre de choses à la compilation pour éviter les buffer overflow et autres soucis du style qui peuvent entraîner des soucis de sécurité, tous les problèmes de sécurité ne viennent pas uniquement de ce genre d'erreurs.

    Tes applications en Rust peuvent donc avoir des failles, même si théoriquement tu devrais éviter beaucoup de failles courants.

    • [^] # Re: Rust n'est pas infaillible

      Posté par  (site web personnel) . Évalué à 5.

      Tout à fait d'accord. Rust apporte des garde-fous.

      L'idée principale que je voulais exprimer (à la suite du texte que tu cites) était que malgré une certaine frustration ressentie parfois face aux contraintes imposées à la compilation, je continue de penser que ces contraintes ont de la valeur. C'est l'histoire du coût de la résolution des bugs selon le moment où ils sont détectés, c.f. aussi mon exemple de cartes à puce. Par ailleurs, je me rends compte que j'ai dû intégrer ces contraintes car je ne me souviens pas avoir ramé ces derniers temps.

  • # Format DAISY

    Posté par  (site web personnel) . Évalué à 5.

    Salut !

    Problématique intéressante. Connais-tu le format DAISY, utilisé couramment par les non voyants qui veulent se promener dans un contenu audio ?
    On trouve des informations sur le site de l'AVH par exemple, et il y a un logiciel fonctionnel empaqueté chez debian: daisy-player. Ça serait chouette de pouvoir faire un export dans ce format avec ton logiciel…
    Ce format gère notamment les structure hiérarchiques complexes (parties, sous-parties, sous-sous parties, etc.). Et le tiens ?

    • [^] # Re: Format DAISY

      Posté par  (site web personnel) . Évalué à 3.

      Salut !

      Je ne connaissais pas, merci pour les pointeurs.
      J'ai créé une issue.

      Pour le moment, seul l'affichage des chapitres est géré dans media-toc et il n'y a pas de structure hiérarchique. Ça ne devrait pas présenter de difficulté d'améliorer cela.

  • # Presque rien à voir: Advene

    Posté par  . Évalué à 1.

    Extrait du site original

    Le projet Advene (Annotations de vidéo numérique (Digital Video) échangées sur le NEt) est mené depuis plusieurs années au laboratoire LIRIS (UMR 5205 CNRS) de l'Université Claude Bernard Lyon 1. L'objectif général du projet est de fournir un modèle et un format permettant de partager des annotations de documents audiovisuels numériques (films, cours, conférence, etc) ainsi que des outils permettant d'éditer et de visualiser/jouer des hypervidéos générées à partir des informations liées aux annotations et aux documents audiovisuels.

    Je voulais juste partager, j'aimerais voir ce format/conteneur se répandre. :)

  • # Joli travail

    Posté par  (site web personnel) . Évalué à 7. Dernière modification le 16 octobre 2017 à 17:48.

    Merci pour ce journal, beau travail. Tu as dû bien t'amuser :)

    C'est intéressant de voir une application graphique en Rust, et qui fonctionne :)

    Je connais davantage Qt que Gtk, mais apparemment c'est plus compliqué pour les bindings (cf discussion).

    J'ai juste des clignotements parfois sur le rendu de la partie audio: https://github.com/fengalin/media-toc/issues/58

    Aussi, en l'état actuel, le projet nécessite Rust nightly. Comme par défaut, je suis en stable, j'ai dû exécuter la commande :

    rustup override set nightly
    

    blog.rom1v.com

    • [^] # Re: Joli travail

      Posté par  (site web personnel) . Évalué à 1.

      Merci pour ton retour et pour la déclaration de bug ! Je n'ai pas encore observé ce problème, je te demanderai probablement des précisions quand je m'y mettrai.

      En effet, je m'amuse bien :)

    • [^] # Re: Joli travail

      Posté par  . Évalué à 3.

      Sans lire la discussion, laisses moi deviner quelques problemes:

      • les exceptions n'ont pas d'ABI stable
      • qt necessite une surcouche a make

      Bon, je t'avoue que, d'un autre cote, j'aurais bien apprecie une ihm non basee sur gtk, parce que, ma foi, j'ai en horreur le widget d'exploration de fichiers de gtk, je prefere voir les chemins reels (non traduits donc) et complets, avec par defaut soit le dernier dossier utilise par l'appli, soit le $HOME.
      Mais c'est 1) hors sujet, 2) parce que j'aime avoir le moins de trucs caches possibles et 3) peut-etre lie a la config par defaut de ma distrib (debian a un packaging et une conf par defaut assez douteux sur certains points)…

      Bref, quels toolkits graphiques sont utilisables en rust, au final?

      • [^] # Re: Joli travail

        Posté par  (site web personnel) . Évalué à 2.

        La discussion cite d'autres problèmes et je pense que ceux que tu mentionnes pourraient venir s'ajouter à la liste. Si le sujet t'intéresse, tu devrais jeter un œil, le débat est plutôt intéressant. Cela dit, la conversation date d'il y a 6 mois.

        Voici quelques pointeurs vers des bibliothèques Rust actives offrant un toolkit (évidemment, cette liste n'est pas exhaustive) :

        • Le binding GTK dont il est question ici. Le projet est actif et il fait ce que je veux qu'il fasse, même si mon IHM reste assez conventionnelle. Sa seule spécificité réside dans le rendu des waveforms et pour cela j'utilise Cairo qui permet le dessin vectoriel.
        • Le projet C++ to Rust de Qt offre des bindings vers les bibliothèques de Qt et semble actif. Voir la doc pour QtGui et QtWidgets. Je ne peux pas donner mon avis vu que je n'ai pas testé. Note cependant la mention : "Il s'agit un travail en cours, l'API va changer significativement à l'avenir. Certaines méthodes manquent encore et certaines ne sont pas pratiques à utiliser. Certaines méthodes ne sont pas sûres alors qu'elles ne sont pas déclarées comme telles". Pour un projet personnel comme le mien, c'est pas ça qui m'arrêterait ;-)

        Il y a des projets pour d'autres toolkits, mais ils semblent pas très actifs. Ex. :

        Un peu HS, mais méritent d'être mentionnés :

  • # Découpage automatique?

    Posté par  (site web personnel) . Évalué à 4.

    Beau travail!

    Est-ce que tu prévois un découpage automatique?

    J'écoute souvent des émissions de radio (30 à 50 minutes) dans ma voiture et la navigation du système audio est pratique pour passer de mp3 en mp3, mais pas pour naviguer au sein d'un même enregistrement.

    L'idéal serait un découpage intelligent:

    • environ toutes les 2-5 minutes.
    • pas au milieu d'une phrase.
    • découpage des types de séquence audio: conversations, musiques…

    Le post ci-dessus est une grosse connerie, ne le lisez pas sérieusement.

    • [^] # Re: Découpage automatique?

      Posté par  (site web personnel) . Évalué à 1.

      Merci devnewton ! C'est noté !

      • [^] # Re: Découpage automatique?

        Posté par  (site web personnel) . Évalué à 4.

        Ce qui m'intéresserais, ce serait de pouvoir chapitrer de grandes pistes de musique dites classique. Aller au mouvement suivant etc …

        Merci pour ton travail.

        « Il vaut mieux mobiliser son intelligence sur des conneries que mobiliser sa connerie sur des choses intelligentes. »

        • [^] # Re: Découpage automatique?

          Posté par  (site web personnel) . Évalué à 2. Dernière modification le 17 octobre 2017 à 13:28.

          Oui, ce serait sympa et ça irait dans le sens d'une indexation hiérarchique comme proposée dans ce commentaire.

          Je comptais aussi implémenter une option pour la génération des fichiers cue sheet. Et aussi des options pour éviter les transitoires suite aux découpages, la gestion du ReplayGain, … Pas mal de boulot encore :)

          • [^] # Re: Découpage automatique?

            Posté par  (site web personnel) . Évalué à 1.

            Merci. Effectivement je me demandais avec quoi (VLC/mplayer …) lire les fichiers ainsi indexés. Le cue sheet est une solution intéressante.

            Courage !

            « Il vaut mieux mobiliser son intelligence sur des conneries que mobiliser sa connerie sur des choses intelligentes. »

        • [^] # Re: Découpage automatique?

          Posté par  (site web personnel) . Évalué à 3. Dernière modification le 18 octobre 2017 à 14:31.

          Moi ça m'intéresserait pour des morceaux ou vidéos d'apprentissage de la batterie, où tu veux rejouer un passage en boucle pour t'entraîner, et pouvoir aller de section en section dans la vidéo :p.

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.