Coverage Report

Created: 2026-06-09 06:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gpac/src/bifs/unquantize.c
Line
Count
Source
1
/*
2
 *      GPAC - Multimedia Framework C SDK
3
 *
4
 *      Authors: Jean Le Feuvre
5
 *      Copyright (c) Telecom ParisTech 2000-2023
6
 *          All rights reserved
7
 *
8
 *  This file is part of GPAC / BIFS codec sub-project
9
 *
10
 *  GPAC is free software; you can redistribute it and/or modify
11
 *  it under the terms of the GNU Lesser General Public License as published by
12
 *  the Free Software Foundation; either version 2, or (at your option)
13
 *  any later version.
14
 *
15
 *  GPAC is distributed in the hope that it will be useful,
16
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
 *  GNU Lesser General Public License for more details.
19
 *
20
 *  You should have received a copy of the GNU Lesser General Public
21
 *  License along with this library; see the file COPYING.  If not, write to
22
 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23
 *
24
 */
25
26
#include "quant.h"
27
28
#ifndef GPAC_DISABLE_BIFS
29
30
#include <math.h>
31
32
u32 gf_bifs_dec_qp14_get_bits(GF_BifsDecoder *codec)
33
0
{
34
0
  if (!codec->ActiveQP || !codec->coord_stored) return 0;
35
0
  return (u32) ceil(log1p(codec->NumCoord) / log(2) );
36
0
}
37
38
void gf_bifs_dec_qp14_enter(GF_BifsDecoder * codec, Bool Enter)
39
0
{
40
0
  if (!codec->ActiveQP) return;
41
0
  if (Enter) codec->storing_coord = GF_TRUE;
42
0
  else {
43
0
    if (codec->storing_coord) codec->coord_stored = GF_TRUE;
44
0
    codec->storing_coord = GF_FALSE;
45
0
  }
46
0
}
47
48
void gf_bifs_dec_qp14_reset(GF_BifsDecoder * codec)
49
0
{
50
0
  codec->coord_stored = GF_FALSE;
51
0
  codec->storing_coord = GF_FALSE;
52
0
  codec->NumCoord = 0;
53
0
}
54
55
void gf_bifs_dec_qp14_set_length(GF_BifsDecoder * codec, u32 NbElements)
56
0
{
57
0
  if (!codec->ActiveQP || !codec->storing_coord || codec->coord_stored) return;
58
0
  codec->NumCoord = NbElements;
59
0
}
60
61
GF_Err gf_bifs_dec_qp_set(GF_BifsDecoder *codec, GF_Node *qp)
62
0
{
63
0
  gf_assert(gf_node_get_tag(qp) == TAG_MPEG4_QuantizationParameter);
64
65
  /*if we have an active QP, push it into the stack*/
66
0
  if (codec->ActiveQP && ((GF_Node*)codec->ActiveQP != codec->scenegraph->global_qp) )
67
0
    gf_list_insert(codec->QPs, codec->ActiveQP, 0);
68
69
0
  codec->ActiveQP = (M_QuantizationParameter *)qp;
70
0
  return GF_OK;
71
0
}
72
73
GF_Err gf_bifs_dec_qp_remove(GF_BifsDecoder *codec, Bool ActivatePrev)
74
0
{
75
0
  if (!codec->force_keep_qp && codec->ActiveQP && ((GF_Node*)codec->ActiveQP != codec->scenegraph->global_qp) ) {
76
0
    gf_node_unregister((GF_Node *) codec->ActiveQP, NULL);
77
0
  }
78
0
  codec->ActiveQP = NULL;
79
0
  if (!ActivatePrev) return GF_OK;
80
81
0
  if (gf_list_count(codec->QPs)) {
82
0
    codec->ActiveQP = (M_QuantizationParameter*)gf_list_get(codec->QPs, 0);
83
0
    gf_list_rem(codec->QPs, 0);
84
0
  } else if (codec->scenegraph->global_qp) {
85
0
    codec->ActiveQP = (M_QuantizationParameter *)codec->scenegraph->global_qp;
86
0
  }
87
0
  return GF_OK;
88
0
}
89
90
//parses efficient float
91
Fixed gf_bifs_dec_mantissa_float(GF_BifsDecoder *codec, GF_BitStream *bs)
92
0
{
93
0
  u32 mantLength, expLength, mantSign, mantissa;
94
0
  unsigned char exp;
95
96
0
  union {
97
0
    Float f;
98
0
    long l;
99
0
  } ft_value;
100
101
0
  mantLength = gf_bs_read_int(bs, 4);
102
0
  if (!mantLength) return 0;
103
104
0
  expLength = gf_bs_read_int(bs, 3);
105
0
  mantSign = gf_bs_read_int(bs, 1);
106
0
  mantissa = gf_bs_read_int(bs, mantLength - 1);
107
108
0
  exp = 127;
109
0
  if (expLength) {
110
0
    u32 expSign = gf_bs_read_int(bs, 1);
111
0
    u32 exponent = gf_bs_read_int(bs, expLength-1);
112
0
    exp += (1-2*expSign)*( (1 << (expLength-1) ) + exponent);
113
0
  }
114
115
0
  ft_value.l = mantSign << 31;
116
0
  ft_value.l |= (exp & 0xff) << 23;
117
0
  ft_value.l |= mantissa << 9;
118
0
  return FLT2FIX(ft_value.f);
119
0
}
120
121
//check if the quant type is on in the QP, and if so retrieves NbBits and Min Max
122
//specified for the field
123
Bool Q_IsTypeOn(M_QuantizationParameter *qp, u32 q_type, u32 *NbBits, SFVec3f *b_min, SFVec3f *b_max)
124
0
{
125
0
  switch (q_type) {
126
0
  case QC_3DPOS:
127
0
    if (!qp->position3DQuant) return GF_FALSE;
128
0
    *NbBits = qp->position3DNbBits;
129
0
    b_min->x = MAX(b_min->x, qp->position3DMin.x);
130
0
    b_min->y = MAX(b_min->y, qp->position3DMin.y);
131
0
    b_min->z = MAX(b_min->z, qp->position3DMin.z);
132
0
    b_max->x = MIN(b_max->x, qp->position3DMax.x);
133
0
    b_max->y = MIN(b_max->y, qp->position3DMax.y);
134
0
    b_max->z = MIN(b_max->z, qp->position3DMax.z);
135
0
    return GF_TRUE;
136
0
  case QC_2DPOS:
137
0
    if (!qp->position2DQuant) return GF_FALSE;
138
0
    *NbBits = qp->position2DNbBits;
139
0
    b_min->x = MAX(b_min->x, qp->position2DMin.x);
140
0
    b_min->y = MAX(b_min->y, qp->position2DMin.y);
141
0
    b_max->x = MIN(b_max->x, qp->position2DMax.x);
142
0
    b_max->y = MIN(b_max->y, qp->position2DMax.y);
143
0
    return GF_TRUE;
144
0
  case QC_ORDER:
145
0
    if (!qp->drawOrderQuant) return GF_FALSE;
146
0
    *NbBits = qp->drawOrderNbBits;
147
0
    b_min->x = MAX(b_min->x, qp->drawOrderMin);
148
0
    b_max->x = MIN(b_max->x, qp->drawOrderMax);
149
0
    return GF_TRUE;
150
0
  case QC_COLOR:
151
0
    if (!qp->colorQuant) return GF_FALSE;
152
0
    *NbBits = qp->colorNbBits;
153
0
    b_min->x = b_min->y = b_min->z = MAX(b_min->x, qp->colorMin);
154
0
    b_max->x = b_max->y = b_max->z = MIN(b_max->x, qp->colorMax);
155
0
    return GF_TRUE;
156
0
  case QC_TEXTURE_COORD:
157
0
    if (!qp->textureCoordinateQuant) return GF_FALSE;
158
0
    *NbBits = qp->textureCoordinateNbBits;
159
0
    b_min->x = b_min->y = b_min->z = MAX(b_min->x, qp->textureCoordinateMin);
160
0
    b_max->x = b_max->y = b_max->z = MIN(b_max->x, qp->textureCoordinateMax);
161
0
    return GF_TRUE;
162
0
  case QC_ANGLE:
163
0
    if (!qp->angleQuant) return GF_FALSE;
164
0
    *NbBits = qp->angleNbBits;
165
0
    b_min->x = b_min->y = b_min->z = MAX(b_min->x, qp->angleMin);
166
0
    b_max->x = b_max->y = b_max->z = MIN(b_max->x, qp->angleMax);
167
0
    return GF_TRUE;
168
0
  case QC_SCALE:
169
0
    if (!qp->scaleQuant) return GF_FALSE;
170
0
    *NbBits = qp->scaleNbBits;
171
0
    b_min->x = b_min->y = b_min->z = MAX(b_min->x, qp->scaleMin);
172
0
    b_max->x = b_max->y = b_max->z = MIN(b_max->x, qp->scaleMax);
173
0
    return GF_TRUE;
174
0
  case QC_INTERPOL_KEYS:
175
0
    if (!qp->keyQuant) return GF_FALSE;
176
0
    *NbBits = qp->keyNbBits;
177
0
    b_min->x = MAX(b_min->x, qp->keyMin);
178
0
    b_min->y = MAX(b_min->y, qp->keyMin);
179
0
    b_min->z = MAX(b_min->z, qp->keyMin);
180
0
    b_max->x = MIN(b_max->x, qp->keyMax);
181
0
    b_max->y = MIN(b_max->y, qp->keyMax);
182
0
    b_max->z = MIN(b_max->z, qp->keyMax);
183
0
    return GF_TRUE;
184
0
  case QC_NORMALS:
185
0
    if (!qp->normalQuant) return GF_FALSE;
186
0
    *NbBits = qp->normalNbBits;
187
0
    b_min->x = b_min->y = b_min->z = 0;
188
0
    b_max->x = b_max->y = b_max->z = FIX_ONE;
189
0
    return GF_TRUE;
190
0
  case QC_ROTATION:
191
0
    if (!qp->normalQuant) return GF_FALSE;
192
0
    *NbBits = qp->normalNbBits;
193
0
    b_min->x = b_min->y = b_min->z = 0;
194
0
    b_max->x = b_max->y = b_max->z = FIX_ONE;
195
0
    return GF_TRUE;
196
0
  case QC_SIZE_3D:
197
0
    if (!qp->sizeQuant) return GF_FALSE;
198
0
    *NbBits = qp->sizeNbBits;
199
0
    b_min->x = b_min->y = b_min->z = MAX(b_min->x, qp->sizeMin);
200
0
    b_max->x = b_max->y = b_max->z = MIN(b_max->x, qp->sizeMax);
201
0
    return GF_TRUE;
202
0
  case QC_SIZE_2D:
203
0
    if (!qp->sizeQuant) return GF_FALSE;
204
0
    *NbBits = qp->sizeNbBits;
205
0
    b_min->x = b_min->y = b_min->z = MAX(b_min->x, qp->sizeMin);
206
0
    b_max->x = b_max->y = b_max->z = MIN(b_max->x, qp->sizeMax);
207
0
    return GF_TRUE;
208
209
  //cf specs, from here ALWAYS ON
210
0
  case QC_LINEAR_SCALAR:
211
    //nbBits is the one from the FCT - DO NOT CHANGE IT
212
0
    return GF_TRUE;
213
0
  case QC_COORD_INDEX:
214
    //nbBits has to be recomputed on the fly
215
0
    return GF_TRUE;
216
0
  case QC_RESERVED:
217
0
    *NbBits = 0;
218
0
    return GF_TRUE;
219
0
  default:
220
0
    return GF_FALSE;
221
0
  }
222
0
}
223
224
225
//Linear inverse Quantization for floats
226
Fixed Q_InverseQuantize(Fixed Min, Fixed Max, u32 NbBits, u32 value)
227
0
{
228
0
  if (!value) return Min;
229
0
  if (NbBits>=sizeof(value)*8) return Max;
230
0
  if (value == (u32) ((1 << NbBits) - 1) ) return Max;
231
0
  return Min + gf_muldiv(Max - Min, INT2FIX(value), INT2FIX( (1 << NbBits) - 1) );
232
0
}
233
234
235
GF_Err Q_DecFloat(GF_BifsDecoder *codec, GF_BitStream *bs, u32 FieldType, SFVec3f BMin, SFVec3f BMax, u32 NbBits, void *field_ptr)
236
0
{
237
0
  switch (FieldType) {
238
0
  case GF_SG_VRML_SFINT32:
239
0
    return GF_NON_COMPLIANT_BITSTREAM;
240
0
  case GF_SG_VRML_SFFLOAT:
241
0
    *((SFFloat *)field_ptr) = Q_InverseQuantize(BMin.x, BMax.x, NbBits, gf_bs_read_int(bs, NbBits));
242
0
    return GF_OK;
243
0
  case GF_SG_VRML_SFVEC2F:
244
0
    ((SFVec2f *)field_ptr)->x = Q_InverseQuantize(BMin.x, BMax.x, NbBits, gf_bs_read_int(bs, NbBits));
245
0
    ((SFVec2f *)field_ptr)->y = Q_InverseQuantize(BMin.y, BMax.y, NbBits, gf_bs_read_int(bs, NbBits));
246
0
    return GF_OK;
247
0
  case GF_SG_VRML_SFVEC3F:
248
0
    ((SFVec3f *)field_ptr)->x = Q_InverseQuantize(BMin.x, BMax.x, NbBits, gf_bs_read_int(bs, NbBits));
249
0
    ((SFVec3f *)field_ptr)->y = Q_InverseQuantize(BMin.y, BMax.y, NbBits, gf_bs_read_int(bs, NbBits));
250
0
    ((SFVec3f *)field_ptr)->z = Q_InverseQuantize(BMin.z, BMax.z, NbBits, gf_bs_read_int(bs, NbBits));
251
0
    return GF_OK;
252
0
  case GF_SG_VRML_SFCOLOR:
253
0
    ((SFColor *)field_ptr)->red = Q_InverseQuantize(BMin.x, BMax.x, NbBits, gf_bs_read_int(bs, NbBits));
254
0
    ((SFColor *)field_ptr)->green = Q_InverseQuantize(BMin.y, BMax.y, NbBits, gf_bs_read_int(bs, NbBits));
255
0
    ((SFColor *)field_ptr)->blue = Q_InverseQuantize(BMin.z, BMax.z, NbBits, gf_bs_read_int(bs, NbBits));
256
0
    return GF_OK;
257
258
0
  case GF_SG_VRML_SFROTATION:
259
    //forbidden in this Q mode
260
0
    return GF_NON_COMPLIANT_BITSTREAM;
261
0
  }
262
0
  return GF_OK;
263
0
}
264
265
//int in quant are either Linear Scalar fields or CoordIndex
266
//the quant is just a bitshifting into [0, 2^NbBits-1]
267
//so IntMin + ReadBit(NbBits) = value
268
GF_Err Q_DecInt(GF_BifsDecoder *codec, GF_BitStream *bs, u32 QType, SFInt32 b_min, u32 NbBits, void *field_ptr)
269
0
{
270
0
  switch (QType) {
271
0
  case QC_LINEAR_SCALAR:
272
0
  case QC_COORD_INDEX:
273
0
    *((SFInt32 *)field_ptr) = gf_bs_read_int(bs, NbBits) + b_min;
274
0
    return GF_OK;
275
0
  default:
276
0
    return GF_NON_COMPLIANT_BITSTREAM;
277
0
  }
278
0
}
279
280
//SFRotation and SFVec3f are quantized as normalized vectors ,mapped on a cube
281
//in the UnitSphere (R=1.0)
282
GF_Err Q_DecCoordOnUnitSphere(GF_BifsDecoder *codec, GF_BitStream *bs, u32 NbBits, u32 NbComp, Fixed *m_ft)
283
0
{
284
0
  u32 i, orient, sign;
285
0
  s32 value;
286
0
  Fixed tang[4], delta;
287
0
  s32 dir;
288
0
  if (!NbBits || NbBits>32) return GF_NON_COMPLIANT_BITSTREAM;
289
0
  if (NbComp != 2 && NbComp != 3) return GF_BAD_PARAM;
290
291
  //only 2 or 3 comp in the quantized version
292
0
  dir = 1;
293
0
  if(NbComp == 2) dir -= 2 * gf_bs_read_int(bs, 1);
294
295
0
  orient = gf_bs_read_int(bs, 2);
296
0
  if ((orient==3) && (NbComp==2)) return GF_NON_COMPLIANT_BITSTREAM;
297
298
0
  for(i=0; i<NbComp; i++) {
299
0
    value = gf_bs_read_int(bs, NbBits) - (1 << (NbBits-1) );
300
0
    sign = (value >= 0) ? 1 : -1;
301
0
    m_ft[i] = sign * Q_InverseQuantize(0, 1, NbBits-1, sign*value);
302
0
  }
303
0
  delta = 1;
304
0
  for (i=0; i<NbComp; i++) {
305
0
    tang[i] = gf_tan(gf_mulfix(GF_PI/4, m_ft[i]) );
306
0
    delta += gf_mulfix(tang[i], tang[i]);
307
0
  }
308
0
  delta = gf_divfix(INT2FIX(dir), gf_sqrt(delta) );
309
0
  m_ft[orient] = delta;
310
311
0
  for (i=0; i<NbComp; i++) {
312
0
    m_ft[ (orient + i+1) % (NbComp+1) ] = gf_mulfix(tang[i], delta);
313
0
  }
314
0
  return GF_OK;
315
0
}
316
317
//parses a rotation
318
GF_Err Q_DecRotation(GF_BifsDecoder *codec, GF_BitStream *bs, u32 NbBits, void *field_ptr)
319
0
{
320
0
  u32 i;
321
0
  Fixed q, sin2, comp[4];
322
0
  GF_Err e;
323
324
0
  e = Q_DecCoordOnUnitSphere(codec, bs, NbBits, 3, comp);
325
0
  if (e) return e;
326
327
0
  q = 2 * gf_acos(comp[0]);
328
0
  sin2 = gf_sin(q / 2);
329
330
0
  if (ABS(sin2) <= FIX_EPSILON) {
331
0
    for (i=1; i<4; i++) comp[i] = 0;
332
0
    comp[3] = FIX_ONE;
333
0
  } else {
334
0
    for (i=1; i<4; i++) comp[i] = gf_divfix(comp[i], sin2);
335
0
  }
336
0
  ((SFRotation *)field_ptr)->x = comp[1];
337
0
  ((SFRotation *)field_ptr)->y = comp[2];
338
0
  ((SFRotation *)field_ptr)->z = comp[3];
339
0
  ((SFRotation *)field_ptr)->q = q;
340
0
  return GF_OK;
341
0
}
342
343
//parses a Normal vec
344
GF_Err Q_DecNormal(GF_BifsDecoder *codec, GF_BitStream *bs, u32 NbBits, void *field_ptr)
345
0
{
346
0
  Fixed comp[4];
347
0
  SFVec3f v;
348
0
  GF_Err e;
349
0
  e = Q_DecCoordOnUnitSphere(codec, bs, NbBits, 2, comp);
350
0
  if (e) return e;
351
0
  v.x = comp[0];
352
0
  v.y = comp[1];
353
0
  v.z = comp[2];
354
0
  gf_vec_norm(&v);
355
0
  *((SFVec3f *)field_ptr) = v;
356
0
  return GF_OK;
357
0
}
358
359
GF_Err gf_bifs_dec_unquant_field(GF_BifsDecoder *codec, GF_BitStream *bs, GF_Node *node, GF_FieldInfo *field)
360
0
{
361
0
  Bool HasQ;
362
0
  u8 QType, AType;
363
0
  u32 NbBits;
364
0
  Fixed b_min, b_max;
365
0
  SFVec3f BMin, BMax;
366
0
  GF_Err e;
367
368
  /*check QP*/
369
0
  if (!codec->ActiveQP) return GF_EOS;
370
  /*check FieldType*/
371
0
  switch (field->fieldType) {
372
0
  case GF_SG_VRML_SFINT32:
373
0
  case GF_SG_VRML_SFFLOAT:
374
0
  case GF_SG_VRML_SFROTATION:
375
0
  case GF_SG_VRML_SFVEC2F:
376
0
  case GF_SG_VRML_SFVEC3F:
377
0
    break;
378
0
  case GF_SG_VRML_SFCOLOR:
379
0
    break;
380
0
  default:
381
0
    return GF_EOS;
382
0
  }
383
384
  /*check NDT*/
385
0
  HasQ = gf_bifs_get_aq_info(node, field->fieldIndex, &QType, &AType, &b_min, &b_max, &NbBits);
386
0
  if (!HasQ || !QType) return GF_EOS;
387
388
  /*get NbBits for QP14 (QC_COORD_INDEX)*/
389
0
  if (QType == QC_COORD_INDEX) {
390
0
    NbBits = gf_bifs_dec_qp14_get_bits(codec);
391
    /*QP14 is always on, not having NbBits set means the coord field is set after the index field, hence not decodable*/
392
0
    if (!NbBits) return GF_NON_COMPLIANT_BITSTREAM;
393
0
  }
394
395
0
  BMin.x = BMin.y = BMin.z = b_min;
396
0
  BMax.x = BMax.y = BMax.z = b_max;
397
398
  /*check is the QP is on and retrieves the bounds*/
399
0
  if (!Q_IsTypeOn(codec->ActiveQP, QType, &NbBits, &BMin, &BMax)) return GF_EOS;
400
401
0
  if (NbBits / 8 > gf_bs_available(bs))
402
0
    return GF_NON_COMPLIANT_BITSTREAM;
403
404
  /*ok the field is Quantized, dequantize*/
405
0
  switch (QType) {
406
  //these are all SFFloat quantized on n fields
407
0
  case QC_3DPOS:
408
0
  case QC_2DPOS:
409
0
  case QC_ORDER:
410
0
  case QC_COLOR:
411
0
  case QC_TEXTURE_COORD:
412
0
  case QC_ANGLE:
413
0
  case QC_SCALE:
414
0
  case QC_INTERPOL_KEYS:
415
0
  case QC_SIZE_3D:
416
0
  case QC_SIZE_2D:
417
0
    e = Q_DecFloat(codec, bs, field->fieldType, BMin, BMax, NbBits, field->far_ptr);
418
0
    break;
419
  //SFInt types
420
0
  case QC_LINEAR_SCALAR:
421
0
  case QC_COORD_INDEX:
422
0
    e = Q_DecInt(codec, bs, QType, (SFInt32) b_min, NbBits, field->far_ptr);
423
0
    break;
424
  //normalized fields (normals and vectors)
425
0
  case QC_NORMALS:
426
    //normal quant is only for SFVec3F
427
0
    if (field->fieldType != GF_SG_VRML_SFVEC3F) return GF_NON_COMPLIANT_BITSTREAM;
428
0
    e = Q_DecNormal(codec, bs, NbBits, field->far_ptr);
429
0
    break;
430
0
  case QC_ROTATION:
431
    //normal quant is only for SFRotation
432
0
    if (field->fieldType != GF_SG_VRML_SFROTATION) return GF_NON_COMPLIANT_BITSTREAM;
433
0
    e = Q_DecRotation(codec, bs, NbBits, field->far_ptr);
434
0
    break;
435
0
  default:
436
0
    return GF_BAD_PARAM;
437
0
  }
438
439
0
  if (e) return e;
440
0
  return GF_OK;
441
0
}
442
443
#endif /*GPAC_DISABLE_BIFS*/