diff --git a/language/English/strings.po b/language/English/strings.po index 0e473bb9f3a09..795d596fc275e 100644 --- a/language/English/strings.po +++ b/language/English/strings.po @@ -12888,7 +12888,12 @@ msgctxt "#25009" msgid "The menu of this Blu-ray is not supported" msgstr "" -#empty strings from id 25010 to 29799 +#: xbmc/video/dialogs/GUIDialogVideoBookmarks.cpp +msgctxt "#25010" +msgid "Chapter %u" +msgstr "" + +#empty strings from id 25011 to 29799 #strings 29800 thru 29998 reserved strings used only in the default Project Mayhem III skin and not c++ code #: skin.confluence @@ -16312,7 +16317,19 @@ msgctxt "#37043" msgid "Defines the time to wait for subsequent key presses before performing the skip. Only applies when using smart skipping (when using more than one skip step for a direction)." msgstr "" -#empty strings from id 37044 to 38009 +#. Setting #37044 Settings -> Video -> File lists -> Extract chapter thumbnails +#: system/settings/settings.xml +msgctxt "#37044" +msgid "Extract chapter thumbnails" +msgstr "" + +#. Description of setting #37044 "Video -> File lists -> Extract chapter thumbnails" +#: system/settings/settings.xml +msgctxt "#37045" +msgid "Extract chapter thumbnails for presentation in the chapters/bookmarks dialog. This might increase CPU load." +msgstr "" + +#empty strings from id 37046 to 38009 #: system/settings/rbp.xml msgctxt "#38010" diff --git a/lib/libdvd/libdvdnav/src/dvdnav.c b/lib/libdvd/libdvdnav/src/dvdnav.c index 7b2ff892a4b67..b261b3e3590e8 100644 --- a/lib/libdvd/libdvdnav/src/dvdnav.c +++ b/lib/libdvd/libdvdnav/src/dvdnav.c @@ -1230,6 +1230,11 @@ int dvdnav_get_button_info(dvdnav_t* this, int alpha[2][4], int color[2][4]) return 0; } +void dvdnav_free(void* pdata) +{ + free(pdata); +} + #undef printerr #define printerr(str) strncpy(self->err_str, str, MAX_ERR_LEN); diff --git a/lib/libdvd/libdvdnav/src/dvdnav/dvdnav.h b/lib/libdvd/libdvdnav/src/dvdnav/dvdnav.h index bf6aae9d2a3ea..8b9d75ea2bdf7 100644 --- a/lib/libdvd/libdvdnav/src/dvdnav/dvdnav.h +++ b/lib/libdvd/libdvdnav/src/dvdnav/dvdnav.h @@ -697,6 +697,7 @@ int8_t dvdnav_is_domain_vtsm(dvdnav_t *self); */ int8_t dvdnav_is_domain_vts(dvdnav_t *self); +void dvdnav_free(void* pdata); #ifdef __cplusplus } diff --git a/lib/libdvd/patches/libdvdnav.diff b/lib/libdvd/patches/libdvdnav.diff index cb702a4b38de2..42bad876b0fb7 100644 --- a/lib/libdvd/patches/libdvdnav.diff +++ b/lib/libdvd/patches/libdvdnav.diff @@ -149,6 +149,16 @@ diff -uwr ../libdvdnav-4.2.1/src/dvdnav/dvdnav.h lib/libdvd/libdvdnav/src/dvdnav /* * Stop playing the current position and start playback of the title + * from the specified timecode. + * +@@ -695,6 +697,7 @@ + */ + int8_t dvdnav_is_domain_vts(dvdnav_t *self); + ++void dvdnav_free(void* pdata); + + #ifdef __cplusplus + } diff -uwr ../libdvdnav-4.2.1/src/dvdnav.c lib/libdvd/libdvdnav/src/dvdnav.c --- ../libdvdnav-4.2.1/src/dvdnav.c Thu Oct 3 23:39:38 2013 +++ lib/libdvd/libdvdnav/src/dvdnav.c Fri Feb 7 19:24:42 2014 @@ -284,6 +294,11 @@ diff -uwr ../libdvdnav-4.2.1/src/dvdnav.c lib/libdvd/libdvdnav/src/dvdnav.c + return 0; +} + ++void dvdnav_free(void* pdata) ++{ ++ free(pdata); ++} ++ +#undef printerr +#define printerr(str) strncpy(self->err_str, str, MAX_ERR_LEN); + diff --git a/system/settings/rbp.xml b/system/settings/rbp.xml index f572eedbfae23..bd3e2ad51f283 100644 --- a/system/settings/rbp.xml +++ b/system/settings/rbp.xml @@ -16,6 +16,13 @@ + + + + false + + +
diff --git a/system/settings/settings.xml b/system/settings/settings.xml index 3ece367d0bee1..0fbb920ec0b57 100644 --- a/system/settings/settings.xml +++ b/system/settings/settings.xml @@ -784,6 +784,11 @@ true + + 1 + true + + 1 true diff --git a/xbmc/ApplicationPlayer.cpp b/xbmc/ApplicationPlayer.cpp index 99d5f3f133501..ede084cbe1bc9 100644 --- a/xbmc/ApplicationPlayer.cpp +++ b/xbmc/ApplicationPlayer.cpp @@ -131,11 +131,21 @@ int CApplicationPlayer::GetChapterCount() return 0; } -void CApplicationPlayer::GetChapterName(std::string& strChapterName) +void CApplicationPlayer::GetChapterName(std::string& strChapterName, + int chapterIdx) { std::shared_ptr player = GetInternal(); if (player) - player->GetChapterName(strChapterName); + player->GetChapterName(strChapterName, chapterIdx); +} + +int64_t CApplicationPlayer::GetChapterPos(int chapterIdx) +{ + std::shared_ptr player = GetInternal(); + if (player) + return player->GetChapterPos(chapterIdx); + + return -1; } bool CApplicationPlayer::HasAudio() const diff --git a/xbmc/ApplicationPlayer.h b/xbmc/ApplicationPlayer.h index fdbd6cafa8ec4..36fce14bb670b 100644 --- a/xbmc/ApplicationPlayer.h +++ b/xbmc/ApplicationPlayer.h @@ -95,7 +95,8 @@ class CApplicationPlayer float GetCachePercentage() const; int GetChapterCount(); int GetChapter(); - void GetChapterName(std::string& strChapterName); + void GetChapterName(std::string& strChapterName, int chapterIdx=-1); + int64_t GetChapterPos(int chapterIdx=-1); void GetDeinterlaceMethods(std::vector &deinterlaceMethods); void GetDeinterlaceModes(std::vector &deinterlaceModes); void GetGeneralInfo(std::string& strVideoInfo); diff --git a/xbmc/cores/IPlayer.h b/xbmc/cores/IPlayer.h index e8b3dcbac66d7..f6a7d71b51bc0 100644 --- a/xbmc/cores/IPlayer.h +++ b/xbmc/cores/IPlayer.h @@ -183,7 +183,8 @@ class IPlayer virtual int GetChapterCount() { return 0; } virtual int GetChapter() { return -1; } - virtual void GetChapterName(std::string& strChapterName) { return; } + virtual void GetChapterName(std::string& strChapterName, int chapterIdx = -1) { return; } + virtual int64_t GetChapterPos(int chapterIdx=-1) { return 0; } virtual int SeekChapter(int iChapter) { return -1; } // virtual bool GetChapterInfo(int chapter, SChapterInfo &info) { return false; } diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemux.h b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemux.h index d69991ea5b02f..fca164d60184d 100644 --- a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemux.h +++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemux.h @@ -275,9 +275,17 @@ class CDVDDemux virtual int GetChapter() { return 0; } /* - * Get the name of the current chapter + * Get the name of a chapter + * \param strChapterName[out] Name of chapter + * \param chapterIdx -1 for current chapter, else a chapter index */ - virtual void GetChapterName(std::string& strChapterName) {} + virtual void GetChapterName(std::string& strChapterName, int chapterIdx=-1) {} + + /* + * Get the position of a chapter + * \param chapterIdx -1 for current chapter, else a chapter index + */ + virtual int64_t GetChapterPos(int chapterIdx=-1) { return 0; } /* * Set the playspeed, if demuxer can handle different diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp index 1315117125680..f58472f6b87a1 100644 --- a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp +++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp @@ -1401,14 +1401,15 @@ int CDVDDemuxFFmpeg::GetChapter() return 0; } -void CDVDDemuxFFmpeg::GetChapterName(std::string& strChapterName) +void CDVDDemuxFFmpeg::GetChapterName(std::string& strChapterName, int chapterIdx) { + if (chapterIdx <= 0 || chapterIdx > GetChapterCount()) + chapterIdx = GetChapter(); CDVDInputStream::IChapter* ich = dynamic_cast(m_pInput); if(ich) - ich->GetChapterName(strChapterName); + ich->GetChapterName(strChapterName, chapterIdx); else { - int chapterIdx = GetChapter(); if(chapterIdx <= 0) return; @@ -1419,6 +1420,20 @@ void CDVDDemuxFFmpeg::GetChapterName(std::string& strChapterName) } } +int64_t CDVDDemuxFFmpeg::GetChapterPos(int chapterIdx) +{ + if (chapterIdx <= 0 || chapterIdx > GetChapterCount()) + chapterIdx = GetChapter(); + if(chapterIdx <= 0) + return 0; + + CDVDInputStream::IChapter* ich = dynamic_cast(m_pInput); + if(ich) + return ich->GetChapterPos(chapterIdx); + + return m_pFormatContext->chapters[chapterIdx-1]->start*av_q2d(m_pFormatContext->chapters[chapterIdx-1]->time_base); +} + bool CDVDDemuxFFmpeg::SeekChapter(int chapter, double* startpts) { if(chapter < 1) @@ -1432,7 +1447,9 @@ bool CDVDDemuxFFmpeg::SeekChapter(int chapter, double* startpts) return false; if(startpts) - *startpts = DVD_NOPTS_VALUE; + { + *startpts = DVD_SEC_TO_TIME(ich->GetChapterPos(chapter)); + } Flush(); return true; diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h index bb64a2f2bfa6d..d180e40392e75 100644 --- a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h +++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h @@ -110,7 +110,8 @@ class CDVDDemuxFFmpeg : public CDVDDemux bool SeekChapter(int chapter, double* startpts = NULL); int GetChapterCount(); int GetChapter(); - void GetChapterName(std::string& strChapterName); + void GetChapterName(std::string& strChapterName, int chapterIdx=-1); + int64_t GetChapterPos(int chapterIdx=-1); virtual void GetStreamCodecName(int iStreamId, std::string &strName); bool Aborted(); diff --git a/xbmc/cores/dvdplayer/DVDFileInfo.cpp b/xbmc/cores/dvdplayer/DVDFileInfo.cpp index e05b6470fd2f0..1648d605f13b8 100644 --- a/xbmc/cores/dvdplayer/DVDFileInfo.cpp +++ b/xbmc/cores/dvdplayer/DVDFileInfo.cpp @@ -97,7 +97,7 @@ int DegreeToOrientation(int degrees) bool CDVDFileInfo::ExtractThumb(const std::string &strPath, CTextureDetails &details, - CStreamDetails *pStreamDetails) + CStreamDetails *pStreamDetails, int pos) { std::string redactPath = CURL::GetRedacted(strPath); unsigned int nTime = XbmcThreads::SystemClockMillis(); @@ -216,7 +216,7 @@ bool CDVDFileInfo::ExtractThumb(const std::string &strPath, if (pVideoCodec) { int nTotalLen = pDemuxer->GetStreamLength(); - int nSeekTo = nTotalLen / 3; + int nSeekTo = (pos==-1?nTotalLen / 3:pos); CLog::Log(LOGDEBUG,"%s - seeking to pos %dms (total: %dms) in %s", __FUNCTION__, nSeekTo, nTotalLen, redactPath.c_str()); if (pDemuxer->SeekTime(nSeekTo, true)) diff --git a/xbmc/cores/dvdplayer/DVDFileInfo.h b/xbmc/cores/dvdplayer/DVDFileInfo.h index 63491ebe6a05e..1afecaf65ae46 100644 --- a/xbmc/cores/dvdplayer/DVDFileInfo.h +++ b/xbmc/cores/dvdplayer/DVDFileInfo.h @@ -36,7 +36,7 @@ class CDVDFileInfo // Extract a thumbnail immage from the media at strPath, optionally populating a streamdetails class with the data static bool ExtractThumb(const std::string &strPath, CTextureDetails &details, - CStreamDetails *pStreamDetails); + CStreamDetails *pStreamDetails, int pos=-1); // Probe the files streams and store the info in the VideoInfoTag static bool GetFileStreamDetails(CFileItem *pItem); diff --git a/xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStream.h b/xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStream.h index 51a3849631147..11df1b804b0fd 100644 --- a/xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStream.h +++ b/xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStream.h @@ -101,7 +101,8 @@ class CDVDInputStream virtual ~IChapter() {}; virtual int GetChapter() = 0; virtual int GetChapterCount() = 0; - virtual void GetChapterName(std::string& name) = 0; + virtual void GetChapterName(std::string& name, int ch=-1) = 0; + virtual int64_t GetChapterPos(int ch=-1) = 0; virtual bool SeekChapter(int ch) = 0; }; diff --git a/xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStreamBluray.cpp b/xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStreamBluray.cpp index 2ef5f95d7fa87..61667bd7ee7f1 100644 --- a/xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStreamBluray.cpp +++ b/xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStreamBluray.cpp @@ -935,6 +935,17 @@ bool CDVDInputStreamBluray::SeekChapter(int ch) return true; } +int64_t CDVDInputStreamBluray::GetChapterPos(int ch) +{ + if (ch == -1 || ch > GetChapterCount()) + ch = GetChapter(); + + if (m_title && m_title->chapters) + return m_title->chapters[ch - 1].start / 90000; + else + return 0; +} + int64_t CDVDInputStreamBluray::Seek(int64_t offset, int whence) { #if LIBBLURAY_BYTESEEK diff --git a/xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStreamBluray.h b/xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStreamBluray.h index 1f5f9266520f2..1107ed2282db7 100644 --- a/xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStreamBluray.h +++ b/xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStreamBluray.h @@ -96,7 +96,8 @@ class CDVDInputStreamBluray int GetChapter(); int GetChapterCount(); - void GetChapterName(std::string& name) {}; + void GetChapterName(std::string& name, int ch=-1) {}; + int64_t GetChapterPos(int ch); bool SeekChapter(int ch); int GetTotalTime(); diff --git a/xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStreamNavigator.cpp b/xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStreamNavigator.cpp index 3fd9a0745816a..c7a6e4c159ff8 100644 --- a/xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStreamNavigator.cpp +++ b/xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStreamNavigator.cpp @@ -1455,3 +1455,26 @@ bool CDVDInputStreamNavigator::GetDVDSerialString(std::string& serialStr) serialStr.assign(str); return true; } + +int64_t CDVDInputStreamNavigator::GetChapterPos(int ch) +{ + if (ch == -1 || ch > GetChapterCount()) + ch = GetChapter(); + + if (ch <= 1) + return 0; + + uint64_t* times = NULL; + uint64_t duration; + + m_dll.dvdnav_describe_title_chapters(m_dvdnav, m_iTitle, ×, &duration); + + int64_t result = 0; + + if (times) + { + result = times[ch - 2] / 90000; + m_dll.dvdnav_free(times); + } + return result; +} diff --git a/xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStreamNavigator.h b/xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStreamNavigator.h index f9a6d0f6ee84e..d7e967cf21907 100644 --- a/xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStreamNavigator.h +++ b/xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStreamNavigator.h @@ -127,7 +127,8 @@ class CDVDInputStreamNavigator int GetChapter() { return m_iPart; } // the current part in the current title int GetChapterCount() { return m_iPartCount; } // the number of parts in the current title - void GetChapterName(std::string& name) {}; + void GetChapterName(std::string& name, int idx=-1) {}; + int64_t GetChapterPos(int ch=-1); bool SeekChapter(int iChapter); int GetTotalTime(); // the total time in milli seconds diff --git a/xbmc/cores/dvdplayer/DVDInputStreams/DllDvdNav.h b/xbmc/cores/dvdplayer/DVDInputStreams/DllDvdNav.h index ecacd978f344a..dcbf829cd840a 100644 --- a/xbmc/cores/dvdplayer/DVDInputStreams/DllDvdNav.h +++ b/xbmc/cores/dvdplayer/DVDInputStreams/DllDvdNav.h @@ -106,6 +106,8 @@ class DllDvdNavInterface virtual dvdnav_status_t dvdnav_mouse_select(dvdnav_t *self, pci_t *pci, int32_t x, int32_t y)=0; virtual dvdnav_status_t dvdnav_get_title_string(dvdnav_t *self, const char **title_str)=0; virtual dvdnav_status_t dvdnav_get_serial_string(dvdnav_t *self, const char **serial_str)=0; + virtual uint32_t dvdnav_describe_title_chapters(dvdnav_t* self, uint32_t title, uint64_t** times, uint64_t* duration)=0; + virtual void dvdnav_free(void* pdata) = 0; }; #if (defined USE_STATIC_LIBDVDNAV) @@ -231,6 +233,10 @@ class DllDvdNav : public DllDynamic, DllDvdNavInterface { return ::dvdnav_get_title_string(self, title_str); } virtual dvdnav_status_t dvdnav_get_serial_string(dvdnav_t *self, const char **serial_str) { return ::dvdnav_get_serial_string(self, serial_str); } + virtual uint32_t dvdnav_describe_title_chapters(dvdnav_t* self, uint32_t title, uint64_t** times, uint64_t* duration) + { return ::dvdnav_describe_title_chapters(self, title, times, duration); } + virtual void dvdnav_free(void* data) + { return ::dvdnav_free(data); } // DLL faking. virtual bool ResolveExports() { return true; } @@ -303,6 +309,8 @@ class DllDvdNav : public DllDynamic, DllDvdNavInterface DEFINE_METHOD4(dvdnav_status_t, dvdnav_mouse_select, (dvdnav_t *p1, pci_t *p2, int32_t p3, int32_t p4)) DEFINE_METHOD2(dvdnav_status_t, dvdnav_get_title_string, (dvdnav_t *p1, const char **p2)) DEFINE_METHOD2(dvdnav_status_t, dvdnav_get_serial_string, (dvdnav_t *p1, const char **p2)) + DEFINE_METHOD4(uint32_t, dvdnav_describe_title_chapters, (dvdnav_t* p1, uint32_t p2, uint64_t** p3, uint64_t* p4)) + DEFINE_METHOD1(void, dvdnav_free, (void *p1)) BEGIN_METHOD_RESOLVE() RESOLVE_METHOD(dvdnav_open) RESOLVE_METHOD(dvdnav_close) @@ -363,6 +371,8 @@ class DllDvdNav : public DllDynamic, DllDvdNavInterface RESOLVE_METHOD(dvdnav_mouse_select) RESOLVE_METHOD(dvdnav_get_title_string) RESOLVE_METHOD(dvdnav_get_serial_string) + RESOLVE_METHOD(dvdnav_describe_title_chapters) + RESOLVE_METHOD(dvdnav_free) END_METHOD_RESOLVE() }; diff --git a/xbmc/cores/dvdplayer/DVDPlayer.cpp b/xbmc/cores/dvdplayer/DVDPlayer.cpp index 9a1e4979a16d9..5e16230fda725 100644 --- a/xbmc/cores/dvdplayer/DVDPlayer.cpp +++ b/xbmc/cores/dvdplayer/DVDPlayer.cpp @@ -4078,7 +4078,7 @@ bool CDVDPlayer::SetPlayerState(const std::string& state) int CDVDPlayer::GetChapterCount() { CSingleLock lock(m_StateSection); - return m_State.chapter_count; + return m_State.chapters.size(); } int CDVDPlayer::GetChapter() @@ -4087,10 +4087,13 @@ int CDVDPlayer::GetChapter() return m_State.chapter; } -void CDVDPlayer::GetChapterName(std::string& strChapterName) +void CDVDPlayer::GetChapterName(std::string& strChapterName, int chapterIdx) { CSingleLock lock(m_StateSection); - strChapterName = m_State.chapter_name; + if (chapterIdx == -1 && m_State.chapter > 0 && m_State.chapter <= (int) m_State.chapters.size()) + strChapterName = m_State.chapters[m_State.chapter - 1].first; + else if (chapterIdx > 0 && chapterIdx <= (int) m_State.chapters.size()) + strChapterName = m_State.chapters[chapterIdx - 1].first; } int CDVDPlayer::SeekChapter(int iChapter) @@ -4110,6 +4113,15 @@ int CDVDPlayer::SeekChapter(int iChapter) return 0; } +int64_t CDVDPlayer::GetChapterPos(int chapterIdx) +{ + CSingleLock lock(m_StateSection); + if (chapterIdx > 0 && chapterIdx <= (int) m_StateInput.chapters.size()) + return m_State.chapters[chapterIdx - 1].second; + + return -1; +} + int CDVDPlayer::AddSubtitle(const std::string& strSubPath) { return AddSubtitleFile(strSubPath); @@ -4281,9 +4293,21 @@ void CDVDPlayer::UpdatePlayState(double timeout) if(m_pDemuxer) { - state.chapter = m_pDemuxer->GetChapter(); - state.chapter_count = m_pDemuxer->GetChapterCount(); - m_pDemuxer->GetChapterName(state.chapter_name); + if (IsInMenu()) + state.chapter = 0; + else + state.chapter = m_pDemuxer->GetChapter(); + + state.chapters.clear(); + if (m_pDemuxer->GetChapterCount() > 0) + { + for (int i = 0; i < m_pDemuxer->GetChapterCount(); ++i) + { + std::string name; + m_pDemuxer->GetChapterName(name, i + 1); + state.chapters.push_back(make_pair(name, m_pDemuxer->GetChapterPos(i + 1))); + } + } if(state.dts == DVD_NOPTS_VALUE) state.time = 0; diff --git a/xbmc/cores/dvdplayer/DVDPlayer.h b/xbmc/cores/dvdplayer/DVDPlayer.h index 8bcda49f39eb4..24d85fb4a1bec 100644 --- a/xbmc/cores/dvdplayer/DVDPlayer.h +++ b/xbmc/cores/dvdplayer/DVDPlayer.h @@ -266,7 +266,8 @@ class CDVDPlayer : public IPlayer, public CThread, public IDVDPlayer virtual int GetChapterCount(); virtual int GetChapter(); - virtual void GetChapterName(std::string& strChapterName); + virtual void GetChapterName(std::string& strChapterName, int chapterIdx=-1); + virtual int64_t GetChapterPos(int chapterIdx=-1); virtual int SeekChapter(int iChapter); virtual void SeekTime(int64_t iTime); @@ -479,8 +480,7 @@ class CDVDPlayer : public IPlayer, public CThread, public IDVDPlayer dts = DVD_NOPTS_VALUE; player_state = ""; chapter = 0; - chapter_name = ""; - chapter_count = 0; + chapters.clear(); canrecord = false; recording = false; canpause = false; @@ -505,9 +505,8 @@ class CDVDPlayer : public IPlayer, public CThread, public IDVDPlayer std::string player_state; // full player state - int chapter; // current chapter - std::string chapter_name; // name of current chapter - int chapter_count;// number of chapter + int chapter; // current chapter + std::vector> chapters; // name and position for chapters bool canrecord; // can input stream record bool recording; // are we currently recording diff --git a/xbmc/video/VideoThumbLoader.cpp b/xbmc/video/VideoThumbLoader.cpp index 196846632e68b..e01609d89772d 100644 --- a/xbmc/video/VideoThumbLoader.cpp +++ b/xbmc/video/VideoThumbLoader.cpp @@ -50,12 +50,16 @@ using namespace VIDEO; CThumbExtractor::CThumbExtractor(const CFileItem& item, const std::string& listpath, bool thumb, - const std::string& target) + const std::string& target, + int64_t pos, + bool fillStreamDetails) { m_listpath = listpath; m_target = target; m_thumb = thumb; m_item = item; + m_pos = pos; + m_fillStreamDetails = fillStreamDetails; if (item.IsVideoDb() && item.HasVideoInfoTag()) m_item.SetPath(item.GetVideoInfoTag()->m_strFileNameAndPath); @@ -73,7 +77,8 @@ bool CThumbExtractor::operator==(const CJob* job) const if (strcmp(job->GetType(),GetType()) == 0) { const CThumbExtractor* jobExtract = dynamic_cast(job); - if (jobExtract && jobExtract->m_listpath == m_listpath) + if (jobExtract && jobExtract->m_listpath == m_listpath + && jobExtract->m_target == m_target) return true; } return false; @@ -106,7 +111,7 @@ bool CThumbExtractor::DoWork() // construct the thumb cache file CTextureDetails details; details.file = CTextureCache::GetCacheFile(m_target) + ".jpg"; - result = CDVDFileInfo::ExtractThumb(m_item.GetPath(), details, &m_item.GetVideoInfoTag()->m_streamDetails); + result = CDVDFileInfo::ExtractThumb(m_item.GetPath(), details, m_fillStreamDetails ? &m_item.GetVideoInfoTag()->m_streamDetails : NULL, (int) m_pos); if(result) { CTextureCache::Get().AddCachedTexture(m_target, details); diff --git a/xbmc/video/VideoThumbLoader.h b/xbmc/video/VideoThumbLoader.h index 55560dad4eeb9..1ad97adfbd847 100644 --- a/xbmc/video/VideoThumbLoader.h +++ b/xbmc/video/VideoThumbLoader.h @@ -38,7 +38,7 @@ class CVideoDatabase; class CThumbExtractor : public CJob { public: - CThumbExtractor(const CFileItem& item, const std::string& listpath, bool thumb, const std::string& strTarget=""); + CThumbExtractor(const CFileItem& item, const std::string& listpath, bool thumb, const std::string& strTarget="", int64_t pos = -1, bool fillStreamDetails = true); virtual ~CThumbExtractor(); /*! @@ -57,6 +57,8 @@ class CThumbExtractor : public CJob std::string m_listpath; ///< path used in fileitem list CFileItem m_item; bool m_thumb; ///< extract thumb? + int64_t m_pos; ///< position to extract thumb from + bool m_fillStreamDetails; ///< fill in stream details? }; class CVideoThumbLoader : public CThumbLoader, public CJobQueue diff --git a/xbmc/video/dialogs/GUIDialogVideoBookmarks.cpp b/xbmc/video/dialogs/GUIDialogVideoBookmarks.cpp index 00139c834b60a..328974bcbcf0f 100644 --- a/xbmc/video/dialogs/GUIDialogVideoBookmarks.cpp +++ b/xbmc/video/dialogs/GUIDialogVideoBookmarks.cpp @@ -48,6 +48,11 @@ #include "utils/Variant.h" #include "Util.h" #include "cores/IPlayer.h" +#include "video/VideoThumbLoader.h" +#include "filesystem/File.h" +#include "TextureCache.h" +#include "ApplicationMessenger.h" +#include "settings/Settings.h" using namespace std; @@ -61,10 +66,12 @@ using namespace std; #define CONTROL_THUMBS 11 CGUIDialogVideoBookmarks::CGUIDialogVideoBookmarks() - : CGUIDialog(WINDOW_DIALOG_VIDEO_BOOKMARKS, "VideoOSDBookmarks.xml") + : CGUIDialog(WINDOW_DIALOG_VIDEO_BOOKMARKS, "VideoOSDBookmarks.xml"), + CJobQueue(false, 1, CJob::PRIORITY_NORMAL) { m_vecItems = new CFileItemList; - m_loadType = KEEP_IN_MEMORY; + m_loadType = LOAD_EVERY_TIME; + m_jobsStarted = 0; } CGUIDialogVideoBookmarks::~CGUIDialogVideoBookmarks() @@ -134,7 +141,17 @@ bool CGUIDialogVideoBookmarks::OnMessage(CGUIMessage& message) break; case GUI_MSG_REFRESH_LIST: { - OnRefreshList(); + switch (message.GetParam1()) + { + case 0: + OnRefreshList(); + break; + case 1: + UpdateItem(message.GetParam2()); + break; + default: + break; + } } break; } @@ -159,7 +176,7 @@ bool CGUIDialogVideoBookmarks::OnAction(const CAction &action) void CGUIDialogVideoBookmarks::OnPopupMenu(int item) { - if (item < 0 || item >= m_vecItems->Size()) + if (item < 0 || item >= (int) m_bookmarks.size()) return; // highlight the item @@ -199,25 +216,41 @@ void CGUIDialogVideoBookmarks::Delete(int item) Update(); } +void CGUIDialogVideoBookmarks::UpdateItem(unsigned int chapterIdx) +{ + CSingleLock lock(m_refreshSection); + int itemPos = ((chapterIdx - 1) + m_chapterOffset); + if (itemPos < m_vecItems->Size()) + { + std::string time = StringUtils::Format("chapter://%s/%i", m_filePath.c_str(), chapterIdx); + std::string cachefile = CTextureCache::Get().GetCachedPath(CTextureCache::Get().GetCacheFile(time) + ".jpg"); + if (XFILE::CFile::Exists(cachefile)) + { + (*m_vecItems)[itemPos]->SetArt("thumb", cachefile); + } + } +} + void CGUIDialogVideoBookmarks::OnRefreshList() { m_bookmarks.clear(); CBookmark resumemark; // open the d/b and retrieve the bookmarks for the current movie - std::string path = g_application.CurrentFile(); + m_filePath = g_application.CurrentFile(); if (g_application.CurrentFileItem().HasProperty("original_listitem_url") && !URIUtils::IsVideoDb(g_application.CurrentFileItem().GetProperty("original_listitem_url").asString())) - path = g_application.CurrentFileItem().GetProperty("original_listitem_url").asString(); + m_filePath = g_application.CurrentFileItem().GetProperty("original_listitem_url").asString(); CVideoDatabase videoDatabase; videoDatabase.Open(); - videoDatabase.GetBookMarksForFile(path, m_bookmarks); - videoDatabase.GetBookMarksForFile(path, m_bookmarks, CBookmark::EPISODE, true); + videoDatabase.GetBookMarksForFile(m_filePath, m_bookmarks); + videoDatabase.GetBookMarksForFile(m_filePath, m_bookmarks, CBookmark::EPISODE, true); /* push in the resume mark first */ - if( videoDatabase.GetResumeBookMark(path, resumemark) ) + if (videoDatabase.GetResumeBookMark(m_filePath, resumemark)) m_bookmarks.push_back(resumemark); videoDatabase.Close(); + CSingleLock lock(m_refreshSection); m_vecItems->Clear(); // cycle through each stored bookmark and add it to our list control for (unsigned int i = 0; i < m_bookmarks.size(); ++i) @@ -235,6 +268,34 @@ void CGUIDialogVideoBookmarks::OnRefreshList() item->SetArt("thumb", m_bookmarks[i].thumbNailImage); m_vecItems->Add(item); } + // add chapters if around + m_chapterOffset = m_vecItems->Size(); + for (int i=1;i<=g_application.m_pPlayer->GetChapterCount();++i) + { + std::string chapterName; + g_application.m_pPlayer->GetChapterName(chapterName, i); + if (chapterName.empty()) + chapterName = StringUtils::Format(g_localizeStrings.Get(25010).c_str(), i); + int64_t pos = g_application.m_pPlayer->GetChapterPos(i); + std::string time = + StringUtils::SecondsToTimeString((long) pos, TIME_FORMAT_HH_MM_SS); + std::string name = StringUtils::Format("%s (%s)", + chapterName.c_str(), time.c_str()); + CFileItemPtr item(new CFileItem(name)); + time = StringUtils::Format("chapter://%s/%i", m_filePath.c_str(), i); + std::string cachefile = CTextureCache::Get().GetCachedPath(CTextureCache::Get().GetCacheFile(time)+".jpg"); + if (XFILE::CFile::Exists(cachefile)) + item->SetArt("thumb", cachefile); + else if (i > m_jobsStarted && CSettings::Get().GetBool("myvideos.extractchapterthumbs")) + { + CFileItem item(m_filePath, false); + CJob* job = new CThumbExtractor(item, m_filePath, true, time, pos * 1000, false); + AddJob(job); + m_mapJobsChapter[job] = i; + m_jobsStarted++; + } + m_vecItems->Add(item); + } m_viewControl.SetItems(*m_vecItems); } @@ -284,11 +345,16 @@ void CGUIDialogVideoBookmarks::Clear() void CGUIDialogVideoBookmarks::GotoBookmark(int item) { - if (item < 0 || item >= (int)m_bookmarks.size()) return; + if (item < 0 || item >= (int)m_bookmarks.size()+g_application.m_pPlayer->GetChapterCount()) return; if (g_application.m_pPlayer->HasPlayer()) { - g_application.m_pPlayer->SetPlayerState(m_bookmarks[item].playerState); - g_application.SeekTime((double)m_bookmarks[item].timeInSeconds); + if (item < (int) m_bookmarks.size()) + { + g_application.m_pPlayer->SetPlayerState(m_bookmarks[item].playerState); + g_application.SeekTime((double)m_bookmarks[item].timeInSeconds); + } + else + g_application.m_pPlayer->SeekChapter(item-m_bookmarks.size()+1); } } @@ -387,10 +453,17 @@ void CGUIDialogVideoBookmarks::OnWindowLoaded() m_viewControl.Reset(); m_viewControl.SetParentWindow(GetID()); m_viewControl.AddView(GetControl(CONTROL_THUMBS)); + m_jobsStarted = 0; + m_mapJobsChapter.clear(); + m_vecItems->Clear(); } void CGUIDialogVideoBookmarks::OnWindowUnload() { + //stop running thumb extraction jobs + CancelJobs(); + m_mapJobsChapter.clear(); + m_vecItems->Clear(); CGUIDialog::OnWindowUnload(); m_viewControl.Reset(); } @@ -474,4 +547,19 @@ bool CGUIDialogVideoBookmarks::OnAddEpisodeBookmark() return bReturn; } - +void CGUIDialogVideoBookmarks::OnJobComplete(unsigned int jobID, + bool success, CJob* job) +{ + if (success && IsActive()) + { + MAPJOBSCHAPS::iterator iter = m_mapJobsChapter.find(job); + if (iter != m_mapJobsChapter.end()) + { + unsigned int chapterIdx = (*iter).second; + CGUIMessage m(GUI_MSG_REFRESH_LIST, GetID(), 0, 1, chapterIdx); + CApplicationMessenger::Get().SendGUIMessage(m); + m_mapJobsChapter.erase(iter); + } + } + CJobQueue::OnJobComplete(jobID, success, job); +} diff --git a/xbmc/video/dialogs/GUIDialogVideoBookmarks.h b/xbmc/video/dialogs/GUIDialogVideoBookmarks.h index 8d0e6213f2147..9bac80ff913ec 100644 --- a/xbmc/video/dialogs/GUIDialogVideoBookmarks.h +++ b/xbmc/video/dialogs/GUIDialogVideoBookmarks.h @@ -23,11 +23,14 @@ #include "guilib/GUIDialog.h" #include "view/GUIViewControl.h" #include "video/VideoDatabase.h" +#include "utils/JobManager.h" class CFileItemList; -class CGUIDialogVideoBookmarks : public CGUIDialog +class CGUIDialogVideoBookmarks : public CGUIDialog, public CJobQueue { + typedef std::map MAPJOBSCHAPS; + public: CGUIDialogVideoBookmarks(void); virtual ~CGUIDialogVideoBookmarks(void); @@ -69,7 +72,18 @@ class CGUIDialogVideoBookmarks : public CGUIDialog void OnPopupMenu(int item); CGUIControl *GetFirstFocusableControl(int id); + void OnJobComplete(unsigned int jobID, bool success, CJob* job); + CFileItemList* m_vecItems; CGUIViewControl m_viewControl; VECBOOKMARKS m_bookmarks; + +private: + void UpdateItem(unsigned int chapterIdx); + + int m_chapterOffset; + int m_jobsStarted; + std::string m_filePath; + CCriticalSection m_refreshSection; + MAPJOBSCHAPS m_mapJobsChapter; };