Skywalker13

Diary of an ex-GeeXboX developer…

Quoi de neuf sur les libs ~ đŸ‡«đŸ‡·

Posted at — Jan 3, 2010

Hello,

maintenant qu’Enna 0.4.0 est dehors et que les paquets sont disponibles, cet article me donne l’occasion de faire un peu la synthĂšse des modifications apportĂ©es Ă  libvalhalla et Ă  libplayer depuis les versions 1.0.0. A noter que la premiĂšre version d’Enna concerne uniquement les versions 1.0.0, et en aucun cas ce que je liste ci-dessous.

libplayer

Concernant libplayer il n’y a pas grand chose de neuf. La plupart des patchs se rapportent Ă  des fix mineurs dans les scripts et Makefiles. Ainsi que le support (en thĂ©orie) de Darwin. Je n’ai pas la moindre idĂ©e si la compilation pour MacOS X fonctionne car je n’ai jamais eu de Mac Ă  ma disposition. A part une image Ă©mulĂ©e d’une Tiger qui n’est pas spĂ©cialement rapide Ă  l’utilisation.

Mise Ă  part ça, la modification la plus importante est le remplacement de Xlib par XCB. Xlib a toujours Ă©tĂ© un problĂšme nĂ©anmoins une astuce permettait de le rendre utilisable dans le contexte de libplayer. X11 dans libplayer a deux raisons d’ĂȘtre. Tout d’abord c’est un bon moyen pour crĂ©er une fenĂȘtre X pour MPlayer. Cette fenĂȘtre Ă©tant entiĂšrement contrĂŽlĂ©e par libplayer, cela Ă©vite d’avoir des problĂšmes avec les Ă©vĂ©nements X11 et il est facile de l’embarquer dans Enna. Ensuite cette fenĂȘtre est indispensable pour xine-lib.

Le problĂšme d’Xlib intervient au niveau des threads. Afin de garantir d’ĂȘtre thread-safe il est nĂ©cessaire d’appeler la fonction XInitThreads() avant n’importe quel autres fonctions d’Xlib. Ou alors, il faut gĂ©rer les locks sur les appels Xlib sois-mĂȘme. J’ai donc optĂ© pour la deuxiĂšme solution (dans le cas de libplayer-1.0.0). Des mĂ©canismes dans xine-lib permettent d’appeler les locks crĂ©Ă©s par libplayer. Mais il y a un point Ă  soulever. Selon les dires des dĂ©veloppeurs de xine, ces mĂ©canismes ne sont pas exempt de bugs. Et l’utilisation d’[XInitThreads()][4] est impossible dans le cas de libplayer. La raison est trĂšs simple. Étant donnĂ© que ce doit ĂȘtre la premiĂšre fonction Ă  appeler, il faudrait ĂȘtre sĂ»r que par exemple avec Evas, Qt ou GTK (si libplayer serait utilisĂ© dans une application qui en dĂ©pend tel qu’Enna avec Evas), que libplayer soit initialisĂ© avant ces libs. Ou alors qu’Evas fasse lui mĂȘme un XInitThreads(). Ou encore que celui qui dĂ©veloppe le GUI (tel qu’Enna) fasse un XInitThreads() dans son main() (avant toutes les autres initialisations). Et donc l’utilisation d’une telle bibliothĂšque deviendrait trĂšs contraignante.

La solution c’est XCB. Il n’y a aucun besoin d’initialiser quoi que se sois pour les threads contrairement Ă  Xlib. XCB peut donc ĂȘtre utilisĂ© de maniĂšre sĂ»re dans libplayer et sans fournir de locks supplĂ©mentaires. C’est sur XCB que les dĂ©veloppeurs de xine se tournent Ă©galement. Car il y a au moins les sorties video Xshm et Xv qui sont portĂ©es pour XCB.

La prochaine release de libplayer utilisera donc XCB. Pour ĂȘtre plus prĂ©cis, le fait d’utiliser XCB dans libplayer n’empĂȘche pas d’utiliser Xlib pour un wrapper de libplayer, pour autant que les mĂ©canismes pour garantir le thread-safe soient implĂ©mentĂ©s.

VDPAU

NVidia fait des efforts pour Linux depuis longtemps. VDPAU en est un exemple parmi d’autres. Mais tout ceci reste qu’en mĂȘme du code fermĂ© avec tous les dĂ©savantages qui en dĂ©coulent. Dans le cas de libplayer, il est aujourd’hui impossible de supporter VDPAU avec xine. Non pas que xine ne peut pas l’utiliser, mais plutĂŽt que xine est obligĂ© de passer par Xlib pour pouvoir l’exploiter.

On pourrait croire alors que je n’aurais pas du changer Xlib pour XCB dans libplayer, mais en rĂ©alitĂ© ça n’a strictement rien Ă  voir. Le problĂšme est au niveau de VDPAU. Celui-ci Ă©tant basĂ© sur Xlib, il est nĂ©cessaire d’avoir l’initialisation des locks. Le seul moyen actuel est de devoir faire appel Ă  XInitThreads(). Ainsi xine refuse de charger VDPAU dans les seuls cas thread-safe tel que XCB ou la variante Xlib (soit disant “buggĂ©e” qui fonctionne qu’en mĂȘme bien par rapport Ă  ce que libplayer-1.0.0 en fait).

Pour ĂȘtre honnĂȘte, il y a un moyen mais c’est un hack. En ajoutant un XInitThreads() dans Enna avant l’initialisation d’Evas ainsi qu’une modification dans le wrapper xine de libplayer pour lui dire qu’il doit travailler avec Xlib.

Tout ceci ne concerne pas le wrapper MPlayer, qui peut parfaitement utiliser VDPAU pour la sortie vidĂ©o comme pour les codecs, Ă©tant donnĂ© que c’est un processus “forkĂ©”.

libvalhalla

C’est sur cette bibliothĂšque oĂč j’ai le plus travaillĂ© depuis la 1.0.0. Mise Ă  part des correctifs sur les scripts et Makefiles comme pour libplayer et Darwin, il y a aussi de nouvelles fonctionnalitĂ©s.

API

Tout d’abord l’API publique est maintenant plus facile Ă  Ă©tendre sans la casser Ă  l’ajout de nouveaux paramĂštres Ă  l’initialisation par exemple. J’ai Ă©galement factorisĂ© toutes les fonctions qui permettent de configurer libvalhalla en une seule fonction variadique.

Statistiques

Avec libvalhalla-1.0.0 il y a dĂ©jĂ  quelques statistiques. Par exemple les rĂ©sultats et les temps utilisĂ©s par les grabbers, ou encore un rĂ©sumĂ© des actions qui ont Ă©tĂ© faites sur la base de donnĂ©e. NĂ©anmoins ces informations ne sont pas disponibles depuis l’API. Ce qui change dans le prochain libvalhalla c’est que toute les statistiques de ce type sont rĂ©cupĂ©rables facilement. Il y en a Ă©galement plus qu’avant. Je dois encore en ajouter sur certaines parties tel que le scanner. Mais les ajouts n’affecteront en rien l’API publique.

Dans le cas d’Enna ça pourra ĂȘtre utilisĂ© pour montrer (pour le fun) l’Ă©tat des diffĂ©rentes parties de libvalhalla dans une fenĂȘtre d’information. Les statistiques peuvent ĂȘtre interrogĂ©es Ă  n’importe quel instant, ce qui permet de suivre l’Ă©volution.

ÉvĂ©nements globaux

Il est possible d’avoir des Ă©vĂ©nements globaux comme par exemple une information qui prĂ©vient que tous les fichiers (pour une passe complĂšte du scanner) ont Ă©tĂ© traitĂ©s. Il n’y a pas beaucoup d’Ă©vĂ©nements pour l’instant. Ils ne sont pas des plus utiles, mais dans le cas d’Enna il permettront d’avoir une notification. Il est Ă©galement facile d’en ajouter des nouveaux.

Metadata callback

C’est un callback qui a Ă©tĂ© ajoutĂ© suite Ă  une proposition d’un tiers pour une demande assez spĂ©cifique. Le but est de pouvoir rĂ©cupĂ©rer depuis l’API publique toutes les metadata en mĂȘme temps qu’elles sont rĂ©cupĂ©rĂ©es par les parsers et grabbers. C’est donc un moyen d’avoir accĂšs aux donnĂ©es sans passer par la base de donnĂ©e. Je ne recommande pas son utilisation pour plusieurs raisons. Tout d’abord si le callback est bloquĂ© relativement longtemps pour chaque metadata, l’utilisation mĂ©moire va augmenter en fonction (le blocage du callback ne bloque pas le reste de la bibliothĂšque). Il faut absolument veiller Ă  traiter les donnĂ©es aussi vite que possible. La deuxiĂšme raison est que SQLite est beaucoup plus performant pour rendre toutes les metadata. Les fonctions de sĂ©lections sont relativement haut-niveaux et permettent de rĂ©cupĂ©rer les informations de maniĂšre efficaces et ordonnĂ©e. Une de ces fonctions a Ă©galement Ă©tĂ© un peu amĂ©liorĂ©e dans le cadre des modifications depuis la version 1.0.0.

J’ai qu’en mĂȘme rajoutĂ© la fonctionnalitĂ© dans la bibliothĂšque car elle n’est pas intrusive et ne peut pas introduire des rĂ©gressions ou des ralentissements.

Grabbers parallélisés

C’est la plus grosse nouveautĂ© pour la prochaine release. Dans le cas de libvalhalla-1.0.0, beaucoup d’Ă©lĂ©ments travaillent en parallĂšle, Ă  l’exception des grabbers (entre eux). Il est possible maintenant d’avoir “autant” de grabbers que l’on veut simultanĂ©ment. Cette fonctionnalitĂ© permet d’Ă©conomiser environ 30% du temps selon mes essais. L’intĂ©rĂȘt est Ă©galement que les fichiers vidĂ©os ne sont plus bloquĂ©s sur les grabbers dĂ©diĂ©s Ă  l’audio et inversement. Par exemple le grabber LyricWiki qui est spĂ©cialement lent, Ă©tait un vrai goulot d’Ă©tranglement pour les fichiers vidĂ©os (aussi pour les autres fichier audio, ce qui est implicite). La parallĂ©lisation permet Ă  ces fichiers (non-audio) de se terminer indĂ©pendamment de ce grabber (et des autres).

J’ai mis la limite maximum Ă  16 grabbers en parallĂšle (ce qui est plus que le nombre de grabbers diffĂ©rents qui existent). Un choix efficace et d’opter pour 3 ou 4. L’utilisation de la RAM n’est pas spĂ©cialement affectĂ©e car la plupart utilisent des services web qui sont plutĂŽt gourmand en temps.

Il y a deux autres effets Ă  noter:

Le fonctionnement en quelques mots

La parallĂ©lisation des grabbers n’est pas comparable Ă  celle des parsers. Lorsqu’un fichier doit ĂȘtre traitĂ© par un parser, il attend simplement dans la queue jusqu’Ă  ce qu’un parser le POP et le traite vraiment. Il n’y a pas de raison de faire autrement car tous les parsers font le mĂȘme travail. Les grabbers sont diffĂ©rents car chacun d’eux fait un travail spĂ©cifique. Ainsi lorsqu’un fichier se retrouve dans la queue et qu’un thread de grabber le POP, il va chercher un grabber de libre. Le cas Ă©chĂ©ant il renvoi le fichier dans la queue et rĂ©essaye avec le suivant. Il n’y a donc jamais de longue attente, ce qui permet de bien enchaĂźner tous les fichiers.

Il y a aussi quelques conditions. Un mĂȘme fichier n’est jamais parallĂ©lisĂ© entre les diffĂ©rents threads des grabbers. Et un mĂȘme grabber travail que dans un seul thread Ă  la fois. Ce qui veut dire par exemple, que s’il y a 10 threads; pour que les 10 soient actifs il faut au moins 10 grabbers diffĂ©rents (FFmpeg, LyricWiki, Amazon, etc,
), et 10 fichiers diffĂ©rents.

Il est ainsi Ă©vident que d’avoir beaucoup de threads n’apportent absolument plus rien au delĂ  d’une certaine limite que j’estime Ă  environ 4. Mais ceci dĂ©pend fortement des types de fichiers diffĂ©rents, des types de grabbers compilĂ©s et leur nombre.

Bonne année,
Mathieu SCHROETER