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