Patrice Ferlet
Patrice Ferlet
Créateur de ce blog.
Publié le août 14, 2012 Temps de lecture: 6 min

Me suivre sur Mastodon

Gstreamer la suite

Toujours envie de faire du gstreamer ? Et si on s’amusait un petit peu avec quelques plugins ? Genre des visualisations graphiques de sons… et appréhender un souci simple de gstreamer qui ne peut pas raccorder une sortie sur deux entrées. Et de trouver la solution.

Je vous fais un petit rappel vite fait. Gstreamer est un framework utilisable en bash, python, C, Vala, Java, Ruby, etc. Ce framework permet de manipuler des flux audio et vidéo au travers de plugins. L’ensemble des liaisons de plugins se nomme un “pipeline”.

Chaque plugins peut être nommé, un peu comme une variable dans un script. On fait un lien entre deux plugins entre des “src” et des “sink” avec un point d’exclamation (!). Le flux va de gauche à droite.

Le plugin “decodebin” est un bonheur magique qui permet de décoder un flux sans avoir à chercher constamment quel démultiplexeur et décodeur utiliser.

On utilise gst-inspect pour trouver un plugin et/ou savoir comment il fonctionne, par exemple pour les “caps” qui sont des options.

On teste un pipeline avec gst-launch.

Un exemple de pipeline:

gst-launch filesrc location="monfichier.ogg" ! decodebin ! \
audioconvert ! audioresample ! autoaudiosink

Ici le flux part d’une source fichier, on utilise le “caps” location qui définit le chemin du fichier. Le flux est envoyé vers decodebin, puis dans audioconvert, puis audioresample et enfin dans un plugin qui va trouver la sortie sonore adéquate (en général c’est pulseaudio, donc on entend le son).

On prend l’habitude de resampler le son, de le convertir etc. Avec l’habitude ça va tout seul.

Quand on a besoin de manipuler deux flux en même temps, par exemple une vidéo avec du son, on fait deux pipes et on les place dans une queue pour avoir deux threads en parallèle. On prend soin de nommer quel plugin réutiliser pour récupérer les “src” dans les pipes qui composent le pipeline. Exemple:

gst-launch filesrc location="mavideo.mp4" ! decodebin name=foo \
foo. ! queue ! ffmpegcolorspace ! videoscale ! autovideosink \
foo. ! queue ! audioconvert ! audioresample ! autoaudiosink

Ici, “foo” est le nom que je donne à “decodebin”. On utilise un point pour récupérer le plugin qui porte ce nom (sinon gstreamer cherchait un plugin “foo”) et je le place dans une queue. Gstreamer se débrouille pour raccoder les src de bon type aux sink qui peuvent supporter le flux. Ici la vidéo est traitée par ffmpegcolorspace, puis videoscale et arrive sur mon écran. Le son part en queue et va dans audioconvert, puis audioresample, puis mes enceintes.

Faites attention de ne pas mettre de “!” partout, il ne sert que de lien quand on en a besoin. Par exemple dans le pipeline précédent, on ne fait pas de lien entre autovideosink et “foo.”

Bon, et bien jouons un peu. J’avais envie d’utiliser un visualisateur de son, vous savez… le truc graphique qui bouge avec le son, c’est joli en plus ! Il existe des plugins gstreamer qui le permettent. Ils se trouvent dans l’ensemble “audiovisualizer”:

gst-inspect | grep -i audiovisual
audiovisualizers:  wavescope: Waveform oscilloscope
audiovisualizers:  synaescope: Synaescope
audiovisualizers:  spectrascope: Frequency spectrum scope
audiovisualizers:  spacescope: Stereo visualizer

Si je vais vous parler de ces outils, c’est surtout pour vous montrer un problème qu’on peut résoudre aisément. Ce problème est simplement de pouvoir réutiliser le même flux dans deux “sink”. **Car gstreamer ne peut pas raccorder une src à deux sink.** Mais il existe un plugin qui va nous permettre de le faire :)

Je vous prépare à un autre problème … ces visualisateurs ne sortent pas une vidéo, mais des images. Du coup “autovideosink” ne fonctionnera pas, il faudra utiliser “ximagesink” ou xvimagesink" selon certains cas.

Ici, ce sont des images brutes… on va utiliser ximagesink comme fenêtre de visualisation.

gst-launch filesrc location="Musique/good_night_moon-shivare_e.ogg" ! decodebin !\
audioconvert ! audioresample ! wavescope ! ximagesink

Ok, cool hein :) c’est joli, on voit la courbe… mais on entend rien ! Alors voilà le souci, on se dit “bha ok, simple, je vais nommer decodebin, et réutiliser la sortie pour la mettre dans autoaudiosink”… Pas bête… mais ça marchera pas. On tente (en utilisant des queues hein, pour faire tourner le son en même temps que le visualisteur):

gst-launch filesrc location="Musique/good_night_moon-shivare_e.ogg" ! decodebin name=d \
d. ! queue ! audioconvert ! audioresample ! wavescope ! ximagesink \
d. ! queue ! audioconvert ! audioresample ! autoaudiosink

Bon, ça bloque… effectivement “decodebin” n’a qu’un flux de sortie, un seul “src” donc… il se raccorde à la queue, et on a plus d’autre src à raccorder à l’autre queue. Ce serait donc cool de pouvoir démultiplier le flux pour l’envoyer dans les deux plugins.

Il existe un plugin qui va faire cela avec une facilité déconcertante: tee. Oui, comme un “T” qu’on utilise pour dériver des câbles d’antennes. Notez aussi que “tee” est une commande linux qui fait pareil en shell: sortir un contenu à deux endroits différents.

Bref, “tee” fait à peu près cela:

        +-------------+
        |    Tee      |
----> (sink)         (src0) -> plugin
        |            (src1) -> plugin
        |            (...)
        |            (srcN) -> plugin...
        |             |
        +-------------+

Il sort un src à la demande, sitôt qu’on tente de le connecter à un autre plugin. “Magique” est encore le mot qui me vient à l’esprit.

Bref, dans notre cas:

gst-launch filesrc location="Musique/good_night_moon-shivare_e.ogg" ! decodebin ! \
audioconvert ! audioresample ! tee name=T \
T. ! queue ! wavescope ! ximagesink \
T. ! queue ! autoaudiosink

Je vous fait un petit asciart pour comprendre:

filesrc >-+
          |
      decodebin ---> audioconvert --+
                                    |
          +------------------------+
          |
          +--->audioresample -------+
                                    |
    +-------------------------------+
    |
    |    +------------------+
    |    |    tee T         >> queue ---> wavescope -> ximagesink
    +--->>                  |
         |                  |
         |                  >> queue --> autoaudiosink
         +------------------+

Le flux sortant de audioresample est dédoublé en deux via le “tee”. On place chaque sortie en queue, et ça tourne nickel !

Ce genre de tee peut justement vous permettre de “voir” une vidéo en l’encodant et l’enregistrant dans un fichier.

Ou alors, pour le fun, raccorder plusieur visualisteur de son, de ce genre:

filesrc >-+
          |
      decodebin ---> audioconvert --+
                                    |
          +------------------------+
          |
          +--->audioresample -------+
                                    |
    +-------------------------------+
    |
    |    +------------------+
    |    |    tee T         >> queue ---> wavescope -> ximagesink
    +--->>                  |
         |                  |
         |                  >> queue --> spacescope -> ximagesink
         |                  |
         |                  >> queue --> autoaudiosink
         +------------------+

En tapant ce pipeline:

gst-launch filesrc location="Musique/good_night_moon-shivare_e.ogg" ! decodebin ! \
audioconvert ! audioresample ! tee name=T \
T. ! queue ! wavescope ! ximagesink \
T. ! queue ! spacescope ! ximagesink \
T. ! queue ! autoaudiosink

Je sais que parfois la lecture d’un pipeline peut paraître un peu ostère, mais à la longue, en quelques heures, vous prendrez le coup.

comments powered by Disqus