openpilot is an open source driver assistance system. openpilot performs the functions of Automated Lane Centering and Adaptive Cruise Control for over 200 supported car makes and models.
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.

177 lines
5.0 KiB

#include "tools/clip/application.h"
#include <QApplication>
#include <QTranslator>
#include <QWindow>
#include <selfdrive/ui/qt/util.h>
#include <selfdrive/ui/qt/window.h>
#include "recorder/widget.h"
3 months ago
Application::Application(int argc, char *argv[], QObject *parent) : QObject(parent) {
argc_ = argc;
argv_ = argv;
initApp(argc_, argv_);
app = new QApplication(argc_, argv_);
3 months ago
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;
3 months ago
recorder = new Recorder(outputFile.toStdString());
recorder->moveToThread(recorderThread);
3 months ago
connect(recorderThread, &QThread::finished, recorder, &QObject::deleteLater);
connect(app, &QCoreApplication::aboutToQuit, recorderThread, &QThread::quit);
recorderThread->start();
// Initialize and start replay
initReplay(route.toStdString());
replayThread = QThread::create([this, startTime] { startReplay(startTime); });
replayThread->start();
3 months ago
// Frame capture optimization
QElapsedTimer frameTimer;
frameTimer.start();
int64_t lastFrameTime = 0;
const int64_t frameInterval = 1000 / UI_FREQ; // Target frame interval in ms
loop = new QTimer;
connect(loop, &QTimer::timeout, this, [&, frameTimer, lastFrameTime]() mutable {
3 months ago
if (!window->isVisible()) {
return;
}
int64_t currentTime = frameTimer.elapsed();
int64_t elapsedSinceLastFrame = currentTime - lastFrameTime;
// Skip frame if we're ahead of schedule
if (elapsedSinceLastFrame < frameInterval) {
return;
}
QPixmap pixmap = window->grab();
// Only process frame if capture was successful
if (!pixmap.isNull()) {
recorder->saveFrame(std::make_shared<QPixmap>(std::move(pixmap)));
lastFrameTime = currentTime;
}
3 months ago
});
// Use a higher timer resolution for more precise frame timing
loop->setTimerType(Qt::PreciseTimer);
loop->start(1); // Run at highest possible frequency, we'll control frame rate ourselves
3 months ago
window->setAttribute(Qt::WA_DontShowOnScreen);
window->setAttribute(Qt::WA_OpaquePaintEvent);
window->setAttribute(Qt::WA_NoSystemBackground);
window->setAttribute(Qt::WA_TranslucentBackground, false);
window->setAttribute(Qt::WA_AlwaysStackOnTop);
window->setAttribute(Qt::WA_ShowWithoutActivating);
window->setAttribute(Qt::WA_UpdatesDisabled);
window->setAttribute(Qt::WA_StaticContents);
}
3 months ago
void Application::initReplay(const std::string& route) {
3 months ago
std::vector<std::string> allow;
std::vector<std::string> block;
3 months ago
replay = std::make_unique<Replay>(route, allow, block, nullptr, REPLAY_FLAG_NONE);
replay->setSegmentCacheLimit(1);
3 months ago
}
3 months ago
void Application::startReplay(int start) {
3 months ago
if (!replay || !replay->load()) {
qWarning() << "Failed to load replay";
3 months ago
QApplication::instance()->quit();
3 months ago
}
qInfo() << "Replay started.";
replayRunning = true;
3 months ago
replay->setEndSeconds(start + 60);
replay->start(start + 2);
3 months ago
replay->waitUntilEnd();
qInfo() << "Replay ended.";
replayRunning = false;
QMetaObject::invokeMethod(app, "quit", Qt::QueuedConnection);
}
Application::~Application() {
3 months ago
if (replayThread) {
replayThread->quit();
replayThread->wait();
delete replayThread;
}
if (recorderThread) {
recorderThread->quit();
recorderThread->wait();
delete recorderThread;
3 months ago
}
delete recorder;
delete window;
delete loop;
delete app;
}
int Application::exec() const {
3 months ago
// TODO: modify Replay to block until all OnroadWindow required messages have been broadcast at least once
std::this_thread::sleep_for(std::chrono::seconds(8));
setMainWindow(window);
3 months ago
return app->exec();
}