1 // Copyright 2016 The Draco Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 #include "draco/compression/point_cloud/point_cloud_decoder.h"
16
17 #include "draco/metadata/metadata_decoder.h"
18
19 namespace draco {
20
PointCloudDecoder()21 PointCloudDecoder::PointCloudDecoder()
22 : point_cloud_(nullptr),
23 buffer_(nullptr),
24 version_major_(0),
25 version_minor_(0),
26 options_(nullptr) {}
27
DecodeHeader(DecoderBuffer * buffer,DracoHeader * out_header)28 Status PointCloudDecoder::DecodeHeader(DecoderBuffer *buffer,
29 DracoHeader *out_header) {
30 constexpr char kIoErrorMsg[] = "Failed to parse Draco header.";
31 if (!buffer->Decode(out_header->draco_string, 5))
32 return Status(Status::IO_ERROR, kIoErrorMsg);
33 if (memcmp(out_header->draco_string, "DRACO", 5) != 0)
34 return Status(Status::DRACO_ERROR, "Not a Draco file.");
35 if (!buffer->Decode(&(out_header->version_major)))
36 return Status(Status::IO_ERROR, kIoErrorMsg);
37 if (!buffer->Decode(&(out_header->version_minor)))
38 return Status(Status::IO_ERROR, kIoErrorMsg);
39 if (!buffer->Decode(&(out_header->encoder_type)))
40 return Status(Status::IO_ERROR, kIoErrorMsg);
41 if (!buffer->Decode(&(out_header->encoder_method)))
42 return Status(Status::IO_ERROR, kIoErrorMsg);
43 if (!buffer->Decode(&(out_header->flags)))
44 return Status(Status::IO_ERROR, kIoErrorMsg);
45 return OkStatus();
46 }
47
DecodeMetadata()48 Status PointCloudDecoder::DecodeMetadata() {
49 std::unique_ptr<GeometryMetadata> metadata =
50 std::unique_ptr<GeometryMetadata>(new GeometryMetadata());
51 MetadataDecoder metadata_decoder;
52 if (!metadata_decoder.DecodeGeometryMetadata(buffer_, metadata.get()))
53 return Status(Status::DRACO_ERROR, "Failed to decode metadata.");
54 point_cloud_->AddMetadata(std::move(metadata));
55 return OkStatus();
56 }
57
Decode(const DecoderOptions & options,DecoderBuffer * in_buffer,PointCloud * out_point_cloud)58 Status PointCloudDecoder::Decode(const DecoderOptions &options,
59 DecoderBuffer *in_buffer,
60 PointCloud *out_point_cloud) {
61 options_ = &options;
62 buffer_ = in_buffer;
63 point_cloud_ = out_point_cloud;
64 DracoHeader header;
65 DRACO_RETURN_IF_ERROR(DecodeHeader(buffer_, &header))
66 // Sanity check that we are really using the right decoder (mostly for cases
67 // where the Decode method was called manually outside of our main API.
68 if (header.encoder_type != GetGeometryType())
69 return Status(Status::DRACO_ERROR,
70 "Using incompatible decoder for the input geometry.");
71 // TODO(ostava): We should check the method as well, but currently decoders
72 // don't expose the decoding method id.
73 version_major_ = header.version_major;
74 version_minor_ = header.version_minor;
75
76 const uint8_t max_supported_major_version =
77 header.encoder_type == POINT_CLOUD ? kDracoPointCloudBitstreamVersionMajor
78 : kDracoMeshBitstreamVersionMajor;
79 const uint8_t max_supported_minor_version =
80 header.encoder_type == POINT_CLOUD ? kDracoPointCloudBitstreamVersionMinor
81 : kDracoMeshBitstreamVersionMinor;
82 // Check for version compatibility.
83 if (version_major_ < 1 || version_major_ > max_supported_major_version)
84 return Status(Status::UNKNOWN_VERSION, "Unknown major version.");
85 if (version_major_ == max_supported_major_version &&
86 version_minor_ > max_supported_minor_version)
87 return Status(Status::UNKNOWN_VERSION, "Unknown minor version.");
88 buffer_->set_bitstream_version(
89 DRACO_BITSTREAM_VERSION(version_major_, version_minor_));
90
91 if (bitstream_version() >= DRACO_BITSTREAM_VERSION(1, 3) &&
92 (header.flags & METADATA_FLAG_MASK)) {
93 DRACO_RETURN_IF_ERROR(DecodeMetadata())
94 }
95 if (!InitializeDecoder())
96 return Status(Status::DRACO_ERROR, "Failed to initialize the decoder.");
97 if (!DecodeGeometryData())
98 return Status(Status::DRACO_ERROR, "Failed to decode geometry data.");
99 if (!DecodePointAttributes())
100 return Status(Status::DRACO_ERROR, "Failed to decode point attributes.");
101 return OkStatus();
102 }
103
DecodePointAttributes()104 bool PointCloudDecoder::DecodePointAttributes() {
105 uint8_t num_attributes_decoders;
106 if (!buffer_->Decode(&num_attributes_decoders))
107 return false;
108 // Create all attribute decoders. This is implementation specific and the
109 // derived classes can use any data encoded in the
110 // PointCloudEncoder::EncodeAttributesEncoderIdentifier() call.
111 for (int i = 0; i < num_attributes_decoders; ++i) {
112 if (!CreateAttributesDecoder(i))
113 return false;
114 }
115
116 // Initialize all attributes decoders. No data is decoded here.
117 for (auto &att_dec : attributes_decoders_) {
118 if (!att_dec->Init(this, point_cloud_))
119 return false;
120 }
121
122 // Decode any data needed by the attribute decoders.
123 for (int i = 0; i < num_attributes_decoders; ++i) {
124 if (!attributes_decoders_[i]->DecodeAttributesDecoderData(buffer_))
125 return false;
126 }
127
128 // Create map between attribute and decoder ids.
129 for (int i = 0; i < num_attributes_decoders; ++i) {
130 const int32_t num_attributes = attributes_decoders_[i]->GetNumAttributes();
131 for (int j = 0; j < num_attributes; ++j) {
132 int att_id = attributes_decoders_[i]->GetAttributeId(j);
133 if (att_id >= attribute_to_decoder_map_.size()) {
134 attribute_to_decoder_map_.resize(att_id + 1);
135 }
136 attribute_to_decoder_map_[att_id] = i;
137 }
138 }
139
140 // Decode the actual attributes using the created attribute decoders.
141 if (!DecodeAllAttributes())
142 return false;
143
144 if (!OnAttributesDecoded())
145 return false;
146 return true;
147 }
148
DecodeAllAttributes()149 bool PointCloudDecoder::DecodeAllAttributes() {
150 for (auto &att_dec : attributes_decoders_) {
151 if (!att_dec->DecodeAttributes(buffer_))
152 return false;
153 }
154 return true;
155 }
156
GetPortableAttribute(int32_t parent_att_id)157 const PointAttribute *PointCloudDecoder::GetPortableAttribute(
158 int32_t parent_att_id) {
159 if (parent_att_id < 0 || parent_att_id >= point_cloud_->num_attributes())
160 return nullptr;
161 const int32_t parent_att_decoder_id =
162 attribute_to_decoder_map_[parent_att_id];
163 return attributes_decoders_[parent_att_decoder_id]->GetPortableAttribute(
164 parent_att_id);
165 }
166
167 } // namespace draco
168