diff options
Diffstat (limited to 'extern/draco/draco/src/draco/compression/attributes')
24 files changed, 277 insertions, 199 deletions
diff --git a/extern/draco/draco/src/draco/compression/attributes/attributes_decoder.cc b/extern/draco/draco/src/draco/compression/attributes/attributes_decoder.cc index ce5b8b9c756..007dd2f4303 100644 --- a/extern/draco/draco/src/draco/compression/attributes/attributes_decoder.cc +++ b/extern/draco/draco/src/draco/compression/attributes/attributes_decoder.cc @@ -43,9 +43,18 @@ bool AttributesDecoder::DecodeAttributesDecoderData(DecoderBuffer *in_buffer) { return false; } } + + // Check that decoded number of attributes is valid. if (num_attributes == 0) { return false; } + if (num_attributes > 5 * in_buffer->remaining_size()) { + // The decoded number of attributes is unreasonably high, because at least + // five bytes of attribute descriptor data per attribute are expected. + return false; + } + + // Decode attribute descriptor data. point_attribute_ids_.resize(num_attributes); PointCloud *pc = point_cloud_; for (uint32_t i = 0; i < num_attributes; ++i) { @@ -69,9 +78,14 @@ bool AttributesDecoder::DecodeAttributesDecoderData(DecoderBuffer *in_buffer) { if (data_type == DT_INVALID || data_type >= DT_TYPES_COUNT) { return false; } - const DataType draco_dt = static_cast<DataType>(data_type); - // Add the attribute to the point cloud + // Check decoded attribute descriptor data. + if (num_components == 0) { + return false; + } + + // Add the attribute to the point cloud. + const DataType draco_dt = static_cast<DataType>(data_type); GeometryAttribute ga; ga.Init(static_cast<GeometryAttribute::Type>(att_type), nullptr, num_components, draco_dt, normalized > 0, @@ -90,7 +104,9 @@ bool AttributesDecoder::DecodeAttributesDecoderData(DecoderBuffer *in_buffer) { } else #endif { - DecodeVarint(&unique_id, in_buffer); + if (!DecodeVarint(&unique_id, in_buffer)) { + return false; + } ga.set_unique_id(unique_id); } const int att_id = pc->AddAttribute( diff --git a/extern/draco/draco/src/draco/compression/attributes/attributes_encoder.cc b/extern/draco/draco/src/draco/compression/attributes/attributes_encoder.cc index 797c62f30aa..480e3ff3436 100644 --- a/extern/draco/draco/src/draco/compression/attributes/attributes_encoder.cc +++ b/extern/draco/draco/src/draco/compression/attributes/attributes_encoder.cc @@ -15,14 +15,16 @@ #include "draco/compression/attributes/attributes_encoder.h" #include "draco/core/varint_encoding.h" +#include "draco/draco_features.h" namespace draco { AttributesEncoder::AttributesEncoder() : point_cloud_encoder_(nullptr), point_cloud_(nullptr) {} -AttributesEncoder::AttributesEncoder(int att_id) : AttributesEncoder() { - AddAttributeId(att_id); +AttributesEncoder::AttributesEncoder(int point_attrib_id) + : AttributesEncoder() { + AddAttributeId(point_attrib_id); } bool AttributesEncoder::Init(PointCloudEncoder *encoder, const PointCloud *pc) { @@ -37,7 +39,15 @@ bool AttributesEncoder::EncodeAttributesEncoderData(EncoderBuffer *out_buffer) { for (uint32_t i = 0; i < num_attributes(); ++i) { const int32_t att_id = point_attribute_ids_[i]; const PointAttribute *const pa = point_cloud_->attribute(att_id); - out_buffer->Encode(static_cast<uint8_t>(pa->attribute_type())); + GeometryAttribute::Type type = pa->attribute_type(); +#ifdef DRACO_TRANSCODER_SUPPORTED + // Attribute types TANGENT, MATERIAL, JOINTS, and WEIGHTS are not supported + // in the official bitstream. They will be encoded as GENERIC. + if (type > GeometryAttribute::GENERIC) { + type = GeometryAttribute::GENERIC; + } +#endif + out_buffer->Encode(static_cast<uint8_t>(type)); out_buffer->Encode(static_cast<uint8_t>(pa->data_type())); out_buffer->Encode(static_cast<uint8_t>(pa->num_components())); out_buffer->Encode(static_cast<uint8_t>(pa->normalized())); diff --git a/extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_decoder.cc b/extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_decoder.cc index 99469f94590..c7c96d77007 100644 --- a/extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_decoder.cc +++ b/extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_decoder.cc @@ -72,7 +72,7 @@ class PointAttributeVectorOutputIterator { Self &operator*() { return *this; } // Still needed in some cases. - // TODO(hemmer): remove. + // TODO(b/199760123): Remove. // hardcoded to 3 based on legacy usage. const Self &operator=(const VectorD<CoeffT, 3> &val) { DRACO_DCHECK_EQ(attributes_.size(), 1); // Expect only ONE attribute. @@ -278,8 +278,10 @@ bool KdTreeAttributesDecoder::DecodeDataNeededByPortableTransforms( return false; } AttributeQuantizationTransform transform; - transform.SetParameters(quantization_bits, min_value.data(), - num_components, max_value_dif); + if (!transform.SetParameters(quantization_bits, min_value.data(), + num_components, max_value_dif)) { + return false; + } const int num_transforms = static_cast<int>(attribute_quantization_transforms_.size()); if (!transform.TransferToAttribute( @@ -293,7 +295,9 @@ bool KdTreeAttributesDecoder::DecodeDataNeededByPortableTransforms( // Decode transform data for signed integer attributes. for (int i = 0; i < min_signed_values_.size(); ++i) { int32_t val; - DecodeVarint(&val, in_buffer); + if (!DecodeVarint(&val, in_buffer)) { + return false; + } min_signed_values_[i] = val; } return true; @@ -353,8 +357,9 @@ bool KdTreeAttributesDecoder::DecodeDataNeededByPortableTransforms( return false; } if (6 < compression_level) { - LOGE("KdTreeAttributesDecoder: compression level %i not supported.\n", - compression_level); + DRACO_LOGE( + "KdTreeAttributesDecoder: compression level %i not supported.\n", + compression_level); return false; } @@ -371,7 +376,7 @@ bool KdTreeAttributesDecoder::DecodeDataNeededByPortableTransforms( GetDecoder()->point_cloud()->attribute(att_id); attr->Reset(num_points); attr->SetIdentityMapping(); - }; + } PointAttributeVectorOutputIterator<uint32_t> out_it(atts); diff --git a/extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_encoder.cc b/extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_encoder.cc index 0f9c31565e5..b70deb9e01f 100644 --- a/extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_encoder.cc +++ b/extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_encoder.cc @@ -71,16 +71,21 @@ bool KdTreeAttributesEncoder::TransformAttributesToPortableFormat() { att->num_components(), range); } else { // Compute quantization settings from the attribute values. - attribute_quantization_transform.ComputeParameters(*att, - quantization_bits); + if (!attribute_quantization_transform.ComputeParameters( + *att, quantization_bits)) { + return false; + } } attribute_quantization_transforms_.push_back( attribute_quantization_transform); // Store the quantized attribute in an array that will be used when we do // the actual encoding of the data. - quantized_portable_attributes_.push_back( - attribute_quantization_transform.GeneratePortableAttribute( - *att, static_cast<int>(num_points))); + auto portable_att = + attribute_quantization_transform.InitTransformedAttribute(*att, + num_points); + attribute_quantization_transform.TransformAttribute(*att, {}, + portable_att.get()); + quantized_portable_attributes_.push_back(std::move(portable_att)); } else if (att->data_type() == DT_INT32 || att->data_type() == DT_INT16 || att->data_type() == DT_INT8) { // For signed types, find the minimum value for each component. These diff --git a/extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_encoder.h b/extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_encoder.h index 8b4c4e2faab..80748e0bf5d 100644 --- a/extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_encoder.h +++ b/extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_encoder.h @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. // -#ifndef DRACO_COMPRESSION_ATTRIBUTES_POINT_CLOUD_KD_TREE_ATTRIBUTES_ENCODER_H_ -#define DRACO_COMPRESSION_ATTRIBUTES_POINT_CLOUD_KD_TREE_ATTRIBUTES_ENCODER_H_ +#ifndef DRACO_COMPRESSION_ATTRIBUTES_KD_TREE_ATTRIBUTES_ENCODER_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_KD_TREE_ATTRIBUTES_ENCODER_H_ #include "draco/attributes/attribute_quantization_transform.h" #include "draco/compression/attributes/attributes_encoder.h" @@ -48,4 +48,4 @@ class KdTreeAttributesEncoder : public AttributesEncoder { } // namespace draco -#endif // DRACO_COMPRESSION_ATTRIBUTES_POINT_CLOUD_KD_TREE_ATTRIBUTES_ENCODER_H_ +#endif // DRACO_COMPRESSION_ATTRIBUTES_KD_TREE_ATTRIBUTES_ENCODER_H_ diff --git a/extern/draco/draco/src/draco/compression/attributes/normal_compression_utils.h b/extern/draco/draco/src/draco/compression/attributes/normal_compression_utils.h index 32e27c711e3..be5ee5b09e3 100644 --- a/extern/draco/draco/src/draco/compression/attributes/normal_compression_utils.h +++ b/extern/draco/draco/src/draco/compression/attributes/normal_compression_utils.h @@ -53,6 +53,7 @@ class OctahedronToolBox { : quantization_bits_(-1), max_quantized_value_(-1), max_value_(-1), + dequantization_scale_(1.f), center_value_(-1) {} bool SetQuantizationBits(int32_t q) { @@ -62,6 +63,7 @@ class OctahedronToolBox { quantization_bits_ = q; max_quantized_value_ = (1 << quantization_bits_) - 1; max_value_ = max_quantized_value_ - 1; + dequantization_scale_ = 2.f / max_value_; center_value_ = max_value_ / 2; return true; } @@ -192,64 +194,11 @@ class OctahedronToolBox { } } - // TODO(b/149328891): Change function to not use templates as |T| is only - // float. - template <typename T> - void OctaherdalCoordsToUnitVector(T in_s, T in_t, T *out_vector) const { - DRACO_DCHECK_GE(in_s, 0); - DRACO_DCHECK_GE(in_t, 0); - DRACO_DCHECK_LE(in_s, 1); - DRACO_DCHECK_LE(in_t, 1); - T s = in_s; - T t = in_t; - T spt = s + t; - T smt = s - t; - T x_sign = 1.0; - if (spt >= 0.5 && spt <= 1.5 && smt >= -0.5 && smt <= 0.5) { - // Right hemisphere. Don't do anything. - } else { - // Left hemisphere. - x_sign = -1.0; - if (spt <= 0.5) { - s = 0.5 - in_t; - t = 0.5 - in_s; - } else if (spt >= 1.5) { - s = 1.5 - in_t; - t = 1.5 - in_s; - } else if (smt <= -0.5) { - s = in_t - 0.5; - t = in_s + 0.5; - } else { - s = in_t + 0.5; - t = in_s - 0.5; - } - spt = s + t; - smt = s - t; - } - const T y = 2.0 * s - 1.0; - const T z = 2.0 * t - 1.0; - const T x = std::min(std::min(2.0 * spt - 1.0, 3.0 - 2.0 * spt), - std::min(2.0 * smt + 1.0, 1.0 - 2.0 * smt)) * - x_sign; - // Normalize the computed vector. - const T normSquared = x * x + y * y + z * z; - if (normSquared < 1e-6) { - out_vector[0] = 0; - out_vector[1] = 0; - out_vector[2] = 0; - } else { - const T d = 1.0 / std::sqrt(normSquared); - out_vector[0] = x * d; - out_vector[1] = y * d; - out_vector[2] = z * d; - } - } - - template <typename T> - void QuantizedOctaherdalCoordsToUnitVector(int32_t in_s, int32_t in_t, - T *out_vector) const { - T scale = 1.0 / static_cast<T>(max_value_); - OctaherdalCoordsToUnitVector(in_s * scale, in_t * scale, out_vector); + inline void QuantizedOctahedralCoordsToUnitVector(int32_t in_s, int32_t in_t, + float *out_vector) const { + OctahedralCoordsToUnitVector(in_s * dequantization_scale_ - 1.f, + in_t * dequantization_scale_ - 1.f, + out_vector); } // |s| and |t| are expected to be signed values. @@ -333,9 +282,77 @@ class OctahedronToolBox { int32_t center_value() const { return center_value_; } private: + inline void OctahedralCoordsToUnitVector(float in_s_scaled, float in_t_scaled, + float *out_vector) const { + // Background about the encoding: + // A normal is encoded in a normalized space <s, t> depicted below. The + // encoding correponds to an octahedron that is unwrapped to a 2D plane. + // During encoding, a normal is projected to the surface of the octahedron + // and the projection is then unwrapped to the 2D plane. Decoding is the + // reverse of this process. + // All points in the central diamond are located on triangles on the + // right "hemisphere" of the octahedron while all points outside of the + // diamond are on the left hemisphere (basically, they would have to be + // wrapped along the diagonal edges to form the octahedron). The central + // point corresponds to the right most vertex of the octahedron and all + // corners of the plane correspond to the left most vertex of the + // octahedron. + // + // t + // ^ *-----*-----* + // | | /|\ | + // | / | \ | + // | / | \ | + // | / | \ | + // *-----*---- * + // | \ | / | + // | \ | / | + // | \ | / | + // | \|/ | + // *-----*-----* --> s + + // Note that the input |in_s_scaled| and |in_t_scaled| are already scaled to + // <-1, 1> range. This way, the central point is at coordinate (0, 0). + float y = in_s_scaled; + float z = in_t_scaled; + + // Remaining coordinate can be computed by projecting the (y, z) values onto + // the surface of the octahedron. + const float x = 1.f - std::abs(y) - std::abs(z); + + // |x| is essentially a signed distance from the diagonal edges of the + // diamond shown on the figure above. It is positive for all points in the + // diamond (right hemisphere) and negative for all points outside the + // diamond (left hemisphere). For all points on the left hemisphere we need + // to update their (y, z) coordinates to account for the wrapping along + // the edges of the diamond. + float x_offset = -x; + x_offset = x_offset < 0 ? 0 : x_offset; + + // This will do nothing for the points on the right hemisphere but it will + // mirror the (y, z) location along the nearest diagonal edge of the + // diamond. + y += y < 0 ? x_offset : -x_offset; + z += z < 0 ? x_offset : -x_offset; + + // Normalize the computed vector. + const float norm_squared = x * x + y * y + z * z; + if (norm_squared < 1e-6) { + out_vector[0] = 0; + out_vector[1] = 0; + out_vector[2] = 0; + } else { + const float d = 1.0f / std::sqrt(norm_squared); + out_vector[0] = x * d; + out_vector[1] = y * d; + out_vector[2] = z * d; + } + } + int32_t quantization_bits_; int32_t max_quantized_value_; int32_t max_value_; + float dequantization_scale_; int32_t center_value_; }; } // namespace draco diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_data.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_data.h index f712952556a..2960a5e71b4 100644 --- a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_data.h +++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_data.h @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. // -#ifndef DRACO_COMPRESSION_ATTRIBUTES_MESH_PREDICTION_SCHEMES_PREDICTION_SCHEME_DATA_H_ -#define DRACO_COMPRESSION_ATTRIBUTES_MESH_PREDICTION_SCHEMES_PREDICTION_SCHEME_DATA_H_ +#ifndef DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_DATA_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_DATA_H_ #include "draco/mesh/corner_table.h" #include "draco/mesh/mesh.h" diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_geometric_normal_predictor_area.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_geometric_normal_predictor_area.h index bf1a6146111..775eded6b55 100644 --- a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_geometric_normal_predictor_area.h +++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_geometric_normal_predictor_area.h @@ -69,7 +69,14 @@ class MeshPredictionSchemeGeometricNormalPredictorArea // Computing cross product. const VectorD<int64_t, 3> cross = CrossProduct(delta_next, delta_prev); - normal = normal + cross; + + // Prevent signed integer overflows by doing math as unsigned. + auto normal_data = reinterpret_cast<uint64_t *>(normal.data()); + auto cross_data = reinterpret_cast<const uint64_t *>(cross.data()); + normal_data[0] = normal_data[0] + cross_data[0]; + normal_data[1] = normal_data[1] + cross_data[1]; + normal_data[2] = normal_data[2] + cross_data[2]; + cit.Next(); } diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_parallelogram_shared.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_parallelogram_shared.h index 485d457ccf6..fd10fb524b3 100644 --- a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_parallelogram_shared.h +++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_parallelogram_shared.h @@ -60,8 +60,13 @@ inline bool ComputeParallelogramPrediction( const int v_next_off = vert_next * num_components; const int v_prev_off = vert_prev * num_components; for (int c = 0; c < num_components; ++c) { - out_prediction[c] = (in_data[v_next_off + c] + in_data[v_prev_off + c]) - - in_data[v_opp_off + c]; + const int64_t in_data_next_off = in_data[v_next_off + c]; + const int64_t in_data_prev_off = in_data[v_prev_off + c]; + const int64_t in_data_opp_off = in_data[v_opp_off + c]; + const int64_t result = + (in_data_next_off + in_data_prev_off) - in_data_opp_off; + + out_prediction[c] = static_cast<DataTypeT>(result); } return true; } diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_tex_coords_portable_predictor.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_tex_coords_portable_predictor.h index 5d8a5060133..f05e5ddd713 100644 --- a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_tex_coords_portable_predictor.h +++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_tex_coords_portable_predictor.h @@ -156,6 +156,13 @@ bool MeshPredictionSchemeTexCoordsPortablePredictor< const VectorD<int64_t, 2> x_uv = n_uv * pn_norm2_squared + (cn_dot_pn * pn_uv); + const int64_t pn_absmax_element = + std::max(std::max(std::abs(pn[0]), std::abs(pn[1])), std::abs(pn[2])); + if (cn_dot_pn > std::numeric_limits<int64_t>::max() / pn_absmax_element) { + // return false if squared length calculation would overflow. + return false; + } + // Compute squared length of vector CX in position coordinate system: const VectorD<int64_t, 3> x_pos = next_pos + (cn_dot_pn * pn) / pn_norm2_squared; diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.cc b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.cc index 428340da013..60429d5c779 100644 --- a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.cc +++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.cc @@ -18,34 +18,51 @@ namespace draco { PredictionSchemeMethod SelectPredictionMethod( int att_id, const PointCloudEncoder *encoder) { - if (encoder->options()->GetSpeed() >= 10) { + return SelectPredictionMethod(att_id, *encoder->options(), encoder); +} + +PredictionSchemeMethod SelectPredictionMethod( + int att_id, const EncoderOptions &options, + const PointCloudEncoder *encoder) { + if (options.GetSpeed() >= 10) { // Selected fastest, though still doing some compression. return PREDICTION_DIFFERENCE; } if (encoder->GetGeometryType() == TRIANGULAR_MESH) { // Use speed setting to select the best encoding method. const PointAttribute *const att = encoder->point_cloud()->attribute(att_id); - if (att->attribute_type() == GeometryAttribute::TEX_COORD) { - if (encoder->options()->GetSpeed() < 4) { + if (att->attribute_type() == GeometryAttribute::TEX_COORD && + att->num_components() == 2) { + if (options.GetSpeed() < 4) { // Use texture coordinate prediction for speeds 0, 1, 2, 3. return MESH_PREDICTION_TEX_COORDS_PORTABLE; } } if (att->attribute_type() == GeometryAttribute::NORMAL) { #ifdef DRACO_NORMAL_ENCODING_SUPPORTED - if (encoder->options()->GetSpeed() < 4) { + if (options.GetSpeed() < 4) { // Use geometric normal prediction for speeds 0, 1, 2, 3. - return MESH_PREDICTION_GEOMETRIC_NORMAL; + // For this prediction, the position attribute needs to be either + // integer or quantized as well. + const int pos_att_id = encoder->point_cloud()->GetNamedAttributeId( + GeometryAttribute::POSITION); + const PointAttribute *const pos_att = + encoder->point_cloud()->GetNamedAttribute( + GeometryAttribute::POSITION); + if (pos_att && (IsDataTypeIntegral(pos_att->data_type()) || + options.GetAttributeInt(pos_att_id, "quantization_bits", + -1) > 0)) { + return MESH_PREDICTION_GEOMETRIC_NORMAL; + } } #endif return PREDICTION_DIFFERENCE; // default } // Handle other attribute types. - if (encoder->options()->GetSpeed() >= 8) { + if (options.GetSpeed() >= 8) { return PREDICTION_DIFFERENCE; } - if (encoder->options()->GetSpeed() >= 2 || - encoder->point_cloud()->num_points() < 40) { + if (options.GetSpeed() >= 2 || encoder->point_cloud()->num_points() < 40) { // Parallelogram prediction is used for speeds 2 - 7 or when the overhead // of using constrained multi-parallelogram would be too high. return MESH_PREDICTION_PARALLELOGRAM; diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.h index 40a7683aa0d..b7e21224fad 100644 --- a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.h +++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.h @@ -38,6 +38,10 @@ namespace draco { PredictionSchemeMethod SelectPredictionMethod(int att_id, const PointCloudEncoder *encoder); +PredictionSchemeMethod SelectPredictionMethod(int att_id, + const EncoderOptions &options, + const PointCloudEncoder *encoder); + // Factory class for creating mesh prediction schemes. template <typename DataTypeT> struct MeshPredictionSchemeEncoderFactory { diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_interface.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_interface.h index ab64bce7114..37aa9f76a9c 100644 --- a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_interface.h +++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_interface.h @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. // -#ifndef DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_ENCODING_INTERFACE_H_ -#define DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_ENCODING_INTERFACE_H_ +#ifndef DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_ENCODER_INTERFACE_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_ENCODER_INTERFACE_H_ #include "draco/compression/attributes/prediction_schemes/prediction_scheme_interface.h" #include "draco/core/encoder_buffer.h" @@ -52,4 +52,4 @@ class PredictionSchemeTypedEncoderInterface } // namespace draco -#endif // DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_ENCODING_INTERFACE_H_ +#endif // DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_ENCODER_INTERFACE_H_ diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_wrap_decoding_transform.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_wrap_decoding_transform.h index 0a14d0d9ba4..e100c738a6c 100644 --- a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_wrap_decoding_transform.h +++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_wrap_decoding_transform.h @@ -36,9 +36,25 @@ class PredictionSchemeWrapDecodingTransform inline void ComputeOriginalValue(const DataTypeT *predicted_vals, const CorrTypeT *corr_vals, DataTypeT *out_original_vals) const { + // For now we assume both |DataTypeT| and |CorrTypeT| are equal. + static_assert(std::is_same<DataTypeT, CorrTypeT>::value, + "Predictions and corrections must have the same type."); + + // The only valid implementation right now is for int32_t. + static_assert(std::is_same<DataTypeT, int32_t>::value, + "Only int32_t is supported for predicted values."); + predicted_vals = this->ClampPredictedValue(predicted_vals); + + // Perform the wrapping using unsigned coordinates to avoid potential signed + // integer overflows caused by malformed input. + const uint32_t *const uint_predicted_vals = + reinterpret_cast<const uint32_t *>(predicted_vals); + const uint32_t *const uint_corr_vals = + reinterpret_cast<const uint32_t *>(corr_vals); for (int i = 0; i < this->num_components(); ++i) { - out_original_vals[i] = predicted_vals[i] + corr_vals[i]; + out_original_vals[i] = + static_cast<DataTypeT>(uint_predicted_vals[i] + uint_corr_vals[i]); if (out_original_vals[i] > this->max_value()) { out_original_vals[i] -= this->max_dif(); } else if (out_original_vals[i] < this->min_value()) { diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_wrap_transform_base.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_wrap_transform_base.h index 26f61fbaf6a..979c63c3d11 100644 --- a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_wrap_transform_base.h +++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_wrap_transform_base.h @@ -73,7 +73,7 @@ class PredictionSchemeWrapTransformBase { return &clamped_value_[0]; } - // TODO(hemmer): Consider refactoring to avoid this dummy. + // TODO(b/199760123): Consider refactoring to avoid this dummy. int quantization_bits() const { DRACO_DCHECK(false); return -1; diff --git a/extern/draco/draco/src/draco/compression/attributes/sequential_attribute_encoders_controller.cc b/extern/draco/draco/src/draco/compression/attributes/sequential_attribute_encoders_controller.cc index 521935c1e99..7d5d1eeff26 100644 --- a/extern/draco/draco/src/draco/compression/attributes/sequential_attribute_encoders_controller.cc +++ b/extern/draco/draco/src/draco/compression/attributes/sequential_attribute_encoders_controller.cc @@ -26,8 +26,8 @@ SequentialAttributeEncodersController::SequentialAttributeEncodersController( : sequencer_(std::move(sequencer)) {} SequentialAttributeEncodersController::SequentialAttributeEncodersController( - std::unique_ptr<PointsSequencer> sequencer, int att_id) - : AttributesEncoder(att_id), sequencer_(std::move(sequencer)) {} + std::unique_ptr<PointsSequencer> sequencer, int point_attrib_id) + : AttributesEncoder(point_attrib_id), sequencer_(std::move(sequencer)) {} bool SequentialAttributeEncodersController::Init(PointCloudEncoder *encoder, const PointCloud *pc) { diff --git a/extern/draco/draco/src/draco/compression/attributes/sequential_integer_attribute_decoder.cc b/extern/draco/draco/src/draco/compression/attributes/sequential_integer_attribute_decoder.cc index d01fb26aad4..17f32fc1612 100644 --- a/extern/draco/draco/src/draco/compression/attributes/sequential_integer_attribute_decoder.cc +++ b/extern/draco/draco/src/draco/compression/attributes/sequential_integer_attribute_decoder.cc @@ -53,6 +53,11 @@ bool SequentialIntegerAttributeDecoder::DecodeValues( if (!in_buffer->Decode(&prediction_transform_type)) { return false; } + // Check that decoded prediction scheme transform type is valid. + if (prediction_transform_type < PREDICTION_TRANSFORM_NONE || + prediction_transform_type >= NUM_PREDICTION_SCHEME_TRANSFORM_TYPES) { + return false; + } prediction_scheme_ = CreateIntPredictionScheme( static_cast<PredictionSchemeMethod>(prediction_scheme_method), static_cast<PredictionSchemeTransformType>(prediction_transform_type)); @@ -143,8 +148,9 @@ bool SequentialIntegerAttributeDecoder::DecodeIntegerValues( return false; } for (size_t i = 0; i < num_values; ++i) { - if (!in_buffer->Decode(portable_attribute_data + i, num_bytes)) + if (!in_buffer->Decode(portable_attribute_data + i, num_bytes)) { return false; + } } } } @@ -223,12 +229,13 @@ void SequentialIntegerAttributeDecoder::StoreTypedValues(uint32_t num_values) { void SequentialIntegerAttributeDecoder::PreparePortableAttribute( int num_entries, int num_components) { - GeometryAttribute va; - va.Init(attribute()->attribute_type(), nullptr, num_components, DT_INT32, + GeometryAttribute ga; + ga.Init(attribute()->attribute_type(), nullptr, num_components, DT_INT32, false, num_components * DataTypeLength(DT_INT32), 0); - std::unique_ptr<PointAttribute> port_att(new PointAttribute(va)); + std::unique_ptr<PointAttribute> port_att(new PointAttribute(ga)); port_att->SetIdentityMapping(); port_att->Reset(num_entries); + port_att->set_unique_id(attribute()->unique_id()); SetPortableAttribute(std::move(port_att)); } diff --git a/extern/draco/draco/src/draco/compression/attributes/sequential_integer_attribute_encoder.cc b/extern/draco/draco/src/draco/compression/attributes/sequential_integer_attribute_encoder.cc index 2889e0521a0..e66a0a8a40a 100644 --- a/extern/draco/draco/src/draco/compression/attributes/sequential_integer_attribute_encoder.cc +++ b/extern/draco/draco/src/draco/compression/attributes/sequential_integer_attribute_encoder.cc @@ -81,6 +81,9 @@ bool SequentialIntegerAttributeEncoder::TransformAttributeToPortableFormat( value_to_value_map[orig_att->mapped_index(point_ids[i])] = AttributeValueIndex(i); } + if (portable_att->is_mapping_identity()) { + portable_att->SetExplicitMapping(encoder()->point_cloud()->num_points()); + } // Go over all points of the original attribute and update the mapping in // the portable attribute. for (PointIndex i(0); i < encoder()->point_cloud()->num_points(); ++i) { diff --git a/extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_decoder.cc b/extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_decoder.cc index 017344393dc..de36c1c36f2 100644 --- a/extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_decoder.cc +++ b/extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_decoder.cc @@ -14,18 +14,17 @@ // #include "draco/compression/attributes/sequential_normal_attribute_decoder.h" -#include "draco/attributes/attribute_octahedron_transform.h" #include "draco/compression/attributes/normal_compression_utils.h" namespace draco { -SequentialNormalAttributeDecoder::SequentialNormalAttributeDecoder() - : quantization_bits_(-1) {} +SequentialNormalAttributeDecoder::SequentialNormalAttributeDecoder() {} bool SequentialNormalAttributeDecoder::Init(PointCloudDecoder *decoder, int attribute_id) { - if (!SequentialIntegerAttributeDecoder::Init(decoder, attribute_id)) + if (!SequentialIntegerAttributeDecoder::Init(decoder, attribute_id)) { return false; + } // Currently, this encoder works only for 3-component normal vectors. if (attribute()->num_components() != 3) { return false; @@ -41,11 +40,13 @@ bool SequentialNormalAttributeDecoder::DecodeIntegerValues( const std::vector<PointIndex> &point_ids, DecoderBuffer *in_buffer) { #ifdef DRACO_BACKWARDS_COMPATIBILITY_SUPPORTED if (decoder()->bitstream_version() < DRACO_BITSTREAM_VERSION(2, 0)) { - uint8_t quantization_bits; - if (!in_buffer->Decode(&quantization_bits)) { + // Note: in older bitstreams, we do not have a PortableAttribute() decoded + // at this stage so we cannot pass it down to the DecodeParameters() call. + // It still works fine for octahedral transform because it does not need to + // use any data from the attribute. + if (!octahedral_transform_.DecodeParameters(*attribute(), in_buffer)) { return false; } - quantization_bits_ = quantization_bits; } #endif return SequentialIntegerAttributeDecoder::DecodeIntegerValues(point_ids, @@ -56,39 +57,20 @@ bool SequentialNormalAttributeDecoder::DecodeDataNeededByPortableTransform( const std::vector<PointIndex> &point_ids, DecoderBuffer *in_buffer) { if (decoder()->bitstream_version() >= DRACO_BITSTREAM_VERSION(2, 0)) { // For newer file version, decode attribute transform data here. - uint8_t quantization_bits; - if (!in_buffer->Decode(&quantization_bits)) { + if (!octahedral_transform_.DecodeParameters(*GetPortableAttribute(), + in_buffer)) { return false; } - quantization_bits_ = quantization_bits; } // Store the decoded transform data in portable attribute. - AttributeOctahedronTransform octahedral_transform; - octahedral_transform.SetParameters(quantization_bits_); - return octahedral_transform.TransferToAttribute(portable_attribute()); + return octahedral_transform_.TransferToAttribute(portable_attribute()); } bool SequentialNormalAttributeDecoder::StoreValues(uint32_t num_points) { // Convert all quantized values back to floats. - const int num_components = attribute()->num_components(); - const int entry_size = sizeof(float) * num_components; - float att_val[3]; - int quant_val_id = 0; - int out_byte_pos = 0; - const int32_t *const portable_attribute_data = GetPortableAttributeData(); - OctahedronToolBox octahedron_tool_box; - if (!octahedron_tool_box.SetQuantizationBits(quantization_bits_)) - return false; - for (uint32_t i = 0; i < num_points; ++i) { - const int32_t s = portable_attribute_data[quant_val_id++]; - const int32_t t = portable_attribute_data[quant_val_id++]; - octahedron_tool_box.QuantizedOctaherdalCoordsToUnitVector(s, t, att_val); - // Store the decoded floating point value into the attribute buffer. - attribute()->buffer()->Write(out_byte_pos, att_val, entry_size); - out_byte_pos += entry_size; - } - return true; + return octahedral_transform_.InverseTransformAttribute( + *GetPortableAttribute(), attribute()); } } // namespace draco diff --git a/extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_decoder.h b/extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_decoder.h index 860eacb4c84..8c2d801b763 100644 --- a/extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_decoder.h +++ b/extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_decoder.h @@ -15,6 +15,7 @@ #ifndef DRACO_COMPRESSION_ATTRIBUTES_SEQUENTIAL_NORMAL_ATTRIBUTE_DECODER_H_ #define DRACO_COMPRESSION_ATTRIBUTES_SEQUENTIAL_NORMAL_ATTRIBUTE_DECODER_H_ +#include "draco/attributes/attribute_octahedron_transform.h" #include "draco/compression/attributes/prediction_schemes/prediction_scheme_decoder_factory.h" #include "draco/compression/attributes/prediction_schemes/prediction_scheme_normal_octahedron_canonicalized_decoding_transform.h" #include "draco/compression/attributes/prediction_schemes/prediction_scheme_normal_octahedron_decoding_transform.h" @@ -42,7 +43,7 @@ class SequentialNormalAttributeDecoder bool StoreValues(uint32_t num_points) override; private: - int32_t quantization_bits_; + AttributeOctahedronTransform octahedral_transform_; std::unique_ptr<PredictionSchemeTypedDecoderInterface<int32_t>> CreateIntPredictionScheme( diff --git a/extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_encoder.cc b/extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_encoder.cc index 23fa8bb7b39..3c5ef0ebcbc 100644 --- a/extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_encoder.cc +++ b/extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_encoder.cc @@ -20,8 +20,9 @@ namespace draco { bool SequentialNormalAttributeEncoder::Init(PointCloudEncoder *encoder, int attribute_id) { - if (!SequentialIntegerAttributeEncoder::Init(encoder, attribute_id)) + if (!SequentialIntegerAttributeEncoder::Init(encoder, attribute_id)) { return false; + } // Currently this encoder works only for 3-component normal vectors. if (attribute()->num_components() != 3) { return false; @@ -44,9 +45,13 @@ bool SequentialNormalAttributeEncoder::EncodeDataNeededByPortableTransform( bool SequentialNormalAttributeEncoder::PrepareValues( const std::vector<PointIndex> &point_ids, int num_points) { - SetPortableAttribute( - attribute_octahedron_transform_.GeneratePortableAttribute( - *(attribute()), point_ids, num_points)); + auto portable_att = attribute_octahedron_transform_.InitTransformedAttribute( + *(attribute()), point_ids.size()); + if (!attribute_octahedron_transform_.TransformAttribute( + *(attribute()), point_ids, portable_att.get())) { + return false; + } + SetPortableAttribute(std::move(portable_att)); return true; } diff --git a/extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_decoder.cc b/extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_decoder.cc index bf925c4a595..3d306e7dae6 100644 --- a/extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_decoder.cc +++ b/extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_decoder.cc @@ -14,13 +14,12 @@ // #include "draco/compression/attributes/sequential_quantization_attribute_decoder.h" -#include "draco/attributes/attribute_quantization_transform.h" #include "draco/core/quantization_utils.h" namespace draco { -SequentialQuantizationAttributeDecoder::SequentialQuantizationAttributeDecoder() - : quantization_bits_(-1), max_value_dif_(0.f) {} +SequentialQuantizationAttributeDecoder:: + SequentialQuantizationAttributeDecoder() {} bool SequentialQuantizationAttributeDecoder::Init(PointCloudDecoder *decoder, int attribute_id) { @@ -59,62 +58,31 @@ bool SequentialQuantizationAttributeDecoder:: } // Store the decoded transform data in portable attribute; - AttributeQuantizationTransform transform; - transform.SetParameters(quantization_bits_, min_value_.get(), - attribute()->num_components(), max_value_dif_); - return transform.TransferToAttribute(portable_attribute()); + return quantization_transform_.TransferToAttribute(portable_attribute()); } -bool SequentialQuantizationAttributeDecoder::StoreValues(uint32_t num_values) { - return DequantizeValues(num_values); +bool SequentialQuantizationAttributeDecoder::StoreValues(uint32_t num_points) { + return DequantizeValues(num_points); } bool SequentialQuantizationAttributeDecoder::DecodeQuantizedDataInfo() { - const int num_components = attribute()->num_components(); - min_value_ = std::unique_ptr<float[]>(new float[num_components]); - if (!decoder()->buffer()->Decode(min_value_.get(), - sizeof(float) * num_components)) { - return false; - } - if (!decoder()->buffer()->Decode(&max_value_dif_)) { - return false; + // Get attribute used as source for decoding. + auto att = GetPortableAttribute(); + if (att == nullptr) { + // This should happen only in the backward compatibility mode. It will still + // work fine for this case because the only thing the quantization transform + // cares about is the number of components that is the same for both source + // and target attributes. + att = attribute(); } - uint8_t quantization_bits; - if (!decoder()->buffer()->Decode(&quantization_bits) || - quantization_bits > 31) { - return false; - } - quantization_bits_ = quantization_bits; - return true; + return quantization_transform_.DecodeParameters(*att, decoder()->buffer()); } bool SequentialQuantizationAttributeDecoder::DequantizeValues( uint32_t num_values) { // Convert all quantized values back to floats. - const int32_t max_quantized_value = - (1u << static_cast<uint32_t>(quantization_bits_)) - 1; - const int num_components = attribute()->num_components(); - const int entry_size = sizeof(float) * num_components; - const std::unique_ptr<float[]> att_val(new float[num_components]); - int quant_val_id = 0; - int out_byte_pos = 0; - Dequantizer dequantizer; - if (!dequantizer.Init(max_value_dif_, max_quantized_value)) { - return false; - } - const int32_t *const portable_attribute_data = GetPortableAttributeData(); - for (uint32_t i = 0; i < num_values; ++i) { - for (int c = 0; c < num_components; ++c) { - float value = - dequantizer.DequantizeFloat(portable_attribute_data[quant_val_id++]); - value = value + min_value_[c]; - att_val[c] = value; - } - // Store the floating point value into the attribute buffer. - attribute()->buffer()->Write(out_byte_pos, att_val.get(), entry_size); - out_byte_pos += entry_size; - } - return true; + return quantization_transform_.InverseTransformAttribute( + *GetPortableAttribute(), attribute()); } } // namespace draco diff --git a/extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_decoder.h b/extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_decoder.h index c0b7637a750..ad372dcd8a6 100644 --- a/extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_decoder.h +++ b/extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_decoder.h @@ -15,6 +15,7 @@ #ifndef DRACO_COMPRESSION_ATTRIBUTES_SEQUENTIAL_QUANTIZATION_ATTRIBUTE_DECODER_H_ #define DRACO_COMPRESSION_ATTRIBUTES_SEQUENTIAL_QUANTIZATION_ATTRIBUTE_DECODER_H_ +#include "draco/attributes/attribute_quantization_transform.h" #include "draco/compression/attributes/sequential_integer_attribute_decoder.h" #include "draco/draco_features.h" @@ -43,12 +44,7 @@ class SequentialQuantizationAttributeDecoder virtual bool DequantizeValues(uint32_t num_values); private: - // Max number of quantization bits used to encode each component of the - // attribute. - int32_t quantization_bits_; - - std::unique_ptr<float[]> min_value_; - float max_value_dif_; + AttributeQuantizationTransform quantization_transform_; }; } // namespace draco diff --git a/extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_encoder.cc b/extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_encoder.cc index cd5b8b141e0..d3666f7a411 100644 --- a/extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_encoder.cc +++ b/extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_encoder.cc @@ -50,9 +50,11 @@ bool SequentialQuantizationAttributeEncoder::Init(PointCloudEncoder *encoder, &quantization_origin[0]); const float range = encoder->options()->GetAttributeFloat( attribute_id, "quantization_range", 1.f); - attribute_quantization_transform_.SetParameters( - quantization_bits, quantization_origin.data(), - attribute->num_components(), range); + if (!attribute_quantization_transform_.SetParameters( + quantization_bits, quantization_origin.data(), + attribute->num_components(), range)) { + return false; + } } else { // Compute quantization settings from the attribute values. if (!attribute_quantization_transform_.ComputeParameters( @@ -70,9 +72,14 @@ bool SequentialQuantizationAttributeEncoder:: bool SequentialQuantizationAttributeEncoder::PrepareValues( const std::vector<PointIndex> &point_ids, int num_points) { - SetPortableAttribute( - attribute_quantization_transform_.GeneratePortableAttribute( - *(attribute()), point_ids, num_points)); + auto portable_attribute = + attribute_quantization_transform_.InitTransformedAttribute( + *attribute(), point_ids.size()); + if (!attribute_quantization_transform_.TransformAttribute( + *(attribute()), point_ids, portable_attribute.get())) { + return false; + } + SetPortableAttribute(std::move(portable_attribute)); return true; } |