From 0107c01911b6817d21422b1503942f968b4fa6a7 Mon Sep 17 00:00:00 2001 From: Voyager-xbmc Date: Mon, 19 Mar 2012 23:22:55 +0100 Subject: [PATCH] allow resume on selected part of stack & stacking issues fix stacking dialog in GUIWindowVideoBase - code generalization in CApp::PlayStack clean up GetResumeItemString to use offset value from GetResumeItemOffset (for iso stacks) --- xbmc/Application.cpp | 159 ++++++++------ xbmc/settings/GUISettings.cpp | 1 - xbmc/settings/GUISettings.h | 3 +- xbmc/video/windows/GUIWindowVideoBase.cpp | 249 ++++++++++------------ xbmc/video/windows/GUIWindowVideoBase.h | 3 +- 5 files changed, 213 insertions(+), 202 deletions(-) diff --git a/xbmc/Application.cpp b/xbmc/Application.cpp index f1d63037b783a..e18c2091f8333 100644 --- a/xbmc/Application.cpp +++ b/xbmc/Application.cpp @@ -3556,88 +3556,123 @@ bool CApplication::PlayStack(const CFileItem& item, bool bRestart) if (!item.IsStack()) return false; - // see if we have the info in the database - // TODO: If user changes the time speed (FPS via framerate conversion stuff) - // then these times will be wrong. - // Also, this is really just a hack for the slow load up times we have - // A much better solution is a fast reader of FPS and fileLength - // that we can use on a file to get it's time. - vector times; - bool haveTimes(false); CVideoDatabase dbs; - if (dbs.Open()) + + // case 1: stacked ISOs + if (CFileItem(CStackDirectory::GetFirstStackedFile(item.GetPath()),false).IsDVDImage()) { - dbs.GetVideoSettings(item.GetPath(), g_settings.m_currentVideoSettings); - haveTimes = dbs.GetStackTimes(item.GetPath(), times); - dbs.Close(); - } + CStackDirectory dir; + CFileItemList movieList; + dir.GetDirectory(item.GetPath(), movieList); + int selectedFile = 1; // if playing from beginning, play file 1. + long startoffset = item.m_lStartOffset; - // calculate the total time of the stack - CStackDirectory dir; - dir.GetDirectory(item.GetPath(), *m_currentStack); - long totalTime = 0; - for (int i = 0; i < m_currentStack->Size(); i++) - { - if (haveTimes) - (*m_currentStack)[i]->m_lEndOffset = times[i]; - else + // We instructed the stack to resume. + if (startoffset == STARTOFFSET_RESUME) // selected file is not specified, pick the 'last' resume point + startoffset = CGUIWindowVideoBase::GetResumeItemOffset(&item); + + if (startoffset & 0xF0000000) /* selected part is specified as a flag */ { - int duration; - if (!CDVDFileInfo::GetFileDuration((*m_currentStack)[i]->GetPath(), duration)) - { - m_currentStack->Clear(); - return false; - } - totalTime += duration / 1000; - (*m_currentStack)[i]->m_lEndOffset = totalTime; - times.push_back(totalTime); - } - } + selectedFile = (startoffset>>28); + startoffset = startoffset & ~0xF0000000; - double seconds = item.m_lStartOffset / 75.0; + // set startoffset in movieitem. The remaining startoffset is either 0 (just play part from beginning) or positive (then we use STARTOFFSET_RESUME). + if (selectedFile > 0 && selectedFile <= (int)movieList.Size()) + movieList[selectedFile - 1]->m_lStartOffset = startoffset > 0 ? STARTOFFSET_RESUME : 0; + } - if (!haveTimes || item.m_lStartOffset == STARTOFFSET_RESUME ) - { // have our times now, so update the dB + // finally play selected item + if (selectedFile > 0 && selectedFile <= (int)movieList.Size()) + return PlayFile(*(movieList[selectedFile - 1])); + } + // case 2: all other stacks + else + { + // see if we have the info in the database + // TODO: If user changes the time speed (FPS via framerate conversion stuff) + // then these times will be wrong. + // Also, this is really just a hack for the slow load up times we have + // A much better solution is a fast reader of FPS and fileLength + // that we can use on a file to get it's time. + vector times; + bool haveTimes(false); + CVideoDatabase dbs; if (dbs.Open()) { - if( !haveTimes ) - dbs.SetStackTimes(item.GetPath(), times); + dbs.GetVideoSettings(item.GetPath(), g_settings.m_currentVideoSettings); + haveTimes = dbs.GetStackTimes(item.GetPath(), times); + dbs.Close(); + } - if( item.m_lStartOffset == STARTOFFSET_RESUME ) + + // calculate the total time of the stack + CStackDirectory dir; + dir.GetDirectory(item.GetPath(), *m_currentStack); + long totalTime = 0; + for (int i = 0; i < m_currentStack->Size(); i++) + { + if (haveTimes) + (*m_currentStack)[i]->m_lEndOffset = times[i]; + else { - // can only resume seek here, not dvdstate - CBookmark bookmark; - if( dbs.GetResumeBookMark(item.GetPath(), bookmark) ) - seconds = bookmark.timeInSeconds; - else - seconds = 0.0f; + int duration; + if (!CDVDFileInfo::GetFileDuration((*m_currentStack)[i]->GetPath(), duration)) + { + m_currentStack->Clear(); + return false; + } + totalTime += duration / 1000; + (*m_currentStack)[i]->m_lEndOffset = totalTime; + times.push_back(totalTime); } - dbs.Close(); } - } - *m_itemCurrentFile = item; - m_currentStackPosition = 0; - m_eCurrentPlayer = EPC_NONE; // must be reset on initial play otherwise last player will be used + double seconds = item.m_lStartOffset / 75.0; - if (seconds > 0) - { - // work out where to seek to - for (int i = 0; i < m_currentStack->Size(); i++) + if (!haveTimes || item.m_lStartOffset == STARTOFFSET_RESUME ) + { // have our times now, so update the dB + if (dbs.Open()) + { + if( !haveTimes ) + dbs.SetStackTimes(item.GetPath(), times); + + if( item.m_lStartOffset == STARTOFFSET_RESUME ) + { + // can only resume seek here, not dvdstate + CBookmark bookmark; + if( dbs.GetResumeBookMark(item.GetPath(), bookmark) ) + seconds = bookmark.timeInSeconds; + else + seconds = 0.0f; + } + dbs.Close(); + } + } + + *m_itemCurrentFile = item; + m_currentStackPosition = 0; + m_eCurrentPlayer = EPC_NONE; // must be reset on initial play otherwise last player will be used + + if (seconds > 0) { - if (seconds < (*m_currentStack)[i]->m_lEndOffset) + // work out where to seek to + for (int i = 0; i < m_currentStack->Size(); i++) { - CFileItem item(*(*m_currentStack)[i]); - long start = (i > 0) ? (*m_currentStack)[i-1]->m_lEndOffset : 0; - item.m_lStartOffset = (long)(seconds - start) * 75; - m_currentStackPosition = i; - return PlayFile(item, true); + if (seconds < (*m_currentStack)[i]->m_lEndOffset) + { + CFileItem item(*(*m_currentStack)[i]); + long start = (i > 0) ? (*m_currentStack)[i-1]->m_lEndOffset : 0; + item.m_lStartOffset = (long)(seconds - start) * 75; + m_currentStackPosition = i; + return PlayFile(item, true); + } } } - } - return PlayFile(*(*m_currentStack)[0], true); + return PlayFile(*(*m_currentStack)[0], true); + } + return false; } bool CApplication::PlayFile(const CFileItem& item, bool bRestart) diff --git a/xbmc/settings/GUISettings.cpp b/xbmc/settings/GUISettings.cpp index b0b95bd0049f7..23ec6c37dd1e2 100644 --- a/xbmc/settings/GUISettings.cpp +++ b/xbmc/settings/GUISettings.cpp @@ -707,7 +707,6 @@ void CGUISettings::Initialize() myVideosSelectActions.insert(make_pair(22081, SELECT_ACTION_INFO)); AddInt(vid, "myvideos.selectaction", 22079, SELECT_ACTION_PLAY_OR_RESUME, myVideosSelectActions, SPIN_CONTROL_TEXT); - AddBool(NULL, "myvideos.treatstackasfile", 20051, true); AddBool(vid, "myvideos.extractflags",20433, true); AddBool(vid, "myvideos.replacelabels", 20419, true); AddBool(NULL, "myvideos.extractthumb",20433, true); diff --git a/xbmc/settings/GUISettings.h b/xbmc/settings/GUISettings.h index fb2308fabe058..4add2280f099b 100644 --- a/xbmc/settings/GUISettings.h +++ b/xbmc/settings/GUISettings.h @@ -186,7 +186,8 @@ enum VideoSelectAction SELECT_ACTION_RESUME, SELECT_ACTION_INFO, SELECT_ACTION_MORE, - SELECT_ACTION_PLAY + SELECT_ACTION_PLAY, + SELECT_ACTION_PLAYPART }; enum SubtitleAlign diff --git a/xbmc/video/windows/GUIWindowVideoBase.cpp b/xbmc/video/windows/GUIWindowVideoBase.cpp index c819f82f0a7cb..13f4cddb85589 100644 --- a/xbmc/video/windows/GUIWindowVideoBase.cpp +++ b/xbmc/video/windows/GUIWindowVideoBase.cpp @@ -822,26 +822,7 @@ int CGUIWindowVideoBase::GetResumeItemOffset(const CFileItem *item) db.Open(); long startoffset = 0; - if (item->IsStack() && (!g_guiSettings.GetBool("myvideos.treatstackasfile") || - CFileItem(CStackDirectory::GetFirstStackedFile(item->GetPath()),false).IsDVDImage()) ) - { - - CStdStringArray movies; - GetStackedFiles(item->GetPath(), movies); - - /* check if any of the stacked files have a resume bookmark */ - for (unsigned i = 0; iIsNFO() && !item->IsPlayList()) + if (!item->IsNFO() && !item->IsPlayList()) { if (item->HasVideoInfoTag() && item->GetVideoInfoTag()->m_resumePoint.timeInSeconds > 0.0) startoffset = (long)(item->GetVideoInfoTag()->m_resumePoint.timeInSeconds*75); @@ -854,6 +835,25 @@ int CGUIWindowVideoBase::GetResumeItemOffset(const CFileItem *item) if (db.GetResumeBookMark(strPath, bookmark)) startoffset = (long)(bookmark.timeInSeconds*75); + + if (URIUtils::IsStack(strPath) && CFileItem(CStackDirectory::GetFirstStackedFile(strPath),false).IsDVDImage()) + { + CStackDirectory dir; + CFileItemList movies; + dir.GetDirectory(strPath, movies); + + /* check if any of the stacked files have a resume bookmark */ + for (int i = 0; i < movies.Size(); i++) + { + CBookmark bookmark; + if (db.GetResumeBookMark(movies[i]->GetPath(), bookmark)) + { + startoffset = (long)(bookmark.timeInSeconds); + startoffset += 0x10000000 * (i+1); /* store file number in here */ + // don't break, we take the last one! + } + } + } } } db.Close(); @@ -895,6 +895,14 @@ bool CGUIWindowVideoBase::OnFileAction(int iItem, int action) CContextButtons choices; bool resume = false; + if (item->IsVideoDb()) + { + CStdString itemPath(item->GetPath()); + itemPath = item->GetVideoInfoTag()->m_strFileNameAndPath; + if (URIUtils::IsStack(itemPath) && CFileItem(CStackDirectory::GetFirstStackedFile(itemPath),false).IsDVDImage()) + choices.Add(SELECT_ACTION_PLAYPART, 20324); // Play Part + } + if (!item->IsLiveTV()) { CStdString resumeString = GetResumeString(*item); @@ -929,6 +937,10 @@ bool CGUIWindowVideoBase::OnFileAction(int iItem, int action) case SELECT_ACTION_RESUME: item->m_lStartOffset = STARTOFFSET_RESUME; break; + case SELECT_ACTION_PLAYPART: + if (!OnPlayStackPart(iItem)) + return false; + break; case SELECT_ACTION_PLAY: default: break; @@ -989,6 +1001,7 @@ void CGUIWindowVideoBase::OnRestartItem(int iItem) CStdString CGUIWindowVideoBase::GetResumeString(CFileItem item) { CStdString resumeString; + CStdString partString; CVideoDatabase db; if (db.Open()) { @@ -996,7 +1009,20 @@ CStdString CGUIWindowVideoBase::GetResumeString(CFileItem item) CStdString itemPath(item.GetPath()); if (item.IsVideoDb() || item.IsDVD()) itemPath = item.GetVideoInfoTag()->m_strFileNameAndPath; - if (db.GetResumeBookMark(itemPath, bookmark) ) + + if (URIUtils::IsStack(itemPath) && CFileItem(CStackDirectory::GetFirstStackedFile(itemPath),false).IsDVDImage()) + { + int startoffset = GetResumeItemOffset(&item); + if (startoffset > 0) + { + int selectedPart = (startoffset>>28); + startoffset = startoffset & ~0xF0000000; + partString.Format(g_localizeStrings.Get(23051).c_str(), selectedPart); + resumeString.Format(g_localizeStrings.Get(12022).c_str(), StringUtils::SecondsToTimeString(lrint(startoffset)).c_str()); + resumeString.append(" (").append(partString).append(")"); + } + } + else if (db.GetResumeBookMark(itemPath, bookmark) ) resumeString.Format(g_localizeStrings.Get(12022).c_str(), StringUtils::SecondsToTimeString(lrint(bookmark.timeInSeconds)).c_str()); db.Close(); } @@ -1085,7 +1111,7 @@ void CGUIWindowVideoBase::GetContextButtons(int itemNumber, CContextButtons &but if (URIUtils::IsStack(path)) { vector times; - if (m_database.GetStackTimes(path,times)) + if (m_database.GetStackTimes(path,times) || CFileItem(CStackDirectory::GetFirstStackedFile(path),false).IsDVDImage()) buttons.Add(CONTEXT_BUTTON_PLAY_PART, 20324); } @@ -1144,6 +1170,64 @@ void CGUIWindowVideoBase::GetNonContextButtons(int itemNumber, CContextButtons & buttons.Add(CONTEXT_BUTTON_NOW_PLAYING, 13350); } +bool CGUIWindowVideoBase::OnPlayStackPart(int iItem) +{ + if (iItem < 0 || iItem >= m_vecItems->Size()) + return false; + + CFileItemPtr stack = m_vecItems->Get(iItem); + CStdString path(stack->GetPath()); + if (stack->IsVideoDb()) + path = stack->GetVideoInfoTag()->m_strFileNameAndPath; + + if (!URIUtils::IsStack(path)) + return false; + + CFileItemList parts; + CDirectory::GetDirectory(path,parts); + CGUIDialogFileStacking* dlg = (CGUIDialogFileStacking*)g_windowManager.GetWindow(WINDOW_DIALOG_FILESTACKING); + if (!dlg) return true; + dlg->SetNumberOfFiles(parts.Size()); + dlg->DoModal(); + int selectedFile = dlg->GetSelectedFile(); + if (selectedFile > 0) + { + // ISO stack + if (CFileItem(CStackDirectory::GetFirstStackedFile(path),false).IsDVDImage()) + { + CStdString resumeString = CGUIWindowVideoBase::GetResumeString(*(parts[selectedFile - 1].get())); + stack->m_lStartOffset = 0x10000000 * (selectedFile); /* store file number in here */ + if (!resumeString.IsEmpty()) + { + CContextButtons choices; + choices.Add(SELECT_ACTION_RESUME, resumeString); + choices.Add(SELECT_ACTION_PLAY, 12021); // Start from beginning + int value = CGUIDialogContextMenu::ShowAndGetChoice(choices); + if (value == SELECT_ACTION_RESUME) + stack->m_lStartOffset += (long)CGUIWindowVideoBase::GetResumeItemOffset(parts[selectedFile - 1].get()); + else if (value != SELECT_ACTION_PLAY) + return false; // if not selected PLAY, then we changed our mind so return + } + } + // regular stack + else + { + if (selectedFile > 1) + { + vector times; + if (m_database.GetStackTimes(path,times)) + stack->m_lStartOffset = times[selectedFile-2]*75; // wtf? + } + else + stack->m_lStartOffset = 0; + } + + + } + + return true; +} + bool CGUIWindowVideoBase::OnContextButton(int itemNumber, CONTEXT_BUTTON button) { CFileItemPtr item; @@ -1158,32 +1242,14 @@ bool CGUIWindowVideoBase::OnContextButton(int itemNumber, CONTEXT_BUTTON button) } case CONTEXT_BUTTON_PLAY_PART: { - CFileItemList items; - CStdString path(item->GetPath()); - if (item->IsVideoDb()) - path = item->GetVideoInfoTag()->m_strFileNameAndPath; - - CDirectory::GetDirectory(path,items); - CGUIDialogFileStacking* dlg = (CGUIDialogFileStacking*)g_windowManager.GetWindow(WINDOW_DIALOG_FILESTACKING); - if (!dlg) return true; - dlg->SetNumberOfFiles(items.Size()); - dlg->DoModal(); - int btn2 = dlg->GetSelectedFile(); - if (btn2 > 0) + if (OnPlayStackPart(itemNumber)) { - if (btn2 > 1) - { - vector times; - if (m_database.GetStackTimes(path,times)) - item->m_lStartOffset = times[btn2-2]*75; // wtf? - } - else - item->m_lStartOffset = 0; - // call CGUIMediaWindow::OnClick() as otherwise autoresume will kick in CGUIMediaWindow::OnClick(itemNumber); + return true; } - return true; + else + return false; } case CONTEXT_BUTTON_QUEUE_ITEM: OnQueueItem(itemNumber); @@ -1302,25 +1368,6 @@ bool CGUIWindowVideoBase::OnContextButton(int itemNumber, CONTEXT_BUTTON button) return CGUIMediaWindow::OnContextButton(itemNumber, button); } -void CGUIWindowVideoBase::GetStackedFiles(const CStdString &strFilePath1, vector &movies) -{ - CStdString strFilePath = strFilePath1; // we're gonna be altering it - - movies.clear(); - - CURL url(strFilePath); - if (url.GetProtocol() == "stack") - { - CStackDirectory dir; - CFileItemList items; - dir.GetDirectory(strFilePath, items); - for (int i = 0; i < items.Size(); ++i) - movies.push_back(items[i]->GetPath()); - } - if (movies.empty()) - movies.push_back(strFilePath); -} - bool CGUIWindowVideoBase::OnPlayMedia(int iItem) { if ( iItem < 0 || iItem >= (int)m_vecItems->Size() ) @@ -1369,85 +1416,13 @@ bool CGUIWindowVideoBase::OnPlayAndQueueMedia(const CFileItemPtr &item) void CGUIWindowVideoBase::PlayMovie(const CFileItem *item) { - CFileItemList movieList; - int selectedFile = 1; - long startoffset = item->m_lStartOffset; - - if (item->IsStack() && (!g_guiSettings.GetBool("myvideos.treatstackasfile") || - CFileItem(CStackDirectory::GetFirstStackedFile(item->GetPath()),false).IsDVDImage()) ) - { - CStdStringArray movies; - GetStackedFiles(item->GetPath(), movies); - - if (item->m_lStartOffset == STARTOFFSET_RESUME) - { - startoffset = GetResumeItemOffset(item); - - if (startoffset & 0xF0000000) /* file is specified as a flag */ - { - selectedFile = (startoffset>>28); - startoffset = startoffset & ~0xF0000000; - } - else - { - /* attempt to start on a specific time in a stack */ - /* if we are lucky, we might have stored timings for */ - /* this stack at some point */ - - m_database.Open(); - - /* figure out what file this time offset is */ - vector times; - m_database.GetStackTimes(item->GetPath(), times); - long totaltime = 0; - for (unsigned i = 0; i < times.size(); i++) - { - totaltime += times[i]*75; - if (startoffset < totaltime ) - { - selectedFile = i+1; - startoffset -= totaltime - times[i]*75; /* rebase agains selected file */ - break; - } - } - m_database.Close(); - } - } - else - { // show file stacking dialog - CGUIDialogFileStacking* dlg = (CGUIDialogFileStacking*)g_windowManager.GetWindow(WINDOW_DIALOG_FILESTACKING); - if (dlg) - { - dlg->SetNumberOfFiles(movies.size()); - dlg->DoModal(); - selectedFile = dlg->GetSelectedFile(); - if (selectedFile < 1) - return; - } - } - // add to our movie list - for (unsigned int i = 0; i < movies.size(); i++) - { - CFileItemPtr movieItem(new CFileItem(movies[i], false)); - movieList.Add(movieItem); - } - } - else - { - CFileItemPtr movieItem(new CFileItem(*item)); - movieList.Add(movieItem); - } + CFileItemPtr movieItem(new CFileItem(*item)); g_playlistPlayer.Reset(); g_playlistPlayer.SetCurrentPlaylist(PLAYLIST_VIDEO); CPlayList& playlist = g_playlistPlayer.GetPlaylist(PLAYLIST_VIDEO); playlist.Clear(); - for (int i = selectedFile - 1; i < (int)movieList.Size(); ++i) - { - if (i == selectedFile - 1) - movieList[i]->m_lStartOffset = startoffset; - playlist.Add(movieList[i]); - } + playlist.Add(movieItem); if(m_thumbLoader.IsLoading()) m_thumbLoader.StopAsync(); diff --git a/xbmc/video/windows/GUIWindowVideoBase.h b/xbmc/video/windows/GUIWindowVideoBase.h index 01cda2cbb9a2c..21aa210e81514 100644 --- a/xbmc/video/windows/GUIWindowVideoBase.h +++ b/xbmc/video/windows/GUIWindowVideoBase.h @@ -114,7 +114,6 @@ class CGUIWindowVideoBase : public CGUIMediaWindow, public IBackgroundLoaderObse bool ShowIMDB(CFileItem *item, const ADDON::ScraperPtr& content); void AddItemToPlayList(const CFileItemPtr &pItem, CFileItemList &queuedItems); - static void GetStackedFiles(const CStdString &strFileName, std::vector &movies); void OnSearch(); void OnSearchItemFound(const CFileItem* pSelItem); @@ -124,6 +123,8 @@ class CGUIWindowVideoBase : public CGUIMediaWindow, public IBackgroundLoaderObse bool StackingAvailable(const CFileItemList &items) const; + bool OnPlayStackPart(int item); + CGUIDialogProgress* m_dlgProgress; CVideoDatabase m_database;