dataload_mcap.cpp
Go to the documentation of this file.
1 #include "dataload_mcap.h"
2 #include <QTextStream>
3 #include <QFile>
4 #include <QMessageBox>
5 #include <QDebug>
6 #include <QSettings>
7 #include <QProgressDialog>
8 #include <QDateTime>
9 #include <QInputDialog>
10 #include <QPushButton>
11 #include "QSyntaxStyle"
12 
13 #include "mcap/reader.hpp"
14 #include "dialog_mcap.h"
15 #include "PlotJuggler/fmt/format.h"
16 
17 #include <QStandardItemModel>
18 
20 {
21 
22 }
23 
25 {
26 
27 }
28 
29 const std::vector<const char*>& DataLoadMCAP::compatibleFileExtensions() const
30 {
31  static std::vector<const char*> ext = {"mcap", "MCAP"};
32  return ext;
33 }
34 
35 
37 {
38  if( !parserFactories() )
39  {
40  throw std::runtime_error("No parsing available");
41  }
42  // open file
43  std::ifstream input(info->filename.toStdString(), std::ios::binary);
44  mcap::FileStreamReader data_source(input);
45 
46  // read metainfo
47  mcap::TypedRecordReader type_reader(data_source, 8);
48 
49  std::unordered_map<int, mcap::SchemaPtr> schemas; // schema_id
50  std::unordered_map<int, mcap::ChannelPtr> channels; // channel_id
51  std::unordered_map<int, MessageParserPtr> parsers_by_channel; // channel_id
52 
53  type_reader.onSchema = [&](const mcap::SchemaPtr recordPtr,
54  mcap::ByteOffset, std::optional<mcap::ByteOffset>)
55  {
56  schemas.insert( {recordPtr->id, recordPtr} );
57  };
58 
59  type_reader.onChannel = [&](const mcap::ChannelPtr recordPtr,
60  mcap::ByteOffset, std::optional<mcap::ByteOffset>)
61  {
62  if(channels.count(recordPtr->id) != 0)
63  {
64  return;
65  }
66  channels.insert( {recordPtr->id, recordPtr} );
67 
68  auto schema = schemas.at(recordPtr->schemaId);
69  const auto& topic_name = recordPtr->topic;
70  std::string definition(reinterpret_cast<const char*>(schema->data.data()),
71  schema->data.size());
72 
73  QString encoding = QString::fromStdString(recordPtr->messageEncoding);
74 
75  auto it = parserFactories()->find( encoding );
76 
77  if(it == parserFactories()->end() )
78  {
79  encoding = QString::fromStdString(schema->encoding);
80  it = parserFactories()->find( encoding );
81  }
82 
83  if(it == parserFactories()->end() )
84  {
85  throw std::runtime_error(
86  fmt::format("No parsing available for encoding [{}] nor [{}]",
87  schema->encoding, recordPtr->messageEncoding) );
88  }
89 
90  auto& parser_factory = it->second;
91  auto parser = parser_factory->createParser(topic_name,
92  schema->name,
93  definition,
94  plot_data);
95  parsers_by_channel.insert( {recordPtr->id, parser} );
96  };
97 
98  bool running = true;
99  while (running)
100  {
101  running = type_reader.next();
102  if (!type_reader.status().ok())
103  {
104  QMessageBox::warning(nullptr, tr("MCAP parsing"),
105  QString("Error reading the MCAP file:\n%1.\n%2")
106  .arg(info->filename)
107  .arg(QString::fromStdString(type_reader.status().message)),
108  QMessageBox::Cancel);
109  return false;
110  }
111  }
112 
113  DialogMCAP dialog(channels, schemas);
114  auto ret = dialog.exec();
115  if (ret != QDialog::Accepted)
116  {
117  return false;
118  }
119 
120  auto dialog_params = dialog.getParams();
121 
122  std::unordered_set<int> enabled_channels;
123 
124  for (const auto& [channel_id, parser] : parsers_by_channel)
125  {
126  parser->setLargeArraysPolicy(dialog_params.clamp_large_arrays,
127  dialog_params.max_array_size);
128 
129  QString topic_name = QString::fromStdString(channels[channel_id]->topic);
130  if( dialog_params.selected_topics.contains(topic_name) )
131  {
132  enabled_channels.insert(channel_id);
133  }
134  }
135 
136  //-------------------------------------------
137  //---------------- Parse messages -----------
138  mcap::McapReader msg_reader;
139  auto status = msg_reader.open(data_source);
140  if (!status.ok())
141  {
142  auto msg = QString::fromStdString(status.message);
143  QMessageBox::warning(nullptr, "MCAP parsing",
144  QString("Error reading the MCAP file: %1").arg(msg),
145  QMessageBox::Cancel);
146  return false;
147  }
148 
149  auto onProblem = [](const mcap::Status& problem) {
150  qDebug() << QString::fromStdString(problem.message);
151  };
152 
153  auto messages = msg_reader.readMessages(onProblem);
154 
155  QProgressDialog progress_dialog("Loading... please wait",
156  "Cancel",
157  0, 0, nullptr);
158  progress_dialog.setModal(true);
159  progress_dialog.setAutoClose(true);
160  progress_dialog.setAutoReset(true);
161  progress_dialog.setMinimumDuration(0);
162  progress_dialog.show();
163  progress_dialog.setValue(0);
164 
165  size_t msg_count = 0;
166 
167  for (const auto& msg_view : messages)
168  {
169  if( enabled_channels.count(msg_view.channel->id) == 0 )
170  {
171  continue;
172  }
173 
174  // MCAP always represents publishTime in nanoseconds
175  double timestamp_sec = double(msg_view.message.publishTime) * 1e-9;
176 
177  auto parser_it = parsers_by_channel.find(msg_view.channel->id);
178  if( parser_it == parsers_by_channel.end() )
179  {
180  qDebug() << "Skipping channeld id: " << msg_view.channel->id;
181  continue;
182  }
183 
184  auto parser = parser_it->second;
185  MessageRef msg(msg_view.message.data, msg_view.message.dataSize);
186  parser->parseMessage(msg, timestamp_sec);
187 
188  if (msg_count++ % 1000 == 0)
189  {
190  QApplication::processEvents();
191  if (progress_dialog.wasCanceled())
192  {
193  break;
194  }
195  }
196  }
197 
198  msg_reader.close();
199  return true;
200 }
201 
std::string message
Definition: errors.hpp:35
Wraps a status code and string message carrying additional context.
Definition: errors.hpp:33
std::function< void(const SchemaPtr, ByteOffset, std::optional< ByteOffset >)> onSchema
Definition: reader.hpp:476
bool ok() const
Definition: errors.hpp:103
IReadable implementation wrapping a std::ifstream input file stream.
Definition: reader.hpp:89
Status open(IReadable &reader)
Opens an MCAP file for reading from an already constructed IReadable implementation.
auto arg(const Char *name, const T &arg) -> detail::named_arg< Char, T >
Definition: core.h:1736
QString filename
name of the file to open
const ParserFactories * parserFactories() const
const Status & status() const
std::shared_ptr< Schema > SchemaPtr
Definition: types.hpp:172
uint64_t ByteOffset
Definition: types.hpp:19
virtual const std::vector< const char * > & compatibleFileExtensions() const override
Provide a list of file extensions that this plugin can open.
std::shared_ptr< Channel > ChannelPtr
Definition: types.hpp:173
virtual ~DataLoadMCAP() override
LinearMessageView readMessages(Timestamp startTime=0, Timestamp endTime=MaxTime)
Returns an iterable view with begin() and end() methods for iterating Messages in the MCAP file...
virtual bool readDataFromFile(PJ::FileLoadInfo *fileload_info, PlotDataMapRef &destination) override
void close()
Closes the MCAP file, clearing any internal data structures and state and dropping the data source re...
const char * definition()
std::function< void(const ChannelPtr, ByteOffset, std::optional< ByteOffset >)> onChannel
Definition: reader.hpp:477
A mid-level interface for parsing and validating MCAP records from a data source. ...
Definition: reader.hpp:473
std::basic_string< Char > format(const text_style &ts, const S &format_str, const Args &... args)
Definition: color.h:583
Params getParams() const
Definition: dialog_mcap.cpp:68
Provides a read interface to an MCAP file.
Definition: reader.hpp:207


plotjuggler
Author(s): Davide Faconti
autogenerated on Mon Jun 19 2023 03:01:01