00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include <QDateTime>
00017 #include <QTimer>
00018 #include <QKeyEvent>
00019
00020
00021 #include <mythcontext.h>
00022 #include <mythuihelper.h>
00023 #include <mythmainwindow.h>
00024 #include <mythdialogbox.h>
00025
00026
00027 #include "zmliveplayer.h"
00028 #include "zmclient.h"
00029
00030
00031 #define MAX_IMAGE_SIZE (2048*1536*3)
00032
00033 const int FRAME_UPDATE_TIME = 1000 / 10;
00034
00035 ZMLivePlayer::ZMLivePlayer(MythScreenStack *parent)
00036 :MythScreenType(parent, "zmliveview")
00037 {
00038 m_paused = false;
00039
00040 m_players = NULL;
00041 m_monitors = NULL;
00042 m_monitorLayout = 1;
00043
00044 GetMythUI()->DoDisableScreensaver();
00045
00046 m_frameTimer = new QTimer(this);
00047 connect(m_frameTimer, SIGNAL(timeout()), this,
00048 SLOT(updateFrame()));
00049
00050 getMonitorList();
00051 }
00052
00053 bool ZMLivePlayer::Create(void)
00054 {
00055 bool foundtheme = false;
00056
00057
00058 foundtheme = LoadWindowFromXML("zoneminder-ui.xml", "zmliveplayer", this);
00059
00060 if (!foundtheme)
00061 return false;
00062
00063 if (!hideAll())
00064 return false;
00065
00066 if (!initMonitorLayout())
00067 return false;
00068
00069 return true;
00070 }
00071
00072 MythUIType* ZMLivePlayer::GetMythUIType(const QString &name, bool optional)
00073 {
00074 MythUIType *type = GetChild(name);
00075
00076 if (!optional && !type)
00077 throw name;
00078
00079 return type;
00080 }
00081
00082 bool ZMLivePlayer::hideAll(void)
00083 {
00084 try
00085 {
00086
00087 GetMythUIType("name1-1")->SetVisible(false);
00088 GetMythUIType("status1-1")->SetVisible(false);
00089 GetMythUIType("frame1-1")->SetVisible(false);
00090
00091
00092 for (int x = 1; x < 3; x++)
00093 {
00094 GetMythUIType(QString("name2-%1").arg(x))->SetVisible(false);
00095 GetMythUIType(QString("status2-%1").arg(x))->SetVisible(false);
00096 GetMythUIType(QString("frame2-%1").arg(x))->SetVisible(false);
00097 }
00098
00099
00100 for (int x = 1; x < 5; x++)
00101 {
00102 GetMythUIType(QString("name3-%1").arg(x))->SetVisible(false);
00103 GetMythUIType(QString("status3-%1").arg(x))->SetVisible(false);
00104 GetMythUIType(QString("frame3-%1").arg(x))->SetVisible(false);
00105 }
00106 }
00107 catch (const QString &name)
00108 {
00109 LOG(VB_GENERAL, LOG_ERR,
00110 QString("Theme is missing a critical theme element ('%1')")
00111 .arg(name));
00112 return false;
00113 }
00114
00115 return true;
00116 }
00117
00118 bool ZMLivePlayer::initMonitorLayout()
00119 {
00120
00121 if (m_monitors->empty())
00122 {
00123 LOG(VB_GENERAL, LOG_ERR, "Cannot find any monitors. Bailing out!");
00124 ShowOkPopup(tr("Can't show live view.") + "\n" +
00125 tr("You don't have any monitors defined!"));
00126 return false;
00127 }
00128
00129 setMonitorLayout(gCoreContext->GetNumSetting("ZoneMinderLiveLayout", 1), true);
00130 m_frameTimer->start(FRAME_UPDATE_TIME);
00131
00132 return true;
00133 }
00134
00135 ZMLivePlayer::~ZMLivePlayer()
00136 {
00137 gCoreContext->SaveSetting("ZoneMinderLiveLayout", m_monitorLayout);
00138
00139 GetMythUI()->DoRestoreScreensaver();
00140
00141 if (m_players)
00142 {
00143 QString s = "";
00144 Player *p;
00145 vector<Player*>::iterator i = m_players->begin();
00146 for (; i != m_players->end(); ++i)
00147 {
00148 p = *i;
00149 if (s != "")
00150 s += ",";
00151 s += QString("%1").arg(p->getMonitor()->id);
00152 }
00153
00154 gCoreContext->SaveSetting("ZoneMinderLiveCameras", s);
00155
00156 delete m_players;
00157 }
00158 else
00159 gCoreContext->SaveSetting("ZoneMinderLiveCameras", "");
00160
00161 if (m_monitors)
00162 delete m_monitors;
00163
00164 delete m_frameTimer;
00165 }
00166
00167 bool ZMLivePlayer::keyPressEvent(QKeyEvent *event)
00168 {
00169 if (GetFocusWidget() && GetFocusWidget()->keyPressEvent(event))
00170 return true;
00171
00172 bool handled = false;
00173 QStringList actions;
00174 handled = GetMythMainWindow()->TranslateKeyPress("TV Playback", event, actions);
00175
00176 for (int i = 0; i < actions.size() && !handled; i++)
00177 {
00178 QString action = actions[i];
00179 handled = true;
00180
00181 if (action == "PAUSE")
00182 {
00183 if (m_paused)
00184 {
00185 m_frameTimer->start(FRAME_UPDATE_TIME);
00186 m_paused = false;
00187 }
00188 else
00189 {
00190 m_frameTimer->stop();
00191 m_paused = true;
00192 }
00193 }
00194 else if (action == "INFO")
00195 {
00196 m_monitorLayout++;
00197 if (m_monitorLayout > 3)
00198 m_monitorLayout = 1;
00199 setMonitorLayout(m_monitorLayout);
00200 }
00201 else if (action == "1" || action == "2" || action == "3" ||
00202 action == "4" || action == "5" || action == "6" ||
00203 action == "7" || action == "8" || action == "9")
00204 changePlayerMonitor(action.toInt());
00205 else
00206 handled = false;
00207 }
00208
00209 if (!handled && MythScreenType::keyPressEvent(event))
00210 handled = true;
00211
00212 return handled;
00213 }
00214
00215 void ZMLivePlayer::changePlayerMonitor(int playerNo)
00216 {
00217 if (playerNo > (int)m_players->size())
00218 return;
00219
00220 m_frameTimer->stop();
00221
00222 int oldMonID = m_players->at(playerNo - 1)->getMonitor()->id;
00223 Monitor *mon;
00224
00225
00226 vector<Monitor*>::iterator i = m_monitors->begin();
00227 for (; i != m_monitors->end(); ++i)
00228 {
00229 mon = *i;
00230 if (oldMonID == mon->id)
00231 {
00232 break;
00233 }
00234 }
00235
00236
00237 if (i != m_monitors->end())
00238 ++i;
00239
00240
00241 if (i == m_monitors->end())
00242 i = m_monitors->begin();
00243
00244 mon = *i;
00245
00246 m_players->at(playerNo - 1)->setMonitor(mon);
00247 m_players->at(playerNo - 1)->updateCamera();
00248
00249 m_frameTimer->start(FRAME_UPDATE_TIME);
00250 }
00251
00252 void ZMLivePlayer::updateFrame()
00253 {
00254 class ZMClient *zm = ZMClient::get();
00255 if (!zm)
00256 return;
00257
00258 static unsigned char buffer[MAX_IMAGE_SIZE];
00259 m_frameTimer->stop();
00260
00261
00262 QList<int> monList;
00263 Player *p;
00264 vector<Player*>::iterator i = m_players->begin();
00265 for (; i != m_players->end(); ++i)
00266 {
00267 p = *i;
00268 if (!monList.contains(p->getMonitor()->id))
00269 monList.append(p->getMonitor()->id);
00270 }
00271
00272 for (int x = 0; x < monList.count(); x++)
00273 {
00274 QString status;
00275 int frameSize = zm->getLiveFrame(monList[x], status, buffer, sizeof(buffer));
00276
00277 if (frameSize > 0 && !status.startsWith("ERROR"))
00278 {
00279
00280 Player *p;
00281 vector<Player*>::iterator i = m_players->begin();
00282 for (; i != m_players->end(); ++i)
00283 {
00284 p = *i;
00285 if (p->getMonitor()->id == monList[x])
00286 {
00287 if (p->getMonitor()->status != status)
00288 {
00289 p->getMonitor()->status = status;
00290 p->updateStatus();
00291 }
00292 p->updateFrame(buffer);
00293 }
00294 }
00295 }
00296 }
00297
00298 m_frameTimer->start(FRAME_UPDATE_TIME);
00299 }
00300
00301 void ZMLivePlayer::stopPlayers()
00302 {
00303 m_frameTimer->stop();
00304 }
00305
00306 void ZMLivePlayer::setMonitorLayout(int layout, bool restore)
00307 {
00308 QStringList monList = gCoreContext->GetSetting("ZoneMinderLiveCameras", "").split(",");
00309 m_monitorLayout = layout;
00310
00311 if (m_players)
00312 {
00313 stopPlayers();
00314 delete m_players;
00315 }
00316
00317 m_players = new vector<Player *>;
00318 m_monitorCount = 1;
00319
00320 if (layout == 1)
00321 m_monitorCount = 1;
00322 else if (layout == 2)
00323 m_monitorCount = 2;
00324 else if (layout == 3)
00325 m_monitorCount = 4;
00326 else if (layout == 4)
00327 m_monitorCount = 9;
00328
00329 hideAll();
00330
00331 uint monitorNo = 1;
00332
00333 for (int x = 1; x <= m_monitorCount; x++)
00334 {
00335 Monitor *monitor = NULL;
00336
00337 if (restore)
00338 {
00339 if (x <= (int) monList.size())
00340 {
00341 QString s = monList.at(x - 1);
00342 int monID = s.toInt();
00343
00344
00345 vector<Monitor*>::iterator i = m_monitors->begin();
00346 for (; i != m_monitors->end(); ++i)
00347 {
00348 if ((*i)->id == monID)
00349 {
00350 monitor = *i;
00351 break;
00352 }
00353 }
00354 }
00355 }
00356
00357 if (!monitor)
00358 monitor = m_monitors->at(monitorNo - 1);
00359
00360 MythUIImage *frameImage = dynamic_cast<MythUIImage *> (GetChild(QString("frame%1-%2").arg(layout).arg(x)));
00361 MythUIText *cameraText = dynamic_cast<MythUIText *> (GetChild(QString("name%1-%2").arg(layout).arg(x)));
00362 MythUIText *statusText = dynamic_cast<MythUIText *> (GetChild(QString("status%1-%2").arg(layout).arg(x)));
00363
00364 Player *p = new Player();
00365 p->setMonitor(monitor);
00366 p->setWidgets(frameImage, statusText, cameraText);
00367 p->updateCamera();
00368 m_players->push_back(p);
00369
00370 monitorNo++;
00371 if (monitorNo > m_monitors->size())
00372 monitorNo = 1;
00373 }
00374
00375 updateFrame();
00376 }
00377
00378 void ZMLivePlayer::getMonitorList(void)
00379 {
00380 if (!m_monitors)
00381 m_monitors = new vector<Monitor *>;
00382
00383 m_monitors->clear();
00384
00385 if (class ZMClient *zm = ZMClient::get())
00386 zm->getMonitorList(m_monitors);
00387 }
00388
00390
00391 Player::Player() :
00392 m_frameImage(NULL), m_statusText(NULL), m_cameraText(NULL),
00393 m_image(NULL), m_rgba(NULL)
00394 {
00395 }
00396
00397 Player::~Player()
00398 {
00399 if (m_rgba)
00400 free(m_rgba);
00401 }
00402
00403 void Player::setMonitor(Monitor *mon)
00404 {
00405 m_monitor = *mon;
00406
00407 if (m_rgba)
00408 free(m_rgba);
00409
00410 m_rgba = (uchar *) malloc(m_monitor.width * m_monitor.height * 4);
00411 }
00412
00413 void Player::setWidgets(MythUIImage *image, MythUIText *status, MythUIText *camera)
00414 {
00415 m_frameImage = image;
00416 m_statusText = status;
00417 m_cameraText = camera;
00418
00419 if (m_frameImage)
00420 m_frameImage->SetVisible(true);
00421
00422 if (m_statusText)
00423 m_statusText->SetVisible(true);
00424
00425 if (m_cameraText)
00426 m_cameraText->SetVisible(true);
00427 }
00428
00429 void Player::updateFrame(const unsigned char* buffer)
00430 {
00431 unsigned int pos_data;
00432 unsigned int pos_rgba = 0;
00433 unsigned int r,g,b;
00434
00435 if (m_monitor.palette == MP_GREY)
00436 {
00437
00438 for (pos_data = 0; pos_data < (unsigned int) (m_monitor.width * m_monitor.height); )
00439 {
00440 m_rgba[pos_rgba++] = buffer[pos_data];
00441 m_rgba[pos_rgba++] = buffer[pos_data];
00442 m_rgba[pos_rgba++] = buffer[pos_data++];
00443 m_rgba[pos_rgba++] = 0xff;
00444 }
00445 }
00446 else
00447 {
00448
00449 for (pos_data = 0; pos_data < (unsigned int) (m_monitor.width * m_monitor.height * 3); )
00450 {
00451 r = buffer[pos_data++];
00452 g = buffer[pos_data++];
00453 b = buffer[pos_data++];
00454 if (m_monitor.isV4L2)
00455 {
00456 m_rgba[pos_rgba++] = g;
00457 m_rgba[pos_rgba++] = r;
00458 m_rgba[pos_rgba++] = b;
00459 m_rgba[pos_rgba++] = 0xff;
00460 }
00461 else
00462 {
00463 m_rgba[pos_rgba++] = b;
00464 m_rgba[pos_rgba++] = g;
00465 m_rgba[pos_rgba++] = r;
00466 m_rgba[pos_rgba++] = 0xff;
00467 }
00468 }
00469 }
00470
00471 QImage image(m_rgba, m_monitor.width, m_monitor.height, QImage::Format_ARGB32);
00472
00473 if (m_image)
00474 {
00475 m_image->DownRef();
00476 m_image = NULL;
00477 }
00478
00479 m_image = GetMythMainWindow()->GetCurrentPainter()->GetFormatImage();
00480 m_image->Assign(image);
00481 m_image->UpRef();
00482
00483 m_frameImage->SetImage(m_image);
00484 }
00485
00486 void Player::updateStatus(void)
00487 {
00488 if (m_statusText)
00489 {
00490 if (m_monitor.status == "Alarm" || m_monitor.status == "Error")
00491 m_statusText->SetFontState("alarm");
00492 else if (m_monitor.status == "Alert")
00493 m_statusText->SetFontState("alert");
00494 else
00495 m_statusText->SetFontState("idle");
00496
00497 m_statusText->SetText(m_monitor.status);
00498 }
00499 }
00500
00501 void Player::updateCamera()
00502 {
00503 if (m_cameraText)
00504 m_cameraText->SetText(m_monitor.name);
00505 }