Articles Tagués ‘Valhalla’

h1

libvalhalla-2.1.0

2012.08.12

Hey ça faisait vraiment longtemps. Comme quoi, vaut mieux tard que jamais.

J’ai publié une nouvelle version de libvalhalla qui remet à jour les grabbers Amazon et TMDB. C’était principalement des problèmes de changement d’API chez ces deux services. A noter que les grabbers qui se basent sur des scripts PHP maison sont cassés mais non-réparés. Je pense à Allocine et ImDB. Mais pour ces deux grabbers il faut être clair, sans vrai webservice c’est très pénible à maintenir. Il existe un webservice caché pour Allocine et j’ai cet API sous la main. Par contre je ne sais pas si c’est encore fonctionnel (car l’API que j’ai a plus d’une année) et peut être que depuis tout ce temps il y a quelque chose d’officiel. En ce qui concerne ImDB j’en ai aucune idée.

A part ça il y a quelques changements plus spécifiques. Je vous invite à consulter le ChangeLog.

Site : http://libvalhalla.geexbox.org

Sources : http://libvalhalla.geexbox.org/releases/libvalhalla-2.1.0.tar.bz2

Bye bye

Mathieu

h1

Quoi de neuf…

2010.07.03

Hello,

Pas beaucoup de nouvelles depuis passablement de temps. Je vais faire néanmoins un petit tour en bref des quelques activités sur lesquels j’ai travaillé. Mon activité sur les projets GeeXboX à baissé nettement depuis quelques semaines pour plusieurs raisons. J’ai eu 3 mois de service civil où j’ai qu’en même pu travailler dans mon domaine (l’informatique et plus précisément la programmation). Et de ces trois mois, sont nés deux petits projets hébergés sur les serveurs GeeXboX.

DaisyDuck & libduck

DaisyDuckJe vous invite à consulter le site internet. DaisyDuck est un lecteur de livre audio Daisy 2.02, basé sur Qt et libVLC. Il est multi-plateforme et distribué aussi bien pour Windows que pour Linux. Il pourrait également être adapté sans trop de problème à MacOSX. Mais pour des questions de temps, je me suis arrêté à la version Windows.

Il existe de "nombreux" (beaucoup de commerciaux aussi) programmes de lecteur de livre Daisy. Mais la grande différence avec DaisyDuck c’est tout d’abord libVLC. La plupart ne sont pas capables de lire une grande variété de format, et encore moins de protocole réseau. Même qu’en principe pouvoir lire n’importe quel format n’est pas un respect entier des spécifications. Par contre c’était le but de mon travail. Permettre la lecture de livre en ligne, ce que le logiciel est parfaitement capable de faire, et ça fonctionne à merveille. Merci à l’équipe de VideoLAN.

Le deuxième petit projet est donc libduck. Il est également présenté sur le site internet de DaisyDuck. Son but est de réaliser le "parsing" des fichiers Daisy 2.02.

Malheureusement je n’ai pas utilisé libplayer comme base à DaisyDuck. La raison principale est que libplayer n’est pas encore très utilisable (compilable) pour Windows pour différentes raisons techniques. Et faute de temps, je ne pouvais pas me permettre de travailler sur le port de libplayer dans mon temps destiné à mon service civil.

Valhalla

Bien que j’ai terminé le service civil depuis fin mai, il me fallait également trouver un emploi. Et depuis mi juin, j’effectue des trajets relativement longs par jour. Mon temps libre en soirée est devenu presque nul. Je me motive alors à travailler sur les projets GeeXboX, dans le train. Et faut bien l’avouer, c’est difficile d’avancer vite. Mais ça avance qu’en même, et sur libvalhalla cette fois ci.

J’ai commencé sérieusement à ajouter le support des langues pour les méta-données. Le patch devrait arriver très vite, peut être même demain. Par contre ce n’est pas encore complet. Je dois adapter les fonctions pour les sélections des méta-données afin de pouvoir filtrer sur les langues, il me faut aussi encore implémenter le support des grabbers multi-lingues. Ou tout du moins, pouvoir paramétrer les grabbers multi-lingues pour récupérer les données dans une langue spécifique. Au moment où j’écris ces lignes, j’ai uniquement ajouté le support des langues dans la base de donnée, et adapté les grabbers afin que l’information de langue soit correctement indiquée avec les meta-données. Par exemple, le grabber Allocine indique ainsi du "fr" pour ce qui est des résumés, catégories, etc,.. Les autres grabbers sont en principe en "en" et les données qui n’ont pas de langue (par exemple un codec, la taille du fichier ou alors la résolution) sont indiquées comme "undef". Toutes les méta-données récupérées par les "parsers" sont également en "undef".

Un autre projet dans lequel je veux me lancer sérieusement, c’est de pouvoir paralléliser le "downloader" et les "grabbers" pour un même fichier. Afin de récupérer les images un peu plus vite. Mais je ne veux pas rentrer dans ce genre d’explications avec ce poste.

libplayer

Aux alentours de mai, j’ai intégré le support de VDPAU directement dans libplayer. Alors non, il n’y a rien d’extraordinaire, ça concerne quelques lignes. L’idée c’est que pour pouvoir exécuter MPlayer correctement avec VDPAU, il faut connaître les caractéristiques du GPU. Et pour ça, il faut interroger la carte graphique. Avec GeeXboX, cela se faisait en dehors d’Enna/libplayer avec un script et un exécutable. Mais ceci n’est plus nécessaire, car maintenant libplayer fait cette tâche de manière transparente.

Enna

Nicolas à modifié en profondeur le VFS d’Enna. J’ai donc pris le temps de retravailler le browser Valhalla. Celui-ci est désormais mieux fait au niveau des chemins d’accès (je n’ai pas envie d’expliquer ça ici). Bref, en gros ce browser re-fonctionne avec le nouveau VFS mais il a qu’en même quelques petites régressions qui ne devraient pas être trop difficiles à corriger.

Le projet de "hardware"

Réaliser un set-top box GeeXboX est très nouveau et assez ambitieux. L’idée est de partir de zéro, de la schématique au PCB puis aux prototypes, pour finir avec la distribution GeeXboX/Enna optimisée au mieux pour le matériel. Le seul gros obstacle actuellement c’est la difficulté à avoir accès aux datasheets des composants intéressants (NDA nécessaires dans quasiment tous les cas). On vise bien sûr le full-HD avec si possible un petit plus par rapport aux autres boards. Tel que par exemple des ports miniPCIe. On a les ressources techniques, manque la doc :-). Ensuite il y aura forcément le problème du temps qui pourra être investi dans ce projet. Mais pour le moment je suis assez confiant.

Pour terminer (et pour arrêter de parler de moi)

Toolchain

Davide fait un gros boulot depuis plusieurs semaines. Il a pris une excellente initiative concernant le toolchain GeeXboX. Le but est d’avoir un toolchain basé sur opkg. Tout se construit via des paquetages, que se sois les dépendances pour la construction du toolchain (gcc, binutils, etc…) que les éléments du "target".

J’ai toujours aimé le toolchain GeeXboX pour sa simplicité. On entend souvent parler d’OpenWRT par exemple. Il est sûrement très bien, mais notre toolchain c’est notre identité. J’ai toujours été réticent à le voir se faire remplacer par une solution qui viendrait d’ailleurs. Alors un grand merci à Davide pour avoir fait ce gros job!

Le site web

Benjamin en avait marre du site web. Je le comprend tout à fait car j’ai toujours eu la flemme d’y faire des modifs. Faut être clair, chez GeeXboX en principe faut un peu toucher à tout. Mais parfois les tâches comme le site, pas grand monde à envie d’y mettre les mains. Alors Benjamin à basculer sur WordPress qui simplifie grandement la vie aussi bien pour la facilité que pour le design.

J’aimerais qu’en même dire un mot sur l’ancien site. Il avait une particularité en comparaison à beaucoup d’autres sites internet. Ce bon vieux site était entièrement réalisé en XML+XSL (un très bel exemple et très professionnel). Bien sûr les sources sont toujours bien au chaud, dans les dépots Mercurial.

Enna

Nicolas a fait diverses modifications sur Enna en plus du VFS. Néanmoins je n’ai pas encore pu compiler ces dernières modifs :-P. Faute de temps principalement, car je dois mettre à jour les EFL.

A bientôt,

Mathieu SCHROETER

h1

De "POSIX" à Windows

2010.02.19

Hello,

La sortie d’Enna au début janvier à réveiller des critiques de tous les genres. En principe (faut être honnête) elles ne m’intéressent pas spécialement. Tout d’abord je n’estime pas qu’il y ait de concurrence entre les logiciels libres. Beaucoup de projets s’inspirent d’autres projets et c’est normal. Et si quelqu’un désire une fonctionnalité spécifique il a plusieurs solutions. La première c’est d’utiliser le projet qui offre la fonctionnalité (non?). La seconde c’est de critiquer simplement le projet car une fonctionnalité évidente est absente. Se sont ces critiques là que j’ignore spécialement, car elles n’apportent rien.  Après vous avez des gens qui critiquent mais qui aident spontanément et ils sont toujours les bienvenue.

De "POSIX" à Windows

Une des critique facile est de dire qu’Enna ne fonctionne pas sous Windows et qu’XBMC par contre est multi-plateforme. Les gens qui le disent ont tendance à oublier (ou alors à ne pas du tout connaitre, même dans les grandes lignes) l’histoire d’XBMC. Et oui, à l’origine XBMC ne fonctionnait pas nativement sous Linux. Le port à pris du temps, et c’est le même problème quand il faut porter dans l’autre sens.

Pour en revenir à Enna, je n’ai aucun intérêt personnel à l’avoir sous Windows. Néanmoins il y a eu des progrès pour qu’un jour, Enna puisse fonctionner sous Windows. Pour quand? Je n’en sais rien et ça n’a aucune importance.

Concernant le titre, si j’ai mis POSIX entre guillemets c’est parce que tout n’est pas vraiment du POSIX. Certaines choses sont des extensions du GNU par exemple. Il y a des adaptations à faire aussi entre les systèmes qui se basent sur POSIX. Même entre les noyaux Linux et *BSD, voir même Hurd.

Par exemple libvalhalla fonctionne correctement sous les noyaux Linux et FreeBSD (je pense spécialement à Debian GNU/kFreeBSD), elle fonctionne aussi avec Hurd (testé avec Debian GNU/Hurd) à la différence que les priorités sur les threads ne sont pas gérées correctement. Chaque noyau à sa façon de faire des threads et ça demande de prendre en compte les cas particuliers.

J’ai volontairement omis de mentionner Mac OS X, ou plus précisément Darwin. Bien qu’Apple dit qu’il soit POSIX-compliant, il y a qu’en même au moins un cas particulier dans libvalhalla car ce n’est pas si POSIX que ça.

MinGW

Le meilleur moyen de réaliser des ports Windows est sans aucun doute MinGW. C’est une base GCC et le compilateur peut être natif Windows ou alors compilé pour une compilation croisée sous GNU/Linux (ou d’autres OS). En principe depuis GNU/Linux on peut cross-compiler aussi bien pour Windows que pour Darwin (c’est ainsi que les différentes versions du générateur d’ISO sont faites). Néanmoins, ça peut paraitre étonnant mais il est plus facile de créer un compilateur croisé pour Windows (merci au projet MinGW) que pour Darwin.

J’ai deux cross-compilateurs binaires pour Darwin8 (PPC et i686). Ils ont été créés il y a maintenant plusieurs années par un ancien membre de GeeXboX. Malheureusement il est parti avec les secrets de fabrication. Je n’ai jamais réussi à les reproduire depuis les sources (et ce n’est pas faute d’avoir essayé). Si quelqu’un à des pistes, elles m’intéressent grandement!

libgeexbox-win32

Avant d’espérer Enna sous Windows il faut bien sûr se concentrer sur les dépendances. Et ce qui nous intéresse ici c’est donc libnfo, libplayer et libvalhalla. Au moment où j’écris cet article, libnfo et libvalhalla sont "complètement" supportés sous Windows. Je vais reprendre quelques éléments intéressants qui ont posés des problèmes.

Notez les guillemets, car en ce qui concerne libvalhalla il reste un potentiel problème. Mais néanmoins la bibliothèque est utilisable.

Libvalhalla utilise des temporisations à différents endroits. Celles-ci sont réalisées à l’aide de variable-conditions/mutex. L’idée est d’avoir des temporisations interruptibles contrairement à des fonctions du type sleep(), usleep() ou nanosleep() (attention, je parle bien de temporisations interruptibles sans l’aide de signaux). La bibliothèque Pthreads de POSIX offre tout ce dont on a besoin. Ainsi libvalhalla et libplayer reposent complètement sur celle-ci. Mais ce n’est pas directement de Pthreads que je désire parler, mais du temps pour pouvoir espérer avoir des temporisations plus ou moins précises. Les fonctions pthreads utilisent la structure `struct timespec` qui en théorie offre un champ à la nanoseconde. Même si la valeur peut être juste au moment de la lecture de l’horloge, les appels de fonctions prennent de toutes façon des nanosecondes/microsecondes. Et même pour un système temps réel dur, c’est très difficile de jouer dans ces ordres de grandeurs. Les seuls applications pratiques où je me suis vraiment amusé à compter les nanosecondes c’est lorsque que je faisais du VHDL sur un bon vieux Xilinx.

Bref.. passons.. Mon but est de pouvoir traiter des temporisations de plusieurs centaines de millisecondes. Ce qui est très facile avec un noyau Linux. La structure timespec évoquée précédemment se présente ainsi.

struct timespec {
  time_t sec;
  long int nsec;
}

Sous *BSD, Linux et Darwin il est très facile de la peupler. Concernant Mac OS X et son pseudo POSIX-compliant, le noyau Mach permet de récupérer une structure relativement semblable avec également des nanosecondes, mais la fonction POSIX clock_gettime() n’existe pas chez Apple. Que le champ nsec soit juste ou non ça n’a pas d’importance, pour autant qu’il ne soit pas faux dans les millisecondes. Finalement ces trois noyaux offrent les fonctions nécessaires et même plus. Mais on ne peut pas en dire autant de l’API Windows.

Une question de temps

GetSystemTime

Windows met à disposition des fonctions nommées GetSystemTime() et GetSystemTimeAsFileTime(). Elles sont sensées retourner une résolution à la milliseconde, respectivement à la centaine de nanoseconde. GetSystemTimeAsFileTime() est connu comme étant plus rapide que GetSystemTime(). Par contre cette fonction n’existe pas sous Windows CE et perd donc de son intérêt (dès le moment qu’on recherche la portabilité).

Voyez plutôt le résultat en pratique avec mon PC.

 WinXP                         GNU/Linux/Wine
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
GetSystemTime ()
 1266227465.000000000          1266233962.000000000
 1266227465.000000000          1266233962.000000000
 1266227465.000000000          1266233962.000000000
 1266227465.000000000          1266233962.000000000
 1266227465.000000000          1266233962.000000000
 - wait 1 ms
 1266227465.015000000          1266233962.001000000
 - wait 2 ms
 1266227465.031000000          1266233962.003000000
 - wait 3 ms
 1266227465.046000000          1266233962.006000000
 - wait 4 ms
 1266227465.062000000          1266233962.010000000
 - wait 5 ms
 1266227465.078000000          1266233962.015000000

A gauche il y a donc les résultats directement depuis Windows XP. A droite c’est le même programme mais exécuté à travers Wine (le même PC est utilisé). Les attentes de 1 à 5 ms sont réalisées simplement par la fonction Sleep() également mise à disposition par l’API Windows. Il est intéressant de noter que Windows n’arrive pas à descendre à la milliseconde avec un Sleep(1). Problème connu ceci dit…

A noter également que la fonction GetSystemTime() n’est pas des plus performante. Elle est reconnue comme étant peu propice à offrir réellement 1 ms de résolution. J’ai fais ainsi une seconde mesure avec 10’000 lectures du compteur, pour détecter la résolution effective.

Après plus de 8’000 lectures, Windows retourne vraiment 15 ms de plus que la lecture précédente.

 1266484241.000000000
 1266484241.000000000
 ... ~8000 fois ...
 1266484241.000000000
 1266484241.000000000
 1266484241.015000000
 1266484241.015000000
 1266484241.015000000
 1266484241.015000000

GetSystemTimeAsFileTime

J’ai donc refais les mêmes mesures mais avec GetSystemTimeAsFileTime() pour voir si on arrive à des meilleurs résultats. Le MSDN parle de 100 ns, on peut donc espérer une résolution utilisable à la milliseconde.

 WinXP                         GNU/Linux/Wine
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
GetSystemTimeAsFileTime ()
 1266227465.078125000          1266233962.015939000
 1266227465.078125000          1266233962.015941000
 1266227465.078125000          1266233962.015942000
 1266227465.078125000          1266233962.015944000
 1266227465.078125000          1266233962.015945000
 - wait 1 ms
 1266227465.093750000          1266233962.017012000
 - wait 2 ms
 1266227465.109375000          1266233962.019076000
 - wait 3 ms
 1266227465.125000000          1266233962.022139000
 - wait 4 ms
 1266227465.140625000          1266233962.026204000
 - wait 5 ms
 1266227465.156250000          1266233962.031268000

La première chose qui frappe ici, c’est que Windows semble donner que des valeurs multiples de 25. Donc d’une résolution de 25 us. On est encore relativement loin des 100 ns promis par le MSDN. Mais pour tester la vrai résolution, j’ai également fais tourner la lecture 10’000 fois.

On constate que Wine arrive à atteindre la microseconde. Néanmoins on n’a pas non plus la résolution de 100 ns. La raison est que Wine se base sur la fonction gettimeofday() qui sous les systèmes POSIX, ne donne pas une résolution meilleure que la microseconde. La structure est un timeval au lieu d’un timespec avec un champ usec au lieu de nsec.

Ici aussi, après environ 8’000 lectures, on constate une résolution d’exactement 109.375-93.75=15.625\,ms. C’est aussi mauvais qu’avant. Les microsecondes n’apportent absolument rien. Au début je me suis fais avoir car je pensais vraiment que les 25 us étaient atteints. Et bien que la fonction est sensée être plus rapide d’après mes recherches, en pratique (sous Windows XP), il n’y a pas de quoi en faire une montagne. Il a fallut presque le même nombre de lecture (un peu plus de 8000) pour environ 15 ms.

 1266484241.093750000
 1266484241.093750000
 ... ~8000 fois ...
 1266484241.093750000
 1266484241.093750000
 1266484241.109375000
 1266484241.109375000
 1266484241.109375000
 1266484241.109375000

Je pense qu’elle est considérée comme plus rapide car elle ne peuple pas une structure relativement complexe comme GetSystemTime (voir SYSTEMTIME). La structure utilisée avec la seconde fonction est FILETIME.

Finalement, comme première conclusion et pour garder la compatibilité avec Windows CE on peut utiliser GetSystemTime() sans regret.

clock_gettime

Il existe donc un moyen d’avoir une bien meilleur résolution. Le principe est d’utiliser l’horloge haute résolution (la TSC dans les processeurs x86) afin d’atteindre la nanoseconde. Pour ce faire, Windows met à disposition deux fonctions, QueryPerformanceFrequeny() conjointement avec QueryPerformanceCounter().

Le but final est de simuler la fonction clock_gettime() de POSIX qui permet d’atteindre une résolution de 1 ns.

La première fonction donne la fréquence de l’horloge haute résolution et la seconde donne le nombre de ticks depuis la mise en route. La fréquence donnée est toujours (à peu de chose près) un multiple de 1193182 Hz.

Le principe est donc de retrouver le tick qui correspond à un temps précis depuis EPOCH. Puis de retrouver le temps en divisant simplement le nombre de ticks par la fréquence. L’horloge étant au minimum cadencée à 1193182 Hz, on devrait avoir au moins une résolution de \frac{1}{1193182}=838.10\,ns.

 WinXP                         GNU/Linux/Wine
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 Freq: 3579545                 Freq: 1193182
 1266227465.156298915          1266233962.031381633
 1266227465.156301150          1266233962.031384147
 1266227465.156302826          1266233962.031385823
 1266227465.156304502          1266233962.031387499
 1266227465.156306178          1266233962.031389176
 - wait 1 ms
 1266227465.171900059          1266233962.032571728
 - wait 2 ms
 1266227465.187522995          1266233962.034622547
 - wait 3 ms
 1266227465.203157943          1266233962.037689975
 - wait 4 ms
 1266227465.218764954          1266233962.041754736
 - wait 5 ms
 1266227465.234392918          1266233962.046825211

A noter que Wine donne toujours la fréquence la plus basse. Cette fréquence normalement dépend du matériel, mais Wine se base sur Linux pour récupérer le temps. Ainsi la fréquence peut être arbitraire. Windows XP me donne par contre une fréquence pas tout à fait correcte. Comme je l’ai dis avant, celle-ci devrait être un multiple de 1193182, pourtant pour que ce multiple soit vrai, il faudrait alors 3579546 au lieu de 3579545. Je suppose que la fonction QueryPerformanceFrequeny() n’arrondit pas la valeur.

On trouve ici un pas de 1676/1677 ns. Aussi bien avec Windows qu’avec Wine. Ce qui est très bon. Le temps perdu vient désormais des appels de fonctions et non plus de l’imprécision des valeurs de temps.

On pourrait crier victoire, mais en réalité il y a encore un problème potentiel. L’horloge haute résolution est indépendante. Ce qui veut dire qu’elle va forcément diverger par rapport à l’horloge qui donne le "vrai" temps. Ainsi sur une longue période, l’erreur entre les deux va s’agrandir linéairement.

Étant donné que la résolution de GetSystemTimeAsFileTime() est trop imprécise pour de courtes mesures, il est nécessaire de faire des mesures sur plusieurs heures pour avoir des résultats significatifs.  Seul la résolution de 15.625 ms peut servir de référence et une telle divergence ne peut pas être détectée sur quelques minutes (à moins que QueryPerformanceCounter() et QueryPerformanceFrequeny() soient complètement faux). Je n’ai donc rien à vous montrer au sujet de ce potentiel problème de divergence.

La synchronisation

Bien que je ne connaisse pas encore la divergence entre les horloges, on peu légitimement se poser la question de la resynchronisation.

Le principe est d’utiliser une information qui est fiable. Et donc a priori c’est la seconde. L’idée est de récupérer le tick qui correspond au changement de seconde. Ensuite ce tick est converti en un temps depuis EPOCH (un temps absolu en seconde). On mémorise cette seconde pour toute la durée de vie du programme.

Dès que clock_gettime() est appelé, on regarde la valeur du compteur de l’horloge haute résolution, puis on la soustrait à la valeur qui correspond aux secondes du début. On a donc une différence de valeur du compteur. On la divise par la fréquence du compteur ce qui nous donne la différence de temps. On additionne ce nouveau temps avec les secondes du départ pour enfin avoir le temps en nanoseconde depuis EPOCH.

Le potentiel problème avec la synchronisation vient spécialement du fait d’utiliser la seconde comme référence. Si la synchronisation commence au début d’une nouvelle seconde, il faut attendre quasiment une seconde pour terminer la synchronisation. Ainsi actuellement dans le libvalhalla pour Windows, il n’y a pas de resynchronisation. En fonction du décalage entre l’horloge haute résolution et l’horloge du temps, les timers finissent par se rentrer dedans ou alors par devenir de plus en plus écartés. Le fait qu’ils divergent ou convergent dépend du matériel.

Je vois deux solutions pour le moment.

  1. Faire la resynchronisation en parallèle au reste du programme. Ainsi on peut continuer d’utiliser clock_gettime() avec la précédente synchronisation.
  2. Synchroniser sur GetSystemTimeAsFileTime() avec son pas de 15.625 ms. Mais la compatibilité avec Windows CE est perdue.

Il reste aussi à déterminer quand est-ce qu’il faut resynchroniser.

Un autre problème vient des changements de l’heure du système. Si cela arrive, actuellement libvalhalla aura toutes les temporisations faussées sous Windows.

Les Pthreads

Finalement, on peut se demander si tout cela vaut la peine. Les Pthreads pour Windows ont été conçus pour fonctionner sur un maximum de versions de Windows. Ainsi la référence de temps utilisée se fait via GetSystemTime(). Le clock_gettime() utilisé dans libvalhalla à deux raisons d’être. D’abord il sert à donner un temps absolu aux fonctions Pthreads, et il sert à faire les mesures de temps pour les statistiques. L’aberration dans tout ce travail sur un clock_gettime() pour Windows est simplement que le temps donné aux fonctions Pthreads est de bien meilleur résolution que la résolution du temps interne au Pthreads-win32  (il faudrait néanmoins que je vérifie ce point, je n’ai fais que survoler les sources de Pthreads-win32). Et avoir une résolution à la nanoseconde pour des statistiques n’apporte rien.

Un des seul intérêt restant c’est donc le petit défi que ça représente.

J’hésite à enlever tout le code relatif à QueryPerformanceCounter() pour n’utiliser que GetSystemTime() avec sa misérable résolution. Ou alors rajouter un test sur la fonction GetSystemTimeAsFileTime() pour la préférer à GetSystemTime() si elle existe. Tout ces problèmes me rappel toujours un peu plus pourquoi Windows à un noyau  qui n’a rien de plus que les autres. Mais qui au contraire, ne créer que des problèmes supplémentaires.

Speedhack

Je profite de cet article pour présenter les speedhacks (ces logiciels de triches permettant par exemple de se déplacer plus vite dans un jeu, très prisé à l’époque sur Counter-Strike).

Si j’en parle ici c’est qu’ils reposent sur les fonctions de l’horloge haute résolution, et plus précisément QueryPerformanceCounter(). Il y a un peu plus d’un an, j’avais écris un article à ce sujet que vous pouvez lire à cette adresse. J’en ai profité pour y faire deux trois améliorations et corrections.

A bientôt,

Mathieu SCHROETER

h1

Quoi de neuf sur les libs

2010.01.03

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() 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 libplayet-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:

  • Les priorités ne sont plus complètement respectées si on défini plus d’un grabber à la configuration. Ce qui veut dire que par exemple un fichier peut être envoyé dans un grabber qui devrait (selon les priorités) être interrogé dans les derniers. Il est donc possible de continuer à travailler comme libvalhalla-1.0.0 en forçant explicitement le nombre à 1.
  • Le second effet est lié au ondemand. Celui-ci est plus rapide car il y a plusieurs threads de grabbers et donc il peut rapidement avoir toutes ces demandes sur tous les threads (à cause des priorités du ondemand).

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

h1

Autour de la compilation d’Enna

2009.12.17

Hello,

je tiens juste à donner quelques précisions pour les personnes qui désirent compiler Enna, et donc également les bibliothèques rattachées. Cet article n’est pas un tutoriel. Si vous ne savez pas comment vous y prendre, il vaut mieux rechercher l’information ailleurs.

Faites aussi un tour à ces adresses (en anglais / in english) :
http://enna.geexbox.org/developers.html
http://captainigloo.wordpress.com/2009/12/21/enna-compilation-on-ubuntu-3/

Evas

Comme vous le savez, Enna se base sur les EFL. Je vous conseil fortement d’utiliser les snapshots ne serait-ce au moins pour ne pas que vous reportiez des "bugs" juste parce que les APIs des EFL auraient trop évoluées. En partant du principe que vous savez compiler les EFL, je vous rappel de ne pas oublier le flag ––enable–gl–x11 avec Evas, si vous avez l’accélération 3D avec votre PC. Les performances graphiques d’Enna sont nettement meilleurs. Toujours concernant Evas, il y a une petite modification dans les sources qui vous permettra d’avoir des textures anti-aliasées. Dans le cas contraire, Enna est plus beau (mais plus lent) en X11 Software plutôt qu’en OpenGL. Il faut tout simplement modifier les définitions GL_NEAREST en GL_LINEAR dans toutes les sources.

cd ~/e17_src/evas
sed -i "s/GL_NEAREST/GL_LINEAR/g" \
    `grep -Rl GL_NEAREST . | grep "\.c$"`

Libgeexbox

Libgeexbox est une manière naïve de parler de toutes les bibliothèques que nous développons en parallèle à la distribution et à Enna. Depuis quelques temps, des releases sont apparues pour libnfo, libplayer et libvalhalla. Il faut savoir que se sont les toutes premières releases! Là où je veux en venir c’est qu’il était totalement justifié de toujours se baser sur les versions de développement pour compiler Enna. Par exemple le premier import de libplayer date de 2006 et c’était une habitude que de faire un hg pull -u régulièrement. Mais maintenant que les versions 1.0.0 sont disponibles, veuillez s.v.p. vous baser uniquement sur celles-ci (ou sur n’importe quelles nouvelles releases de ces libs dans le futur).

Il y a deux solutions, en passant sur les sites web respectifs des projets (les liens sont disponibles à droite des articles de ce blog) ou alors avec Mercurial. Mais dans ce cas veuillez préciser la version de la dernière release. Tel que par exemple:

hg clone -r v1.0.0 http://hg.geexbox.org/libvalhalla

Si vous chargez la devel (donc le "tip") vous ne pourrez pas compiler Enna ou alors vous avez de la chance :-). Depuis qu’il y a les releases je me permets de casser les APIs des bibliothèques parce que je suis un éternel insatisfait (je rigole…) et ça faisait longtemps que je voulais faire un peu de ménage dans certaines en-têtes publiques.

Et après l’installation des libgeexbox, n’oubliez pas de faire un `sudo ldconfig`. Question que le chargeur de programme ait les nouvelles bibliothèques de référencées.

libvalhalla

Quand vous exécutez le configure de libvalhalla, jetez un œil aux informations retournées avant de faire bêtement un `make`. Le configure désactive les éléments en fonction des bibliothèques qu’il ne trouve pas. Par exemple, si vous n’avez pas la libcurl-dev, le support des grabbers est complètement désactivé mais cela n’empêche pas la compilation.

Admettons que vous avez toutes les libs nécessaires et que vous voyez certains grabbers de désactivés. Je pense par exemple à lyricsfly. Ce n’est pas un bug. Lyricsfly n’est pas utilisable car la clef de l’API pour le webservice était provisoire. Ce grabber est donc désactivé par défaut. Si vous utilisez ––enable–grabbers pour être sûr d’activer tous les grabbers vous n’aurez rien à gagner. Vous ferez perdre du temps à libvalhalla sur lyricsfly qui ne retournera jamais rien (je parle de lyricsfly, mais ça peut être d’autres à l’avenir).

A noter également que dès que vous forcez les grabbers ou seulement quelques grabbers, leurs dépendances deviennent obligatoires. Par exemple si vous faites ––enable–grabber–ffmpeg vous forcez la dépendance sur libavcodec. Si vous avez vraiment libavcodec et que ça échoue, c’est simplement que votre version est trop ancienne. Par exemple, le libavcodec que vous trouvez avec Ubuntu Karmic ne supporte pas la fonction av_lockmgr_register() qui garanti l’utilisation des codecs à être multi-thread safe.

libplayer

Concernant libplayer, c’est la dépendance indirecte avec MPlayer qui est la plus importante. Assurez-vous que votre MPlayer est en anglais uniquement. Libplayer peut détecter les MPlayer incompatibles jusqu’à un certain point. En fonction de la manière dont MPlayer a été compilé, libplayer ne peut pas savoir s’il est en anglais ou non et va donc l’utiliser (pour les curieux, je parle de la variable d’environnement LINGUAS à la compilation d’MPlayer; libplayer ne détecte la langue que si celle-ci est passée avec ––language–msg= ou ––language=).

Démarrer Enna

Contrairement à certains tutoriels sur Enna, il n’est pas nécessaire de copier le fichier d’exemple enna.cfg qui se trouve à la racine des sources, dans le dossier ~/.enna. Parce que ce fichier est automatiquement créé au premier démarrage de l’interface. Et allez jeter un œil au contenu. Si vous voulez que libvalhalla puisse faire son travail, vaut mieux lui dire où il doit scanner. Dans le cas contraire 100% des fichiers seront traités en ondemand (je vous laisser chercher dans ce blog si vous ne comprenez pas).

Et maintenant que vous avez l’OpenGL, vous remarquerez assez vite qu’en le spécifiant dans ~/.enna/enna.cfg ça ne change pas grand chose. Pire que cela, ça ne change absolument rien ;-).

Pour l’instant il faudra le faire à la main depuis un terminal, avec:

ELM_ENGINE=gl enna

A bientôt,

Mathieu SCHROETER

h1

Le "decrapifier" de libvalhalla

2009.12.02

Hello,

sous ce nom barbare se cache un modeste et petit mécanisme pour nettoyer les noms des fichiers. Il faut savoir qu’avec des conteneurs audio et vidéo de bonne qualité, le titre du média est généralement stocké dans une méta-donnée "title". En général ce titre est propre et peut être utilisé tel quel pour une recherche d’information sur internet. Dans notre contexte, il est utilisé en général par les "grabbers" pour rechercher les données, paroles des chansons, descriptions, liste des acteurs, etc, … Malheureusement, on traine encore des boulets au niveau conteneur multimédia.

Un petit bond en arrière

Je me rappel encore très bien, à l’époque de Windows 3.1/3.11 d’avoir installé le composant optionnel "Video for Windows". Celui-ci rendait possible la lecture de petites vidéos dans des conteneurs AVI (entre autres). J’avais les yeux qui brillaient quand je voyais ces mini-films défiler. Pourtant aujourd’hui on se plaint quand une vidéo n’est même pas en 720p. D’un autre côté quand on voit le lecteur Flash qui bouffe toute la puissance CPU avec des vidéos de mauvaise qualité, y a de quoi se poser des questions par rapport à ce qui se faisait déjà il y a 15 ans en arrière. Voyez par exemple la vidéo suivante:

Cliquez dessus pour la lire! (si vous le pouvez :-P)

C’est un petit film qui date des alentours de 1997 (peut être même 1996), et qui est enregistré au format FLI. C’est un format d’animation d’image dans la même idée que le GIF. Ce petit film est cadencé à 14 images/sec avec une définition d’image de 320×200 px. Il peut y avoir également de la compression avec ce format, mais ce n’est pas aussi sophistiqué que du MPEG. Là où je veux en venir, c’est que cette vidéo est lisible de manière fluide sur un Smaky 130, qui correspond à un processeur Motorola 68030 (fixé à 25 MHz pour cet ordinateur). C’est d’un Smaky que j’ai récupéré ce film à l’aide d’un outil que je m’étais amusé à faire http://home.gna.org/fosfat/. La grande partie des logiciels Smaky sont écrits en CALM (en calme aussi), qui est une sorte de langage d’abstraction sur les assembleurs (une notation assembleur indépendante du fabricant). Il y a donc de forte chance que le Smaky utilise un logiciel écrit non pas en C/Pascal, mais en CALM pour arriver à lire cette animation. Ainsi le Flash me donne vraiment mal au ventre quand je le vois suer avec un Athlon X2 64.

Decrapifier

Bref, pour en revenir au "decrapifier", j’ai abordé les fichiers AVI. Ce conteneur développé à l’origine par Microsoft a aujourd’hui des défauts, et malheureusement on le retrouve encore bien trop souvent (on ne peut pas en vouloir à l’AVI, il est vieux). Quoiqu’il en soit, il n’y a pas de méta-donnée "title" la dedans.

Le "decrapifier" va alors se charger d’éliminer tous les caractères peu propice à aider à effectuer des recherches via les "grabbers". A noter également que lorsqu’un titre est nettoyé, c’est aussi une bonne chose pour l’utilisateur. Le principe est très simple et efficace dans la plupart des cas. Pour l’illustrer, prenons un nom de fichier inutilisable pour une recherche (et bien trop courant).

"{XvID-LOL}.Elephant.-.Dreams.s02e10_(DVDRip)_Etach.avi"
  1. Le nom est nettoyé de tous ses caractères dont le code ASCII est inclus dans les 7 premiers bits (128 premiers caractères). L’ASCII 7 bits à l’avantage d’être présent dans (presque) tous les codages de caractères dont l’unicode. L’idée est de simplement remplacer chacun de ces caractères par un espace, en prenant soins de supprimer l’extension du fichier (sauf exception pour l’apostrophe, les espaces et les caractères alpha-numériques qui sont conservés).
    "XvID LOL  Elephant   Dreams s02e10  DVDRip  Etach"
  2. Une liste noir de mots clefs va permettre d’éliminer tout ce qui ne nous intéresse pas pour la recherche. Les valeurs par défaut avec Enna (fichier ~/.enna/enna.cfg) sont:

    0tv, 1080p, 2hd, 720p, ac3, booya, caph, crimson, ctu, dimension, divx, dot, dsr, dvdrip, dvdscr, e7, etach, fov, fqm, hdq, hdtv, lol, mainevent, notv, pdtv, proper, pushercrew, repack, reseed, screencam, screener, sys, vtv, x264, xor, xvid, SExEP, sSEeEP

    Cette liste est donc éditable à souhait. Il y a deux mots clefs particulier (en fin de liste) que je vais expliquer dans un deuxième temps. Tous les autres mots clefs sont écrits en minuscules car le système n’est pas sensible aux majuscules en temps normal. On peut donc voir le résultat sous la forme suivante:

    "          Elephant   Dreams s02e10               "
  3. Mais le résultat précédent, bien que beaucoup plus intéressant, ne correspond pas à la réalité. Le mot clef "sSEeEP" présent dans la liste va permettre de gérer le s02e10. L’idée est de récupérer également des informations utiles comme la saison et le numéro d’épisode. Le vrai résultat est donc:
    "          Elephant   Dreams                      "
    

    Add new metadata "season", value: "2"
    Add new metadata "episode", value: "10"

  4. La dernière étape est de supprimer tous les espaces blancs superflus. Pour finalement avoir une chaîne de caractère sous cette forme:
    "Elephant Dreams"

Les motifs

Deux motifs ont été présentés brièvement. En réalité il y en a trois.

  • NUM (indique un nombre non signé et entier)
  • SE (indique un nombre non signé et entier qui représente une saison)
  • EP (indique un nombre non signé et entier qui représente un épisode)

Il y a quelques règles à prendre en compte lorsqu’on les utilise. Tout d’abord, ce type de mot clef est sensible aux majuscules. Par exemple, SSEEEP n’est pas égale à sSEeEP. Ensuite NUM, ne retournant aucune valeur, il peut être utilisé plusieurs fois dans un même mot clef.

Prenons l’exemple d’Elephant Dreams. Si le mot clef était sNUMeNUM, le résultat final serait exactement le même qu’au point 4. Néanmoins, aucune nouvelle méta-donnée seraient insérées. Cela peut donc être utile dans certains cas de figure où on trouverait des numéros inutiles. Il ne faut pas non plus abuser de ce genre de mots clefs. En voulant supprimer tous les numéros, on risquerait de ne plus avoir de titre (je pense au film "2012" par exemple).

Concernant SE et EP, ils ne doivent être utilisés qu’une seule fois par mot clef. Mais il y a qu’en même quelques libertés comme par exemple les mots clefs suivants sont parfaitement possibles: SeasonSE, EpisodeEP. Il n’est donc pas obligatoire d’avoir toujours SE et EP dans le même mot clef. Une autre considération concerne le nombre de saisons et d’épisodes pour un seul et même fichier. Imaginons un autre exemple complètement absurde:

"Mes Vacances (02x100) -s55e10-"

Si les mots clefs SExEP et sSEeEP sont présents dans la liste noir, le résultat final est donc bien:

"Mes Vacances"

Mais en plus il y a 4 nouvelles méta-données :

Add new metadata "season", value: "2"
Add new metadata "episode", value: "100"
Add new metadata "season", value: "55"
Add new metadata "episode", value: "10"

Pour terminer

Je ne tiens pas à donner des explications techniques sur le fonctionnement. Le gros du travail se fait via la magie de sscanf(). Le choix de NUM, SE et EP n’est pas non plus arbitraire. C’est uniquement par souci de commodité. En interne, le NUM est remplacé par %*u, les SE et EP sont remplacés par %u. Cela évite de devoir jouer l’accordéon avec les chaînes de caractères. Pour des détails, lisez le MAN de sscanf.

A bientôt,

Mathieu SCHROETER

h1

Un (tout petit) tour d’horizon

2009.11.23

Yop,

un tout petit tour d’horizon s’impose. Le travail sur (et autour de) Enna fait son petit bonhomme de chemin. Le design était sans cesse modifié mais depuis quelques semaines on a enfin quelque chose de relativement stable. Personnellement je n’ai pas beaucoup travaillé sur Enna car je continue à me concentrer sur libvalhalla. Il y a encore deux régressions de Enna qui sont dues à l’utilisation de libvalhalla.

Je parle de régressions, bien qu’il n’y a jamais eu de sortie officielle et stable. Il faut comprendre par là qu’avec toutes les modifications qui ont été apportées à Enna, de temps en temps des fonctionnalités disparaissent simplement parce qu’elle devraient être gérées d’une autre manière.

La première régression que je veux souligner est celle de pouvoir reprendre la lecture d’un film à l’endroit où il a été interrompu. Dit comme ça, il n’y a rien d’exceptionnel. Mais "à l’époque", l’enregistrement se faisait à l’aide de Eet qui était également utilisé pour stocker les méta-données des fichiers audio/vidéos. Depuis l’arrivée de libvalhalla et donc d’une base de donnée SQLite, Eet n’avait plus beaucoup de sens et cette partie a été simplement supprimée d’Enna. Mais la lib ne permet pas l’écriture depuis son API publique pour plusieurs raisons. Tout d’abord Valhalla ce n’est pas une bibliothèque pour gérer une base de donnée, mais c’est avant tout un scanner de fichiers, des "parsers" et des "grabbers". Les données sont récupérées par elle automatiquement. Il est donc possible de les lire depuis l’API publique. Lorsque des données doivent être modifiées, elles le sont depuis les fichiers (tags ID3 par exemple), ou alors depuis les site internets qui fournissent des informations (les grabbers, ImDB, Amazon, etc, …).

Mais pour répondre à certains besoins comme la sauvegarde de la position d’un film, il est nécessaire de reconsidérer cette question sur libvalhalla. J’ai donc commencé à travailler sur cet aspect il y a peu de temps. Il y aura ainsi une information qui permettra d’identifier des données venant de l’extérieur (parser, grabbers, …) et des données venant de l’intérieur. Pour mieux comprendre pourquoi il est nécessaire de faire des séparations, l’exemple d’un champ "playcount" est bien adapté. Le "playcount" (donc le nombre de fois qu’un fichier est lu), dépend uniquement de l’utilisateur d’Enna. Si le fichier en question est modifié (les tags par exemple), ce champ doit rester intacte ce qui n’est pas possible actuellement.

La deuxième régression concerne les "snapshots" (ou "fanarts"). Ils servent à avoir une image illustrant une video. Par exemple les images suivantes présentent les résultats pour quatre "trailers" où des données intéressantes ont pu être récupérées par les "grabbers" (j’ai récupéré les "trailers" sur le site d’Apple, merci au blogger en lien <ici> et <ici> pour l’astuce).


Dans tous ces exemples les images de fond ont pu être téléchargées sur le site TheMovieDB.org. Mais il peut arriver qu’aucune image ne soient disponibles et donc une alternative est nécessaire. Actuellement il y a une image de fond par défaut pour ces cas de figure, mais le but est de créer un "snapshot" directement avec le contenu de la vidéo. Cette fonctionnalité était disponible à l’époque où libvalhalla n’existait pas, et libplayer faisait office d’intermédiaire pour récupérer l’image à 20% de la vidéo. L’idée désormais est donc d’utiliser le "grabber" FFmpeg (ajouté il y a peu de temps) pour extraire l’image. Bien sûr, il ne faut pas l’extraire dans les cas où TheMovieDB contient déjà un "snapshot" de bien meilleur qualité.

Il y bien entendu toujours un panneau d’informations pour les vidéos. Il va encore probablement subir des modifications, et donc rien de ce qui est montré dans ces "screenshots" ne peut être considéré comme définitif.

Il y a encore d’autres choses qui ont évoluées aussi bien au niveau de l’audio que de la vidéo, mais mon objectif  pour ce billet est uniquement de parler des deux régressions. Du côté de libvalhalla, les "grabbers" tels que Amazon, Allocine et LyricWiki re-fonctionnent normalement (espérons que se sois pour encore longtemps). A part ça, une grande partie des modifications sont internes tel que de l’optimisation et des corrections de bugs par exemple.

A bientôt,

Mathieu SCHROETER

h1

Une image pour illustrer libvalhalla

2009.11.05

valhalla

Il manquait une illustration pour libvalhalla. C’est toujours plus sympathique de pouvoir faire référence à une bibliothèque par l’intermédiaire d’images. Ce n’est pas non plus pour rien que je lui ai donné ce nom. Contrairement à celle que j’avais fais pour libplayer, cette fois j’ai choisi un style un peu plus classique et complètement monochrome.

Les personnages représentent des Valkyries à la recherche de vos fichiers multimédias perdus dans les champs de batailles de vos disques durs.

C’est sûrement le billet le plus court que je n’ai jamais publié :-P.

A bientôt,

Mathieu SCHROETER

h1

Force-stop, on demand, events, …

2009.10.11

Hello,

avec les projets GeeXboX parfois j’ai l’impression de ne jamais arriver au bout. Quand quelque chose se termine, il y a toujours autre chose à faire. On ne risque pas de s’ennuyer. Mais il arrive qu’on fasse les choses à double, triple ou pire. Tout ça pour dire que les fonctionnalités présentées dans le billet précédent ("force-stop", "on demand" et "events") sont implémentées.

Je vous invite à lire l’article à ce lien si vous ne comprenez pas de quoi je parle; reste aussi à être intéressé par ce genre d’article :-).

En quelques phrases

force-stop

Je ne vais pas revenir sur les détails. La réalisation du "force-stop" a introduit de nouvelles tables dans la base de donnée. Une table pour sauvegarder les "grabbers" et une table pour sauvegarder les contextes du "downloader". En résumé, lorsqu’un fichier a été traité par un "grabber" et que les données ont été sauvegardées, la relation avec ce "grabber" est également introduite dans la base de donnée. Ça évite ainsi au prochain démarrage de "regrabber" les même données. Pour le "downloader" l’idée est un tout petit peu différente. Lorsque Valhalla se termine, il sauvegarde toutes les listes de fichiers à télécharger dans la base de donnée. Au prochain démarrage, quand le scanner tombe sur un fichier où il y avait encore des données à télécharger, il réintroduit les listes dans les structures.

ondemand

Pour le "ondemand" le travail s’est montré un peu plus compliqué que je le pensais. Étant donné que le "ondemand" peut se passer à n’importe quel moment il y a de nombreux cas à considérer. Par exemple, vous faites une requête "ondemand", le fichier de la requête n’a pas été vu par le scanner. Le "ondemand" se met en branle et ce fichier se retrouve dans le mécanisme, puis le scanner voit le fichier et l’introduit presque en même temps dans le mécanisme. Du coup vous vous trouvez avec deux paquets différents pour un même fichier. Il y a ainsi deux-trois astuces pour gérer ce cas de figure ainsi que beaucoup d’autres (je vous épargne le plus tordu sur lequel je suis tombé). Aucune nouvelle table a été introduite pour cette fonctionnalité, uniquement un nouveau champ dans la table des fichiers, pour savoir si le fichier existe dans les chemins du scanner, ou pas.
Grosso modo le "ondemand" se passe ainsi: pause de tous les threads en aval au scanner (donc depuis le DBManager); il attend que tout le monde s’en dort; il cherche dans les queues si le fichier à traiter existe déjà; en fonction de ça il créer un nouveau ou il modifie l’existant; puis il réveille tout le monde. Les paquets "ondemand" ont également une haute priorité et sont donc traités le plus rapidement possible par les différents threads de Valhalla.

events

Concernant les événements, il y a simplement des retours au "front-end" pour lui signaler quelle étapes ont été réalisées, via un callback. Les événements sont possibles uniquement avec les requêtes "ondemand".

L’architecture

valhalla-internals

Deux threads ont donc fait leur apparition (en rose pâle). L’architecture n’a donc pas été modifiée, mais étendue. Au lieu de n’avoir que le scanner comme intervenant pour l’ajout de fichiers, il y a donc le "ondemand" en parallèle. Les événements sont traités exclusivement par le DBManager.

Comme toujours, ces diagrammes sont un peu simplifiés. Par exemple, les commandes "ondemand" ne sont pas bloquantes. Et donc en réalité il y a une queue devant la flèche entrante du "front-end". Mais ça n’apportait rien d’intéressant à la lecture de ce diagramme. Il suffit de lire la documentation Doxygen pour connaître ce genre de précision quant a l’utilisation des fonctions publiques.

La base de donnée

valhalla-db

Les modifications sur la base de donnée concernent les tables grabber, dlcontext, file ainsi que la table d’allocation pour les relations (n,n) avec les "grabbers". Les champs interrupted__ et outofpath__ ont intégrés la table file. Notez bien que les champs terminés par __ sont utilisés uniquement comme données internes pour le bon fonctionnement de Valhalla.

Mais encore …

Comme je le disais au début, on aime faire du travail à double et même à triple. Écrire des "grabbers" dans Enna pour ensuite les porter dans Valhalla. Et le meilleur c’est quand le fournisseur d’un service utilisé par un "grabber" aime se foutre du monde. Amazon par exemple, un jour il décide de dire que toutes les requêtes pour le service doivent être signées HMAC-SHA256 (c’est limite ridicule mais ça n’engage que moi). Ou alors la MPAA/RIAA qui aime emmerder les petits (et dire qu’ils sont payés pour ça) et qui empêche ainsi Lyricwiki de fournir une WebAPI pour les paroles des chansons. Du coup deux "grabbers" cassés, le "grabber" Lyricwiki qui a été fixé d’une autre manière mais qui s’est vu à nouveau être inutilisable (je crois, je ne m’en suis pas occupé).

En ce qui concerne Amazon c’est pas une grosse affaire mais j’ai la flemme. C’est fatiguant de devoir toujours revenir sur ce qui a déjà été fait, encore et encore. Imaginez le jour où il y a une release. Vous aurez deux-trois "grabbers" de morts en à peine quelques semaines.

Finalement avant de fixer des "grabbers" mieux vaut attendre le dernier moment.

Mais encore …, …

Il manque (et oui) des moyens depuis l’API publique pour modifier des méta-données; un exemple: le "play-count". Vous pouvez imaginez d’autres types de champs dans cette idée. mais qui dit modifier les données dit aussi de considérer deux cas de figure:

  1. Modifier uniquement dans la base de donnée
  2. Modifier également dans le fichier en question (avec FFmpeg)

Selon les méta-données et le type de fichier, seul le cas (1.) est envisageable. Mais pour par exemple un OGG et l’artiste, il peut être bien de pouvoir directement l’écrire dans le fichier. Tout ceci reste encore sujet à réflexion.

A bientôt,

Mathieu SCHROETER

Suivre

Recevez les nouvelles publications par mail.

%d bloggers like this: