Commit 81f2d561 authored by Noritaka Iguchi's avatar Noritaka Iguchi Committed by David Flynn
Browse files

attr/m47834: add support for per-layer luma/chroma qp offsets

This commit allow individual QP offsets to be specified for each
LoD/RAHT layer in attribute coding.
parent b6b98bf3
......@@ -181,7 +181,8 @@ AttributeDecoder::decode(
{
int abhSize;
AttributeBrickHeader abh = parseAbh(attr_aps, payload, &abhSize);
Quantizers quant = deriveQuantizers(attr_aps, abh);
std::vector<Quantizers> quantLayers = deriveQuantizerLayers(attr_aps, abh);
PCCResidualsDecoder decoder;
decoder.start(payload.data() + abhSize, payload.size() - abhSize);
......@@ -189,29 +190,32 @@ AttributeDecoder::decode(
if (attr_desc.attr_num_dimensions == 1) {
switch (attr_aps.attr_encoding) {
case AttributeEncoding::kRAHTransform:
decodeReflectancesRaht(attr_desc, attr_aps, quant, decoder, pointCloud);
decodeReflectancesRaht(
attr_desc, attr_aps, quantLayers, decoder, pointCloud);
break;
case AttributeEncoding::kPredictingTransform:
decodeReflectancesPred(attr_desc, attr_aps, quant, decoder, pointCloud);
decodeReflectancesPred(
attr_desc, attr_aps, quantLayers, decoder, pointCloud);
break;
case AttributeEncoding::kLiftingTransform:
decodeReflectancesLift(attr_desc, attr_aps, quant, decoder, pointCloud);
decodeReflectancesLift(
attr_desc, attr_aps, quantLayers, decoder, pointCloud);
break;
}
} else if (attr_desc.attr_num_dimensions == 3) {
switch (attr_aps.attr_encoding) {
case AttributeEncoding::kRAHTransform:
decodeColorsRaht(attr_desc, attr_aps, quant, decoder, pointCloud);
decodeColorsRaht(attr_desc, attr_aps, quantLayers, decoder, pointCloud);
break;
case AttributeEncoding::kPredictingTransform:
decodeColorsPred(attr_desc, attr_aps, quant, decoder, pointCloud);
decodeColorsPred(attr_desc, attr_aps, quantLayers, decoder, pointCloud);
break;
case AttributeEncoding::kLiftingTransform:
decodeColorsLift(attr_desc, attr_aps, quant, decoder, pointCloud);
decodeColorsLift(attr_desc, attr_aps, quantLayers, decoder, pointCloud);
break;
}
} else {
......@@ -263,7 +267,7 @@ void
AttributeDecoder::decodeReflectancesPred(
const AttributeDescription& desc,
const AttributeParameterSet& aps,
const Quantizers& quant,
const std::vector<Quantizers>& quantLayers,
PCCResidualsDecoder& decoder,
PCCPointSet3& pointCloud)
{
......@@ -280,9 +284,15 @@ AttributeDecoder::decodeReflectancesPred(
const int64_t maxReflectance = (1ll << desc.attr_bitdepth) - 1;
int zero_cnt = decoder.decodeZeroCnt(pointCount);
int quantLayer = 0;
for (size_t predictorIndex = 0; predictorIndex < pointCount;
++predictorIndex) {
if (predictorIndex == numberOfPointsPerLOD[quantLayer]) {
quantLayer = std::min(int(quantLayers.size()) - 1, quantLayer + 1);
}
auto& quant = quantLayers[quantLayer];
auto& predictor = predictors[predictorIndex];
computeReflectancePredictionWeights(
aps, pointCloud, indexesLOD, predictor, decoder);
const uint32_t pointIndex = indexesLOD[predictorIndex];
......@@ -348,7 +358,7 @@ void
AttributeDecoder::decodeColorsPred(
const AttributeDescription& desc,
const AttributeParameterSet& aps,
const Quantizers& quant,
const std::vector<Quantizers>& quantLayers,
PCCResidualsDecoder& decoder,
PCCPointSet3& pointCloud)
{
......@@ -365,9 +375,15 @@ AttributeDecoder::decodeColorsPred(
uint32_t values[3];
int zero_cnt = decoder.decodeZeroCnt(pointCount);
int quantLayer = 0;
for (size_t predictorIndex = 0; predictorIndex < pointCount;
++predictorIndex) {
if (predictorIndex == numberOfPointsPerLOD[quantLayer]) {
quantLayer = std::min(int(quantLayers.size()) - 1, quantLayer + 1);
}
auto& quant = quantLayers[quantLayer];
auto& predictor = predictors[predictorIndex];
computeColorPredictionWeights(
aps, pointCloud, indexesLOD, predictor, decoder);
if (zero_cnt > 0) {
......@@ -405,7 +421,7 @@ void
AttributeDecoder::decodeReflectancesRaht(
const AttributeDescription& desc,
const AttributeParameterSet& aps,
const Quantizers& quant,
const std::vector<Quantizers>& quantLayers,
PCCResidualsDecoder& decoder,
PCCPointSet3& pointCloud)
{
......@@ -441,7 +457,7 @@ AttributeDecoder::decodeReflectancesRaht(
int* attributes = new int[attribCount * voxelCount];
regionAdaptiveHierarchicalInverseTransform(
aps.raht_prediction_enabled_flag, quant, mortonCode, attributes,
aps.raht_prediction_enabled_flag, quantLayers, mortonCode, attributes,
attribCount, voxelCount, coefficients);
const int64_t maxReflectance = (1 << desc.attr_bitdepth) - 1;
......@@ -465,7 +481,7 @@ void
AttributeDecoder::decodeColorsRaht(
const AttributeDescription& desc,
const AttributeParameterSet& aps,
const Quantizers& quant,
const std::vector<Quantizers>& quantLayers,
PCCResidualsDecoder& decoder,
PCCPointSet3& pointCloud)
{
......@@ -505,7 +521,7 @@ AttributeDecoder::decodeColorsRaht(
int* attributes = new int[attribCount * voxelCount];
regionAdaptiveHierarchicalInverseTransform(
aps.raht_prediction_enabled_flag, quant, mortonCode, attributes,
aps.raht_prediction_enabled_flag, quantLayers, mortonCode, attributes,
attribCount, voxelCount, coefficients);
const int clipMax = (1 << desc.attr_bitdepth) - 1;
......@@ -532,7 +548,7 @@ void
AttributeDecoder::decodeColorsLift(
const AttributeDescription& desc,
const AttributeParameterSet& aps,
const Quantizers& quant,
const std::vector<Quantizers>& quantLayers,
PCCResidualsDecoder& decoder,
PCCPointSet3& pointCloud)
{
......@@ -556,10 +572,17 @@ AttributeDecoder::decodeColorsLift(
const size_t lodCount = numberOfPointsPerLOD.size();
std::vector<Vec3<int64_t>> colors;
colors.resize(pointCount);
// decompress
int zero_cnt = decoder.decodeZeroCnt(pointCount);
int quantLayer = 0;
for (size_t predictorIndex = 0; predictorIndex < pointCount;
++predictorIndex) {
if (predictorIndex == numberOfPointsPerLOD[quantLayer]) {
quantLayer = std::min(int(quantLayers.size()) - 1, quantLayer + 1);
}
auto& quant = quantLayers[quantLayer];
uint32_t values[3];
if (zero_cnt > 0) {
values[0] = values[1] = values[2] = 0;
......@@ -607,7 +630,7 @@ void
AttributeDecoder::decodeReflectancesLift(
const AttributeDescription& desc,
const AttributeParameterSet& aps,
const Quantizers& quant,
const std::vector<Quantizers>& quantLayers,
PCCResidualsDecoder& decoder,
PCCPointSet3& pointCloud)
{
......@@ -635,8 +658,14 @@ AttributeDecoder::decodeReflectancesLift(
// decompress
int zero_cnt = decoder.decodeZeroCnt(pointCount);
int quantLayer = 0;
for (size_t predictorIndex = 0; predictorIndex < pointCount;
++predictorIndex) {
if (predictorIndex == numberOfPointsPerLOD[quantLayer]) {
quantLayer = std::min(int(quantLayers.size()) - 1, quantLayer + 1);
}
auto& quant = quantLayers[quantLayer];
int64_t detail = 0;
if (zero_cnt > 0) {
zero_cnt--;
......
......@@ -64,42 +64,42 @@ protected:
void decodeReflectancesLift(
const AttributeDescription& desc,
const AttributeParameterSet& aps,
const Quantizers& quant,
const std::vector<Quantizers>& quantLayers,
PCCResidualsDecoder& decoder,
PCCPointSet3& pointCloud);
void decodeColorsLift(
const AttributeDescription& desc,
const AttributeParameterSet& aps,
const Quantizers& quant,
const std::vector<Quantizers>& quantLayers,
PCCResidualsDecoder& decoder,
PCCPointSet3& pointCloud);
void decodeReflectancesPred(
const AttributeDescription& desc,
const AttributeParameterSet& aps,
const Quantizers& quant,
const std::vector<Quantizers>& quantLayers,
PCCResidualsDecoder& decoder,
PCCPointSet3& pointCloud);
void decodeColorsPred(
const AttributeDescription& desc,
const AttributeParameterSet& aps,
const Quantizers& quant,
const std::vector<Quantizers>& quantLayers,
PCCResidualsDecoder& decoder,
PCCPointSet3& pointCloud);
void decodeReflectancesRaht(
const AttributeDescription& desc,
const AttributeParameterSet& aps,
const Quantizers& quant,
const std::vector<Quantizers>& quantLayers,
PCCResidualsDecoder& decoder,
PCCPointSet3& pointCloud);
void decodeColorsRaht(
const AttributeDescription& desc,
const AttributeParameterSet& aps,
const Quantizers& quant,
const std::vector<Quantizers>& quantLayers,
PCCResidualsDecoder& decoder,
PCCPointSet3& pointCloud);
......
......@@ -333,7 +333,7 @@ AttributeEncoder::encode(
PCCPointSet3& pointCloud,
PayloadBuffer* payload)
{
Quantizers quant = deriveQuantizers(attr_aps, abh);
std::vector<Quantizers> quantLayers = deriveQuantizerLayers(attr_aps, abh);
PCCResidualsEncoder encoder;
encoder.start(int(pointCloud.getPointCount()));
......@@ -342,29 +342,30 @@ AttributeEncoder::encode(
switch (attr_aps.attr_encoding) {
case AttributeEncoding::kRAHTransform:
encodeReflectancesTransformRaht(
desc, attr_aps, quant, pointCloud, encoder);
desc, attr_aps, quantLayers, pointCloud, encoder);
break;
case AttributeEncoding::kPredictingTransform:
encodeReflectancesPred(desc, attr_aps, quant, pointCloud, encoder);
encodeReflectancesPred(desc, attr_aps, quantLayers, pointCloud, encoder);
break;
case AttributeEncoding::kLiftingTransform:
encodeReflectancesLift(desc, attr_aps, quant, pointCloud, encoder);
encodeReflectancesLift(desc, attr_aps, quantLayers, pointCloud, encoder);
break;
}
} else if (desc.attr_num_dimensions == 3) {
switch (attr_aps.attr_encoding) {
case AttributeEncoding::kRAHTransform:
encodeColorsTransformRaht(desc, attr_aps, quant, pointCloud, encoder);
encodeColorsTransformRaht(
desc, attr_aps, quantLayers, pointCloud, encoder);
break;
case AttributeEncoding::kPredictingTransform:
encodeColorsPred(desc, attr_aps, quant, pointCloud, encoder);
encodeColorsPred(desc, attr_aps, quantLayers, pointCloud, encoder);
break;
case AttributeEncoding::kLiftingTransform:
encodeColorsLift(desc, attr_aps, quant, pointCloud, encoder);
encodeColorsLift(desc, attr_aps, quantLayers, pointCloud, encoder);
break;
}
} else {
......@@ -467,7 +468,7 @@ void
AttributeEncoder::encodeReflectancesPred(
const AttributeDescription& desc,
const AttributeParameterSet& aps,
const Quantizers& quant,
const std::vector<Quantizers>& quantLayers,
PCCPointSet3& pointCloud,
PCCResidualsEncoder& encoder)
{
......@@ -490,9 +491,15 @@ AttributeEncoder::encodeReflectancesPred(
std::vector<uint32_t> residual;
residual.resize(pointCount);
int quantLayer = 0;
for (size_t predictorIndex = 0; predictorIndex < pointCount;
++predictorIndex) {
if (predictorIndex == numberOfPointsPerLOD[quantLayer]) {
quantLayer = std::min(int(quantLayers.size()) - 1, quantLayer + 1);
}
auto& quant = quantLayers[quantLayer];
auto& predictor = predictors[predictorIndex];
computeReflectancePredictionWeights(
aps, pointCloud, indexesLOD, predictorIndex, predictor, encoder, context,
quant[0]);
......@@ -651,7 +658,7 @@ void
AttributeEncoder::encodeColorsPred(
const AttributeDescription& desc,
const AttributeParameterSet& aps,
const Quantizers& quant,
const std::vector<Quantizers>& quantLayers,
PCCPointSet3& pointCloud,
PCCResidualsEncoder& encoder)
{
......@@ -669,7 +676,6 @@ AttributeEncoder::encodeColorsPred(
const int64_t clipMax = (1ll << desc.attr_bitdepth) - 1;
uint32_t values[3];
PCCResidualsEntropyEstimator context;
int zero_cnt = 0;
std::vector<int> zerorun;
std::vector<uint32_t> residual[3];
......@@ -677,9 +683,15 @@ AttributeEncoder::encodeColorsPred(
residual[i].resize(pointCount);
}
int quantLayer = 0;
for (size_t predictorIndex = 0; predictorIndex < pointCount;
++predictorIndex) {
if (predictorIndex == numberOfPointsPerLOD[quantLayer]) {
quantLayer = std::min(int(quantLayers.size()) - 1, quantLayer + 1);
}
auto& quant = quantLayers[quantLayer];
auto& predictor = predictors[predictorIndex];
computeColorPredictionWeights(
aps, pointCloud, indexesLOD, predictorIndex, predictor, encoder, context,
quant);
......@@ -757,7 +769,7 @@ void
AttributeEncoder::encodeReflectancesTransformRaht(
const AttributeDescription& desc,
const AttributeParameterSet& aps,
const Quantizers& quant,
const std::vector<Quantizers>& quantLayers,
PCCPointSet3& pointCloud,
PCCResidualsEncoder& encoder)
{
......@@ -784,7 +796,7 @@ AttributeEncoder::encodeReflectancesTransformRaht(
// Transform.
regionAdaptiveHierarchicalTransform(
aps.raht_prediction_enabled_flag, quant, mortonCode, attributes,
aps.raht_prediction_enabled_flag, quantLayers, mortonCode, attributes,
attribCount, voxelCount, coefficients);
// Entropy encode.
......@@ -825,7 +837,7 @@ void
AttributeEncoder::encodeColorsTransformRaht(
const AttributeDescription& desc,
const AttributeParameterSet& aps,
const Quantizers& quant,
const std::vector<Quantizers>& quantLayers,
PCCPointSet3& pointCloud,
PCCResidualsEncoder& encoder)
{
......@@ -854,7 +866,7 @@ AttributeEncoder::encodeColorsTransformRaht(
// Transform.
regionAdaptiveHierarchicalTransform(
aps.raht_prediction_enabled_flag, quant, mortonCode, attributes,
aps.raht_prediction_enabled_flag, quantLayers, mortonCode, attributes,
attribCount, voxelCount, coefficients);
// Entropy encode.
......@@ -899,7 +911,7 @@ void
AttributeEncoder::encodeColorsLift(
const AttributeDescription& desc,
const AttributeParameterSet& aps,
const Quantizers& quant,
const std::vector<Quantizers>& quantLayers,
PCCPointSet3& pointCloud,
PCCResidualsEncoder& encoder)
{
......@@ -941,8 +953,14 @@ AttributeEncoder::encodeColorsLift(
// compress
int zero_cnt = 0;
int quantLayer = 0;
for (size_t predictorIndex = 0; predictorIndex < pointCount;
++predictorIndex) {
if (predictorIndex == numberOfPointsPerLOD[quantLayer]) {
quantLayer = std::min(int(quantLayers.size()) - 1, quantLayer + 1);
}
auto& quant = quantLayers[quantLayer];
const int64_t quantWeight = weights[predictorIndex];
auto& color = colors[predictorIndex];
const int64_t delta = quant[0].quantize(color[0] * quantWeight);
......@@ -996,7 +1014,7 @@ void
AttributeEncoder::encodeReflectancesLift(
const AttributeDescription& desc,
const AttributeParameterSet& aps,
const Quantizers& quant,
const std::vector<Quantizers>& quantLayers,
PCCPointSet3& pointCloud,
PCCResidualsEncoder& encoder)
{
......@@ -1038,8 +1056,14 @@ AttributeEncoder::encodeReflectancesLift(
// compress
int zero_cnt = 0;
int quantLayer = 0;
for (size_t predictorIndex = 0; predictorIndex < pointCount;
++predictorIndex) {
if (predictorIndex == numberOfPointsPerLOD[quantLayer]) {
quantLayer = std::min(int(quantLayers.size()) - 1, quantLayer + 1);
}
auto& quant = quantLayers[quantLayer];
const int64_t quantWeight = weights[predictorIndex];
auto& reflectance = reflectances[predictorIndex];
const int64_t delta = quant[0].quantize(reflectance * quantWeight);
......
......@@ -67,42 +67,42 @@ protected:
void encodeReflectancesLift(
const AttributeDescription& desc,
const AttributeParameterSet& aps,
const Quantizers& quant,
const std::vector<Quantizers>& quantLayers,
PCCPointSet3& pointCloud,
PCCResidualsEncoder& encoder);
void encodeColorsLift(
const AttributeDescription& desc,
const AttributeParameterSet& aps,
const Quantizers& quant,
const std::vector<Quantizers>& quantLayers,
PCCPointSet3& pointCloud,
PCCResidualsEncoder& encoder);
void encodeReflectancesPred(
const AttributeDescription& desc,
const AttributeParameterSet& aps,
const Quantizers& quant,
const std::vector<Quantizers>& quantLayers,
PCCPointSet3& pointCloud,
PCCResidualsEncoder& encoder);
void encodeColorsPred(
const AttributeDescription& desc,
const AttributeParameterSet& aps,
const Quantizers& quant,
const std::vector<Quantizers>& quantLayers,
PCCPointSet3& pointCloud,
PCCResidualsEncoder& encoder);
void encodeReflectancesTransformRaht(
const AttributeDescription& desc,
const AttributeParameterSet& aps,
const Quantizers& quant,
const std::vector<Quantizers>& quantLayers,
PCCPointSet3& pointCloud,
PCCResidualsEncoder& encoder);
void encodeColorsTransformRaht(
const AttributeDescription& desc,
const AttributeParameterSet& aps,
const Quantizers& quant,
const std::vector<Quantizers>& quantLayers,
PCCPointSet3& pointCloud,
PCCResidualsEncoder& encoder);
......
......@@ -64,7 +64,10 @@ enum class PartitionMethod
//============================================================================
struct EncoderAttributeParams {};
struct EncoderAttributeParams {
// NB: this only makes sense for setting configurable parameters
AttributeBrickHeader abh;
};
//----------------------------------------------------------------------------
......
......@@ -514,7 +514,7 @@ template<bool isEncoder>
void
uraht_process(
bool raht_prediction_enabled_flag,
const Quantizers& quant,
const std::vector<Quantizers>& quantLayers,
int numPoints,
int numAttrs,
int64_t* positions,
......@@ -577,6 +577,9 @@ uraht_process(
std::vector<UrahtNode> weightsParent;
weightsParent.reserve(numPoints);
// quant layer selection
auto quantLayerIt = quantLayers.begin();
// descend tree
weightsLf.resize(1);
attrsLf.resize(numAttrs);
......@@ -603,6 +606,11 @@ uraht_process(
bool enablePrediction = inheritDc && raht_prediction_enabled_flag;
isFirst = 0;
// select quantiser according to transform layer
const auto& quant = *quantLayerIt;
if (std::next(quantLayerIt) != quantLayers.end())
quantLayerIt++;
// prepare reconstruction buffers
// previous reconstruction -> attrRecParent
std::swap(attrRec, attrRecParent);
......@@ -774,6 +782,8 @@ uraht_process(
std::swap(attrRec, attrRecParent);
auto attrRecParentIt = attrRecParent.cbegin();
auto attrsHfIt = attrsHf.cbegin();
const auto& quant = quantLayers.back();
for (int i = 0, out = 0, iEnd = weightsLf.size(); i < iEnd; i++) {
int weight = weightsLf[i].weight;
// unique points have weight = 1
......@@ -874,7 +884,7 @@ uraht_process(
void
regionAdaptiveHierarchicalTransform(
bool raht_prediction_enabled_flag,
const Quantizers& quant,
const std::vector<Quantizers>& quantLayers,
int64_t* mortonCode,
int* attributes,
const int attribCount,
......@@ -882,8 +892,8 @@ regionAdaptiveHierarchicalTransform(
int* coefficients)
{
uraht_process<true>(
raht_prediction_enabled_flag, quant, voxelCount, attribCount, mortonCode,
attributes, coefficients);
raht_prediction_enabled_flag, quantLayers, voxelCount, attribCount,
mortonCode, attributes, coefficients);
}
//============================================================================
......@@ -906,7 +916,7 @@ regionAdaptiveHierarchicalTransform(
void
regionAdaptiveHierarchicalInverseTransform(
bool raht_prediction_enabled_flag,
const Quantizers& quant,
const std::vector<Quantizers>& quantLayers,
int64_t* mortonCode,
int* attributes,
const int attribCount,
......@@ -914,8 +924,8 @@ regionAdaptiveHierarchicalInverseTransform(
int* coefficients)
{
uraht_process<false>(
raht_prediction_enabled_flag, quant, voxelCount, attribCount, mortonCode,
attributes, coefficients);
raht_prediction_enabled_flag, quantLayers, voxelCount, attribCount,
mortonCode, attributes, coefficients);
}
//============================================================================
......
......@@ -34,17 +34,19 @@
*/
#pragma once
#include <cstdint>
#include "FixedPoint.h"
#include "quantization.h"
#include "quantization.h"
#include <vector>
namespace pcc {
void regionAdaptiveHierarchicalTransform(
bool raht_prediction_enabled_flag,
const Quantizers& quant,
const std::vector<Quantizers>& quantLayers,
int64_t* mortonCode,
int* attributes,
const int attribCount,
......@@ -53,7 +55,7 @@ void regionAdaptiveHierarchicalTransform(
void regionAdaptiveHierarchicalInverseTransform(
bool raht_prediction_enabled_flag,
const Quantizers& quant,
const std::vector<Quantizers>& quantLayers,
int64_t* mortonCode,
int* attributes,
const int attribCount,
......
......@@ -462,6 +462,14 @@ ParseParameters(int argc, char* argv[], Parameters& params)
params_attr.aps.aps_slice_qp_deltas_present_flag, false,
"Enable signalling of per-slice QP values")
("qpLayerOffsetsLuma",
params_attr.encoder.abh.attr_layer_qp_delta_luma, {},
"Attribute's per layer luma QP offsets")
("qpLayerOffsetsChroma",
params_attr.encoder.abh.attr_layer_qp_delta_chroma, {},
"Attribute's per layer chroma QP offsets")
// This section is just dedicated to attribute recolouring (encoder only).
// parameters are common to all attributes.
(po::Section("Recolouring"))
......@@ -559,10 +567,12 @@ ParseParameters(int argc, char* argv[], Parameters& params)
for (const auto& it : params.encoder.attributeIdxMap) {
auto& attr_sps = params.encoder.sps.attributeSets[it.second];
auto& attr_aps = params.encoder.aps[it.second];
auto& attr_enc = params.encoder.attr[it.second];
// Avoid wasting bits signalling chroma quant step size for reflectance
if (it.first == "reflectance") {
attr_aps.aps_chroma_qp_offset = 0;
attr_enc.abh.attr_layer_qp_delta_chroma.clear();
}
bool isLifting =
......@@ -626,6 +636,16 @@ ParseParameters(int argc, char* argv[], Parameters& params)
for (const auto& it : params.encoder.attributeIdxMap) {
const auto& attr_sps = params.encoder.sps.attributeSets[it.second];
const auto& attr_aps = params.encoder.aps[it.second];