1 /*
2  *  Copyright (C) 2012-2018 Team Kodi
3  *  This file is part of Kodi - https://kodi.tv
4  *
5  *  SPDX-License-Identifier: GPL-2.0-or-later
6  *  See LICENSES/README.md for more information.
7  */
8 
9 #include "guilib/guiinfo/PlayerGUIInfo.h"
10 
11 #include "Application.h"
12 #include "FileItem.h"
13 #include "PlayListPlayer.h"
14 #include "ServiceBroker.h"
15 #include "URL.h"
16 #include "cores/AudioEngine/Utils/AEUtil.h"
17 #include "cores/Cut.h"
18 #include "cores/DataCacheCore.h"
19 #include "guilib/GUIComponent.h"
20 #include "guilib/GUIDialog.h"
21 #include "guilib/GUIWindowManager.h"
22 #include "guilib/guiinfo/GUIInfo.h"
23 #include "guilib/guiinfo/GUIInfoHelper.h"
24 #include "guilib/guiinfo/GUIInfoLabels.h"
25 #include "utils/StringUtils.h"
26 #include "utils/TimeUtils.h"
27 #include "utils/URIUtils.h"
28 #include "utils/Variant.h"
29 #include "utils/log.h"
30 
31 #include <cmath>
32 
33 using namespace KODI::GUILIB::GUIINFO;
34 
CPlayerGUIInfo()35 CPlayerGUIInfo::CPlayerGUIInfo()
36 : m_playerShowTime(false),
37   m_playerShowInfo(false)
38 {
39 }
40 
41 CPlayerGUIInfo::~CPlayerGUIInfo() = default;
42 
GetTotalPlayTime() const43 int CPlayerGUIInfo::GetTotalPlayTime() const
44 {
45   return std::lrint(g_application.GetTotalTime());
46 }
47 
GetPlayTime() const48 int CPlayerGUIInfo::GetPlayTime() const
49 {
50   return std::lrint(g_application.GetTime());
51 }
52 
GetPlayTimeRemaining() const53 int CPlayerGUIInfo::GetPlayTimeRemaining() const
54 {
55   int iReverse = GetTotalPlayTime() - std::lrint(g_application.GetTime());
56   return iReverse > 0 ? iReverse : 0;
57 }
58 
GetSeekPercent() const59 float CPlayerGUIInfo::GetSeekPercent() const
60 {
61   int iTotal = GetTotalPlayTime();
62   if (iTotal == 0)
63     return 0.0f;
64 
65   float fPercentPlayTime = static_cast<float>(GetPlayTime() * 1000) / iTotal * 0.1f;
66   float fPercentPerSecond = 100.0f / static_cast<float>(iTotal);
67   float fPercent = fPercentPlayTime + fPercentPerSecond * g_application.GetAppPlayer().GetSeekHandler().GetSeekSize();
68   fPercent = std::max(0.0f, std::min(fPercent, 100.0f));
69   return fPercent;
70 }
71 
GetCurrentPlayTime(TIME_FORMAT format) const72 std::string CPlayerGUIInfo::GetCurrentPlayTime(TIME_FORMAT format) const
73 {
74   if (format == TIME_FORMAT_GUESS && GetTotalPlayTime() >= 3600)
75     format = TIME_FORMAT_HH_MM_SS;
76 
77   return StringUtils::SecondsToTimeString(std::lrint(GetPlayTime()), format);
78 }
79 
GetCurrentPlayTimeRemaining(TIME_FORMAT format) const80 std::string CPlayerGUIInfo::GetCurrentPlayTimeRemaining(TIME_FORMAT format) const
81 {
82   if (format == TIME_FORMAT_GUESS && GetTotalPlayTime() >= 3600)
83     format = TIME_FORMAT_HH_MM_SS;
84 
85   int iTimeRemaining = GetPlayTimeRemaining();
86   if (iTimeRemaining)
87     return StringUtils::SecondsToTimeString(iTimeRemaining, format);
88 
89   return std::string();
90 }
91 
GetDuration(TIME_FORMAT format) const92 std::string CPlayerGUIInfo::GetDuration(TIME_FORMAT format) const
93 {
94   int iTotal = GetTotalPlayTime();
95   if (iTotal > 0)
96   {
97     if (format == TIME_FORMAT_GUESS && iTotal >= 3600)
98       format = TIME_FORMAT_HH_MM_SS;
99     return StringUtils::SecondsToTimeString(iTotal, format);
100   }
101   return std::string();
102 }
103 
GetCurrentSeekTime(TIME_FORMAT format) const104 std::string CPlayerGUIInfo::GetCurrentSeekTime(TIME_FORMAT format) const
105 {
106   if (format == TIME_FORMAT_GUESS && GetTotalPlayTime() >= 3600)
107     format = TIME_FORMAT_HH_MM_SS;
108 
109   return StringUtils::SecondsToTimeString(g_application.GetTime() + g_application.GetAppPlayer().GetSeekHandler().GetSeekSize(), format);
110 }
111 
GetSeekTime(TIME_FORMAT format) const112 std::string CPlayerGUIInfo::GetSeekTime(TIME_FORMAT format) const
113 {
114   if (!g_application.GetAppPlayer().GetSeekHandler().HasTimeCode())
115     return std::string();
116 
117   int iSeekTimeCode = g_application.GetAppPlayer().GetSeekHandler().GetTimeCodeSeconds();
118   if (format == TIME_FORMAT_GUESS && iSeekTimeCode >= 3600)
119     format = TIME_FORMAT_HH_MM_SS;
120 
121   return StringUtils::SecondsToTimeString(iSeekTimeCode, format);
122 }
123 
SetDisplayAfterSeek(unsigned int timeOut,int seekOffset)124 void CPlayerGUIInfo::SetDisplayAfterSeek(unsigned int timeOut, int seekOffset)
125 {
126   if (timeOut > 0)
127   {
128     m_AfterSeekTimeout = CTimeUtils::GetFrameTime() +  timeOut;
129     if (seekOffset)
130       m_seekOffset = seekOffset;
131   }
132   else
133     m_AfterSeekTimeout = 0;
134 }
135 
GetDisplayAfterSeek() const136 bool CPlayerGUIInfo::GetDisplayAfterSeek() const
137 {
138   if (CTimeUtils::GetFrameTime() < m_AfterSeekTimeout)
139     return true;
140   m_seekOffset = 0;
141   return false;
142 }
143 
SetShowInfo(bool showinfo)144 void CPlayerGUIInfo::SetShowInfo(bool showinfo)
145 {
146   m_playerShowInfo = showinfo;
147 }
148 
ToggleShowInfo()149 bool CPlayerGUIInfo::ToggleShowInfo()
150 {
151   SetShowInfo(!m_playerShowInfo);
152   return m_playerShowInfo;
153 }
154 
InitCurrentItem(CFileItem * item)155 bool CPlayerGUIInfo::InitCurrentItem(CFileItem *item)
156 {
157   if (item && g_application.GetAppPlayer().IsPlaying())
158   {
159     CLog::Log(LOGDEBUG, "CPlayerGUIInfo::InitCurrentItem(%s)", CURL::GetRedacted(item->GetPath()).c_str());
160     m_currentItem.reset(new CFileItem(*item));
161   }
162   else
163   {
164     m_currentItem.reset();
165   }
166   return false;
167 }
168 
GetLabel(std::string & value,const CFileItem * item,int contextWindow,const CGUIInfo & info,std::string * fallback) const169 bool CPlayerGUIInfo::GetLabel(std::string& value, const CFileItem *item, int contextWindow, const CGUIInfo &info, std::string *fallback) const
170 {
171   switch (info.m_info)
172   {
173     ///////////////////////////////////////////////////////////////////////////////////////////////
174     // PLAYER_*
175     ///////////////////////////////////////////////////////////////////////////////////////////////
176     case PLAYER_SEEKOFFSET:
177     {
178       std::string seekOffset = StringUtils::SecondsToTimeString(std::abs(m_seekOffset / 1000), static_cast<TIME_FORMAT>(info.GetData1()));
179       if (m_seekOffset < 0)
180         value = "-" + seekOffset;
181       else if (m_seekOffset > 0)
182         value = "+" + seekOffset;
183       return true;
184     }
185     case PLAYER_PROGRESS:
186       value = std::to_string(std::lrintf(g_application.GetPercentage()));
187       return true;
188     case PLAYER_PROGRESS_CACHE:
189       value = std::to_string(std::lrintf(g_application.GetCachePercentage()));
190       return true;
191     case PLAYER_VOLUME:
192       value = StringUtils::Format("%2.1f dB", CAEUtil::PercentToGain(g_application.GetVolumeRatio()));
193       return true;
194     case PLAYER_SUBTITLE_DELAY:
195       value = StringUtils::Format("%2.3f s", g_application.GetAppPlayer().GetVideoSettings().m_SubtitleDelay);
196       return true;
197     case PLAYER_AUDIO_DELAY:
198       value = StringUtils::Format("%2.3f s", g_application.GetAppPlayer().GetVideoSettings().m_AudioDelay);
199       return true;
200     case PLAYER_CHAPTER:
201       value = StringUtils::Format("%02d", g_application.GetAppPlayer().GetChapter());
202       return true;
203     case PLAYER_CHAPTERCOUNT:
204       value = StringUtils::Format("%02d", g_application.GetAppPlayer().GetChapterCount());
205       return true;
206     case PLAYER_CHAPTERNAME:
207       g_application.GetAppPlayer().GetChapterName(value);
208       return true;
209     case PLAYER_PATH:
210     case PLAYER_FILENAME:
211     case PLAYER_FILEPATH:
212       value = GUIINFO::GetFileInfoLabelValueFromPath(info.m_info, item->GetPath());
213       return true;
214     case PLAYER_TITLE:
215       // use label or drop down to title from path
216       value = item->GetLabel();
217       if (value.empty())
218         value = CUtil::GetTitleFromPath(item->GetPath());
219       return true;
220     case PLAYER_PLAYSPEED:
221     {
222       float speed = g_application.GetAppPlayer().GetPlaySpeed();
223       if (speed == 1.0)
224         speed = g_application.GetAppPlayer().GetPlayTempo();
225       value = StringUtils::Format("%.2f", speed);
226       return true;
227     }
228     case PLAYER_TIME:
229       value = GetCurrentPlayTime(static_cast<TIME_FORMAT>(info.GetData1()));
230       return true;
231     case PLAYER_START_TIME:
232     {
233       const CDateTime time(g_application.GetAppPlayer().GetStartTime());
234       value = time.GetAsLocalizedTime(static_cast<TIME_FORMAT>(info.GetData1()));
235       return true;
236     }
237     case PLAYER_DURATION:
238       value = GetDuration(static_cast<TIME_FORMAT>(info.GetData1()));
239       return true;
240     case PLAYER_TIME_REMAINING:
241       value = GetCurrentPlayTimeRemaining(static_cast<TIME_FORMAT>(info.GetData1()));
242       return true;
243     case PLAYER_FINISH_TIME:
244     {
245       CDateTime time(CDateTime::GetCurrentDateTime());
246       int playTimeRemaining = GetPlayTimeRemaining();
247       float speed = g_application.GetAppPlayer().GetPlaySpeed();
248       float tempo = g_application.GetAppPlayer().GetPlayTempo();
249       if (speed == 1.0)
250         playTimeRemaining /= tempo;
251       time += CDateTimeSpan(0, 0, 0, playTimeRemaining);
252       value = time.GetAsLocalizedTime(static_cast<TIME_FORMAT>(info.GetData1()));
253       return true;
254     }
255     case PLAYER_TIME_SPEED:
256     {
257       float speed = g_application.GetAppPlayer().GetPlaySpeed();
258       if (speed != 1.0)
259         value = StringUtils::Format("%s (%ix)", GetCurrentPlayTime(static_cast<TIME_FORMAT>(info.GetData1())).c_str(), static_cast<int>(speed));
260       else
261         value = GetCurrentPlayTime(TIME_FORMAT_GUESS);
262       return true;
263     }
264     case PLAYER_SEEKTIME:
265       value = GetCurrentSeekTime(static_cast<TIME_FORMAT>(info.GetData1()));
266       return true;
267     case PLAYER_SEEKSTEPSIZE:
268     {
269       int seekSize = g_application.GetAppPlayer().GetSeekHandler().GetSeekSize();
270       std::string strSeekSize = StringUtils::SecondsToTimeString(abs(seekSize), static_cast<TIME_FORMAT>(info.GetData1()));
271       if (seekSize < 0)
272         value = "-" + strSeekSize;
273       if (seekSize > 0)
274         value = "+" + strSeekSize;
275       return true;
276     }
277     case PLAYER_SEEKNUMERIC:
278       value = GetSeekTime(static_cast<TIME_FORMAT>(info.GetData1()));
279       return !value.empty();
280     case PLAYER_CACHELEVEL:
281     {
282       int iLevel = g_application.GetAppPlayer().GetCacheLevel();
283       if (iLevel >= 0)
284       {
285         value = StringUtils::Format("%i", iLevel);
286         return true;
287       }
288       break;
289     }
290     case PLAYER_ITEM_ART:
291       value = item->GetArt(info.GetData3());
292       return true;
293     case PLAYER_ICON:
294       value = item->GetArt("thumb");
295       if (value.empty())
296         value = item->GetArt("icon");
297       if (fallback)
298         *fallback = item->GetArt("icon");
299       return true;
300     case PLAYER_CUTLIST:
301     case PLAYER_CHAPTERS:
302       value = GetContentRanges(info.m_info);
303       return true;
304 
305     ///////////////////////////////////////////////////////////////////////////////////////////////
306     // PLAYER_PROCESS_*
307     ///////////////////////////////////////////////////////////////////////////////////////////////
308     case PLAYER_PROCESS_VIDEODECODER:
309       value = CServiceBroker::GetDataCacheCore().GetVideoDecoderName();
310       return true;
311     case PLAYER_PROCESS_DEINTMETHOD:
312       value = CServiceBroker::GetDataCacheCore().GetVideoDeintMethod();
313       return true;
314     case PLAYER_PROCESS_PIXELFORMAT:
315       value = CServiceBroker::GetDataCacheCore().GetVideoPixelFormat();
316       return true;
317     case PLAYER_PROCESS_VIDEOFPS:
318       value = StringUtils::Format("%.3f", CServiceBroker::GetDataCacheCore().GetVideoFps());
319       return true;
320     case PLAYER_PROCESS_VIDEODAR:
321       value = StringUtils::Format("%.2f", CServiceBroker::GetDataCacheCore().GetVideoDAR());
322       return true;
323     case PLAYER_PROCESS_VIDEOWIDTH:
324       value = StringUtils::FormatNumber(CServiceBroker::GetDataCacheCore().GetVideoWidth());
325       return true;
326     case PLAYER_PROCESS_VIDEOHEIGHT:
327       value = StringUtils::FormatNumber(CServiceBroker::GetDataCacheCore().GetVideoHeight());
328       return true;
329     case PLAYER_PROCESS_AUDIODECODER:
330       value = CServiceBroker::GetDataCacheCore().GetAudioDecoderName();
331       return true;
332     case PLAYER_PROCESS_AUDIOCHANNELS:
333       value = CServiceBroker::GetDataCacheCore().GetAudioChannels();
334       return true;
335     case PLAYER_PROCESS_AUDIOSAMPLERATE:
336       value = StringUtils::FormatNumber(CServiceBroker::GetDataCacheCore().GetAudioSampleRate());
337       return true;
338     case PLAYER_PROCESS_AUDIOBITSPERSAMPLE:
339       value = StringUtils::FormatNumber(CServiceBroker::GetDataCacheCore().GetAudioBitsPerSample());
340       return true;
341 
342     ///////////////////////////////////////////////////////////////////////////////////////////////
343     // PLAYLIST_*
344     ///////////////////////////////////////////////////////////////////////////////////////////////
345     case PLAYLIST_LENGTH:
346     case PLAYLIST_POSITION:
347     case PLAYLIST_RANDOM:
348     case PLAYLIST_REPEAT:
349       value = GUIINFO::GetPlaylistLabel(info.m_info, info.GetData1());
350       return true;
351   }
352 
353   return false;
354 }
355 
GetInt(int & value,const CGUIListItem * gitem,int contextWindow,const CGUIInfo & info) const356 bool CPlayerGUIInfo::GetInt(int& value, const CGUIListItem *gitem, int contextWindow, const CGUIInfo &info) const
357 {
358   switch (info.m_info)
359   {
360     ///////////////////////////////////////////////////////////////////////////////////////////////
361     // PLAYER_*
362     ///////////////////////////////////////////////////////////////////////////////////////////////
363     case PLAYER_VOLUME:
364       value = static_cast<int>(g_application.GetVolumePercent());
365       return true;
366     case PLAYER_SUBTITLE_DELAY:
367       value = g_application.GetSubtitleDelay();
368       return true;
369     case PLAYER_AUDIO_DELAY:
370       value = g_application.GetAudioDelay();
371       return true;
372     case PLAYER_PROGRESS:
373       value = std::lrintf(g_application.GetPercentage());
374       return true;
375     case PLAYER_PROGRESS_CACHE:
376       value = std::lrintf(g_application.GetCachePercentage());
377       return true;
378     case PLAYER_CACHELEVEL:
379       value = g_application.GetAppPlayer().GetCacheLevel();
380       return true;
381     case PLAYER_CHAPTER:
382       value = g_application.GetAppPlayer().GetChapter();
383       return true;
384     case PLAYER_CHAPTERCOUNT:
385       value = g_application.GetAppPlayer().GetChapterCount();
386       return true;
387     case PLAYER_SEEKBAR:
388       value = std::lrintf(GetSeekPercent());
389       return true;
390   }
391 
392   return false;
393 }
394 
GetBool(bool & value,const CGUIListItem * gitem,int contextWindow,const CGUIInfo & info) const395 bool CPlayerGUIInfo::GetBool(bool& value, const CGUIListItem *gitem, int contextWindow, const CGUIInfo &info) const
396 {
397   const CFileItem *item = nullptr;
398   if (gitem->IsFileItem())
399     item = static_cast<const CFileItem*>(gitem);
400 
401   switch (info.m_info)
402   {
403     ///////////////////////////////////////////////////////////////////////////////////////////////
404     // PLAYER_*
405     ///////////////////////////////////////////////////////////////////////////////////////////////
406     case PLAYER_SHOWINFO:
407       value = m_playerShowInfo;
408       return true;
409     case PLAYER_DISPLAY_AFTER_SEEK:
410       value = GetDisplayAfterSeek();
411       return true;
412     case PLAYER_SHOWTIME:
413       value = m_playerShowTime;
414       return true;
415     case PLAYER_MUTED:
416       value = (g_application.IsMuted() || g_application.GetVolumeRatio() <= VOLUME_MINIMUM);
417       return true;
418     case PLAYER_HAS_MEDIA:
419       value = g_application.GetAppPlayer().IsPlaying();
420       return true;
421     case PLAYER_HAS_AUDIO:
422       value = g_application.GetAppPlayer().IsPlayingAudio();
423       return true;
424     case PLAYER_HAS_VIDEO:
425       value = g_application.GetAppPlayer().IsPlayingVideo();
426       return true;
427     case PLAYER_HAS_GAME:
428       value = g_application.GetAppPlayer().IsPlayingGame();
429       return true;
430     case PLAYER_PLAYING:
431       value = g_application.GetAppPlayer().GetPlaySpeed() == 1.0;
432       return true;
433     case PLAYER_PAUSED:
434       value = g_application.GetAppPlayer().IsPausedPlayback();
435       return true;
436     case PLAYER_REWINDING:
437       value = g_application.GetAppPlayer().GetPlaySpeed() < 0;
438       return true;
439     case PLAYER_FORWARDING:
440       value = g_application.GetAppPlayer().GetPlaySpeed() > 1.5;
441       return true;
442     case PLAYER_REWINDING_2x:
443       value = g_application.GetAppPlayer().GetPlaySpeed() == -2;
444       return true;
445     case PLAYER_REWINDING_4x:
446       value = g_application.GetAppPlayer().GetPlaySpeed() == -4;
447       return true;
448     case PLAYER_REWINDING_8x:
449       value = g_application.GetAppPlayer().GetPlaySpeed() == -8;
450       return true;
451     case PLAYER_REWINDING_16x:
452       value = g_application.GetAppPlayer().GetPlaySpeed() == -16;
453       return true;
454     case PLAYER_REWINDING_32x:
455       value = g_application.GetAppPlayer().GetPlaySpeed() == -32;
456       return true;
457     case PLAYER_FORWARDING_2x:
458       value = g_application.GetAppPlayer().GetPlaySpeed() == 2;
459       return true;
460     case PLAYER_FORWARDING_4x:
461       value = g_application.GetAppPlayer().GetPlaySpeed() == 4;
462       return true;
463     case PLAYER_FORWARDING_8x:
464       value = g_application.GetAppPlayer().GetPlaySpeed() == 8;
465       return true;
466     case PLAYER_FORWARDING_16x:
467       value = g_application.GetAppPlayer().GetPlaySpeed() == 16;
468       return true;
469     case PLAYER_FORWARDING_32x:
470       value = g_application.GetAppPlayer().GetPlaySpeed() == 32;
471       return true;
472     case PLAYER_CAN_PAUSE:
473       value = g_application.GetAppPlayer().CanPause();
474       return true;
475     case PLAYER_CAN_SEEK:
476       value = g_application.GetAppPlayer().CanSeek();
477       return true;
478     case PLAYER_SUPPORTS_TEMPO:
479       value = g_application.GetAppPlayer().SupportsTempo();
480       return true;
481     case PLAYER_IS_TEMPO:
482     {
483       value = (g_application.GetAppPlayer().GetPlayTempo() != 1.0 &&
484                g_application.GetAppPlayer().GetPlaySpeed() == 1.0);
485       return true;
486     }
487     case PLAYER_CACHING:
488       value = g_application.GetAppPlayer().IsCaching();
489       return true;
490     case PLAYER_SEEKBAR:
491     {
492       CGUIDialog *seekBar = CServiceBroker::GetGUI()->GetWindowManager().GetDialog(WINDOW_DIALOG_SEEK_BAR);
493       value = seekBar ? seekBar->IsDialogRunning() : false;
494       return true;
495     }
496     case PLAYER_SEEKING:
497       value = g_application.GetAppPlayer().GetSeekHandler().InProgress();
498       return true;
499     case PLAYER_PASSTHROUGH:
500       value = g_application.GetAppPlayer().IsPassthrough();
501       return true;
502     case PLAYER_ISINTERNETSTREAM:
503       if (item)
504       {
505         value = URIUtils::IsInternetStream(item->GetDynPath());
506         return true;
507       }
508       break;
509     case PLAYER_HAS_PROGRAMS:
510       value = (g_application.GetAppPlayer().GetProgramsCount() > 1) ? true : false;
511       return true;
512     case PLAYER_HAS_RESOLUTIONS:
513       value = CServiceBroker::GetWinSystem()->GetGfxContext().IsFullScreenRoot() &&
514               CResolutionUtils::HasWhitelist();
515       return true;
516     case PLAYER_HASDURATION:
517       value = g_application.GetTotalTime() > 0;
518       return true;
519     case PLAYER_FRAMEADVANCE:
520       value = CServiceBroker::GetDataCacheCore().IsFrameAdvance();
521       return true;
522 
523     ///////////////////////////////////////////////////////////////////////////////////////////////
524     // PLAYLIST_*
525     ///////////////////////////////////////////////////////////////////////////////////////////////
526     case PLAYLIST_ISRANDOM:
527     {
528       PLAYLIST::CPlayListPlayer& player = CServiceBroker::GetPlaylistPlayer();
529       int playlistid = info.GetData1();
530       if (info.GetData2() > 0 && playlistid > PLAYLIST_NONE)
531         value = player.IsShuffled(playlistid);
532       else
533         value = player.IsShuffled(player.GetCurrentPlaylist());
534       return true;
535     }
536     case PLAYLIST_ISREPEAT:
537     {
538       PLAYLIST::CPlayListPlayer& player = CServiceBroker::GetPlaylistPlayer();
539       int playlistid = info.GetData1();
540       if (info.GetData2() > 0 && playlistid > PLAYLIST_NONE)
541         value = (player.GetRepeat(playlistid) == PLAYLIST::REPEAT_ALL);
542       else
543         value = player.GetRepeat(player.GetCurrentPlaylist()) == PLAYLIST::REPEAT_ALL;
544       return true;
545     }
546     case PLAYLIST_ISREPEATONE:
547     {
548       PLAYLIST::CPlayListPlayer& player = CServiceBroker::GetPlaylistPlayer();
549       int playlistid = info.GetData1();
550       if (info.GetData2() > 0 && playlistid > PLAYLIST_NONE)
551         value = (player.GetRepeat(playlistid) == PLAYLIST::REPEAT_ONE);
552       else
553         value = player.GetRepeat(player.GetCurrentPlaylist()) == PLAYLIST::REPEAT_ONE;
554       return true;
555     }
556 
557     ///////////////////////////////////////////////////////////////////////////////////////////////
558     // PLAYER_PROCESS_*
559     ///////////////////////////////////////////////////////////////////////////////////////////////
560     case PLAYER_PROCESS_VIDEOHWDECODER:
561       value = CServiceBroker::GetDataCacheCore().IsVideoHwDecoder();
562       return true;
563 
564     ///////////////////////////////////////////////////////////////////////////////////////////////
565     // LISTITEM_*
566     ///////////////////////////////////////////////////////////////////////////////////////////////
567     case LISTITEM_ISPLAYING:
568     {
569       if (item)
570       {
571         if (item->HasProperty("playlistposition"))
572         {
573           value = static_cast<int>(item->GetProperty("playlisttype").asInteger()) == CServiceBroker::GetPlaylistPlayer().GetCurrentPlaylist() &&
574                   static_cast<int>(item->GetProperty("playlistposition").asInteger()) == CServiceBroker::GetPlaylistPlayer().GetCurrentSong();
575           return true;
576         }
577         else if (m_currentItem && !m_currentItem->GetPath().empty())
578         {
579           if (!g_application.m_strPlayListFile.empty())
580           {
581             //playlist file that is currently playing or the playlistitem that is currently playing.
582             value = item->IsPath(g_application.m_strPlayListFile) || m_currentItem->IsSamePath(item);
583           }
584           else
585           {
586             value = m_currentItem->IsSamePath(item);
587           }
588           return true;
589         }
590       }
591       break;
592     }
593   }
594 
595   return false;
596 }
597 
GetContentRanges(int iInfo) const598 std::string CPlayerGUIInfo::GetContentRanges(int iInfo) const
599 {
600   std::string values;
601 
602   CDataCacheCore& data = CServiceBroker::GetDataCacheCore();
603   std::vector<std::pair<float, float>> ranges;
604 
605   time_t start;
606   int64_t current;
607   int64_t min;
608   int64_t max;
609   data.GetPlayTimes(start, current, min, max);
610 
611   time_t duration = max - start * 1000;
612   if (duration > 0)
613   {
614     switch (iInfo)
615     {
616       case PLAYER_CUTLIST:
617         ranges = GetCutList(data, duration);
618         break;
619       case PLAYER_CHAPTERS:
620         ranges = GetChapters(data, duration);
621         break;
622       default:
623         CLog::Log(LOGERROR, "CPlayerGUIInfo::GetContentRanges(%i) - unhandled guiinfo", iInfo);
624         break;
625     }
626 
627     // create csv string from ranges
628     for (const auto& range : ranges)
629       values += StringUtils::Format("%.5f,%.5f,", range.first, range.second);
630 
631     if (!values.empty())
632       values.pop_back(); // remove trailing comma
633   }
634 
635   return values;
636 }
637 
GetCutList(CDataCacheCore & data,time_t duration) const638 std::vector<std::pair<float, float>> CPlayerGUIInfo::GetCutList(CDataCacheCore& data, time_t duration) const
639 {
640   std::vector<std::pair<float, float>> ranges;
641 
642   const std::vector<EDL::Cut> cuts = data.GetCutList();
643   for (const auto& cut : cuts)
644   {
645     if (cut.action != EDL::Action::CUT &&
646         cut.action != EDL::Action::COMM_BREAK)
647       continue;
648 
649     float cutStart = cut.start * 100.0f / duration;
650     float cutEnd = cut.end * 100.0f / duration;
651     ranges.emplace_back(std::make_pair(cutStart, cutEnd));
652   }
653   return ranges;
654 }
655 
GetChapters(CDataCacheCore & data,time_t duration) const656 std::vector<std::pair<float, float>> CPlayerGUIInfo::GetChapters(CDataCacheCore& data, time_t duration) const
657 {
658   std::vector<std::pair<float, float>> ranges;
659 
660   const std::vector<std::pair<std::string, int64_t>> chapters = data.GetChapters();
661   float lastMarker = 0.0f;
662   for (const auto& chapter : chapters)
663   {
664     float marker = chapter.second * 1000 * 100.0f / duration;
665     if (marker != 0)
666       ranges.emplace_back(std::make_pair(lastMarker, marker));
667 
668     lastMarker = marker;
669   }
670   return ranges;
671 }
672