You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
139 lines
3.8 KiB
139 lines
3.8 KiB
#include "tools/clip/application.h"
|
|
|
|
#include <QApplication>
|
|
#include <QTranslator>
|
|
#include <selfdrive/ui/qt/util.h>
|
|
#include <selfdrive/ui/qt/window.h>
|
|
|
|
#include "recorder/widget.h"
|
|
|
|
Application::Application(int argc, char *argv[], QObject *parent) : QObject(parent) {
|
|
argc_ = argc;
|
|
argv_ = argv;
|
|
|
|
initApp(argc_, argv_);
|
|
|
|
app = new QApplication(argc_, argv_);
|
|
|
|
QCommandLineParser parser;
|
|
parser.setApplicationDescription("Clip your ride!");
|
|
parser.addHelpOption();
|
|
|
|
const QCommandLineOption start({"s", "start"}, "start time", "start");
|
|
parser.addOption(start);
|
|
|
|
const QCommandLineOption output({"o", "output"}, "output file", "output");
|
|
parser.addOption(output);
|
|
|
|
parser.addPositionalArgument("route", "route string");
|
|
|
|
parser.process(*app);
|
|
|
|
int startTime = 0;
|
|
if (parser.isSet(start)) {
|
|
bool ok;
|
|
int parsed = parser.value(start).toInt(&ok);
|
|
if (!ok) {
|
|
qDebug() << "start time must be an integer\n";
|
|
fprintf(stderr, "%s", parser.helpText().toStdString().c_str());
|
|
exit(1);
|
|
}
|
|
startTime = parsed;
|
|
}
|
|
|
|
if (!parser.isSet(output)) {
|
|
qDebug() << "output is required\n";
|
|
fprintf(stderr, "%s", parser.helpText().toStdString().c_str());
|
|
exit(1);
|
|
}
|
|
QString outputFile = parser.value(output);
|
|
|
|
QString route;
|
|
QStringList positionalArgs = parser.positionalArguments();
|
|
if (!positionalArgs.isEmpty()) {
|
|
route = positionalArgs.at(0);
|
|
} else {
|
|
qDebug() << "No file specified\n";
|
|
fprintf(stderr, "%s", parser.helpText().toStdString().c_str());
|
|
exit(1);
|
|
}
|
|
|
|
QTranslator translator;
|
|
QString translation_file = QString::fromStdString(Params().get("LanguageSetting"));
|
|
if (!translator.load(QString(":/%1").arg(translation_file)) && translation_file.length()) {
|
|
qCritical() << "Failed to load translation file:" << translation_file;
|
|
}
|
|
|
|
app->installTranslator(&translator);
|
|
|
|
window = new OnroadWindow();
|
|
|
|
recorderThread = new QThread;
|
|
recorder = new Recorder(outputFile.toStdString());
|
|
recorder->moveToThread(recorderThread);
|
|
QObject::connect(recorderThread, &QThread::finished, recorder, &QObject::deleteLater);
|
|
|
|
QObject::connect(window, &OnroadWindow::redrew, this, [&]() {
|
|
recorder->saveFrame(std::make_shared<QPixmap>(std::move(window->grab())));
|
|
}, Qt::DirectConnection);
|
|
|
|
QObject::connect(app, &QCoreApplication::aboutToQuit, recorderThread, &QThread::quit);
|
|
|
|
window->setAttribute(Qt::WA_DontShowOnScreen);
|
|
window->setAttribute(Qt::WA_Mapped);
|
|
window->setAttribute(Qt::WA_NoSystemBackground);
|
|
recorderThread->start();
|
|
|
|
// Initialize and start replay
|
|
initReplay(route.toStdString());
|
|
replayThread = QThread::create([this, startTime] { startReplay(startTime); });
|
|
replayThread->start();
|
|
}
|
|
|
|
void Application::initReplay(const std::string& route) {
|
|
std::vector<std::string> allow;
|
|
std::vector<std::string> block;
|
|
replay = std::make_unique<Replay>(route, allow, block, nullptr, REPLAY_FLAG_NONE);
|
|
replay->setSegmentCacheLimit(1);
|
|
}
|
|
|
|
void Application::startReplay(int start) {
|
|
if (!replay || !replay->load()) {
|
|
qWarning() << "Failed to load replay";
|
|
QApplication::instance()->quit();
|
|
}
|
|
|
|
qInfo() << "Replay started.";
|
|
replayRunning = true;
|
|
replay->setEndSeconds(start + 60);
|
|
replay->start(start + 2);
|
|
replay->waitUntilEnd();
|
|
qInfo() << "Replay ended.";
|
|
replayRunning = false;
|
|
QMetaObject::invokeMethod(app, "quit", Qt::QueuedConnection);
|
|
}
|
|
|
|
Application::~Application() {
|
|
if (replayThread) {
|
|
replayThread->quit();
|
|
replayThread->wait();
|
|
delete replayThread;
|
|
}
|
|
|
|
if (recorderThread) {
|
|
recorderThread->quit();
|
|
recorderThread->wait();
|
|
}
|
|
|
|
delete window;
|
|
delete app;
|
|
}
|
|
|
|
int Application::exec() const {
|
|
// TODO: modify Replay to block until all OnroadWindow required messages have been broadcast at least once
|
|
std::this_thread::sleep_for(std::chrono::seconds(5));
|
|
setMainWindow(window);
|
|
return app->exec();
|
|
}
|
|
|
|
|
|
|