Décoder l’image d’un vidéophone Sony

Il y a quelques mois, Matthew Taylor de Techmoan (je vous encourage à aller regarder si vous ne connaissez pas) a publié une vidéo sur un produit Sony un peu spécial : un vidéophone des années 80, le Sony PCT-15.

Le produit en lui-même ne m’a pas marqué, c’est une sorte de boîtier avec une caméra et un écran cathodique (monochrome) qui pouvait transférer (et recevoir) des images. On est évidemment assez loin de FaceTime : l’appareil transmettait des images par modem, et pas de la vidéo. Une simple image basse définition nécessitait plusieurs secondes par transfert et donc vous vous doutez bien que ça n’a pas été un succès. Mais c’est ce point qui m’a fait réagir : vers 12 minutes, Matt propose la version audio du transfert. Et quand j’ai entendu le son, j’ai pensé que c’était modulé comme les vinyles et les cassettes audio que je traite régulièrement ici depuis quelques mois. J’ai donc mis ça dans un coin (dans un brouillon) pour plus tard.

Un peu après, il a d’ailleurs mis en ligne un extrait sans la compression YouTube (plus exactement, le même extrait). Et il y a quelques semaines, je me suis dit « Et si j’essayais de décoder ça ? ». Je ne suis pas le premier, Dmitrii Eliuseev a fait un post Medium quelques jours après la publication, je suis aussi tombé sur un message de Zerosquare dans un forum, ainsi qu’un post rapide sur un blog.

Le plus intéressant pour commencer les essais était évidemment le post de Dmitrii, mais avec deux bémols. Premièrement, il y a quelques points ou il extrapole pas mal. Deuxièmement, surtout, son image ne semblait pas très fidèle (elle est inversée sur les couleurs, par exemple). Celle de Zerosquare, par contre, était a priori plus fidèle au résultat à l’écran. Mais Zerosquare (qui m’a répondu et m’a aidé, merci à lui) n’avait pas codé quelque chose, il a utilisé The Gimp en important l’image, une méthode qui fonctionne mais n’est pas très pratique.

L’image de Dmitrii (inversée, de façon évidente)


L’image de Zerosquare


L’image originale

Je vais vous passer les deux dimanches après-midi à essayer de comprendre le code, pour essayer d’aller à l’essentiel. Premièrement, truc basique, j’ai effacé les silences avant et après les données avec Audacity. C’est probablement possible en Python aussi, mais un simple filtre Tronquer le silence est plus rapide.

Un coup de filtre

La structure comprend 400 ms avec un signal qui sert a priori à indiquer une transmission, suivi de 400 ms de pause. On peut donc s’en passer pour l’image. Ensuite il y environ 200 ms de données qui servent a priori à calibrer le niveau. Puis il y a les données. J’ai eu un peu de mal à comprendre, mais grâce à Zerosquare, j’ai à peu près capté. Le signal utilise une fréquence de ~1 748 Hz et chaque période représente un pixel, modulé en amplitude. Pourquoi ~1 748 ? C’est la fréquence classique d’une porteuse NTSC (3.579545 MHz) divisée par 2^11. L’intérêt de cette fréquence est probablement de réutiliser le quartz d’un téléviseur, par exemple. Il n’y a pas vraiment de synchro, par contre : dans le cas de l’image de Techmoan, qui est transmise en mode Quick, on a simplement tous les pixels transmis séquentiellement. La bonne nouvelle, c’est qu’on a la définition de l’image : 96 x 100. Plus concrètement, le code Python va obtenir l’enveloppe du signal (les valeurs de la modulation en amplitude, si j’ai bien compris) et les placer dans une image dans la bonne définition. Pour le niveau du signal, j’ai considéré que le signal au début sert à indiquer la valeur maximale, donc je l’utilise pour calibrer l’image avec un signal 8 bits (255 valeurs).

Le code Python est vraiment perfectible (je ne suis pas développeur) mais ça semble fonctionner sur les deux exemples que j’ai avec une image qui garde les mêmes valeurs. Le truc, c’est que j’ai deux fois la même image : une récupérée directement dans la vidéo YouTube, l’autre fournie, mais c’est le même code. J’ai même dû mettre une valeur en dur dans le code, pour une raison idiote : j’utilisais des divisions entières à pleins d’endroits et la valeur de 1 748 Hz est une approximation. Comme je connais mal Python, j’ai fait le calcul à la main pour obtenir une valeur correcte (au passage, l’approximation de Dmitrii est proche). Dans tous les cas, j’obtiens une image assez propre qui a l’air correcte.

Ma version, un peu plus claire

La prochaine étape va être de trouver un (ou deux) Sony PCT-15 et d’essayer le code avec d’autres images, ainsi qu’avec la version Normal, en 160 x 100. Avec un peu de chances, les quelques trucs que j’ai essayé de déduire sont corrects.

J’ai mis le code sur GitHub, mais ça nécessiterait vraiment qu’un développeur passe dessus.