Coverage Report

Created: 2026-06-09 06:40

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gpac/src/bifs/quantize.c
Line
Count
Source
1
/*
2
 *      GPAC - Multimedia Framework C SDK
3
 *
4
 *      Authors: Jean Le Feuvre
5
 *      Copyright (c) Telecom ParisTech 2000-2012
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 "math.h"
27
#include "quant.h"
28
29
#ifndef GPAC_DISABLE_BIFS_ENC
30
31
GF_Err gf_bifs_enc_qp_set(GF_BifsEncoder *codec, GF_Node *qp)
32
0
{
33
0
  if (gf_node_get_tag(qp) != TAG_MPEG4_QuantizationParameter) return GF_BAD_PARAM;
34
35
  /*if we have an active QP, push it into the stack*/
36
0
  if (codec->ActiveQP && ((GF_Node*)codec->ActiveQP != codec->scene_graph->global_qp) )
37
0
    gf_list_insert(codec->QPs, codec->ActiveQP, 0);
38
39
0
  codec->ActiveQP = (M_QuantizationParameter *)qp;
40
0
  return GF_OK;
41
0
}
42
43
GF_Err gf_bifs_enc_qp_remove(GF_BifsEncoder *codec, Bool ActivatePrev)
44
0
{
45
0
  codec->ActiveQP = NULL;
46
0
  if (!ActivatePrev) return GF_OK;
47
48
0
  if (gf_list_count(codec->QPs)) {
49
0
    codec->ActiveQP = (M_QuantizationParameter*)gf_list_get(codec->QPs, 0);
50
0
    gf_list_rem(codec->QPs, 0);
51
0
  } else if (codec->scene_graph->global_qp) {
52
0
    codec->ActiveQP = (M_QuantizationParameter *)codec->scene_graph->global_qp;
53
0
  }
54
0
  return GF_OK;
55
0
}
56
57
58
u32 gf_bifs_enc_qp14_get_bits(GF_BifsEncoder *codec)
59
0
{
60
0
  if (!codec->ActiveQP || !codec->coord_stored) return 0;
61
0
  return (u32) ceil(log1p(codec->NumCoord) / log(2) );
62
0
}
63
64
void gf_bifs_enc_qp14_enter(GF_BifsEncoder *codec, Bool Enter)
65
0
{
66
0
  if (!codec->ActiveQP) return;
67
0
  if (Enter) codec->storing_coord = GF_TRUE;
68
0
  else {
69
0
    if (codec->storing_coord) codec->coord_stored = GF_TRUE;
70
0
    codec->storing_coord = GF_FALSE;
71
0
  }
72
0
}
73
74
void gf_bifs_enc_qp14_reset(GF_BifsEncoder *codec)
75
0
{
76
0
  codec->coord_stored = GF_FALSE;
77
0
  codec->storing_coord = GF_FALSE;
78
0
  codec->NumCoord = 0;
79
0
}
80
81
void gf_bifs_enc_qp14_set_length(GF_BifsEncoder *codec, u32 NbElements)
82
0
{
83
0
  if (!codec->ActiveQP || !codec->storing_coord || codec->coord_stored) return;
84
0
  codec->NumCoord = NbElements;
85
0
}
86
87
void gf_bifs_enc_mantissa_float(GF_BifsEncoder *codec, Fixed ft, GF_BitStream *bs)
88
0
{
89
0
  u32 mantLength, expLength, mantSign, mantissa, expSign, i, nbBits;
90
0
  s32 exp;
91
92
0
  union
93
0
  {
94
0
    Float f;
95
0
    s32 l;
96
0
  } ft_val;
97
98
0
  if (ft == 0) {
99
0
    gf_bs_write_int(bs, 0, 4);
100
0
    return;
101
0
  }
102
0
  ft_val.f = FIX2FLT(ft);
103
104
0
  mantSign = ((ft_val.l & 0x80000000) >> 31) & 0x1;
105
0
  mantissa = (ft_val.l & 0x007FFFFF) >> 9;
106
0
  mantLength = 15;
107
0
  expSign=0;
108
0
  exp =(((ft_val.l & 0x7F800000) >> 23)-127);
109
0
  expLength = 8;
110
111
0
  if (mantissa == 0) mantLength = 1;
112
113
114
0
  if (exp) {
115
0
    if (exp< 0) {
116
0
      expSign = 1;
117
0
      exp = -exp;
118
0
    }
119
0
    while ((exp & (1<<(--expLength)))==0) { }
120
0
    exp &= ~(1<<expLength);
121
0
    expLength++;
122
0
  } else {
123
0
    expLength=0;
124
0
  }
125
126
0
  nbBits=0;
127
0
  for(i = mantissa; i>0; ++nbBits) i >>= 1;
128
129
0
  gf_bs_write_int(bs, nbBits+1, 4);
130
0
  if (mantLength) {
131
0
    gf_bs_write_int(bs, expLength, 3);
132
0
    gf_bs_write_int(bs, mantSign, 1);
133
0
    gf_bs_write_int(bs, mantissa, nbBits);
134
0
    if(expLength) {
135
0
      gf_bs_write_int(bs, expSign, 1);
136
0
      gf_bs_write_int(bs, exp, expLength - 1);
137
0
    }
138
0
  }
139
0
}
140
141
142
//Linear Quantization for floats - go back to float to avoid overflow if nbBits more than 15...
143
s32 Q_Quantize(Fixed Min, Fixed Max, u32 NbBits, Fixed value)
144
0
{
145
0
  Float _v;
146
0
  if (value <= Min) return 0;
147
0
  if (value >= Max) return (1<<NbBits)-1;
148
0
  _v = FIX2FLT(value - Min);
149
0
  _v *= (1 << NbBits) - 1;
150
0
  _v /= FIX2FLT(Max - Min);
151
0
  return FIX2INT(gf_floor( FLT2FIX(_v+0.5) ) );
152
0
}
153
154
155
GF_Err Q_EncFloat(GF_BifsEncoder *codec, GF_BitStream *bs, u32 FieldType, SFVec3f BMin, SFVec3f BMax, u32 NbBits, void *field_ptr)
156
0
{
157
0
  s32 newVal;
158
0
  switch (FieldType) {
159
0
  case GF_SG_VRML_SFINT32:
160
0
    return GF_NON_COMPLIANT_BITSTREAM;
161
0
  case GF_SG_VRML_SFFLOAT:
162
0
    newVal = Q_Quantize(BMin.x, BMax.x, NbBits, *((SFFloat *)field_ptr));
163
0
    gf_bs_write_int(bs, newVal, NbBits);
164
0
    return GF_OK;
165
0
  case GF_SG_VRML_SFVEC2F:
166
0
    newVal = Q_Quantize(BMin.x, BMax.x, NbBits, ((SFVec2f *)field_ptr)->x);
167
0
    gf_bs_write_int(bs, newVal, NbBits);
168
0
    newVal = Q_Quantize(BMin.y, BMax.y, NbBits, ((SFVec2f *)field_ptr)->y);
169
0
    gf_bs_write_int(bs, newVal, NbBits);
170
0
    return GF_OK;
171
0
  case GF_SG_VRML_SFVEC3F:
172
0
    newVal = Q_Quantize(BMin.x, BMax.x, NbBits, ((SFVec3f *)field_ptr)->x);
173
0
    gf_bs_write_int(bs, newVal, NbBits);
174
0
    newVal = Q_Quantize(BMin.y, BMax.y, NbBits, ((SFVec3f *)field_ptr)->y);
175
0
    gf_bs_write_int(bs, newVal, NbBits);
176
0
    newVal = Q_Quantize(BMin.z, BMax.z, NbBits, ((SFVec3f *)field_ptr)->z);
177
0
    gf_bs_write_int(bs, newVal, NbBits);
178
0
    return GF_OK;
179
0
  case GF_SG_VRML_SFCOLOR:
180
0
    newVal = Q_Quantize(BMin.x, BMax.x, NbBits, ((SFColor *)field_ptr)->red);
181
0
    gf_bs_write_int(bs, newVal, NbBits);
182
0
    newVal = Q_Quantize(BMin.y, BMax.y, NbBits, ((SFColor *)field_ptr)->green);
183
0
    gf_bs_write_int(bs, newVal, NbBits);
184
0
    newVal = Q_Quantize(BMin.z, BMax.z, NbBits, ((SFColor *)field_ptr)->blue);
185
0
    gf_bs_write_int(bs, newVal, NbBits);
186
0
    return GF_OK;
187
188
0
  case GF_SG_VRML_SFROTATION:
189
    //forbidden in this Q mode
190
0
    return GF_NON_COMPLIANT_BITSTREAM;
191
0
  }
192
0
  return GF_OK;
193
0
}
194
195
//int in quant are either Linear Scalar fields or CoordIndex
196
//the quant is just a bitshifting into [0, 2^NbBits-1]
197
//so v = value - b_min
198
GF_Err Q_EncInt(GF_BifsEncoder *codec, GF_BitStream *bs, u32 QType, SFInt32 b_min, u32 NbBits, void *field_ptr)
199
0
{
200
0
  switch (QType) {
201
0
  case QC_LINEAR_SCALAR:
202
0
  case QC_COORD_INDEX:
203
0
    gf_bs_write_int(bs, *((SFInt32 *)field_ptr) - b_min, NbBits);
204
0
    return GF_OK;
205
0
  default:
206
0
    return GF_NON_COMPLIANT_BITSTREAM;
207
0
  }
208
0
}
209
210
GF_Err Q_EncCoordOnUnitSphere(GF_BifsEncoder *codec, GF_BitStream *bs, u32 NbBits, u32 NbComp, Fixed *m_ft)
211
0
{
212
0
  u32 i;
213
0
  u32 len = NbComp+1;
214
0
  u32 orientation=0;
215
0
  Fixed maxTmp = - FIX_MAX;
216
0
  for (i=0; i<len; i++) {
217
0
    if (ABS(m_ft[i]) > maxTmp) {
218
0
      maxTmp = ABS(m_ft[i]);
219
0
      orientation = i;
220
0
    }
221
0
  }
222
0
  if(NbComp==2) gf_bs_write_int(bs, ((m_ft[orientation]>0) ? 0 : 1), 1);
223
0
  gf_bs_write_int(bs, orientation, 2);
224
0
  for (i=0; i<NbComp; i++) {
225
0
    Fixed v = gf_mulfix(gf_divfix(INT2FIX(4), GF_PI) , gf_atan2(m_ft[orientation], m_ft[(orientation+i+1) % len]));
226
0
    s32 qdt = Q_Quantize(0, 1, NbBits-1, (v>=0 ? v : -v));
227
0
    s32 qv = (1<<(NbBits-1)) + (v>=0 ? 1 : -1) * qdt;
228
0
    gf_bs_write_int(bs, qv, NbBits);
229
0
  }
230
0
  return GF_OK;
231
0
}
232
233
GF_Err Q_EncNormal(GF_BifsEncoder *codec, GF_BitStream *bs, u32 NbBits, void *field_ptr)
234
0
{
235
0
  Fixed comp[3];
236
0
  SFVec3f v =  * (SFVec3f *)field_ptr;
237
0
  gf_vec_norm(&v);
238
0
  comp[0] = v.x;
239
0
  comp[1] = v.y;
240
0
  comp[2] = v.z;
241
0
  return Q_EncCoordOnUnitSphere(codec, bs, NbBits, 2, comp);
242
0
}
243
244
GF_Err Q_EncRotation(GF_BifsEncoder *codec, GF_BitStream *bs, u32 NbBits, void *field_ptr)
245
0
{
246
0
  GF_Vec4 quat;
247
0
  Fixed comp[4];
248
249
  /*get quaternion*/
250
0
  quat = gf_quat_from_rotation(*(SFRotation *)field_ptr);
251
0
  comp[0] = quat.q;
252
0
  comp[1] = quat.x;
253
0
  comp[2] = quat.y;
254
0
  comp[3] = quat.z;
255
0
  return Q_EncCoordOnUnitSphere(codec, bs, NbBits, 3, comp);
256
0
}
257
258
GF_Err gf_bifs_enc_quant_field(GF_BifsEncoder *codec, GF_BitStream *bs, GF_Node *node, GF_FieldInfo *field)
259
0
{
260
0
  Bool HasQ;
261
0
  u8 QType, AType;
262
0
  u32 NbBits;
263
0
  Fixed b_min, b_max;
264
0
  SFVec3f BMin, BMax;
265
0
  GF_Err e;
266
267
  /*check QP*/
268
0
  if (!codec->ActiveQP) return GF_EOS;
269
  /*check FieldType*/
270
0
  switch (field->fieldType) {
271
0
  case GF_SG_VRML_SFINT32:
272
0
  case GF_SG_VRML_SFFLOAT:
273
0
  case GF_SG_VRML_SFROTATION:
274
0
  case GF_SG_VRML_SFVEC2F:
275
0
  case GF_SG_VRML_SFVEC3F:
276
0
    break;
277
0
  case GF_SG_VRML_SFCOLOR:
278
0
    break;
279
0
  default:
280
0
    return GF_EOS;
281
0
  }
282
283
  /*check NDT*/
284
0
  HasQ = gf_bifs_get_aq_info(node, field->fieldIndex, &QType, &AType, &b_min, &b_max, &NbBits);
285
0
  if (!HasQ || !QType) return GF_EOS;
286
287
  /*get NbBits for QP14 (QC_COORD_INDEX)*/
288
0
  if (QType == QC_COORD_INDEX) {
289
0
    NbBits = gf_bifs_enc_qp14_get_bits(codec);
290
    /*QP14 is always on, not having NbBits set means the coord field is set after the index field, hence not decodable*/
291
0
    if (!NbBits)
292
0
      return GF_NON_COMPLIANT_BITSTREAM;
293
0
  }
294
295
0
  BMin.x = BMin.y = BMin.z = b_min;
296
0
  BMax.x = BMax.y = BMax.z = b_max;
297
298
  /*check is the QP is on and retrieves the bounds*/
299
0
  if (!Q_IsTypeOn(codec->ActiveQP, QType, &NbBits, &BMin, &BMax)) return GF_EOS;
300
301
  /*ok the field is Quantized, dequantize*/
302
0
  switch (QType) {
303
  //these are all SFFloat quantized on n fields
304
0
  case QC_3DPOS:
305
0
  case QC_2DPOS:
306
0
  case QC_ORDER:
307
0
  case QC_COLOR:
308
0
  case QC_TEXTURE_COORD:
309
0
  case QC_ANGLE:
310
0
  case QC_SCALE:
311
0
  case QC_INTERPOL_KEYS:
312
0
  case QC_SIZE_3D:
313
0
  case QC_SIZE_2D:
314
0
    e = Q_EncFloat(codec, bs, field->fieldType, BMin, BMax, NbBits, field->far_ptr);
315
0
    break;
316
  //SFInt types
317
0
  case QC_LINEAR_SCALAR:
318
0
  case QC_COORD_INDEX:
319
0
    e = Q_EncInt(codec, bs, QType, (SFInt32) b_min, NbBits, field->far_ptr);
320
0
    break;
321
  //normalized fields (normals and vectors)
322
0
  case QC_NORMALS:
323
    //normal quant is only for SFVec3F
324
0
    if (field->fieldType != GF_SG_VRML_SFVEC3F) return GF_NON_COMPLIANT_BITSTREAM;
325
0
    e = Q_EncNormal(codec, bs, NbBits, field->far_ptr);
326
0
    break;
327
0
  case QC_ROTATION:
328
    //normal quant is only for SFVec3F
329
0
    if (field->fieldType != GF_SG_VRML_SFROTATION) return GF_NON_COMPLIANT_BITSTREAM;
330
0
    e = Q_EncRotation(codec, bs, NbBits, field->far_ptr);
331
0
    break;
332
0
  default:
333
0
    return GF_BAD_PARAM;
334
0
  }
335
0
  return e;
336
0
}
337
338
#endif  /*GPAC_DISABLE_BIFS_ENC*/