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 }
MythFormatTimeMs
QString MythFormatTimeMs(int msecs, const QString &fmt)
Format a milliseconds time value.
Definition: mythmiscutil.cpp:1232
ACTION_UP
#define ACTION_UP
Definition: mythuiactions.h:16
DeleteMap::SaveMap
void SaveMap(bool isAutoSave=false)
Saves the delete map to the database.
Definition: deletemap.cpp:773
PlayerContext::UnlockPlayingInfo
void UnlockPlayingInfo(const char *file, int line) const
Definition: playercontext.cpp:557
DeleteMap::Add
void Add(uint64_t frame, MarkTypes type)
Private addition to the deleteMap.
Definition: deletemap.cpp:549
MythPlayer::GetTotalFrameCount
uint64_t GetTotalFrameCount(void) const
Definition: mythplayer.h:236
deletemap.h
DeleteMap::ReverseAll
void ReverseAll(void)
Reverses the direction of each mark in the map.
Definition: deletemap.cpp:274
DeleteMap::TranslatePositionRelToAbs
uint64_t TranslatePositionRelToAbs(uint64_t position) const
Definition: deletemap.cpp:919
DeleteMap::TrackerReset
void TrackerReset(uint64_t frame)
Resets the internal state tracker.
Definition: deletemap.cpp:806
ACTION_DOWN
#define ACTION_DOWN
Definition: mythuiactions.h:17
DeleteMap::m_undoStack
QVector< DeleteMapUndoEntry > m_undoStack
Definition: deletemap.h:115
MARK_PLACEHOLDER
@ MARK_PLACEHOLDER
Definition: programtypes.h:54
DeleteMap::LoadAutoSaveMap
bool LoadAutoSaveMap(void)
Returns true if an auto-save map was loaded.
Definition: deletemap.cpp:753
DeleteMap::GetNearestMark
uint64_t GetNearestMark(uint64_t frame, bool right, bool *hasMark=nullptr) const
Returns the next or previous mark.
Definition: deletemap.cpp:610
DeleteMap::SetMap
void SetMap(const frm_dir_map_t &map)
Use the given map.
Definition: deletemap.cpp:715
LOC
#define LOC
Definition: deletemap.cpp:17
DeleteMap::HandleAction
bool HandleAction(QString &action, uint64_t frame)
Definition: deletemap.cpp:86
MARK_CUT_END
@ MARK_CUT_END
Definition: programtypes.h:55
OSD::SetGraph
void SetGraph(const QString &Window, const QString &Graph, int64_t Timecode)
Definition: osd.cpp:608
MythCoreContext::IsDatabaseIgnored
bool IsDatabaseIgnored(void) const
/brief Returns true if database is being ignored.
Definition: mythcorecontext.cpp:894
arg
arg(title).arg(filename).arg(doDelete))
DeleteMap::SetFileEditing
void SetFileEditing(bool edit)
Update the editing status in the file's ProgramInfo.
Definition: deletemap.cpp:234
frm_dir_map_t
QMap< uint64_t, MarkTypes > frm_dir_map_t
Frame # -> Mark map.
Definition: programtypes.h:82
ProgramInfo::SetEditing
void SetEditing(bool editing)
Definition: programinfo.h:534
osd.h
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
MythPlayer::GetCurrentFrameCount
uint64_t GetCurrentFrameCount(void) const
Definition: mythplayer.cpp:4873
DeleteMap::IsEmpty
bool IsEmpty(void) const
Definition: deletemap.cpp:259
OSD::SetText
void SetText(const QString &Window, const InfoMap &Map, OSDTimeout Timeout)
Definition: osd.cpp:377
mythplayer.h
DeleteMap::TranslatePositionMsToFrame
uint64_t TranslatePositionMsToFrame(uint64_t dur_ms, float fallback_framerate, bool use_cutlist) const
Definition: deletemap.cpp:904
kOSDTimeout_None
@ kOSDTimeout_None
Definition: osd.h:60
DeleteMap::m_nextCutStart
uint64_t m_nextCutStart
Definition: deletemap.h:106
DeleteMapUndoEntry
Definition: deletemap.h:17
OSD::SetRegions
void SetRegions(const QString &Window, frm_dir_map_t &Map, long long Total)
Definition: osd.cpp:542
DeleteMap::SetEditing
void SetEditing(bool edit, OSD *osd=nullptr)
Set the edit mode and optionally hide the edit mode OSD.
Definition: deletemap.cpp:226
DeleteMap::Push
void Push(const QString &undoMessage)
Definition: deletemap.cpp:25
DeleteMap::GetUndoMessage
QString GetUndoMessage(void) const
Definition: deletemap.cpp:74
DeleteMap::TrackerWantsToJump
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
tmp
static guint32 * tmp
Definition: goom_core.cpp:30
ACTION_INVERTMAP
#define ACTION_INVERTMAP
Definition: tv_actions.h:87
DeleteMap::CleanMap
void CleanMap(void)
Removes redundant marks and ensures the markup sequence is valid.
Definition: deletemap.cpp:659
InfoMap
QHash< QString, QString > InfoMap
Definition: mythtypes.h:15
OSD::HideWindow
void HideWindow(const QString &Window)
Definition: osd.cpp:899
DeleteMap::m_changed
bool m_changed
Definition: deletemap.h:109
DecoderBase::TranslatePositionAbsToRel
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)
Definition: decoderbase.cpp:1361
programinfo.h
mythlogging.h
ACTION_CLEARMAP
#define ACTION_CLEARMAP
Definition: tv_actions.h:86
PlayerContext::m_playingInfo
ProgramInfo * m_playingInfo
Currently playing info.
Definition: playercontext.h:156
tv_actions.h
DeleteMap::NewCut
void NewCut(uint64_t frame)
Add a new cut marker (to start or end a cut region)
Definition: deletemap.cpp:394
PlayerContext::LockPlayingInfo
void LockPlayingInfo(const char *file, int line) const
Definition: playercontext.cpp:545
DecoderBase::TranslatePositionRelToAbs
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)
Definition: decoderbase.cpp:1410
DeleteMap::m_ctx
PlayerContext * m_ctx
Definition: deletemap.h:112
DeleteMap::IsInDelete
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
ProgramInfo::QueryCutList
bool QueryCutList(frm_dir_map_t &delMap, bool loadAutosave=false) const
Definition: programinfo.cpp:3291
mythtypes.h
DeleteMap::m_deleteMap
frm_dir_map_t m_deleteMap
Definition: deletemap.h:107
clear
static void clear(SettingsMap &cache, SettingsMap &overrides, const QString &myKey)
Definition: mythdb.cpp:846
DeleteMap::LoadMap
void LoadMap(const QString &undoMessage="")
Loads the delete map from the database.
Definition: deletemap.cpp:737
DeleteMap::TranslatePositionFrameToMs
uint64_t TranslatePositionFrameToMs(uint64_t position, float fallback_framerate, bool use_cutlist) const
Definition: deletemap.cpp:895
EDIT_CHECK
#define EDIT_CHECK
Definition: deletemap.cpp:18
DeleteMap::TranslatePositionAbsToRel
uint64_t TranslatePositionAbsToRel(uint64_t position) const
Definition: deletemap.cpp:914
DeleteMap::Clear
void Clear(const QString &undoMessage="")
Clears the deleteMap.
Definition: deletemap.cpp:265
DeleteMap::IsFileEditing
bool IsFileEditing(void)
Determines whether the file is currently in edit mode.
Definition: deletemap.cpp:246
DeleteMap::LoadCommBreakMap
void LoadCommBreakMap(frm_dir_map_t &map)
Loads the given commercial break map into the deleteMap.
Definition: deletemap.cpp:726
DeleteMap::HasRedo
bool HasRedo(void) const
Definition: deletemap.h:87
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:57
DeleteMap::AddMark
void AddMark(uint64_t frame, MarkTypes type)
Add a new mark of the given type.
Definition: deletemap.cpp:289
ONEHOURINMS
#define ONEHOURINMS
Definition: mythmiscutil.h:94
DeleteMap::m_nextCutStartIsValid
bool m_nextCutStartIsValid
Definition: deletemap.h:105
MythPlayer::GetDecoder
DecoderBase * GetDecoder(void)
Returns the stream decoder currently in use.
Definition: mythplayer.h:313
DeleteMap::m_undoStackPointer
int m_undoStackPointer
Definition: deletemap.h:116
DeleteMap::CreateTimeString
QString CreateTimeString(uint64_t frame, bool use_cutlist, double frame_rate, bool full_resolution) const
Definition: deletemap.cpp:162
DeleteMap::IsSaved
bool IsSaved(void) const
Compares the current cut list with the saved cut list.
Definition: deletemap.cpp:872
MARK_CUT_START
@ MARK_CUT_START
Definition: programtypes.h:56
DeleteMap::m_cachedTotalForOSD
uint64_t m_cachedTotalForOSD
Definition: deletemap.h:113
next
PictureAttribute next(PictureAttributeSupported Supported, PictureAttribute Attribute)
Definition: videoouttypes.h:350
mythmiscutil.h
DecoderBase::TranslatePositionMsToFrame
uint64_t TranslatePositionMsToFrame(uint64_t dur_ms, float fallback_framerate, const frm_dir_map_t &cutlist)
Definition: decoderbase.cpp:1337
MythPlayer::IsWatchingInprogress
bool IsWatchingInprogress(void) const
Definition: mythplayer.cpp:221
DeleteMap::Delete
void Delete(uint64_t frame, const QString &undoMessage)
Remove the mark at the given frame.
Definition: deletemap.cpp:361
mythcorecontext.h
DeleteMap::Move
void Move(uint64_t frame, uint64_t to)
Move an existing mark to a new frame.
Definition: deletemap.cpp:533
playercontext.h
MARK_UPDATED_CUT
@ MARK_UPDATED_CUT
Definition: programtypes.h:53
ProgramInfo::QueryIsEditing
bool QueryIsEditing(void) const
Queries "recorded" table for its "editing" field and returns true if it is set to true.
Definition: programinfo.cpp:2927
DecoderBase::TranslatePositionFrameToMs
uint64_t TranslatePositionFrameToMs(long long position, float fallback_framerate, const frm_dir_map_t &cutlist)
Definition: decoderbase.cpp:1309
MarkTypes
MarkTypes
Definition: programtypes.h:48
DeleteMap::Redo
bool Redo(void)
Definition: deletemap.cpp:61
DeleteMap::MoveRelative
void MoveRelative(uint64_t frame, bool right)
Move the previous (!right) or next (right) cut to frame.
Definition: deletemap.cpp:498
DeleteMap::PushDeferred
void PushDeferred(const frm_dir_map_t &savedMap, const QString &undoMessage)
Definition: deletemap.cpp:36
ProgramInfo::SaveCutList
void SaveCutList(frm_dir_map_t &delMap, bool isAutoSave=false) const
Definition: programinfo.cpp:3323
ProgramInfo::ToMap
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...
Definition: programinfo.cpp:1464
DeleteMap::HasTemporaryMark
bool HasTemporaryMark(void) const
Returns true if a temporary placeholder mark is defined.
Definition: deletemap.cpp:642
build_compdb.action
action
Definition: build_compdb.py:9
DeleteMap::m_editing
bool m_editing
Definition: deletemap.h:104
OSD::SetValues
void SetValues(const QString &Window, const QHash< QString, int > &Map, OSDTimeout Timeout)
Definition: osd.cpp:319
MARK_UNSET
@ MARK_UNSET
Definition: programtypes.h:50
ProgramInfo::SaveMarkupFlag
void SaveMarkupFlag(MarkTypes type) const
Clears the specified flag, then if sets it.
Definition: programinfo.cpp:3582
mythuiactions.h
DeleteMap::Undo
bool Undo(void)
Definition: deletemap.cpp:48
DeleteMap::m_seekamountpos
int m_seekamountpos
Definition: deletemap.h:110
DeleteMap::HasUndo
bool HasUndo(void) const
Definition: deletemap.h:86
DeleteMap::IsTemporaryMark
bool IsTemporaryMark(uint64_t frame) const
Returns true if the given frame is a temporary/placeholder mark.
Definition: deletemap.cpp:595
DeleteMap::GetLastFrame
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
PlayerContext::m_player
MythPlayer * m_player
Definition: playercontext.h:151
MARK_COMM_START
@ MARK_COMM_START
Definition: programtypes.h:59
DeleteMap::UpdateOSD
void UpdateOSD(uint64_t frame, double frame_rate, OSD *osd)
Show and update the edit mode On Screen Display.
Definition: deletemap.cpp:177
DeleteMap::m_seekText
QString m_seekText
Definition: deletemap.h:108
OSD
Definition: osd.h:132
DeleteMap::m_seekamount
float m_seekamount
Definition: deletemap.h:111
DeleteMap::UpdateSeekAmount
void UpdateSeekAmount(int change)
Definition: deletemap.cpp:137
DeleteMap::GetRedoMessage
QString GetRedoMessage(void) const
Definition: deletemap.cpp:80