Commit e9dd9ce0 authored by David Flynn's avatar David Flynn
Browse files

geom/m44750: occupancy context maps with on-the-fly update

Bitwise geometry occupancy coding uses a mapping table to select entropy
contexts.  This commit employs a dynamic mapping which is updated after
each coding operation, replacing the previous static mapping tables.

NB: the proposed version used a context with a halving period
(max_count) of 64 symbols.  However, this conflicts with another
adoption (512 symbols), and a wholesale replacement of the arithmetic
codec and context model.  To resolve the conflict, the existing halving
period (128) is used.
parent fc813708
...@@ -11,6 +11,7 @@ categories: ...@@ -11,6 +11,7 @@ categories:
# - preserve lossless geometry property # - preserve lossless geometry property
- geometryCodec: 1 - geometryCodec: 1
- mergeDuplicatedPoints: 0 - mergeDuplicatedPoints: 0
- ctxOccupancyReductionFactor: 3
- neighbourAvailBoundaryLog2: 9 - neighbourAvailBoundaryLog2: 9
- positionQuantizationScale: 1 - positionQuantizationScale: 1
......
...@@ -10,6 +10,7 @@ categories: ...@@ -10,6 +10,7 @@ categories:
# geometry parameters (octree) # geometry parameters (octree)
- geometryCodec: 1 - geometryCodec: 1
- mergeDuplicatedPoints: 1 - mergeDuplicatedPoints: 1
- ctxOccupancyReductionFactor: 3
- neighbourAvailBoundaryLog2: 9 - neighbourAvailBoundaryLog2: 9
- positionQuantizationScale: - positionQuantizationScale:
r01: '$eval{ $rp = 5; $gp = ${src-geometry-precision}; $p_min = max(gp - 9, 7); $start = min(1, $gp - ($p_min + 6)); $step = max(1, (min($gp - 1, $p_min + 7) - $p_min) / 5); $y = $start + round($rp * $step); $div = 1 << (abs($y) + 1); ((1 - 2*signbit($y)) % $div) / $div }' r01: '$eval{ $rp = 5; $gp = ${src-geometry-precision}; $p_min = max(gp - 9, 7); $start = min(1, $gp - ($p_min + 6)); $step = max(1, (min($gp - 1, $p_min + 7) - $p_min) / 5); $y = $start + round($rp * $step); $div = 1 << (abs($y) + 1); ((1 - 2*signbit($y)) % $div) / $div }'
......
...@@ -14,6 +14,7 @@ categories: ...@@ -14,6 +14,7 @@ categories:
# geometry parameters (octree) # geometry parameters (octree)
- geometryCodec: 1 - geometryCodec: 1
- neighbourAvailBoundaryLog2: 9 - neighbourAvailBoundaryLog2: 9
- ctxOccupancyReductionFactor: 3
#### ####
# attribute coding (common options -- relies on option ordering) # attribute coding (common options -- relies on option ordering)
......
...@@ -14,6 +14,7 @@ categories: ...@@ -14,6 +14,7 @@ categories:
# geometry parameters (octree) # geometry parameters (octree)
- geometryCodec: 1 - geometryCodec: 1
- neighbourAvailBoundaryLog2: 9 - neighbourAvailBoundaryLog2: 9
- ctxOccupancyReductionFactor: 3
#### ####
# attribute coding (common options -- relies on option ordering) # attribute coding (common options -- relies on option ordering)
......
...@@ -11,6 +11,7 @@ categories: ...@@ -11,6 +11,7 @@ categories:
# - preserve lossless geometry property # - preserve lossless geometry property
- geometryCodec: 1 - geometryCodec: 1
- mergeDuplicatedPoints: 0 - mergeDuplicatedPoints: 0
- ctxOccupancyReductionFactor: 3
- neighbourAvailBoundaryLog2: 9 - neighbourAvailBoundaryLog2: 9
- positionQuantizationScale: 1 - positionQuantizationScale: 1
......
...@@ -10,6 +10,7 @@ categories: ...@@ -10,6 +10,7 @@ categories:
# geometry parameters (octree) # geometry parameters (octree)
- geometryCodec: 1 - geometryCodec: 1
- mergeDuplicatedPoints: 1 - mergeDuplicatedPoints: 1
- ctxOccupancyReductionFactor: 3
- neighbourAvailBoundaryLog2: 9 - neighbourAvailBoundaryLog2: 9
- positionQuantizationScale: - positionQuantizationScale:
r01: '$eval{ $rp = 5; $gp = ${src-geometry-precision}; $p_min = max(gp - 9, 7); $start = min(1, $gp - ($p_min + 6)); $step = max(1, (min($gp - 1, $p_min + 7) - $p_min) / 5); $y = $start + round($rp * $step); $div = 1 << (abs($y) + 1); ((1 - 2*signbit($y)) % $div) / $div }' r01: '$eval{ $rp = 5; $gp = ${src-geometry-precision}; $p_min = max(gp - 9, 7); $start = min(1, $gp - ($p_min + 6)); $step = max(1, (min($gp - 1, $p_min + 7) - $p_min) / 5); $y = $start + round($rp * $step); $div = 1 << (abs($y) + 1); ((1 - 2*signbit($y)) % $div) / $div }'
......
...@@ -10,6 +10,7 @@ categories: ...@@ -10,6 +10,7 @@ categories:
## ##
# geometry parameters (trisoup) # geometry parameters (trisoup)
- geometryCodec: 2 - geometryCodec: 2
- ctxOccupancyReductionFactor: 3
- neighbourAvailBoundaryLog2: 9 - neighbourAvailBoundaryLog2: 9
- inferredDirectCodingMode: 0 - inferredDirectCodingMode: 0
- triSoupDepth: ${test-depth} - triSoupDepth: ${test-depth}
......
...@@ -10,6 +10,7 @@ categories: ...@@ -10,6 +10,7 @@ categories:
## ##
# geometry parameters (trisoup) # geometry parameters (trisoup)
- geometryCodec: 2 - geometryCodec: 2
- ctxOccupancyReductionFactor: 3
- neighbourAvailBoundaryLog2: 9 - neighbourAvailBoundaryLog2: 9
- inferredDirectCodingMode: 0 - inferredDirectCodingMode: 0
- triSoupDepth: ${test-depth} - triSoupDepth: ${test-depth}
......
...@@ -323,6 +323,10 @@ ParseParameters(int argc, char* argv[], Parameters& params) ...@@ -323,6 +323,10 @@ ParseParameters(int argc, char* argv[], Parameters& params)
params.encoder.gps.inferred_direct_coding_mode_enabled_flag, true, params.encoder.gps.inferred_direct_coding_mode_enabled_flag, true,
"Permits early termination of the geometry octree for isolated points") "Permits early termination of the geometry octree for isolated points")
("ctxOccupancyReductionFactor",
params.encoder.gps.geom_occupancy_ctx_reduction_factor, 3,
"Adjusts the number of contexts used in occupancy coding")
// (trisoup) geometry parameters // (trisoup) geometry parameters
("triSoupDepth", // log2(maxBB+1), where maxBB+1 is analogous to image width ("triSoupDepth", // log2(maxBB+1), where maxBB+1 is analogous to image width
params.encoder.gps.trisoup_depth, 10, params.encoder.gps.trisoup_depth, 10,
......
...@@ -198,4 +198,29 @@ updateGeometryNeighState( ...@@ -198,4 +198,29 @@ updateGeometryNeighState(
//============================================================================ //============================================================================
CtxMapOctreeOccupancy::CtxMapOctreeOccupancy()
{
map.reset(new CtxIdxMap);
b[0] = map->b0;
b[1] = map->b1;
b[2] = map->b2;
b[3] = map->b3;
b[4] = map->b4;
b[5] = map->b5;
b[6] = map->b6;
b[7] = map->b7;
using namespace std;
fill(begin(map->b0), end(map->b0), 127);
fill(begin(map->b1), end(map->b1), 127);
fill(begin(map->b2), end(map->b2), 127);
fill(begin(map->b3), end(map->b3), 127);
fill(begin(map->b4), end(map->b4), 127);
fill(begin(map->b5), end(map->b5), 127);
fill(begin(map->b6), end(map->b6), 127);
fill(begin(map->b7), end(map->b7), 127);
}
//============================================================================
} // namespace pcc } // namespace pcc
...@@ -42,6 +42,7 @@ ...@@ -42,6 +42,7 @@
#include "PCCPointSet.h" #include "PCCPointSet.h"
#include "hls.h" #include "hls.h"
#include "ringbuf.h" #include "ringbuf.h"
#include "tables.h"
namespace pcc { namespace pcc {
...@@ -130,32 +131,63 @@ isDirectModeEligible( ...@@ -130,32 +131,63 @@ isDirectModeEligible(
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
struct CtxModelOctreeOccupancy { struct CtxModelOctreeOccupancy {
o3dgc::Adaptive_Bit_Model_Fast b0[10]; o3dgc::Adaptive_Bit_Model_Fast contexts[256];
o3dgc::Adaptive_Bit_Model_Fast b1[2 * 10]; int ctxFactorShift;
o3dgc::Adaptive_Bit_Model_Fast b2[4 * 10];
o3dgc::Adaptive_Bit_Model_Fast b3[8 * 10]; CtxModelOctreeOccupancy(int ctxFactorShift) : ctxFactorShift(ctxFactorShift)
o3dgc::Adaptive_Bit_Model_Fast b4[75]; {}
o3dgc::Adaptive_Bit_Model_Fast b5[112];
o3dgc::Adaptive_Bit_Model_Fast b6[117]; o3dgc::Adaptive_Bit_Model& operator[](int idx)
o3dgc::Adaptive_Bit_Model_Fast b7[127];
o3dgc::Adaptive_Bit_Model* operator[](int bit_pos)
{ {
assert(unsigned(bit_pos) < 8); return contexts[idx >> ctxFactorShift];
switch (bit_pos) {
case 0: return b0;
case 1: return b1;
case 2: return b2;
case 3: return b3;
case 4: return b4;
case 5: return b5;
case 6: return b6;
case 7: return b7;
default: return nullptr;
}
} }
}; };
//---------------------------------------------------------------------------
// Encapsulates the derivation of ctxIdx for occupancy coding.
class CtxMapOctreeOccupancy {
public:
struct CtxIdxMap {
uint8_t b0[10];
uint8_t b1[20];
uint8_t b2[39];
uint8_t b3[76];
uint8_t b4[149];
uint8_t b5[294];
uint8_t b6[391];
uint8_t b7[520];
};
CtxMapOctreeOccupancy();
const uint8_t* operator[](int bit) const { return b[bit]; }
uint8_t* operator[](int bit) { return b[bit]; }
// return *ctxIdx and update *ctxIdx according to bit
static uint8_t evolve(bool bit, uint8_t* ctxIdx);
private:
std::unique_ptr<CtxIdxMap> map;
uint8_t* b[8];
};
//----------------------------------------------------------------------------
inline uint8_t
CtxMapOctreeOccupancy::evolve(bool bit, uint8_t* ctxIdx)
{
uint8_t retval = *ctxIdx;
if (bit)
*ctxIdx = kCtxMapOctreeOccupancyEvolutionOn1[*ctxIdx];
else
*ctxIdx = kCtxMapOctreeOccupancyEvolutionOn0[*ctxIdx];
return retval;
}
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
} // namespace pcc } // namespace pcc
...@@ -85,6 +85,7 @@ private: ...@@ -85,6 +85,7 @@ private:
// For bitwise occupancy coding // For bitwise occupancy coding
CtxModelOctreeOccupancy _ctxOccupancy; CtxModelOctreeOccupancy _ctxOccupancy;
CtxMapOctreeOccupancy _ctxIdxMap;
// For bytewise occupancy coding // For bytewise occupancy coding
DualLutCoder<true> _bytewiseOccupancyCoder[10]; DualLutCoder<true> _bytewiseOccupancyCoder[10];
...@@ -96,6 +97,7 @@ GeometryOctreeDecoder::GeometryOctreeDecoder( ...@@ -96,6 +97,7 @@ GeometryOctreeDecoder::GeometryOctreeDecoder(
const GeometryParameterSet& gps, o3dgc::Arithmetic_Codec* arithmeticDecoder) const GeometryParameterSet& gps, o3dgc::Arithmetic_Codec* arithmeticDecoder)
: _useBitwiseOccupancyCoder(gps.bitwise_occupancy_coding_flag) : _useBitwiseOccupancyCoder(gps.bitwise_occupancy_coding_flag)
, _arithmeticDecoder(arithmeticDecoder) , _arithmeticDecoder(arithmeticDecoder)
, _ctxOccupancy(gps.geom_occupancy_ctx_reduction_factor)
{ {
if (!_useBitwiseOccupancyCoder) { if (!_useBitwiseOccupancyCoder) {
for (int i = 0; i < 10; i++) for (int i = 0; i < 10; i++)
...@@ -146,9 +148,10 @@ GeometryOctreeDecoder::decodeOccupancyNeighZ() ...@@ -146,9 +148,10 @@ GeometryOctreeDecoder::decodeOccupancyNeighZ()
// NB: There must be at least two occupied child nodes // NB: There must be at least two occupied child nodes
// -- avoid coding the occupancy bit if it is implied. // -- avoid coding the occupancy bit if it is implied.
if (numOccupiedAcc >= minOccupied + i - 7) { if (numOccupiedAcc >= minOccupied + i - 7) {
int idx = numOccupiedAcc; int ctxIdx = _ctxIdxMap[i][numOccupiedAcc];
bit = _arithmeticDecoder->decode(_ctxOccupancy[i][idx]); bit = _arithmeticDecoder->decode(_ctxOccupancy[ctxIdx]);
} }
_ctxIdxMap.evolve(bit, &_ctxIdxMap[i][numOccupiedAcc]);
numOccupiedAcc += bit; numOccupiedAcc += bit;
occupancy |= bit << occupancyCodingOrder[i]; occupancy |= bit << occupancyCodingOrder[i];
} }
...@@ -173,30 +176,26 @@ GeometryOctreeDecoder::decodeOccupancyNeighNZ(int neighPattern10) ...@@ -173,30 +176,26 @@ GeometryOctreeDecoder::decodeOccupancyNeighNZ(int neighPattern10)
// NB: it is impossible for pattern to be 0 (handled in Z case). // NB: it is impossible for pattern to be 0 (handled in Z case).
// NB: offsets are added since ctxIdxMap is shared between Z and NZ cases. // NB: offsets are added since ctxIdxMap is shared between Z and NZ cases.
for (int i = 0; i < 8; i++) { for (int i = 0; i < 8; i++) {
int idx, bit; int idx;
if (i < 4) { if (i < 6) {
idx = (neighPattern10 << i) + partialOccupancy; idx = ((neighPattern10 - 1) << i) + partialOccupancy + i + 1;
} else if (i == 4) {
idx = ((neighPattern10 - 1) << i) + partialOccupancy;
idx = kOccMapBit4CtxIdx[idx] + i;
} else if (i == 5) {
idx = ((neighPattern10 - 1) << i) + partialOccupancy;
idx = kOccMapBit5CtxIdx[idx] + i;
} else if (i == 6) { } else if (i == 6) {
idx = ((neighPattern7 - 1) << i) + partialOccupancy; idx = ((neighPattern7 - 1) << i) + partialOccupancy + i + 1;
idx = kOccMapBit6CtxIdx[idx] + i;
} else if (i == 7) { } else if (i == 7) {
idx = ((neighPattern5 - 1) << i) + partialOccupancy; idx = ((neighPattern5 - 1) << i) + partialOccupancy + i + 1;
idx = kOccMapBit7CtxIdx[idx] + i;
bit = 1;
} else { } else {
// work around clang -Wsometimes-uninitialized fault // work around clang -Wsometimes-uninitialized fault
break; break;
} }
// NB: if firt 7 bits are 0, then the last is implicitly 1. // NB: if firt 7 bits are 0, then the last is implicitly 1.
if (i < 7 || partialOccupancy) int bit = 1;
bit = _arithmeticDecoder->decode(_ctxOccupancy[i][idx]); if (i < 7 || partialOccupancy) {
int ctxIdx = _ctxIdxMap[i][idx];
bit = _arithmeticDecoder->decode(_ctxOccupancy[ctxIdx]);
}
_ctxIdxMap.evolve(bit, &_ctxIdxMap[i][idx]);
partialOccupancy |= bit << i; partialOccupancy |= bit << i;
occupancy |= bit << occupancyCodingOrder[i]; occupancy |= bit << occupancyCodingOrder[i];
} }
......
...@@ -86,6 +86,7 @@ private: ...@@ -86,6 +86,7 @@ private:
// For bitwise occupancy coding // For bitwise occupancy coding
CtxModelOctreeOccupancy _ctxOccupancy; CtxModelOctreeOccupancy _ctxOccupancy;
CtxMapOctreeOccupancy _ctxIdxMap;
// For bytewise occupancy coding // For bytewise occupancy coding
DualLutCoder<true> _bytewiseOccupancyCoder[10]; DualLutCoder<true> _bytewiseOccupancyCoder[10];
...@@ -97,6 +98,7 @@ GeometryOctreeEncoder::GeometryOctreeEncoder( ...@@ -97,6 +98,7 @@ GeometryOctreeEncoder::GeometryOctreeEncoder(
const GeometryParameterSet& gps, o3dgc::Arithmetic_Codec* arithmeticEncoder) const GeometryParameterSet& gps, o3dgc::Arithmetic_Codec* arithmeticEncoder)
: _useBitwiseOccupancyCoder(gps.bitwise_occupancy_coding_flag) : _useBitwiseOccupancyCoder(gps.bitwise_occupancy_coding_flag)
, _arithmeticEncoder(arithmeticEncoder) , _arithmeticEncoder(arithmeticEncoder)
, _ctxOccupancy(gps.geom_occupancy_ctx_reduction_factor)
{ {
if (!_useBitwiseOccupancyCoder) { if (!_useBitwiseOccupancyCoder) {
for (int i = 0; i < 10; i++) for (int i = 0; i < 10; i++)
...@@ -142,16 +144,17 @@ GeometryOctreeEncoder::encodeOccupancyNeighZ(int mappedOccupancy) ...@@ -142,16 +144,17 @@ GeometryOctreeEncoder::encodeOccupancyNeighZ(int mappedOccupancy)
int numOccupiedAcc = 0; int numOccupiedAcc = 0;
for (int i = 0; i < 8; i++) { for (int i = 0; i < 8; i++) {
int occupancyBit = (mappedOccupancy >> occupancyCodingOrder[i]) & 1;
int idx = numOccupiedAcc;
int ctxIdx = _ctxIdxMap.evolve(occupancyBit, &_ctxIdxMap[i][idx]);
// NB: There must be at least minOccupied child nodes // NB: There must be at least minOccupied child nodes
// -- avoid coding the occupancyBit if it is implied. // -- avoid coding the occupancyBit if it is implied.
if (numOccupiedAcc < minOccupied + i - 7) { if (numOccupiedAcc >= minOccupied + i - 7) {
assert(i >= 6); _arithmeticEncoder->encode(occupancyBit, _ctxOccupancy[ctxIdx]);
break;
} }
int occupancyBit = (mappedOccupancy >> occupancyCodingOrder[i]) & 1;
int idx = numOccupiedAcc;
_arithmeticEncoder->encode(occupancyBit, _ctxOccupancy[i][idx]);
numOccupiedAcc += occupancyBit; numOccupiedAcc += occupancyBit;
} }
} }
...@@ -175,29 +178,23 @@ GeometryOctreeEncoder::encodeOccupancyNeighNZ( ...@@ -175,29 +178,23 @@ GeometryOctreeEncoder::encodeOccupancyNeighNZ(
int occupancyBit = (mappedOccupancy >> occupancyCodingOrder[i]) & 1; int occupancyBit = (mappedOccupancy >> occupancyCodingOrder[i]) & 1;
int idx; int idx;
if (i < 4) if (i < 6) {
idx = (neighPattern10 << i) + partialOccupancy; idx = ((neighPattern10 - 1) << i) + partialOccupancy + i + 1;
else if (i == 4) {
idx = ((neighPattern10 - 1) << i) + partialOccupancy;
idx = kOccMapBit4CtxIdx[idx] + i;
} else if (i == 5) {
idx = ((neighPattern10 - 1) << i) + partialOccupancy;
idx = kOccMapBit5CtxIdx[idx] + i;
} else if (i == 6) { } else if (i == 6) {
idx = ((neighPattern7 - 1) << i) + partialOccupancy; idx = ((neighPattern7 - 1) << i) + partialOccupancy + i + 1;
idx = kOccMapBit6CtxIdx[idx] + i;
} else if (i == 7) { } else if (i == 7) {
// NB: if firt 7 bits are 0, then the last is implicitly 1. idx = ((neighPattern5 - 1) << i) + partialOccupancy + i + 1;
if (!partialOccupancy)
break;
idx = ((neighPattern5 - 1) << i) + partialOccupancy;
idx = kOccMapBit7CtxIdx[idx] + i;
} else { } else {
// work around clang -Wsometimes-uninitialized fault // work around clang -Wsometimes-uninitialized fault
break; break;
} }
_arithmeticEncoder->encode(occupancyBit, _ctxOccupancy[i][idx]); int ctxIdx = _ctxIdxMap.evolve(occupancyBit, &_ctxIdxMap[i][idx]);
// NB: if firt 7 bits are 0, then the last is implicitly 1.
if (i < 7 || partialOccupancy)
_arithmeticEncoder->encode(occupancyBit, _ctxOccupancy[ctxIdx]);
partialOccupancy |= occupancyBit << i; partialOccupancy |= occupancyBit << i;
} }
} }
......
...@@ -207,6 +207,10 @@ struct GeometryParameterSet { ...@@ -207,6 +207,10 @@ struct GeometryParameterSet {
// Selects between bitwise and bytewise occupancy coding // Selects between bitwise and bytewise occupancy coding
bool bitwise_occupancy_coding_flag; bool bitwise_occupancy_coding_flag;
// Experimental knob to control the number of contexts used
// for occupancy coding.
int geom_occupancy_ctx_reduction_factor;
// depth of voxels (reconstructed points) in trisoup geometry // depth of voxels (reconstructed points) in trisoup geometry
int trisoup_depth; int trisoup_depth;
......
...@@ -193,6 +193,7 @@ write(const GeometryParameterSet& gps) ...@@ -193,6 +193,7 @@ write(const GeometryParameterSet& gps)
bs.write(gps.neighbour_context_restriction_flag); bs.write(gps.neighbour_context_restriction_flag);
bs.write(gps.inferred_direct_coding_mode_enabled_flag); bs.write(gps.inferred_direct_coding_mode_enabled_flag);
bs.write(gps.bitwise_occupancy_coding_flag); bs.write(gps.bitwise_occupancy_coding_flag);
bs.writeUe(gps.geom_occupancy_ctx_reduction_factor);
bs.writeUe(gps.neighbour_avail_boundary_log2); bs.writeUe(gps.neighbour_avail_boundary_log2);
if (gps.geom_codec_type == GeometryCodecType::kTriSoup) { if (gps.geom_codec_type == GeometryCodecType::kTriSoup) {
...@@ -224,6 +225,7 @@ parseGps(const PayloadBuffer& buf) ...@@ -224,6 +225,7 @@ parseGps(const PayloadBuffer& buf)
bs.read(&gps.neighbour_context_restriction_flag); bs.read(&gps.neighbour_context_restriction_flag);
bs.read(&gps.inferred_direct_coding_mode_enabled_flag); bs.read(&gps.inferred_direct_coding_mode_enabled_flag);
bs.read(&gps.bitwise_occupancy_coding_flag); bs.read(&gps.bitwise_occupancy_coding_flag);
bs.readUe(&gps.geom_occupancy_ctx_reduction_factor);
bs.readUe(&gps.neighbour_avail_boundary_log2); bs.readUe(&gps.neighbour_avail_boundary_log2);
if (gps.geom_codec_type == GeometryCodecType::kTriSoup) { if (gps.geom_codec_type == GeometryCodecType::kTriSoup) {
......
...@@ -247,96 +247,48 @@ const uint8_t pcc::kOccMapRotateZ090[256] = { ...@@ -247,96 +247,48 @@ const uint8_t pcc::kOccMapRotateZ090[256] = {
50, 54, 58, 62, 114, 118, 122, 126, 178, 182, 186, 190, 242, 246, 250, 254, 50, 54, 58, 62, 114, 118, 122, 126, 178, 182, 186, 190, 242, 246, 250, 254,
51, 55, 59, 63, 115, 119, 123, 127, 179, 183, 187, 191, 243, 247, 251, 255}; 51, 55, 59, 63, 115, 119, 123, 127, 179, 183, 187, 191, 243, 247, 251, 255};
const uint8_t pcc::kOccMapBit4CtxIdx[16 * 9] = { //============================================================================
1, 3, 3, 3, 3, 4, 5, 6, 7, 6, 8, 4, 3, 9, 10, 11, 12, 13,
14, 15, 13, 16, 13, 17, 5, 18, 19, 18, 20, 21, 22, 16, 23, 20, 4, 4,
5, 4, 9, 24, 4, 4, 25, 26, 4, 9, 13, 25, 27, 28, 29, 19, 24, 30,
17, 31, 26, 32, 33, 34, 9, 23, 35, 36, 37, 13, 38, 3, 33, 39, 40, 9,
13, 41, 18, 6, 7, 9, 29, 20, 11, 9, 8, 24, 4, 24, 6, 22, 15, 34,
18, 23, 33, 42, 43, 23, 44, 28, 43, 16, 39, 11, 12, 45, 33, 41, 46, 45,
47, 48, 49, 50, 51, 11, 32, 30, 41, 2, 41, 52, 17, 53, 27, 54, 42, 55,
36, 48, 56, 57, 54, 49, 58, 59, 60, 37, 61, 62, 63, 64, 65, 66, 67, 68};
const uint8_t pcc::kOccMapBit5CtxIdx[32 * 9] = {
1, 3, 3, 4, 5, 6, 7, 8, 9, 10, 4, 11, 9, 12, 13, 14, 15,
16, 15, 17, 18, 7, 19, 20, 21, 8, 19, 22, 22, 23, 24, 25, 26, 6,
27, 28, 5, 29, 30, 14, 31, 21, 32, 33, 34, 15, 11, 35, 36, 8, 6,
37, 38, 7, 29, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 5, 27, 11,
37, 11, 49, 7, 10, 20, 18, 50, 51, 52, 17, 47, 53, 17, 54, 55, 56,
19, 57, 36, 40, 50, 54, 58, 36, 59, 60, 61, 62, 35, 16, 63, 27, 15,
4, 16, 15, 12, 33, 64, 4, 15, 10, 65, 47, 66, 67, 15, 12, 36, 68,
65, 19, 47, 69, 44, 70, 57, 71, 33, 61, 64, 15, 72, 31, 30, 13, 28,
73, 26, 42, 74, 3, 17, 5, 15, 75, 76, 77, 78, 61, 79, 25, 80, 81,
82, 83, 84, 80, 84, 85, 26, 47, 35, 5, 12, 68, 55, 42, 70, 38, 41,
38, 7, 7, 54, 86, 19, 43, 14, 69, 87, 22, 59, 79, 62, 86, 88, 56,
45, 77, 25, 89, 25, 57, 37, 29, 15, 17, 40, 88, 55, 5, 90, 33, 32,
64, 33, 42, 39, 41, 7, 87, 35, 19, 91, 23, 88, 92, 31, 43, 35, 61,
59, 93, 67, 25, 73, 88, 94, 95, 59, 24, 2, 70, 46, 96, 97, 44, 24,
48, 57, 62, 57, 57, 98, 60, 77, 99, 79, 100, 2, 101, 100, 2, 60, 79,
79, 85, 62, 62, 60, 60, 89, 89, 102, 57, 100, 61, 103, 100, 89, 103, 75,
61, 101, 93, 25, 104, 105, 105, 106, 78, 25, 60, 85, 85, 76, 81, 102};
const uint8_t pcc::kOccMapBit6CtxIdx[64 * 6] = { // transition tables L= 10; 256 ctx
1, 3, 4, 5, 4, 6, 7, 8, 9, 10, 11, 12, 13, 12, 14, 12, 15, const uint8_t pcc::kCtxMapOctreeOccupancyEvolutionOn0[256] = {
16, 7, 17, 18, 19, 20, 21, 8, 18, 22, 23, 24, 20, 20, 25, 26, 27, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 10, 11, 12, 13,
28, 29, 8, 29, 30, 31, 10, 28, 32, 33, 34, 24, 21, 35, 34, 36, 37, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28,
38, 39, 33, 40, 41, 39, 21, 33, 42, 43, 19, 44, 45, 23, 34, 6, 15, 29, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42,
7, 46, 47, 18, 48, 18, 10, 49, 50, 51, 14, 18, 52, 24, 53, 33, 54, 43, 44, 45, 46, 47, 48, 48, 49, 50, 51, 52, 53, 54, 55, 56,
55, 56, 25, 57, 24, 40, 25, 58, 59, 60, 61, 10, 62, 34, 63, 46, 46, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 66, 67, 68, 69, 70,
20, 64, 65, 49, 47, 66, 52, 8, 7, 63, 12, 67, 56, 31, 57, 68, 2, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 82, 83, 84,
60, 33, 69, 2, 70, 21, 71, 72, 73, 74, 11, 36, 8, 62, 75, 76, 39, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 96, 97, 98,
34, 47, 56, 77, 54, 21, 66, 63, 36, 29, 30, 78, 17, 21, 31, 58, 37, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 109, 110, 111, 112,
63, 19, 79, 38, 70, 71, 68, 47, 49, 44, 56, 37, 56, 72, 2, 39, 31, 113, 114, 115, 116, 117, 118, 119, 120, 120, 121, 122, 123, 124, 125, 126,