5 #include "mcap/reader.hpp"
10 #include <QMessageBox>
13 #include <QProgressDialog>
15 #include <QInputDialog>
16 #include <QPushButton>
17 #include <QElapsedTimer>
18 #include <QStandardItemModel>
19 #include <QtConcurrent>
37 QDomElement elem = doc.createElement(
"parameters");
39 elem.setAttribute(
"use_timestamp",
int(params.use_timestamp));
40 elem.setAttribute(
"use_mcap_log_time",
int(params.use_mcap_log_time));
41 elem.setAttribute(
"clamp_large_arrays",
int(params.clamp_large_arrays));
42 elem.setAttribute(
"max_array_size", params.max_array_size);
43 elem.setAttribute(
"selected_topics", params.selected_topics.join(
';'));
45 parent_element.appendChild(elem);
51 QDomElement elem = parent_element.firstChildElement(
"parameters");
58 params.
use_timestamp = bool(elem.attribute(
"use_timestamp").toInt());
69 static std::vector<const char*> ext = {
"mcap",
"MCAP" };
77 throw std::runtime_error(
"No parsing available");
81 mcap::McapReader reader;
82 auto status = reader.open(info->
filename.toStdString());
85 QMessageBox::warning(
nullptr,
"Can't open file",
86 tr(
"Code: %0\n Message: %1")
87 .
arg(
int(status.code))
88 .arg(QString::fromStdString(status.message)));
92 status = reader.readSummary(mcap::ReadSummaryMethod::NoFallbackScan);
95 QMessageBox::warning(
nullptr,
"Can't open summary of the file",
96 tr(
"Code: %0\n Message: %1")
97 .
arg(
int(status.code))
98 .arg(QString::fromStdString(status.message)));
102 ->second.pushBack({ 0, std::any(info->
filename.toStdString()) });
104 const std::optional<mcap::Statistics> statistics = reader.statistics();
106 std::unordered_map<int, mcap::SchemaPtr> mcap_schemas;
107 std::unordered_map<int, mcap::ChannelPtr> channels;
108 std::unordered_map<int, MessageParserPtr> parsers_by_channel;
110 int total_dt_schemas = 0;
112 std::unordered_set<mcap::ChannelId> channels_containing_datatamer_schema;
113 std::unordered_set<mcap::ChannelId> channels_containing_datatamer_data;
115 for (
const auto& [schema_id, schema_ptr] : reader.schemas())
117 mcap_schemas.insert({ schema_id, schema_ptr });
125 for (
const auto& [channel_id, channel_ptr] : reader.channels())
127 channels.insert({ channel_id, channel_ptr });
133 std::unordered_map<uint16_t, uint64_t> msg_count;
136 msg_count = statistics->channelMessageCounts;
139 auto ret = dialog.exec();
140 if (
ret != QDialog::Accepted)
147 std::set<QString> notified_encoding_problem;
152 struct FailedParserInfo
154 std::set<std::string> topics;
155 std::string error_message;
158 std::map<std::string, FailedParserInfo> parsers_blacklist;
160 for (
const auto& [channel_id, channel_ptr] : channels)
162 const auto& topic_name = channel_ptr->topic;
163 const QString topic_name_qt = QString::fromStdString(topic_name);
169 const auto& schema = mcap_schemas.at(channel_ptr->schemaId);
172 auto blacklist_it = parsers_blacklist.find(schema->name);
173 if (blacklist_it != parsers_blacklist.end())
175 blacklist_it->second.topics.insert(channel_ptr->topic);
179 const std::string
definition(
reinterpret_cast<const char*
>(schema->data.data()),
180 schema->data.size());
182 if (schema->name ==
"data_tamer_msgs/msg/Schemas")
184 channels_containing_datatamer_schema.insert(channel_id);
185 total_dt_schemas += statistics->channelMessageCounts.at(channel_id);
187 if (schema->name ==
"data_tamer_msgs/msg/Snapshot")
189 channels_containing_datatamer_data.insert(channel_id);
192 QString channel_encoding = QString::fromStdString(channel_ptr->messageEncoding);
193 QString schema_encoding = QString::fromStdString(schema->encoding);
205 if (notified_encoding_problem.count(schema_encoding) == 0)
207 notified_encoding_problem.insert(schema_encoding);
208 auto msg = QString(
"No parser available for encoding [%0] nor [%1]")
209 .arg(channel_encoding)
210 .arg(schema_encoding);
211 QMessageBox::warning(
nullptr,
"Encoding problem",
msg);
218 auto& parser_factory = it->second;
220 parser_factory->createParser(topic_name, schema->name,
definition, plot_data);
222 parsers_by_channel.insert({ channel_ptr->id,
parser });
224 catch (std::exception& e)
226 FailedParserInfo failed_parser_info;
227 failed_parser_info.error_message = e.what();
228 failed_parser_info.topics.insert(channel_ptr->topic);
229 parsers_blacklist.insert({ schema->name, failed_parser_info });
234 if (!parsers_blacklist.empty())
236 QString error_message;
237 for (
const auto& [schema_name, failed_parser_info] : parsers_blacklist)
239 error_message += QString(
"Schema: %1\n").arg(QString::fromStdString(schema_name));
240 error_message += QString(
"Error: %1\n")
241 .arg(QString::fromStdString(failed_parser_info.error_message));
242 error_message += QString(
"Topics affected: \n");
243 for (
const auto&
topic : failed_parser_info.topics)
245 error_message += QString(
" - %1\n").arg(QString::fromStdString(
topic));
247 error_message +=
"------------------\n";
249 QMessageBox::warning(
nullptr,
"Parser Error", error_message);
252 std::unordered_set<int> enabled_channels;
253 size_t total_msgs = 0;
255 for (
const auto& [channel_id,
parser] : parsers_by_channel)
261 QString topic_name = QString::fromStdString(channels[channel_id]->
topic);
264 enabled_channels.insert(channel_id);
265 auto mcap_channel = channels[channel_id]->id;
266 if (statistics->channelMessageCounts.count(mcap_channel) != 0)
268 total_msgs += statistics->channelMessageCounts.at(channel_id);
276 auto onProblem = [](
const mcap::Status& problem) {
277 qDebug() << QString::fromStdString(problem.message);
280 auto messages = reader.readMessages(onProblem);
282 QProgressDialog progress_dialog(
"Loading... please wait",
"Cancel", 0, 0,
nullptr);
283 progress_dialog.setWindowTitle(
"Loading the MCAP file");
284 progress_dialog.setWindowModality(Qt::ApplicationModal);
285 progress_dialog.setRange(0, std::max<size_t>(total_msgs, 1) - 1);
286 progress_dialog.show();
287 progress_dialog.setValue(0);
289 size_t msg_count = 0;
291 for (
const auto& msg_view : messages)
293 if (enabled_channels.count(msg_view.channel->id) == 0)
299 double timestamp_sec = double(msg_view.message.publishTime) * 1e-9;
302 timestamp_sec = double(msg_view.message.logTime) * 1e-9;
304 auto parser_it = parsers_by_channel.find(msg_view.channel->id);
305 if (parser_it == parsers_by_channel.end())
307 qDebug() <<
"Skipping channeld id: " << msg_view.channel->id;
311 auto parser = parser_it->second;
312 MessageRef msg(msg_view.message.data, msg_view.message.dataSize);
313 parser->parseMessage(
msg, timestamp_sec);
315 if (msg_count++ % 1000 == 0)
317 progress_dialog.setValue(msg_count);
318 QApplication::processEvents();
319 if (progress_dialog.wasCanceled())
327 qDebug() <<
"Loaded file in " << timer.elapsed() <<
"milliseconds";