En faisant quelques tests, j'ai trouvé une solution plus simple que de modifier Xorg pour pouvoir faire des XvShmPutImage vers un Pixmap. De toute façon il n'y avait aucune garantie sur le résultat et ça n'aurait probablement pas été portable sur toutes les cartes graphiques.

La nouvelle technique

Chaque trame du fichier vidéo est décodée vers un XvImage au format YV12, que j'affiche comme précédemment dans ma fenêtre principale avec un XvShmPutImage. Ensuite, il suffit de copier le contenu de cette fenêtre vers un Pixmap avec XCopyArea. J'ai testé, ça fonctionne correctement.

Il faut faire attention à bien créer un Pixmap avec la même profondeur de couleur que celle de la fenêtre quand on la crée avec XCreateWindow (24bpp ici), sinon ça provoque une erreur sur le XCopyArea. Il faudra s'en rappeler au moment d'intégrer le code dans MPlayer.

Ensuite, la boucle d'affichage consiste comme prévu à alterner des XCopyArea et des XFlush en utilisant glXGetVideoSyncSGI et glXWaitVideoSyncSGI pour la synchronisation avec le retour vertical.

Sauts de trames

Il n'y a quasiment pas de sauts de frames et le cas échéant ils sont de toute façon correctement détectés par glXGetVideoSyncSGI. Il devrait donc être possible de gérer ces sauts dans MPlayer pour éviter l'inversion des yeux.

il y a par contre quelques artefacts visuels assez légers, mais un petit peu gênants quand même. Par moment quand on ferme un oeil on voit pendant un très court moment - moins de quelques millisecondes à priori - une image superposée à l'autre. Ça le fait surtout au début puis ça semble le faire de moins en moins, à croire que glXWaitVideoSyncSGI met du temps à se mettre en route mais finit par se stabiliser.

Je ne sais pas trop à quoi c'est dû, sans doute au fait qu'il peut y avoir un délai plus important que la durée du retour vertical entre la fin de l'attente de glXWaitVideoSyncSGI et la fin du XCopyArea/XFlush.

Le XCopyArea/XFlush étant particulièrement rapide - environ 150 microsecondes pour une image de 500x500 - j'imagine que ça peut être dû au scheduler qui ne donne pas forcément la main tout de suite à l'appel suivant le glXWaitVideoSyncSGI. Peut-être que ça pourra se régler en utilisant des threads avec une priorité élevée.

Synchronisation au lancement de l'application

Il existe un autre problème, l'affichage n'est pas forcément correctement synchronisé au bon oeil au lancement de l'application. Puisque l'appel à glXGetVideoSyncSGI fournit le nombre de retours verticaux, on devrait pouvoir afficher l'image appropriée à chaque oeil en testant si la valeur est paire ou impaire, mais ça ne fonctionne pas.

Ça veut dire qu'il ne faudra pas compter sur l'activator eDimensional si on veut que les vidéos s'affichent correctement et donc qu'il faudra implémenter les appels DDC pour contrôler directement les lunettes. Mais c'est quand même pas normal, il faudra essayer de trouver pourquoi ça ne fonctionne pas correctement.

C'est un peu inquiétant aussi, ça veut dire que glXGetVideoSyncSGI rate peut-être des trames de temps en temps, ce qui pourrait arriver pendant la lecture. Si c'est vraiment le cas, je n'ai aucun moyen de corriger ça pour l'instant.

Utilisation CPU

Côté performances, l'application prend entre 0.7 et 1.3 % de CPU, ce qui est vraiment négligeable. Xorg prend entre 2 et 3 %, à comparer aux 1 à 2 % quand l'application n'est pas lancée. Ça va donc laisser pas mal de temps à MPlayer pour décoder les trames et c'est un gain assez net par rapport à l'ancienne méthode à base de XvShmPutImage uniquement.

Prochaine étape, probablement l'intégration de cette technique dans MPlayer...