| 
 | 1 | +// SPDX-License-Identifier: BSD-3-Clause  | 
 | 2 | +// SPDX-FileCopyrightText: Czech Technical University in Prague .. 2019, paplhjak  | 
 | 3 | + | 
 | 4 | +#include <dynamic_reconfigure/Config.h>  | 
 | 5 | +#include <point_cloud_transport/point_cloud_codec.h>  | 
 | 6 | +#include <ros/console.h>  | 
 | 7 | +#include <ros/time.h>  | 
 | 8 | +#include <rosbag/bag.h>  | 
 | 9 | +#include <rosbag/view.h>  | 
 | 10 | +#include <sensor_msgs/PointCloud2.h>  | 
 | 11 | + | 
 | 12 | +int main(int argc, char** argv)  | 
 | 13 | +{  | 
 | 14 | +  ros::console::initialize();  | 
 | 15 | +  ros::Time::init();  | 
 | 16 | +    | 
 | 17 | +  point_cloud_transport::PointCloudCodec pct;  | 
 | 18 | +    | 
 | 19 | +  std::string codec = "draco";  | 
 | 20 | +  dynamic_reconfigure::Config config;  | 
 | 21 | +  if (argc > 2)  | 
 | 22 | +    codec = argv[2];  | 
 | 23 | +  else  | 
 | 24 | +  {  | 
 | 25 | +    config.ints.emplace_back();  | 
 | 26 | +    config.ints[0].name = "quantization_POSITION";  | 
 | 27 | +    config.ints[0].value = 10;  | 
 | 28 | +  }  | 
 | 29 | +  auto encoder = pct.getEncoderByName(codec);  | 
 | 30 | +  if (!encoder)  | 
 | 31 | +    return 1;  | 
 | 32 | +    | 
 | 33 | +  ROS_INFO("Found encoder: %s", encoder->getTransportName().c_str());  | 
 | 34 | +    | 
 | 35 | +  rosbag::Bag bag;  | 
 | 36 | +  bag.open(argv[1], rosbag::bagmode::Read);  | 
 | 37 | + | 
 | 38 | +  for (const auto& m: rosbag::View(bag))  | 
 | 39 | +  {  | 
 | 40 | +    sensor_msgs::PointCloud2::ConstPtr i = m.instantiate<sensor_msgs::PointCloud2>();  | 
 | 41 | +    if (i != nullptr)  | 
 | 42 | +    {  | 
 | 43 | +      //  | 
 | 44 | +      // Encode the message normally via C++ API  | 
 | 45 | +      //  | 
 | 46 | +      auto rawLen = ros::serialization::serializationLength(*i);  | 
 | 47 | +      auto msg = encoder->encode(*i, config);  | 
 | 48 | +      if (!msg)  // msg is of type cras::expected; if it evaluates to false, it has .error(), otherwise it has .value()  | 
 | 49 | +        ROS_ERROR("%s", msg.error().c_str());  | 
 | 50 | +      else if (!msg.value())  // .value() can be nullptr if the encoder did not return anything for this input  | 
 | 51 | +        ROS_INFO("No message produced");  | 
 | 52 | +      else  // ->value() is shorthand for .value().value() (unpacking cras::expected, and then cras::optional)  | 
 | 53 | +        ROS_INFO_THROTTLE(1.0, "ENCODE Raw size: %zu, compressed size: %u, ratio: %.2f %%, compressed type: %s",  | 
 | 54 | +                          i->data.size(), msg->value().size(), 100.0 * msg->value().size() / rawLen,  | 
 | 55 | +                          msg->value().getDataType().c_str());  | 
 | 56 | + | 
 | 57 | +      //  | 
 | 58 | +      // Decode using C API; this is much more cumbersome, but it allows writing bindings in other languages.  | 
 | 59 | +      //  | 
 | 60 | +        | 
 | 61 | +      // Convert config to shapeshifter  | 
 | 62 | +      dynamic_reconfigure::Config configMsg;  | 
 | 63 | +      topic_tools::ShapeShifter configShifter;  | 
 | 64 | +      cras::msgToShapeShifter(configMsg, configShifter);  | 
 | 65 | +        | 
 | 66 | +      // Prepare output allocators; this is a very rough idea, they can probably be written much better.  | 
 | 67 | +      // Each dynamically sized output of the C API is exported via calling the allocator with a suitable size and  | 
 | 68 | +      // writing the result to the allocated buffer.  | 
 | 69 | +      sensor_msgs::PointCloud2 raw;  | 
 | 70 | +      uint32_t numFields;  | 
 | 71 | +      static std::vector<char*> fieldNames;  | 
 | 72 | +      fieldNames.clear();  | 
 | 73 | +      cras::allocator_t fieldNamesAllocator = [](size_t size) {  | 
 | 74 | +        fieldNames.push_back(new char[size]); return reinterpret_cast<void*>(fieldNames.back());};  | 
 | 75 | +      static std::vector<uint32_t> fieldOffsets;  | 
 | 76 | +      fieldOffsets.clear();  | 
 | 77 | +      cras::allocator_t fieldOffsetsAllocator = [](size_t) {  | 
 | 78 | +        fieldOffsets.push_back(0); return reinterpret_cast<void*>(&fieldOffsets.back());};  | 
 | 79 | +      static std::vector<uint8_t> fieldDatatypes;  | 
 | 80 | +      fieldDatatypes.clear();  | 
 | 81 | +      cras::allocator_t fieldDatatypesAllocator = [](size_t) {  | 
 | 82 | +        fieldDatatypes.push_back(0); return reinterpret_cast<void*>(&fieldDatatypes.back());};  | 
 | 83 | +      static std::vector<uint32_t> fieldCounts;  | 
 | 84 | +      fieldCounts.clear();  | 
 | 85 | +      cras::allocator_t fieldCountsAllocator = [](size_t) {  | 
 | 86 | +        fieldCounts.push_back(0); return reinterpret_cast<void*>(&fieldCounts.back());};  | 
 | 87 | +      static std::vector<uint8_t> data;  | 
 | 88 | +      data.clear();  | 
 | 89 | +      cras::allocator_t dataAllocator = [](size_t size) {  | 
 | 90 | +        data.resize(size); return reinterpret_cast<void*>(data.data());};  | 
 | 91 | +      static char* errorString = nullptr;  | 
 | 92 | +      cras::allocator_t errorStringAllocator = [](size_t size) {  | 
 | 93 | +        errorString = new char[size]; return reinterpret_cast<void*>(errorString); };  | 
 | 94 | +        | 
 | 95 | +      // Call the C API  | 
 | 96 | +      bool success = pointCloudTransportCodecsDecode(  | 
 | 97 | +          "draco", msg->value().getDataType().c_str(), msg->value().getMD5Sum().c_str(),  | 
 | 98 | +          cras::getBufferLength(msg->value()), cras::getBuffer(msg->value()), raw.height, raw.width,  | 
 | 99 | +          numFields, fieldNamesAllocator, fieldOffsetsAllocator, fieldDatatypesAllocator, fieldCountsAllocator,  | 
 | 100 | +          raw.is_bigendian, raw.point_step, raw.row_step, dataAllocator, raw.is_dense,  | 
 | 101 | +          cras::getBufferLength(configShifter), cras::getBuffer(configShifter), errorStringAllocator  | 
 | 102 | +      );  | 
 | 103 | + | 
 | 104 | +      if (success)  | 
 | 105 | +      {  | 
 | 106 | +        // Reconstruct the fields  | 
 | 107 | +        for (size_t j = 0; j < numFields; ++j)  | 
 | 108 | +        {  | 
 | 109 | +          sensor_msgs::PointField field;  | 
 | 110 | +          field.name = fieldNames[j];  | 
 | 111 | +          field.offset = fieldOffsets[j];  | 
 | 112 | +          field.datatype = fieldDatatypes[j];  | 
 | 113 | +          field.count = fieldCounts[j];  | 
 | 114 | +          raw.fields.push_back(field);  | 
 | 115 | +        }  | 
 | 116 | +        ROS_INFO_THROTTLE(1.0, "DECODE Raw size: %zu, compressed size: %zu, num_fields %zu, field1 %s",  | 
 | 117 | +                          data.size(), cras::getBufferLength(msg->value()), fieldNames.size(), fieldNames[0]);  | 
 | 118 | +        // ROS_INFO_STREAM_THROTTLE(1.0, raw);  | 
 | 119 | +        raw.data = data;  | 
 | 120 | +      }  | 
 | 121 | +      else  | 
 | 122 | +      {  | 
 | 123 | +        ROS_ERROR("%s", errorString);  | 
 | 124 | +      }  | 
 | 125 | +    }  | 
 | 126 | +  }  | 
 | 127 | +}  | 
0 commit comments