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 "mythmiscutil.h"
12 #include "mythtypes.h" // for InfoMap
13 #include "mythuiactions.h" // for ACTION_DOWN, ACTION_UP
14 #include "playercontext.h" // for PlayerContext
15 #include "tv_actions.h" // for ACTION_CLEARMAP, etc
16 
17 #define LOC QString("DelMap: ")
18 #define EDIT_CHECK do { \
19  if(!m_editing) { \
20  LOG(VB_GENERAL, LOG_ERR, LOC + "Cannot edit outside edit mode."); \
21  return; \
22  } \
23 } while(false)
24 
25 void DeleteMap::Push(const QString &undoMessage)
26 {
27  DeleteMapUndoEntry entry(m_deleteMap, undoMessage);
28  // Remove all "redo" entries
29  while (m_undoStack.size() > m_undoStackPointer)
30  m_undoStack.pop_back();
31  m_undoStack.append(entry);
33  SaveMap(true);
34 }
35 
37  const QString &undoMessage)
38 {
39  // Temporarily roll back to the initial state, push the undo
40  // entry, then restore the correct state.
42  m_deleteMap = savedMap;
43  Push(undoMessage);
44  m_deleteMap = tmp;
45  SaveMap(true);
46 }
47 
48 bool DeleteMap::Undo(void)
49 {
50  if (!HasUndo())
51  return false;
55  m_undoStack[m_undoStackPointer].m_deleteMap = tmp;
56  m_changed = true;
57  SaveMap(true);
58  return true;
59 }
60 
61 bool DeleteMap::Redo(void)
62 {
63  if (!HasRedo())
64  return false;
67  m_undoStack[m_undoStackPointer].m_deleteMap = tmp;
69  m_changed = true;
70  SaveMap(true);
71  return true;
72 }
73 
74 QString DeleteMap::GetUndoMessage(void) const
75 {
76  return (HasUndo() ? m_undoStack[m_undoStackPointer - 1].m_message :
77  tr("(Nothing to undo)"));
78 }
79 
80 QString DeleteMap::GetRedoMessage(void) const
81 {
82  return (HasRedo() ? m_undoStack[m_undoStackPointer].m_message :
83  tr("(Nothing to redo)"));
84 }
85 
86 bool DeleteMap::HandleAction(QString &action, uint64_t frame)
87 {
88  bool handled = true;
89  if (action == ACTION_UP)
91  else if (action == ACTION_DOWN)
92  UpdateSeekAmount(-1);
93  else if (action == ACTION_CLEARMAP)
94  Clear(tr("Clear Cuts"));
95  else if (action == ACTION_INVERTMAP)
96  ReverseAll();
97  else if (action == "MOVEPREV")
98  MoveRelative(frame, false);
99  else if (action == "MOVENEXT")
100  MoveRelative(frame, true);
101  else if (action == "CUTTOBEGINNING")
102  {
103  Push(tr("Cut to Beginning"));
104  AddMark(frame, MARK_CUT_END);
105  }
106  else if (action == "CUTTOEND")
107  {
108  Push(tr("Cut to End"));
109  AddMark(frame, MARK_CUT_START);
110  // If the recording is still in progress, add an explicit end
111  // mark at the end.
114  }
115  else if (action == "NEWCUT")
116  NewCut(frame);
117  else if (action == "DELETE")
118  {
119  //: Delete the current cut or preserved region
120  Delete(frame, tr("Delete"));
121  }
122  else if (action == "UNDO")
123  {
124  Undo();
125  }
126  else if (action == "REDO")
127  {
128  Redo();
129  }
130  else
131  {
132  handled = false;
133  }
134  return handled;
135 }
136 
138 {
139  m_seekamountpos += change;
140  if (m_seekamountpos > 9)
141  m_seekamountpos = 9;
142  if (m_seekamountpos < 0)
143  m_seekamountpos = 0;
144 
145  m_seekText = "";
146  switch (m_seekamountpos)
147  {
148  case 0: m_seekText = tr("cut point"); m_seekamount = -2; break;
149  case 1: m_seekText = tr("keyframe"); m_seekamount = -1; break;
150  case 2: m_seekText = tr("1 frame"); m_seekamount = 0; break;
151  case 3: m_seekText = tr("0.5 seconds"); m_seekamount = 0.5; break;
152  case 4: m_seekText = tr("%n second(s)", "", 1); m_seekamount = 1; break;
153  case 5: m_seekText = tr("%n second(s)", "", 5); m_seekamount = 5; break;
154  case 6: m_seekText = tr("%n second(s)", "", 20); m_seekamount = 20; break;
155  case 7: m_seekText = tr("%n minute(s)", "", 1); m_seekamount = 60; break;
156  case 8: m_seekText = tr("%n minute(s)", "", 5); m_seekamount = 300; break;
157  case 9: m_seekText = tr("%n minute(s)", "", 10); m_seekamount = 600; break;
158  default: m_seekText = tr("error"); m_seekamount = 1; break;
159  }
160 }
161 
162 QString DeleteMap::CreateTimeString(uint64_t frame, bool use_cutlist,
163  double frame_rate, bool full_resolution)
164  const
165 {
166  uint64_t ms = TranslatePositionFrameToMs(frame, frame_rate, use_cutlist);
167  QString fmt = (ms >= ONEHOURINMS) ? "H:mm:ss" : "mm:ss";
168  if (full_resolution)
169  fmt += ".zzz";
170  return MythFormatTimeMs(ms, fmt);
171 }
172 
177 void DeleteMap::UpdateOSD(uint64_t frame, double frame_rate, OSD *osd)
178 {
179  if (!osd || !m_ctx)
180  return;
181  CleanMap();
182 
183  InfoMap infoMap;
184  m_ctx->LockPlayingInfo(__FILE__, __LINE__);
185  if (m_ctx->m_playingInfo)
186  m_ctx->m_playingInfo->ToMap(infoMap);
187  m_ctx->UnlockPlayingInfo(__FILE__, __LINE__);
188 
189  QString cutmarker = " ";
190  if (IsInDelete(frame))
191  cutmarker = tr("cut");
192 
193  uint64_t total = m_ctx->m_player->GetTotalFrameCount();
194  QString timestr = CreateTimeString(frame, false, frame_rate, true);
195  QString relTimeDisplay;
196  relTimeDisplay = CreateTimeString(frame, true, frame_rate, false);
197  QString relLengthDisplay;
198  relLengthDisplay = CreateTimeString(total, true, frame_rate, false);
199  infoMap["timedisplay"] = timestr;
200  infoMap["framedisplay"] = QString::number(frame);
201  infoMap["cutindicator"] = cutmarker;
202  infoMap["title"] = tr("Edit");
203  infoMap["seekamount"] = m_seekText;;
204  infoMap["reltimedisplay"] = relTimeDisplay;
205  infoMap["rellengthdisplay"] = relLengthDisplay;
206  //: example: "13:24 (10:23 of 24:37)"
207  infoMap["fulltimedisplay"] = tr("%3 (%1 of %2)").arg(relTimeDisplay)
208  .arg(relLengthDisplay).arg(timestr);
209 
210  QHash<QString,float> posMap;
211  posMap.insert("position", (float)((double)frame/(double)total));
212  osd->SetValues("osd_program_editor", posMap, kOSDTimeout_None);
213  osd->SetText("osd_program_editor", infoMap, kOSDTimeout_None);
214  if (m_changed || total != m_cachedTotalForOSD)
215  osd->SetRegions("osd_program_editor", m_deleteMap, total);
216  m_changed = false;
217  m_cachedTotalForOSD = total;
218 }
219 
220 void DeleteMap::UpdateOSD(int64_t timecode, OSD *osd)
221 {
222  osd->SetGraph("osd_program_editor", "audiograph", timecode);
223 }
224 
226 void DeleteMap::SetEditing(bool edit, OSD *osd)
227 {
228  if (osd && !edit)
229  osd->HideWindow("osd_program_editor");
230  m_editing = edit;
231 }
232 
235 {
236  if (m_ctx)
237  {
238  m_ctx->LockPlayingInfo(__FILE__, __LINE__);
239  if (m_ctx->m_playingInfo)
241  m_ctx->UnlockPlayingInfo(__FILE__, __LINE__);
242  }
243 }
244 
247 {
248  bool result = false;
249  if (m_ctx)
250  {
251  m_ctx->LockPlayingInfo(__FILE__, __LINE__);
252  if (m_ctx->m_playingInfo)
253  result = m_ctx->m_playingInfo->QueryIsEditing();
254  m_ctx->UnlockPlayingInfo(__FILE__, __LINE__);
255  }
256  return result;
257 }
258 
259 bool DeleteMap::IsEmpty(void) const
260 {
261  return m_deleteMap.empty();
262 }
263 
265 void DeleteMap::Clear(const QString& undoMessage)
266 {
267  if (!undoMessage.isEmpty())
268  Push(undoMessage);
269  m_deleteMap.clear();
270  m_changed = true;
271 }
272 
275 {
276  EDIT_CHECK;
277  Push(tr("Reverse Cuts"));
278  for (auto it = m_deleteMap.begin(); 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  auto otherframe = static_cast<uint64_t>(existing);
417  if (otherframe == frame)
418  Delete(otherframe);
419  else
420  {
421  uint64_t startframe = 0;
422  uint64_t endframe = 0;
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 = 0;
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  for (auto it = m_deleteMap.cbegin(); it != m_deleteMap.cend(); ++it)
647  if (MARK_PLACEHOLDER == it.value())
648  return true;
649  }
650 
651  return false;
652 }
653 
660 {
661  if (IsEmpty())
662  return;
663 
664  uint64_t total = m_ctx->m_player->GetTotalFrameCount();
665  Delete(0);
666  Delete(total);
667 
668  bool clear = false;
669  while (!IsEmpty() && !clear)
670  {
671  clear = true;
672  int lasttype = MARK_UNSET;
673  int64_t lastframe = -1;
674  int64_t tempframe = -1;
675  QList<int64_t> deleteList;
676  for (auto it = m_deleteMap.begin(); it != m_deleteMap.end(); ++it)
677  {
678  int thistype = it.value();
679  uint64_t thisframe = it.key();
680  if (thisframe >= total)
681  {
682  deleteList.append(thisframe);
683  }
684  else if (lasttype == thistype)
685  {
686  deleteList.append(thistype == MARK_CUT_END ? thisframe :
687  (uint64_t)lastframe);
688  clear = false;
689  break;
690  }
691  if (MARK_PLACEHOLDER == thistype)
692  {
693  if (tempframe > 0)
694  deleteList.append(tempframe);
695  tempframe = thisframe;
696  }
697  else
698  {
699  lasttype = thistype;
700  lastframe = thisframe;
701  }
702  }
703 
704  // Delete the unwanted frame marks safely, and not while iterating over
705  // the map which would lead to a crash
706  for (const long & dit : qAsConst(deleteList))
707  {
708  Delete(dit);
709  }
710  deleteList.clear();
711  }
712 }
713 
716 {
717  // Can't save an undo point for SetMap() or transcodes fail.
718  // Leaving as a marker for refactor.
719  //Push(tr("Set New Cut List"));
720 
721  Clear();
722  m_deleteMap = map;
723 }
724 
727 {
728  Push(tr("Load Detected Commercials"));
729  Clear();
730  for (auto it = map.begin(); it != map.end(); ++it)
731  Add(it.key(), it.value() == MARK_COMM_START ?
733  CleanMap();
734 }
735 
737 void DeleteMap::LoadMap(const QString& undoMessage)
738 {
740  return;
741 
742  if (!undoMessage.isEmpty())
743  Push(undoMessage);
744  Clear();
745  m_ctx->LockPlayingInfo(__FILE__, __LINE__);
747  m_ctx->UnlockPlayingInfo(__FILE__, __LINE__);
748  CleanMap();
749 }
750 
754 {
756  return false;
757 
758  frm_dir_map_t tmpDeleteMap = m_deleteMap;
759  Clear();
760  m_ctx->LockPlayingInfo(__FILE__, __LINE__);
761  bool result = m_ctx->m_playingInfo->QueryCutList(m_deleteMap, true);
762  m_ctx->UnlockPlayingInfo(__FILE__, __LINE__);
763  CleanMap();
764  if (result)
765  PushDeferred(tmpDeleteMap, tr("Load Auto-saved Cuts"));
766  else
767  m_deleteMap = tmpDeleteMap;
768 
769  return result;
770 }
771 
773 void DeleteMap::SaveMap(bool isAutoSave)
774 {
776  return;
777 
778  if (!isAutoSave)
779  {
780  // Remove temporary placeholder marks
781  QMutableMapIterator<uint64_t, MarkTypes> it(m_deleteMap);
782  while (it.hasNext())
783  {
784  it.next();
785  if (MARK_PLACEHOLDER == it.value())
786  {
787  it.remove();
788  m_changed = true;
789  }
790  }
791 
792  CleanMap();
793  }
794  m_ctx->LockPlayingInfo(__FILE__, __LINE__);
797  m_ctx->UnlockPlayingInfo(__FILE__, __LINE__);
798 }
799 
806 void DeleteMap::TrackerReset(uint64_t frame)
807 {
808  m_nextCutStart = 0;
809  m_nextCutStartIsValid = false;
810  if (IsEmpty())
811  return;
812 
813  frm_dir_map_t::iterator cutpoint = m_deleteMap.find(frame);
814  if (cutpoint != m_deleteMap.end())
815  {
816  if (cutpoint.value() == MARK_CUT_START)
817  {
818  m_nextCutStartIsValid = true;
819  m_nextCutStart = cutpoint.key();
820  }
821  else
822  {
823  ++cutpoint;
824  m_nextCutStartIsValid = (cutpoint != m_deleteMap.end());
825  m_nextCutStart = m_nextCutStartIsValid ? cutpoint.key() :
827  }
828  }
829  else
830  m_nextCutStart = GetNearestMark(frame, !IsInDelete(frame),
832  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Tracker next CUT_START: %1")
833  .arg(m_nextCutStart));
834 }
835 
840 bool DeleteMap::TrackerWantsToJump(uint64_t frame, uint64_t &to) const
841 {
842  if (IsEmpty() || !m_nextCutStartIsValid || frame < m_nextCutStart)
843  return false;
844 
845  to = GetNearestMark(m_nextCutStart, true);
846  LOG(VB_PLAYBACK, LOG_INFO, LOC +
847  QString("Tracker wants to jump to: %1").arg(to));
848  return true;
849 }
850 
855 uint64_t DeleteMap::GetLastFrame(void) const
856 {
857  uint64_t result = m_ctx->m_player->GetCurrentFrameCount();
858  if (IsEmpty())
859  return result;
860 
861  frm_dir_map_t::const_iterator it = m_deleteMap.end();
862  --it;
863 
864  if (it.value() == MARK_CUT_START)
865  result = it.key();
866  return result;
867 }
868 
872 bool DeleteMap::IsSaved(void) const
873 {
875  return true;
876 
877  frm_dir_map_t currentMap(m_deleteMap);
878  frm_dir_map_t savedMap;
879  m_ctx->LockPlayingInfo(__FILE__, __LINE__);
880  m_ctx->m_playingInfo->QueryCutList(savedMap);
881  m_ctx->UnlockPlayingInfo(__FILE__, __LINE__);
882 
883  // Remove temporary placeholder marks from currentMap
884  QMutableMapIterator<uint64_t, MarkTypes> it(currentMap);
885  while (it.hasNext())
886  {
887  it.next();
888  if (MARK_PLACEHOLDER == it.value())
889  it.remove();
890  }
891 
892  return currentMap == savedMap;
893 }
894 
895 uint64_t DeleteMap::TranslatePositionFrameToMs(uint64_t position,
896  float fallback_framerate,
897  bool use_cutlist) const
898 {
899  return m_ctx->m_player->GetDecoder()
900  ->TranslatePositionFrameToMs(position, fallback_framerate,
901  use_cutlist ? m_deleteMap :
902  frm_dir_map_t());
903 }
904 uint64_t DeleteMap::TranslatePositionMsToFrame(uint64_t dur_ms,
905  float fallback_framerate,
906  bool use_cutlist) const
907 {
908  return m_ctx->m_player->GetDecoder()
909  ->TranslatePositionMsToFrame(dur_ms, fallback_framerate,
910  use_cutlist ? m_deleteMap :
911  frm_dir_map_t());
912 }
913 
914 uint64_t DeleteMap::TranslatePositionAbsToRel(uint64_t position) const
915 {
917 }
918 
919 uint64_t DeleteMap::TranslatePositionRelToAbs(uint64_t position) const
920 {
922 }
void SetEditing(bool edit, OSD *osd=nullptr)
Set the edit mode and optionally hide the edit mode OSD.
Definition: deletemap.cpp:226
void SetMap(const frm_dir_map_t &map)
Use the given map.
Definition: deletemap.cpp:715
void CleanMap(void)
Removes redundant marks and ensures the markup sequence is valid.
Definition: deletemap.cpp:659
MythPlayer * m_player
float m_seekamount
Definition: deletemap.h:111
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:234
void PushDeferred(const frm_dir_map_t &savedMap, const QString &undoMessage)
Definition: deletemap.cpp:36
void SetEditing(bool editing)
Definition: programinfo.h:533
#define ACTION_INVERTMAP
Definition: tv_actions.h:87
bool m_changed
Definition: deletemap.h:109
uint64_t TranslatePositionAbsToRel(uint64_t position) const
Definition: deletemap.cpp:914
void Clear(const QString &undoMessage="")
Clears the deleteMap.
Definition: deletemap.cpp:265
uint64_t m_cachedTotalForOSD
Definition: deletemap.h:113
#define LOC
Definition: deletemap.cpp:17
QHash< QString, QString > InfoMap
Definition: mythtypes.h:15
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:855
#define EDIT_CHECK
Definition: deletemap.cpp:18
bool HasUndo(void) const
Definition: deletemap.h:86
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:61
bool TrackerWantsToJump(uint64_t frame, uint64_t &to) const
Returns true if the given frame has passed the last cut point start and provides the frame number of ...
Definition: deletemap.cpp:840
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:177
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:80
void AddMark(uint64_t frame, MarkTypes type)
Add a new mark of the given type.
Definition: deletemap.cpp:289
static guint32 * tmp
Definition: goom_core.cpp:30
bool Undo(void)
Definition: deletemap.cpp:48
int m_undoStackPointer
Definition: deletemap.h:116
int m_seekamountpos
Definition: deletemap.h:110
QString CreateTimeString(uint64_t frame, bool use_cutlist, double frame_rate, bool full_resolution) const
Definition: deletemap.cpp:162
bool IsTemporaryMark(uint64_t frame) const
Returns true if the given frame is a temporary/placeholder mark.
Definition: deletemap.cpp:595
void SetGraph(const QString &Window, const QString &Graph, int64_t Timecode)
Definition: osd.cpp:618
void SaveMap(bool isAutoSave=false)
Saves the delete map to the database.
Definition: deletemap.cpp:773
bool m_editing
Definition: deletemap.h:104
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:753
uint64_t m_nextCutStart
Definition: deletemap.h:106
bool IsSaved(void) const
Compares the current cut list with the saved cut list.
Definition: deletemap.cpp:872
void LoadMap(const QString &undoMessage="")
Loads the delete map from the database.
Definition: deletemap.cpp:737
void SetText(const QString &Window, const InfoMap &Map, OSDTimeout Timeout)
Definition: osd.cpp:377
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:115
void HideWindow(const QString &Window)
Definition: osd.cpp:909
QString GetUndoMessage(void) const
Definition: deletemap.cpp:74
static void clear(SettingsMap &cache, SettingsMap &overrides, const QString &myKey)
Definition: mythdb.cpp:846
bool HasRedo(void) const
Definition: deletemap.h:87
bool m_nextCutStartIsValid
Definition: deletemap.h:105
QString m_seekText
Definition: deletemap.h:108
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:904
uint64_t TranslatePositionMsToFrame(uint64_t dur_ms, float fallback_framerate, const frm_dir_map_t &cutlist)
void SetRegions(const QString &Window, frm_dir_map_t &Map, long long Total)
Definition: osd.cpp:552
void Delete(uint64_t frame, const QString &undoMessage)
Remove the mark at the given frame.
Definition: deletemap.cpp:361
QString MythFormatTimeMs(int msecs, QString fmt)
Format a milliseconds time value.
bool HandleAction(QString &action, uint64_t frame)
Definition: deletemap.cpp:86
#define ACTION_CLEARMAP
Definition: tv_actions.h:86
void Push(const QString &undoMessage)
Definition: deletemap.cpp:25
void SetValues(const QString &Window, const QHash< QString, int > &Map, OSDTimeout Timeout)
Definition: osd.cpp:319
#define ONEHOURINMS
Definition: mythmiscutil.h:91
void NewCut(uint64_t frame)
Add a new cut marker (to start or end a cut region)
Definition: deletemap.cpp:394
void UpdateSeekAmount(int change)
Definition: deletemap.cpp:137
PictureAttribute next(PictureAttributeSupported Supported, PictureAttribute Attribute)
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:274
uint64_t TranslatePositionRelToAbs(uint64_t position) const
Definition: deletemap.cpp:919
uint64_t GetTotalFrameCount(void) const
Definition: mythplayer.h:236
uint64_t TranslatePositionFrameToMs(long long position, float fallback_framerate, const frm_dir_map_t &cutlist)
PlayerContext * m_ctx
Definition: deletemap.h:112
Definition: osd.h:131
bool IsEmpty(void) const
Definition: deletemap.cpp:259
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:726
void TrackerReset(uint64_t frame)
Resets the internal state tracker.
Definition: deletemap.cpp:806
uint64_t TranslatePositionFrameToMs(uint64_t position, float fallback_framerate, bool use_cutlist) const
Definition: deletemap.cpp:895
QMap< uint64_t, MarkTypes > frm_dir_map_t
Frame # -> Mark map.
Definition: programtypes.h:81
bool IsFileEditing(void)
Determines whether the file is currently in edit mode.
Definition: deletemap.cpp:246
uint64_t GetNearestMark(uint64_t frame, bool right, bool *hasMark=nullptr) const
Returns the next or previous mark.
Definition: deletemap.cpp:610
bool QueryCutList(frm_dir_map_t &delMap, bool loadAutosave=false) const
#define ACTION_DOWN
Definition: mythuiactions.h:17
DecoderBase * GetDecoder(void)
Returns the stream decoder currently in use.
Definition: mythplayer.h:313
frm_dir_map_t m_deleteMap
Definition: deletemap.h:107
bool IsWatchingInprogress(void) const
Definition: mythplayer.cpp:221
void SaveCutList(frm_dir_map_t &delMap, bool isAutoSave=false) const
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
uint64_t GetCurrentFrameCount(void) const