Coverage Report

Created: 2024-09-08 06:46

/src/draco/src/draco/compression/point_cloud/point_cloud_decoder.cc
Line
Count
Source (jump to first uncovered line)
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
21
PointCloudDecoder::PointCloudDecoder()
22
    : point_cloud_(nullptr),
23
      buffer_(nullptr),
24
      version_major_(0),
25
      version_minor_(0),
26
8.01k
      options_(nullptr) {}
27
28
Status PointCloudDecoder::DecodeHeader(DecoderBuffer *buffer,
29
16.0k
                                       DracoHeader *out_header) {
30
16.0k
  constexpr char kIoErrorMsg[] = "Failed to parse Draco header.";
31
16.0k
  if (!buffer->Decode(out_header->draco_string, 5)) {
32
0
    return Status(Status::IO_ERROR, kIoErrorMsg);
33
0
  }
34
16.0k
  if (memcmp(out_header->draco_string, "DRACO", 5) != 0) {
35
3
    return Status(Status::DRACO_ERROR, "Not a Draco file.");
36
3
  }
37
16.0k
  if (!buffer->Decode(&(out_header->version_major))) {
38
0
    return Status(Status::IO_ERROR, kIoErrorMsg);
39
0
  }
40
16.0k
  if (!buffer->Decode(&(out_header->version_minor))) {
41
0
    return Status(Status::IO_ERROR, kIoErrorMsg);
42
0
  }
43
16.0k
  if (!buffer->Decode(&(out_header->encoder_type))) {
44
0
    return Status(Status::IO_ERROR, kIoErrorMsg);
45
0
  }
46
16.0k
  if (!buffer->Decode(&(out_header->encoder_method))) {
47
0
    return Status(Status::IO_ERROR, kIoErrorMsg);
48
0
  }
49
16.0k
  if (!buffer->Decode(&(out_header->flags))) {
50
0
    return Status(Status::IO_ERROR, kIoErrorMsg);
51
0
  }
52
16.0k
  return OkStatus();
53
16.0k
}
54
55
501
Status PointCloudDecoder::DecodeMetadata() {
56
501
  std::unique_ptr<GeometryMetadata> metadata =
57
501
      std::unique_ptr<GeometryMetadata>(new GeometryMetadata());
58
501
  MetadataDecoder metadata_decoder;
59
501
  if (!metadata_decoder.DecodeGeometryMetadata(buffer_, metadata.get())) {
60
489
    return Status(Status::DRACO_ERROR, "Failed to decode metadata.");
61
489
  }
62
12
  point_cloud_->AddMetadata(std::move(metadata));
63
12
  return OkStatus();
64
501
}
65
66
Status PointCloudDecoder::Decode(const DecoderOptions &options,
67
                                 DecoderBuffer *in_buffer,
68
8.01k
                                 PointCloud *out_point_cloud) {
69
8.01k
  options_ = &options;
70
8.01k
  buffer_ = in_buffer;
71
8.01k
  point_cloud_ = out_point_cloud;
72
8.01k
  DracoHeader header;
73
8.01k
  DRACO_RETURN_IF_ERROR(DecodeHeader(buffer_, &header))
74
  // Sanity check that we are really using the right decoder (mostly for cases
75
  // where the Decode method was called manually outside of our main API.
76
8.01k
  if (header.encoder_type != GetGeometryType()) {
77
0
    return Status(Status::DRACO_ERROR,
78
0
                  "Using incompatible decoder for the input geometry.");
79
0
  }
80
  // TODO(ostava): We should check the method as well, but currently decoders
81
  // don't expose the decoding method id.
82
8.01k
  version_major_ = header.version_major;
83
8.01k
  version_minor_ = header.version_minor;
84
85
8.01k
  const uint8_t max_supported_major_version =
86
8.01k
      header.encoder_type == POINT_CLOUD ? kDracoPointCloudBitstreamVersionMajor
87
8.01k
                                         : kDracoMeshBitstreamVersionMajor;
88
8.01k
  const uint8_t max_supported_minor_version =
89
8.01k
      header.encoder_type == POINT_CLOUD ? kDracoPointCloudBitstreamVersionMinor
90
8.01k
                                         : kDracoMeshBitstreamVersionMinor;
91
92
  // Check for version compatibility.
93
8.01k
#ifdef DRACO_BACKWARDS_COMPATIBILITY_SUPPORTED
94
8.01k
  if (version_major_ < 1 || version_major_ > max_supported_major_version) {
95
0
    return Status(Status::UNKNOWN_VERSION, "Unknown major version.");
96
0
  }
97
8.01k
  if (version_major_ == max_supported_major_version &&
98
8.01k
      version_minor_ > max_supported_minor_version) {
99
0
    return Status(Status::UNKNOWN_VERSION, "Unknown minor version.");
100
0
  }
101
#else
102
  if (version_major_ != max_supported_major_version) {
103
    return Status(Status::UNKNOWN_VERSION, "Unsupported major version.");
104
  }
105
  if (version_minor_ != max_supported_minor_version) {
106
    return Status(Status::UNKNOWN_VERSION, "Unsupported minor version.");
107
  }
108
#endif
109
8.01k
  buffer_->set_bitstream_version(
110
8.01k
      DRACO_BITSTREAM_VERSION(version_major_, version_minor_));
111
112
8.01k
  if (bitstream_version() >= DRACO_BITSTREAM_VERSION(1, 3) &&
113
8.01k
      (header.flags & METADATA_FLAG_MASK)) {
114
501
    DRACO_RETURN_IF_ERROR(DecodeMetadata())
115
501
  }
116
7.52k
  if (!InitializeDecoder()) {
117
0
    return Status(Status::DRACO_ERROR, "Failed to initialize the decoder.");
118
0
  }
119
7.52k
  if (!DecodeGeometryData()) {
120
3.09k
    return Status(Status::DRACO_ERROR, "Failed to decode geometry data.");
121
3.09k
  }
122
4.43k
  if (!DecodePointAttributes()) {
123
3.45k
    return Status(Status::DRACO_ERROR, "Failed to decode point attributes.");
124
3.45k
  }
125
977
  return OkStatus();
126
4.43k
}
127
128
4.43k
bool PointCloudDecoder::DecodePointAttributes() {
129
4.43k
  uint8_t num_attributes_decoders;
130
4.43k
  if (!buffer_->Decode(&num_attributes_decoders)) {
131
109
    return false;
132
109
  }
133
  // Create all attribute decoders. This is implementation specific and the
134
  // derived classes can use any data encoded in the
135
  // PointCloudEncoder::EncodeAttributesEncoderIdentifier() call.
136
29.7k
  for (int i = 0; i < num_attributes_decoders; ++i) {
137
25.5k
    if (!CreateAttributesDecoder(i)) {
138
181
      return false;
139
181
    }
140
25.5k
  }
141
142
  // Initialize all attributes decoders. No data is decoded here.
143
25.3k
  for (auto &att_dec : attributes_decoders_) {
144
25.3k
    if (!att_dec->Init(this, point_cloud_)) {
145
0
      return false;
146
0
    }
147
25.3k
  }
148
149
  // Decode any data needed by the attribute decoders.
150
12.4k
  for (int i = 0; i < num_attributes_decoders; ++i) {
151
8.49k
    if (!attributes_decoders_[i]->DecodeAttributesDecoderData(buffer_)) {
152
175
      return false;
153
175
    }
154
8.49k
  }
155
156
  // Create map between attribute and decoder ids.
157
9.41k
  for (int i = 0; i < num_attributes_decoders; ++i) {
158
5.44k
    const int32_t num_attributes = attributes_decoders_[i]->GetNumAttributes();
159
28.7k
    for (int j = 0; j < num_attributes; ++j) {
160
23.3k
      int att_id = attributes_decoders_[i]->GetAttributeId(j);
161
23.3k
      if (att_id >= attribute_to_decoder_map_.size()) {
162
23.3k
        attribute_to_decoder_map_.resize(att_id + 1);
163
23.3k
      }
164
23.3k
      attribute_to_decoder_map_[att_id] = i;
165
23.3k
    }
166
5.44k
  }
167
168
  // Decode the actual attributes using the created attribute decoders.
169
3.96k
  if (!DecodeAllAttributes()) {
170
2.98k
    return false;
171
2.98k
  }
172
173
977
  if (!OnAttributesDecoded()) {
174
0
    return false;
175
0
  }
176
977
  return true;
177
977
}
178
179
3.96k
bool PointCloudDecoder::DecodeAllAttributes() {
180
4.12k
  for (auto &att_dec : attributes_decoders_) {
181
4.12k
    if (!att_dec->DecodeAttributes(buffer_)) {
182
2.98k
      return false;
183
2.98k
    }
184
4.12k
  }
185
977
  return true;
186
3.96k
}
187
188
const PointAttribute *PointCloudDecoder::GetPortableAttribute(
189
2.54k
    int32_t parent_att_id) {
190
2.54k
  if (parent_att_id < 0 || parent_att_id >= point_cloud_->num_attributes()) {
191
0
    return nullptr;
192
0
  }
193
2.54k
  const int32_t parent_att_decoder_id =
194
2.54k
      attribute_to_decoder_map_[parent_att_id];
195
2.54k
  return attributes_decoders_[parent_att_decoder_id]->GetPortableAttribute(
196
2.54k
      parent_att_id);
197
2.54k
}
198
199
}  // namespace draco