diff options
35 files changed, 348 insertions, 231 deletions
diff --git a/addons/skin.confluence/720p/ViewsFileMode.xml b/addons/skin.confluence/720p/ViewsFileMode.xml index 53bda87853..bc93810d14 100644 --- a/addons/skin.confluence/720p/ViewsFileMode.xml +++ b/addons/skin.confluence/720p/ViewsFileMode.xml @@ -68,19 +68,9 @@ <top>8</top> <width>40</width> <height>26</height> - <texture>$INFO[ListItem.VideoResolution,flagging/lists/,.png]</texture> + <texture>$VAR[MediaInfoOverlayVar]</texture> <aspectratio>keep</aspectratio> - <visible>Window.IsVisible(Videos) + [Container.Content(Movies) | Container.Content(Episodes) | Container.Content(MusicVideos)]</visible> - <visible>!ListItem.IsStereoscopic</visible> - </control> - <control type="image"> - <left>625</left> - <top>8</top> - <width>40</width> - <height>26</height> - <texture>flagging/lists/3D.png</texture> - <visible>Window.IsVisible(Videos) + [Container.Content(Movies) | Container.Content(Episodes) | Container.Content(MusicVideos)]</visible> - <visible>ListItem.IsStereoscopic</visible> + <visible>Window.IsVisible(Videos) + [Container.Content(Movies) | Container.Content(Sets) | Container.Content(Episodes) | Container.Content(MusicVideos)]</visible> </control> <control type="image"> <left>665</left> @@ -171,19 +161,9 @@ <top>8</top> <width>40</width> <height>26</height> - <texture>$INFO[ListItem.VideoResolution,flagging/lists/,.png]</texture> + <texture>$VAR[MediaInfoOverlayVar]</texture> <aspectratio>keep</aspectratio> - <visible>Window.IsVisible(Videos) + [Container.Content(Movies) | Container.Content(Episodes) | Container.Content(MusicVideos)]</visible> - <visible>!ListItem.IsStereoscopic</visible> - </control> - <control type="image"> - <left>625</left> - <top>8</top> - <width>40</width> - <height>26</height> - <texture>flagging/lists/3D.png</texture> - <visible>Window.IsVisible(Videos) + [Container.Content(Movies) | Container.Content(Episodes) | Container.Content(MusicVideos)]</visible> - <visible>ListItem.IsStereoscopic</visible> + <visible>Window.IsVisible(Videos) + [Container.Content(Movies) | Container.Content(Sets) | Container.Content(Episodes) | Container.Content(MusicVideos)]</visible> </control> <control type="image"> <left>665</left> @@ -588,19 +568,9 @@ <top>8</top> <width>40</width> <height>26</height> - <texture>$INFO[ListItem.VideoResolution,flagging/lists/,.png]</texture> + <texture>$VAR[MediaInfoOverlayVar]</texture> <aspectratio>keep</aspectratio> - <visible>Window.IsVisible(Videos) + [Container.Content(Movies) | Container.Content(Episodes) | Container.Content(MusicVideos)]</visible> - <visible>!ListItem.IsStereoscopic</visible> - </control> - <control type="image"> - <left>1010</left> - <top>8</top> - <width>40</width> - <height>26</height> - <texture>flagging/lists/3D.png</texture> - <visible>Window.IsVisible(Videos) + [Container.Content(Movies) | Container.Content(Episodes) | Container.Content(MusicVideos)]</visible> - <visible>ListItem.IsStereoscopic</visible> + <visible>Window.IsVisible(Videos) + [Container.Content(Movies) | Container.Content(Sets) | Container.Content(Episodes) | Container.Content(MusicVideos)]</visible> </control> <control type="image"> <left>1050</left> @@ -699,19 +669,9 @@ <top>8</top> <width>40</width> <height>26</height> - <texture>$INFO[ListItem.VideoResolution,flagging/lists/,.png]</texture> + <texture>$VAR[MediaInfoOverlayVar]</texture> <aspectratio>keep</aspectratio> - <visible>Window.IsVisible(Videos) + [Container.Content(Movies) | Container.Content(Episodes) | Container.Content(MusicVideos)]</visible> - <visible>!ListItem.IsStereoscopic</visible> - </control> - <control type="image"> - <left>1010</left> - <top>8</top> - <width>40</width> - <height>26</height> - <texture>flagging/lists/3D.png</texture> - <visible>Window.IsVisible(Videos) + [Container.Content(Movies) | Container.Content(Episodes) | Container.Content(MusicVideos)]</visible> - <visible>ListItem.IsStereoscopic</visible> + <visible>Window.IsVisible(Videos) + [Container.Content(Movies) | Container.Content(Sets) | Container.Content(Episodes) | Container.Content(MusicVideos)]</visible> </control> <control type="image"> <left>1050</left> diff --git a/addons/skin.confluence/720p/ViewsVideoLibrary.xml b/addons/skin.confluence/720p/ViewsVideoLibrary.xml index 3b173be113..eba09863b2 100644 --- a/addons/skin.confluence/720p/ViewsVideoLibrary.xml +++ b/addons/skin.confluence/720p/ViewsVideoLibrary.xml @@ -811,9 +811,9 @@ <top>8</top> <width>40</width> <height>26</height> - <texture>$VAR[ResolutionOverlayVar]</texture> + <texture>$VAR[MediaInfoOverlayVar]</texture> <aspectratio>keep</aspectratio> - <visible>Container.Content(Movies) | Container.Content(Episodes) | Container.Content(MusicVideos)</visible> + <visible>Container.Content(Movies) | Container.Content(Sets) | Container.Content(Episodes) | Container.Content(MusicVideos)</visible> </control> <control type="image"> <left>555</left> @@ -882,9 +882,9 @@ <top>8</top> <width>40</width> <height>26</height> - <texture>$VAR[ResolutionOverlayVar]</texture> + <texture>$VAR[MediaInfoOverlayVar]</texture> <aspectratio>keep</aspectratio> - <visible>Container.Content(Movies) | Container.Content(Episodes) | Container.Content(MusicVideos)</visible> + <visible>Container.Content(Movies) | Container.Content(Sets) | Container.Content(Episodes) | Container.Content(MusicVideos)</visible> </control> <control type="image"> <left>555</left> @@ -1227,9 +1227,9 @@ <top>8</top> <width>40</width> <height>26</height> - <texture>$VAR[ResolutionOverlayVar]</texture> + <texture>$VAR[MediaInfoOverlayVar]</texture> <aspectratio>keep</aspectratio> - <visible>Container.Content(Movies) | Container.Content(Episodes) | Container.Content(MusicVideos)</visible> + <visible>Container.Content(Movies) | Container.Content(Sets) | Container.Content(Episodes) | Container.Content(MusicVideos)</visible> </control> <control type="image"> <left>555</left> @@ -1298,9 +1298,9 @@ <top>8</top> <width>40</width> <height>26</height> - <texture>$VAR[ResolutionOverlayVar]</texture> + <texture>$VAR[MediaInfoOverlayVar]</texture> <aspectratio>keep</aspectratio> - <visible>Container.Content(Movies) | Container.Content(Episodes) | Container.Content(MusicVideos)</visible> + <visible>Container.Content(Movies) | Container.Content(Sets) | Container.Content(Episodes) | Container.Content(MusicVideos)</visible> </control> <control type="image"> <left>555</left> diff --git a/addons/skin.confluence/720p/includes.xml b/addons/skin.confluence/720p/includes.xml index 902fa4da24..c9e8a045dd 100644 --- a/addons/skin.confluence/720p/includes.xml +++ b/addons/skin.confluence/720p/includes.xml @@ -16,7 +16,8 @@ <include file="IncludesBackgroundBuilding.xml" /> <constant name="FanartCrossfadeTime">500</constant> <constant name="IconCrossfadeTime">400</constant> - <variable name="ResolutionOverlayVar"> + <variable name="MediaInfoOverlayVar"> + <value condition="ListItem.IsCollection">flagging/video/Set.png</value> <value condition="!ListItem.IsStereoscopic">$INFO[ListItem.VideoResolution,flagging/lists/,.png]</value> <value>flagging/lists/3D.png</value> </variable> @@ -68,11 +69,19 @@ <value condition="Player.Forwarding">$LOCALIZE[31044]</value> <value condition="Player.Rewinding">$LOCALIZE[31045]</value> </variable> + <variable name="PlayerControlsRepeatImageVar"> + <value condition="Playlist.IsRepeatOne + Control.HasFocus(604)">OSDRepeatOneFO.png</value> + <value condition="Playlist.IsRepeat + Control.HasFocus(604)">OSDRepeatAllFO.png</value> + <value condition="Control.HasFocus(604)">OSDRepeatFO.png</value> + <value condition="Playlist.IsRepeatOne">OSDRepeatOneNF.png</value> + <value condition="Playlist.IsRepeat">OSDRepeatAllNF.png</value> + <value>OSDRepeatNF.png</value> + </variable> <variable name="PVRChannelMgrHeader"> <value condition="!IsEmpty(Window.Property(IsRadio))">$LOCALIZE[19199] - $LOCALIZE[19024]</value> <value>$LOCALIZE[19199] - $LOCALIZE[19023]</value> </variable> - <include name="DialogBackgroundCommons"> + <include name="DialogBackgroundCommons"> <control type="image"> <description>background image</description> <left>0</left> @@ -897,54 +906,7 @@ <top>2</top> <width>39</width> <height>39</height> - <texture>OSDRepeatNF.png</texture> - <visible>!Playlist.IsRepeat + !Playlist.IsRepeatOne</visible> - <visible>!Control.HasFocus(604)</visible> - </control> - <control type="image"> - <left>165</left> - <top>2</top> - <width>39</width> - <height>39</height> - <texture>OSDRepeatFO.png</texture> - <visible>!Playlist.IsRepeat + !Playlist.IsRepeatOne</visible> - <visible>Control.HasFocus(604)</visible> - </control> - <control type="image"> - <left>165</left> - <top>2</top> - <width>39</width> - <height>39</height> - <texture>OSDRepeatOneNF.png</texture> - <visible>Playlist.IsRepeatOne</visible> - <visible>!Control.HasFocus(604)</visible> - </control> - <control type="image"> - <left>165</left> - <top>2</top> - <width>39</width> - <height>39</height> - <texture>OSDRepeatOneFO.png</texture> - <visible>Playlist.IsRepeatOne</visible> - <visible>Control.HasFocus(604)</visible> - </control> - <control type="image"> - <left>165</left> - <top>2</top> - <width>39</width> - <height>39</height> - <texture>OSDRepeatAllNF.png</texture> - <visible>Playlist.IsRepeat</visible> - <visible>!Control.HasFocus(604)</visible> - </control> - <control type="image"> - <left>165</left> - <top>2</top> - <width>39</width> - <height>39</height> - <texture>OSDRepeatAllFO.png</texture> - <visible>Playlist.IsRepeat</visible> - <visible>Control.HasFocus(604)</visible> + <texture>$VAR[PlayerControlsRepeatImageVar]</texture> </control> <control type="togglebutton" id="605"> <left>205</left> diff --git a/addons/skin.confluence/media/flagging/video/Set.png b/addons/skin.confluence/media/flagging/video/Set.png Binary files differnew file mode 100644 index 0000000000..fd8834fab2 --- /dev/null +++ b/addons/skin.confluence/media/flagging/video/Set.png diff --git a/project/BuildDependencies/scripts/0_package.list b/project/BuildDependencies/scripts/0_package.list index a1de1e25a8..ab64b4c94a 100644 --- a/project/BuildDependencies/scripts/0_package.list +++ b/project/BuildDependencies/scripts/0_package.list @@ -16,7 +16,7 @@ freetype-2.4.6-win32-3.7z giflib-5.0.5p-win32.7z gnutls-3.2.3-win32.zip jsonschemabuilder-1.0.0-win32-3.7z -libass-0.10.2-win32.7z +libass-0.12.1-win32.7z libbluray-0.4.0-win32.zip libcdio-0.83-win32-2.7z libcec-2.2.0-win32-1.7z diff --git a/project/cmake/addons/addons/pvr.iptvsimple/pvr.iptvsimple.txt b/project/cmake/addons/addons/pvr.iptvsimple/pvr.iptvsimple.txt index dd0ba6bdca..d1d4d3c2ce 100644 --- a/project/cmake/addons/addons/pvr.iptvsimple/pvr.iptvsimple.txt +++ b/project/cmake/addons/addons/pvr.iptvsimple/pvr.iptvsimple.txt @@ -1 +1 @@ -pvr.iptvsimple https://github.com/kodi-pvr/pvr.iptvsimple 38a72e5 +pvr.iptvsimple https://github.com/kodi-pvr/pvr.iptvsimple a2e6c6f diff --git a/system/settings/settings.xml b/system/settings/settings.xml index 921247ff58..323a2f14ac 100644 --- a/system/settings/settings.xml +++ b/system/settings/settings.xml @@ -2168,7 +2168,7 @@ </dependencies> <control type="toggle" /> </setting> - <setting id="services.upnpcontroller" type="boolean" label="21361" help="36326"> + <setting id="services.upnpcontroller" type="boolean" parent="services.upnpserver" label="21361" help="36326"> <level>1</level> <default>false</default> <dependencies> diff --git a/tools/depends/target/libass/Makefile b/tools/depends/target/libass/Makefile index 8df2cecc1f..5fba256894 100644 --- a/tools/depends/target/libass/Makefile +++ b/tools/depends/target/libass/Makefile @@ -3,7 +3,7 @@ DEPS= ../../Makefile.include Makefile # lib name, version LIBNAME=libass -VERSION=0.10.1 +VERSION=0.12.1 SOURCE=$(LIBNAME)-$(VERSION) ARCHIVE=$(SOURCE).tar.gz @@ -31,9 +31,9 @@ $(LIBDYLIB): $(PLATFORM) .installed-$(PLATFORM): $(LIBDYLIB) $(MAKE) -C $(PLATFORM) install ifeq ($(OS),android) - rm -f $(PREFIX)/lib/libass.la $(PREFIX)/lib/libass.so $(PREFIX)/lib/libass.so.4 - mv -f $(PREFIX)/lib/libass.so.4.1.0 $(PREFIX)/lib/libass.so - $(RPL) -e "libass.so.4" "libass.so\x00\x00" $(PREFIX)/lib/libass.so + rm -f $(PREFIX)/lib/libass.la $(PREFIX)/lib/libass.so $(PREFIX)/lib/libass.so.5 + mv -f $(PREFIX)/lib/libass.so.5.1.0 $(PREFIX)/lib/libass.so + $(RPL) -e "libass.so.5" "libass.so\x00\x00" $(PREFIX)/lib/libass.so -$(READELF) --dynamic $(PREFIX)/lib/libass.so | grep ibrary endif touch $@ diff --git a/xbmc/GUIInfoManager.cpp b/xbmc/GUIInfoManager.cpp index 208ca41a09..3f2e1cb426 100644 --- a/xbmc/GUIInfoManager.cpp +++ b/xbmc/GUIInfoManager.cpp @@ -567,6 +567,7 @@ const infomap listitem_labels[]= {{ "thumb", LISTITEM_THUMB }, { "isresumable", LISTITEM_IS_RESUMABLE}, { "percentplayed", LISTITEM_PERCENT_PLAYED}, { "isfolder", LISTITEM_IS_FOLDER }, + { "iscollection", LISTITEM_IS_COLLECTION }, { "originaltitle", LISTITEM_ORIGINALTITLE }, { "lastplayed", LISTITEM_LASTPLAYED }, { "playcount", LISTITEM_PLAYCOUNT }, @@ -5440,6 +5441,11 @@ bool CGUIInfoManager::GetItemBool(const CGUIListItem *item, int condition) const if (!stereoMode.empty() && stereoMode != "mono") return true; } + else if (condition == LISTITEM_IS_COLLECTION) + { + if (pItem->HasVideoInfoTag()) + return (pItem->GetVideoInfoTag()->m_type == MediaTypeVideoCollection); + } } return false; diff --git a/xbmc/GUIInfoManager.h b/xbmc/GUIInfoManager.h index fec4431661..f82fdf2386 100644 --- a/xbmc/GUIInfoManager.h +++ b/xbmc/GUIInfoManager.h @@ -663,6 +663,7 @@ namespace INFO #define LISTITEM_CHANNEL_NUMBER_LBL (LISTITEM_START + 145) #define LISTITEM_IMDBNUMBER (LISTITEM_START + 146) #define LISTITEM_EPISODENAME (LISTITEM_START + 147) +#define LISTITEM_IS_COLLECTION (LISTITEM_START + 148) #define LISTITEM_PROPERTY_START (LISTITEM_START + 200) #define LISTITEM_PROPERTY_END (LISTITEM_PROPERTY_START + 1000) diff --git a/xbmc/GUILargeTextureManager.cpp b/xbmc/GUILargeTextureManager.cpp index d7255a66de..cb94356ff7 100644 --- a/xbmc/GUILargeTextureManager.cpp +++ b/xbmc/GUILargeTextureManager.cpp @@ -57,27 +57,33 @@ bool CImageLoader::DoWork() else loadPath = texturePath; - if (m_use_cache && loadPath.empty()) - { - // not in our texture cache, so try and load directly and then cache the result - loadPath = CTextureCache::Get().CacheImage(texturePath, &m_texture); - if (m_texture) - return true; // we're done - } - if (!m_use_cache || !loadPath.empty()) + if (!loadPath.empty()) { // direct route - load the image unsigned int start = XbmcThreads::SystemClockMillis(); m_texture = CBaseTexture::LoadFromFile(loadPath, g_graphicsContext.GetWidth(), g_graphicsContext.GetHeight(), CSettings::Get().GetBool("pictures.useexifrotation")); - if (!m_texture) - return false; + if (XbmcThreads::SystemClockMillis() - start > 100) CLog::Log(LOGDEBUG, "%s - took %u ms to load %s", __FUNCTION__, XbmcThreads::SystemClockMillis() - start, loadPath.c_str()); - if (needsChecking) - CTextureCache::Get().BackgroundCacheImage(texturePath); + if (m_texture) + { + if (needsChecking) + CTextureCache::Get().BackgroundCacheImage(texturePath); + + return true; + } + + // Fallthrough on failure: + CLog::Log(LOGERROR, "%s - Direct texture file loading failed for %s", __FUNCTION__, loadPath.c_str()); } - return true; + + if (!m_use_cache) + return false; // We're done + + // not in our texture cache or it failed to load from it, so try and load directly and then cache the result + CTextureCache::Get().CacheImage(texturePath, &m_texture); + return (m_texture != NULL); } CGUILargeTextureManager::CLargeTexture::CLargeTexture(const std::string &path): @@ -241,6 +247,3 @@ void CGUILargeTextureManager::OnJobComplete(unsigned int jobID, bool success, CJ } } } - - - diff --git a/xbmc/TextureCache.cpp b/xbmc/TextureCache.cpp index 542183b9e1..44c20b74f7 100644 --- a/xbmc/TextureCache.cpp +++ b/xbmc/TextureCache.cpp @@ -133,16 +133,7 @@ void CTextureCache::BackgroundCacheImage(const std::string &url) AddJob(new CTextureCacheJob(CTextureUtils::UnwrapImageURL(url), details.hash)); } -bool CTextureCache::CacheImage(const std::string &image, CTextureDetails &details) -{ - std::string path = GetCachedImage(image, details); - if (path.empty()) // not cached - path = CacheImage(image, NULL, &details); - - return !path.empty(); -} - -std::string CTextureCache::CacheImage(const std::string &image, CBaseTexture **texture, CTextureDetails *details) +std::string CTextureCache::CacheImage(const std::string &image, CBaseTexture **texture /* = NULL */, CTextureDetails *details /* = NULL */) { std::string url = CTextureUtils::UnwrapImageURL(image); CSingleLock lock(m_processingSection); @@ -176,6 +167,15 @@ std::string CTextureCache::CacheImage(const std::string &image, CBaseTexture **t return GetCachedImage(url, *details, true); } +bool CTextureCache::CacheImage(const std::string &image, CTextureDetails &details) +{ + std::string path = GetCachedImage(image, details); + if (path.empty()) // not cached + path = CacheImage(image, NULL, &details); + + return !path.empty(); +} + void CTextureCache::ClearCachedImage(const std::string &url, bool deleteSource /*= false */) { // TODO: This can be removed when the texture cache covers everything. diff --git a/xbmc/TextureCache.h b/xbmc/TextureCache.h index f35c56c7c9..549d565f7c 100644 --- a/xbmc/TextureCache.h +++ b/xbmc/TextureCache.h @@ -92,7 +92,7 @@ public: \return cached url of this image \sa CTextureCacheJob::CacheTexture */ - std::string CacheImage(const std::string &url, CBaseTexture **texture = NULL, CTextureDetails *details = NULL); + std::string CacheImage(const std::string &image, CBaseTexture **texture = NULL, CTextureDetails *details = NULL); /*! \brief Cache an image to image cache if not already cached, returning the image details. \param image url of the image to cache. diff --git a/xbmc/cores/VideoRenderers/BaseRenderer.cpp b/xbmc/cores/VideoRenderers/BaseRenderer.cpp index 751a61bd02..4345c0fb13 100644 --- a/xbmc/cores/VideoRenderers/BaseRenderer.cpp +++ b/xbmc/cores/VideoRenderers/BaseRenderer.cpp @@ -306,10 +306,11 @@ float CBaseRenderer::GetAspectRatio() const return m_sourceFrameRatio * width / height * m_sourceHeight / m_sourceWidth; } -void CBaseRenderer::GetVideoRect(CRect &source, CRect &dest) +void CBaseRenderer::GetVideoRect(CRect &source, CRect &dest, CRect &view) { source = m_sourceRect; dest = m_destRect; + view = m_viewRect; } inline void CBaseRenderer::ReorderDrawPoints() @@ -567,7 +568,7 @@ void CBaseRenderer::CalculateFrameAspectRatio(unsigned int desired_width, unsign void CBaseRenderer::ManageDisplay() { - const CRect view = g_graphicsContext.GetViewWindow(); + m_viewRect = g_graphicsContext.GetViewWindow(); m_sourceRect.x1 = 0.0f; m_sourceRect.y1 = 0.0f; @@ -614,7 +615,7 @@ void CBaseRenderer::ManageDisplay() break; } - CalcNormalDisplayRect(view.x1, view.y1, view.Width(), view.Height(), GetAspectRatio() * CDisplaySettings::Get().GetPixelRatio(), CDisplaySettings::Get().GetZoomAmount(), CDisplaySettings::Get().GetVerticalShift()); + CalcNormalDisplayRect(m_viewRect.x1, m_viewRect.y1, m_viewRect.Width(), m_viewRect.Height(), GetAspectRatio() * CDisplaySettings::Get().GetPixelRatio(), CDisplaySettings::Get().GetZoomAmount(), CDisplaySettings::Get().GetVerticalShift()); } void CBaseRenderer::SetViewMode(int viewMode) diff --git a/xbmc/cores/VideoRenderers/BaseRenderer.h b/xbmc/cores/VideoRenderers/BaseRenderer.h index 8988e352d2..389695ac30 100644 --- a/xbmc/cores/VideoRenderers/BaseRenderer.h +++ b/xbmc/cores/VideoRenderers/BaseRenderer.h @@ -80,7 +80,13 @@ public: void SetViewMode(int viewMode); RESOLUTION GetResolution() const; - void GetVideoRect(CRect &source, CRect &dest); +
+ /*! \brief Get video rectangle and view window
+ \param source is original size of the video
+ \param dest is the target rendering area honoring aspect ratio of source
+ \param view is the entire target rendering area for the video (including black bars)
+ */
+ void GetVideoRect(CRect &source, CRect &dest, CRect &view); float GetAspectRatio() const; virtual bool AddVideoPicture(DVDVideoPicture* picture, int index) { return false; } @@ -139,6 +145,7 @@ protected: CRect m_destRect; CRect m_oldDestRect; // destrect of the previous frame CRect m_sourceRect; + CRect m_viewRect; // rendering flags unsigned m_iFlags; diff --git a/xbmc/cores/VideoRenderers/OverlayRenderer.cpp b/xbmc/cores/VideoRenderers/OverlayRenderer.cpp index e8c4bec535..866992ffa8 100644 --- a/xbmc/cores/VideoRenderers/OverlayRenderer.cpp +++ b/xbmc/cores/VideoRenderers/OverlayRenderer.cpp @@ -220,8 +220,7 @@ void CRenderer::Render(COverlay* o, float adjust_height) { CRect rs, rd, rv; RESOLUTION_INFO res; - g_renderManager.GetVideoRect(rs, rd); - rv = g_graphicsContext.GetViewWindow(); + g_renderManager.GetVideoRect(rs, rd, rv); res = g_graphicsContext.GetResInfo(g_renderManager.GetResolution()); SRenderState state; @@ -326,14 +325,40 @@ bool CRenderer::HasOverlay(int idx) COverlay* CRenderer::Convert(CDVDOverlaySSA* o, double pts) { - CRect src, dst; - g_renderManager.GetVideoRect(src, dst); - - int width = MathUtils::round_int(dst.Width()); - int height = MathUtils::round_int(dst.Height()); - + // libass render in a target area which named as frame. the frame size may bigger than video size, + // and including margins between video to frame edge. libass allow to render subtitles into the margins.
+ // this has been used to show subtitles in the top or bottom "black bar" between video to frame border.
+ CRect src, dst, target; + g_renderManager.GetVideoRect(src, dst, target); + int videoWidth = MathUtils::round_int(dst.Width()); + int videoHeight = MathUtils::round_int(dst.Height()); + int targetWidth = MathUtils::round_int(target.Width()); + int targetHeight = MathUtils::round_int(target.Height()); + int useMargin; + + int subalign = CSettings::Get().GetInt("subtitles.align"); + if(subalign == SUBTITLE_ALIGN_BOTTOM_OUTSIDE + || subalign == SUBTITLE_ALIGN_TOP_OUTSIDE + || subalign == SUBTITLE_ALIGN_MANUAL) + useMargin = 1; + else + useMargin = 0; + double position; + // position used to call ass_set_line_position, it's vertical line position of subtitles in percent. + // value is 0-100: 0 = on the bottom (default), 100 = on top. + if(subalign == SUBTITLE_ALIGN_TOP_INSIDE + || subalign == SUBTITLE_ALIGN_TOP_OUTSIDE) + position = 100.0; + else if (subalign == SUBTITLE_ALIGN_MANUAL) + { + RESOLUTION_INFO res; + res = g_graphicsContext.GetResInfo(g_renderManager.GetResolution()); + position = 100.0 - (res.iSubtitles - res.Overscan.top) * 100 / res.iHeight; + } + else + position = 0.0; int changes = 0; - ASS_Image* images = o->m_libass->RenderImage(width, height, pts, &changes); + ASS_Image* images = o->m_libass->RenderImage(targetWidth, targetHeight, videoWidth, videoHeight, pts, useMargin, position, &changes); if(o->m_overlay) { @@ -341,12 +366,21 @@ COverlay* CRenderer::Convert(CDVDOverlaySSA* o, double pts) return o->m_overlay->Acquire(); } + COverlay *overlay = NULL; #if defined(HAS_GL) || defined(HAS_GLES) - return new COverlayGlyphGL(images, width, height); + overlay = new COverlayGlyphGL(images, targetWidth, targetHeight); #elif defined(HAS_DX) - return new COverlayQuadsDX(images, width, height); + overlay = new COverlayQuadsDX(images, targetWidth, targetHeight); #endif - return NULL; + // scale to video dimensions + if (overlay) + { + overlay->m_width = (float)targetWidth / videoWidth; + overlay->m_height = (float)targetHeight / videoHeight; + overlay->m_x = ((float)videoWidth - targetWidth) / 2 / videoWidth; + overlay->m_y = ((float)videoHeight - targetHeight) / 2 / videoHeight; + } + return overlay; } diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp index cfef46ccf9..25323ef43c 100644 --- a/xbmc/cores/VideoRenderers/RenderManager.cpp +++ b/xbmc/cores/VideoRenderers/RenderManager.cpp @@ -129,11 +129,11 @@ CXBMCRenderManager::~CXBMCRenderManager() m_pRenderer = NULL; } -void CXBMCRenderManager::GetVideoRect(CRect &source, CRect &dest) +void CXBMCRenderManager::GetVideoRect(CRect &source, CRect &dest, CRect &view) { CSharedLock lock(m_sharedSection); if (m_pRenderer) - m_pRenderer->GetVideoRect(source, dest); + m_pRenderer->GetVideoRect(source, dest, view); } float CXBMCRenderManager::GetAspectRatio() diff --git a/xbmc/cores/VideoRenderers/RenderManager.h b/xbmc/cores/VideoRenderers/RenderManager.h index b5ceb799ba..f32f4a9fd4 100644 --- a/xbmc/cores/VideoRenderers/RenderManager.h +++ b/xbmc/cores/VideoRenderers/RenderManager.h @@ -54,7 +54,7 @@ public: ~CXBMCRenderManager(); // Functions called from the GUI - void GetVideoRect(CRect &source, CRect &dest); + void GetVideoRect(CRect &source, CRect &dest, CRect &view); float GetAspectRatio(); void Update(); void FrameMove(); diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Overlay/DVDOverlayCodecFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Overlay/DVDOverlayCodecFFmpeg.cpp index 354a0f1dbd..113c9fd68c 100644 --- a/xbmc/cores/dvdplayer/DVDCodecs/Overlay/DVDOverlayCodecFFmpeg.cpp +++ b/xbmc/cores/dvdplayer/DVDCodecs/Overlay/DVDOverlayCodecFFmpeg.cpp @@ -27,7 +27,6 @@ #include "utils/log.h" #include "utils/EndianSwap.h" #include "guilib/GraphicContext.h" -#include "xbmc/rendering/RenderSystem.h" CDVDOverlayCodecFFmpeg::CDVDOverlayCodecFFmpeg() : CDVDOverlayCodec("FFmpeg Subtitle Decoder") { diff --git a/xbmc/cores/dvdplayer/DVDOverlayRenderer.cpp b/xbmc/cores/dvdplayer/DVDOverlayRenderer.cpp index 34506c9f6e..0a20cc273f 100644 --- a/xbmc/cores/dvdplayer/DVDOverlayRenderer.cpp +++ b/xbmc/cores/dvdplayer/DVDOverlayRenderer.cpp @@ -71,7 +71,7 @@ void CDVDOverlayRenderer::Render(DVDPictureRenderer* pPicture, CDVDOverlaySSA* p height = pPicture->height; width = pPicture->width; - ASS_Image* img = pOverlay->m_libass->RenderImage(width, height, pts); + ASS_Image* img = pOverlay->m_libass->RenderImage(width, height, width, height, pts); int depth = OVERLAY::GetStereoscopicDepth(); diff --git a/xbmc/cores/dvdplayer/DVDPlayer.cpp b/xbmc/cores/dvdplayer/DVDPlayer.cpp index 82b59d2080..ab7816c26b 100644 --- a/xbmc/cores/dvdplayer/DVDPlayer.cpp +++ b/xbmc/cores/dvdplayer/DVDPlayer.cpp @@ -3924,8 +3924,8 @@ bool CDVDPlayer::OnAction(const CAction &action) case ACTION_MOUSE_MOVE: case ACTION_MOUSE_LEFT_CLICK: { - CRect rs, rd; - m_dvdPlayerVideo->GetVideoRect(rs, rd); + CRect rs, rd, rv; + m_dvdPlayerVideo->GetVideoRect(rs, rd, rv); CPoint pt(action.GetAmount(), action.GetAmount(1)); if (!rd.PtInRect(pt)) return false; // out of bounds @@ -4162,7 +4162,8 @@ void CDVDPlayer::GetVideoStreamInfo(SPlayerVideoStreamInfo &info) } info.videoCodecName = retVal; info.videoAspectRatio = m_dvdPlayerVideo->GetAspectRatio(); - m_dvdPlayerVideo->GetVideoRect(info.SrcRect, info.DestRect); + CRect viewRect; + m_dvdPlayerVideo->GetVideoRect(info.SrcRect, info.DestRect, viewRect); info.stereoMode = m_dvdPlayerVideo->GetStereoMode(); if (info.stereoMode == "mono") info.stereoMode = ""; diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.h b/xbmc/cores/dvdplayer/DVDPlayerVideo.h index ead6f70798..3dfba89a46 100644 --- a/xbmc/cores/dvdplayer/DVDPlayerVideo.h +++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.h @@ -84,7 +84,7 @@ public: void EnableFullscreen(bool bEnable) { m_bAllowFullscreen = bEnable; } #ifdef HAS_VIDEO_PLAYBACK - void GetVideoRect(CRect& SrcRect, CRect& DestRect) const { g_renderManager.GetVideoRect(SrcRect, DestRect); } + void GetVideoRect(CRect& SrcRect, CRect& DestRect, CRect& ViewRect) const { g_renderManager.GetVideoRect(SrcRect, DestRect, ViewRect); } float GetAspectRatio() { return g_renderManager.GetAspectRatio(); } #endif diff --git a/xbmc/cores/dvdplayer/DVDSubtitles/DVDSubtitlesLibass.cpp b/xbmc/cores/dvdplayer/DVDSubtitles/DVDSubtitlesLibass.cpp index 6890c264df..0b5b050bbd 100644 --- a/xbmc/cores/dvdplayer/DVDSubtitles/DVDSubtitlesLibass.cpp +++ b/xbmc/cores/dvdplayer/DVDSubtitles/DVDSubtitlesLibass.cpp @@ -154,7 +154,7 @@ bool CDVDSubtitlesLibass::CreateTrack(char* buf, size_t size) return true; } -ASS_Image* CDVDSubtitlesLibass::RenderImage(int imageWidth, int imageHeight, double pts, int *changes) +ASS_Image* CDVDSubtitlesLibass::RenderImage(int frameWidth, int frameHeight, int videoWidth, int videoHeight, double pts, int useMargin, double position, int *changes) { CSingleLock lock(m_section); if(!m_renderer || !m_track) @@ -163,8 +163,13 @@ ASS_Image* CDVDSubtitlesLibass::RenderImage(int imageWidth, int imageHeight, dou return NULL; } - double storage_aspact = (double)imageWidth / imageHeight; - m_dll.ass_set_frame_size(m_renderer, imageWidth, imageHeight); + double storage_aspact = (double)frameWidth / frameHeight; + m_dll.ass_set_frame_size(m_renderer, frameWidth, frameHeight); + int topmargin = (frameHeight - videoHeight) / 2; + int leftmargin = (frameWidth - videoWidth) / 2; + m_dll.ass_set_margins(m_renderer, topmargin, topmargin, leftmargin, leftmargin); + m_dll.ass_set_use_margins(m_renderer, useMargin); + m_dll.ass_set_line_position(m_renderer, position); m_dll.ass_set_aspect_ratio(m_renderer, storage_aspact / g_graphicsContext.GetResInfo().fPixelRatio, storage_aspact); return m_dll.ass_render_frame(m_renderer, m_track, DVD_TIME_TO_MSEC(pts), changes); } diff --git a/xbmc/cores/dvdplayer/DVDSubtitles/DVDSubtitlesLibass.h b/xbmc/cores/dvdplayer/DVDSubtitles/DVDSubtitlesLibass.h index ee30436184..b9129928ad 100644 --- a/xbmc/cores/dvdplayer/DVDSubtitles/DVDSubtitlesLibass.h +++ b/xbmc/cores/dvdplayer/DVDSubtitles/DVDSubtitlesLibass.h @@ -32,7 +32,7 @@ public: CDVDSubtitlesLibass(); virtual ~CDVDSubtitlesLibass(); - ASS_Image* RenderImage(int imageWidth, int imageHeight, double pts, int* changes = NULL); + ASS_Image* RenderImage(int frameWidth, int frameHeight, int videoWidth, int videoHeight, double pts, int useMargin = 0, double position = 0.0, int* changes = NULL); ASS_Event* GetEvents(); int GetNrOfEvents(); diff --git a/xbmc/cores/dvdplayer/DVDSubtitles/DllLibass.h b/xbmc/cores/dvdplayer/DVDSubtitles/DllLibass.h index 6e30ea4cbe..78716e61b5 100644 --- a/xbmc/cores/dvdplayer/DVDSubtitles/DllLibass.h +++ b/xbmc/cores/dvdplayer/DVDSubtitles/DllLibass.h @@ -49,6 +49,7 @@ public: virtual void ass_set_aspect_ratio(ASS_Renderer* priv, double dar, double sar)=0; virtual void ass_set_margins(ASS_Renderer* priv, int t, int b, int l, int r)=0; virtual void ass_set_use_margins(ASS_Renderer* priv, int use)=0; + virtual void ass_set_line_position(ASS_Renderer* priv, double line_position)=0; virtual void ass_set_font_scale(ASS_Renderer* priv, double font_scale)=0; virtual ASS_Image* ass_render_frame(ASS_Renderer *priv, ASS_Track* track, long long now, int* detect_change)=0; virtual ASS_Track* ass_new_track(ASS_Library*)=0; @@ -77,6 +78,7 @@ class DllLibass : public DllDynamic, DllLibassInterface DEFINE_METHOD3(void, ass_set_aspect_ratio, (ASS_Renderer * p1, double p2, double p3)) DEFINE_METHOD5(void, ass_set_margins, (ASS_Renderer * p1, int p2, int p3, int p4, int p5)) DEFINE_METHOD2(void, ass_set_use_margins, (ASS_Renderer * p1, int p2)) + DEFINE_METHOD2(void, ass_set_line_position, (ASS_Renderer * p1, double p2)) DEFINE_METHOD2(void, ass_set_font_scale, (ASS_Renderer * p1, double p2)) DEFINE_METHOD4(ASS_Image *, ass_render_frame, (ASS_Renderer * p1, ASS_Track * p2, long long p3, int * p4)) DEFINE_METHOD1(ASS_Track *, ass_new_track, (ASS_Library * p1)) @@ -99,6 +101,7 @@ class DllLibass : public DllDynamic, DllLibassInterface RESOLVE_METHOD(ass_set_aspect_ratio) RESOLVE_METHOD(ass_set_margins) RESOLVE_METHOD(ass_set_use_margins) + RESOLVE_METHOD(ass_set_line_position) RESOLVE_METHOD(ass_set_font_scale) RESOLVE_METHOD(ass_render_frame) RESOLVE_METHOD(ass_new_track) diff --git a/xbmc/cores/dvdplayer/IDVDPlayer.h b/xbmc/cores/dvdplayer/IDVDPlayer.h index cd8abfdc78..bbf76e06f9 100644 --- a/xbmc/cores/dvdplayer/IDVDPlayer.h +++ b/xbmc/cores/dvdplayer/IDVDPlayer.h @@ -69,7 +69,7 @@ public: virtual bool IsSubtitleEnabled() = 0; virtual void EnableFullscreen(bool bEnable) = 0; #ifdef HAS_VIDEO_PLAYBACK - virtual void GetVideoRect(CRect& SrcRect, CRect& DestRect) const = 0; + virtual void GetVideoRect(CRect& SrcRect, CRect& DestRect, CRect& ViewRect) const = 0; virtual float GetAspectRatio() = 0; #endif virtual double GetDelay() = 0; diff --git a/xbmc/cores/omxplayer/OMXPlayerVideo.h b/xbmc/cores/omxplayer/OMXPlayerVideo.h index 7908ee57a2..3d0c13e162 100644 --- a/xbmc/cores/omxplayer/OMXPlayerVideo.h +++ b/xbmc/cores/omxplayer/OMXPlayerVideo.h @@ -124,7 +124,7 @@ public: void SetFlags(unsigned flags) { m_flags = flags; }; int GetFreeSpace(); void SetVideoRect(const CRect &SrcRect, const CRect &DestRect); - void GetVideoRect(CRect& SrcRect, CRect& DestRect) const { g_renderManager.GetVideoRect(SrcRect, DestRect); } + void GetVideoRect(CRect& SrcRect, CRect& DestRect, CRect& ViewRect) const { g_renderManager.GetVideoRect(SrcRect, DestRect, ViewRect); } static void RenderUpdateCallBack(const void *ctx, const CRect &SrcRect, const CRect &DestRect); void ResolutionUpdateCallBack(uint32_t width, uint32_t height, float framerate, float pixel_aspect); static void ResolutionUpdateCallBack(void *ctx, uint32_t width, uint32_t height, float framerate, float pixel_aspect); diff --git a/xbmc/input/linux/LIRC.cpp b/xbmc/input/linux/LIRC.cpp index f0693f0f3b..e19a00fc42 100644 --- a/xbmc/input/linux/LIRC.cpp +++ b/xbmc/input/linux/LIRC.cpp @@ -36,6 +36,7 @@ #include "utils/log.h" #include "settings/AdvancedSettings.h" #include "utils/TimeUtils.h" +#include "threads/SingleLock.h" CRemoteControl::CRemoteControl() : CThread("RemoteControl") @@ -46,10 +47,10 @@ CRemoteControl::CRemoteControl() , m_holdTime(0) , m_button(0) , m_bInitialized(false) - , m_used(true) - , m_deviceName(LIRC_DEVICE) , m_inReply(false) , m_nrSending(0) + , m_used(true) + , m_deviceName(LIRC_DEVICE) { } @@ -74,6 +75,9 @@ void CRemoteControl::Reset() void CRemoteControl::Disconnect() { + CSingleLock lock(m_CS); + //make sure that any new function calls abort directly + m_bInitialized = false; m_event.Set(); if (IsRunning()) @@ -81,7 +85,6 @@ void CRemoteControl::Disconnect() if (m_fd != -1) { - m_bInitialized = false; if (m_file != NULL) fclose(m_file); if (m_fd != -1) @@ -113,6 +116,11 @@ void CRemoteControl::SetDeviceName(const std::string& value) void CRemoteControl::Initialize() { + //Create must not be called twice, make sure to lock before + //check IsRunning() so that any other thread will block until + //we know IsRunning is true and will not call Create again + CSingleLock lock(m_CS); + if (m_bInitialized || !m_used || IsRunning()) return; @@ -121,6 +129,13 @@ void CRemoteControl::Initialize() void CRemoteControl::Process() { struct sockaddr_un addr; + if (m_deviceName.length() >= sizeof(addr.sun_path)) + { + CLog::Log(LOGERROR, "LIRC %s: device name is too long(%ud), maximum is %d", + __FUNCTION__, m_deviceName.length(), sizeof(addr.sun_path)); + return; + } + addr.sun_family = AF_UNIX; strcpy(addr.sun_path, m_deviceName.c_str()); @@ -134,7 +149,10 @@ void CRemoteControl::Process() while (!m_bStop && iAttempt <= 60) { if (Connect(addr, iAttempt == 0)) + { + m_bInitialized = true; break; + } if (iAttempt == 0) CLog::Log(LOGINFO, "CRemoteControl::Process - failed to connect to LIRC, will keep retrying every %d seconds", iMsRetryDelay / 1000); @@ -152,6 +170,9 @@ void CRemoteControl::Process() } bool CRemoteControl::CheckDevice() { + if (!m_bInitialized || !m_used) + return false; + #ifdef HAVE_INOTIFY if (m_inotify_fd < 0 || m_inotify_wd < 0) return true; // inotify wasn't setup for some reason, assume all is well @@ -181,11 +202,18 @@ void CRemoteControl::Update() uint32_t now = XbmcThreads::SystemClockMillis(); + char buf[128]; // Read a line from the socket - while (fgets(m_buf, sizeof(m_buf), m_file) != NULL) + while (true) { + { + CSingleLock lock(m_CS); + if (fgets(buf, sizeof(buf), m_file) == NULL) + break; + } + // Remove the \n - m_buf[strlen(m_buf)-1] = '\0'; + buf[strlen(buf)-1] = '\0'; // Parse the result. Sample line: // 000000037ff07bdd 00 OK mceusb @@ -193,7 +221,7 @@ void CRemoteControl::Update() char buttonName[128]; char repeatStr[4]; char deviceName[128]; - sscanf(m_buf, "%s %s %s %s", &scanCode[0], &repeatStr[0], &buttonName[0], &deviceName[0]); + sscanf(buf, "%s %s %s %s", &scanCode[0], &repeatStr[0], &buttonName[0], &deviceName[0]); //beginning of lirc reply packet //we get one when lirc is done sending something @@ -232,7 +260,7 @@ void CRemoteControl::Update() CLog::Log(LOGERROR, "LIRC: invalid non-numeric character in expression %s", repeatStr); if (repeat == 0) { - CLog::Log(LOGDEBUG, "LIRC: %s - NEW at %d:%s (%s)", __FUNCTION__, now, m_buf, buttonName); + CLog::Log(LOGDEBUG, "LIRC: %s - NEW at %d:%s (%s)", __FUNCTION__, now, buf, buttonName); m_firstClickTime = now; m_holdTime = 0; return; @@ -250,6 +278,8 @@ void CRemoteControl::Update() //drop commands when already sending //because keypresses come in faster than lirc can send we risk hammering the daemon with commands + CSingleLock lock(m_CS); + if (m_nrSending > 0) { m_sendData.clear(); @@ -268,7 +298,10 @@ void CRemoteControl::Update() } if (feof(m_file) != 0) + { + CSingleExit ex(m_CS); //Disconnect takes the lock Disconnect(); + } } WORD CRemoteControl::GetButton() @@ -286,12 +319,15 @@ void CRemoteControl::AddSendCommand(const std::string& command) if (!m_bInitialized || !m_used) return; + CSingleLock lock(m_CS); + m_sendData += command; m_sendData += '\n'; } bool CRemoteControl::Connect(struct sockaddr_un addr, bool logMessages) { + bool bResult = false; // Open the socket from which we will receive the remote commands if ((m_fd = socket(AF_UNIX, SOCK_STREAM, 0)) != -1) { @@ -320,7 +356,7 @@ bool CRemoteControl::Connect(struct sockaddr_un addr, bool logMessages) // Set an inotify watch on the lirc device if ((m_inotify_wd = inotify_add_watch(m_inotify_fd, m_deviceName.c_str(), IN_DELETE_SELF)) != -1) { - m_bInitialized = true; + bResult = true; CLog::Log(LOGINFO, "LIRC %s: successfully started", __FUNCTION__); } else @@ -329,7 +365,7 @@ bool CRemoteControl::Connect(struct sockaddr_un addr, bool logMessages) } } #else - m_bInitialized = true; + bResult = true; CLog::Log(LOGINFO, "LIRC %s: successfully started", __FUNCTION__); #endif } @@ -348,7 +384,7 @@ bool CRemoteControl::Connect(struct sockaddr_un addr, bool logMessages) else if (logMessages) CLog::Log(LOGINFO, "LIRC %s: socket failed: %s", __FUNCTION__, strerror(errno)); - return m_bInitialized; + return bResult; } #endif diff --git a/xbmc/input/linux/LIRC.h b/xbmc/input/linux/LIRC.h index 2e8bdc5512..5fd872381f 100644 --- a/xbmc/input/linux/LIRC.h +++ b/xbmc/input/linux/LIRC.h @@ -22,6 +22,7 @@ #define LIRC_H #include <string> +#include <atomic> #include "system.h" #include "threads/Thread.h" @@ -59,16 +60,19 @@ private: FILE* m_file; unsigned int m_holdTime; int32_t m_button; - char m_buf[128]; - bool m_bInitialized; + + std::atomic<bool> m_bInitialized; + std::atomic<bool> m_inReply; + std::atomic<int> m_nrSending; + bool m_used; uint32_t m_firstClickTime; std::string m_deviceName; bool CheckDevice(); std::string m_sendData; - bool m_inReply; - int m_nrSending; CEvent m_event; + CCriticalSection m_CS; + }; #endif diff --git a/xbmc/interfaces/json-rpc/PlayerOperations.cpp b/xbmc/interfaces/json-rpc/PlayerOperations.cpp index 181fd80145..80d885ea4d 100644 --- a/xbmc/interfaces/json-rpc/PlayerOperations.cpp +++ b/xbmc/interfaces/json-rpc/PlayerOperations.cpp @@ -1033,10 +1033,10 @@ int CPlayerOperations::GetActivePlayers() PlayerType CPlayerOperations::GetPlayer(const CVariant &player) { - int activePlayers = GetActivePlayers(); - int playerID; + int iPlayer = (int)player.asInteger(); + PlayerType playerID; - switch ((int)player.asInteger()) + switch (iPlayer) { case PLAYLIST_VIDEO: playerID = Video; @@ -1051,38 +1051,35 @@ PlayerType CPlayerOperations::GetPlayer(const CVariant &player) break; default: - playerID = PlayerImplicit; + playerID = None; break; } - int choosenPlayer = playerID & activePlayers; - - // Implicit order - if (choosenPlayer & Video) - return Video; - else if (choosenPlayer & Audio) - return Audio; - else if (choosenPlayer & Picture) - return Picture; + if (GetPlaylist(playerID) == iPlayer) + return playerID; else return None; } int CPlayerOperations::GetPlaylist(PlayerType player) { + int playlist = g_playlistPlayer.GetCurrentPlaylist(); + if (playlist == PLAYLIST_NONE) // No active playlist, try guessing + playlist = g_application.m_pPlayer->GetPreferredPlaylist(); + switch (player) { case Video: - return PLAYLIST_VIDEO; + return playlist == PLAYLIST_NONE ? PLAYLIST_VIDEO : playlist; case Audio: - return PLAYLIST_MUSIC; + return playlist == PLAYLIST_NONE ? PLAYLIST_MUSIC : playlist; case Picture: return PLAYLIST_PICTURE; default: - return PLAYLIST_NONE; + return playlist; } } @@ -1292,7 +1289,7 @@ JSONRPC_STATUS CPlayerOperations::GetPropertyValue(PlayerType player, const std: switch (player) { case Video: - case Audio: + case Audio: /* Return the position of current item if there is an active playlist */ if (!IsPVRChannel() && g_playlistPlayer.GetCurrentPlaylist() == playlist) result = g_playlistPlayer.GetCurrentSong(); else diff --git a/xbmc/network/NetworkServices.cpp b/xbmc/network/NetworkServices.cpp index 5dab3d1d37..a09078b535 100644 --- a/xbmc/network/NetworkServices.cpp +++ b/xbmc/network/NetworkServices.cpp @@ -279,9 +279,11 @@ bool CNetworkServices::OnSettingChanging(const CSetting *setting) if (!StartUPnPServer()) return false; - // always stop and restart the client if necessary + // always stop and restart the client and controller if necessary StopUPnPClient(); + StopUPnPController(); StartUPnPClient(); + StartUPnPController(); } else return StopUPnPServer(); @@ -296,9 +298,9 @@ bool CNetworkServices::OnSettingChanging(const CSetting *setting) else if (settingId == "services.upnpcontroller") { // always stop and restart - StopUPnPClient(); + StopUPnPController(); if (((CSettingBool*)setting)->GetValue()) - return StartUPnPClient(); + return StartUPnPController(); } else #endif // HAS_UPNP @@ -799,6 +801,7 @@ bool CNetworkServices::StartUPnP() #ifdef HAS_UPNP ret |= StartUPnPClient(); ret |= StartUPnPServer(); + ret |= StartUPnPController(); ret |= StartUPnPRenderer(); #endif // HAS_UPNP return ret; @@ -821,11 +824,7 @@ bool CNetworkServices::StopUPnP(bool bWait) bool CNetworkServices::StartUPnPClient() { #ifdef HAS_UPNP - if (!CSettings::Get().GetBool("services.upnpcontroller") || - !CSettings::Get().GetBool("services.upnpserver")) - return false; - - CLog::Log(LOGNOTICE, "starting upnp controller"); + CLog::Log(LOGNOTICE, "starting upnp client"); CUPnP::GetInstance()->StartClient(); return IsUPnPClientRunning(); #endif // HAS_UPNP @@ -843,7 +842,7 @@ bool CNetworkServices::IsUPnPClientRunning() bool CNetworkServices::StopUPnPClient() { #ifdef HAS_UPNP - if (!IsUPnPRendererRunning()) + if (!IsUPnPClientRunning()) return true; CLog::Log(LOGNOTICE, "stopping upnp client"); @@ -854,6 +853,42 @@ bool CNetworkServices::StopUPnPClient() return false; } +bool CNetworkServices::StartUPnPController() +{ +#ifdef HAS_UPNP + if (!CSettings::Get().GetBool("services.upnpcontroller") || + !CSettings::Get().GetBool("services.upnpserver")) + return false; + + CLog::Log(LOGNOTICE, "starting upnp controller"); + CUPnP::GetInstance()->StartController(); + return IsUPnPControllerRunning(); +#endif // HAS_UPNP + return false; +} + +bool CNetworkServices::IsUPnPControllerRunning() +{ +#ifdef HAS_UPNP + return CUPnP::GetInstance()->IsControllerStarted(); +#endif // HAS_UPNP + return false; +} + +bool CNetworkServices::StopUPnPController() +{ +#ifdef HAS_UPNP + if (!IsUPnPControllerRunning()) + return true; + + CLog::Log(LOGNOTICE, "stopping upnp controller"); + CUPnP::GetInstance()->StopController(); + + return true; +#endif // HAS_UPNP + return false; +} + bool CNetworkServices::StartUPnPRenderer() { #ifdef HAS_UPNP @@ -911,10 +946,10 @@ bool CNetworkServices::IsUPnPServerRunning() bool CNetworkServices::StopUPnPServer() { #ifdef HAS_UPNP - if (!IsUPnPRendererRunning()) + if (!IsUPnPServerRunning()) return true; - StopUPnPClient(); + StopUPnPController(); CLog::Log(LOGNOTICE, "stopping upnp server"); CUPnP::GetInstance()->StopServer(); diff --git a/xbmc/network/NetworkServices.h b/xbmc/network/NetworkServices.h index 5e1e628099..8612ecd53b 100644 --- a/xbmc/network/NetworkServices.h +++ b/xbmc/network/NetworkServices.h @@ -76,6 +76,9 @@ public: bool StartUPnPClient(); bool IsUPnPClientRunning(); bool StopUPnPClient(); + bool StartUPnPController(); + bool IsUPnPControllerRunning(); + bool StopUPnPController(); bool StartUPnPRenderer(); bool IsUPnPRendererRunning(); bool StopUPnPRenderer(); diff --git a/xbmc/network/upnp/UPnP.cpp b/xbmc/network/upnp/UPnP.cpp index 05ba0111d5..23b1ebdf31 100644 --- a/xbmc/network/upnp/UPnP.cpp +++ b/xbmc/network/upnp/UPnP.cpp @@ -448,6 +448,7 @@ CUPnP::~CUPnP() { m_UPnP->Stop(); StopClient(); + StopController(); StopServer(); delete m_UPnP; @@ -492,7 +493,7 @@ CUPnP::ReleaseInstance(bool bWait) } /*---------------------------------------------------------------------- -| CUPnP::StartServer +| CUPnP::GetServer +---------------------------------------------------------------------*/ CUPnPServer* CUPnP::GetServer() { @@ -530,27 +531,47 @@ CUPnP::SaveFileState(const CFileItem& item, const CBookmark& bookmark, const boo } /*---------------------------------------------------------------------- -| CUPnP::StartClient +| CUPnP::CreateControlPoint +---------------------------------------------------------------------*/ void -CUPnP::StartClient() +CUPnP::CreateControlPoint() { - if (!m_CtrlPointHolder->m_CtrlPoint.IsNull()) return; + if (!m_CtrlPointHolder->m_CtrlPoint.IsNull()) + return; // create controlpoint m_CtrlPointHolder->m_CtrlPoint = new PLT_CtrlPoint(); // start it m_UPnP->AddCtrlPoint(m_CtrlPointHolder->m_CtrlPoint); +} + +/*---------------------------------------------------------------------- +| CUPnP::DestroyControlPoint ++---------------------------------------------------------------------*/ +void +CUPnP::DestroyControlPoint() +{ + if (m_CtrlPointHolder->m_CtrlPoint.IsNull()) + return; + + m_UPnP->RemoveCtrlPoint(m_CtrlPointHolder->m_CtrlPoint); + m_CtrlPointHolder->m_CtrlPoint = NULL; +} + +/*---------------------------------------------------------------------- +| CUPnP::StartClient ++---------------------------------------------------------------------*/ +void +CUPnP::StartClient() +{ + if (m_MediaBrowser != NULL) + return; + + CreateControlPoint(); // start browser m_MediaBrowser = new CMediaBrowser(m_CtrlPointHolder->m_CtrlPoint); - - // start controller - if (CSettings::Get().GetBool("services.upnpcontroller") && - CSettings::Get().GetBool("services.upnpserver")) { - m_MediaController = new CMediaController(m_CtrlPointHolder->m_CtrlPoint); - } } /*---------------------------------------------------------------------- @@ -559,15 +580,44 @@ CUPnP::StartClient() void CUPnP::StopClient() { - if (m_CtrlPointHolder->m_CtrlPoint.IsNull()) return; - - m_UPnP->RemoveCtrlPoint(m_CtrlPointHolder->m_CtrlPoint); - m_CtrlPointHolder->m_CtrlPoint = NULL; + if (m_MediaBrowser == NULL) + return; delete m_MediaBrowser; m_MediaBrowser = NULL; - delete m_MediaController; - m_MediaController = NULL; + + if (!IsControllerStarted()) + DestroyControlPoint(); +} + +/*---------------------------------------------------------------------- +| CUPnP::StartController ++---------------------------------------------------------------------*/ +void +CUPnP::StartController() +{ + if (m_MediaController != NULL) + return; + + CreateControlPoint(); + + m_MediaController = new CMediaController(m_CtrlPointHolder->m_CtrlPoint); +} + +/*---------------------------------------------------------------------- +| CUPnP::StopController ++---------------------------------------------------------------------*/ +void +CUPnP::StopController() +{ + if (m_MediaController == NULL) + return; + + delete m_MediaController; + m_MediaController = NULL; + + if (!IsClientStarted()) + DestroyControlPoint(); } /*---------------------------------------------------------------------- diff --git a/xbmc/network/upnp/UPnP.h b/xbmc/network/upnp/UPnP.h index 56c91b0a7b..69c4e94afe 100644 --- a/xbmc/network/upnp/UPnP.h +++ b/xbmc/network/upnp/UPnP.h @@ -58,6 +58,11 @@ public: void StopClient(); bool IsClientStarted() { return (m_MediaBrowser != NULL); } + // controller + void StartController(); + void StopController(); + bool IsControllerStarted() { return (m_MediaController != NULL); } + // renderer bool StartRenderer(); void StopRenderer(); @@ -79,6 +84,9 @@ public: static void RegisterUserdata(void* ptr); static void UnregisterUserdata(void* ptr); private: + void CreateControlPoint(); + void DestroyControlPoint(); + // methods CUPnPRenderer* CreateRenderer(int port = 0); CUPnPServer* CreateServer(int port = 0); diff --git a/xbmc/pvr/dialogs/GUIDialogPVRChannelManager.cpp b/xbmc/pvr/dialogs/GUIDialogPVRChannelManager.cpp index 25292e7292..ab2be2b91b 100644 --- a/xbmc/pvr/dialogs/GUIDialogPVRChannelManager.cpp +++ b/xbmc/pvr/dialogs/GUIDialogPVRChannelManager.cpp @@ -769,12 +769,14 @@ void CGUIDialogPVRChannelManager::SaveList(void) CPVRChannelGroupPtr group = g_PVRChannelGroups->GetGroupAll(m_bIsRadio); if (!group) return; + for (int iListPtr = 0; iListPtr < m_channelItems->Size(); iListPtr++) { - if (!m_channelItems->HasPVRChannelInfoTag()) + CFileItemPtr pItem = m_channelItems->Get(iListPtr); + + if (!pItem->HasPVRChannelInfoTag()) continue; - CFileItemPtr pItem = m_channelItems->Get(iListPtr); if (pItem->GetProperty("SupportsSettings").asBoolean()) RenameChannel(pItem); |