AttributeDecoder.cpp 23.5 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
/* The copyright in this software is being made available under the BSD
 * Licence, included below.  This software may be subject to other third
 * party and contributor rights, including patent rights, and no such
 * rights are granted under this licence.
 *
 * Copyright (c) 2017-2018, ISO/IEC
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * * Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 *
 * * Neither the name of the ISO/IEC nor the names of its contributors
 *   may be used to endorse or promote products derived from this
 *   software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include "AttributeDecoder.h"
37

38
#include "DualLutCoder.h"
39
#include "constants.h"
40
#include "entropy.h"
41
#include "io_hls.h"
42
#include "RAHT.h"
43
#include "FixedPoint.h"
44
45
46
47
48
49
50

namespace pcc {

//============================================================================
// An encapsulation of the entropy decoding methods used in attribute coding

struct PCCResidualsDecoder {
51
52
53
54
  EntropyDecoder arithmeticDecoder;
  StaticBitModel binaryModel0;
  AdaptiveBitModel binaryModelDiff[7];
  AdaptiveBitModel binaryModelIsZero[7];
55
  AdaptiveBitModel ctxPredMode[2];
56
57
  AdaptiveBitModel ctxZeroCnt[3];
  AdaptiveBitModel binaryModelIsOne[7];
58
  DualLutCoder<false> symbolCoder[2];
59

60
  void start(const SequenceParameterSet& sps, const char* buf, int buf_len);
61
  void stop();
62
  int decodePredMode(int max);
63
  int decodeZeroCnt(int max);
64
  uint32_t decodeSymbol(int k1, int k2, int k3);
65
66
  void decode(uint32_t values[3]);
  uint32_t decode();
67
68
69
70
};

//----------------------------------------------------------------------------

71
void
72
73
PCCResidualsDecoder::start(
  const SequenceParameterSet& sps, const char* buf, int buf_len)
74
{
75
  arithmeticDecoder.setBuffer(buf_len, buf);
76
  arithmeticDecoder.enableBypassStream(sps.cabac_bypass_stream_enabled_flag);
77
  arithmeticDecoder.start();
78
79
80
81
}

//----------------------------------------------------------------------------

82
83
84
void
PCCResidualsDecoder::stop()
{
85
  arithmeticDecoder.stop();
86
87
88
89
}

//----------------------------------------------------------------------------

90
91
int
PCCResidualsDecoder::decodePredMode(int maxMode)
92
{
93
94
95
96
97
98
99
100
101
102
103
104
105
106
  int mode = 0;

  if (maxMode == 0)
    return mode;

  int ctxIdx = 0;
  while (arithmeticDecoder.decode(ctxPredMode[ctxIdx])) {
    ctxIdx = 1;
    mode++;
    if (mode == maxMode)
      break;
  }

  return mode;
107
108
109
110
}

//----------------------------------------------------------------------------

111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
int
PCCResidualsDecoder::decodeZeroCnt(int maxMode)
{
  int mode = 0;

  if (maxMode == 0)
    return mode;

  int ctxIdx = 0;
  while (arithmeticDecoder.decode(ctxZeroCnt[ctxIdx])) {
    ctxIdx = (ctxIdx == 0 ? 1 : 2);
    mode++;
    if (mode == maxMode)
      break;
  }
  return mode;
}

//----------------------------------------------------------------------------

131
uint32_t
132
PCCResidualsDecoder::decodeSymbol(int k1, int k2, int k3)
133
{
134
  if (arithmeticDecoder.decode(binaryModelIsZero[k1]))
135
    return 0u;
136

137
  if (arithmeticDecoder.decode(binaryModelIsOne[k2]))
138
    return 1u;
139

140
  uint32_t value = symbolCoder[k3].decode(&arithmeticDecoder);
141
  if (value == kAttributeResidualAlphabetSize) {
142
    value +=
143
      arithmeticDecoder.decodeExpGolomb(0, binaryModel0, binaryModelDiff[k1]);
144
  }
145

146
  return value + 2;
147
148
149
150
}

//----------------------------------------------------------------------------

151
152
153
void
PCCResidualsDecoder::decode(uint32_t value[3])
{
154
  value[0] = decodeSymbol(0, 0, 0);
155
  int b0 = value[0] == 0;
156
157
158
159
160
  int b1 = value[0] <= 1;
  value[1] = decodeSymbol(1 + b0, 1 + b1, 1);
  int b2 = value[1] == 0;
  int b3 = value[1] <= 1;
  value[2] = decodeSymbol(3 + (b0 << 1) + b2, 3 + (b1 << 1) + b3, 1);
161
162
163
164
165

  int d = (value[0] == value[1] && value[0] == value[2]);
  for (int k = 0; k < 3; k++) {
    value[k] += d;
  }
166
167
168
169
}

//----------------------------------------------------------------------------

170
uint32_t
171
PCCResidualsDecoder::decode()
172
{
173
  return decodeSymbol(0, 0, 0) + 1;
174
175
176
177
178
}

//============================================================================
// AttributeDecoder Members

179
void
180
AttributeDecoder::decode(
181
  const SequenceParameterSet& sps,
182
183
  const AttributeDescription& attr_desc,
  const AttributeParameterSet& attr_aps,
184
185
  int geom_num_points,
  int minGeomNodeSizeLog2,
186
187
  const PayloadBuffer& payload,
  PCCPointSet3& pointCloud)
188
{
189
  int abhSize;
190
  AttributeBrickHeader abh = parseAbh(attr_aps, payload, &abhSize);
191
192

  std::vector<Quantizers> quantLayers = deriveQuantizerLayers(attr_aps, abh);
193

194
  PCCResidualsDecoder decoder;
195
  decoder.start(sps, payload.data() + abhSize, payload.size() - abhSize);
196

197
  if (attr_desc.attr_num_dimensions == 1) {
198
199
    switch (attr_aps.attr_encoding) {
    case AttributeEncoding::kRAHTransform:
200
201
      decodeReflectancesRaht(
        attr_desc, attr_aps, quantLayers, decoder, pointCloud);
202
      break;
203

204
    case AttributeEncoding::kPredictingTransform:
205
206
      decodeReflectancesPred(
        attr_desc, attr_aps, quantLayers, decoder, pointCloud);
207
      break;
208

209
    case AttributeEncoding::kLiftingTransform:
210
      decodeReflectancesLift(
211
212
        attr_desc, attr_aps, quantLayers, geom_num_points, minGeomNodeSizeLog2,
        decoder, pointCloud);
213
214
      break;
    }
215
  } else if (attr_desc.attr_num_dimensions == 3) {
216
217
    switch (attr_aps.attr_encoding) {
    case AttributeEncoding::kRAHTransform:
218
      decodeColorsRaht(attr_desc, attr_aps, quantLayers, decoder, pointCloud);
219
220
221
      break;

    case AttributeEncoding::kPredictingTransform:
222
      decodeColorsPred(attr_desc, attr_aps, quantLayers, decoder, pointCloud);
223
224
225
      break;

    case AttributeEncoding::kLiftingTransform:
226
227
228
      decodeColorsLift(
        attr_desc, attr_aps, quantLayers, geom_num_points, minGeomNodeSizeLog2,
        decoder, pointCloud);
229
230
231
      break;
    }
  } else {
232
233
234
    assert(
      attr_desc.attr_num_dimensions == 1
      || attr_desc.attr_num_dimensions == 3);
235
  }
236
237
238
239
240
241

  decoder.stop();
}

//----------------------------------------------------------------------------

242
void
243
AttributeDecoder::computeReflectancePredictionWeights(
244
  const AttributeParameterSet& aps,
245
  const PCCPointSet3& pointCloud,
246
  const std::vector<uint32_t>& indexes,
247
248
249
250
  PCCPredictor& predictor,
  PCCResidualsDecoder& decoder)
{
  predictor.computeWeights();
251
252
  int64_t maxDiff = 0;

253
254
255
  if (predictor.neighborCount > 1) {
    int64_t minValue = 0;
    int64_t maxValue = 0;
256
    for (int i = 0; i < predictor.neighborCount; ++i) {
257
      const attr_t reflectanceNeighbor = pointCloud.getReflectance(
258
        indexes[predictor.neighbors[i].predictorIndex]);
259
260
261
262
263
264
265
      if (i == 0 || reflectanceNeighbor < minValue) {
        minValue = reflectanceNeighbor;
      }
      if (i == 0 || reflectanceNeighbor > maxValue) {
        maxValue = reflectanceNeighbor;
      }
    }
266
267
268
269
270
    maxDiff = maxValue - minValue;
  }

  if (maxDiff >= aps.adaptive_prediction_threshold) {
    predictor.predMode = decoder.decodePredMode(aps.max_num_direct_predictors);
271
272
273
274
275
  }
}

//----------------------------------------------------------------------------

276
void
277
AttributeDecoder::decodeReflectancesPred(
278
  const AttributeDescription& desc,
279
  const AttributeParameterSet& aps,
280
  const std::vector<Quantizers>& quantLayers,
281
282
  PCCResidualsDecoder& decoder,
  PCCPointSet3& pointCloud)
283
{
284
  const size_t pointCount = pointCloud.getPointCount();
285
286
287
  std::vector<PCCPredictor> predictors;
  std::vector<uint32_t> numberOfPointsPerLOD;
  std::vector<uint32_t> indexesLOD;
288

289
  buildPredictorsFast(
290
    aps, pointCloud, 0, predictors, numberOfPointsPerLOD, indexesLOD);
291

292
  const int64_t maxReflectance = (1ll << desc.attr_bitdepth) - 1;
293
  int zero_cnt = decoder.decodeZeroCnt(pointCount);
294
  int quantLayer = 0;
295
296
  for (size_t predictorIndex = 0; predictorIndex < pointCount;
       ++predictorIndex) {
297
298
299
300
    if (predictorIndex == numberOfPointsPerLOD[quantLayer]) {
      quantLayer = std::min(int(quantLayers.size()) - 1, quantLayer + 1);
    }
    auto& quant = quantLayers[quantLayer];
301
    auto& predictor = predictors[predictorIndex];
302

303
304
305
    computeReflectancePredictionWeights(
      aps, pointCloud, indexesLOD, predictor, decoder);
    const uint32_t pointIndex = indexesLOD[predictorIndex];
306
    attr_t& reflectance = pointCloud.getReflectance(pointIndex);
307
308
309
310
311
312
313
    uint32_t attValue0 = 0;
    if (zero_cnt > 0) {
      zero_cnt--;
    } else {
      attValue0 = decoder.decode();
      zero_cnt = decoder.decodeZeroCnt(pointCount);
    }
314
315
    const int64_t quantPredAttValue =
      predictor.predictReflectance(pointCloud, indexesLOD);
316
    const int64_t delta = divExp2RoundHalfUp(
317
      quant[0].scale(UIntToInt(attValue0)), kFixedPointAttributeShift);
318
    const int64_t reconstructedQuantAttValue = quantPredAttValue + delta;
319
320
    reflectance =
      attr_t(PCCClip(reconstructedQuantAttValue, int64_t(0), maxReflectance));
321
322
323
324
325
326
327
  }
}

//----------------------------------------------------------------------------

void
AttributeDecoder::computeColorPredictionWeights(
328
  const AttributeParameterSet& aps,
329
  const PCCPointSet3& pointCloud,
330
  const std::vector<uint32_t>& indexes,
331
332
333
334
  PCCPredictor& predictor,
  PCCResidualsDecoder& decoder)
{
  predictor.computeWeights();
335
336
  int64_t maxDiff = 0;

337
338
339
  if (predictor.neighborCount > 1) {
    int64_t minValue[3] = {0, 0, 0};
    int64_t maxValue[3] = {0, 0, 0};
340
    for (int i = 0; i < predictor.neighborCount; ++i) {
341
      const Vec3<attr_t> colorNeighbor =
342
        pointCloud.getColor(indexes[predictor.neighbors[i].predictorIndex]);
343
344
345
346
347
348
349
350
351
      for (size_t k = 0; k < 3; ++k) {
        if (i == 0 || colorNeighbor[k] < minValue[k]) {
          minValue[k] = colorNeighbor[k];
        }
        if (i == 0 || colorNeighbor[k] > maxValue[k]) {
          maxValue[k] = colorNeighbor[k];
        }
      }
    }
352
    maxDiff = (std::max)(
353
354
      maxValue[2] - minValue[2],
      (std::max)(maxValue[0] - minValue[0], maxValue[1] - minValue[1]));
355
356
357
358
  }

  if (maxDiff >= aps.adaptive_prediction_threshold) {
    predictor.predMode = decoder.decodePredMode(aps.max_num_direct_predictors);
359
360
361
362
363
  }
}

//----------------------------------------------------------------------------

364
void
365
AttributeDecoder::decodeColorsPred(
366
  const AttributeDescription& desc,
367
  const AttributeParameterSet& aps,
368
  const std::vector<Quantizers>& quantLayers,
369
370
  PCCResidualsDecoder& decoder,
  PCCPointSet3& pointCloud)
371
{
372
  const size_t pointCount = pointCloud.getPointCount();
373
374
375
  std::vector<PCCPredictor> predictors;
  std::vector<uint32_t> numberOfPointsPerLOD;
  std::vector<uint32_t> indexesLOD;
376

377
  buildPredictorsFast(
378
    aps, pointCloud, 0, predictors, numberOfPointsPerLOD, indexesLOD);
379

380
381
382
383
  Vec3<int64_t> clipMax{(1 << desc.attr_bitdepth) - 1,
                        (1 << desc.attr_bitdepth_secondary) - 1,
                        (1 << desc.attr_bitdepth_secondary) - 1};

384
  uint32_t values[3];
385
  int zero_cnt = decoder.decodeZeroCnt(pointCount);
386
  int quantLayer = 0;
387
388
  for (size_t predictorIndex = 0; predictorIndex < pointCount;
       ++predictorIndex) {
389
390
391
392
    if (predictorIndex == numberOfPointsPerLOD[quantLayer]) {
      quantLayer = std::min(int(quantLayers.size()) - 1, quantLayer + 1);
    }
    auto& quant = quantLayers[quantLayer];
393
    auto& predictor = predictors[predictorIndex];
394

395
396
    computeColorPredictionWeights(
      aps, pointCloud, indexesLOD, predictor, decoder);
397
398
399
400
401
402
403
    if (zero_cnt > 0) {
      values[0] = values[1] = values[2] = 0;
      zero_cnt--;
    } else {
      decoder.decode(values);
      zero_cnt = decoder.decodeZeroCnt(pointCount);
    }
404
    const uint32_t pointIndex = indexesLOD[predictorIndex];
405
406
    Vec3<attr_t>& color = pointCloud.getColor(pointIndex);
    const Vec3<attr_t> predictedColor =
407
      predictor.predictColor(pointCloud, indexesLOD);
408

409
    int64_t residual0 = 0;
410
411
412
413
    for (int k = 0; k < 3; ++k) {
      const auto& q = quant[std::min(k, 1)];
      const int64_t residual = divExp2RoundHalfUp(
        q.scale(UIntToInt(values[k])), kFixedPointAttributeShift);
414
      const int64_t recon = predictedColor[k] + residual + residual0;
415
      color[k] = attr_t(PCCClip(recon, int64_t(0), clipMax[k]));
416
417
418

      if (!k && aps.inter_component_prediction_enabled_flag)
        residual0 = residual;
419
420
421
422
    }
  }
}

423
424
//----------------------------------------------------------------------------

425
426
void
AttributeDecoder::decodeReflectancesRaht(
427
  const AttributeDescription& desc,
428
  const AttributeParameterSet& aps,
429
  const std::vector<Quantizers>& quantLayers,
430
431
  PCCResidualsDecoder& decoder,
  PCCPointSet3& pointCloud)
432
{
433
434
435
  const int voxelCount = int(pointCloud.getPointCount());
  std::vector<MortonCodeWithIndex> packedVoxel(voxelCount);
  for (int n = 0; n < voxelCount; n++) {
436
    packedVoxel[n].mortonCode = mortonAddr(pointCloud[n], 0);
437
438
439
440
    packedVoxel[n].index = n;
  }
  sort(packedVoxel.begin(), packedVoxel.end());

441
  // Morton codes
442
  int64_t* mortonCode = new int64_t[voxelCount];
443
444
445
446
447
  for (int n = 0; n < voxelCount; n++) {
    mortonCode[n] = packedVoxel[n].mortonCode;
  }

  // Entropy decode
448
  const int attribCount = 1;
David Flynn's avatar
David Flynn committed
449
  int* coefficients = new int[attribCount * voxelCount];
450
  int zero_cnt = decoder.decodeZeroCnt(voxelCount);
451
  for (int n = 0; n < voxelCount; ++n) {
452
453
454
455
456
457
458
    uint32_t value = 0;
    if (zero_cnt > 0) {
      zero_cnt--;
    } else {
      value = decoder.decode();
      zero_cnt = decoder.decodeZeroCnt(voxelCount);
    }
David Flynn's avatar
David Flynn committed
459
    coefficients[n] = UIntToInt(value);
460
461
  }

David Flynn's avatar
David Flynn committed
462
  int* attributes = new int[attribCount * voxelCount];
463
464

  regionAdaptiveHierarchicalInverseTransform(
465
    aps.raht_prediction_enabled_flag, quantLayers, mortonCode, attributes,
466
    attribCount, voxelCount, coefficients);
467

468
469
  const int64_t maxReflectance = (1 << desc.attr_bitdepth) - 1;
  const int64_t minReflectance = 0;
470
  for (int n = 0; n < voxelCount; n++) {
David Flynn's avatar
David Flynn committed
471
    int64_t val = attributes[attribCount * n];
472
473
    const attr_t reflectance =
      attr_t(PCCClip(val, minReflectance, maxReflectance));
474
    pointCloud.setReflectance(packedVoxel[n].index, reflectance);
475
476
477
478
479
  }

  // De-allocate arrays.
  delete[] mortonCode;
  delete[] attributes;
David Flynn's avatar
David Flynn committed
480
  delete[] coefficients;
481
482
483
484
}

//----------------------------------------------------------------------------

485
486
void
AttributeDecoder::decodeColorsRaht(
487
  const AttributeDescription& desc,
488
  const AttributeParameterSet& aps,
489
  const std::vector<Quantizers>& quantLayers,
490
491
  PCCResidualsDecoder& decoder,
  PCCPointSet3& pointCloud)
492
{
493
494
495
  const int voxelCount = int(pointCloud.getPointCount());
  std::vector<MortonCodeWithIndex> packedVoxel(voxelCount);
  for (int n = 0; n < voxelCount; n++) {
496
    packedVoxel[n].mortonCode = mortonAddr(pointCloud[n], 0);
497
498
499
500
    packedVoxel[n].index = n;
  }
  sort(packedVoxel.begin(), packedVoxel.end());

501
  // Morton codes
502
  int64_t* mortonCode = new int64_t[voxelCount];
503
504
505
506
507
508
  for (int n = 0; n < voxelCount; n++) {
    mortonCode[n] = packedVoxel[n].mortonCode;
  }

  // Entropy decode
  const int attribCount = 3;
509
  int zero_cnt = decoder.decodeZeroCnt(voxelCount);
David Flynn's avatar
David Flynn committed
510
  int* coefficients = new int[attribCount * voxelCount];
511

512
  for (int n = 0; n < voxelCount; ++n) {
513
514
515
516
517
518
519
520
    uint32_t values[3];
    if (zero_cnt > 0) {
      values[0] = values[1] = values[2] = 0;
      zero_cnt--;
    } else {
      decoder.decode(values);
      zero_cnt = decoder.decodeZeroCnt(voxelCount);
    }
521
    for (int d = 0; d < attribCount; ++d) {
David Flynn's avatar
David Flynn committed
522
      coefficients[voxelCount * d + n] = UIntToInt(values[d]);
523
524
525
    }
  }

David Flynn's avatar
David Flynn committed
526
  int* attributes = new int[attribCount * voxelCount];
527

528
  regionAdaptiveHierarchicalInverseTransform(
529
    aps.raht_prediction_enabled_flag, quantLayers, mortonCode, attributes,
530
    attribCount, voxelCount, coefficients);
531

532
533
534
535
  Vec3<int> clipMax{(1 << desc.attr_bitdepth) - 1,
                    (1 << desc.attr_bitdepth_secondary) - 1,
                    (1 << desc.attr_bitdepth_secondary) - 1};

536
  for (int n = 0; n < voxelCount; n++) {
David Flynn's avatar
David Flynn committed
537
538
539
    const int r = attributes[attribCount * n];
    const int g = attributes[attribCount * n + 1];
    const int b = attributes[attribCount * n + 2];
540
    Vec3<attr_t> color;
541
542
543
    color[0] = attr_t(PCCClip(r, 0, clipMax[0]));
    color[1] = attr_t(PCCClip(g, 0, clipMax[1]));
    color[2] = attr_t(PCCClip(b, 0, clipMax[2]));
544
545
546
547
548
549
    pointCloud.setColor(packedVoxel[n].index, color);
  }

  // De-allocate arrays.
  delete[] mortonCode;
  delete[] attributes;
David Flynn's avatar
David Flynn committed
550
  delete[] coefficients;
551
552
}

553
554
555
556
//----------------------------------------------------------------------------

void
AttributeDecoder::decodeColorsLift(
557
  const AttributeDescription& desc,
558
  const AttributeParameterSet& aps,
559
  const std::vector<Quantizers>& quantLayers,
560
561
  int geom_num_points,
  int minGeomNodeSizeLog2,
562
563
  PCCResidualsDecoder& decoder,
  PCCPointSet3& pointCloud)
564
565
{
  const size_t pointCount = pointCloud.getPointCount();
566
  std::vector<PCCPredictor> predictors;
567
568
  std::vector<uint32_t> numberOfPointsPerLOD;
  std::vector<uint32_t> indexesLOD;
569

570
571
572
  if (minGeomNodeSizeLog2 > 0)
    assert(aps.scalable_lifting_enabled_flag);

573
  buildPredictorsFast(
574
575
    aps, pointCloud, minGeomNodeSizeLog2, predictors, numberOfPointsPerLOD,
    indexesLOD);
576

577
578
579
580
  for (size_t predictorIndex = 0; predictorIndex < pointCount;
       ++predictorIndex) {
    predictors[predictorIndex].computeWeights();
  }
581
  std::vector<uint64_t> weights;
582
583
584
585
586
587
588
589
  if (!aps.scalable_lifting_enabled_flag) {
    PCCComputeQuantizationWeights(predictors, weights);
  } else {
    computeQuantizationWeightsScalable(
      predictors, numberOfPointsPerLOD, geom_num_points, minGeomNodeSizeLog2,
      weights);
  }

590
  const size_t lodCount = numberOfPointsPerLOD.size();
591
  std::vector<Vec3<int64_t>> colors;
592
  colors.resize(pointCount);
593

594
595
596
597
598
  // NB: when partially decoding, the truncated unary limit for zero_run
  // must be the original value.  geom_num_points may be the case.  However,
  // the encoder does lie sometimes, and there are actually more points.
  int zeroCntLimit = std::max(geom_num_points, int(pointCount));

599
  // decompress
600
601
  int zero_cnt = decoder.decodeZeroCnt(zeroCntLimit);
  std::cout << zero_cnt << '\n';
602
  int quantLayer = 0;
603
604
  for (size_t predictorIndex = 0; predictorIndex < pointCount;
       ++predictorIndex) {
605
606
607
608
609
    if (predictorIndex == numberOfPointsPerLOD[quantLayer]) {
      quantLayer = std::min(int(quantLayers.size()) - 1, quantLayer + 1);
    }
    auto& quant = quantLayers[quantLayer];

610
    uint32_t values[3];
611
612
613
614
615
    if (zero_cnt > 0) {
      values[0] = values[1] = values[2] = 0;
      zero_cnt--;
    } else {
      decoder.decode(values);
616
617
      zero_cnt = decoder.decodeZeroCnt(zeroCntLimit);
  std::cout << zero_cnt << '\n';
618
    }
619

620
    const int64_t quantWeight = weights[predictorIndex];
621
    auto& color = colors[predictorIndex];
622
    const int64_t delta = UIntToInt(values[0]);
623
    const int64_t reconstructedDelta = quant[0].scale(delta);
624
625
    color[0] = reconstructedDelta / quantWeight;
    for (size_t d = 1; d < 3; ++d) {
626
      const int64_t delta = UIntToInt(values[d]);
627
      const int64_t reconstructedDelta = quant[1].scale(delta);
628
629
630
631
632
633
634
635
636
637
638
      color[d] = reconstructedDelta / quantWeight;
    }
  }

  // reconstruct
  for (size_t lodIndex = 1; lodIndex < lodCount; ++lodIndex) {
    const size_t startIndex = numberOfPointsPerLOD[lodIndex - 1];
    const size_t endIndex = numberOfPointsPerLOD[lodIndex];
    PCCLiftUpdate(predictors, weights, startIndex, endIndex, false, colors);
    PCCLiftPredict(predictors, startIndex, endIndex, false, colors);
  }
639

640
641
642
643
  Vec3<int64_t> clipMax{(1 << desc.attr_bitdepth) - 1,
                        (1 << desc.attr_bitdepth_secondary) - 1,
                        (1 << desc.attr_bitdepth_secondary) - 1};

644
  for (size_t f = 0; f < pointCount; ++f) {
645
646
    const auto color0 =
      divExp2RoundHalfInf(colors[f], kFixedPointAttributeShift);
647
    Vec3<attr_t> color;
648
    for (size_t d = 0; d < 3; ++d) {
649
      color[d] = attr_t(PCCClip(color0[d], int64_t(0), clipMax[d]));
650
    }
651
    pointCloud.setColor(indexesLOD[f], color);
652
653
654
655
656
657
658
  }
}

//----------------------------------------------------------------------------

void
AttributeDecoder::decodeReflectancesLift(
659
  const AttributeDescription& desc,
660
  const AttributeParameterSet& aps,
661
  const std::vector<Quantizers>& quantLayers,
662
663
  int geom_num_points,
  int minGeomNodeSizeLog2,
664
665
  PCCResidualsDecoder& decoder,
  PCCPointSet3& pointCloud)
666
{
667
  const size_t pointCount = pointCloud.getPointCount();
668
  std::vector<PCCPredictor> predictors;
669
670
  std::vector<uint32_t> numberOfPointsPerLOD;
  std::vector<uint32_t> indexesLOD;
671

672
673
674
  if (minGeomNodeSizeLog2 > 0)
    assert(aps.scalable_lifting_enabled_flag);

675
  buildPredictorsFast(
676
677
    aps, pointCloud, minGeomNodeSizeLog2, predictors, numberOfPointsPerLOD,
    indexesLOD);
678

679
680
681
682
  for (size_t predictorIndex = 0; predictorIndex < pointCount;
       ++predictorIndex) {
    predictors[predictorIndex].computeWeights();
  }
683

684
  std::vector<uint64_t> weights;
685
686
687
688
689
690
691
692
  if (!aps.scalable_lifting_enabled_flag) {
    PCCComputeQuantizationWeights(predictors, weights);
  } else {
    computeQuantizationWeightsScalable(
      predictors, numberOfPointsPerLOD, geom_num_points, minGeomNodeSizeLog2,
      weights);
  }

693
  const size_t lodCount = numberOfPointsPerLOD.size();
694
  std::vector<int64_t> reflectances;
695
  reflectances.resize(pointCount);
696

697
698
699
700
701
  // NB: when partially decoding, the truncated unary limit for zero_run
  // must be the original value.  geom_num_points may be the case.  However,
  // the encoder does lie sometimes, and there are actually more points.
  int zeroCntLimit = std::max(geom_num_points, int(pointCount));

702
  // decompress
703
  int zero_cnt = decoder.decodeZeroCnt(zeroCntLimit);
704
  int quantLayer = 0;
705
706
  for (size_t predictorIndex = 0; predictorIndex < pointCount;
       ++predictorIndex) {
707
708
709
710
711
    if (predictorIndex == numberOfPointsPerLOD[quantLayer]) {
      quantLayer = std::min(int(quantLayers.size()) - 1, quantLayer + 1);
    }
    auto& quant = quantLayers[quantLayer];

712
713
714
715
716
    int64_t detail = 0;
    if (zero_cnt > 0) {
      zero_cnt--;
    } else {
      detail = decoder.decode();
717
      zero_cnt = decoder.decodeZeroCnt(zeroCntLimit);
718
    }
719
    const int64_t quantWeight = weights[predictorIndex];
720
    auto& reflectance = reflectances[predictorIndex];
721
    const int64_t delta = UIntToInt(detail);
722
    const int64_t reconstructedDelta = quant[0].scale(delta);
723
724
725
726
727
728
729
730
731
732
733
    reflectance = reconstructedDelta / quantWeight;
  }

  // reconstruct
  for (size_t lodIndex = 1; lodIndex < lodCount; ++lodIndex) {
    const size_t startIndex = numberOfPointsPerLOD[lodIndex - 1];
    const size_t endIndex = numberOfPointsPerLOD[lodIndex];
    PCCLiftUpdate(
      predictors, weights, startIndex, endIndex, false, reflectances);
    PCCLiftPredict(predictors, startIndex, endIndex, false, reflectances);
  }
734
  const int64_t maxReflectance = (1 << desc.attr_bitdepth) - 1;
735
  for (size_t f = 0; f < pointCount; ++f) {
736
737
    const auto refl =
      divExp2RoundHalfInf(reflectances[f], kFixedPointAttributeShift);
738
    pointCloud.setReflectance(
739
      indexesLOD[f], attr_t(PCCClip(refl, int64_t(0), maxReflectance)));
740
741
742
  }
}

743
744
//============================================================================

745
} /* namespace pcc */