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