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