|
MythTV
0.26-pre
|
00001 /* ============================================================ 00002 * This program is free software; you can redistribute it 00003 * and/or modify it under the terms of the GNU General 00004 * Public License as published bythe Free Software Foundation; 00005 * either version 2, or (at your option) 00006 * any later version. 00007 * 00008 * This program is distributed in the hope that it will be useful, 00009 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00010 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00011 * GNU General Public License for more details. 00012 * 00013 * ============================================================ */ 00014 00015 // qt 00016 #include <QDateTime> 00017 #include <QTimer> 00018 #include <QKeyEvent> 00019 00020 // myth 00021 #include <mythcontext.h> 00022 #include <mythuihelper.h> 00023 #include <mythmainwindow.h> 00024 #include <mythdialogbox.h> 00025 00026 // zoneminder 00027 #include "zmliveplayer.h" 00028 #include "zmclient.h" 00029 00030 // the maximum image size we are ever likely to get from ZM 00031 #define MAX_IMAGE_SIZE (2048*1536*3) 00032 00033 const int FRAME_UPDATE_TIME = 1000 / 10; // try to update the frame 10 times a second 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 // Load the theme for this screen 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 // one player layout 00087 GetMythUIType("name1-1")->SetVisible(false); 00088 GetMythUIType("status1-1")->SetVisible(false); 00089 GetMythUIType("frame1-1")->SetVisible(false); 00090 00091 // two player layout 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 // four player layout 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 // if we haven't got any monitors there's not much we can do so bail out! 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 // find the old monitor ID in the list of available monitors 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 // get the next monitor in the list 00237 if (i != m_monitors->end()) 00238 ++i; 00239 00240 // wrap around to the start if we've reached the end 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 // get a list of monitor id's that need updating 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 // update each player that is displaying this monitor 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 // try to find a monitor that matches the monID 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 // grey palette 00438 for (pos_data = 0; pos_data < (unsigned int) (m_monitor.width * m_monitor.height); ) 00439 { 00440 m_rgba[pos_rgba++] = buffer[pos_data]; //b 00441 m_rgba[pos_rgba++] = buffer[pos_data]; //g 00442 m_rgba[pos_rgba++] = buffer[pos_data++]; //r 00443 m_rgba[pos_rgba++] = 0xff; //a 00444 } 00445 } 00446 else 00447 { 00448 // all other color palettes 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 }
1.7.6.1