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
The input point cloud is decomposed using an octree with the configured
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
---------------
......
......@@ -57,7 +57,7 @@ struct PCCResidualsDecoder {
AdaptiveBitModel binaryModelIsOne[7];
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();
int decodePredMode(int max);
int decodeZeroCnt(int max);
......@@ -69,9 +69,11 @@ struct PCCResidualsDecoder {
//----------------------------------------------------------------------------
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.enableBypassStream(sps.cabac_bypass_stream_enabled_flag);
arithmeticDecoder.start();
}
......@@ -174,6 +176,7 @@ PCCResidualsDecoder::decode()
void
AttributeDecoder::decode(
const SequenceParameterSet& sps,
const AttributeDescription& attr_desc,
const AttributeParameterSet& attr_aps,
const PayloadBuffer& payload,
......@@ -185,7 +188,7 @@ AttributeDecoder::decode(
std::vector<Quantizers> quantLayers = deriveQuantizerLayers(attr_aps, abh);
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) {
switch (attr_aps.attr_encoding) {
......
......@@ -53,6 +53,7 @@ struct PCCResidualsDecoder;
class AttributeDecoder {
public:
void decode(
const SequenceParameterSet& sps,
const AttributeDescription& desc,
const AttributeParameterSet& aps,
const PayloadBuffer&,
......
......@@ -61,7 +61,7 @@ struct PCCResidualsEncoder {
AdaptiveBitModel binaryModelIsOne[7];
DualLutCoder<false> symbolCoder[2];
void start(int numPoints);
void start(const SequenceParameterSet& sps, int numPoints);
int stop();
void encodePredMode(int value, int max);
void encodeZeroCnt(int value, int max);
......@@ -73,11 +73,12 @@ struct PCCResidualsEncoder {
//----------------------------------------------------------------------------
void
PCCResidualsEncoder::start(int pointCount)
PCCResidualsEncoder::start(const SequenceParameterSet& sps, int pointCount)
{
// todo(df): remove estimate when arithmetic codec is replaced
int maxAcBufLen = pointCount * 3 * 2 + 1024;
arithmeticEncoder.setBuffer(maxAcBufLen, nullptr);
arithmeticEncoder.enableBypassStream(sps.cabac_bypass_stream_enabled_flag);
arithmeticEncoder.start();
}
......@@ -327,6 +328,7 @@ PCCResidualsEntropyEstimator::update(
void
AttributeEncoder::encode(
const SequenceParameterSet& sps,
const AttributeDescription& desc,
const AttributeParameterSet& attr_aps,
const AttributeBrickHeader& abh,
......@@ -336,7 +338,7 @@ AttributeEncoder::encode(
std::vector<Quantizers> quantLayers = deriveQuantizerLayers(attr_aps, abh);
PCCResidualsEncoder encoder;
encoder.start(int(pointCloud.getPointCount()));
encoder.start(sps, int(pointCloud.getPointCount()));
if (desc.attr_num_dimensions == 1) {
switch (attr_aps.attr_encoding) {
......
......@@ -55,6 +55,7 @@ struct PCCResidualsEntropyEstimator;
class AttributeEncoder {
public:
void encode(
const SequenceParameterSet& sps,
const AttributeDescription& desc,
const AttributeParameterSet& attr_aps,
const AttributeBrickHeader& abh,
......
......@@ -340,6 +340,10 @@ ParseParameters(int argc, char* argv[], Parameters& params)
params.encoder.partitionOctreeDepth, 2,
"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",
params.disableAttributeCoding, false,
"Ignore attribute coding configuration")
......
......@@ -187,6 +187,7 @@ PCCTMC3Decoder3::decodeGeometryBrick(const PayloadBuffer& buf)
_sliceOrigin = gbh.geomBoxOrigin;
EntropyDecoder arithmeticDecoder;
arithmeticDecoder.enableBypassStream(_sps->cabac_bypass_stream_enabled_flag);
arithmeticDecoder.setBuffer(int(buf.size()) - gbhSize, buf.data() + gbhSize);
arithmeticDecoder.start();
......@@ -238,7 +239,7 @@ PCCTMC3Decoder3::decodeAttributeBrick(const PayloadBuffer& buf)
pcc::chrono::Stopwatch<pcc::chrono::utime_inc_children_clock> clock_user;
clock_user.start();
attrDecoder.decode(attr_sps, attr_aps, buf, _currentPointCloud);
attrDecoder.decode(*_sps, attr_sps, attr_aps, buf, _currentPointCloud);
clock_user.stop();
std::cout << label << "s bitstream size " << buf.size() << " B\n";
......
......@@ -323,7 +323,7 @@ PCCTMC3Encoder3::compressPartition(
write(attr_aps, abh, &payload);
AttributeEncoder attrEncoder;
attrEncoder.encode(attr_sps, attr_aps, abh, pointCloud, &payload);
attrEncoder.encode(*_sps, attr_sps, attr_aps, abh, pointCloud, &payload);
clock_user.stop();
int coded_size = int(payload.size());
......@@ -372,6 +372,7 @@ PCCTMC3Encoder3::encodeGeometryBrick(PayloadBuffer* buf)
// todo(df): remove estimate when arithmetic codec is replaced
int maxAcBufLen = int(pointCloud.getPointCount()) * 3 * 4 + 1024;
EntropyEncoder arithmeticEncoder(maxAcBufLen, nullptr);
arithmeticEncoder.enableBypassStream(_sps->cabac_bypass_stream_enabled_flag);
arithmeticEncoder.start();
if (_gps->trisoup_node_size_log2 == 0) {
......
......@@ -105,6 +105,17 @@ namespace dirac {
allocatedBuffer.reset(new uint8_t[size]);
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 {
size_t stop()
{
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 {
//------------------------------------------------------------------------
void encode(int bit, SchroContextFixed& model)
void encode(int bit, SchroContextFixed&)
{
uint16_t probability = 0x8000; // p=0.5
schro_arith_encode_bit(&impl, &probability, bit);
if (!_cabac_bypass_stream_enabled_flag) {
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 {
::SchroArith impl;
::SchroBuffer buf;
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 {
{
buf.data = reinterpret_cast<uint8_t*>(const_cast<char*>(buffer));
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 {
//------------------------------------------------------------------------
int decode(SchroContextFixed& model)
int decode(SchroContextFixed&)
{
uint16_t probability = 0x8000; // p=0.5
return schro_arith_decode_bit(&impl, &probability);
if (!_cabac_bypass_stream_enabled_flag) {
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 {
private:
::SchroArith impl;
::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 {
public:
using Base::Base;
using Base::buffer;
using Base::enableBypassStream;
using Base::encode;
using Base::setBuffer;
using Base::start;
......@@ -105,6 +106,7 @@ public:
EntropyDecoderWrapper() : Base() {}
using Base::decode;
using Base::enableBypassStream;
using Base::setBuffer;
using Base::start;
using Base::stop;
......
......@@ -157,6 +157,10 @@ struct SequenceParameterSet {
// NB: attributeSets.size() = num_attribute_sets
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)
}
}
bs.write(sps.cabac_bypass_stream_enabled_flag);
bool sps_extension_flag = false;
bs.write(sps_extension_flag);
bs.byteAlign();
......@@ -169,6 +171,8 @@ parseSps(const PayloadBuffer& buf)
}
}
bs.read(&sps.cabac_bypass_stream_enabled_flag);
bool sps_extension_flag = bs.read();
if (sps_extension_flag) {
// 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