Commit 952112c4 authored by David Flynn's avatar David Flynn
Browse files

geom: refactor/isolate geometry brick coding

This commit splits the handling of the geometry brick header and octree
geometry coding.  The encoder/decoder classes now take care of coding
the header, while the geometry coder handles the geometry coding itself.
parent a9d066e6
...@@ -71,6 +71,7 @@ file(GLOB PROJECT_INC_FILES ...@@ -71,6 +71,7 @@ file(GLOB PROJECT_INC_FILES
"RAHT.h" "RAHT.h"
"TMC3.h" "TMC3.h"
"constants.h" "constants.h"
"geometry.h"
"geometry_octree.h" "geometry_octree.h"
"hls.h" "hls.h"
"io_hls.h" "io_hls.h"
......
...@@ -79,7 +79,6 @@ private: ...@@ -79,7 +79,6 @@ private:
int decodeGeometryBrick(const PayloadBuffer& buf); int decodeGeometryBrick(const PayloadBuffer& buf);
void decodeAttributeBrick(const PayloadBuffer& buf); void decodeAttributeBrick(const PayloadBuffer& buf);
int decodeTrisoup(const PayloadBuffer& buf, PCCPointSet3& pointCloud); int decodeTrisoup(const PayloadBuffer& buf, PCCPointSet3& pointCloud);
void decodePositions(const PayloadBuffer& buf, PCCPointSet3& pointCloud);
//========================================================================== //==========================================================================
......
...@@ -82,7 +82,7 @@ public: ...@@ -82,7 +82,7 @@ public:
private: private:
void reconstructedPointCloud(PCCPointSet3* reconstructedCloud); void reconstructedPointCloud(PCCPointSet3* reconstructedCloud);
void encodePositions(PayloadBuffer* buf); void encodeGeometryBrick(PayloadBuffer* buf);
int encodeTrisoup(bool hasColor, bool hasReflectance, PayloadBuffer* buf); int encodeTrisoup(bool hasColor, bool hasReflectance, PayloadBuffer* buf);
......
...@@ -41,6 +41,7 @@ ...@@ -41,6 +41,7 @@
#include "AttributeDecoder.h" #include "AttributeDecoder.h"
#include "PayloadBuffer.h" #include "PayloadBuffer.h"
#include "PCCPointSet.h" #include "PCCPointSet.h"
#include "geometry.h"
#include "io_hls.h" #include "io_hls.h"
#include "io_tlv.h" #include "io_tlv.h"
#include "pcc_chrono.h" #include "pcc_chrono.h"
...@@ -159,13 +160,27 @@ PCCTMC3Decoder3::decodeGeometryBrick(const PayloadBuffer& buf) ...@@ -159,13 +160,27 @@ PCCTMC3Decoder3::decodeGeometryBrick(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();
int gbhSize;
GeometryBrickHeader gbh = parseGbh(*_gps, buf, &gbhSize);
minPositions.x() = gbh.geomBoxOrigin.x();
minPositions.y() = gbh.geomBoxOrigin.y();
minPositions.z() = gbh.geomBoxOrigin.z();
o3dgc::Arithmetic_Codec arithmeticDecoder(
int(buf.size()) - gbhSize,
reinterpret_cast<uint8_t*>(const_cast<char*>(buf.data() + gbhSize)));
arithmeticDecoder.start_decoder();
if (_gps->geom_codec_type == GeometryCodecType::kOctree) { if (_gps->geom_codec_type == GeometryCodecType::kOctree) {
decodePositions(buf, _currentPointCloud); _currentPointCloud.resize(gbh.geom_num_points);
decodeGeometryOctree(*_gps, gbh, _currentPointCloud, &arithmeticDecoder);
} }
if (_gps->geom_codec_type == GeometryCodecType::kTriSoup) { if (_gps->geom_codec_type == GeometryCodecType::kTriSoup) {
if (decodeTrisoup(buf, _currentPointCloud)) if (decodeTrisoup(buf, _currentPointCloud))
return -1; return -1;
} }
arithmeticDecoder.stop_decoder();
clock_user.stop(); clock_user.stop();
auto total_user = auto total_user =
......
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
#include "AttributeEncoder.h" #include "AttributeEncoder.h"
#include "PCCPointSetProcessing.h" #include "PCCPointSetProcessing.h"
#include "geometry.h"
#include "io_hls.h" #include "io_hls.h"
#include "osspecific.h" #include "osspecific.h"
#include "pcc_chrono.h" #include "pcc_chrono.h"
...@@ -157,7 +158,7 @@ PCCTMC3Encoder3::compress( ...@@ -157,7 +158,7 @@ PCCTMC3Encoder3::compress(
clock_user.start(); clock_user.start();
if (_gps->geom_codec_type == GeometryCodecType::kOctree) { if (_gps->geom_codec_type == GeometryCodecType::kOctree) {
encodePositions(&payload); encodeGeometryBrick(&payload);
} }
if (_gps->geom_codec_type == GeometryCodecType::kTriSoup) { if (_gps->geom_codec_type == GeometryCodecType::kTriSoup) {
bool hasColor = inputPointCloud.hasColors(); bool hasColor = inputPointCloud.hasColors();
...@@ -245,6 +246,42 @@ PCCTMC3Encoder3::compress( ...@@ -245,6 +246,42 @@ PCCTMC3Encoder3::compress(
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void
PCCTMC3Encoder3::encodeGeometryBrick(PayloadBuffer* buf)
{
// todo(df): confirm minimum of 1 isn't needed
uint32_t maxBB =
std::max({1u, boundingBox.max[0], boundingBox.max[1], boundingBox.max[2]});
// the current node dimension (log2) encompasing maxBB
int nodeSizeLog2 = ceillog2(maxBB + 1);
GeometryBrickHeader gbh;
gbh.geom_geom_parameter_set_id = _gps->gps_geom_parameter_set_id;
gbh.geomBoxOrigin.x() = int(minPositions.x());
gbh.geomBoxOrigin.y() = int(minPositions.y());
gbh.geomBoxOrigin.z() = int(minPositions.z());
gbh.geom_box_log2_scale = 0;
gbh.geom_max_node_size_log2 = nodeSizeLog2;
gbh.geom_num_points = int(pointCloud.getPointCount());
write(*_gps, gbh, buf);
// todo(df): remove estimate when arithmetic codec is replaced
int maxAcBufLen = int(pointCloud.getPointCount()) * 3 * 4 + 1024;
o3dgc::Arithmetic_Codec arithmeticEncoder(maxAcBufLen, nullptr);
arithmeticEncoder.start_encoder();
if (_gps->geom_codec_type == GeometryCodecType::kOctree) {
encodeGeometryOctree(*_gps, gbh, pointCloud, &arithmeticEncoder);
}
// todo(df): move trisoup coding here
uint32_t dataLen = arithmeticEncoder.stop_encoder();
std::copy_n(arithmeticEncoder.buffer(), dataLen, std::back_inserter(*buf));
}
//----------------------------------------------------------------------------
void void
PCCTMC3Encoder3::reconstructedPointCloud(PCCPointSet3* reconstructedCloud) PCCTMC3Encoder3::reconstructedPointCloud(PCCPointSet3* reconstructedCloud)
{ {
......
/* 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.
*/
#pragma once
#include "ArithmeticCodec.h"
#include "PCCPointSet.h"
#include "hls.h"
namespace pcc {
//============================================================================
void encodeGeometryOctree(
const GeometryParameterSet& gps,
const GeometryBrickHeader& gbh,
PCCPointSet3& pointCloud,
o3dgc::Arithmetic_Codec* arithmeticEncoder);
void decodeGeometryOctree(
const GeometryParameterSet& gps,
const GeometryBrickHeader& gbh,
PCCPointSet3& pointCloud,
o3dgc::Arithmetic_Codec* arithmeticDecoder);
//============================================================================
} // namespace pcc
...@@ -33,12 +33,10 @@ ...@@ -33,12 +33,10 @@
* POSSIBILITY OF SUCH DAMAGE. * POSSIBILITY OF SUCH DAMAGE.
*/ */
#include "geometry_octree.h" #include "geometry.h"
// todo: break dependency
#include "PCCTMC3Decoder.h"
#include "OctreeNeighMap.h" #include "OctreeNeighMap.h"
#include "geometry_octree.h"
#include "io_hls.h" #include "io_hls.h"
#include "tables.h" #include "tables.h"
...@@ -252,29 +250,18 @@ GeometryOctreeDecoder::decodeDirectPosition( ...@@ -252,29 +250,18 @@ GeometryOctreeDecoder::decodeDirectPosition(
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
void void
PCCTMC3Decoder3::decodePositions( decodeGeometryOctree(
const PayloadBuffer& buf, PCCPointSet3& pointCloud) const GeometryParameterSet& gps,
const GeometryBrickHeader& gbh,
PCCPointSet3& pointCloud,
o3dgc::Arithmetic_Codec* arithmeticDecoder)
{ {
assert(buf.type == PayloadType::kGeometryBrick); GeometryOctreeDecoder decoder(arithmeticDecoder);
int gbhSize;
GeometryBrickHeader gbh = parseGbh(*_gps, buf, &gbhSize);
minPositions.x() = gbh.geomBoxOrigin.x();
minPositions.y() = gbh.geomBoxOrigin.y();
minPositions.z() = gbh.geomBoxOrigin.z();
pointCloud.resize(gbh.geom_num_points);
o3dgc::Arithmetic_Codec arithmeticDecoder(
int(buf.size()) - gbhSize,
reinterpret_cast<uint8_t*>(const_cast<char*>(buf.data() + gbhSize)));
arithmeticDecoder.start_decoder();
GeometryOctreeDecoder decoder(&arithmeticDecoder);
// init main fifo // init main fifo
// -- worst case size is the last level containing every input poit // -- worst case size is the last level containing every input poit
// and each point being isolated in the previous level. // and each point being isolated in the previous level.
pcc::ringbuf<PCCOctree3Node> fifo(pointCloud.getPointCount() + 1); pcc::ringbuf<PCCOctree3Node> fifo(gbh.geom_num_points + 1);
// the current node dimension (log2) // the current node dimension (log2)
int nodeSizeLog2 = gbh.geom_max_node_size_log2; int nodeSizeLog2 = gbh.geom_max_node_size_log2;
...@@ -283,7 +270,7 @@ PCCTMC3Decoder3::decodePositions( ...@@ -283,7 +270,7 @@ PCCTMC3Decoder3::decodePositions(
fifo.emplace_back(); fifo.emplace_back();
PCCOctree3Node& node00 = fifo.back(); PCCOctree3Node& node00 = fifo.back();
node00.start = uint32_t(0); node00.start = uint32_t(0);
node00.end = uint32_t(pointCloud.getPointCount()); node00.end = uint32_t(0);
node00.pos = uint32_t(0); node00.pos = uint32_t(0);
node00.neighPattern = 0; node00.neighPattern = 0;
node00.numSiblingsPlus1 = 8; node00.numSiblingsPlus1 = 8;
...@@ -300,8 +287,8 @@ PCCTMC3Decoder3::decodePositions( ...@@ -300,8 +287,8 @@ PCCTMC3Decoder3::decodePositions(
PCCVector3<uint32_t> occupancyAtlasOrigin(0xffffffff); PCCVector3<uint32_t> occupancyAtlasOrigin(0xffffffff);
MortonMap3D occupancyAtlas; MortonMap3D occupancyAtlas;
if (_gps->neighbour_avail_boundary_log2) { if (gps.neighbour_avail_boundary_log2) {
occupancyAtlas.resize(_gps->neighbour_avail_boundary_log2); occupancyAtlas.resize(gps.neighbour_avail_boundary_log2);
occupancyAtlas.clear(); occupancyAtlas.clear();
} }
...@@ -315,7 +302,7 @@ PCCTMC3Decoder3::decodePositions( ...@@ -315,7 +302,7 @@ PCCTMC3Decoder3::decodePositions(
} }
PCCOctree3Node& node0 = fifo.front(); PCCOctree3Node& node0 = fifo.front();
if (_gps->neighbour_avail_boundary_log2) { if (gps.neighbour_avail_boundary_log2) {
updateGeometryOccupancyAtlas( updateGeometryOccupancyAtlas(
node0.pos, nodeSizeLog2, fifo, fifoCurrLvlEnd, &occupancyAtlas, node0.pos, nodeSizeLog2, fifo, fifoCurrLvlEnd, &occupancyAtlas,
&occupancyAtlasOrigin); &occupancyAtlasOrigin);
...@@ -351,7 +338,7 @@ PCCTMC3Decoder3::decodePositions( ...@@ -351,7 +338,7 @@ PCCTMC3Decoder3::decodePositions(
if (childSizeLog2 == 0) { if (childSizeLog2 == 0) {
int numPoints = 1; int numPoints = 1;
if (!_gps->geom_unique_points_flag) { if (!gps.geom_unique_points_flag) {
numPoints = decoder.decodePositionLeafNumPoints(); numPoints = decoder.decodePositionLeafNumPoints();
} }
...@@ -377,7 +364,7 @@ PCCTMC3Decoder3::decodePositions( ...@@ -377,7 +364,7 @@ PCCTMC3Decoder3::decodePositions(
child.numSiblingsPlus1 = numOccupied; child.numSiblingsPlus1 = numOccupied;
child.siblingOccupancy = occupancy; child.siblingOccupancy = occupancy;
bool idcmEnabled = _gps->inferred_direct_coding_mode_enabled_flag; bool idcmEnabled = gps.inferred_direct_coding_mode_enabled_flag;
if (isDirectModeEligible(idcmEnabled, nodeSizeLog2, node0, child)) { if (isDirectModeEligible(idcmEnabled, nodeSizeLog2, node0, child)) {
int numPoints = decoder.decodeDirectPosition( int numPoints = decoder.decodeDirectPosition(
childSizeLog2, child, &pointCloud[processedPointCount]); childSizeLog2, child, &pointCloud[processedPointCount]);
...@@ -395,16 +382,13 @@ PCCTMC3Decoder3::decodePositions( ...@@ -395,16 +382,13 @@ PCCTMC3Decoder3::decodePositions(
numNodesNextLvl++; numNodesNextLvl++;
if (!_gps->neighbour_avail_boundary_log2) { if (!gps.neighbour_avail_boundary_log2) {
updateGeometryNeighState( updateGeometryNeighState(
_gps->neighbour_context_restriction_flag, fifo.end(), gps.neighbour_context_restriction_flag, fifo.end(), numNodesNextLvl,
numNodesNextLvl, childSizeLog2, child, i, node0.neighPattern, childSizeLog2, child, i, node0.neighPattern, occupancy);
occupancy);
} }
} }
} }
arithmeticDecoder.stop_decoder();
} }
//============================================================================ //============================================================================
......
...@@ -33,12 +33,10 @@ ...@@ -33,12 +33,10 @@
* POSSIBILITY OF SUCH DAMAGE. * POSSIBILITY OF SUCH DAMAGE.
*/ */
#include "geometry_octree.h" #include "geometry.h"
// todo: break dependency
#include "PCCTMC3Encoder.h"
#include "OctreeNeighMap.h" #include "OctreeNeighMap.h"
#include "geometry_octree.h"
#include "io_hls.h" #include "io_hls.h"
#include "tables.h" #include "tables.h"
...@@ -248,30 +246,13 @@ GeometryOctreeEncoder::encodeDirectPosition( ...@@ -248,30 +246,13 @@ GeometryOctreeEncoder::encodeDirectPosition(
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
void void
PCCTMC3Encoder3::encodePositions(PayloadBuffer* buf) encodeGeometryOctree(
const GeometryParameterSet& gps,
const GeometryBrickHeader& gbh,
PCCPointSet3& pointCloud,
o3dgc::Arithmetic_Codec* arithmeticEncoder)
{ {
uint32_t maxBB = GeometryOctreeEncoder encoder(arithmeticEncoder);
std::max({// todo(df): confirm minimum of 1 isn't needed
1u, boundingBox.max[0], boundingBox.max[1], boundingBox.max[2]});
// the current node dimension (log2) encompasing maxBB
int nodeSizeLog2 = ceillog2(maxBB + 1);
GeometryBrickHeader gbh;
gbh.geom_geom_parameter_set_id = _gps->gps_geom_parameter_set_id;
gbh.geomBoxOrigin.x() = int(minPositions.x());
gbh.geomBoxOrigin.y() = int(minPositions.y());
gbh.geomBoxOrigin.z() = int(minPositions.z());
gbh.geom_box_log2_scale = 0;
gbh.geom_max_node_size_log2 = nodeSizeLog2;
gbh.geom_num_points = int(pointCloud.getPointCount());
write(*_gps, gbh, buf);
// todo(df): remove estimate when arithmetic codec is replaced
int maxAcBufLen = int(pointCloud.getPointCount()) * 3 * 4 + 1024;
o3dgc::Arithmetic_Codec arithmeticEncoder(maxAcBufLen, nullptr);
arithmeticEncoder.start_encoder();
GeometryOctreeEncoder encoder(&arithmeticEncoder);
// init main fifo // init main fifo
// -- worst case size is the last level containing every input poit // -- worst case size is the last level containing every input poit
...@@ -298,13 +279,16 @@ PCCTMC3Encoder3::encodePositions(PayloadBuffer* buf) ...@@ -298,13 +279,16 @@ PCCTMC3Encoder3::encodePositions(PayloadBuffer* buf)
auto fifoCurrLvlEnd = fifo.end(); auto fifoCurrLvlEnd = fifo.end();
// the initial node size is the root node's
int nodeSizeLog2 = gbh.geom_max_node_size_log2;
// this counter represents fifo.end() - fifoCurrLvlEnd(). // this counter represents fifo.end() - fifoCurrLvlEnd().
// ie, the number of nodes added to the next level of the tree // ie, the number of nodes added to the next level of the tree
int numNodesNextLvl = 0; int numNodesNextLvl = 0;
MortonMap3D occupancyAtlas; MortonMap3D occupancyAtlas;
if (_gps->neighbour_avail_boundary_log2) { if (gps.neighbour_avail_boundary_log2) {
occupancyAtlas.resize(_gps->neighbour_avail_boundary_log2); occupancyAtlas.resize(gps.neighbour_avail_boundary_log2);
occupancyAtlas.clear(); occupancyAtlas.clear();
} }
PCCVector3<uint32_t> occupancyAtlasOrigin(0xffffffff); PCCVector3<uint32_t> occupancyAtlasOrigin(0xffffffff);
...@@ -346,7 +330,7 @@ PCCTMC3Encoder3::encodePositions(PayloadBuffer* buf) ...@@ -346,7 +330,7 @@ PCCTMC3Encoder3::encodePositions(PayloadBuffer* buf)
} }
} }
if (_gps->neighbour_avail_boundary_log2) { if (gps.neighbour_avail_boundary_log2) {
updateGeometryOccupancyAtlas( updateGeometryOccupancyAtlas(
node0.pos, nodeSizeLog2, fifo, fifoCurrLvlEnd, &occupancyAtlas, node0.pos, nodeSizeLog2, fifo, fifoCurrLvlEnd, &occupancyAtlas,
&occupancyAtlasOrigin); &occupancyAtlasOrigin);
...@@ -370,7 +354,7 @@ PCCTMC3Encoder3::encodePositions(PayloadBuffer* buf) ...@@ -370,7 +354,7 @@ PCCTMC3Encoder3::encodePositions(PayloadBuffer* buf)
// if the bitstream is configured to represent unique points, // if the bitstream is configured to represent unique points,
// no point count is sent. // no point count is sent.
if (_gps->geom_unique_points_flag) { if (gps.geom_unique_points_flag) {
assert(childCounts[i] == 1); assert(childCounts[i] == 1);
continue; continue;
} }
...@@ -412,7 +396,7 @@ PCCTMC3Encoder3::encodePositions(PayloadBuffer* buf) ...@@ -412,7 +396,7 @@ PCCTMC3Encoder3::encodePositions(PayloadBuffer* buf)
child.numSiblingsPlus1 = numSiblings; child.numSiblingsPlus1 = numSiblings;
child.siblingOccupancy = occupancy; child.siblingOccupancy = occupancy;
bool idcmEnabled = _gps->inferred_direct_coding_mode_enabled_flag; bool idcmEnabled = gps.inferred_direct_coding_mode_enabled_flag;
if (isDirectModeEligible(idcmEnabled, nodeSizeLog2, node0, child)) { if (isDirectModeEligible(idcmEnabled, nodeSizeLog2, node0, child)) {
bool directModeUsed = bool directModeUsed =
encoder.encodeDirectPosition(childSizeLog2, child, pointCloud); encoder.encodeDirectPosition(childSizeLog2, child, pointCloud);
...@@ -436,11 +420,10 @@ PCCTMC3Encoder3::encodePositions(PayloadBuffer* buf) ...@@ -436,11 +420,10 @@ PCCTMC3Encoder3::encodePositions(PayloadBuffer* buf)
// NB: when neighbourAvailBoundaryLog2 is set, an alternative // NB: when neighbourAvailBoundaryLog2 is set, an alternative
// implementation is used to calculate neighPattern. // implementation is used to calculate neighPattern.
if (!_gps->neighbour_avail_boundary_log2) { if (!gps.neighbour_avail_boundary_log2) {
updateGeometryNeighState( updateGeometryNeighState(
_gps->neighbour_context_restriction_flag, fifo.end(), gps.neighbour_context_restriction_flag, fifo.end(), numNodesNextLvl,
numNodesNextLvl, childSizeLog2, child, i, node0.neighPattern, childSizeLog2, child, i, node0.neighPattern, occupancy);
occupancy);
} }
} }
} }
...@@ -470,9 +453,6 @@ PCCTMC3Encoder3::encodePositions(PayloadBuffer* buf) ...@@ -470,9 +453,6 @@ PCCTMC3Encoder3::encodePositions(PayloadBuffer* buf)
} }
swap(pointCloud, pointCloud2); swap(pointCloud, pointCloud2);
uint32_t acDataLen = arithmeticEncoder.stop_encoder();
std::copy_n(arithmeticEncoder.buffer(), acDataLen, std::back_inserter(*buf));
} }
//============================================================================ //============================================================================
......
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