[PVR][Estuary] Timer settings dialog: Show client name in timer type selection dialog...
[xbmc.git] / xbmc / application / ApplicationStackHelper.cpp
bloba1e8a0e8c8815693e2df5dbcd8a2a5dfe81a337a
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 "FileItem.h"
12 #include "URL.h"
13 #include "Util.h"
14 #include "cores/VideoPlayer/DVDFileInfo.h"
15 #include "filesystem/StackDirectory.h"
16 #include "utils/URIUtils.h"
17 #include "utils/log.h"
18 #include "video/VideoDatabase.h"
20 #include <utility>
22 using namespace XFILE;
24 CApplicationStackHelper::CApplicationStackHelper(void)
25 : m_currentStack(new CFileItemList)
29 void CApplicationStackHelper::Clear()
31 m_currentStackPosition = 0;
32 m_currentStack->Clear();
35 void CApplicationStackHelper::OnPlayBackStarted(const CFileItem& item)
37 std::unique_lock<CCriticalSection> lock(m_critSection);
39 // time to clean up stack map
40 if (!HasRegisteredStack(item))
41 m_stackmap.clear();
42 else
44 auto stack = GetRegisteredStack(item);
45 Stackmap::iterator itr = m_stackmap.begin();
46 while (itr != m_stackmap.end())
48 if (itr->second->m_pStack != stack)
50 itr = m_stackmap.erase(itr);
52 else
54 ++itr;
60 bool CApplicationStackHelper::InitializeStack(const CFileItem & item)
62 if (!item.IsStack())
63 return false;
65 auto stack = std::make_shared<CFileItem>(item);
67 Clear();
68 // read and determine kind of stack
69 CStackDirectory dir;
70 if (!dir.GetDirectory(item.GetURL(), *m_currentStack) || m_currentStack->IsEmpty())
71 return false;
72 for (int i = 0; i < m_currentStack->Size(); i++)
74 // keep cross-references between stack parts and the stack
75 SetRegisteredStack(GetStackPartFileItem(i), stack);
76 SetRegisteredStackPartNumber(GetStackPartFileItem(i), i);
78 m_currentStackIsDiscImageStack = CFileItem(CStackDirectory::GetFirstStackedFile(item.GetPath()), false).IsDiscImage();
80 return true;
83 int CApplicationStackHelper::InitializeStackStartPartAndOffset(const CFileItem& item)
85 CVideoDatabase dbs;
86 int64_t startoffset = 0;
88 // case 1: stacked ISOs
89 if (m_currentStackIsDiscImageStack)
91 // first assume values passed to the stack
92 int selectedFile = item.m_lStartPartNumber;
93 startoffset = item.GetStartOffset();
95 // check if we instructed the stack to resume from default
96 if (startoffset == STARTOFFSET_RESUME) // selected file is not specified, pick the 'last' resume point
98 if (dbs.Open())
100 CBookmark bookmark;
101 std::string path = item.GetPath();
102 if (item.HasProperty("original_listitem_url") && URIUtils::IsPlugin(item.GetProperty("original_listitem_url").asString()))
103 path = item.GetProperty("original_listitem_url").asString();
104 if (dbs.GetResumeBookMark(path, bookmark))
106 startoffset = CUtil::ConvertSecsToMilliSecs(bookmark.timeInSeconds);
107 selectedFile = bookmark.partNumber;
109 dbs.Close();
111 else
112 CLog::LogF(LOGERROR, "Cannot open VideoDatabase");
115 // make sure that the selected part is within the boundaries
116 if (selectedFile <= 0)
118 CLog::LogF(LOGWARNING, "Selected part {} out of range, playing part 1", selectedFile);
119 selectedFile = 1;
121 else if (selectedFile > m_currentStack->Size())
123 CLog::LogF(LOGWARNING, "Selected part {} out of range, playing part {}", selectedFile,
124 m_currentStack->Size());
125 selectedFile = m_currentStack->Size();
128 // set startoffset in selected item, track stack item for updating purposes, and finally play disc part
129 m_currentStackPosition = selectedFile - 1;
130 startoffset = startoffset > 0 ? STARTOFFSET_RESUME : 0;
132 // case 2: all other stacks
133 else
135 // see if we have the info in the database
136 //! @todo If user changes the time speed (FPS via framerate conversion stuff)
137 //! then these times will be wrong.
138 //! Also, this is really just a hack for the slow load up times we have
139 //! A much better solution is a fast reader of FPS and fileLength
140 //! that we can use on a file to get it's time.
141 std::vector<uint64_t> times;
142 bool haveTimes(false);
144 if (dbs.Open())
146 haveTimes = dbs.GetStackTimes(item.GetPath(), times);
147 dbs.Close();
150 // calculate the total time of the stack
151 uint64_t totalTimeMs = 0;
152 for (int i = 0; i < m_currentStack->Size(); i++)
154 if (haveTimes)
156 // set end time in every part
157 GetStackPartFileItem(i).SetEndOffset(times[i]);
159 else
161 int duration;
162 if (!CDVDFileInfo::GetFileDuration(GetStackPartFileItem(i).GetPath(), duration))
164 m_currentStack->Clear();
165 return false;
167 totalTimeMs += duration;
168 // set end time in every part
169 GetStackPartFileItem(i).SetEndOffset(totalTimeMs);
170 times.push_back(totalTimeMs);
172 // set start time in every part
173 SetRegisteredStackPartStartTimeMs(GetStackPartFileItem(i), GetStackPartStartTimeMs(i));
175 // set total time in every part
176 totalTimeMs = GetStackTotalTimeMs();
177 for (int i = 0; i < m_currentStack->Size(); i++)
178 SetRegisteredStackTotalTimeMs(GetStackPartFileItem(i), totalTimeMs);
180 uint64_t msecs = item.GetStartOffset();
182 if (!haveTimes || item.GetStartOffset() == STARTOFFSET_RESUME)
184 if (dbs.Open())
186 // have our times now, so update the dB
187 if (!haveTimes && !times.empty())
188 dbs.SetStackTimes(item.GetPath(), times);
190 if (item.GetStartOffset() == STARTOFFSET_RESUME)
192 // can only resume seek here, not dvdstate
193 CBookmark bookmark;
194 std::string path = item.GetPath();
195 if (item.HasProperty("original_listitem_url") && URIUtils::IsPlugin(item.GetProperty("original_listitem_url").asString()))
196 path = item.GetProperty("original_listitem_url").asString();
197 if (dbs.GetResumeBookMark(path, bookmark))
198 msecs = static_cast<uint64_t>(bookmark.timeInSeconds * 1000);
199 else
200 msecs = 0;
202 dbs.Close();
206 m_currentStackPosition = GetStackPartNumberAtTimeMs(msecs);
207 startoffset = msecs - GetStackPartStartTimeMs(m_currentStackPosition);
209 return startoffset;
212 bool CApplicationStackHelper::IsPlayingISOStack() const
214 return m_currentStack->Size() > 0 && m_currentStackIsDiscImageStack;
217 bool CApplicationStackHelper::IsPlayingRegularStack() const
219 return m_currentStack->Size() > 0 && !m_currentStackIsDiscImageStack;
222 bool CApplicationStackHelper::HasNextStackPartFileItem() const
224 return m_currentStackPosition < m_currentStack->Size() - 1;
227 uint64_t CApplicationStackHelper::GetStackPartEndTimeMs(int partNumber) const
229 return GetStackPartFileItem(partNumber).GetEndOffset();
232 uint64_t CApplicationStackHelper::GetStackTotalTimeMs() const
234 return GetStackPartEndTimeMs(m_currentStack->Size() - 1);
237 int CApplicationStackHelper::GetStackPartNumberAtTimeMs(uint64_t msecs)
239 if (msecs > 0)
241 // work out where to seek to
242 for (int partNumber = 0; partNumber < m_currentStack->Size(); partNumber++)
244 if (msecs < GetStackPartEndTimeMs(partNumber))
245 return partNumber;
248 return 0;
251 void CApplicationStackHelper::ClearAllRegisteredStackInformation()
253 m_stackmap.clear();
256 std::shared_ptr<const CFileItem> CApplicationStackHelper::GetRegisteredStack(
257 const CFileItem& item) const
259 return GetStackPartInformation(item.GetPath())->m_pStack;
262 bool CApplicationStackHelper::HasRegisteredStack(const CFileItem& item) const
264 const auto it = m_stackmap.find(item.GetPath());
265 return it != m_stackmap.end() && it->second != nullptr;
268 void CApplicationStackHelper::SetRegisteredStack(const CFileItem& item,
269 std::shared_ptr<CFileItem> stackItem)
271 GetStackPartInformation(item.GetPath())->m_pStack = std::move(stackItem);
274 CFileItem& CApplicationStackHelper::GetStackPartFileItem(int partNumber)
276 return *(*m_currentStack)[partNumber];
279 const CFileItem& CApplicationStackHelper::GetStackPartFileItem(int partNumber) const
281 return *(*m_currentStack)[partNumber];
284 int CApplicationStackHelper::GetRegisteredStackPartNumber(const CFileItem& item)
286 return GetStackPartInformation(item.GetPath())->m_lStackPartNumber;
289 void CApplicationStackHelper::SetRegisteredStackPartNumber(const CFileItem& item, int partNumber)
291 GetStackPartInformation(item.GetPath())->m_lStackPartNumber = partNumber;
294 uint64_t CApplicationStackHelper::GetRegisteredStackPartStartTimeMs(const CFileItem& item) const
296 return GetStackPartInformation(item.GetPath())->m_lStackPartStartTimeMs;
299 void CApplicationStackHelper::SetRegisteredStackPartStartTimeMs(const CFileItem& item, uint64_t startTime)
301 GetStackPartInformation(item.GetPath())->m_lStackPartStartTimeMs = startTime;
304 uint64_t CApplicationStackHelper::GetRegisteredStackTotalTimeMs(const CFileItem& item) const
306 return GetStackPartInformation(item.GetPath())->m_lStackTotalTimeMs;
309 void CApplicationStackHelper::SetRegisteredStackTotalTimeMs(const CFileItem& item, uint64_t totalTime)
311 GetStackPartInformation(item.GetPath())->m_lStackTotalTimeMs = totalTime;
314 CApplicationStackHelper::StackPartInformationPtr CApplicationStackHelper::GetStackPartInformation(
315 const std::string& key)
317 if (m_stackmap.count(key) == 0)
319 StackPartInformationPtr value(new StackPartInformation());
320 m_stackmap[key] = value;
322 return m_stackmap[key];
325 CApplicationStackHelper::StackPartInformationPtr CApplicationStackHelper::GetStackPartInformation(
326 const std::string& key) const
328 const auto it = m_stackmap.find(key);
329 if (it == m_stackmap.end())
330 return std::make_shared<StackPartInformation>();
331 return it->second;