Merge pull request #26350 from jjd-uk/estuary_media_align
[xbmc.git] / xbmc / application / ApplicationPlayerCallback.cpp
blob2c37831db98b4d13e3bb1a62e8202d7e9982265c
1 /*
2 * Copyright (C) 2005-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 "ApplicationPlayerCallback.h"
11 #include "FileItem.h"
12 #include "GUIUserMessages.h"
13 #include "PlayListPlayer.h"
14 #include "ServiceBroker.h"
15 #include "URL.h"
16 #include "application/ApplicationComponents.h"
17 #include "application/ApplicationPlayer.h"
18 #include "application/ApplicationStackHelper.h"
19 #include "guilib/GUIComponent.h"
20 #include "guilib/GUIMessage.h"
21 #include "guilib/GUIWindowManager.h"
22 #include "guilib/StereoscopicsManager.h"
23 #include "interfaces/AnnouncementManager.h"
24 #include "interfaces/python/XBPython.h"
25 #include "music/MusicFileItemClassify.h"
26 #include "network/NetworkFileItemClassify.h"
27 #include "profiles/ProfileManager.h"
28 #include "settings/AdvancedSettings.h"
29 #include "settings/MediaSettings.h"
30 #include "settings/SettingsComponent.h"
31 #include "utils/JobManager.h"
32 #include "utils/SaveFileStateJob.h"
33 #include "utils/URIUtils.h"
34 #include "utils/log.h"
35 #include "video/VideoDatabase.h"
36 #include "video/VideoFileItemClassify.h"
37 #include "video/VideoInfoTag.h"
39 #include <memory>
41 using namespace KODI;
43 CApplicationPlayerCallback::CApplicationPlayerCallback()
47 void CApplicationPlayerCallback::OnPlayBackEnded()
49 CLog::LogF(LOGDEBUG, "CApplicationPlayerCallback::OnPlayBackEnded");
51 CGUIMessage msg(GUI_MSG_PLAYBACK_ENDED, 0, 0);
52 CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg);
55 void CApplicationPlayerCallback::OnPlayBackStarted(const CFileItem& file)
57 CLog::LogF(LOGDEBUG, "CApplication::OnPlayBackStarted");
58 std::shared_ptr<CFileItem> itemCurrentFile;
60 // check if VideoPlayer should set file item stream details from its current streams
61 const bool isBlu_dvd_image_or_stream = URIUtils::IsBlurayPath(file.GetPath()) ||
62 VIDEO::IsDVDFile(file) || file.IsDiscImage() ||
63 NETWORK::IsInternetStream(file);
65 const bool hasNoStreamDetails =
66 (!file.HasVideoInfoTag() || !file.GetVideoInfoTag()->HasStreamDetails());
68 if (file.GetProperty("get_stream_details_from_player").asBoolean() ||
69 (hasNoStreamDetails && isBlu_dvd_image_or_stream))
71 auto& components = CServiceBroker::GetAppComponents();
72 const auto appPlayer = components.GetComponent<CApplicationPlayer>();
73 appPlayer->SetUpdateStreamDetails();
76 auto& components = CServiceBroker::GetAppComponents();
77 const auto stackHelper = components.GetComponent<CApplicationStackHelper>();
79 if (stackHelper->IsPlayingISOStack() || stackHelper->IsPlayingRegularStack())
80 itemCurrentFile = std::make_shared<CFileItem>(*stackHelper->GetRegisteredStack(file));
81 else
82 itemCurrentFile = std::make_shared<CFileItem>(file);
84 /* When playing video pause any low priority jobs, they will be unpaused when playback stops.
85 * This should speed up player startup for files on internet filesystems (eg. webdav) and
86 * increase performance on low powered systems (Atom/ARM).
88 if (VIDEO::IsVideo(file) || file.IsGame())
90 CServiceBroker::GetJobManager()->PauseJobs();
93 stackHelper->OnPlayBackStarted(file);
95 CGUIMessage msg(GUI_MSG_PLAYBACK_STARTED, 0, 0, 0, 0, itemCurrentFile);
96 CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg);
99 void CApplicationPlayerCallback::OnPlayerCloseFile(const CFileItem& file,
100 const CBookmark& bookmarkParam)
102 auto& components = CServiceBroker::GetAppComponents();
103 const auto stackHelper = components.GetComponent<CApplicationStackHelper>();
105 std::unique_lock<CCriticalSection> lock(stackHelper->m_critSection);
107 CFileItem fileItem(file);
108 CBookmark bookmark = bookmarkParam;
109 CBookmark resumeBookmark;
110 bool playCountUpdate = false;
111 float percent = 0.0f;
113 // Make sure we don't reset existing bookmark etc. on eg. player start failure
114 if (bookmark.timeInSeconds == 0.0)
115 return;
117 if (stackHelper->GetRegisteredStack(fileItem) != nullptr &&
118 stackHelper->GetRegisteredStackTotalTimeMs(fileItem) > 0)
120 // regular stack case: we have to save the bookmark on the stack
121 fileItem = *stackHelper->GetRegisteredStack(file);
122 // the bookmark coming from the player is only relative to the current part, thus needs to be corrected with these attributes (start time will be 0 for non-stackparts)
123 bookmark.timeInSeconds += stackHelper->GetRegisteredStackPartStartTimeMs(file) / 1000.0;
124 if (stackHelper->GetRegisteredStackTotalTimeMs(file) > 0)
125 bookmark.totalTimeInSeconds = stackHelper->GetRegisteredStackTotalTimeMs(file) / 1000.0;
126 bookmark.partNumber = stackHelper->GetRegisteredStackPartNumber(file);
129 percent = bookmark.timeInSeconds / bookmark.totalTimeInSeconds * 100;
131 const std::shared_ptr<CAdvancedSettings> advancedSettings =
132 CServiceBroker::GetSettingsComponent()->GetAdvancedSettings();
134 if ((MUSIC::IsAudio(fileItem) && advancedSettings->m_audioPlayCountMinimumPercent > 0 &&
135 percent >= advancedSettings->m_audioPlayCountMinimumPercent) ||
136 (VIDEO::IsVideo(fileItem) && advancedSettings->m_videoPlayCountMinimumPercent > 0 &&
137 percent >= advancedSettings->m_videoPlayCountMinimumPercent))
139 playCountUpdate = true;
142 if (advancedSettings->m_videoIgnorePercentAtEnd > 0 &&
143 bookmark.totalTimeInSeconds - bookmark.timeInSeconds <
144 0.01 * static_cast<double>(advancedSettings->m_videoIgnorePercentAtEnd) *
145 bookmark.totalTimeInSeconds)
147 resumeBookmark.timeInSeconds = -1.0;
149 else if (bookmark.timeInSeconds > advancedSettings->m_videoIgnoreSecondsAtStart)
151 resumeBookmark = bookmark;
152 if (stackHelper->GetRegisteredStack(file) != nullptr)
154 // also update video info tag with total time
155 fileItem.GetVideoInfoTag()->m_streamDetails.SetVideoDuration(
156 0, resumeBookmark.totalTimeInSeconds);
159 else
161 resumeBookmark.timeInSeconds = 0.0;
164 if (CServiceBroker::GetSettingsComponent()
165 ->GetProfileManager()
166 ->GetCurrentProfile()
167 .canWriteDatabases())
169 CSaveFileState::DoWork(fileItem, resumeBookmark, playCountUpdate);
173 void CApplicationPlayerCallback::OnPlayBackPaused()
175 #ifdef HAS_PYTHON
176 CServiceBroker::GetXBPython().OnPlayBackPaused();
177 #endif
179 CGUIMessage msg(GUI_MSG_PLAYBACK_PAUSED, 0, 0);
180 CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg);
183 void CApplicationPlayerCallback::OnPlayBackResumed()
185 #ifdef HAS_PYTHON
186 CServiceBroker::GetXBPython().OnPlayBackResumed();
187 #endif
189 CGUIMessage msg(GUI_MSG_PLAYBACK_RESUMED, 0, 0);
190 CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg);
193 void CApplicationPlayerCallback::OnPlayBackStopped()
195 CLog::LogF(LOGDEBUG, "CApplication::OnPlayBackStopped");
197 CGUIMessage msg(GUI_MSG_PLAYBACK_STOPPED, 0, 0);
198 CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg);
201 void CApplicationPlayerCallback::OnPlayBackError()
203 //@todo Playlists can be continued by calling OnPlaybackEnded instead
204 // open error dialog
205 CGUIMessage msg(GUI_MSG_PLAYBACK_ERROR, 0, 0);
206 CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg);
207 OnPlayBackStopped();
210 void CApplicationPlayerCallback::OnQueueNextItem()
212 CLog::LogF(LOGDEBUG, "CApplication::OnQueueNextItem");
214 // informs python script currently running that we are requesting the next track
215 // (does nothing if python is not loaded)
216 #ifdef HAS_PYTHON
217 CServiceBroker::GetXBPython().OnQueueNextItem(); // currently unimplemented
218 #endif
220 CGUIMessage msg(GUI_MSG_QUEUE_NEXT_ITEM, 0, 0);
221 CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg);
224 void CApplicationPlayerCallback::OnPlayBackSeek(int64_t iTime, int64_t seekOffset)
226 #ifdef HAS_PYTHON
227 CServiceBroker::GetXBPython().OnPlayBackSeek(static_cast<int>(iTime),
228 static_cast<int>(seekOffset));
229 #endif
231 CGUIMessage msg(GUI_MSG_PLAYBACK_SEEKED, 0, 0, iTime, seekOffset);
232 CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg);
235 void CApplicationPlayerCallback::OnPlayBackSeekChapter(int iChapter)
237 #ifdef HAS_PYTHON
238 CServiceBroker::GetXBPython().OnPlayBackSeekChapter(iChapter);
239 #endif
242 void CApplicationPlayerCallback::OnPlayBackSpeedChanged(int iSpeed)
244 #ifdef HAS_PYTHON
245 CServiceBroker::GetXBPython().OnPlayBackSpeedChanged(iSpeed);
246 #endif
248 CGUIMessage msg(GUI_MSG_PLAYBACK_SPEED_CHANGED, 0, 0, iSpeed);
249 CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg);
252 void CApplicationPlayerCallback::OnAVChange()
254 CLog::LogF(LOGDEBUG, "CApplication::OnAVChange");
256 CServiceBroker::GetGUI()->GetStereoscopicsManager().OnStreamChange();
258 CGUIMessage msg(GUI_MSG_PLAYBACK_AVCHANGE, 0, 0);
259 CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg);
262 void CApplicationPlayerCallback::OnAVStarted(const CFileItem& file)
264 CLog::LogF(LOGDEBUG, "CApplication::OnAVStarted");
266 CGUIMessage msg(GUI_MSG_PLAYBACK_AVSTARTED, 0, 0);
267 CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg);
270 void CApplicationPlayerCallback::RequestVideoSettings(const CFileItem& fileItem)
272 CVideoDatabase dbs;
273 if (dbs.Open())
275 CLog::Log(LOGDEBUG, "Loading settings for {}", CURL::GetRedacted(fileItem.GetPath()));
277 // Load stored settings if they exist, otherwise use default
278 CVideoSettings vs;
279 if (!dbs.GetVideoSettings(fileItem, vs))
280 vs = CMediaSettings::GetInstance().GetDefaultVideoSettings();
282 auto& components = CServiceBroker::GetAppComponents();
283 const auto appPlayer = components.GetComponent<CApplicationPlayer>();
284 appPlayer->SetVideoSettings(vs);
286 dbs.Close();
290 void CApplicationPlayerCallback::StoreVideoSettings(const CFileItem& fileItem,
291 const CVideoSettings& vs)
293 CVideoDatabase dbs;
294 if (dbs.Open())
296 if (vs != CMediaSettings::GetInstance().GetDefaultVideoSettings())
298 dbs.SetVideoSettings(fileItem, vs);
300 else
302 dbs.EraseVideoSettings(fileItem);
304 dbs.Close();