diff options
Diffstat (limited to 'extern/draco/draco/src/draco/compression/point_cloud/point_cloud_decoder.cc')
-rw-r--r-- | extern/draco/draco/src/draco/compression/point_cloud/point_cloud_decoder.cc | 189 |
1 files changed, 189 insertions, 0 deletions
diff --git a/extern/draco/draco/src/draco/compression/point_cloud/point_cloud_decoder.cc b/extern/draco/draco/src/draco/compression/point_cloud/point_cloud_decoder.cc new file mode 100644 index 00000000000..5196edf960c --- /dev/null +++ b/extern/draco/draco/src/draco/compression/point_cloud/point_cloud_decoder.cc @@ -0,0 +1,189 @@ +// Copyright 2016 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#include "draco/compression/point_cloud/point_cloud_decoder.h" + +#include "draco/metadata/metadata_decoder.h" + +namespace draco { + +PointCloudDecoder::PointCloudDecoder() + : point_cloud_(nullptr), + buffer_(nullptr), + version_major_(0), + version_minor_(0), + options_(nullptr) {} + +Status PointCloudDecoder::DecodeHeader(DecoderBuffer *buffer, + DracoHeader *out_header) { + constexpr char kIoErrorMsg[] = "Failed to parse Draco header."; + if (!buffer->Decode(out_header->draco_string, 5)) { + return Status(Status::IO_ERROR, kIoErrorMsg); + } + if (memcmp(out_header->draco_string, "DRACO", 5) != 0) { + return Status(Status::DRACO_ERROR, "Not a Draco file."); + } + if (!buffer->Decode(&(out_header->version_major))) { + return Status(Status::IO_ERROR, kIoErrorMsg); + } + if (!buffer->Decode(&(out_header->version_minor))) { + return Status(Status::IO_ERROR, kIoErrorMsg); + } + if (!buffer->Decode(&(out_header->encoder_type))) { + return Status(Status::IO_ERROR, kIoErrorMsg); + } + if (!buffer->Decode(&(out_header->encoder_method))) { + return Status(Status::IO_ERROR, kIoErrorMsg); + } + if (!buffer->Decode(&(out_header->flags))) { + return Status(Status::IO_ERROR, kIoErrorMsg); + } + return OkStatus(); +} + +Status PointCloudDecoder::DecodeMetadata() { + std::unique_ptr<GeometryMetadata> metadata = + std::unique_ptr<GeometryMetadata>(new GeometryMetadata()); + MetadataDecoder metadata_decoder; + if (!metadata_decoder.DecodeGeometryMetadata(buffer_, metadata.get())) { + return Status(Status::DRACO_ERROR, "Failed to decode metadata."); + } + point_cloud_->AddMetadata(std::move(metadata)); + return OkStatus(); +} + +Status PointCloudDecoder::Decode(const DecoderOptions &options, + DecoderBuffer *in_buffer, + PointCloud *out_point_cloud) { + options_ = &options; + buffer_ = in_buffer; + point_cloud_ = out_point_cloud; + DracoHeader header; + DRACO_RETURN_IF_ERROR(DecodeHeader(buffer_, &header)) + // Sanity check that we are really using the right decoder (mostly for cases + // where the Decode method was called manually outside of our main API. + if (header.encoder_type != GetGeometryType()) { + return Status(Status::DRACO_ERROR, + "Using incompatible decoder for the input geometry."); + } + // TODO(ostava): We should check the method as well, but currently decoders + // don't expose the decoding method id. + version_major_ = header.version_major; + version_minor_ = header.version_minor; + + const uint8_t max_supported_major_version = + header.encoder_type == POINT_CLOUD ? kDracoPointCloudBitstreamVersionMajor + : kDracoMeshBitstreamVersionMajor; + const uint8_t max_supported_minor_version = + header.encoder_type == POINT_CLOUD ? kDracoPointCloudBitstreamVersionMinor + : kDracoMeshBitstreamVersionMinor; + // Check for version compatibility. + if (version_major_ < 1 || version_major_ > max_supported_major_version) { + return Status(Status::UNKNOWN_VERSION, "Unknown major version."); + } + if (version_major_ == max_supported_major_version && + version_minor_ > max_supported_minor_version) { + return Status(Status::UNKNOWN_VERSION, "Unknown minor version."); + } + buffer_->set_bitstream_version( + DRACO_BITSTREAM_VERSION(version_major_, version_minor_)); + + if (bitstream_version() >= DRACO_BITSTREAM_VERSION(1, 3) && + (header.flags & METADATA_FLAG_MASK)) { + DRACO_RETURN_IF_ERROR(DecodeMetadata()) + } + if (!InitializeDecoder()) { + return Status(Status::DRACO_ERROR, "Failed to initialize the decoder."); + } + if (!DecodeGeometryData()) { + return Status(Status::DRACO_ERROR, "Failed to decode geometry data."); + } + if (!DecodePointAttributes()) { + return Status(Status::DRACO_ERROR, "Failed to decode point attributes."); + } + return OkStatus(); +} + +bool PointCloudDecoder::DecodePointAttributes() { + uint8_t num_attributes_decoders; + if (!buffer_->Decode(&num_attributes_decoders)) { + return false; + } + // Create all attribute decoders. This is implementation specific and the + // derived classes can use any data encoded in the + // PointCloudEncoder::EncodeAttributesEncoderIdentifier() call. + for (int i = 0; i < num_attributes_decoders; ++i) { + if (!CreateAttributesDecoder(i)) { + return false; + } + } + + // Initialize all attributes decoders. No data is decoded here. + for (auto &att_dec : attributes_decoders_) { + if (!att_dec->Init(this, point_cloud_)) { + return false; + } + } + + // Decode any data needed by the attribute decoders. + for (int i = 0; i < num_attributes_decoders; ++i) { + if (!attributes_decoders_[i]->DecodeAttributesDecoderData(buffer_)) { + return false; + } + } + + // Create map between attribute and decoder ids. + for (int i = 0; i < num_attributes_decoders; ++i) { + const int32_t num_attributes = attributes_decoders_[i]->GetNumAttributes(); + for (int j = 0; j < num_attributes; ++j) { + int att_id = attributes_decoders_[i]->GetAttributeId(j); + if (att_id >= attribute_to_decoder_map_.size()) { + attribute_to_decoder_map_.resize(att_id + 1); + } + attribute_to_decoder_map_[att_id] = i; + } + } + + // Decode the actual attributes using the created attribute decoders. + if (!DecodeAllAttributes()) { + return false; + } + + if (!OnAttributesDecoded()) { + return false; + } + return true; +} + +bool PointCloudDecoder::DecodeAllAttributes() { + for (auto &att_dec : attributes_decoders_) { + if (!att_dec->DecodeAttributes(buffer_)) { + return false; + } + } + return true; +} + +const PointAttribute *PointCloudDecoder::GetPortableAttribute( + int32_t parent_att_id) { + if (parent_att_id < 0 || parent_att_id >= point_cloud_->num_attributes()) { + return nullptr; + } + const int32_t parent_att_decoder_id = + attribute_to_decoder_map_[parent_att_id]; + return attributes_decoders_[parent_att_decoder_id]->GetPortableAttribute( + parent_att_id); +} + +} // namespace draco |