|
#include "Application.hpp"
|
|
|
|
#include <Wt/WApplication>
|
|
#include <Wt/WDialog>
|
|
#include <Wt/WPushButton>
|
|
#include <Wt/WPopupMenu>
|
|
#include <Wt/WEnvironment>
|
|
|
|
#include "Interface.hpp"
|
|
|
|
|
|
Application::Application(const Wt::WEnvironment &env)
|
|
: WQApplication(env,true)
|
|
{
|
|
qsrand(QDateTime::currentSecsSinceEpoch());
|
|
sessionId=QString::number(qrand());
|
|
|
|
enableUpdates();
|
|
|
|
setTheme(&_bootstrapTheme);
|
|
root()->setLayout(&_mainLayout);
|
|
|
|
setConfirmCloseMessage("Use release button to let this view being indexed for other clients."
|
|
" Otherwise session expire needed to unlock this camera.");
|
|
|
|
//_revisionInfo.setTextFormat(Wt::XHTMLUnsafeText);
|
|
// _revisionInfo.setText("<center>Revision: 4</center>");
|
|
// _revisionInfo.setMaximumSize(Wt::WLength(),Wt::WLength(40));
|
|
// _revisionInfo.setMargin(0);
|
|
|
|
_mainLayout.setContentsMargins(0,0,0,0);
|
|
_mainLayout.setSpacing(0);
|
|
_mainLayout.addWidget(&_table);
|
|
// _mainLayout.addWidget(&_revisionInfo);
|
|
// _mainLayout.setStretchFactor(&_table,1000);
|
|
// _mainLayout.setStretchFactor(&_revisionInfo,1);
|
|
|
|
_table.setStyleClass("table table-bordered table-hover table-condensed table-striped");
|
|
}
|
|
|
|
void Application::getProcessors()
|
|
{
|
|
_table.clear();
|
|
|
|
_table.setHeaderCount(1);
|
|
_table.setWidth(Wt::WLength("100%"));
|
|
|
|
_table.elementAt(0, 0)->addWidget(new Wt::WText("URL"));
|
|
_table.elementAt(0, 1)->addWidget(new Wt::WText("Frame Rate"));
|
|
_table.elementAt(0, 2)->addWidget(new Wt::WText("State"));
|
|
|
|
_processors=akil::AnalyticsInterface::getCameras();
|
|
|
|
int row=1;
|
|
for (QHash<QString,akil::Camera>::iterator it=_processors.begin();
|
|
it!=_processors.end();
|
|
++it)
|
|
{
|
|
_table.elementAt(row, 0)->addWidget(new Wt::WText(Wt::toWString(it.value().url)));
|
|
_table.elementAt(row, 1)->addWidget(new Wt::WText(Wt::toWString(QString::number(it.value().fps))));
|
|
|
|
Wt::WPushButton *button = new Wt::WPushButton;
|
|
|
|
Wt::WPopupMenu *menu = new Wt::WPopupMenu();
|
|
Wt::WMenuItem *attachItem=menu->addItem("Attach");
|
|
Wt::WMenuItem *createItem=menu->addItem("Create");
|
|
Wt::WMenuItem *deleteItem=menu->addItem("Delete");
|
|
Wt::WMenuItem *forceRelease=menu->addItem("Force Release");
|
|
forceRelease->hide();
|
|
|
|
button->setText(it.value().processor ? "Running": "Null");
|
|
|
|
if(it.value().processor)
|
|
{
|
|
attachItem->show();
|
|
deleteItem->show();
|
|
createItem->hide();
|
|
}
|
|
else
|
|
{
|
|
attachItem->hide();
|
|
deleteItem->hide();
|
|
createItem->show();
|
|
}
|
|
|
|
createItem->triggered().connect(std::bind([=] ()
|
|
{
|
|
Wt::WDialog *dialog = new Wt::WDialog("Tracking Resolution");
|
|
|
|
Wt::WLineEdit *edit = new Wt::WLineEdit(dialog->contents());
|
|
edit->setPlaceholderText("Width of the internal processing resolution");
|
|
|
|
dialog->contents()->addStyleClass("form-group");
|
|
|
|
Wt::WPushButton *ok = new Wt::WPushButton("Set", dialog->footer());
|
|
|
|
Wt::WPushButton *cancel = new Wt::WPushButton("Cancel", dialog->footer());
|
|
dialog->rejectWhenEscapePressed();
|
|
cancel->setDefault(true);
|
|
|
|
ok->clicked().connect(std::bind([=] ()
|
|
{
|
|
if(!edit->text().empty())
|
|
{dialog->accept();}
|
|
}));
|
|
|
|
cancel->clicked().connect(dialog, &Wt::WDialog::reject);
|
|
|
|
dialog->finished().connect(std::bind([=]()
|
|
{
|
|
if (dialog->result() == Wt::WDialog::Accepted)
|
|
{
|
|
button->setText("Ready");
|
|
|
|
_trackingWidth=Wt::toQString(edit->text()).toInt();
|
|
|
|
it.value().trackingWidth=_trackingWidth;
|
|
akil::AnalyticsInterface::updateProcessor(it.value(),false);
|
|
|
|
_newInstance=true;
|
|
|
|
createItem->hide();
|
|
attachItem->show();
|
|
deleteItem->show();
|
|
}
|
|
|
|
delete dialog;
|
|
}));
|
|
|
|
dialog->show();
|
|
}));
|
|
|
|
attachItem->triggered().connect(std::bind([=] ()
|
|
{
|
|
if(it.value().processor)
|
|
{
|
|
if(it.value().processor->attached())
|
|
{
|
|
button->setText("Already attached. Re-create, force release or wait for release");
|
|
|
|
attachItem->hide();
|
|
deleteItem->show();
|
|
createItem->hide();
|
|
forceRelease->show();
|
|
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
forceRelease->hide();
|
|
_view=it.value().processor;
|
|
_license=it.value().license;
|
|
}
|
|
}
|
|
|
|
_url=it.value().url;
|
|
_fps=it.value().fps;
|
|
_trackingWidth=it.value().trackingWidth;
|
|
_okay=true;
|
|
|
|
localLoop();
|
|
}));
|
|
|
|
deleteItem->triggered().connect(std::bind([=] ()
|
|
{
|
|
if(it.value().processor)
|
|
{
|
|
akil::AnalyticsInterface::deleteProcessor(it.value());
|
|
it.value().processor.reset();
|
|
}
|
|
|
|
createItem->show();
|
|
attachItem->hide();
|
|
deleteItem->hide();
|
|
forceRelease->hide();
|
|
|
|
button->setText("Null");
|
|
}));
|
|
|
|
forceRelease->triggered().connect(std::bind([=] ()
|
|
{
|
|
if(it.value().processor)
|
|
{
|
|
forceRelease->hide();
|
|
_view=it.value().processor;
|
|
_license=it.value().license;
|
|
}
|
|
|
|
_url=it.value().url;
|
|
_fps=it.value().fps;
|
|
_trackingWidth=it.value().trackingWidth;
|
|
_okay=true;
|
|
}));
|
|
|
|
button->setMenu(menu);
|
|
|
|
_table.elementAt(row, 2)->addWidget(button);
|
|
|
|
++row;
|
|
}
|
|
}
|
|
|
|
std::shared_ptr<SingleView> Application::getView() const
|
|
{return _view;}
|
|
|
|
QString Application::getSessionId() const
|
|
{return sessionId;}
|
|
|
|
void Application::localLoop()
|
|
{
|
|
if(!_once)
|
|
{
|
|
getProcessors();
|
|
_once=true;
|
|
}
|
|
|
|
if(_okay && _fps && _trackingWidth && !_url.isEmpty())
|
|
{
|
|
if(_view)
|
|
{
|
|
_analytics=_view->_analytics;
|
|
_streamer=_view->_streamer;
|
|
}
|
|
else
|
|
{
|
|
_analytics=new akil::VideoAnalytics(_trackingWidth,_fps,0);
|
|
QThread* _analyticsThread=new QThread;
|
|
_analytics->moveToThread(_analyticsThread);
|
|
QObject::connect(_analyticsThread,&QThread::started,_analytics,&akil::VideoAnalytics::init);
|
|
QObject::connect(_analyticsThread,&QThread::finished,_analyticsThread,&QThread::deleteLater);
|
|
QObject::connect(_analyticsThread,&QThread::finished,_analytics,&akil::VideoAnalytics::deleteLater);
|
|
_analyticsThread->start();
|
|
|
|
#ifdef CUDA_AVAILABLE
|
|
_streamer=new akil::Streamer(akil::VisionUtils::GpuDecoder,"",0);
|
|
#else
|
|
_streamer=new akil::Streamer(akil::VisionUtils::SoftwareDecoder,"",0);
|
|
#endif
|
|
QThread *_streamerThread=new QThread;
|
|
_streamer->moveToThread(_streamerThread);
|
|
QObject::connect(_streamerThread,&QThread::started,_streamer,&akil::Streamer::init);
|
|
QObject::connect(_streamerThread,&QThread::finished,_streamerThread,&QThread::deleteLater);
|
|
QObject::connect(_streamerThread,&QThread::finished,_streamer,&akil::Streamer::deleteLater);
|
|
_streamerThread->start();
|
|
}
|
|
|
|
start();
|
|
}
|
|
else
|
|
{Wt::WTimer::singleShot(100,this,&Application::localLoop);}
|
|
}
|
|
|
|
void Application::create()
|
|
{localLoop();}
|
|
|
|
void Application::start()
|
|
{
|
|
bool again=true;
|
|
|
|
_okay=false;
|
|
|
|
if(_analytics && _streamer)
|
|
{
|
|
if(_analytics->initializationDone() && _streamer->initializationDone())
|
|
{
|
|
WQApplication::UpdateLock lock(this);
|
|
|
|
if(lock)
|
|
{
|
|
again=false;
|
|
|
|
if(!_view)
|
|
{
|
|
_streamer->setSource(_url);
|
|
_view=std::make_shared<SingleView>(this,_analytics,_streamer,_fps);
|
|
}
|
|
|
|
akil::Camera current(_trackingWidth,_view,_url,_fps,_license,sessionId);
|
|
akil::AnalyticsInterface::updateProcessor(current);
|
|
|
|
if(_newInstance)
|
|
{
|
|
itsTimeToBindCamera();
|
|
_newInstance=false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(again)
|
|
{Wt::WTimer::singleShot(100,this,&Application::start);}
|
|
}
|
|
|
|
void Application::viewReleased()
|
|
{
|
|
// if(_view)
|
|
{_mainLayout.removeWidget(_view.get());}
|
|
// _mainLayout.removeWidget(&_revisionInfo);
|
|
_mainLayout.removeWidget(&_table);
|
|
|
|
_mainLayout.addWidget(&_table);
|
|
// _mainLayout.addWidget(&_revisionInfo);
|
|
// _mainLayout.setStretchFactor(&_table,1000);
|
|
// _mainLayout.setStretchFactor(&_revisionInfo,1);
|
|
_table.show();
|
|
|
|
root()->setLayout(&_mainLayout);
|
|
|
|
_once=false;
|
|
_okay=false;
|
|
_fps=0;
|
|
_trackingWidth=0;
|
|
_url.clear();
|
|
|
|
_view.reset();
|
|
|
|
_analytics=nullptr;
|
|
_streamer=nullptr;
|
|
_processors.clear();
|
|
_license=akil::Camera::License();
|
|
|
|
localLoop();
|
|
}
|
|
|
|
void Application::getReleaseCommand(QString toBeReleasedSession,QString newOwnerToBeNotified)
|
|
{
|
|
Application *app = dynamic_cast<Application *>(WQApplication::instance());
|
|
if (app)
|
|
{
|
|
if(toBeReleasedSession==app->getSessionId())
|
|
{
|
|
if(toBeReleasedSession!=newOwnerToBeNotified)
|
|
{
|
|
app->viewReleased();
|
|
app->refresh();
|
|
}
|
|
|
|
if(!newOwnerToBeNotified.isEmpty())
|
|
{Wt::WServer::instance()->postAll(boost::bind(&Application::otherPeerReleasedCam
|
|
,newOwnerToBeNotified));}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Application::otherPeerReleasedCam(QString newOwnerToBeNotified)
|
|
{
|
|
Application *app = dynamic_cast<Application *>(WQApplication::instance());
|
|
if (app)
|
|
{
|
|
if(newOwnerToBeNotified==app->getSessionId())
|
|
{app->itsTimeToBindCamera();}
|
|
}
|
|
}
|
|
|
|
void Application::itsTimeToBindCamera()
|
|
{
|
|
_view->_app=this;
|
|
_view->setAttached(true);
|
|
|
|
Wt::WQApplication::UpdateLock lock(wApp);
|
|
if(lock)
|
|
{
|
|
_mainLayout.removeWidget(&_table);
|
|
// _mainLayout.removeWidget(&_revisionInfo);
|
|
|
|
_mainLayout.addWidget(_view.get());
|
|
// _mainLayout.addWidget(&_revisionInfo);
|
|
|
|
// _mainLayout.setStretchFactor(_view.get(),1000);
|
|
// _mainLayout.setStretchFactor(&_revisionInfo,1);
|
|
|
|
root()->setLayout(&_mainLayout);
|
|
root()->addWidget(_view.get());
|
|
|
|
_view->show();
|
|
_table.hide();
|
|
|
|
if(!_view->getProcessFired())
|
|
{_view->process();}
|
|
}
|
|
}
|
|
|
|
void Application::finalize()
|
|
{
|
|
qDebug()<<"finalize";
|
|
|
|
WQApplication::finalize();
|
|
}
|
|
|
|
void Application::unload()
|
|
{
|
|
qDebug()<<"unload";
|
|
|
|
WQApplication::unload();
|
|
}
|
|
|
|
void Application::destroy()
|
|
{
|
|
qDebug()<<"destroy";
|
|
}
|
|
|
|
Application::~Application()
|
|
{
|
|
qDebug()<<"dtor";
|
|
}
|