Programmer un module pour "The Removers' Animator"

Auteur : Stabylo / The Removers
2 août 1998 - 12 Août 2000

Table des matières

Avant Propos

Chapitre 1 : Modules AVC et AAC

Chapitre 2 : Modules de format de fichier AFH

Avant propos

Ce document s'adresse aux programmeurs. Il décrit comment programmer un module d'extension pour Animator selon un des trois types suivants :

AVC : Animator Video Codec
(permet de décompresser un flux video)
AAC : Animator Audio Codec
(permet de décompresser un flux audio)
AFH : Animator File Handler
(permet de relire un type de fichier d'animation)

Chapitre 1 :

Modules de compression/décompression AVC et AAC

Introduction aux AVC et AAC

Afin d'intégrer plus facilement de nouveaux types de fichiers d'animation, Animator est modulaire. Nous décrirons ici toutes les règles de programmation à respecter pour construire soi-même un module. Le but de cette description est évident : des personnes autres que l'auteur peuvent améliorer Animator en écrivant des modules pour ce dernier.

L'élément fondateur de la complication de ces règles de programmation, c'est la gestion de la mémoire. En effet, chaque module a le droit d'allouer de la mémoire, par exemple pour faire des précalculs, mais dans le cas où Animator doit faire appel à plusieurs modules, pour jouer une série d'animations, n'est-il pas dommage de devoir toujours recréer les mêmes précalculs ?

Par ailleurs, si on choisi de conserver ces précalculs (comme le faisait AviPlayer) il serait dommage d'en venir à manquer de mémoire, alors qu'il est probable que certains d'entre eux ne sont pas utilisés dans l'animation en cours et qu'il constituent un gros bloc de mémoire perdue.

C'est pour répondre à la fois à ces deux problèmes qu'a été mise en place une micro-bibliothèque de fonctions mises à la disposition du programmeur de modules.

Ces modules doivent donc déclarer leurs précalculs au noyau au moyen de routines transmises en paramètres lors de l'initialisation du module. De même, l'allocation de mémoire se fera par le biais d'une fonction du noyau, afin de libérer un précalcul inutilisé en cas de manque de mémoire. De surcroît, Animator se chargera de générer un message d'erreur si rien n'a pu être fait pour réussir l'allocation d'un bloc. En reprenant la main, le noyau cesse alors le parcours de l'animation en cours et passe à la suivante, sauf si l'erreur est fatale ou si l'option 'Fail' a été positionnée dans la ligne de commande, auquel cas Animator effectue un retour au bureau GEM.

Si une erreur survient lors de la décompression d'une image ou d'un son, la routine'erreur_survenue' permet de le signaler au noyau. Une telle erreur n'affecte aucunement le noyau dans la restitution de l'animation.

Enfin, lorsqu'Animator a fini d'utiliser un module, il appelle une routine de ce dernier qui de charge de signaler que les précalculs compterons un utilisateur de moins.

En effet, il se peut qu'à un instant donné, plusieurs modules cohabitent en mémoire en utilisant les mêmes précalculs ! Cela se produit pour les fichiers AVI comportant plusieurs flux video. C'est pourquoi Animator compte le nombre d'utilisateurs d'un précalcul donné plutôt que de signaler si un précalcul est utilisé ou non.

Bien entendu, afin d'éviter que deux modules ne créent deux fois le même précalcul - celui de conversion YUV->RGB, par exemple -, il est associé un identifiant à chaque précalcul. Cet identifiant comporte quatre caractères : c'est un mot long du type '_YUV' ou bien 'HCCV' (Hi Color ConVert) ou '_URS'(UnsignedReSampling). Notez bien que tous les identificateurs commençant par le caractère '_' (caractère "underscore") sont réservés pour les identifiants officiels.


Routine d'installation : 'init_module'

Bien sûr, elle initialise le module. Elle est située au début de celui-ci de telle sorte que l'on puisse l'appeler en sautant à la première instruction de la zone TEXT. Comme toutes les routines du module, elle se termine par l'instruction 'RTS'

En gros.

En détail.

'init_module' est appelée par un saut (JSR) sur le début de la zone TEXT du module.


Arguments.

Règles de programmation.

'init_module' n'a le droit de modifier QUE les registres d0/a0 (pour transmettre les valeurs de retour).

En cas d'erreur, elle s'occupe de désallouer les blocs qu'elle a réservé le cas échéant : la routine de libération du module n'est pas transmise, donc elle ne sera pas appelée.

La routine doit vérifier que le tableau est assez grand pour comporter les variables dont elle a besoin (voir le retour d'erreurs ci-dessous). Ceci permettra d'allonger ce tableau plus tard sans pénaliser les modules écrits auparavant.

Cette routine a la possibilité de créer des précalculs (voir méthode détaillée plus loin) à l'aide de ces variables. Les adresses des précalculs créés peuvent être gardées dans des variables internes au module pour être utilisé plus simplement, mais elles doivent systématiquement être réinitialisée par 'init_module'.

Important

Elle a l'obligation de copier toutes les valeurs qui peuvent lui être utile par la suite, car le contenu du tableau de paramètres est susceptible d'être modifié sans préavis.

Les valeurs ainsi copiées bénéficieront en outre d'un accès plus simple et plus rapide pour le module.

retours


INIT_MOD_OK                     equ     0
INIT_MOD_BAD_COMP               equ     -1
INIT_MOD_TOO_FEW_ARGS           equ     -2
INIT_MOD_MEMORY_ERROR           equ     -3
INIT_MOD_USER_DEFINED_ERROR     equ     -4
INIT_MOD_UNEXP_ERROR            equ     -5
INIT_MOD_BAD_FORMAT             equ     -6
d0.l=0 :
autorisation d'utiliser le module
d0.l<0 :
utilisation du module interdite : erreur d'initialisation.
d0.l=-1 : compression non reconnue
d0.l=-2 : pas assez de paramètres
d0.l=-3 : manque de mémoire libre
d0.l=-4 : erreur précisée par le module : a0.l pointe vers une chaîne au format C qui explicite l'erreur rencontrée.
d0.l=-5 : erreur inattendue
d0.l=-6 : compression reconnue, mais le format de sortie ne convient pas
d0.l>0 :
Sans signification. Ne pas utiliser.
a0.l :
Adresse du tableau de retour (décrit plus loin) si d0.l=0. Adresse d'une chaîne décrivant l'erreur si d0.l=-4 Bien sûr, cette valeur n'a de sens que si d0.l=0 ou d0.l=-4

tableau d'entrée.


info_init_codec         rsstruct
chemin_application      rs.l    1
adr_recherche_precalc   rs.l    1       ; \
adr_mem_alloc           rs.l    1       ; |-> détaillés ci-dessous
adr_libere_precalc      rs.l    1       ; /
type                    rs.b    4
sizeof                  rs      0

Voici des explication sur ces variables générales :

adr_recherche_precalc

C'est l'adresse d'une routine qui recherche le précalcul correspondant à l'identificateur passé en argument.

Retour.

    1. Trois cas se présentent pour le retour.
    2. d0.l=0 : précalcul inexistant
    3. a0.l : pointe sur un descripteur vide prêt à être rempli. (structure détaillée plus loin)
    4. d0.l>0 : précalcul trouvé
    5. a0.l : pointe sur le descripteur du précalcul correspondant.
    6. d0.l<0 : création de précalcul impossible (erreur fatale déjà produite)

Modifications de registres.


      ...
      move.l    taille,d0
      move.w    #3,d1
      jsr       mem_alloc
      tst.l     d0
      beq       allocation_impossible
      ...
adr_libere_precalc

C'est l'adresse d'une routine qui recherche le précalcul correspondant à l'identificateur passé en argument. S'il existe, elle le signale comme non utilisé.


******* Si le type vaut 'vids' (flux vidéo : modules AVC) *******
compression             rs.b    4       ; détaillé ci-dessous
bits_par_pixel          rs.w    1       ; 2, 4, 8, 16, 24 ou 32
adr_palette             rs.l    1
largeur                 rs.w    1       ; \ dimensions du flux video
hauteur                 rs.w    1       ; /
adr_ecran_centre        rs.l    1       ; détaillé ci-dessous
x_ecran                 rs.w    1       ; dimensions de l'écran
y_ecran                 rs.w    1
nb_bits_sortie          rs.w    1       ; 16 ou 24 (avec restrictions)
type_de_sortie          rs.w    1
video_sizeof            rs      0

Voici des explication sur ces variables spécifiques à la video :

compression
C'est le FOURCC (four character code) qui identifie la compression. Pour éviter d'éventuelles erreurs de la part du noyau,'init_module' doit vérifier qu'il s'agit bien d'une compression qu'elle reconnaît.
adr_ecran_centree
C'est est l'adresse du pixel situé au coin supérieur gauche de l'animation, calculée de manière à obtenir un affichage centré. Dans le cas d'une décompression de haut en bas, il s'agit là de l'adresse à partir de laquelle la décompression se fait.
nb_bits_sortie
Ce champ désigne le nombre de couleurs en sortie.
type_de_sortie
Ce mot identifie le format de sortie à partir des constantes suivantes :

ATARI                   equ     0
CARTE_GRAPHIQUE         equ     1

Remarque :

Le format ATARI correspond au format HiColor Falcon. Seuls certains couples de (nb_bits_sortie , type_de_sortie ) sont valides :


******* Si le type vaut 'auds' (flux audio : modules AAC) *******
                        rsset   info_init_codec.sizeof
format                  rs.w    1       ; 0=inconnu, 1=PCM, 2=ADPCM, ....
nb_voies                rs.b    1       ; 1=mono, 2=stéréo
bits_par_sample         rs.b    1       ; en général égal à 4, 8 ou 16.
frequence               rs.l    1       ; en général égal à 11025, 22050 ou 44100
block_align             rs.w    1
format_sortie           rs.w    1       ; 1=PCM ATARI (signé)
nb_voies_sortie         rs.b    1       ; 1=mono, 2=stéréo
bits_sortie             rs.b    1       ; 8 ou 16
frequence_sortie        rs.l    1       ; toujours supérieur à 'frequence'
audio_sizeof            rs      0
                        rsend

Voici des explication sur ces variables spécifiques à l'audio :

Les variables 'format', 'nb_voies', 'bits_par_sample' et 'frequence' définissent le format du son en entrée.

Les variables 'format_sortie', 'nb_voies_sortie', 'bits_sortie' et 'frequence_sortie' définissent le format du son en sortie. Notez que la frequence de sortie demandée au décodeur vérifie toujours les inégalités suivantes :

frequence_sortie/2 <= frequence < frequence_sortie

format_sortie
La routine décodeuse interprète le format PCM=1 8 bits en sortie comme signé (format PCM sur Atari) et en entrée comme non signé (format PCM sur PC).

La routine encodeuse interprète à l'inverse : le PCM 8 bit est signé en entrée et non signé en sortie. Ceci permet la conversion au format PCM lors de la création d'un fichier AVI.


tableau de retour


******* L'adresse de ce tableau est retournée dans a0. *******
information_module      rsstruct
adr_decodeur            rs.l    1
adr_encodeur            rs.l    1
adr_libere_module       rs.l    1
auteur                  rs.l    1
description             rs.l    1
version                 rs.l    1
sizeof                  rs      0

Si l'une des deux premières routines est absente du module, alors l'adresse correspondante doit être mise à zéro (NULL).

Si une erreur s'est produite lors de l'initialisation, on peut positionner 'adr_libere_module' à 0 (NULL).

adr_decodeur
Adresse de la routine de décompression. Voir ci-dessous la partie concernant cette routine.
adr_encodeur
Adresse de la routine de compression. Voir ci-dessous la partie concernant cette routine.
adr_libere_module
Adresse de la routine de libération du module. Voir ci-dessous la partie concernant cette routine.
auteur
Adresse d'une chaîne de caractères au format C qui contient le ou les noms du ou des auteurs.
description
Adresse d'une chaîne de caractères au format C qui contient le nom du format traité par le module, ainsi qu'éventuellement d'autres informations utiles. Il est par exemple possible d'y préciser que le module utilise le DSP le cas échéant.
version
Contient le numéro de version du module sous forme de quatre caractères ASCII formatés comme suit : 'M.mr' ou M est le numéro de version majeur, m le numéro de version mineur et r le numéro du correctif de bug. Les numéro sont hexa décimaux : ce sont des chiffres de 0 à 9 ou des lettres de A à F.

******* Si le type vaut 'vids' (flux vidéo : modules AVC) *******
                        rsset   information_module.sizeof
adr_MFDB                rs.l    1
video_sizeof            rs      0
adr_MFDB

Contient l'adresse d'un bloc MFDB (20 octets) qui décrit le format de l'image crée par le module lorsqu'il décompresse une image. Voici cette structure :


  MFDB          rsstruct
  fd_addr       rs.l    1       ; adresse mémoire (NULL = écran courant)
  fd_width      rs.w    1       ; largeur en pixels de la zone
  fd_height     rs.w    1       ; hauteur en pixels de la zone
  fd_wdwidth    rs.w    1       ; largeur en mots de la zone (fdwisth +15)/16
  fd_stand      rs.w    1       ; format (0 = spécifique au périphérique, 1 = format VDI)
  fd_planes     rs.w    1       ; nombre de plans
  reserved1     rs.w    1       ; \
  reserved2     rs.w    1       ; | (mettre à 0)
  reserved3     rs.w    1       ; /
  sizeof        rs      0
              rsend
  

Typiquement, elle sera remplie ainsi :


  fd_addr      =info_init_codec.adr_ecran_centre
  fd_width     =info_init_codec.x_ecran
  fd_height    =info_init_codec.hauteur
  fd_wdwidth   =info_init_codec.x_ecran
  fd_stand     =0
  fd_planes    =16
  reserved1    =0
  reserved2    =0
  reserved3    =0
  

******* Si le type vaut 'auds' (flux audio : modules AAC) *******
                        rsset      information_module.sizeof
min_bit_rate            rs.l      1
audio_sizeof            rs      0
                        rsend
min_bit_rate

Il s'agit de la bande passante minimale en bit par seconde du son compressé. Cette valeur est ensuite utilisée pour calculer la taille utilisée par un son décompressé selon la formule suivante :

taille_non_compresse = taille_compresse * (bit_rate_sortie/min_bit_rate)

Pour calculer la valeur de min_bit_rate, il est possible de diviser la taille d'un block_align (bloc de son élémentaire insécable) en bits par la durée maximale du son qu'il code. Si le flux audio a un taux de compression constant, il est possible d'utiliser la formule suivante :

min_bit_rate = 8 * taille_echantillon * nombre_echantillons_par_seconde

Par exemple, si vous décompressez 65 octets en 384 octets contenant 192 échantillons de 8 bits rejoués à la fréquence 44100 Hz :

min_bit_rate = 8*65*(44100/192)

Attention : s'il faut arrondir certains calculs, il faut arrondir à l'unité inférieure.


Création de précalculs

Cette création se fait à l'aide des routines 'recherche_precalc' et 'mem_alloc'.

Dans le cas où le précalcul est déjà présent (d0<>0), il est à la charge de 'init_module' d'incrémenter d'une unité le nombre d'utilisateurs de ce précalcul pour signaler l'utilisation de ce dernier par le module.

Dans le cas où le précalcul n'est pas déjà en mémoire (d0=0), la routine d'initialisation doit remplir le descripteur vide pointé par a0.


descripteur_precalc     rsstruct
identificateur          rs.b    4
adresse_bloc            rs.l    1
nb_utilisateurs         rs.w    1
sizeof                  rs      0
                        rsend

exemple de descripteur fraîchement créé.


        dc.b    '_YUV'          ; Conversion YUV->RGB
        dc.l    $35df54         ; adresse du précalcul
        dc.w    1               ; un seul utilisateur

Remarques

Les identificateurs commençant par le caractère de soulignement '_'sont réservés pour les identificateurs officiels.

Voici ci-dessous la liste des identifiants officiels pour la version actuelle d'Animator. Cette liste n'est donnée qu'à titre d'exemple car elle est amenée à changer profondément dans les futures versions d'Animator :

Modules video AVC :

_MLU
Multiples Unsigned (FLIC, RGB, RLE)
_HCC
HiColor Convert (CRAM, RGB)
_YUV
YUV->RGB (CVID, YUV9)
YUV2
YUV->RGB (IV32)
YUV3
YUV->Greyscale (IV32)
_LSM
Luminance Signed Multiples (IV32)
_CSM
Chrominance Signed Multiples (IV32)
_UYP
Ultimotion Yuv Precalcul (ULTI)
_ULP
Ultimotion Ltc Precalcul (ULTI)

Modules audio AAC :

IMA4
ima4 precalcul (IMA4)
_SRS
précalcul Signed ReSampling (PCM)
_URS
précalcul Unsigned ReSampling (PCM)

Libération de précalculs

  1. IMPORTANT
  2. Les BLOCS alloués pour les précalculs ne sont jamais explicitement libérés par le module.
  3. C'est le gestionnaire de mémoire s'en occupe selon les besoins auxquels il fait face.

Le module signale qu'il cesse d'utiliser un précalcul en appelant la routine 'libere_precalc' qui diminue d'une unité le nombre d'utilisateurs du précalcul.


Routine décodeuse

Codecs video (AVC)

Arguments
a0.l : adresse du bloc à décompresser.
d0.l : longueur de ce bloc.
Format video décompressé.
Le décodeur écrit à l'adresse indiquée lors de l'initialisation l'image décompressée au format ATARI True Color (ou plutôt HiColor). Les champs RVB occupent respectivement 5, 6, et 5 bits d'un mot au format Motorola (Big Endian), et s'y succèdent dans cet ordre.
Retours.
Aucun
TOUS les registres peuvent être modifiés par la routine décodeuse.

Codecs audio (AAC)

Arguments
d0.l : longueur du bloc source.
a0.l : adresse du bloc source à décompresser.
a1.l : adresse du bloc destination où décompresser le son.
Format audio décompressé.
Le format de sortie est précisé à l'initialisation. Le décodeur écrit à l'adresse indiquée en paramètre le bloc de son décompressé et rééchantionné à la fréquence demandée.
Retours.
d0.l : longueur du bloc destination
TOUS les registres peuvent être modifiés par la routine décodeuse.

Routine encodeuse

Pas de spécifications. Ne pas se servir de cette possibilité.


Routine de libération du module

Elle a pour rôle essentiel de libérer chaque précalcul par un appel à la routine 'libere_precalc'.

En gros

Règles de programmation.

Cette routine ne doit modifier aucun registre.

CHAQUE précalcul utilisé par le module DOIT être l'objet d'un appel à 'libere_precalc'.

Toute mémoire allouée en douce avec le GEMDOS doit être libérée. (Nota : préférez 'Mxalloc #3' au traditionnel Malloc pour les allouer)


Chapitre 2 :

Modules de format de fichier AFH

Pas de spécifications. Ne pas se servir de cette possibilité.

Devrait contenir :

Routines à transmettre :