lundi 10 mars 2014

Format de sous-titres ASS, édition et capacités

C'est en voulant regarder le film d'animation japonais The Garden of Words (言の葉の庭) que j'ai découvert quelques capacités du format de sous-titres SSA/ASS.
En fait, celui-ci n'existe qu'en VO ou VOSTEN, mais même si il est possible de trouver des sous-titres en français (pour ne pas perdre de temps à la lecture, ratant de ce fait les images magnifiques), on perd alors le joli style (enfin la police quoi) donné aux écritures.


Je suis donc parti dans l'adaptation de mon "pauvre" sous-titrage français au format SRT :
1
00:00:38,706 --> 00:00:42,084
Je ne connaissais pas ces choses-là
il y a encore deux mois,

2
00:00:42,334 --> 00:00:43,586
avant d'entrer au lycée.

vers le format ASS qui permet d'utiliser des polices :

[V4+ Styles]
Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
Style: garden,LTFinnegan Medium,72,&H00FFF7E7,&H000000FF,&H00042419,&H00475244,0,0,0,0,100,100,0,0,1,3.5,2,2,15,15,65,1
[...]
[Events]
Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
Dialogue: 0,0:00:38.70,0:00:42.08,garden,Unknown,0,0,0,,{\i1}Je ne connaissais pas ces choses-là\Nil y a encore deux mois,{\i0}
Dialogue: 0,0:00:42.33,0:00:43.58,garden,Unknown,0,0,0,,{\i1}avant d'entrer au lycée.{\i0}


D'abord, les sous-titres et les polices utilisées sont inclues dans le MKV.

> mkvmerge -i "The_Garden_of_Words.mkv"
Fichier 'The_Garden_of_Words.mkv' : conteneur : Matroska
Piste numéro 0 : video (V_MPEG4/ISO/AVC)
Piste numéro 1 : audio (A_FLAC)
Piste numéro 2 : subtitles (S_TEXT/ASS)
Pièce jointe numéro 1 : type 'application/x-truetype-font', taille 4654020 octets, nom de fichier 'A-OTF-Jun501Pro-Bold.
otf'
Pièce jointe numéro 2 : type 'application/x-truetype-font', taille 4796008 octets, nom de fichier 'G-OTF-GJun501Pro-Bold
.otf'
Pièce jointe numéro 3 : type 'application/x-truetype-font', taille 42980 octets, nom de fichier 'ITCGaramondStd-Bk.otf'
Pièce jointe numéro 4 : type 'application/x-truetype-font', taille 45940 octets, nom de fichier 'LegacySerifStd-Book.otf
'
Pièce jointe numéro 5 : type 'application/x-truetype-font', taille 62536 octets, nom de fichier 'LT.ttf'
Pièce jointe numéro 6 : type 'application/x-truetype-font', taille 62480 octets, nom de fichier 'LT_3italic.ttf'
Pièce jointe numéro 7 : type 'application/x-truetype-font', taille 58700 octets, nom de fichier 'PPETRIAL.otf'
Pièce jointe numéro 8 : type 'application/x-truetype-font', taille 109200 octets, nom de fichier 'PPETRIAL.ttf'
Pièce jointe numéro 9 : type 'application/x-truetype-font', taille 172732 octets, nom de fichier 'segoepr.ttf'
Pièce jointe numéro 10 : type 'application/x-truetype-font', taille 35752 octets, nom de fichier 'TheGreatEscape.ttf'
Pièce jointe numéro 11 : type 'application/x-truetype-font', taille 93152 octets, nom de fichier 'Thin Pencil Handwritin
g.otf'
Pièce jointe numéro 12 : type 'application/x-truetype-font', taille 3419056 octets, nom de fichier 'epsonthora.ttf'

Il est possible de tout extraire, mais seul le fichier de sous-titres ASS est utile :

> mkvextract tracks "The_Garden_of_Words.mkv" 2:en.ass
Extraction de la piste 2 avec le codec 'S_TEXT/ASS' dans le fichier 'en.ass'. Format de conteneur : SSA/ASS text subtitles
Progression : 100%

Ensuite commence le travail. J'ai choisi de conserver les temps du sous-titrage français, principalement parce que j'ai pu remarquer qu'a plusieurs endroits la découpe des dialogues est faite différemment.
Une dizaine de regex dans Notepad++, quelques corrections de bugs (nombre de décimales), on rajoute les en-têtes du ASS d'origine et hop : le SRT devient un ASS, le principal est fait.

Mais le fichier ASS d'origine contient plus que des dialogues, j'ai pu m'en rendre compte en comparant l'original à mon ASS modifié dans WinMerge. Une des grosse différence sert en fait .. à générer un texte animé lors du titre principal !


Pour le reste, il s'agit en fait de texte incrusté, et si on ne le sait pas, il est facile de passer à côté.

Quelques exemples :

  • "June"



Et d'autres sont vraiment cachés :

  • l'examen

  • les noms sur le portable ...
Il a donc fallu traduire ces textes aussi, cette fois manuellement, et ça aura aussi permis de supprimer quelques traductions en trop comme "Juin" qui étaient présentes dans le SRT.

Le plus gros travail aura été la chanson de fin, puisqu'il a fallu faire un découpage correct des textes pour remplacer la traduction existante.

Enfin, je me suis essayé à incruster une des traduction du SRT dans l'image, comme le fait le ASS, voila la résultat :

En bref, j'ai été impressionné de voir les capacités des formats actuels de sous-titrage, adapter une traduction aura été un exercice sympa.

 「鳴る神の 少し響みて さし曇り 雨も降らぬか 君を留めむ」

La traduction au format ASS : https://drive.google.com/file/d/0B63FLnZuVDrvVGcweHlEakhhNlE

Annexes : 
http://matroska.org/technical/specs/subtitles/ssa.html
http://pireze.org/2013/anime-review-makoto-shinkais-the-garden-of-words-%E8%A8%80%E3%81%AE%E8%91%89%E3%81%AE%E5%BA%AD-kotonoha-no-niwa/
http://mlr.inktails.com/2013/07/jp-movie-the-garden-of-words-2013/
http://louvreuse.net/critique/the-garden-of-words.html
http://www.imdb.com/title/tt2591814
http://www.subsynchro.com/2012/the-garden-of-words.html ("Byousuku 5 Centimeters" semble sympa à voir aussi)

dimanche 19 janvier 2014

Hacking du module hid-wiimote pour fonctionner avec le Pro Controller U sous RetroPie

Introduction

Aujourd'hui, un article qui risque d'être assez long (et très probablement assez mal écrit) pour revenir sur mon activité de ces derniers jours.


Avant de commencer, le contexte : la plateforme RaspberryPi est équivalente à un téléphone portable et permet de faire de l'émulation de consoles grâce à des distributions comme RetroPie (utilisant RetroArch, un des seul émulateur pi basé sur Pico capable de faire tourner certains jeux de Megadrive, comme Sonic Spinball, et EmulsationStation pour proposer une interface de lancement des jeux). Il existe aussi Chameleon et PiMAME, mais malheureusement l'émulateur Megadrive qui y est intégré ne fonctionne pas avec tout les jeux.

J'ai pu valider cette partie, et tester avec une manette bas de gamme (moyennant quelques configurations à la main pour EmulationStation et RetroArch).
Maintenant il peut être intéressant de pouvoir jouer à 2, et donc connecter 2 manettes, mais :
  • les fils, c'est chiants
  • la Pi n'aime pas trop se faire tirer du courant, ça la fait planter

D'où cette idée : acheter un dongle bluetooth et utiliser des manettes sans fil. J'en ai commandé 2 sur Amazon : 

Cette première n'est absolument pas Bluetooth contrairement à ce qu'indique son nom .. Il faut utiliser leur gros dongle .. Amazon va la récupérer.
L'autre manette est celle ci :
Qui n'est pas une manette WiiU Pro contrairement à ce qu'indique son nom, mais une Wii Classic Controller Pro (qui fait aussi Wiimote simple).
Elle fonctionne en bluetooth comme les manettes Wii, on peut donc en associer plusieurs sur un simple dongle bluetooth.

Première approche

Ma première approche a été d'utiliser les tutos disponibles sur internet, tel que :
Ils se basent sur cwiid couplé avec wminput pour gérer les boutons. Seulement .. avec cette manette, ça ne fonctionne pas, il y a des messages d'erreur ("Received unexpected write report") et la partie Classic (il y a un switch sur la manette) fait comme si aucune touche n'était pressée. J'ai tenté de compiler la derniere version de cwiid, qui m'a permit de jouer avec les leds, mais pas plus.

J'ai fait d'autres recherche et suis tombé sur quelques liens : 
Il a fallu compiler wiiuse (je passe les détails, c'est expliqué), mais je n'ai pas eu beaucoup plus de succès.

J'ai songé à un moment à parser les messages de la manette à la main, en prenant la méthode suitante : http://smus.com/prototyping-wii-remote-python/ mais quand un rapide test montre que la manette balance des 0xFF en continu, c'est qu'il faut lui envoyer les bonnes données avant, et bon .. flemme.

L'approche xwiimote / hid-wiimote

C'est en faisant des recherche sur la WiiU Pro Controller que j'ai vu qu'il existait une manette pour WiiU, qui n'est donc pas la même, et qu'il existe des logiciels pour l'utiliser (mais la mienne n'est pas celle-ci, même si je l'ai cru à un moment, le nom de la manette prêtant à confusion) : 
XWiimote is an open-source linux device driver for Nintendo Wii / Wii U Remotes and compatible devices. It is a relatively new driver that tries to supercede cwiid, wiiuse and others by integrating the driver into existing linux infrastructure. The project consists of an official linux kernel driver, which is part of the kernel since linux-3.1, an extension to bluez, the official linux bluetooth stack, an X11 input driver, some user-space helpers and test applications.
Surprise donc ! Il existe un module kernel, qui se prétend mieux que cwiid et wiiuse, et qui se trouve être présent dans RetroPie (kernel 3.6.11+). Il y a même un super programme qui affiche les touches de la Wiimote et ses extensions en ASCII (xwiishow) !
(tiré de http://leftbraintinkering.blogspot.fr/2014/01/wii-remote-plus-and-linux.html)
Mais après compilation de xwiishow, malheureusement même constat, le Classic controller ne fonctionne pas :(. Je commence à penser que la manette est défectueuse.
A noter qu'il faut utiliser hidd pour associer la Wiimote, bluez demandant un PIN.

Hack de hid-wiimote

Ayant jeté un œil aux sources du module hid-wiimote, et n'ayant plus rien à perdre (a part renvoyer la manette, mais elle me plait vraiment avec sa forme à la SuperNES), je me lance dans la modification de ce module.
Il faut pour ça pouvoir compiler, sur une Pi contrairement aux petits logiciels d'avant, c'est impensable, il faut donc passer par de la cross-compilation. l'avantage avec la Pi c'est qu'il existe plein de docs/tutos, on trouve donc des instructions pour cela : http://elinux.org/RPi_Kernel_Compilation.
Une VM Ubuntu x64, les libs pour exécuter des programmes x86, puis il suffit de suivre les instructions :

KERNEL_SRC=/home/user/raspbian-kernel/linux-rpi-3.6.y/
CCPREFIX=/home/user/raspbian-kernel/tools-master/arm-bcm2708/arm-bcm2708hardfp-linux-gnueabi/bin/arm-bcm2708hardfp-linux-gnueabi-
make mrproper
make ARCH=arm CROSS_COMPILE=${CCPREFIX} oldconfig
make ARCH=arm CROSS_COMPILE=${CCPREFIX}
make ARCH=arm CROSS_COMPILE=${CCPREFIX} modules

A noter qu'il faut compiler le kernel (make) avant de compiler les modules (make modules), sinon :
ERROR: could not insert 'hid_wiimote': Exec format error

Reconnaissance du Classic Controller

Le principal problème étant que l'extensions Classic n'est pas reconnu, alors qu'a priori présente, je décide de la forcer :
  wmem = 0x55;
  wiimote_cmd_write(ext->wdata, 0xa400f0, &wmem, sizeof(wmem));
  wmem = 0x0;
  wiimote_cmd_write(ext->wdata, 0xa400fb, &wmem, sizeof(wmem));
  return WIIEXT_CLASSIC;
Et la, même si rien n'est reconnu ou fonctionnel dans xwiishow, evtest affiche bien des boutons en mode Classic !
Mais le stick gauche ne fonctionne pas en vertical et les triggers font 2 actions au lieu d'une.

Debug des controles

Pour voir ce qu'envoi la manette, j'essaye un débogage (comme je peux, le debugging de kernel je connais pas), c'est sale (mais fonctionnel) :
#define BYTETOBINARYPATTERN "%d%d%d%d%d%d%d%d"
#define BYTETOBINARY(byte)  \
  (byte & 0x80 ? 1 : 0), \
  (byte & 0x40 ? 1 : 0), \
  (byte & 0x20 ? 1 : 0), \
  (byte & 0x10 ? 1 : 0), \
  (byte & 0x08 ? 1 : 0), \
  (byte & 0x04 ? 1 : 0), \
  (byte & 0x02 ? 1 : 0), \
  (byte & 0x01 ? 1 : 0) 
  
  
  printk(KERN_INFO "Byte %d "BYTETOBINARYPATTERN"", 0, BYTETOBINARY(payload[0]));
  printk(KERN_INFO "Byte %d "BYTETOBINARYPATTERN"", 1, BYTETOBINARY(payload[1]));
  printk(KERN_INFO "Byte %d "BYTETOBINARYPATTERN"", 2, BYTETOBINARY(payload[2]));
  printk(KERN_INFO "Byte %d "BYTETOBINARYPATTERN"", 3, BYTETOBINARY(payload[3]));
  printk(KERN_INFO "Byte %d "BYTETOBINARYPATTERN"", 4, BYTETOBINARY(payload[4]));
  printk(KERN_INFO "Byte %d "BYTETOBINARYPATTERN"", 5, BYTETOBINARY(payload[5]));
Et ça donne pleiiiiin de lignes dans les logs :
Jan 17 17:16:52 raspberrypi kernel: [65820.154165] Byte 1 00100000Byte 2 00010000
Jan 17 17:16:52 raspberrypi kernel: [65820.154198] Byte 3 00000000Byte 4 11111111
Jan 17 17:16:52 raspberrypi kernel: [65820.154221] Byte 5 11111111Byte 0 10100000
Jan 17 17:16:52 raspberrypi kernel: [65820.161071] Byte 1 00100000Byte 2 00010000
Jan 17 17:16:52 raspberrypi kernel: [65820.161100] Byte 3 00000000Byte 4 11111111
Jan 17 17:16:52 raspberrypi kernel: [65820.161121] Byte 5 11111111Byte 0 10100000
Comme je disais, c'est sale, mais ça fonctionne et permet de repérer doucement les touches, je me suis alors construit une carte :
Byte 0 10100000
       ^^-------RX(12)
         ^^^^^^-LX

Byte 1 00100000
       ^^-------RX(34)
         ^^^^^^-LY

Byte 2 00010000
       ^--------RX(5)
        ^^------TL
          ^^^^^-RY


Byte 3 00000000
       ^^^------TL
          ^^^^^-TR

Byte 4 11111111
       ^--------RIGHT
        ^-------DOWN
         ^------BTL
          ^-----MINUS
           ^----HOME
            ^---PLUS
             ^--BTR
              ^-1

Byte 5 11111111
       ^--------TL2
        ^-------B = ZL
         ^------Y
          ^-----A
           ^----X = ZR
            ^---TR2
             ^--LEFT
              ^-UP

Corrections

Il s'avère que cela correspond aux indications dans les sources de hid-wiimote .. C'est donc ailleurs que se situe le problème. Entre temps je tombe sur les sources du module pour le kernel 3.11, qui sont corrigées
                lx = payload[0] & 0x3e;
                ly = payload[0] & 0x3e;
lx = ly ? Oui, il y a comme un problème.
Il y a aussi une double négation sur les touches qui fait qu'elle apparaissent comme pressées en permanence, c'est corrigé aussi.

J'en profite aussi pour modifier les touches du D-Pad pour mapper des boutons au lieu des touches UP/DOWN/LEFT/RIGHT, qui ne sont pas reconnues par retroarch-joyconfig.
Enfin il y a un dernier bug qui est apparu quand j'ai voulu tester l'utilisation avec 2 wiimotes (voir si les leds sont gérées .. la réponse est non), qui nécessite de supprimer l'intégration du report des informations batterie dans le kernel, sinon il tente de créer 2 fois le même périphérique, et alors :
[178790.876742] ------------[ cut here ]------------
[178790.876794] WARNING: at fs/sysfs/dir.c:536 sysfs_add_one+0x88/0xc0()
[178790.876810] sysfs: cannot create duplicate filename '/class/power_supply/wiimote_battery'
[...]
[178790.883777] ---[ end trace 66509376675ee1a0 ]---
[178791.878245] power_supply wiimote_battery: driver failed to report `capacity' property: 4294967291
[178791.878349] wiimote 0005:057E:0306.0015: Cannot register battery device
[178792.882087] wiimote: probe of 0005:057E:0306.0015 failed with error -17

Bref, l'ensemble des modification est visible ici :
https://github.com/Alex131089/raspberrypi-linux/compare/raspberrypi:rpi-3.6.y...rpi-3.6.y-hid-wiimote

Conclusion

Bien que je ne soit pas entré dans le détail, j'ai une petite vue du fonctionnement des Wiimote, et de la gestion au niveau du kernel. Première expérience de cross-compilation aussi, merci au projet RaspberryPi qui a préparé les outils.

Ma manette est donc fonctionnelle, il reste à tester en condition réelle, mais les contrôles semblent tous reconnus cette fois. Il reste à créer un script qui pourra scanner une liste de commande (hidd --connect) ou toute commande (hidd --search) pour s'y connecter, qui scannera en permanence, et qui affectera les bonnes leds (p1, p2) aux commandes, à coup de recherche dans /sys/class ^^

Je joins aussi mon fichier de "travail" qui contient moulte liens sur lesquels je suis tombé pendant mes recherches.