[FileItem][Cleanup] Add getter/setter for start/end offset
[xbmc.git] / xbmc / ApplicationStackHelper.cpp
blobf74101cd43f8826885fd51050c7cd15995b60ab6
1 /*
2 * Copyright (C) 2017-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
7 */
9 #include "ApplicationStackHelper.h"
11 #include "ApplicationPlayer.h"
12 #include "Util.h"
13 #include "cores/VideoPlayer/DVDFileInfo.h"
14 #include "filesystem/StackDirectory.h"
15 #include "utils/URIUtils.h"
16 #include "utils/log.h"
17 #include "video/VideoDatabase.h"
19 #include <utility>
21 using namespace XFILE;
23 CApplicationStackHelper::CApplicationStackHelper(void)
24 : m_currentStack(new CFileItemList)
28 void CApplicationStackHelper::Clear()
30 m_currentStackPosition = 0;
31 m_currentStack->Clear();
34 void CApplicationStackHelper::OnPlayBackStarted(const CFileItem& item)
36 std::unique_lock<CCriticalSection> lock(m_critSection);
38 // time to clean up stack map
39 if (!HasRegisteredStack(item))
40 m_stackmap.clear();
41 else
43 auto stack = GetRegisteredStack(item);
44 Stackmap::iterator itr = m_stackmap.begin();
45 while (itr != m_stackmap.end())
47 if (itr->second->m_pStack != stack)
49 itr = m_stackmap.erase(itr);
51 else
53 ++itr;
59 bool CApplicationStackHelper::InitializeStack(const CFileItem & item)
61 if (!item.IsStack())
62 return false;
64 CFileItemPtr stack(new CFileItem(item));
66 Clear();
67 // read and determine kind of stack
68 CStackDirectory dir;
69 if (!dir.GetDirectory(item.GetURL(), *m_currentStack) || m_currentStack->IsEmpty())
70 return false;
71 for (int i = 0; i < m_currentStack->Size(); i++)
73 // keep cross-references between stack parts and the stack
74 SetRegisteredStack(GetStackPartFileItem(i), stack);
75 SetRegisteredStackPartNumber(GetStackPartFileItem(i), i);
77 m_currentStackIsDiscImageStack = CFileItem(CStackDirectory::GetFirstStackedFile(item.GetPath()), false).IsDiscImage();
79 return true;
82 int CApplicationStackHelper::InitializeStackStartPartAndOffset(const CFileItem& item)
84 CVideoDatabase dbs;
85 int64_t startoffset = 0;
87 // case 1: stacked ISOs
88 if (m_currentStackIsDiscImageStack)
90 // first assume values passed to the stack
91 int selectedFile = item.m_lStartPartNumber;
92 startoffset = item.GetStartOffset();
94 // check if we instructed the stack to resume from default
95 if (startoffset == STARTOFFSET_RESUME) // selected file is not specified, pick the 'last' resume point
97 if (dbs.Open())
99 CBookmark bookmark;
100 std::string path = item.GetPath();
101 if (item.HasProperty("original_listitem_url") && URIUtils::IsPlugin(item.GetProperty("original_listitem_url").asString()))
102 path = item.GetProperty("original_listitem_url").asString();
103 if (dbs.GetResumeBookMark(path, bookmark))
105 startoffset = CUtil::ConvertSecsToMilliSecs(bookmark.timeInSeconds);
106 selectedFile = bookmark.partNumber;
108 dbs.Close();
110 else
111 CLog::LogF(LOGERROR, "Cannot open VideoDatabase");
114 // make sure that the selected part is within the boundaries
115 if (selectedFile <= 0)
117 CLog::LogF(LOGWARNING, "Selected part {} out of range, playing part 1", selectedFile);
118 selectedFile = 1;
120 else if (selectedFile > m_currentStack->Size())
122 CLog::LogF(LOGWARNING, "Selected part {} out of range, playing part {}", selectedFile,
123 m_currentStack->Size());
124 selectedFile = m_currentStack->Size();
127 // set startoffset in selected item, track stack item for updating purposes, and finally play disc part
128 m_currentStackPosition = selectedFile - 1;
129 startoffset = startoffset > 0 ? STARTOFFSET_RESUME : 0;
131 // case 2: all other stacks
132 else
134 // see if we have the info in the database
135 //! @todo If user changes the time speed (FPS via framerate conversion stuff)
136 //! then these times will be wrong.
137 //! Also, this is really just a hack for the slow load up times we have
138 //! A much better solution is a fast reader of FPS and fileLength
139 //! that we can use on a file to get it's time.
140 std::vector<uint64_t> times;
141 bool haveTimes(false);
143 if (dbs.Open())
145 haveTimes = dbs.GetStackTimes(item.GetPath(), times);
146 dbs.Close();
149 // calculate the total time of the stack
150 uint64_t totalTimeMs = 0;
151 for (int i = 0; i < m_currentStack->Size(); i++)
153 if (haveTimes)
155 // set end time in every part
156 GetStackPartFileItem(i).SetEndOffset(times[i]);
158 else
160 int duration;
161 if (!CDVDFileInfo::GetFileDuration(GetStackPartFileItem(i).GetPath(), duration))
163 m_currentStack->Clear();
164 return false;
166 totalTimeMs += duration;
167 // set end time in every part
168 GetStackPartFileItem(i).SetEndOffset(totalTimeMs);
169 times.push_back(totalTimeMs);
171 // set start time in every part
172 SetRegisteredStackPartStartTimeMs(GetStackPartFileItem(i), GetStackPartStartTimeMs(i));
174 // set total time in every part
175 totalTimeMs = GetStackTotalTimeMs();
176 for (int i = 0; i < m_currentStack->Size(); i++)
177 SetRegisteredStackTotalTimeMs(GetStackPartFileItem(i), totalTimeMs);
179 uint64_t msecs = item.GetStartOffset();
181 if (!haveTimes || item.GetStartOffset() == STARTOFFSET_RESUME)
183 if (dbs.Open())
185 // have our times now, so update the dB
186 if (!haveTimes && !times.empty())
187 dbs.SetStackTimes(item.GetPath(), times);
189 if (item.GetStartOffset() == STARTOFFSET_RESUME)
191 // can only resume seek here, not dvdstate
192 CBookmark bookmark;
193 std::string path = item.GetPath();
194 if (item.HasProperty("original_listitem_url") && URIUtils::IsPlugin(item.GetProperty("original_listitem_url").asString()))
195 path = item.GetProperty("original_listitem_url").asString();
196 if (dbs.GetResumeBookMark(path, bookmark))
197 msecs = static_cast<uint64_t>(bookmark.timeInSeconds * 1000);
198 else
199 msecs = 0;
201 dbs.Close();
205 m_currentStackPosition = GetStackPartNumberAtTimeMs(msecs);
206 startoffset = msecs - GetStackPartStartTimeMs(m_currentStackPosition);
208 return startoffset;
211 int CApplicationStackHelper::GetStackPartNumberAtTimeMs(uint64_t msecs)
213 if (msecs > 0)
215 // work out where to seek to
216 for (int partNumber = 0; partNumber < m_currentStack->Size(); partNumber++)
218 if (msecs < GetStackPartEndTimeMs(partNumber))
219 return partNumber;
222 return 0;
225 void CApplicationStackHelper::ClearAllRegisteredStackInformation()
227 m_stackmap.clear();
230 std::shared_ptr<const CFileItem> CApplicationStackHelper::GetRegisteredStack(
231 const CFileItem& item) const
233 return GetStackPartInformation(item.GetPath())->m_pStack;
236 bool CApplicationStackHelper::HasRegisteredStack(const CFileItem& item) const
238 const auto it = m_stackmap.find(item.GetPath());
239 return it != m_stackmap.end() && it->second != nullptr;
242 void CApplicationStackHelper::SetRegisteredStack(const CFileItem& item, CFileItemPtr stackItem)
244 GetStackPartInformation(item.GetPath())->m_pStack = std::move(stackItem);
247 int CApplicationStackHelper::GetRegisteredStackPartNumber(const CFileItem& item)
249 return GetStackPartInformation(item.GetPath())->m_lStackPartNumber;
252 void CApplicationStackHelper::SetRegisteredStackPartNumber(const CFileItem& item, int partNumber)
254 GetStackPartInformation(item.GetPath())->m_lStackPartNumber = partNumber;
257 uint64_t CApplicationStackHelper::GetRegisteredStackPartStartTimeMs(const CFileItem& item) const
259 return GetStackPartInformation(item.GetPath())->m_lStackPartStartTimeMs;
262 void CApplicationStackHelper::SetRegisteredStackPartStartTimeMs(const CFileItem& item, uint64_t startTime)
264 GetStackPartInformation(item.GetPath())->m_lStackPartStartTimeMs = startTime;
267 uint64_t CApplicationStackHelper::GetRegisteredStackTotalTimeMs(const CFileItem& item) const
269 return GetStackPartInformation(item.GetPath())->m_lStackTotalTimeMs;
272 void CApplicationStackHelper::SetRegisteredStackTotalTimeMs(const CFileItem& item, uint64_t totalTime)
274 GetStackPartInformation(item.GetPath())->m_lStackTotalTimeMs = totalTime;
277 CApplicationStackHelper::StackPartInformationPtr CApplicationStackHelper::GetStackPartInformation(
278 const std::string& key)
280 if (m_stackmap.count(key) == 0)
282 StackPartInformationPtr value(new StackPartInformation());
283 m_stackmap[key] = value;
285 return m_stackmap[key];
288 CApplicationStackHelper::StackPartInformationPtr CApplicationStackHelper::GetStackPartInformation(
289 const std::string& key) const
291 const auto it = m_stackmap.find(key);
292 if (it == m_stackmap.end())
293 return std::make_shared<StackPartInformation>();
294 return it->second;