|
MythTV
0.26-pre
|
00001 #include <cmath> 00002 #include <stdint.h> 00003 00004 #include "mythlogging.h" 00005 #include "mythcontext.h" 00006 #include "osd.h" 00007 #include "deletemap.h" 00008 #include "mythplayer.h" 00009 00010 #define LOC QString("DelMap: ") 00011 #define EDIT_CHECK do { \ 00012 if(!m_editing) { \ 00013 LOG(VB_GENERAL, LOG_ERR, LOC + "Cannot edit outside edit mode."); \ 00014 return; \ 00015 } \ 00016 } while(0) 00017 00018 DeleteMapUndoEntry::DeleteMapUndoEntry(frm_dir_map_t dm, QString msg) : 00019 deleteMap(dm), message(msg) { } 00020 00021 DeleteMapUndoEntry::DeleteMapUndoEntry(void) 00022 { 00023 frm_dir_map_t dm; 00024 deleteMap = dm; 00025 message = ""; 00026 } 00027 00028 void DeleteMap::Push(QString undoMessage) 00029 { 00030 DeleteMapUndoEntry entry(m_deleteMap, undoMessage); 00031 // Remove all "redo" entries 00032 while (m_undoStack.size() > m_undoStackPointer + 1) 00033 m_undoStack.pop_back(); 00034 m_undoStack.append(entry); 00035 m_undoStackPointer ++; 00036 SaveMap(0, true); 00037 } 00038 00039 bool DeleteMap::Undo(void) 00040 { 00041 if (!HasUndo()) 00042 return false; 00043 m_undoStackPointer --; 00044 m_deleteMap = m_undoStack[m_undoStackPointer].deleteMap; 00045 m_changed = true; 00046 SaveMap(0, true); 00047 return true; 00048 } 00049 00050 bool DeleteMap::Redo(void) 00051 { 00052 if (!HasRedo()) 00053 return false; 00054 m_undoStackPointer ++; 00055 m_deleteMap = m_undoStack[m_undoStackPointer].deleteMap; 00056 m_changed = true; 00057 SaveMap(0, true); 00058 return true; 00059 } 00060 00061 QString DeleteMap::GetUndoMessage(void) const 00062 { 00063 return (HasUndo() ? m_undoStack[m_undoStackPointer].message : 00064 QObject::tr("(Nothing to undo)")); 00065 } 00066 00067 QString DeleteMap::GetRedoMessage(void) const 00068 { 00069 return (HasRedo() ? m_undoStack[m_undoStackPointer + 1].message : 00070 QObject::tr("(Nothing to redo)")); 00071 } 00072 00073 bool DeleteMap::HandleAction(QString &action, uint64_t frame, 00074 uint64_t played, uint64_t total, double rate) 00075 { 00076 bool handled = true; 00077 if (action == ACTION_UP) 00078 UpdateSeekAmount(1, rate); 00079 else if (action == ACTION_DOWN) 00080 UpdateSeekAmount(-1, rate); 00081 else if (action == ACTION_CLEARMAP) 00082 Clear(QObject::tr("Clear Cuts")); 00083 else if (action == ACTION_INVERTMAP) 00084 ReverseAll(total); 00085 else if (action == "MOVEPREV") 00086 MoveRelative(frame, total, false); 00087 else if (action == "MOVENEXT") 00088 MoveRelative(frame, total, true); 00089 else if (action == "CUTTOBEGINNING") 00090 Add(frame, total, MARK_CUT_END, QObject::tr("Cut to Beginning")); 00091 else if (action == "CUTTOEND") 00092 { 00093 Add(frame, total, MARK_CUT_START, QObject::tr("Cut to End")); 00094 // If the recording is still in progress, add an explicit end 00095 // mark at the end. 00096 if (m_ctx->player && m_ctx->player->IsWatchingInprogress()) 00097 Add(total - 1, total, MARK_CUT_END, ""); 00098 } 00099 else if (action == "NEWCUT") 00100 NewCut(frame, total); 00101 else if (action == "DELETE") 00102 Delete(frame, total, QObject::tr("Delete")); 00103 else if (action == "UNDO") 00104 Undo(); 00105 else if (action == "REDO") 00106 Redo(); 00107 else 00108 handled = false; 00109 return handled; 00110 } 00111 00112 void DeleteMap::UpdateSeekAmount(int change, double framerate) 00113 { 00114 m_seekamountpos += change; 00115 if (m_seekamountpos > 9) 00116 m_seekamountpos = 9; 00117 if (m_seekamountpos < 0) 00118 m_seekamountpos = 0; 00119 00120 m_seekText = ""; 00121 switch (m_seekamountpos) 00122 { 00123 case 0: m_seekText = QObject::tr("cut point"); m_seekamount = -2; break; 00124 case 1: m_seekText = QObject::tr("keyframe"); m_seekamount = -1; break; 00125 case 2: m_seekText = QObject::tr("1 frame"); m_seekamount = 1; break; 00126 case 3: m_seekText = QObject::tr("0.5 seconds"); m_seekamount = (int)roundf(framerate / 2); break; 00127 case 4: m_seekText = QObject::tr("%n second(s)", "", 1); m_seekamount = (int)roundf(framerate); break; 00128 case 5: m_seekText = QObject::tr("%n second(s)", "", 5); m_seekamount = (int)roundf(framerate * 5); break; 00129 case 6: m_seekText = QObject::tr("%n second(s)", "", 20); m_seekamount = (int)roundf(framerate * 20); break; 00130 case 7: m_seekText = QObject::tr("%n minute(s)", "", 1); m_seekamount = (int)roundf(framerate * 60); break; 00131 case 8: m_seekText = QObject::tr("%n minute(s)", "", 5); m_seekamount = (int)roundf(framerate * 300); break; 00132 case 9: m_seekText = QObject::tr("%n minute(s)", "", 10); m_seekamount = (int)roundf(framerate * 600); break; 00133 default: m_seekText = QObject::tr("error"); m_seekamount = (int)roundf(framerate); break; 00134 } 00135 } 00136 00137 static QString createTimeString(uint64_t frame, uint64_t total, 00138 double frame_rate, bool full_resolution) 00139 { 00140 int secs = (int)(frame / frame_rate); 00141 int frames = frame - (int)(secs * frame_rate); 00142 int totalSecs = (int)(total / frame_rate); 00143 QString timestr; 00144 if (totalSecs >= 3600) 00145 timestr = QString::number(secs / 3600) + ":"; 00146 timestr += QString("%1").arg((secs / 60) % 60, 2, 10, QChar(48)) + 00147 QString(":%1").arg(secs % 60, 2, 10, QChar(48)); 00148 if (full_resolution) 00149 timestr += QString(".%1").arg(frames, 2, 10, QChar(48)); 00150 return timestr; 00151 } 00152 00157 void DeleteMap::UpdateOSD(uint64_t frame, uint64_t total, double frame_rate, 00158 OSD *osd) 00159 { 00160 if (!osd || !m_ctx) 00161 return; 00162 CleanMap(total); 00163 00164 InfoMap infoMap; 00165 m_ctx->LockPlayingInfo(__FILE__, __LINE__); 00166 if (m_ctx->playingInfo) 00167 m_ctx->playingInfo->ToMap(infoMap); 00168 infoMap.detach(); 00169 m_ctx->UnlockPlayingInfo(__FILE__, __LINE__); 00170 00171 QString cutmarker = " "; 00172 if (IsInDelete(frame)) 00173 cutmarker = QObject::tr("cut"); 00174 00175 QString timestr = createTimeString(frame, total, frame_rate, true); 00176 uint64_t relTotal = TranslatePositionAbsToRel(total); 00177 QString relTimeDisplay = createTimeString(TranslatePositionAbsToRel(frame), 00178 relTotal, frame_rate, false); 00179 QString relLengthDisplay = createTimeString(relTotal, 00180 relTotal, frame_rate, false); 00181 infoMap["timedisplay"] = timestr; 00182 infoMap["framedisplay"] = QString::number(frame); 00183 infoMap["cutindicator"] = cutmarker; 00184 infoMap["title"] = QObject::tr("Edit"); 00185 infoMap["seekamount"] = m_seekText;; 00186 infoMap["reltimedisplay"] = relTimeDisplay; 00187 infoMap["rellengthdisplay"] = relLengthDisplay; 00188 infoMap["fulltimedisplay"] = timestr + " (" + 00189 QObject::tr("%1 of %2").arg(relTimeDisplay).arg(relLengthDisplay) + ")"; 00190 00191 QHash<QString,float> posMap; 00192 posMap.insert("position", (float)((double)frame/(double)total)); 00193 osd->SetValues("osd_program_editor", posMap, kOSDTimeout_None); 00194 osd->SetText("osd_program_editor", infoMap, kOSDTimeout_None); 00195 if (m_changed || total != m_cachedTotalForOSD) 00196 osd->SetRegions("osd_program_editor", m_deleteMap, total); 00197 m_changed = false; 00198 m_cachedTotalForOSD = total; 00199 } 00200 00202 void DeleteMap::SetEditing(bool edit, OSD *osd) 00203 { 00204 if (osd && !edit) 00205 osd->HideWindow("osd_program_editor"); 00206 m_editing = edit; 00207 } 00208 00210 void DeleteMap::SetFileEditing(bool edit) 00211 { 00212 if (m_ctx) 00213 { 00214 m_ctx->LockPlayingInfo(__FILE__, __LINE__); 00215 if (m_ctx->playingInfo) 00216 m_ctx->playingInfo->SetEditing(edit); 00217 m_ctx->UnlockPlayingInfo(__FILE__, __LINE__); 00218 } 00219 } 00220 00222 bool DeleteMap::IsFileEditing(void) 00223 { 00224 bool result = false; 00225 if (m_ctx) 00226 { 00227 m_ctx->LockPlayingInfo(__FILE__, __LINE__); 00228 if (m_ctx->playingInfo) 00229 result = m_ctx->playingInfo->QueryIsEditing(); 00230 m_ctx->UnlockPlayingInfo(__FILE__, __LINE__); 00231 } 00232 return result; 00233 } 00234 00235 bool DeleteMap::IsEmpty(void) const 00236 { 00237 return m_deleteMap.empty(); 00238 } 00239 00241 void DeleteMap::Clear(QString undoMessage) 00242 { 00243 m_deleteMap.clear(); 00244 m_changed = true; 00245 if (!undoMessage.isEmpty()) 00246 Push(undoMessage); 00247 } 00248 00250 void DeleteMap::ReverseAll(uint64_t total) 00251 { 00252 EDIT_CHECK; 00253 frm_dir_map_t::Iterator it = m_deleteMap.begin(); 00254 for ( ; it != m_deleteMap.end(); ++it) 00255 Add(it.key(), it.value() == MARK_CUT_END ? MARK_CUT_START : 00256 MARK_CUT_END); 00257 CleanMap(total); 00258 Push(QObject::tr("Reverse Cuts")); 00259 } 00260 00266 void DeleteMap::Add(uint64_t frame, uint64_t total, MarkTypes type, 00267 QString undoMessage) 00268 { 00269 EDIT_CHECK; 00270 if ((MARK_CUT_START != type) && (MARK_CUT_END != type) && 00271 (MARK_PLACEHOLDER != type)) 00272 return; 00273 00274 frm_dir_map_t::Iterator find_temporary = m_deleteMap.find(frame); 00275 if (find_temporary != m_deleteMap.end()) 00276 { 00277 if (MARK_PLACEHOLDER == find_temporary.value()) 00278 { 00279 // Delete the temporary mark before putting a real mark at its 00280 // location 00281 Delete(frame, total); 00282 } 00283 else // Don't add a mark on top of a mark 00284 return; 00285 } 00286 00287 int lasttype = MARK_UNSET; 00288 long long lastframe = -1; 00289 long long remove = -1; 00290 QMutableMapIterator<uint64_t, MarkTypes> it(m_deleteMap); 00291 00292 if (type == MARK_CUT_END) 00293 { 00294 // remove curent end marker if it exists 00295 while (it.hasNext()) 00296 { 00297 it.next(); 00298 if (it.key() > frame) 00299 { 00300 if ((lasttype == MARK_CUT_END) && (lastframe > -1)) 00301 remove = lastframe; 00302 break; 00303 } 00304 lasttype = it.value(); 00305 lastframe = it.key(); 00306 } 00307 if ((remove < 0) && (lasttype == MARK_CUT_END) && 00308 (lastframe > -1) && (lastframe < (int64_t)frame)) 00309 remove = lastframe; 00310 } 00311 else if (type == MARK_CUT_START) 00312 { 00313 // remove curent start marker if it exists 00314 it.toBack(); 00315 while (it.hasPrevious()) 00316 { 00317 it.previous(); 00318 if (it.key() <= frame) 00319 { 00320 if (lasttype == MARK_CUT_START && (lastframe > -1)) 00321 remove = lastframe; 00322 break; 00323 } 00324 lasttype = it.value(); 00325 lastframe = it.key(); 00326 } 00327 if ((remove < 0) && (lasttype == MARK_CUT_START) && 00328 (lastframe > -1) && (lastframe > (int64_t)frame)) 00329 remove = lastframe; 00330 } 00331 00332 if (remove > -1) 00333 Delete((uint64_t)remove); 00334 Add(frame, type); 00335 CleanMap(total); 00336 if (!undoMessage.isEmpty()) 00337 Push(undoMessage); 00338 } 00339 00341 void DeleteMap::Delete(uint64_t frame, uint64_t total, QString undoMessage) 00342 { 00343 EDIT_CHECK; 00344 if (m_deleteMap.isEmpty()) 00345 return; 00346 00347 uint64_t prev = GetNearestMark(frame, total, false); 00348 uint64_t next = GetNearestMark(frame, total, true); 00349 00350 // If frame is a cut point, GetNearestMark() would return the previous/next 00351 // mark (not this frame), so check to see if we need to use frame, instead 00352 frm_dir_map_t::Iterator it = m_deleteMap.find(frame); 00353 if (it != m_deleteMap.end()) 00354 { 00355 int type = it.value(); 00356 if (MARK_PLACEHOLDER == type) 00357 next = prev = frame; 00358 else if (MARK_CUT_END == type) 00359 next = frame; 00360 else if (MARK_CUT_START == type) 00361 prev = frame; 00362 } 00363 00364 Delete(prev); 00365 if (prev != next) 00366 Delete(next); 00367 CleanMap(total); 00368 if (!undoMessage.isEmpty()) 00369 Push(undoMessage); 00370 } 00371 00373 void DeleteMap::NewCut(uint64_t frame, uint64_t total) 00374 { 00375 EDIT_CHECK; 00376 00377 // find any existing temporary marker to determine cut range 00378 int64_t existing = -1; 00379 frm_dir_map_t::Iterator it; 00380 for (it = m_deleteMap.begin() ; it != m_deleteMap.end(); ++it) 00381 { 00382 if (MARK_PLACEHOLDER == it.value()) 00383 { 00384 existing = it.key(); 00385 break; 00386 } 00387 } 00388 00389 if (existing > -1) 00390 { 00391 uint64_t otherframe = static_cast<uint64_t>(existing); 00392 if (otherframe == frame) 00393 Delete(otherframe); 00394 else 00395 { 00396 uint64_t startframe; 00397 uint64_t endframe; 00398 int64_t cut_start = -1; 00399 int64_t cut_end = -1; 00400 if (IsInDelete(frame)) 00401 { 00402 MarkTypes type = MARK_UNSET; 00403 cut_start = GetNearestMark(frame, total, false); 00404 cut_end = GetNearestMark(frame, total, true); 00405 frm_dir_map_t::Iterator it = m_deleteMap.find(frame); 00406 if (it != m_deleteMap.end()) 00407 type = it.value(); 00408 if (MARK_CUT_START == type) 00409 { 00410 cut_start = frame; 00411 } 00412 else if (MARK_CUT_END == type) 00413 { 00414 cut_end = frame; 00415 } 00416 } 00417 00418 if (otherframe < frame) 00419 { 00420 startframe = otherframe; 00421 endframe = cut_end != -1 ? static_cast<uint64_t>(cut_end) 00422 : frame; 00423 } 00424 else 00425 { 00426 startframe = cut_start != -1 ? static_cast<uint64_t>(cut_start) 00427 : frame; 00428 endframe = otherframe; 00429 } 00430 00431 // Don't place a cut marker on first or last frame; instead cut 00432 // to beginning or end 00433 if (startframe == 1) 00434 startframe = 0; 00435 if (endframe >= total - 1) 00436 endframe = total; 00437 00438 // Don't cut the entire recording 00439 if ((startframe == 0) && (endframe == total)) 00440 { 00441 LOG(VB_GENERAL, LOG_CRIT, LOC + 00442 "Refusing to cut entire recording."); 00443 return; 00444 } 00445 00446 Delete(otherframe); 00447 Add(startframe, MARK_CUT_START); 00448 Add(endframe, MARK_CUT_END); 00449 // Clear out any markers between the start and end frames 00450 otherframe = 0; 00451 frm_dir_map_t::Iterator it = m_deleteMap.find(startframe); 00452 for ( ; it != m_deleteMap.end() && otherframe < endframe; ++it) 00453 { 00454 otherframe = it.key(); 00455 if ((startframe < otherframe) && (endframe > otherframe)) 00456 { 00457 LOG(VB_PLAYBACK, LOG_INFO, LOC + 00458 QString("Deleting bounded marker: %1").arg(otherframe)); 00459 Delete(otherframe); 00460 } 00461 } 00462 } 00463 } 00464 else 00465 Add(frame, MARK_PLACEHOLDER); 00466 00467 CleanMap(total); 00468 Push(QObject::tr("New Cut")); 00469 } 00470 00472 void DeleteMap::MoveRelative(uint64_t frame, uint64_t total, bool right) 00473 { 00474 frm_dir_map_t::Iterator it = m_deleteMap.find(frame); 00475 if (it != m_deleteMap.end()) 00476 { 00477 int type = it.value(); 00478 if (((MARK_CUT_START == type) && !right) || 00479 ((MARK_CUT_END == type) && right)) 00480 { 00481 // If on a mark, don't move a mark from a different cut region; 00482 // instead, "move" this mark onto itself 00483 return; 00484 } 00485 else if (((MARK_CUT_START == type) && right) || 00486 ((MARK_CUT_END == type) && !right)) 00487 { 00488 // If on a mark, don't collapse a cut region to 0; 00489 // instead, delete the region 00490 Delete(frame, total, QObject::tr("Delete")); 00491 return; 00492 } 00493 else if (MARK_PLACEHOLDER == type) 00494 { 00495 // Delete the temporary mark before putting a real mark at its 00496 // location 00497 Delete(frame, total); 00498 } 00499 } 00500 00501 uint64_t from = GetNearestMark(frame, total, right); 00502 Move(from, frame, total); 00503 } 00504 00506 void DeleteMap::Move(uint64_t frame, uint64_t to, uint64_t total) 00507 { 00508 EDIT_CHECK; 00509 MarkTypes type = Delete(frame); 00510 if (MARK_UNSET == type) 00511 { 00512 if (frame == 0) 00513 type = MARK_CUT_START; 00514 else if (frame == total) 00515 type = MARK_CUT_END; 00516 } 00517 Add(to, total, type, QObject::tr("Move Mark")); 00518 } 00519 00521 void DeleteMap::Add(uint64_t frame, MarkTypes type) 00522 { 00523 m_deleteMap[frame] = type; 00524 m_changed = true; 00525 } 00526 00528 MarkTypes DeleteMap::Delete(uint64_t frame) 00529 { 00530 if (m_deleteMap.contains(frame)) 00531 { 00532 m_changed = true; 00533 return m_deleteMap.take(frame); 00534 } 00535 return MARK_UNSET; 00536 } 00537 00542 bool DeleteMap::IsInDelete(uint64_t frame) const 00543 { 00544 if (m_deleteMap.isEmpty()) 00545 return false; 00546 00547 frm_dir_map_t::const_iterator it = m_deleteMap.find(frame); 00548 if (it != m_deleteMap.end()) 00549 return true; 00550 00551 int lasttype = MARK_UNSET; 00552 uint64_t lastframe = -1; 00553 for (it = m_deleteMap.begin() ; it != m_deleteMap.end(); ++it) 00554 { 00555 if (it.key() > frame) 00556 return MARK_CUT_END == it.value(); 00557 lasttype = it.value(); 00558 lastframe = it.key(); 00559 } 00560 00561 if (lasttype == MARK_CUT_START && lastframe <= frame) 00562 return true; 00563 return false; 00564 } 00565 00569 bool DeleteMap::IsTemporaryMark(uint64_t frame) const 00570 { 00571 if (m_deleteMap.isEmpty()) 00572 return false; 00573 00574 frm_dir_map_t::const_iterator it = m_deleteMap.find(frame); 00575 return (it != m_deleteMap.end()) && (MARK_PLACEHOLDER == it.value()); 00576 } 00577 00584 uint64_t DeleteMap::GetNearestMark( 00585 uint64_t frame, uint64_t total, bool right, 00586 bool *hasMark) const 00587 { 00588 uint64_t result; 00589 if (hasMark) 00590 *hasMark = true; 00591 frm_dir_map_t::const_iterator it = m_deleteMap.begin(); 00592 if (right) 00593 { 00594 result = total; 00595 for (; it != m_deleteMap.end(); ++it) 00596 if (it.key() > frame) 00597 return it.key(); 00598 if (hasMark) 00599 *hasMark = false; 00600 } 00601 else 00602 { 00603 result = 0; 00604 for (; it != m_deleteMap.end(); ++it) 00605 { 00606 if (it.key() >= frame) 00607 return result; 00608 result = it.key(); 00609 } 00610 } 00611 return result; 00612 } 00613 00617 bool DeleteMap::HasTemporaryMark(void) const 00618 { 00619 if (!m_deleteMap.isEmpty()) 00620 { 00621 frm_dir_map_t::const_iterator it = m_deleteMap.begin(); 00622 for ( ; it != m_deleteMap.end(); ++it) 00623 if (MARK_PLACEHOLDER == it.value()) 00624 return true; 00625 } 00626 00627 return false; 00628 } 00629 00635 void DeleteMap::CleanMap(uint64_t total) 00636 { 00637 if (IsEmpty()) 00638 return; 00639 00640 Delete(0); 00641 Delete(total); 00642 00643 bool clear = false; 00644 while (!IsEmpty() && !clear) 00645 { 00646 clear = true; 00647 int lasttype = MARK_UNSET; 00648 int64_t lastframe = -1; 00649 int64_t tempframe = -1; 00650 frm_dir_map_t::iterator it = m_deleteMap.begin(); 00651 for ( ; it != m_deleteMap.end(); ++it) 00652 { 00653 int thistype = it.value(); 00654 uint64_t thisframe = it.key(); 00655 if (thisframe >= total) 00656 { 00657 Delete(thisframe); 00658 } 00659 else if (lasttype == thistype) 00660 { 00661 Delete(thistype == MARK_CUT_END ? thisframe : 00662 (uint64_t)lastframe); 00663 clear = false; 00664 break; 00665 } 00666 if (MARK_PLACEHOLDER == thistype) 00667 { 00668 if (tempframe > 0) 00669 Delete(tempframe); 00670 tempframe = thisframe; 00671 } 00672 else 00673 { 00674 lasttype = thistype; 00675 lastframe = thisframe; 00676 } 00677 } 00678 } 00679 } 00680 00682 void DeleteMap::SetMap(const frm_dir_map_t &map) 00683 { 00684 Clear(); 00685 m_deleteMap = map; 00686 m_deleteMap.detach(); 00687 // Can't save an undo point for SetMap() or transcodes fail. 00688 // Leaving as a marker for refactor. 00689 //Push(QObject::tr("Set New Cut List")); 00690 } 00691 00693 void DeleteMap::LoadCommBreakMap(uint64_t total, frm_dir_map_t &map) 00694 { 00695 Clear(); 00696 frm_dir_map_t::Iterator it = map.begin(); 00697 for ( ; it != map.end(); ++it) 00698 Add(it.key(), it.value() == MARK_COMM_START ? 00699 MARK_CUT_START : MARK_CUT_END); 00700 CleanMap(total); 00701 Push(QObject::tr("Load Detected Commercials")); 00702 } 00703 00705 void DeleteMap::LoadMap(uint64_t total, QString undoMessage) 00706 { 00707 if (!m_ctx || !m_ctx->playingInfo || gCoreContext->IsDatabaseIgnored()) 00708 return; 00709 00710 Clear(); 00711 m_ctx->LockPlayingInfo(__FILE__, __LINE__); 00712 m_ctx->playingInfo->QueryCutList(m_deleteMap); 00713 m_ctx->UnlockPlayingInfo(__FILE__, __LINE__); 00714 CleanMap(total); 00715 if (!undoMessage.isEmpty()) 00716 Push(undoMessage); 00717 } 00718 00721 bool DeleteMap::LoadAutoSaveMap(uint64_t total) 00722 { 00723 if (!m_ctx || !m_ctx->playingInfo || gCoreContext->IsDatabaseIgnored()) 00724 return false; 00725 00726 frm_dir_map_t tmpDeleteMap = m_deleteMap; 00727 Clear(); 00728 m_ctx->LockPlayingInfo(__FILE__, __LINE__); 00729 bool result = m_ctx->playingInfo->QueryCutList(m_deleteMap, true); 00730 m_ctx->UnlockPlayingInfo(__FILE__, __LINE__); 00731 CleanMap(total); 00732 if (result) 00733 Push(QObject::tr("Load Auto-saved Cuts")); 00734 else 00735 m_deleteMap = tmpDeleteMap; 00736 00737 return result; 00738 } 00739 00741 void DeleteMap::SaveMap(uint64_t total, bool isAutoSave) 00742 { 00743 if (!m_ctx || !m_ctx->playingInfo || gCoreContext->IsDatabaseIgnored()) 00744 return; 00745 00746 if (!isAutoSave) 00747 { 00748 // Remove temporary placeholder marks 00749 QMutableMapIterator<uint64_t, MarkTypes> it(m_deleteMap); 00750 while (it.hasNext()) 00751 { 00752 it.next(); 00753 if (MARK_PLACEHOLDER == it.value()) 00754 { 00755 it.remove(); 00756 m_changed = true; 00757 } 00758 } 00759 00760 CleanMap(total); 00761 } 00762 m_ctx->LockPlayingInfo(__FILE__, __LINE__); 00763 m_ctx->playingInfo->SaveMarkupFlag(MARK_UPDATED_CUT); 00764 m_ctx->playingInfo->SaveCutList(m_deleteMap, isAutoSave); 00765 m_ctx->UnlockPlayingInfo(__FILE__, __LINE__); 00766 } 00767 00774 void DeleteMap::TrackerReset(uint64_t frame, uint64_t total) 00775 { 00776 m_nextCutStart = 0; 00777 m_nextCutStartIsValid = false; 00778 if (IsEmpty()) 00779 return; 00780 00781 frm_dir_map_t::iterator cutpoint = m_deleteMap.find(frame); 00782 if (cutpoint != m_deleteMap.end()) 00783 { 00784 if (cutpoint.value() == MARK_CUT_START) 00785 { 00786 m_nextCutStartIsValid = true; 00787 m_nextCutStart = cutpoint.key(); 00788 } 00789 else 00790 { 00791 ++cutpoint; 00792 m_nextCutStartIsValid = (cutpoint != m_deleteMap.end()); 00793 m_nextCutStart = m_nextCutStartIsValid ? cutpoint.key() : total; 00794 } 00795 } 00796 else 00797 m_nextCutStart = GetNearestMark(frame, total, !IsInDelete(frame), 00798 &m_nextCutStartIsValid); 00799 LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Tracker next CUT_START: %1") 00800 .arg(m_nextCutStart)); 00801 } 00802 00807 bool DeleteMap::TrackerWantsToJump(uint64_t frame, uint64_t total, uint64_t &to) 00808 { 00809 if (IsEmpty() || !m_nextCutStartIsValid || frame < m_nextCutStart) 00810 return false; 00811 00812 to = GetNearestMark(m_nextCutStart, total, true); 00813 LOG(VB_PLAYBACK, LOG_INFO, LOC + 00814 QString("Tracker wants to jump to: %1").arg(to)); 00815 return true; 00816 } 00817 00822 uint64_t DeleteMap::GetLastFrame(uint64_t total) const 00823 { 00824 uint64_t result = total; 00825 if (IsEmpty()) 00826 return result; 00827 00828 frm_dir_map_t::const_iterator it = m_deleteMap.end(); 00829 --it; 00830 00831 if (it.value() == MARK_CUT_START) 00832 result = it.key(); 00833 return result; 00834 } 00835 00839 bool DeleteMap::IsSaved(void) const 00840 { 00841 if (!m_ctx || !m_ctx->playingInfo || gCoreContext->IsDatabaseIgnored()) 00842 return true; 00843 00844 frm_dir_map_t currentMap(m_deleteMap); 00845 frm_dir_map_t savedMap; 00846 m_ctx->LockPlayingInfo(__FILE__, __LINE__); 00847 m_ctx->playingInfo->QueryCutList(savedMap); 00848 m_ctx->UnlockPlayingInfo(__FILE__, __LINE__); 00849 00850 // Remove temporary placeholder marks from currentMap 00851 QMutableMapIterator<uint64_t, MarkTypes> it(currentMap); 00852 while (it.hasNext()) 00853 { 00854 it.next(); 00855 if (MARK_PLACEHOLDER == it.value()) 00856 it.remove(); 00857 } 00858 00859 return currentMap == savedMap; 00860 } 00861 00862 uint64_t DeleteMap::TranslatePositionAbsToRel(const frm_dir_map_t &deleteMap, 00863 uint64_t absPosition) 00864 { 00865 uint64_t subtraction = 0; 00866 uint64_t startOfCutRegion = 0; 00867 frm_dir_map_t::const_iterator i; 00868 bool withinCut = false; 00869 bool first = true; 00870 for (i = deleteMap.constBegin(); i != deleteMap.constEnd(); ++i) 00871 { 00872 if (first) 00873 withinCut = (i.value() == MARK_CUT_END); 00874 first = false; 00875 if (i.key() > absPosition) 00876 break; 00877 if (i.value() == MARK_CUT_START && !withinCut) 00878 { 00879 withinCut = true; 00880 startOfCutRegion = i.key(); 00881 } 00882 else if (i.value() == MARK_CUT_END && withinCut) 00883 { 00884 withinCut = false; 00885 subtraction += (i.key() - startOfCutRegion); 00886 } 00887 } 00888 if (withinCut) 00889 subtraction += (absPosition - startOfCutRegion); 00890 return absPosition - subtraction; 00891 } 00892 00893 uint64_t DeleteMap::TranslatePositionRelToAbs(const frm_dir_map_t &deleteMap, 00894 uint64_t relPosition) 00895 { 00896 uint64_t addition = 0; 00897 uint64_t startOfCutRegion = 0; 00898 frm_dir_map_t::const_iterator i; 00899 bool withinCut = false; 00900 bool first = true; 00901 for (i = deleteMap.constBegin(); i != deleteMap.constEnd(); ++i) 00902 { 00903 if (first) 00904 withinCut = (i.value() == MARK_CUT_END); 00905 first = false; 00906 if (i.value() == MARK_CUT_START && !withinCut) 00907 { 00908 withinCut = true; 00909 startOfCutRegion = i.key(); 00910 if (relPosition + addition <= startOfCutRegion) 00911 break; 00912 } 00913 else if (i.value() == MARK_CUT_END && withinCut) 00914 { 00915 withinCut = false; 00916 addition += (i.key() - startOfCutRegion); 00917 } 00918 } 00919 return relPosition + addition; 00920 }
1.7.6.1