MythTV  master
deletemap.cpp
Go to the documentation of this file.
1 
2 #include "deletemap.h"
3 
4 #include <cstdint>
5 
6 #include "mythlogging.h"
7 #include "osd.h"
8 #include "mythplayer.h"
9 #include "programinfo.h"
10 #include "mythcorecontext.h" // for MythCoreContext, etc
11 #include "mythtypes.h" // for InfoMap
12 #include "mythuiactions.h" // for ACTION_DOWN, ACTION_UP
13 #include "playercontext.h" // for PlayerContext
14 #include "tv_actions.h" // for ACTION_CLEARMAP, etc
15 
16 #define LOC QString("DelMap: ")
17 #define EDIT_CHECK do { \
18  if(!m_editing) { \
19  LOG(VB_GENERAL, LOG_ERR, LOC + "Cannot edit outside edit mode."); \
20  return; \
21  } \
22 } while(false)
23 
24 void DeleteMap::Push(const QString &undoMessage)
25 {
26  DeleteMapUndoEntry entry(m_deleteMap, undoMessage);
27  // Remove all "redo" entries
28  while (m_undoStack.size() > m_undoStackPointer)
29  m_undoStack.pop_back();
30  m_undoStack.append(entry);
32  SaveMap(true);
33 }
34 
36  const QString &undoMessage)
37 {
38  // Temporarily roll back to the initial state, push the undo
39  // entry, then restore the correct state.
41  m_deleteMap = savedMap;
42  Push(undoMessage);
43  m_deleteMap = tmp;
44  SaveMap(true);
45 }
46 
47 bool DeleteMap::Undo(void)
48 {
49  if (!HasUndo())
50  return false;
54  m_undoStack[m_undoStackPointer].m_deleteMap = tmp;
55  m_changed = true;
56  SaveMap(true);
57  return true;
58 }
59 
60 bool DeleteMap::Redo(void)
61 {
62  if (!HasRedo())
63  return false;
66  m_undoStack[m_undoStackPointer].m_deleteMap = tmp;
68  m_changed = true;
69  SaveMap(true);
70  return true;
71 }
72 
73 QString DeleteMap::GetUndoMessage(void) const
74 {
75  return (HasUndo() ? m_undoStack[m_undoStackPointer - 1].m_message :
76  tr("(Nothing to undo)"));
77 }
78 
79 QString DeleteMap::GetRedoMessage(void) const
80 {
81  return (HasRedo() ? m_undoStack[m_undoStackPointer].m_message :
82  tr("(Nothing to redo)"));
83 }
84 
85 bool DeleteMap::HandleAction(QString &action, uint64_t frame)
86 {
87  bool handled = true;
88  if (action == ACTION_UP)
90  else if (action == ACTION_DOWN)
91  UpdateSeekAmount(-1);
92  else if (action == ACTION_CLEARMAP)
93  Clear(tr("Clear Cuts"));
94  else if (action == ACTION_INVERTMAP)
95  ReverseAll();
96  else if (action == "MOVEPREV")
97  MoveRelative(frame, false);
98  else if (action == "MOVENEXT")
99  MoveRelative(frame, true);
100  else if (action == "CUTTOBEGINNING")
101  {
102  Push(tr("Cut to Beginning"));
103  AddMark(frame, MARK_CUT_END);
104  }
105  else if (action == "CUTTOEND")
106  {
107  Push(tr("Cut to End"));
108  AddMark(frame, MARK_CUT_START);
109  // If the recording is still in progress, add an explicit end
110  // mark at the end.
113  }
114  else if (action == "NEWCUT")
115  NewCut(frame);
116  else if (action == "DELETE")
117  //: Delete the current cut or preserved region
118  Delete(frame, tr("Delete"));
119  else if (action == "UNDO")
120  Undo();
121  else if (action == "REDO")
122  Redo();
123  else
124  handled = false;
125  return handled;
126 }
127 
129 {
130  m_seekamountpos += change;
131  if (m_seekamountpos > 9)
132  m_seekamountpos = 9;
133  if (m_seekamountpos < 0)
134  m_seekamountpos = 0;
135 
136  m_seekText = "";
137  switch (m_seekamountpos)
138  {
139  case 0: m_seekText = tr("cut point"); m_seekamount = -2; break;
140  case 1: m_seekText = tr("keyframe"); m_seekamount = -1; break;
141  case 2: m_seekText = tr("1 frame"); m_seekamount = 0; break;
142  case 3: m_seekText = tr("0.5 seconds"); m_seekamount = 0.5; break;
143  case 4: m_seekText = tr("%n second(s)", "", 1); m_seekamount = 1; break;
144  case 5: m_seekText = tr("%n second(s)", "", 5); m_seekamount = 5; break;
145  case 6: m_seekText = tr("%n second(s)", "", 20); m_seekamount = 20; break;
146  case 7: m_seekText = tr("%n minute(s)", "", 1); m_seekamount = 60; break;
147  case 8: m_seekText = tr("%n minute(s)", "", 5); m_seekamount = 300; break;
148  case 9: m_seekText = tr("%n minute(s)", "", 10); m_seekamount = 600; break;
149  default: m_seekText = tr("error"); m_seekamount = 1; break;
150  }
151 }
152 
153 QString DeleteMap::CreateTimeString(uint64_t frame, bool use_cutlist,
154  double frame_rate, bool full_resolution)
155  const
156 {
157  uint64_t ms = TranslatePositionFrameToMs(frame, frame_rate, use_cutlist);
158  int secs = (int)(ms / 1000);
159  int remainder = (int)(ms % 1000);
160  int totalSecs = (int)
161  (TranslatePositionFrameToMs(frame, frame_rate, use_cutlist) / 1000);
162  QString timestr;
163  if (totalSecs >= 3600)
164  timestr = QString::number(secs / 3600) + ":";
165  timestr += QString("%1").arg((secs / 60) % 60, 2, 10, QChar(48)) +
166  QString(":%1").arg(secs % 60, 2, 10, QChar(48));
167  if (full_resolution)
168  timestr += QString(".%1").arg(remainder, 3, 10, QChar(48));
169  return timestr;
170 }
171 
176 void DeleteMap::UpdateOSD(uint64_t frame, double frame_rate, OSD *osd)
177 {
178  if (!osd || !m_ctx)
179  return;
180  CleanMap();
181 
182  InfoMap infoMap;
183  m_ctx->LockPlayingInfo(__FILE__, __LINE__);
184  if (m_ctx->m_playingInfo)
185  m_ctx->m_playingInfo->ToMap(infoMap);
186  m_ctx->UnlockPlayingInfo(__FILE__, __LINE__);
187 
188  QString cutmarker = " ";
189  if (IsInDelete(frame))
190  cutmarker = tr("cut");
191 
192  uint64_t total = m_ctx->m_player->GetTotalFrameCount();
193  QString timestr = CreateTimeString(frame, false, frame_rate, true);
194  QString relTimeDisplay;
195  relTimeDisplay = CreateTimeString(frame, true, frame_rate, false);
196  QString relLengthDisplay;
197  relLengthDisplay = CreateTimeString(total, true, frame_rate, false);
198  infoMap["timedisplay"] = timestr;
199  infoMap["framedisplay"] = QString::number(frame);
200  infoMap["cutindicator"] = cutmarker;
201  infoMap["title"] = tr("Edit");
202  infoMap["seekamount"] = m_seekText;;
203  infoMap["reltimedisplay"] = relTimeDisplay;
204  infoMap["rellengthdisplay"] = relLengthDisplay;
205  //: example: "13:24 (10:23 of 24:37)"
206  infoMap["fulltimedisplay"] = tr("%3 (%1 of %2)").arg(relTimeDisplay)
207  .arg(relLengthDisplay).arg(timestr);
208 
209  QHash<QString,float> posMap;
210  posMap.insert("position", (float)((double)frame/(double)total));
211  osd->SetValues("osd_program_editor", posMap, kOSDTimeout_None);
212  osd->SetText("osd_program_editor", infoMap, kOSDTimeout_None);
213  if (m_changed || total != m_cachedTotalForOSD)
214  osd->SetRegions("osd_program_editor", m_deleteMap, total);
215  m_changed = false;
216  m_cachedTotalForOSD = total;
217 }
218 
219 void DeleteMap::UpdateOSD(int64_t timecode, OSD *osd)
220 {
221  osd->SetGraph("osd_program_editor", "audiograph", timecode);
222 }
223 
225 void DeleteMap::SetEditing(bool edit, OSD *osd)
226 {
227  if (osd && !edit)
228  osd->HideWindow("osd_program_editor");
229  m_editing = edit;
230 }
231 
234 {
235  if (m_ctx)
236  {
237  m_ctx->LockPlayingInfo(__FILE__, __LINE__);
238  if (m_ctx->m_playingInfo)
240  m_ctx->UnlockPlayingInfo(__FILE__, __LINE__);
241  }
242 }
243 
246 {
247  bool result = false;
248  if (m_ctx)
249  {
250  m_ctx->LockPlayingInfo(__FILE__, __LINE__);
251  if (m_ctx->m_playingInfo)
252  result = m_ctx->m_playingInfo->QueryIsEditing();
253  m_ctx->UnlockPlayingInfo(__FILE__, __LINE__);
254  }
255  return result;
256 }
257 
258 bool DeleteMap::IsEmpty(void) const
259 {
260  return m_deleteMap.empty();
261 }
262 
264 void DeleteMap::Clear(const QString& undoMessage)
265 {
266  if (!undoMessage.isEmpty())
267  Push(undoMessage);
268  m_deleteMap.clear();
269  m_changed = true;
270 }
271 
274 {
275  EDIT_CHECK;
276  Push(tr("Reverse Cuts"));
277  frm_dir_map_t::Iterator it = m_deleteMap.begin();
278  for ( ; it != m_deleteMap.end(); ++it)
279  Add(it.key(), it.value() == MARK_CUT_END ? MARK_CUT_START :
280  MARK_CUT_END);
281  CleanMap();
282 }
283 
289 void DeleteMap::AddMark(uint64_t frame, MarkTypes type)
290 {
291  EDIT_CHECK;
292  if ((MARK_CUT_START != type) && (MARK_CUT_END != type) &&
293  (MARK_PLACEHOLDER != type))
294  return;
295 
296  frm_dir_map_t::Iterator find_temporary = m_deleteMap.find(frame);
297  if (find_temporary != m_deleteMap.end())
298  {
299  if (MARK_PLACEHOLDER == find_temporary.value())
300  {
301  // Delete the temporary mark before putting a real mark at its
302  // location
303  Delete(frame, "");
304  }
305  else // Don't add a mark on top of a mark
306  return;
307  }
308 
309  int lasttype = MARK_UNSET;
310  long long lastframe = -1;
311  long long remove = -1;
312  QMutableMapIterator<uint64_t, MarkTypes> it(m_deleteMap);
313 
314  if (type == MARK_CUT_END)
315  {
316  // remove curent end marker if it exists
317  while (it.hasNext())
318  {
319  it.next();
320  if (it.key() > frame)
321  {
322  if ((lasttype == MARK_CUT_END) && (lastframe > -1))
323  remove = lastframe;
324  break;
325  }
326  lasttype = it.value();
327  lastframe = it.key();
328  }
329  if ((remove < 0) && (lasttype == MARK_CUT_END) &&
330  (lastframe > -1) && (lastframe < (int64_t)frame))
331  remove = lastframe;
332  }
333  else if (type == MARK_CUT_START)
334  {
335  // remove curent start marker if it exists
336  it.toBack();
337  while (it.hasPrevious())
338  {
339  it.previous();
340  if (it.key() <= frame)
341  {
342  if (lasttype == MARK_CUT_START && (lastframe > -1))
343  remove = lastframe;
344  break;
345  }
346  lasttype = it.value();
347  lastframe = it.key();
348  }
349  if ((remove < 0) && (lasttype == MARK_CUT_START) &&
350  (lastframe > -1) && (lastframe > (int64_t)frame))
351  remove = lastframe;
352  }
353 
354  if (remove > -1)
355  Delete((uint64_t)remove);
356  Add(frame, type);
357  CleanMap();
358 }
359 
361 void DeleteMap::Delete(uint64_t frame, const QString& undoMessage)
362 {
363  EDIT_CHECK;
364  if (m_deleteMap.isEmpty())
365  return;
366 
367  if (!undoMessage.isEmpty())
368  Push(undoMessage);
369 
370  uint64_t prev = GetNearestMark(frame, false);
371  uint64_t next = GetNearestMark(frame, true);
372 
373  // If frame is a cut point, GetNearestMark() would return the previous/next
374  // mark (not this frame), so check to see if we need to use frame, instead
375  frm_dir_map_t::Iterator it = m_deleteMap.find(frame);
376  if (it != m_deleteMap.end())
377  {
378  int type = it.value();
379  if (MARK_PLACEHOLDER == type)
380  next = prev = frame;
381  else if (MARK_CUT_END == type)
382  next = frame;
383  else if (MARK_CUT_START == type)
384  prev = frame;
385  }
386 
387  Delete(prev);
388  if (prev != next)
389  Delete(next);
390  CleanMap();
391 }
392 
394 void DeleteMap::NewCut(uint64_t frame)
395 {
396  EDIT_CHECK;
397 
398  // Defer pushing the undo entry until the end, when we're sure a
399  // change has been made.
400  frm_dir_map_t initialDeleteMap = m_deleteMap;
401 
402  // find any existing temporary marker to determine cut range
403  int64_t existing = -1;
404  for (auto it = m_deleteMap.begin() ; it != m_deleteMap.end(); ++it)
405  {
406  if (MARK_PLACEHOLDER == it.value())
407  {
408  existing = it.key();
409  break;
410  }
411  }
412 
413  if (existing > -1)
414  {
415  uint64_t total = m_ctx->m_player->GetTotalFrameCount();
416  uint64_t otherframe = static_cast<uint64_t>(existing);
417  if (otherframe == frame)
418  Delete(otherframe);
419  else
420  {
421  uint64_t startframe;
422  uint64_t endframe;
423  int64_t cut_start = -1;
424  int64_t cut_end = -1;
425  if (IsInDelete(frame))
426  {
428  cut_start = GetNearestMark(frame, false);
429  cut_end = GetNearestMark(frame, true);
430  frm_dir_map_t::Iterator it2 = m_deleteMap.find(frame);
431  if (it2 != m_deleteMap.end())
432  type = it2.value();
433  if (MARK_CUT_START == type)
434  {
435  cut_start = frame;
436  }
437  else if (MARK_CUT_END == type)
438  {
439  cut_end = frame;
440  }
441  }
442 
443  if (otherframe < frame)
444  {
445  startframe = otherframe;
446  endframe = cut_end != -1 ? static_cast<uint64_t>(cut_end)
447  : frame;
448  }
449  else
450  {
451  startframe = cut_start != -1 ? static_cast<uint64_t>(cut_start)
452  : frame;
453  endframe = otherframe;
454  }
455 
456  // Don't place a cut marker on first or last frame; instead cut
457  // to beginning or end
458  if (startframe == 1)
459  startframe = 0;
460  if (endframe >= total - 1)
461  endframe = total;
462 
463  // Don't cut the entire recording
464  if ((startframe == 0) && (endframe == total))
465  {
466  LOG(VB_GENERAL, LOG_CRIT, LOC +
467  "Refusing to cut entire recording.");
468  return;
469  }
470 
471  Delete(otherframe);
472  Add(startframe, MARK_CUT_START);
473  Add(endframe, MARK_CUT_END);
474  // Clear out any markers between the start and end frames
475  otherframe = 0;
476  frm_dir_map_t::Iterator it = m_deleteMap.find(startframe);
477  for ( ; it != m_deleteMap.end() && otherframe < endframe; ++it)
478  {
479  otherframe = it.key();
480  if ((startframe < otherframe) && (endframe > otherframe))
481  {
482  LOG(VB_PLAYBACK, LOG_INFO, LOC +
483  QString("Deleting bounded marker: %1").arg(otherframe));
484  it = m_deleteMap.erase(it);
485  m_changed = true;
486  }
487  }
488  }
489  }
490  else
491  Add(frame, MARK_PLACEHOLDER);
492 
493  CleanMap();
494  PushDeferred(initialDeleteMap, tr("New Cut"));
495 }
496 
498 void DeleteMap::MoveRelative(uint64_t frame, bool right)
499 {
500  frm_dir_map_t::Iterator it = m_deleteMap.find(frame);
501  if (it != m_deleteMap.end())
502  {
503  int type = it.value();
504  if (((MARK_CUT_START == type) && !right) ||
505  ((MARK_CUT_END == type) && right))
506  {
507  // If on a mark, don't move a mark from a different cut region;
508  // instead, "move" this mark onto itself
509  return;
510  }
511  if (((MARK_CUT_START == type) && right) ||
512  ((MARK_CUT_END == type) && !right))
513  {
514  // If on a mark, don't collapse a cut region to 0;
515  // instead, delete the region
516  //: Delete the current cut or preserved region
517  Delete(frame, tr("Delete"));
518  return;
519  }
520  if (MARK_PLACEHOLDER == type)
521  {
522  // Delete the temporary mark before putting a real mark at its
523  // location
524  Delete(frame, "");
525  }
526  }
527 
528  uint64_t from = GetNearestMark(frame, right);
529  Move(from, frame);
530 }
531 
533 void DeleteMap::Move(uint64_t frame, uint64_t to)
534 {
535  EDIT_CHECK;
536  Push(tr("Move Mark"));
537  MarkTypes type = Delete(frame);
538  if (MARK_UNSET == type)
539  {
540  if (frame == 0)
542  else if (frame == m_ctx->m_player->GetTotalFrameCount())
543  type = MARK_CUT_END;
544  }
545  AddMark(to, type);
546 }
547 
549 void DeleteMap::Add(uint64_t frame, MarkTypes type)
550 {
551  m_deleteMap[frame] = type;
552  m_changed = true;
553 }
554 
557 {
558  if (m_deleteMap.contains(frame))
559  {
560  m_changed = true;
561  return m_deleteMap.take(frame);
562  }
563  return MARK_UNSET;
564 }
565 
570 bool DeleteMap::IsInDelete(uint64_t frame) const
571 {
572  if (m_deleteMap.isEmpty())
573  return false;
574 
575  frm_dir_map_t::const_iterator it = m_deleteMap.find(frame);
576  if (it != m_deleteMap.end())
577  return true;
578 
579  int lasttype = MARK_UNSET;
580  uint64_t lastframe = UINT64_MAX;
581  for (it = m_deleteMap.begin() ; it != m_deleteMap.end(); ++it)
582  {
583  if (it.key() > frame)
584  return MARK_CUT_END == it.value();
585  lasttype = it.value();
586  lastframe = it.key();
587  }
588 
589  return lasttype == MARK_CUT_START && lastframe <= frame;
590 }
591 
595 bool DeleteMap::IsTemporaryMark(uint64_t frame) const
596 {
597  if (m_deleteMap.isEmpty())
598  return false;
599 
600  frm_dir_map_t::const_iterator it = m_deleteMap.find(frame);
601  return (it != m_deleteMap.end()) && (MARK_PLACEHOLDER == it.value());
602 }
603 
610 uint64_t DeleteMap::GetNearestMark(uint64_t frame, bool right, bool *hasMark)
611  const
612 {
613  uint64_t result;
614  if (hasMark)
615  *hasMark = true;
616  frm_dir_map_t::const_iterator it = m_deleteMap.begin();
617  if (right)
618  {
619  result = m_ctx->m_player->GetTotalFrameCount();
620  for (; it != m_deleteMap.end(); ++it)
621  if (it.key() > frame)
622  return it.key();
623  if (hasMark)
624  *hasMark = false;
625  }
626  else
627  {
628  result = 0;
629  for (; it != m_deleteMap.end(); ++it)
630  {
631  if (it.key() >= frame)
632  return result;
633  result = it.key();
634  }
635  }
636  return result;
637 }
638 
643 {
644  if (!m_deleteMap.isEmpty())
645  {
646  frm_dir_map_t::const_iterator it = m_deleteMap.begin();
647  for ( ; it != m_deleteMap.end(); ++it)
648  if (MARK_PLACEHOLDER == it.value())
649  return true;
650  }
651 
652  return false;
653 }
654 
661 {
662  if (IsEmpty())
663  return;
664 
665  uint64_t total = m_ctx->m_player->GetTotalFrameCount();
666  Delete(0);
667  Delete(total);
668 
669  bool clear = false;
670  while (!IsEmpty() && !clear)
671  {
672  clear = true;
673  int lasttype = MARK_UNSET;
674  int64_t lastframe = -1;
675  int64_t tempframe = -1;
676  QList<int64_t> deleteList;
677  frm_dir_map_t::iterator it = m_deleteMap.begin();
678  for ( ; it != m_deleteMap.end(); ++it)
679  {
680  int thistype = it.value();
681  uint64_t thisframe = it.key();
682  if (thisframe >= total)
683  {
684  deleteList.append(thisframe);
685  }
686  else if (lasttype == thistype)
687  {
688  deleteList.append(thistype == MARK_CUT_END ? thisframe :
689  (uint64_t)lastframe);
690  clear = false;
691  break;
692  }
693  if (MARK_PLACEHOLDER == thistype)
694  {
695  if (tempframe > 0)
696  deleteList.append(tempframe);
697  tempframe = thisframe;
698  }
699  else
700  {
701  lasttype = thistype;
702  lastframe = thisframe;
703  }
704  }
705 
706  // Delete the unwanted frame marks safely, and not while iterating over
707  // the map which would lead to a crash
708  QList<int64_t>::iterator dit = deleteList.begin();
709  for (; dit != deleteList.end(); ++dit)
710  {
711  Delete(*dit);
712  }
713  deleteList.clear();
714  }
715 }
716 
719 {
720  // Can't save an undo point for SetMap() or transcodes fail.
721  // Leaving as a marker for refactor.
722  //Push(tr("Set New Cut List"));
723 
724  Clear();
725  m_deleteMap = map;
726 }
727 
730 {
731  Push(tr("Load Detected Commercials"));
732  Clear();
733  frm_dir_map_t::Iterator it = map.begin();
734  for ( ; it != map.end(); ++it)
735  Add(it.key(), it.value() == MARK_COMM_START ?
737  CleanMap();
738 }
739 
741 void DeleteMap::LoadMap(const QString& undoMessage)
742 {
744  return;
745 
746  if (!undoMessage.isEmpty())
747  Push(undoMessage);
748  Clear();
749  m_ctx->LockPlayingInfo(__FILE__, __LINE__);
751  m_ctx->UnlockPlayingInfo(__FILE__, __LINE__);
752  CleanMap();
753 }
754 
758 {
760  return false;
761 
762  frm_dir_map_t tmpDeleteMap = m_deleteMap;
763  Clear();
764  m_ctx->LockPlayingInfo(__FILE__, __LINE__);
765  bool result = m_ctx->m_playingInfo->QueryCutList(m_deleteMap, true);
766  m_ctx->UnlockPlayingInfo(__FILE__, __LINE__);
767  CleanMap();
768  if (result)
769  PushDeferred(tmpDeleteMap, tr("Load Auto-saved Cuts"));
770  else
771  m_deleteMap = tmpDeleteMap;
772 
773  return result;
774 }
775 
777 void DeleteMap::SaveMap(bool isAutoSave)
778 {
780  return;
781 
782  if (!isAutoSave)
783  {
784  // Remove temporary placeholder marks
785  QMutableMapIterator<uint64_t, MarkTypes> it(m_deleteMap);
786  while (it.hasNext())
787  {
788  it.next();
789  if (MARK_PLACEHOLDER == it.value())
790  {
791  it.remove();
792  m_changed = true;
793  }
794  }
795 
796  CleanMap();
797  }
798  m_ctx->LockPlayingInfo(__FILE__, __LINE__);
801  m_ctx->UnlockPlayingInfo(__FILE__, __LINE__);
802 }
803 
810 void DeleteMap::TrackerReset(uint64_t frame)
811 {
812  m_nextCutStart = 0;
813  m_nextCutStartIsValid = false;
814  if (IsEmpty())
815  return;
816 
817  frm_dir_map_t::iterator cutpoint = m_deleteMap.find(frame);
818  if (cutpoint != m_deleteMap.end())
819  {
820  if (cutpoint.value() == MARK_CUT_START)
821  {
822  m_nextCutStartIsValid = true;
823  m_nextCutStart = cutpoint.key();
824  }
825  else
826  {
827  ++cutpoint;
828  m_nextCutStartIsValid = (cutpoint != m_deleteMap.end());
829  m_nextCutStart = m_nextCutStartIsValid ? cutpoint.key() :
831  }
832  }
833  else
834  m_nextCutStart = GetNearestMark(frame, !IsInDelete(frame),
836  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Tracker next CUT_START: %1")
837  .arg(m_nextCutStart));
838 }
839 
844 bool DeleteMap::TrackerWantsToJump(uint64_t frame, uint64_t &to)
845 {
846  if (IsEmpty() || !m_nextCutStartIsValid || frame < m_nextCutStart)
847  return false;
848 
849  to = GetNearestMark(m_nextCutStart, true);
850  LOG(VB_PLAYBACK, LOG_INFO, LOC +
851  QString("Tracker wants to jump to: %1").arg(to));
852  return true;
853 }
854 
859 uint64_t DeleteMap::GetLastFrame(void) const
860 {
861  uint64_t result = m_ctx->m_player->GetCurrentFrameCount();
862  if (IsEmpty())
863  return result;
864 
865  frm_dir_map_t::const_iterator it = m_deleteMap.end();
866  --it;
867 
868  if (it.value() == MARK_CUT_START)
869  result = it.key();
870  return result;
871 }
872 
876 bool DeleteMap::IsSaved(void) const
877 {
879  return true;
880 
881  frm_dir_map_t currentMap(m_deleteMap);
882  frm_dir_map_t savedMap;
883  m_ctx->LockPlayingInfo(__FILE__, __LINE__);
884  m_ctx->m_playingInfo->QueryCutList(savedMap);
885  m_ctx->UnlockPlayingInfo(__FILE__, __LINE__);
886 
887  // Remove temporary placeholder marks from currentMap
888  QMutableMapIterator<uint64_t, MarkTypes> it(currentMap);
889  while (it.hasNext())
890  {
891  it.next();
892  if (MARK_PLACEHOLDER == it.value())
893  it.remove();
894  }
895 
896  return currentMap == savedMap;
897 }
898 
899 uint64_t DeleteMap::TranslatePositionFrameToMs(uint64_t position,
900  float fallback_framerate,
901  bool use_cutlist) const
902 {
903  return m_ctx->m_player->GetDecoder()
904  ->TranslatePositionFrameToMs(position, fallback_framerate,
905  use_cutlist ? m_deleteMap :
906  frm_dir_map_t());
907 }
908 uint64_t DeleteMap::TranslatePositionMsToFrame(uint64_t dur_ms,
909  float fallback_framerate,
910  bool use_cutlist) const
911 {
912  return m_ctx->m_player->GetDecoder()
913  ->TranslatePositionMsToFrame(dur_ms, fallback_framerate,
914  use_cutlist ? m_deleteMap :
915  frm_dir_map_t());
916 }
917 
918 uint64_t DeleteMap::TranslatePositionAbsToRel(uint64_t position) const
919 {
921 }
922 
923 uint64_t DeleteMap::TranslatePositionRelToAbs(uint64_t position) const
924 {
926 }
void SetEditing(bool edit, OSD *osd=nullptr)
Set the edit mode and optionally hide the edit mode OSD.
Definition: deletemap.cpp:225
void SetMap(const frm_dir_map_t &map)
Use the given map.
Definition: deletemap.cpp:718
void CleanMap(void)
Removes redundant marks and ensures the markup sequence is valid.
Definition: deletemap.cpp:660
MythPlayer * m_player
float m_seekamount
Definition: deletemap.h:108
virtual void ToMap(InfoMap &progMap, bool showrerecord=false, uint star_range=10) const
Converts ProgramInfo into QString QHash containing each field in ProgramInfo converted into localized...
void SetFileEditing(bool edit)
Update the editing status in the file's ProgramInfo.
Definition: deletemap.cpp:233
void PushDeferred(const frm_dir_map_t &savedMap, const QString &undoMessage)
Definition: deletemap.cpp:35
void SetEditing(bool editing)
Definition: programinfo.h:531
#define ACTION_INVERTMAP
Definition: tv_actions.h:88
bool m_changed
Definition: deletemap.h:106
uint64_t TranslatePositionAbsToRel(uint64_t position) const
Definition: deletemap.cpp:918
void Clear(const QString &undoMessage="")
Clears the deleteMap.
Definition: deletemap.cpp:264
uint64_t m_cachedTotalForOSD
Definition: deletemap.h:110
#define LOC
Definition: deletemap.cpp:16
uint64_t GetLastFrame(void) const
Returns the number of the last frame in the video that is not in a cut sequence.
Definition: deletemap.cpp:859
#define EDIT_CHECK
Definition: deletemap.cpp:17
bool HasUndo(void) const
Definition: deletemap.h:83
void UnlockPlayingInfo(const char *file, int line) const
void SaveMarkupFlag(MarkTypes type) const
Clears the specified flag, then if sets it.
#define ACTION_UP
Definition: mythuiactions.h:16
bool Redo(void)
Definition: deletemap.cpp:60
bool QueryCutList(frm_dir_map_t &, bool loadAutosave=false) const
static uint64_t TranslatePositionAbsToRel(const frm_dir_map_t &deleteMap, uint64_t absPosition, const frm_pos_map_t &map=frm_pos_map_t(), float fallback_ratio=1.0)
void UpdateOSD(uint64_t frame, double frame_rate, OSD *osd)
Show and update the edit mode On Screen Display.
Definition: deletemap.cpp:176
QMap< uint64_t, MarkTypes > frm_dir_map_t
Frame # -> Mark map.
Definition: programtypes.h:81
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
bool HasTemporaryMark(void) const
Returns true if a temporary placeholder mark is defined.
Definition: deletemap.cpp:642
bool IsDatabaseIgnored(void) const
/brief Returns true if database is being ignored.
void Move(uint64_t frame, uint64_t to)
Move an existing mark to a new frame.
Definition: deletemap.cpp:533
QString GetRedoMessage(void) const
Definition: deletemap.cpp:79
void AddMark(uint64_t frame, MarkTypes type)
Add a new mark of the given type.
Definition: deletemap.cpp:289
void SetGraph(const QString &window, const QString &graph, int64_t timecode)
Definition: osd.cpp:657
bool Undo(void)
Definition: deletemap.cpp:47
int m_undoStackPointer
Definition: deletemap.h:113
static guint32 * tmp
Definition: goom_core.c:35
int m_seekamountpos
Definition: deletemap.h:107
QString CreateTimeString(uint64_t frame, bool use_cutlist, double frame_rate, bool full_resolution) const
Definition: deletemap.cpp:153
bool IsTemporaryMark(uint64_t frame) const
Returns true if the given frame is a temporary/placeholder mark.
Definition: deletemap.cpp:595
void SaveMap(bool isAutoSave=false)
Saves the delete map to the database.
Definition: deletemap.cpp:777
bool m_editing
Definition: deletemap.h:101
MarkTypes
Definition: programtypes.h:48
ProgramInfo * m_playingInfo
Currently playing info.
bool LoadAutoSaveMap(void)
Returns true if an auto-save map was loaded.
Definition: deletemap.cpp:757
uint64_t m_nextCutStart
Definition: deletemap.h:103
bool IsSaved(void) const
Compares the current cut list with the saved cut list.
Definition: deletemap.cpp:876
void LoadMap(const QString &undoMessage="")
Loads the delete map from the database.
Definition: deletemap.cpp:741
static uint64_t TranslatePositionRelToAbs(const frm_dir_map_t &deleteMap, uint64_t relPosition, const frm_pos_map_t &map=frm_pos_map_t(), float fallback_ratio=1.0)
QVector< DeleteMapUndoEntry > m_undoStack
Definition: deletemap.h:112
QString GetUndoMessage(void) const
Definition: deletemap.cpp:73
void SetValues(const QString &window, const QHash< QString, int > &map, OSDTimeout timeout)
Definition: osd.cpp:355
static void clear(SettingsMap &cache, SettingsMap &overrides, const QString &myKey)
Definition: mythdb.cpp:830
bool HasRedo(void) const
Definition: deletemap.h:84
QHash< QString, QString > InfoMap
Definition: mythtypes.h:15
bool TrackerWantsToJump(uint64_t frame, uint64_t &to)
Returns true if the given frame has passed the last cut point start and provides the frame number of ...
Definition: deletemap.cpp:844
bool m_nextCutStartIsValid
Definition: deletemap.h:102
QString m_seekText
Definition: deletemap.h:105
void MoveRelative(uint64_t frame, bool right)
Move the previous (!right) or next (right) cut to frame.
Definition: deletemap.cpp:498
void LockPlayingInfo(const char *file, int line) const
uint64_t TranslatePositionMsToFrame(uint64_t dur_ms, float fallback_framerate, bool use_cutlist) const
Definition: deletemap.cpp:908
uint64_t TranslatePositionMsToFrame(uint64_t dur_ms, float fallback_framerate, const frm_dir_map_t &cutlist)
void Delete(uint64_t frame, const QString &undoMessage)
Remove the mark at the given frame.
Definition: deletemap.cpp:361
bool HandleAction(QString &action, uint64_t frame)
Definition: deletemap.cpp:85
#define ACTION_CLEARMAP
Definition: tv_actions.h:87
void Push(const QString &undoMessage)
Definition: deletemap.cpp:24
void SaveCutList(frm_dir_map_t &, bool isAutoSave=false) const
PictureAttribute next(PictureAttributeSupported supported, PictureAttribute attribute)
void NewCut(uint64_t frame)
Add a new cut marker (to start or end a cut region)
Definition: deletemap.cpp:394
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
void UpdateSeekAmount(int change)
Definition: deletemap.cpp:128
void Add(uint64_t frame, MarkTypes type)
Private addition to the deleteMap.
Definition: deletemap.cpp:549
bool QueryIsEditing(void) const
Queries "recorded" table for its "editing" field and returns true if it is set to true.
void ReverseAll(void)
Reverses the direction of each mark in the map.
Definition: deletemap.cpp:273
void SetText(const QString &window, const InfoMap &map, OSDTimeout timeout)
Definition: osd.cpp:414
uint64_t TranslatePositionRelToAbs(uint64_t position) const
Definition: deletemap.cpp:923
uint64_t GetTotalFrameCount(void) const
Definition: mythplayer.h:194
uint64_t TranslatePositionFrameToMs(long long position, float fallback_framerate, const frm_dir_map_t &cutlist)
void HideWindow(const QString &window)
Definition: osd.cpp:1135
PlayerContext * m_ctx
Definition: deletemap.h:109
Definition: osd.h:132
bool IsEmpty(void) const
Definition: deletemap.cpp:258
bool IsInDelete(uint64_t frame) const
Returns true if the given frame is deemed to be within a region that should be cut.
Definition: deletemap.cpp:570
void LoadCommBreakMap(frm_dir_map_t &map)
Loads the given commercial break map into the deleteMap.
Definition: deletemap.cpp:729
void TrackerReset(uint64_t frame)
Resets the internal state tracker.
Definition: deletemap.cpp:810
uint64_t TranslatePositionFrameToMs(uint64_t position, float fallback_framerate, bool use_cutlist) const
Definition: deletemap.cpp:899
bool IsFileEditing(void)
Determines whether the file is currently in edit mode.
Definition: deletemap.cpp:245
uint64_t GetNearestMark(uint64_t frame, bool right, bool *hasMark=nullptr) const
Returns the next or previous mark.
Definition: deletemap.cpp:610
void SetRegions(const QString &window, frm_dir_map_t &map, long long total)
Definition: osd.cpp:590
#define ACTION_DOWN
Definition: mythuiactions.h:17
DecoderBase * GetDecoder(void)
Returns the stream decoder currently in use.
Definition: mythplayer.h:278
frm_dir_map_t m_deleteMap
Definition: deletemap.h:104
bool IsWatchingInprogress(void) const
Definition: mythplayer.cpp:350
uint64_t GetCurrentFrameCount(void) const