Commit e72b9af7 authored by David Flynn's avatar David Flynn Committed by David Flynn
Browse files

entropy/m47927: add ability to put bypass bins in separate reverse stream

Rather than code bypass bins using a simplified mode of the
arithmetic coder, this commit adds the ability to signal bypass bins
in a separate byte-reversed sub-stream.
parent 053cd4dd
...@@ -142,6 +142,15 @@ Sets the depth of the octree for slice generation using ...@@ -142,6 +142,15 @@ Sets the depth of the octree for slice generation using
The input point cloud is decomposed using an octree with the configured The input point cloud is decomposed using an octree with the configured
depth. Each occupied leaf of the octree represents a single slice. depth. Each occupied leaf of the octree represents a single slice.
### `--cabac_bypass_stream_enabled_flag=0|1`
Controls the entropy coding method used for equi-probable (bypass) bins:
| Value | Description |
|:-----:| --------------------------------------|
| 0 | bypass bins coded using CABAC |
| 1 | bypass bins coded in bypass substream |
Geometry coding Geometry coding
--------------- ---------------
......
...@@ -57,7 +57,7 @@ struct PCCResidualsDecoder { ...@@ -57,7 +57,7 @@ struct PCCResidualsDecoder {
AdaptiveBitModel binaryModelIsOne[7]; AdaptiveBitModel binaryModelIsOne[7];
DualLutCoder<false> symbolCoder[2]; DualLutCoder<false> symbolCoder[2];
void start(const char* buf, int buf_len); void start(const SequenceParameterSet& sps, const char* buf, int buf_len);
void stop(); void stop();
int decodePredMode(int max); int decodePredMode(int max);
int decodeZeroCnt(int max); int decodeZeroCnt(int max);
...@@ -69,9 +69,11 @@ struct PCCResidualsDecoder { ...@@ -69,9 +69,11 @@ struct PCCResidualsDecoder {
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void void
PCCResidualsDecoder::start(const char* buf, int buf_len) PCCResidualsDecoder::start(
const SequenceParameterSet& sps, const char* buf, int buf_len)
{ {
arithmeticDecoder.setBuffer(buf_len, buf); arithmeticDecoder.setBuffer(buf_len, buf);
arithmeticDecoder.enableBypassStream(sps.cabac_bypass_stream_enabled_flag);
arithmeticDecoder.start(); arithmeticDecoder.start();
} }
...@@ -174,6 +176,7 @@ PCCResidualsDecoder::decode() ...@@ -174,6 +176,7 @@ PCCResidualsDecoder::decode()
void void
AttributeDecoder::decode( AttributeDecoder::decode(
const SequenceParameterSet& sps,
const AttributeDescription& attr_desc, const AttributeDescription& attr_desc,
const AttributeParameterSet& attr_aps, const AttributeParameterSet& attr_aps,
const PayloadBuffer& payload, const PayloadBuffer& payload,
...@@ -185,7 +188,7 @@ AttributeDecoder::decode( ...@@ -185,7 +188,7 @@ AttributeDecoder::decode(
std::vector<Quantizers> quantLayers = deriveQuantizerLayers(attr_aps, abh); std::vector<Quantizers> quantLayers = deriveQuantizerLayers(attr_aps, abh);
PCCResidualsDecoder decoder; PCCResidualsDecoder decoder;
decoder.start(payload.data() + abhSize, payload.size() - abhSize); decoder.start(sps, payload.data() + abhSize, payload.size() - abhSize);
if (attr_desc.attr_num_dimensions == 1) { if (attr_desc.attr_num_dimensions == 1) {
switch (attr_aps.attr_encoding) { switch (attr_aps.attr_encoding) {
......
...@@ -53,6 +53,7 @@ struct PCCResidualsDecoder; ...@@ -53,6 +53,7 @@ struct PCCResidualsDecoder;
class AttributeDecoder { class AttributeDecoder {
public: public:
void decode( void decode(
const SequenceParameterSet& sps,
const AttributeDescription& desc, const AttributeDescription& desc,
const AttributeParameterSet& aps, const AttributeParameterSet& aps,
const PayloadBuffer&, const PayloadBuffer&,
......
...@@ -61,7 +61,7 @@ struct PCCResidualsEncoder { ...@@ -61,7 +61,7 @@ struct PCCResidualsEncoder {
AdaptiveBitModel binaryModelIsOne[7]; AdaptiveBitModel binaryModelIsOne[7];
DualLutCoder<false> symbolCoder[2]; DualLutCoder<false> symbolCoder[2];
void start(int numPoints); void start(const SequenceParameterSet& sps, int numPoints);
int stop(); int stop();
void encodePredMode(int value, int max); void encodePredMode(int value, int max);
void encodeZeroCnt(int value, int max); void encodeZeroCnt(int value, int max);
...@@ -73,11 +73,12 @@ struct PCCResidualsEncoder { ...@@ -73,11 +73,12 @@ struct PCCResidualsEncoder {
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void void
PCCResidualsEncoder::start(int pointCount) PCCResidualsEncoder::start(const SequenceParameterSet& sps, int pointCount)
{ {
// todo(df): remove estimate when arithmetic codec is replaced // todo(df): remove estimate when arithmetic codec is replaced
int maxAcBufLen = pointCount * 3 * 2 + 1024; int maxAcBufLen = pointCount * 3 * 2 + 1024;
arithmeticEncoder.setBuffer(maxAcBufLen, nullptr); arithmeticEncoder.setBuffer(maxAcBufLen, nullptr);
arithmeticEncoder.enableBypassStream(sps.cabac_bypass_stream_enabled_flag);
arithmeticEncoder.start(); arithmeticEncoder.start();
} }
...@@ -327,6 +328,7 @@ PCCResidualsEntropyEstimator::update( ...@@ -327,6 +328,7 @@ PCCResidualsEntropyEstimator::update(
void void
AttributeEncoder::encode( AttributeEncoder::encode(
const SequenceParameterSet& sps,
const AttributeDescription& desc, const AttributeDescription& desc,
const AttributeParameterSet& attr_aps, const AttributeParameterSet& attr_aps,
const AttributeBrickHeader& abh, const AttributeBrickHeader& abh,
...@@ -336,7 +338,7 @@ AttributeEncoder::encode( ...@@ -336,7 +338,7 @@ AttributeEncoder::encode(
std::vector<Quantizers> quantLayers = deriveQuantizerLayers(attr_aps, abh); std::vector<Quantizers> quantLayers = deriveQuantizerLayers(attr_aps, abh);
PCCResidualsEncoder encoder; PCCResidualsEncoder encoder;
encoder.start(int(pointCloud.getPointCount())); encoder.start(sps, int(pointCloud.getPointCount()));
if (desc.attr_num_dimensions == 1) { if (desc.attr_num_dimensions == 1) {
switch (attr_aps.attr_encoding) { switch (attr_aps.attr_encoding) {
......
...@@ -55,6 +55,7 @@ struct PCCResidualsEntropyEstimator; ...@@ -55,6 +55,7 @@ struct PCCResidualsEntropyEstimator;
class AttributeEncoder { class AttributeEncoder {
public: public:
void encode( void encode(
const SequenceParameterSet& sps,
const AttributeDescription& desc, const AttributeDescription& desc,
const AttributeParameterSet& attr_aps, const AttributeParameterSet& attr_aps,
const AttributeBrickHeader& abh, const AttributeBrickHeader& abh,
......
...@@ -340,6 +340,10 @@ ParseParameters(int argc, char* argv[], Parameters& params) ...@@ -340,6 +340,10 @@ ParseParameters(int argc, char* argv[], Parameters& params)
params.encoder.partitionOctreeDepth, 2, params.encoder.partitionOctreeDepth, 2,
"Depth of octree partition for partitionMethod=3") "Depth of octree partition for partitionMethod=3")
("cabac_bypass_stream_enabled_flag",
params.encoder.sps.cabac_bypass_stream_enabled_flag, false,
"Controls coding method for ep(bypass) bins")
("disableAttributeCoding", ("disableAttributeCoding",
params.disableAttributeCoding, false, params.disableAttributeCoding, false,
"Ignore attribute coding configuration") "Ignore attribute coding configuration")
......
...@@ -187,6 +187,7 @@ PCCTMC3Decoder3::decodeGeometryBrick(const PayloadBuffer& buf) ...@@ -187,6 +187,7 @@ PCCTMC3Decoder3::decodeGeometryBrick(const PayloadBuffer& buf)
_sliceOrigin = gbh.geomBoxOrigin; _sliceOrigin = gbh.geomBoxOrigin;
EntropyDecoder arithmeticDecoder; EntropyDecoder arithmeticDecoder;
arithmeticDecoder.enableBypassStream(_sps->cabac_bypass_stream_enabled_flag);
arithmeticDecoder.setBuffer(int(buf.size()) - gbhSize, buf.data() + gbhSize); arithmeticDecoder.setBuffer(int(buf.size()) - gbhSize, buf.data() + gbhSize);
arithmeticDecoder.start(); arithmeticDecoder.start();
...@@ -238,7 +239,7 @@ PCCTMC3Decoder3::decodeAttributeBrick(const PayloadBuffer& buf) ...@@ -238,7 +239,7 @@ PCCTMC3Decoder3::decodeAttributeBrick(const PayloadBuffer& buf)
pcc::chrono::Stopwatch<pcc::chrono::utime_inc_children_clock> clock_user; pcc::chrono::Stopwatch<pcc::chrono::utime_inc_children_clock> clock_user;
clock_user.start(); clock_user.start();
attrDecoder.decode(attr_sps, attr_aps, buf, _currentPointCloud); attrDecoder.decode(*_sps, attr_sps, attr_aps, buf, _currentPointCloud);
clock_user.stop(); clock_user.stop();
std::cout << label << "s bitstream size " << buf.size() << " B\n"; std::cout << label << "s bitstream size " << buf.size() << " B\n";
......
...@@ -323,7 +323,7 @@ PCCTMC3Encoder3::compressPartition( ...@@ -323,7 +323,7 @@ PCCTMC3Encoder3::compressPartition(
write(attr_aps, abh, &payload); write(attr_aps, abh, &payload);
AttributeEncoder attrEncoder; AttributeEncoder attrEncoder;
attrEncoder.encode(attr_sps, attr_aps, abh, pointCloud, &payload); attrEncoder.encode(*_sps, attr_sps, attr_aps, abh, pointCloud, &payload);
clock_user.stop(); clock_user.stop();
int coded_size = int(payload.size()); int coded_size = int(payload.size());
...@@ -372,6 +372,7 @@ PCCTMC3Encoder3::encodeGeometryBrick(PayloadBuffer* buf) ...@@ -372,6 +372,7 @@ PCCTMC3Encoder3::encodeGeometryBrick(PayloadBuffer* buf)
// todo(df): remove estimate when arithmetic codec is replaced // todo(df): remove estimate when arithmetic codec is replaced
int maxAcBufLen = int(pointCloud.getPointCount()) * 3 * 4 + 1024; int maxAcBufLen = int(pointCloud.getPointCount()) * 3 * 4 + 1024;
EntropyEncoder arithmeticEncoder(maxAcBufLen, nullptr); EntropyEncoder arithmeticEncoder(maxAcBufLen, nullptr);
arithmeticEncoder.enableBypassStream(_sps->cabac_bypass_stream_enabled_flag);
arithmeticEncoder.start(); arithmeticEncoder.start();
if (_gps->trisoup_node_size_log2 == 0) { if (_gps->trisoup_node_size_log2 == 0) {
......
...@@ -105,6 +105,17 @@ namespace dirac { ...@@ -105,6 +105,17 @@ namespace dirac {
allocatedBuffer.reset(new uint8_t[size]); allocatedBuffer.reset(new uint8_t[size]);
buf.data = allocatedBuffer.get(); buf.data = allocatedBuffer.get();
} }
// bypass data is written backwards, starting at the end of the buffer
bypassPtr = buf.data + size;
bypassCount = 8;
}
//------------------------------------------------------------------------
void enableBypassStream(bool cabac_bypass_stream_enabled_flag)
{
_cabac_bypass_stream_enabled_flag = cabac_bypass_stream_enabled_flag;
} }
//------------------------------------------------------------------------ //------------------------------------------------------------------------
...@@ -116,7 +127,17 @@ namespace dirac { ...@@ -116,7 +127,17 @@ namespace dirac {
size_t stop() size_t stop()
{ {
schro_arith_flush(&impl); schro_arith_flush(&impl);
return impl.offset; if (bypassCount != 8) {
bypassAccum <<= bypassCount;
*--bypassPtr = bypassAccum;
}
// make the bypass data contiguous with the arithmetic coded data
// since they share an initial buffer
auto end =
std::move(bypassPtr, buf.data + buf.length, buf.data + impl.offset);
return end - buf.data;
} }
//------------------------------------------------------------------------ //------------------------------------------------------------------------
...@@ -125,10 +146,22 @@ namespace dirac { ...@@ -125,10 +146,22 @@ namespace dirac {
//------------------------------------------------------------------------ //------------------------------------------------------------------------
void encode(int bit, SchroContextFixed& model) void encode(int bit, SchroContextFixed&)
{ {
uint16_t probability = 0x8000; // p=0.5 if (!_cabac_bypass_stream_enabled_flag) {
schro_arith_encode_bit(&impl, &probability, bit); uint16_t probability = 0x8000; // p=0.5
schro_arith_encode_bit(&impl, &probability, bit);
return;
}
bypassAccum <<= 1;
bypassAccum |= bit;
if (--bypassCount)
return;
bypassCount = 8;
*--bypassPtr = bypassAccum;
} }
//------------------------------------------------------------------------ //------------------------------------------------------------------------
...@@ -150,6 +183,22 @@ namespace dirac { ...@@ -150,6 +183,22 @@ namespace dirac {
::SchroArith impl; ::SchroArith impl;
::SchroBuffer buf; ::SchroBuffer buf;
std::unique_ptr<uint8_t[]> allocatedBuffer; std::unique_ptr<uint8_t[]> allocatedBuffer;
// Controls entropy coding method for bypass bins
bool _cabac_bypass_stream_enabled_flag = false;
// State related to bypass stream coding.
// The bypass stream is stored as a byte-reversed sequence starting at
// the end of buf and growing downwards.
// Pointer to the tail of the bypass stream
uint8_t* bypassPtr;
// Number of bins in the bypass accumulator
int bypassCount;
// Accumulator for bypass bins to construct
uint8_t bypassAccum;
}; };
//========================================================================== //==========================================================================
...@@ -160,6 +209,16 @@ namespace dirac { ...@@ -160,6 +209,16 @@ namespace dirac {
{ {
buf.data = reinterpret_cast<uint8_t*>(const_cast<char*>(buffer)); buf.data = reinterpret_cast<uint8_t*>(const_cast<char*>(buffer));
buf.length = int(size); buf.length = int(size);
bypassPtr = buf.data + buf.length - 1;
bypassCount = 0;
}
//------------------------------------------------------------------------
void enableBypassStream(bool cabac_bypass_stream_enabled_flag)
{
_cabac_bypass_stream_enabled_flag = cabac_bypass_stream_enabled_flag;
} }
//------------------------------------------------------------------------ //------------------------------------------------------------------------
...@@ -172,10 +231,20 @@ namespace dirac { ...@@ -172,10 +231,20 @@ namespace dirac {
//------------------------------------------------------------------------ //------------------------------------------------------------------------
int decode(SchroContextFixed& model) int decode(SchroContextFixed&)
{ {
uint16_t probability = 0x8000; // p=0.5 if (!_cabac_bypass_stream_enabled_flag) {
return schro_arith_decode_bit(&impl, &probability); uint16_t probability = 0x8000; // p=0.5
return schro_arith_decode_bit(&impl, &probability);
}
if (!bypassCount--) {
bypassAccum = *bypassPtr--;
bypassCount = 7;
}
int bit = !!(bypassAccum & 0x80);
bypassAccum <<= 1;
return bit;
} }
//------------------------------------------------------------------------ //------------------------------------------------------------------------
...@@ -202,6 +271,22 @@ namespace dirac { ...@@ -202,6 +271,22 @@ namespace dirac {
private: private:
::SchroArith impl; ::SchroArith impl;
::SchroBuffer buf; ::SchroBuffer buf;
// Controls entropy coding method for bypass bins
bool _cabac_bypass_stream_enabled_flag = false;
// State related to bypass stream coding.
// The bypass stream is stored as a byte-reversed sequence starting at
// the end of buf and growing downwards.
// Pointer to the tail of the bypass stream
uint8_t* bypassPtr;
// Number of bins in the bypass accumulator
int bypassCount;
// Accumulator for bypass bins to construct
uint8_t bypassAccum;
}; };
//========================================================================== //==========================================================================
......
...@@ -57,6 +57,7 @@ class EntropyEncoderWrapper : protected Base { ...@@ -57,6 +57,7 @@ class EntropyEncoderWrapper : protected Base {
public: public:
using Base::Base; using Base::Base;
using Base::buffer; using Base::buffer;
using Base::enableBypassStream;
using Base::encode; using Base::encode;
using Base::setBuffer; using Base::setBuffer;
using Base::start; using Base::start;
...@@ -105,6 +106,7 @@ public: ...@@ -105,6 +106,7 @@ public:
EntropyDecoderWrapper() : Base() {} EntropyDecoderWrapper() : Base() {}
using Base::decode; using Base::decode;
using Base::enableBypassStream;
using Base::setBuffer; using Base::setBuffer;
using Base::start; using Base::start;
using Base::stop; using Base::stop;
......
...@@ -157,6 +157,10 @@ struct SequenceParameterSet { ...@@ -157,6 +157,10 @@ struct SequenceParameterSet {
// NB: attributeSets.size() = num_attribute_sets // NB: attributeSets.size() = num_attribute_sets
std::vector<AttributeDescription> attributeSets; std::vector<AttributeDescription> attributeSets;
// Controls whether bypass bins are written to a seperate sub-stream, or
// encoded as ep bins via CABAC.
bool cabac_bypass_stream_enabled_flag;
}; };
//============================================================================ //============================================================================
......
...@@ -111,6 +111,8 @@ write(const SequenceParameterSet& sps) ...@@ -111,6 +111,8 @@ write(const SequenceParameterSet& sps)
} }
} }
bs.write(sps.cabac_bypass_stream_enabled_flag);
bool sps_extension_flag = false; bool sps_extension_flag = false;
bs.write(sps_extension_flag); bs.write(sps_extension_flag);
bs.byteAlign(); bs.byteAlign();
...@@ -169,6 +171,8 @@ parseSps(const PayloadBuffer& buf) ...@@ -169,6 +171,8 @@ parseSps(const PayloadBuffer& buf)
} }
} }
bs.read(&sps.cabac_bypass_stream_enabled_flag);
bool sps_extension_flag = bs.read(); bool sps_extension_flag = bs.read();
if (sps_extension_flag) { if (sps_extension_flag) {
// todo(df): sps_extension_data; // todo(df): sps_extension_data;
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment