MythTV  master
zmplayer.cpp
Go to the documentation of this file.
1 /* ============================================================
2  * This program is free software; you can redistribute it
3  * and/or modify it under the terms of the GNU General
4  * Public License as published bythe Free Software Foundation;
5  * either version 2, or (at your option)
6  * any later version.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * ============================================================ */
14 
15 // C
16 #include <cstdlib>
17 
18 // C++
19 #include <chrono>
20 #include <iostream>
21 
22 // Qt
23 #include <QKeyEvent>
24 #include <QTimer>
25 
26 // MythTV
27 #include <mythcontext.h>
28 #include <mythdbcon.h>
29 #include <mythuihelper.h>
30 #include <mythmainwindow.h>
31 #include <mythdate.h>
32 
33 // zoneminder
34 #include "zmclient.h"
35 #include "zmplayer.h"
36 
37 using namespace std::chrono_literals;
38 
39 ZMPlayer::ZMPlayer(MythScreenStack *parent, const char *name,
40  std::vector<Event *> *eventList, size_t *currentEvent)
41  :MythScreenType(parent, name),
42  m_currentEvent(currentEvent),
43  m_eventList(eventList), m_frameList(new std::vector<Frame*>),
44  m_frameTimer(new QTimer(this))
45 {
46  connect(m_frameTimer, &QTimer::timeout, this,
48 }
49 
51 {
52  stopPlayer();
53 
54  m_frameTimer->deleteLater();
55 
56  delete m_frameList;
57 }
58 
60 {
61  m_frameTimer->stop();
62 }
63 
64 bool ZMPlayer::Create(void)
65 {
66  // Load the theme for this screen
67  bool foundtheme = LoadWindowFromXML("zoneminder-ui.xml", "zmplayer", this);
68  if (!foundtheme)
69  return false;
70 
71  bool err = false;
72 
73  UIUtilE::Assign(this, m_frameImageFS, "framefsimage", &err);
74  UIUtilE::Assign(this, m_frameImage, "frameimage", &err);
75  UIUtilE::Assign(this, m_noEventsText, "noevents_text", &err);
76  UIUtilE::Assign(this, m_eventText, "event_text", &err);
77  UIUtilE::Assign(this, m_cameraText, "camera_text", &err);
78  UIUtilE::Assign(this, m_frameText, "frame_text", &err);
79  UIUtilE::Assign(this, m_dateText, "date_text", &err);
80 
81  UIUtilW::Assign(this, m_playButton, "play_button");
82  UIUtilW::Assign(this, m_deleteButton, "delete_button");
83  UIUtilW::Assign(this, m_prevButton, "prev_button");
84  UIUtilW::Assign(this, m_nextButton, "next_button");
85 
86  if (err)
87  {
88  LOG(VB_GENERAL, LOG_ERR, "Cannot load screen 'zmplayer'");
89  return false;
90  }
91 
92  if (m_playButton)
93  {
94  m_playButton->SetText(tr("Pause"));
96  }
97 
98  if (m_deleteButton)
99  {
100  m_deleteButton->SetText(tr("Delete"));
102  }
103 
104  if (m_prevButton)
105  {
106  m_prevButton->SetText(tr("Previous"));
108  }
109 
110  if (m_nextButton)
111  {
112  m_nextButton->SetText(tr("Next"));
114  }
115 
116  // hide the fullscreen image
117  m_frameImageFS->SetVisible(false);
119 
120  BuildFocusList();
121 
123 
124  getEventInfo();
125 
126  return true;
127 }
128 
130 {
131  m_frameTimer->stop();
132 
133  if (*m_currentEvent == static_cast<size_t>(-1))
134  {
135  stopPlayer();
136 
137  if (m_noEventsText)
138  m_noEventsText->SetVisible(true);
139 
140  m_activeFrameImage->SetFilename(QString("mz_black.png"));
142 
143  m_eventText->Reset();
144  m_cameraText->Reset();
145  m_frameText->Reset();
146  m_dateText->Reset();
147 
148  return;
149  }
150 
151  if (m_noEventsText)
152  m_noEventsText->SetVisible(false);
153 
154  Event *event = m_eventList->at(*m_currentEvent);
155  if (!event)
156  return;
157 
158  m_curFrame = 1;
159 
160  m_eventText->SetText(event->eventName() + QString(" (%1/%2)")
161  .arg((*m_currentEvent) + 1)
162  .arg(m_eventList->size()));
163  m_cameraText->SetText(event->monitorName());
166  event->startTime(),
168 
169  // get frames data
170  m_frameList->clear();
171  if (class ZMClient *zm = ZMClient::get())
172  {
173  zm->getFrameList(event->eventID(), m_frameList);
174  m_frameText->SetText(QString("%1/%2").arg(m_curFrame).arg(m_frameList->size()));
175  getFrame();
176  }
177 }
178 
179 bool ZMPlayer::keyPressEvent(QKeyEvent *event)
180 {
181  if (GetFocusWidget()->keyPressEvent(event))
182  return true;
183 
184  QStringList actions;
185  bool handled = GetMythMainWindow()->TranslateKeyPress("TV Playback", event, actions);
186 
187  for (int i = 0; i < actions.size() && !handled; i++)
188  {
189  QString action = actions[i];
190  handled = true;
191 
192  if (action == "PAUSE")
193  {
194  if (m_playButton)
195  m_playButton->Push();
196  }
197  else if (action == "DELETE")
198  {
199  if (m_deleteButton)
200  m_deleteButton->Push();
201  }
202  else if (action == "LEFT")
203  {
204  if (m_paused)
205  {
206  if (m_curFrame > 1)
207  m_curFrame--;
208  getFrame();
209  }
210  }
211  else if (action == "RIGHT")
212  {
213  if (m_paused)
214  {
215  if (m_curFrame < m_frameList->size())
216  m_curFrame++;
217  getFrame();
218  }
219  }
220  else if (action == "PAGEUP")
221  {
222  if (m_prevButton)
223  m_prevButton->Push();
224  }
225  else if (action == "PAGEDOWN")
226  {
227  if (m_nextButton)
228  m_nextButton->Push();
229  }
230  else if (action == "TOGGLEASPECT" || action == "TOGGLEFILL")
231  {
232  if (!m_eventList->empty())
233  {
234  stopPlayer();
235 
236  if (m_fullScreen)
237  {
238  m_fullScreen = false;
239  m_frameImage->SetVisible(false);
240  m_frameImageFS->SetVisible(true);
242  }
243  else
244  {
245  m_fullScreen = true;
246  m_frameImageFS->SetVisible(false);
247  m_frameImage->SetVisible(true);
249  }
250 
251  if (!m_paused)
252  m_frameTimer->start(10ms);
253 
254  }
255  }
256  else
257  handled = false;
258  }
259 
260  if (!handled && MythScreenType::keyPressEvent(event))
261  handled = true;
262 
263  return handled;
264 }
265 
267 {
268  if (m_eventList->empty())
269  return;
270 
271  if (m_paused)
272  {
273  m_frameTimer->start(40ms);
274  m_paused = false;
275  if (m_playButton)
276  m_playButton->SetText(tr("Pause"));
277  }
278  else
279  {
280  m_frameTimer->stop();
281  m_paused = true;
282  if (m_playButton)
283  m_playButton->SetText(tr("Play"));
284  }
285 }
286 
288 {
289  if (m_eventList->empty() || (*m_currentEvent > m_eventList->size() - 1))
290  return;
291 
292  Event *event = m_eventList->at(*m_currentEvent);
293  if (event)
294  {
295  m_frameTimer->stop();
296 
297  if (class ZMClient *zm = ZMClient::get())
298  zm->deleteEvent(event->eventID());
299 
300  m_eventList->erase(m_eventList->begin() + *m_currentEvent);
301  if (*m_currentEvent > (m_eventList->size() - 1))
302  *m_currentEvent = (m_eventList->size() - 1);
303 
304  getEventInfo();
305 
306  if (!m_eventList->empty())
307  {
308  m_frameTimer->start(40ms);
309  m_paused = false;
310  }
311  }
312 }
313 
315 {
316  if (m_eventList->empty())
317  return;
318 
319  if (*m_currentEvent >= (m_eventList->size() - 1))
320  return;
321 
322  (*m_currentEvent)++;
323 
324  getEventInfo();
325 
326  if (m_paused)
327  playPressed();
328 }
329 
331 {
332  if (m_eventList->empty())
333  return;
334 
335  if (*m_currentEvent == 0)
336  return;
337 
338  if (*m_currentEvent > m_eventList->size())
339  *m_currentEvent = m_eventList->size();
340 
341  (*m_currentEvent)--;
342 
343  getEventInfo();
344 
345  if (m_paused)
346  playPressed();
347 }
348 
350 {
351  if (m_frameList->empty())
352  return;
353 
354  m_frameTimer->stop();
355 
356  m_curFrame++;
357  if (m_curFrame > m_frameList->size())
358  {
359  m_paused = true;
360  m_curFrame = 1;
361  if (m_playButton)
362  m_playButton->SetText(tr("Play"));
363  return;
364  }
365 
366  getFrame();
367 }
368 
370 {
371  if (m_eventList->empty())
372  return;
373 
374  Event *event = m_eventList->at(*m_currentEvent);
375  if (event)
376  {
377  if (class ZMClient *zm = ZMClient::get())
378  zm->getEventFrame(event, m_curFrame, &m_image);
379 
380  if (m_image)
381  {
383  m_frameText->SetText(QString("%1/%2").arg(m_curFrame).arg(m_frameList->size()));
384  }
385 
386  if (!m_paused)
387  {
388  if (m_curFrame < m_frameList->size())
389  {
390  double delta = m_frameList->at(m_curFrame)->delta -
391  m_frameList->at(m_curFrame - 1)->delta;
392 
393  // FIXME: this is a bit of a hack to try to not swamp the cpu
394  if (delta < 0.1)
395  delta = 0.1;
396 
397  m_frameTimer->start((int) (1000 * delta));
398  }
399  else
400  m_frameTimer->start(10ms);
401  }
402  }
403 }
MythUIButton::Clicked
void Clicked()
ZMPlayer::m_noEventsText
MythUIText * m_noEventsText
Definition: zmplayer.h:61
MythDate::toString
QString toString(const QDateTime &raw_dt, uint format)
Returns formatted string representing the time.
Definition: mythdate.cpp:80
ZMPlayer::m_frameImage
MythUIImage * m_frameImage
Definition: zmplayer.h:59
hardwareprofile.smolt.timeout
float timeout
Definition: smolt.py:103
ZMPlayer::deletePressed
void deletePressed(void)
Definition: zmplayer.cpp:287
ZMPlayer::stopPlayer
void stopPlayer(void)
Definition: zmplayer.cpp:59
MythUIText::Reset
void Reset(void) override
Reset the widget to it's original state, should not reset changes made by the theme.
Definition: mythuitext.cpp:84
ZMPlayer::m_eventText
MythUIText * m_eventText
Definition: zmplayer.h:62
ZMPlayer::m_dateText
MythUIText * m_dateText
Definition: zmplayer.h:65
ZMPlayer::prevPressed
void prevPressed(void)
Definition: zmplayer.cpp:330
MythMainWindow::TranslateKeyPress
bool TranslateKeyPress(const QString &context, QKeyEvent *e, QStringList &actions, bool allowJumps=true)
Get a list of actions for a keypress in the given context.
Definition: mythmainwindow.cpp:1142
MythUIImage::Load
bool Load(bool allowLoadInBackground=true, bool forceStat=false)
Load the image(s), wraps ImageLoader::LoadImage()
Definition: mythuiimage.cpp:968
Frame
Definition: zmdefines.h:94
ZMPlayer::Create
bool Create(void) override
Definition: zmplayer.cpp:64
ZMPlayer::m_activeFrameImage
MythUIImage * m_activeFrameImage
Definition: zmplayer.h:57
MythScreenStack
Definition: mythscreenstack.h:16
arg
arg(title).arg(filename).arg(doDelete))
mythdbcon.h
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
MythScreenType
Screen in which all other widgets are contained and rendered.
Definition: mythscreentype.h:45
ZMPlayer::m_prevButton
MythUIButton * m_prevButton
Definition: zmplayer.h:70
ZMPlayer::m_currentEvent
size_t * m_currentEvent
Definition: zmplayer.h:72
ZMPlayer::m_fullScreen
bool m_fullScreen
Definition: zmplayer.h:80
MythScreenType::GetFocusWidget
MythUIType * GetFocusWidget(void) const
Definition: mythscreentype.cpp:112
zmclient.h
ZMPlayer::m_nextButton
MythUIButton * m_nextButton
Definition: zmplayer.h:69
mythdate.h
ZMPlayer::m_frameText
MythUIText * m_frameText
Definition: zmplayer.h:64
ZMPlayer::playPressed
void playPressed(void)
Definition: zmplayer.cpp:266
Event
Event details.
Definition: zmdefines.h:27
MythScreenType::SetFocusWidget
bool SetFocusWidget(MythUIType *widget=nullptr)
Definition: mythscreentype.cpp:117
ZMPlayer::updateFrame
void updateFrame(void)
Definition: zmplayer.cpp:349
MythUIButton::SetText
void SetText(const QString &msg)
Definition: mythuibutton.cpp:229
ZMPlayer::~ZMPlayer
~ZMPlayer() override
Definition: zmplayer.cpp:50
MythScreenType::BuildFocusList
void BuildFocusList(void)
Definition: mythscreentype.cpp:222
ZMPlayer::nextPressed
void nextPressed(void)
Definition: zmplayer.cpp:314
ZMPlayer::m_paused
bool m_paused
Definition: zmplayer.h:79
MythUIButton::Push
void Push(bool lock=false)
Definition: mythuibutton.cpp:175
ZMPlayer::m_curFrame
uint m_curFrame
Definition: zmplayer.h:77
ZMPlayer::ZMPlayer
ZMPlayer(MythScreenStack *parent, const char *name, std::vector< Event * > *eventList, size_t *currentEvent)
Definition: zmplayer.cpp:39
ZMClient::get
static ZMClient * get(void)
Definition: zmclient.cpp:38
zmplayer.h
ZMPlayer::m_cameraText
MythUIText * m_cameraText
Definition: zmplayer.h:63
UIUtilDisp::Assign
static bool Assign(ContainerType *container, UIType *&item, const QString &name, bool *err=nullptr)
Definition: mythuiutils.h:27
ZMPlayer::getEventInfo
void getEventInfo(void)
Definition: zmplayer.cpp:129
MythDate::kSimplify
@ kSimplify
Do Today/Yesterday/Tomorrow transform.
Definition: mythdate.h:23
mythuihelper.h
MythScreenType::keyPressEvent
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
Definition: mythscreentype.cpp:414
XMLParseBase::LoadWindowFromXML
static bool LoadWindowFromXML(const QString &xmlfile, const QString &windowname, MythUIType *parent)
Definition: xmlparsebase.cpp:692
ZMPlayer::m_deleteButton
MythUIButton * m_deleteButton
Definition: zmplayer.h:68
MythUIText::SetText
virtual void SetText(const QString &text)
Definition: mythuitext.cpp:134
MythUIType::SetVisible
virtual void SetVisible(bool visible)
Definition: mythuitype.cpp:1086
mythcontext.h
GetMythMainWindow
MythMainWindow * GetMythMainWindow(void)
Definition: mythmainwindow.cpp:108
ZMPlayer::m_frameList
std::vector< Frame * > * m_frameList
Definition: zmplayer.h:75
ZMPlayer::m_image
MythImage * m_image
Definition: zmplayer.h:82
build_compdb.action
action
Definition: build_compdb.py:9
ZMPlayer::getFrame
void getFrame(void)
Definition: zmplayer.cpp:369
ZMPlayer::m_frameTimer
QTimer * m_frameTimer
Definition: zmplayer.h:76
MythUIImage::SetImage
void SetImage(MythImage *img)
Should not be used unless absolutely necessary since it bypasses the image caching and threaded loade...
Definition: mythuiimage.cpp:748
MythDate::kDateTimeFull
@ kDateTimeFull
Default local time.
Definition: mythdate.h:20
ZMPlayer::m_eventList
std::vector< Event * > * m_eventList
Definition: zmplayer.h:73
MythUIImage::SetFilename
void SetFilename(const QString &filename)
Must be followed by a call to Load() to load the image.
Definition: mythuiimage.cpp:676
ZMPlayer::keyPressEvent
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
Definition: zmplayer.cpp:179
mythmainwindow.h
ZMPlayer::m_playButton
MythUIButton * m_playButton
Definition: zmplayer.h:67
ZMPlayer::m_frameImageFS
MythUIImage * m_frameImageFS
Definition: zmplayer.h:58
ZMClient
Definition: zmclient.h:18