OVH Cloud OVH Cloud

Récupération des infos dans un fichier binaire C3D

22 réponses
Avatar
Michael
Bonsoir à tous,

pour un programme que je suis en train de développer, je dois extraire
des informations d'un fichier C3D écrit en binaire, et qui contient des
renseignements sur le résultat d'une capture de mouvement.

Le souci, c'est que je n'ai jamais eu à faire ce genre de lecture, et que
je sais pas comment m'y prendre.

Pour commencer, je voudrais juste pouvoir extraire les infos de l'entête
du fichier.
Dans la doc (http://www.c3d.org/HTML/default.htm), il y est dit que ce
fichier est composé de multiples blocs de 512 bytes.

//
All C3D files contain a minimum of three sections of information:
-----------------------------------------------------------------
A single, 512 byte, header section
-----------------------------------------------------------------
A parameter section consisting of one, or more, 512-byte blocks.
-----------------------------------------------------------------
3D point/analog data section consisting of one, or more, 512-byte blocks.
//

Cette page me donne les différentes composantes de cet entête:
http://www.c3d.org/HTML/description.htm

On m'a filé un code en C qui lit cet entête, mais j'y pipe rien du tout,
je vous la donne...

#define RECORD 512

typedef struct S_C3D {
int nbr_block_parameter;
int processor;
char **nom_block_parameter;
} C3D;

C3D c3d;

typedef struct matrice {
double **Mat;
} MATRICE;

typedef struct {
short cleffich; // w0 Clef du fichier
short nbmarqs; // w1 Nombre de marqueurs
short nbanalog; // w2 Nombre de donnees analogiques par image
video
short premimage; // w3 Premiere image
short dernimage; // w4 Derniere image
short maxinterpol; // w5 Interpolation maximum (nombre d'images)
float echelle; // w6-7 Facteur de conversion des donnees video
stockees sous forme d'entiers
short debutdonnees; // w8 Enregistrement de debut des donnees 1
enregistrement = 256 * word; 1 word = 16 bits
short freqanal; // w9 frequence d'echantillonage
analogique/donnees video
float freqvid; // w10-11 frequence d'echantillonage video
short x1[137]; // w12-w148 inutilise
short clef; // w149 mot clef (12345 octal typical value)
short nbevnttps; // w150 nb d'evenements temps definis
short x2; // w151 Number of defined time events
float fmtevnttps[18]; // w152-w187 dates evenements temporels (max
9-,pas 18!)
short fmtevntswitch[10];// w188-w197 byte switch de l evenement (0=on,1
=off)
char labelevnt[9][8]; // w198-w233 label de l evenement sur 4
caracteres
short x3[22]; // w234-w255 inutilise
}ENTETEC3D;

typedef union {
long lg;
float flt;
int in[2];
char ch[4];
}trans;

int LgLabel,NbTraj;
char *dim_label;
char **p_label; // Labels des points
trans tr;
short Nbimage;
char TempChar;

// Implémentation
float fltdecpc (char byt[4]) // fonction donnee par Oxford pour
transformer DEC en FLOAT .Recopiee integralement donc no comment !
{
long mantis;
short exp;
float flt;
float *f;

switch (proc) {
case 0:
f = (float *) byt;
flt = *f;
break;

case 1:
mantis = (byt[2] & 0xff) + ((byt[3] & 0xffl) << 8) + (((byt[0] &
0x7fl) | 0x80) << 16);
exp = (byt[1] & 0x7f) * 2 + ((byt[0] & 0x80) ? 1 : 0);
if (byt[1] & 0x80) mantis = -mantis;
flt = (mantis || exp) ? ((float) ldexp (mantis, (exp - 128 - 24)))
: 0;
break;
}
return (flt);
}


void litentete (char *nomfich)
{
char H[sizeof(ENTETEC3D)];
ENTETEC3D *header;
FILE *fich;
int i;

int n, G, m, n2, G2, d;
char *GroupName=NULL;
char *GroupDescription=NULL;
char *ParamName=NULL;
int *Dimensions=NULL;
short offset2, offset1;

if ((fich = OuvreFichier (nomfich, "rb", 0))!=NULL) {
header = (ENTETEC3D *)H;

for (i=0; i<sizeof(ENTETEC3D); i++) H[i] = fgetc(fich);

tr.flt = header->echelle;
header->echelle = fltdecpc(tr.ch);
tr.flt = header->freqvid;
header->freqvid = fltdecpc(tr.ch);
Nbimage = header->dernimage - header->premimage + 1;

// Lecture des paramètres pour récuperer les noms des marqueurs
correspondants à chaque trajectoire*/
fread (&TempChar, sizeof(char), 1, fich); // Byte 1
fread (&TempChar, sizeof(char), 1, fich); // Byte 1
fread (&TempChar, sizeof(char), 1, fich); // Byte 1
fread (&TempChar, sizeof(char), 1, fich); // Byte 1

// header
// n
fread (&TempChar, sizeof(char), 1, fich);
n = (int)TempChar;

while (n!=0) {
// G
fread (&TempChar, sizeof(char), 1, fich);
G = (int)TempChar;

// Group Name
GroupName = calloc (n+1, sizeof(*GroupName));
for (i=0;i<n;i++)
fread ((GroupName+i), sizeof(char), 1, fich);

// offset
fread (&offset1, sizeof(short), 1, fich);

// m
fread (&TempChar, sizeof(char), 1, fich);
m = (int)TempChar;

if (m==0) fseek(fich,(offset1-3),SEEK_CUR);
else {
GroupDescription = calloc (m, sizeof(*GroupDescription)); //
Group Description
for (i=0;i<(m);i++)
fread ((GroupDescription+i), sizeof(char), 1, fich);
free (GroupDescription);
}

// Paramètres
// n2
fread (&TempChar, sizeof(char), 1, fich);
n2 = (int) TempChar;

// G2
fread (&TempChar, sizeof(char), 1, fich);
G2 = (int) TempChar;

while (G2 == -G) {
// Param Name
ParamName = calloc (n2+1, sizeof(*ParamName));
for (i=0; i<n2; i++)
fread (&ParamName[i], sizeof(ParamName[i]), 1, fich);

// offset2
fread (&offset2, sizeof(short), 1, fich);

if ((strcmp(GroupName, "POINT")==0) &&
(strcmp(ParamName, "LABELS")==0)) {
// T
fread (&TempChar, sizeof(char), 1, fich);

// d
fread (&TempChar, sizeof(char), 1, fich);
d = (int) TempChar;

// Dimensions
Dimensions = calloc (d, sizeof(*Dimensions));
for (i=0;i<d;i++) {
fread (&TempChar, sizeof(char), 1, fich);
Dimensions[i] = (int)TempChar;
}

// lecture des labels
LgLabel = Dimensions[0];
NbTraj = Dimensions[1];
free (Dimensions);
fseek (fich, LgLabel*NbTraj, SEEK_CUR); // on passe les labels

// m2
fread(&TempChar, sizeof(char), 1, fich);
fseek(fich, (int)TempChar, SEEK_CUR); // on passe m2

fread (&TempChar, sizeof(char), 1, fich); // n2
n2 = (int)TempChar;

fread (&TempChar, sizeof(char), 1, fich); // G2
G2 = (int)TempChar;

}
else {
free (ParamName);

// Passage au parametre suivant
fseek(fich,(offset2-2),SEEK_CUR);

fread (&TempChar, sizeof(char), 1, fich); // n2
n2 = (int)TempChar;

fread (&TempChar, sizeof(char), 1, fich); // G2
G2 = (int)TempChar;
}
}

fseek (fich,(-2),SEEK_CUR);
free (GroupName);

fread(&TempChar, sizeof(char), 1, fich); // n
n = (int) TempChar;
}
FermeFichier (&fich);
}
}


Comment je peux lire correctement cet entête en bon C++?

Merci d'avance

Mike

2 réponses

1 2 3
Avatar
Michael
Merci pour ce "cours" ;)

Promis, je lis tout ça bien comme il faut et me renseigne sur tout ce que
je ne comprends pas dès que j'ai un peu de temps libre :)
Avatar
kanze
Michael wrote:
"kanze" wrote in news:1140691900.559197.28400
@z34g2000cwc.googlegroups.com:

float
IntelDataHandler::readFloat(
istream& source ) const
{
unsigned char tmp[ 4 ] ;
if ( ! source.read( reinterpret_cast< char* >( tmp ), 4) ) {
// Erreur...
}
float result
= ((tmp[ 2 ] & 0x7F) << 16) | (tmp[ 1 ] << 8) | tmp[ 0 ] ;
int dummy ;
result = ldexp( frexp( result, &dummy ),
tmp[ 2 ] >> 7 | tmp[ 3 ] << 1 ) ;
return (tmp[ 3 ] & 0x80) != 0
? - result
: result ;
}


J'ai une erreur à l'éxécution sur la dernière ligne:

Débordement en virgule flottante

sur :

return (tmp[ 3 ] & 0x80) != 0 ? - result : result;

De où ça vient?


C'est normal. Ce code est la première version que j'ai postée.
Non-testée, et avec quelques oublies. Surtout, j'ai oublié la
correction pour la représentation excès 126 dans l'exposant (et
aussi d'ajouter le bit implicit dans la mantisse). C'est donc
comme si toutes les valeurs étaient multipliées par 2^126 -- ce
qui pourrait bien expliquer un débordement. Je me serais bien
attendu à l'avoir sur l'appel de ldexp, quand même.

Essaie plutôt la version templatée que j'ai postée. Celle-là, je
l'ai réelement testée, au moins pour le format Intel.

Question subsidiaire: avez-vous des liens qui pourraient me
permettre de comprendre le code ci-dessus, qui pour moi est du
chinois le plus complet?


Ça dépend ce que tu ne comprends pas.

Pour les manipulations bit-à-bit (les opérateurs >>, <<, |, &, ^
et ~ -- ils appartiennent tous ensemble, même si je ne me sers
pas de tous ici), je ne sais pas où en trouver une explication
détaillée. J'avoue qu'il m'ont toujours semblé « évidents »,
sans doute parce que j'avais fait l'électronique numérique bien
avant de me mettre à la programmation. Enfin, ils implémentent
des opérations « classiques » sur des bits, sans tenir compte de
la valeur numérique de l'entité sur laquelle ils travaillent. En
gros, il faudrait que tu cherches quelque chose comme « bit-wise
operators », ou sur la représentation interne des données dans
l'ordinateur. Mais je ne sais pas trop où ; peut-être quelqu'un
d'autre a un bon tuyau.

S'il s'agit des représentations des flottantes -- c-à-d pourquoi
je viens chercher tels bits à tels endroits -- j'ai le problème
inverse. Les problèmes du virgule flottant en informatique sont
tellement documentés, c'est difficile à savoir où t'envoyer pour
commencer. D'autant plus que mes connaissances ici viennent d'un
mélanges des sources : je sais, par exemple, que Intel utilise
le format IEEE, avec les champs signe, exposant et mantisse
juxtaposés dans cet ordre, du poids fort au poid faible, et
qu'il est petit-boutien. (Je le sais parce que j'ai enseigné
l'assembleur 8086 en 1979:-). Pour dire que je ne me base pas
sur une page de Web.) Et le format IEEE est documenté à beaucoup
d'endroits sur le Web -- essaie par exemple
http://stevehollasch.com/cgindex/coding/ieeefloat.html. Plus
généralement, pour beaucoup d'informations sur le virgule
flottant, et comment on le représente, il y a beaucoup de liens
à http://cch.loria.fr/documentation/IEEE754/ ou
http://www.validlab.com/.

En ce qui concerne le format DEC, je l'ai déduit à partir du
code que tu avais posté ET une bonne connaissance de comment
fonction la représentation des virgules flottants en général.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


1 2 3