dataload_mcap.cpp
Go to the documentation of this file.
1 #include "dataload_mcap.h"
2 
5 
6 #include "mcap/reader.hpp"
7 #include "dialog_mcap.h"
8 
9 #include <QTextStream>
10 #include <QFile>
11 #include <QMessageBox>
12 #include <QDebug>
13 #include <QSettings>
14 #include <QProgressDialog>
15 #include <QDateTime>
16 #include <QInputDialog>
17 #include <QPushButton>
18 #include <QElapsedTimer>
19 #include <QStandardItemModel>
20 
21 #include <set>
22 
24 {
25 }
26 
28 {
29 }
30 
31 bool DataLoadMCAP::xmlSaveState(QDomDocument& doc, QDomElement& parent_element) const
32 {
33  if (!_dialog_parameters)
34  {
35  return false;
36  }
37  QDomElement elem = doc.createElement("parameters");
38  const auto& params = *_dialog_parameters;
39  elem.setAttribute("use_timestamp", int(params.use_timestamp));
40  elem.setAttribute("clamp_large_arrays", int(params.clamp_large_arrays));
41  elem.setAttribute("max_array_size", params.max_array_size);
42  elem.setAttribute("selected_topics", params.selected_topics.join(';'));
43 
44  parent_element.appendChild(elem);
45  return true;
46 }
47 
48 bool DataLoadMCAP::xmlLoadState(const QDomElement& parent_element)
49 {
50  QDomElement elem = parent_element.firstChildElement("parameters");
51  if (elem.isNull())
52  {
54  return false;
55  }
56  mcap::LoadParams params;
57  params.use_timestamp = bool(elem.attribute("use_timestamp").toInt());
58  params.clamp_large_arrays = bool(elem.attribute("clamp_large_arrays").toInt());
59  params.max_array_size = elem.attribute("max_array_size").toInt();
60  params.selected_topics = elem.attribute("selected_topics").split(';');
61  _dialog_parameters = params;
62  return true;
63 }
64 
65 const std::vector<const char*>& DataLoadMCAP::compatibleFileExtensions() const
66 {
67  static std::vector<const char*> ext = { "mcap", "MCAP" };
68  return ext;
69 }
70 
72 {
73  if (!parserFactories())
74  {
75  throw std::runtime_error("No parsing available");
76  }
77 
78  // open file
80  auto status = reader.open(info->filename.toStdString());
81  if (!status.ok())
82  {
83  QMessageBox::warning(nullptr, "Can't open file",
84  tr("Code: %0\n Message: %1")
85  .arg(int(status.code))
86  .arg(QString::fromStdString(status.message)));
87  return false;
88  }
89 
90  status = reader.readSummary(mcap::ReadSummaryMethod::NoFallbackScan);
91  if (!status.ok())
92  {
93  QMessageBox::warning(nullptr, "Can't open summary of the file",
94  tr("Code: %0\n Message: %1")
95  .arg(int(status.code))
96  .arg(QString::fromStdString(status.message)));
97  return false;
98  }
99  auto statistics = reader.statistics();
100 
101  std::unordered_map<int, mcap::SchemaPtr> mcap_schemas; // schema_id
102  std::unordered_map<int, mcap::ChannelPtr> channels; // channel_id
103  std::unordered_map<int, MessageParserPtr> parsers_by_channel; // channel_id
104 
105  std::unordered_map<int, DataTamerParser::Schema> dt_schames;
106  int total_dt_schemas = 0;
107 
108  std::unordered_set<mcap::ChannelId> channels_containing_datatamer_schema;
109  std::unordered_set<mcap::ChannelId> channels_containing_datatamer_data;
110 
111  for (const auto& [schema_id, schema_ptr] : reader.schemas())
112  {
113  mcap_schemas.insert({ schema_id, schema_ptr });
114  }
115 
116  std::set<QString> notified_encoding_problem;
117 
118  QElapsedTimer timer;
119  timer.start();
120 
121  for (const auto& [channel_id, channel_ptr] : reader.channels())
122  {
123  channels.insert({ channel_id, channel_ptr });
124  const auto& schema = mcap_schemas.at(channel_ptr->schemaId);
125  const auto& topic_name = channel_ptr->topic;
126  std::string definition(reinterpret_cast<const char*>(schema->data.data()),
127  schema->data.size());
128 
129  if (schema->name == "data_tamer_msgs/msg/Schemas")
130  {
131  channels_containing_datatamer_schema.insert(channel_id);
132  total_dt_schemas += statistics->channelMessageCounts.at(channel_id);
133  }
134  if (schema->name == "data_tamer_msgs/msg/Snapshot")
135  {
136  channels_containing_datatamer_data.insert(channel_id);
137  }
138 
139  QString channel_encoding = QString::fromStdString(channel_ptr->messageEncoding);
140  QString schema_encoding = QString::fromStdString(schema->encoding);
141 
142  auto it = parserFactories()->find(channel_encoding);
143 
144  if (it == parserFactories()->end())
145  {
146  it = parserFactories()->find(schema_encoding);
147  }
148 
149  if (it == parserFactories()->end())
150  {
151  // show message only once per encoding type
152  if (notified_encoding_problem.count(schema_encoding) == 0)
153  {
154  notified_encoding_problem.insert(schema_encoding);
155  auto msg = QString("No parser available for encoding [%0] nor [%1]")
156  .arg(channel_encoding)
157  .arg(schema_encoding);
158  QMessageBox::warning(nullptr, "Encoding problem", msg);
159  }
160  continue;
161  }
162 
163  auto& parser_factory = it->second;
164  auto parser =
165  parser_factory->createParser(topic_name, schema->name, definition, plot_data);
166  parsers_by_channel.insert({ channel_ptr->id, parser });
167  };
168 
169  if (!info->plugin_config.hasChildNodes())
170  {
172  }
173 
174  // don't show the dialog if we already loaded the parameters with xmlLoadState
175  if (!_dialog_parameters)
176  {
177  DialogMCAP dialog(channels, mcap_schemas, _dialog_parameters);
178  auto ret = dialog.exec();
179  if (ret != QDialog::Accepted)
180  {
181  return false;
182  }
183  _dialog_parameters = dialog.getParams();
184  }
185 
186  std::unordered_set<int> enabled_channels;
187 
188  for (const auto& [channel_id, parser] : parsers_by_channel)
189  {
190  parser->setLargeArraysPolicy(_dialog_parameters->clamp_large_arrays,
191  _dialog_parameters->max_array_size);
192  parser->enableEmbeddedTimestamp(_dialog_parameters->use_timestamp);
193 
194  QString topic_name = QString::fromStdString(channels[channel_id]->topic);
195  if (_dialog_parameters->selected_topics.contains(topic_name))
196  {
197  enabled_channels.insert(channel_id);
198  }
199  }
200 
201  //-------------------------------------------
202  //---------------- Parse messages -----------
203 
204  auto onProblem = [](const mcap::Status& problem) {
205  qDebug() << QString::fromStdString(problem.message);
206  };
207 
208  auto messages = reader.readMessages(onProblem);
209 
210  QProgressDialog progress_dialog("Loading... please wait", "Cancel", 0, 0, nullptr);
211  progress_dialog.setWindowTitle("Loading the MCAP file");
212  progress_dialog.setModal(true);
213  progress_dialog.setAutoClose(true);
214  progress_dialog.setAutoReset(true);
215  progress_dialog.setMinimumDuration(0);
216  progress_dialog.show();
217  progress_dialog.setValue(0);
218 
219  size_t msg_count = 0;
220 
221  for (const auto& msg_view : messages)
222  {
223  if (enabled_channels.count(msg_view.channel->id) == 0)
224  {
225  continue;
226  }
227 
228  // MCAP always represents publishTime in nanoseconds
229  double timestamp_sec = double(msg_view.message.publishTime) * 1e-9;
230  auto parser_it = parsers_by_channel.find(msg_view.channel->id);
231  if (parser_it == parsers_by_channel.end())
232  {
233  qDebug() << "Skipping channeld id: " << msg_view.channel->id;
234  continue;
235  }
236 
237  auto parser = parser_it->second;
238  MessageRef msg(msg_view.message.data, msg_view.message.dataSize);
239  parser->parseMessage(msg, timestamp_sec);
240 
241  if (msg_count++ % 1000 == 0)
242  {
243  QApplication::processEvents();
244  if (progress_dialog.wasCanceled())
245  {
246  break;
247  }
248  }
249  }
250 
251  reader.close();
252  qDebug() << "Loaded file in " << timer.elapsed() << "milliseconds";
253  return true;
254 }
DialogMCAP
Definition: dialog_mcap.h:14
PJ::FileLoadInfo
Definition: dataloader_base.h:18
reader.hpp
mcap::ReadSummaryMethod::NoFallbackScan
@ NoFallbackScan
Parse the Summary section to produce seeking indexes and summary statistics. If the Summary section i...
mcap::LoadParams
Definition: dataload_params.h:8
definition
const char * definition()
DataLoadMCAP::~DataLoadMCAP
virtual ~DataLoadMCAP() override
Definition: dataload_mcap.cpp:27
dialog_mcap.h
mcap::Status
Wraps a status code and string message carrying additional context.
Definition: errors.hpp:35
PJ::FileLoadInfo::plugin_config
QDomDocument plugin_config
Saved configuration from a previous run or a Layout file.
Definition: dataloader_base.h:25
arg
auto arg(const Char *name, const T &arg) -> detail::named_arg< Char, T >
Definition: core.h:1875
mcap::McapReader
Provides a read interface to an MCAP file.
Definition: reader.hpp:271
mqtt_test_proto.msg
msg
Definition: mqtt_test_proto.py:43
dataload_mcap.h
mcap::LoadParams::max_array_size
unsigned max_array_size
Definition: dataload_params.h:11
mcap::LoadParams::clamp_large_arrays
bool clamp_large_arrays
Definition: dataload_params.h:12
start_test_publisher.topic
topic
Definition: start_test_publisher.py:22
data_tamer_parser.hpp
DataLoadMCAP::xmlLoadState
bool xmlLoadState(const QDomElement &parent_element) override
Override this method to load the status of the plugin from XML.
Definition: dataload_mcap.cpp:48
DialogMCAP::getParams
mcap::LoadParams getParams() const
Definition: dialog_mcap.cpp:80
DataLoadMCAP::xmlSaveState
bool xmlSaveState(QDomDocument &doc, QDomElement &parent_element) const override
Override this method to save the status of the plugin to XML.
Definition: dataload_mcap.cpp:31
DataLoadMCAP::DataLoadMCAP
DataLoadMCAP()
Definition: dataload_mcap.cpp:23
udp_client.parser
parser
Definition: udp_client.py:9
DataLoadMCAP::compatibleFileExtensions
virtual const std::vector< const char * > & compatibleFileExtensions() const override
Provide a list of file extensions that this plugin can open.
Definition: dataload_mcap.cpp:65
mcap::LoadParams::selected_topics
QStringList selected_topics
Definition: dataload_params.h:10
reader
static const char * reader(lua_State *L, void *ud, size_t *size)
Definition: luac.c:126
PJ::MessageRef
Definition: messageparser_base.h:28
mcap::LoadParams::use_timestamp
bool use_timestamp
Definition: dataload_params.h:13
PJ::PlotDataMapRef
Definition: plotdata.h:34
DataLoadMCAP::readDataFromFile
virtual bool readDataFromFile(PJ::FileLoadInfo *fileload_info, PlotDataMapRef &destination) override
Definition: dataload_mcap.cpp:71
eprosima::fastcdr::nullopt
static constexpr nullopt_t nullopt
nullopt is a constant of type nullopt_t that is used to indicate optional type with uninitialized sta...
Definition: optional.hpp:40
messageparser_base.h
mqtt_test.ret
ret
Definition: mqtt_test.py:30
DataLoadMCAP::_dialog_parameters
std::optional< mcap::LoadParams > _dialog_parameters
Definition: dataload_mcap.h:38
PJ::DataLoader::parserFactories
const ParserFactories * parserFactories() const
Definition: dataloader_base.h:52
PJ::FileLoadInfo::filename
QString filename
name of the file to open
Definition: dataloader_base.h:21


plotjuggler
Author(s): Davide Faconti
autogenerated on Mon Nov 11 2024 03:23:44