aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--addons/resource.language.en_gb/resources/strings.po2
-rw-r--r--addons/screensaver.xbmc.builtin.dim/addon.xml2
-rw-r--r--addons/skin.estouchy/addon.xml2
-rw-r--r--addons/skin.estouchy/language/resource.language.he_il/strings.po4
-rw-r--r--addons/skin.estouchy/language/resource.language.it_it/strings.po4
-rw-r--r--addons/skin.estouchy/xml/ViewsList.xml12
-rw-r--r--addons/skin.estouchy/xml/ViewsThumbnail.xml73
-rw-r--r--addons/skin.estuary/addon.xml4
-rw-r--r--addons/skin.estuary/language/resource.language.he_il/strings.po16
-rw-r--r--addons/skin.estuary/language/resource.language.ja_jp/strings.po2
-rw-r--r--addons/skin.estuary/xml/SkinSettings.xml4
-rw-r--r--cmake/installdata/test-reference-data.txt1
-rw-r--r--cmake/scripts/osx/ArchSetup.cmake2
-rw-r--r--media/splash.jpgbin821747 -> 821899 bytes
-rw-r--r--project/BuildDependencies/scripts/get_formed.cmd2
-rw-r--r--system/playercorefactory.xml2
-rw-r--r--tools/depends/target/Toolchain.cmake.in5
-rw-r--r--tools/depends/target/Toolchain_binaddons.cmake.in5
-rw-r--r--tools/depends/target/gnutls/02-darwin-getentropy.patch13
-rw-r--r--tools/depends/target/gnutls/Makefile11
-rw-r--r--tools/depends/target/gnutls/add-dl-as-private-lib.patch26
-rw-r--r--tools/depends/target/gnutls/remove-weak_import-check-for-osx.patch17
-rw-r--r--tools/depends/target/nettle/Makefile2
-rw-r--r--version.txt6
-rw-r--r--xbmc/CMakeLists.txt1
-rw-r--r--xbmc/FileItem.cpp69
-rw-r--r--xbmc/FileItem.h9
-rw-r--r--xbmc/GUIPassword.cpp160
-rw-r--r--xbmc/GUIPassword.h24
-rw-r--r--xbmc/LockType.h2
-rw-r--r--xbmc/MediaSource.cpp10
-rw-r--r--xbmc/MediaSource.h8
-rw-r--r--xbmc/TextureCache.cpp28
-rw-r--r--xbmc/addons/Addon.cpp2
-rw-r--r--xbmc/addons/binary-addons/AddonDll.cpp7
-rw-r--r--xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/Inputstream.h104
-rw-r--r--xbmc/addons/kodi-addon-dev-kit/include/kodi/versions.h2
-rw-r--r--xbmc/cores/AudioEngine/Sinks/AESinkAUDIOTRACK.cpp16
-rw-r--r--xbmc/cores/AudioEngine/Sinks/AESinkAUDIOTRACK.h1
-rw-r--r--xbmc/cores/RetroPlayer/rendering/VideoRenderers/RPRendererGuiTexture.cpp2
-rw-r--r--xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.cpp320
-rw-r--r--xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.h55
-rw-r--r--xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp1
-rw-r--r--xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp8
-rw-r--r--xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.h3
-rw-r--r--xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxVobsub.cpp2
-rw-r--r--xbmc/cores/VideoPlayer/DVDDemuxers/DVDFactoryDemuxer.cpp16
-rw-r--r--xbmc/cores/VideoPlayer/DVDFileInfo.cpp8
-rw-r--r--xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStream.h1
-rw-r--r--xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamBluray.cpp34
-rw-r--r--xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamBluray.h2
-rw-r--r--xbmc/cores/VideoPlayer/DVDInputStreams/InputStreamAddon.cpp54
-rw-r--r--xbmc/cores/VideoPlayer/DVDInputStreams/InputStreamAddon.h21
-rw-r--r--xbmc/cores/VideoPlayer/DVDSubtitles/DVDSubtitleParserSami.cpp2
-rw-r--r--xbmc/cores/VideoPlayer/DVDSubtitles/DVDSubtitleTagSami.cpp7
-rw-r--r--xbmc/cores/VideoPlayer/VideoPlayer.cpp34
-rw-r--r--xbmc/cores/playercorefactory/PlayerSelectionRule.cpp3
-rw-r--r--xbmc/cores/playercorefactory/PlayerSelectionRule.h1
-rw-r--r--xbmc/dbwrappers/Database.cpp6
-rw-r--r--xbmc/dbwrappers/Database.h1
-rw-r--r--xbmc/dialogs/GUIDialogContextMenu.cpp55
-rw-r--r--xbmc/dialogs/GUIDialogKaiToast.cpp28
-rw-r--r--xbmc/favourites/GUIDialogFavourites.cpp5
-rw-r--r--xbmc/filesystem/CurlFile.cpp7
-rw-r--r--xbmc/filesystem/FileDirectoryFactory.cpp12
-rw-r--r--xbmc/filesystem/SourcesDirectory.cpp17
-rw-r--r--xbmc/filesystem/ZipFile.cpp41
-rw-r--r--xbmc/filesystem/ZipManager.h1
-rw-r--r--xbmc/filesystem/test/TestZipFile.cpp24
-rw-r--r--xbmc/filesystem/test/extendedlocalheader.zipbin0 -> 15352 bytes
-rw-r--r--xbmc/games/windows/GUIWindowGames.cpp27
-rw-r--r--xbmc/guilib/GUIFadeLabelControl.cpp12
-rw-r--r--xbmc/guilib/GUIFadeLabelControl.h3
-rw-r--r--xbmc/guilib/GUIWindowManager.cpp11
-rw-r--r--xbmc/input/InputManager.cpp6
-rw-r--r--xbmc/interfaces/json-rpc/FileOperations.cpp16
-rw-r--r--xbmc/interfaces/legacy/ModuleXbmc.cpp6
-rw-r--r--xbmc/media/CMakeLists.txt3
-rw-r--r--xbmc/media/MediaLockState.h16
-rw-r--r--xbmc/music/MusicDatabase.cpp29
-rw-r--r--xbmc/music/windows/GUIWindowMusicBase.cpp9
-rw-r--r--xbmc/network/httprequesthandler/HTTPVfsHandler.cpp21
-rw-r--r--xbmc/pictures/GUIWindowPictures.cpp34
-rw-r--r--xbmc/pictures/SlideShowPicture.cpp2
-rw-r--r--xbmc/platform/android/activity/XBMCApp.cpp14
-rw-r--r--xbmc/platform/darwin/ios/IOSEAGLView.mm3
-rw-r--r--xbmc/platform/darwin/ios/IOSScreenManager.mm1
-rw-r--r--xbmc/platform/darwin/ios/XBMCController.h2
-rw-r--r--xbmc/platform/darwin/ios/XBMCController.mm44
-rw-r--r--xbmc/playlists/PlayListXML.cpp14
-rw-r--r--xbmc/profiles/ProfileManager.cpp18
-rw-r--r--xbmc/profiles/ProfileManager.h1
-rw-r--r--xbmc/profiles/dialogs/GUIDialogProfileSettings.cpp2
-rw-r--r--xbmc/programs/GUIWindowPrograms.cpp16
-rw-r--r--xbmc/pvr/PVRGUIInfo.cpp6
-rw-r--r--xbmc/pvr/epg/EpgContainer.cpp24
-rw-r--r--xbmc/settings/MediaSourceSettings.cpp18
-rw-r--r--xbmc/utils/FileUtils.cpp29
-rw-r--r--xbmc/utils/LangCodeExpander.cpp21
-rw-r--r--xbmc/utils/Mime.cpp16
-rw-r--r--xbmc/utils/URIUtils.cpp8
-rw-r--r--xbmc/utils/URIUtils.h1
-rw-r--r--xbmc/video/VideoInfoTag.cpp5
-rw-r--r--xbmc/video/tags/VideoTagLoaderNFO.cpp2
-rw-r--r--xbmc/video/windows/GUIWindowVideoNav.cpp5
-rw-r--r--xbmc/windowing/GraphicContext.cpp10
-rw-r--r--xbmc/windowing/Resolution.cpp15
-rw-r--r--xbmc/windowing/Resolution.h12
-rw-r--r--xbmc/windowing/android/WinSystemAndroid.cpp2
109 files changed, 1156 insertions, 759 deletions
diff --git a/addons/resource.language.en_gb/resources/strings.po b/addons/resource.language.en_gb/resources/strings.po
index 07a6646614..03b5894ef4 100644
--- a/addons/resource.language.en_gb/resources/strings.po
+++ b/addons/resource.language.en_gb/resources/strings.po
@@ -5753,7 +5753,7 @@ msgstr ""
#: xbmc/dialogs/GUIDialogGamepad.cpp
#: xbmc/dialogs/GUIDialogNumeric.cpp
msgctxt "#12343"
-msgid "retries left "
+msgid "retries left"
msgstr ""
#: xbmc/dialogs/GUIDialogGamepad.cpp
diff --git a/addons/screensaver.xbmc.builtin.dim/addon.xml b/addons/screensaver.xbmc.builtin.dim/addon.xml
index 32aa209a94..212906fb71 100644
--- a/addons/screensaver.xbmc.builtin.dim/addon.xml
+++ b/addons/screensaver.xbmc.builtin.dim/addon.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<addon id="screensaver.xbmc.builtin.dim"
name="Dim"
- version="1.0.58"
+ version="1.0.59"
provider-name="Team Kodi">
<extension point="xbmc.ui.screensaver" library=""/>
<extension point="xbmc.addon.metadata">
diff --git a/addons/skin.estouchy/addon.xml b/addons/skin.estouchy/addon.xml
index 90b49b37c0..3ae257f0b2 100644
--- a/addons/skin.estouchy/addon.xml
+++ b/addons/skin.estouchy/addon.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<addon id="skin.estouchy" version="2.0.27" name="Estouchy" provider-name="Team Kodi">
+<addon id="skin.estouchy" version="2.0.28" name="Estouchy" provider-name="Team Kodi">
<requires>
<import addon="xbmc.gui" version="5.14.0"/>
</requires>
diff --git a/addons/skin.estouchy/language/resource.language.he_il/strings.po b/addons/skin.estouchy/language/resource.language.he_il/strings.po
index fee3d132cf..bc894eb120 100644
--- a/addons/skin.estouchy/language/resource.language.he_il/strings.po
+++ b/addons/skin.estouchy/language/resource.language.he_il/strings.po
@@ -56,6 +56,10 @@ msgctxt "#31014"
msgid "Episodes"
msgstr "פרקים"
+msgctxt "#31015"
+msgid "Player info"
+msgstr "פרטי הנגן"
+
msgctxt "#31016"
msgid "Albums"
msgstr "אלבומים"
diff --git a/addons/skin.estouchy/language/resource.language.it_it/strings.po b/addons/skin.estouchy/language/resource.language.it_it/strings.po
index 83a9129347..7ae241c6f2 100644
--- a/addons/skin.estouchy/language/resource.language.it_it/strings.po
+++ b/addons/skin.estouchy/language/resource.language.it_it/strings.po
@@ -56,6 +56,10 @@ msgctxt "#31014"
msgid "Episodes"
msgstr "Episodi"
+msgctxt "#31015"
+msgid "Player info"
+msgstr "Informazioni player"
+
msgctxt "#31016"
msgid "Albums"
msgstr "Album"
diff --git a/addons/skin.estouchy/xml/ViewsList.xml b/addons/skin.estouchy/xml/ViewsList.xml
index e0c32771b4..fbeedd24da 100644
--- a/addons/skin.estouchy/xml/ViewsList.xml
+++ b/addons/skin.estouchy/xml/ViewsList.xml
@@ -113,7 +113,7 @@
<width>60</width>
<height>40</height>
<texture>flagging/source/Set.png</texture>
- <visible>[Container.Content(Movies) | Container.Content(Sets)] + ListItem.IsCollection</visible>
+ <visible>ListItem.IsCollection</visible>
</control>
<control type="image">
<posx>48r</posx>
@@ -122,7 +122,7 @@
<height>26</height>
<aspectratio>keep</aspectratio>
<texture>OverlayWatching.png</texture>
- <visible>[Container.Content(Movies) | Container.Content(Episodes) | Container.Content(MusicVideos) | Container.Content(Videos)] + ListItem.IsResumable</visible>
+ <visible>ListItem.IsResumable</visible>
</control>
<control type="image">
<posx>50r</posx>
@@ -130,7 +130,7 @@
<width>30</width>
<height>30</height>
<texture>$INFO[ListItem.Overlay]</texture>
- <visible>[Container.Content(Movies) | Container.Content(TVShows) | Container.Content(Seasons) | Container.Content(Episodes) | Container.Content(MusicVideos) | Container.Content(Videos)] + !ListItem.IsResumable</visible>
+ <visible>!ListItem.IsResumable</visible>
</control>
<control type="label">
<posx>$PARAM[label2-posx]</posx>
@@ -255,7 +255,7 @@
<width>60</width>
<height>40</height>
<texture>flagging/source/Set.png</texture>
- <visible>[Container.Content(Movies) | Container.Content(Sets)] + ListItem.IsCollection</visible>
+ <visible>ListItem.IsCollection</visible>
</control>
<control type="image">
<posx>48r</posx>
@@ -264,7 +264,7 @@
<height>26</height>
<aspectratio>keep</aspectratio>
<texture>OverlayWatching.png</texture>
- <visible>[Container.Content(Movies) | Container.Content(Episodes) | Container.Content(MusicVideos) | Container.Content(Videos)] + ListItem.IsResumable</visible>
+ <visible>ListItem.IsResumable</visible>
</control>
<control type="image">
<posx>50r</posx>
@@ -272,7 +272,7 @@
<width>30</width>
<height>30</height>
<texture>$INFO[ListItem.Overlay]</texture>
- <visible>[Container.Content(Movies) | Container.Content(TVShows) | Container.Content(Seasons) | Container.Content(Episodes) | Container.Content(MusicVideos) | Container.Content(Videos)] + !ListItem.IsResumable</visible>
+ <visible>!ListItem.IsResumable</visible>
</control>
<control type="label">
<posx>$PARAM[label2-posx]</posx>
diff --git a/addons/skin.estouchy/xml/ViewsThumbnail.xml b/addons/skin.estouchy/xml/ViewsThumbnail.xml
index a3e4dade5a..99a40208d4 100644
--- a/addons/skin.estouchy/xml/ViewsThumbnail.xml
+++ b/addons/skin.estouchy/xml/ViewsThumbnail.xml
@@ -72,6 +72,22 @@
<texture>OverlayWatched.png</texture>
<visible>Window.IsVisible(AddonBrowser) + String.IsEqual(ListItem.Label2,$LOCALIZE[305])</visible>
</control>
+ <control type="image">
+ <posx>182</posx>
+ <posy>4</posy>
+ <width>26</width>
+ <height>26</height>
+ <aspectratio>keep</aspectratio>
+ <texture>OverlayWatching.png</texture>
+ <visible>ListItem.IsResumable</visible>
+ </control>
+ <control type="image">
+ <posx>180</posx>
+ <posy>2</posy>
+ <width>30</width>
+ <height>30</height>
+ <texture>$INFO[ListItem.Overlay]</texture>
+ </control>
</itemlayout>
<focusedlayout condition="!Container.Content(Movies) + !Container.Content(Seasons) + !Container.Content(Episodes) + !Container.Content(TVShows) + !Container.Content(MusicVideos) + !Container.Content(Videos)" height="250" width="218">
<control type="image">
@@ -128,6 +144,23 @@
<texture>OverlayWatched.png</texture>
<visible>Window.IsVisible(AddonBrowser) + String.IsEqual(ListItem.Label2,$LOCALIZE[305])</visible>
</control>
+ <control type="image">
+ <posx>182</posx>
+ <posy>4</posy>
+ <width>26</width>
+ <height>26</height>
+ <aspectratio>keep</aspectratio>
+ <texture>OverlayWatching.png</texture>
+ <visible>ListItem.IsResumable</visible>
+ </control>
+ <control type="image">
+ <posx>180</posx>
+ <posy>2</posy>
+ <width>30</width>
+ <height>30</height>
+ <texture>$INFO[ListItem.Overlay]</texture>
+ <visible>!ListItem.IsResumable</visible>
+ </control>
</focusedlayout>
<itemlayout condition="Container.Content(Movies) | Container.Content(Seasons) | Container.Content(TVShows)" height="375" width="218">
<control type="image">
@@ -181,11 +214,21 @@
<visible>ListItem.IsCollection</visible>
</control>
<control type="image">
+ <posx>172</posx>
+ <posy>262</posy>
+ <width>26</width>
+ <height>26</height>
+ <aspectratio>keep</aspectratio>
+ <texture>OverlayWatching.png</texture>
+ <visible>ListItem.IsResumable</visible>
+ </control>
+ <control type="image">
<posx>170</posx>
<posy>260</posy>
<width>30</width>
<height>30</height>
<texture>$INFO[ListItem.Overlay]</texture>
+ <visible>!ListItem.IsResumable</visible>
</control>
</itemlayout>
<focusedlayout condition="Container.Content(Movies) | Container.Content(Seasons) | Container.Content(TVShows)" height="375" width="218">
@@ -240,11 +283,21 @@
<visible>ListItem.IsCollection</visible>
</control>
<control type="image">
+ <posx>172</posx>
+ <posy>262</posy>
+ <width>26</width>
+ <height>26</height>
+ <aspectratio>keep</aspectratio>
+ <texture>OverlayWatching.png</texture>
+ <visible>ListItem.IsResumable</visible>
+ </control>
+ <control type="image">
<posx>170</posx>
<posy>260</posy>
<width>30</width>
<height>30</height>
<texture>$INFO[ListItem.Overlay]</texture>
+ <visible>!ListItem.IsResumable</visible>
</control>
</focusedlayout>
<itemlayout condition="Container.Content(Episodes) | Container.Content(MusicVideos) | Container.Content(Videos)" height="250" width="$PARAM[layout-width]">
@@ -291,11 +344,21 @@
<texture>$INFO[ListItem.VideoResolution,flagging/resolution/,.png]</texture>
</control>
<control type="image">
+ <posx>265</posx>
+ <posy>147</posy>
+ <width>26</width>
+ <height>26</height>
+ <aspectratio>keep</aspectratio>
+ <texture>OverlayWatching.png</texture>
+ <visible>ListItem.IsResumable</visible>
+ </control>
+ <control type="image">
<posx>263</posx>
<posy>145</posy>
<width>30</width>
<height>30</height>
<texture>$INFO[ListItem.Overlay]</texture>
+ <visible>!ListItem.IsResumable</visible>
</control>
</itemlayout>
<focusedlayout condition="Container.Content(Episodes) | Container.Content(MusicVideos) | Container.Content(Videos)" height="250" width="$PARAM[layout-width]">
@@ -342,11 +405,21 @@
<texture>$INFO[ListItem.VideoResolution,flagging/resolution/,.png]</texture>
</control>
<control type="image">
+ <posx>265</posx>
+ <posy>147</posy>
+ <width>26</width>
+ <height>26</height>
+ <aspectratio>keep</aspectratio>
+ <texture>OverlayWatching.png</texture>
+ <visible>ListItem.IsResumable</visible>
+ </control>
+ <control type="image">
<posx>263</posx>
<posy>145</posy>
<width>30</width>
<height>30</height>
<texture>$INFO[ListItem.Overlay]</texture>
+ <visible>!ListItem.IsResumable</visible>
</control>
</focusedlayout>
</control>
diff --git a/addons/skin.estuary/addon.xml b/addons/skin.estuary/addon.xml
index caddb89042..b01c61dc6f 100644
--- a/addons/skin.estuary/addon.xml
+++ b/addons/skin.estuary/addon.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<addon id="skin.estuary" version="2.0.26" name="Estuary" provider-name="phil65, Ichabod Fletchman">
+<addon id="skin.estuary" version="2.0.27" name="Estuary" provider-name="phil65, Ichabod Fletchman">
<requires>
<import addon="xbmc.gui" version="5.14.0"/>
</requires>
@@ -51,7 +51,7 @@
<summary lang="pt_PT">Visual Estuary de phil65 e Piers. (Visual por omissão do Kodi)</summary>
<summary lang="ro_RO">Tema Estuary de phil65. (Temă implicită pentru Kodi)</summary>
<summary lang="ru_RU">Обложка Estuary (стандартная обложка Kodi). Авторы: phil65 and Piers.</summary>
- <summary lang="sk_SK">Vzhľad Estuary, vytvorili phil65 a Piers. (predvolený vzhľad pre Kodi)</summary>
+ <summary lang="sk_SK">Vzhľad Estuary, vytvorili phil65. (predvolený vzhľad pre Kodi)</summary>
<summary lang="sr_RS">Маска Estuary аутора phil65 и Piers. (Подразумевана Коди маска)</summary>
<summary lang="sr_RS@latin">Maska Estuary autora phil65 i Piers. (Podrazumevana Kodi maska)</summary>
<summary lang="sv_SE">Estuary, ett skal av phil65. (Kodi's standardskal)</summary>
diff --git a/addons/skin.estuary/language/resource.language.he_il/strings.po b/addons/skin.estuary/language/resource.language.he_il/strings.po
index 709493f0ac..80b2fa112f 100644
--- a/addons/skin.estuary/language/resource.language.he_il/strings.po
+++ b/addons/skin.estuary/language/resource.language.he_il/strings.po
@@ -448,6 +448,10 @@ msgctxt "#31132"
msgid "Select Program"
msgstr "בחר תוכנית"
+msgctxt "#31133"
+msgid "Select Resolution"
+msgstr "בחירת רזולוציה"
+
msgctxt "#31134"
msgid "Remaining"
msgstr "נותר"
@@ -556,6 +560,18 @@ msgctxt "#31163"
msgid "Show Fanart background"
msgstr "הצג רקע פאנארט"
+msgctxt "#31164"
+msgid "Choose kind of profile identification"
+msgstr "לבחור סוג של זיהוי פרופיל"
+
msgctxt "#31165"
msgid "Profile name"
msgstr "שם משתמש"
+
+msgctxt "#31166"
+msgid "Profile avatar"
+msgstr "דמות מייצגת לפרופיל"
+
+msgctxt "#31167"
+msgid "Animate background"
+msgstr "הנפשת הרקע"
diff --git a/addons/skin.estuary/language/resource.language.ja_jp/strings.po b/addons/skin.estuary/language/resource.language.ja_jp/strings.po
index f521d9b0cc..44d72b1a72 100644
--- a/addons/skin.estuary/language/resource.language.ja_jp/strings.po
+++ b/addons/skin.estuary/language/resource.language.ja_jp/strings.po
@@ -46,7 +46,7 @@ msgstr "ランダムムービー"
msgctxt "#31007"
msgid "Unwatched movies"
-msgstr "未視聴な映画"
+msgstr "未視聴の映画"
msgctxt "#31008"
msgid "Enable category widgets"
diff --git a/addons/skin.estuary/xml/SkinSettings.xml b/addons/skin.estuary/xml/SkinSettings.xml
index e63001fadd..6c82f75339 100644
--- a/addons/skin.estuary/xml/SkinSettings.xml
+++ b/addons/skin.estuary/xml/SkinSettings.xml
@@ -328,8 +328,8 @@
<orientation>vertical</orientation>
<texturesliderbackground />
<animation effect="slide" end="6,0" time="300" tween="sine" easing="inout" condition="!Control.HasFocus(60)">conditional</animation>
- <onleft>1000</onleft>
- <onright>1000</onright>
+ <onleft>10000</onleft>
+ <onright>10000</onright>
<animation effect="fade" start="0" end="100" time="200" delay="300">Visible</animation>
<animation effect="fade" start="100" end="0" time="200">Hidden</animation>
<animation effect="fade" start="0" end="100" delay="300" time="320">WindowOpen</animation>
diff --git a/cmake/installdata/test-reference-data.txt b/cmake/installdata/test-reference-data.txt
index b6c94a7f7d..8bc1c03adc 100644
--- a/cmake/installdata/test-reference-data.txt
+++ b/cmake/installdata/test-reference-data.txt
@@ -1,5 +1,6 @@
xbmc/utils/test/CXBMCTinyXML-test.xml
xbmc/utils/test/data/language/Spanish/strings.po
+xbmc/filesystem/test/extendedlocalheader.zip
xbmc/filesystem/test/reffile.txt
xbmc/filesystem/test/reffile.txt.rar
xbmc/filesystem/test/reffile.txt.zip
diff --git a/cmake/scripts/osx/ArchSetup.cmake b/cmake/scripts/osx/ArchSetup.cmake
index 9ba0596c9c..ae98485c03 100644
--- a/cmake/scripts/osx/ArchSetup.cmake
+++ b/cmake/scripts/osx/ArchSetup.cmake
@@ -34,7 +34,7 @@ list(APPEND DEPLIBS "-framework DiskArbitration" "-framework IOKit"
"-framework ApplicationServices" "-framework AppKit"
"-framework CoreAudio" "-framework AudioToolbox"
"-framework CoreGraphics" "-framework CoreMedia"
- "-framework VideoToolbox")
+ "-framework VideoToolbox" "-framework Security")
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.9)
set(CMAKE_XCODE_ATTRIBUTE_CLANG_LINK_OBJC_RUNTIME OFF)
diff --git a/media/splash.jpg b/media/splash.jpg
index 880349919d..23b8c9ed16 100644
--- a/media/splash.jpg
+++ b/media/splash.jpg
Binary files differ
diff --git a/project/BuildDependencies/scripts/get_formed.cmd b/project/BuildDependencies/scripts/get_formed.cmd
index 92fcb80a8c..41f40510ac 100644
--- a/project/BuildDependencies/scripts/get_formed.cmd
+++ b/project/BuildDependencies/scripts/get_formed.cmd
@@ -64,7 +64,7 @@ IF EXIST %1 (
) ELSE (
CALL :setSubStageName Downloading %1...
SET DOWNLOAD_URL=%KODI_MIRROR%/build-deps/win32/%1
- %WGET% -S --quiet --tries=5 --retry-connrefused --waitretry=2 --show-progress "!DOWNLOAD_URL!" 2>&1 | findstr /L /I "Location:"
+ %WGET% --quiet --tries=5 --retry-connrefused --waitretry=2 --show-progress "!DOWNLOAD_URL!" 2>&1
REM Apparently there's a quirk in cmd so this means if error level => 1
IF ERRORLEVEL 1 (
ECHO %1^|Download of !DOWNLOAD_URL! failed >> %FORMED_FAILED_LIST%
diff --git a/system/playercorefactory.xml b/system/playercorefactory.xml
index be6b7219ab..bb57a08e6c 100644
--- a/system/playercorefactory.xml
+++ b/system/playercorefactory.xml
@@ -26,7 +26,7 @@
<!-- DVDs -->
<rule name="dvd" dvd="true" player="VideoPlayer" />
- <rule name="dvdimage" dvdimage="true" player="VideoPlayer" />
+ <rule name="dvdimage" dvdimage="true" game="false" player="VideoPlayer" />
<!-- Only VideoPlayer can handle these normally -->
<rule name="sdp/asf" filetypes="sdp|asf" player="VideoPlayer" />
diff --git a/tools/depends/target/Toolchain.cmake.in b/tools/depends/target/Toolchain.cmake.in
index 23e5c882bb..236400cce8 100644
--- a/tools/depends/target/Toolchain.cmake.in
+++ b/tools/depends/target/Toolchain.cmake.in
@@ -2,6 +2,11 @@ set(DEPENDS_PATH "@prefix@/@deps_dir@")
set(NATIVEPREFIX "@prefix@/@tool_dir@")
set(OS "@platform_os@")
+set(CMAKE_SYSTEM_PROCESSOR @host_cpu@)
+# TODO: remove this after the host triplet for arm64 darwin builds is corrected to aarch64-apple-darwin
+if(@platform_os@ STREQUAL darwin_embedded AND @use_cpu@ STREQUAL arm64)
+ set(CMAKE_SYSTEM_PROCESSOR aarch64)
+endif()
set(CPU "@use_cpu@")
set(PLATFORM "@target_platform@")
diff --git a/tools/depends/target/Toolchain_binaddons.cmake.in b/tools/depends/target/Toolchain_binaddons.cmake.in
index a889085ecf..ead0871915 100644
--- a/tools/depends/target/Toolchain_binaddons.cmake.in
+++ b/tools/depends/target/Toolchain_binaddons.cmake.in
@@ -1,4 +1,9 @@
set(OS "@platform_os@")
+set(CMAKE_SYSTEM_PROCESSOR @host_cpu@)
+# TODO: remove this after the host triplet for arm64 darwin builds is corrected to aarch64-apple-darwin
+if(@platform_os@ STREQUAL darwin_embedded AND @use_cpu@ STREQUAL arm64)
+ set(CMAKE_SYSTEM_PROCESSOR aarch64)
+endif()
set(CPU "@use_cpu@")
set(PLATFORM "@target_platform@")
set(APP_RENDER_SYSTEM @app_rendersystem@)
diff --git a/tools/depends/target/gnutls/02-darwin-getentropy.patch b/tools/depends/target/gnutls/02-darwin-getentropy.patch
index 300490c12f..80ddd9d43a 100644
--- a/tools/depends/target/gnutls/02-darwin-getentropy.patch
+++ b/tools/depends/target/gnutls/02-darwin-getentropy.patch
@@ -1,14 +1,15 @@
---- a/configure.ac
-+++ b/configure.ac
-@@ -220,6 +220,7 @@
- rnd_variant=getrandom],
- [AC_MSG_RESULT(no)])
+diff -Naur a/configure.ac b/configure.ac
+--- a/configure.ac 2019-12-02 08:32:16.000000000 -0800
++++ b/configure.ac 2020-01-31 10:25:36.473631501 -0800
+@@ -278,6 +278,7 @@
+
+ AM_CONDITIONAL(HAVE_KERN_ARND, test "$rnd_variant" = "kern_arnd")
+if test "x$have_macosx" != "xyes"; then
AC_MSG_CHECKING([for getentropy])
AC_LINK_IFELSE([AC_LANG_PROGRAM([
#include <unistd.h>
-@@ -233,6 +234,7 @@
+@@ -294,6 +295,7 @@
AC_DEFINE([HAVE_GETENTROPY], 1, [Enable the OpenBSD getentropy function])
rnd_variant=getentropy],
[AC_MSG_RESULT(no)])
diff --git a/tools/depends/target/gnutls/Makefile b/tools/depends/target/gnutls/Makefile
index 5eb41e45e4..d78be875c7 100644
--- a/tools/depends/target/gnutls/Makefile
+++ b/tools/depends/target/gnutls/Makefile
@@ -1,9 +1,9 @@
include ../../Makefile.include
-DEPS= ../../Makefile.include Makefile size-max.patch 02-darwin-getentropy.patch
+DEPS= ../../Makefile.include Makefile size-max.patch 02-darwin-getentropy.patch remove-weak_import-check-for-osx.patch add-dl-as-private-lib.patch
# lib name, version
LIBNAME=gnutls
-VERSION=3.5.10
+VERSION=3.6.11.1
SOURCE=$(LIBNAME)-$(VERSION)
ARCHIVE=$(SOURCE).tar.xz
@@ -15,10 +15,9 @@ CONFIGURE_HACKS+= ac_cv_func_fork=no
endif
# configuration settings
-CONFIGURE=cp -f $(CONFIG_SUB) $(CONFIG_GUESS) .; \
- ./configure --prefix=$(PREFIX) --disable-shared --without-p11-kit --disable-nls --with-included-unistring \
+CONFIGURE=./configure --prefix=$(PREFIX) --disable-shared --without-p11-kit --disable-nls --with-included-unistring \
--with-included-libtasn1 --enable-local-libopts --disable-doc --disable-tests --disable-guile \
- $(CONFIGURE_HACKS)
+ --disable-tools $(CONFIGURE_HACKS)
LIBDYLIB=$(PLATFORM)/lib/.libs/lib$(LIBNAME).a
@@ -32,6 +31,8 @@ $(PLATFORM): $(TARBALLS_LOCATION)/$(ARCHIVE) $(DEPS)
cd $(PLATFORM); $(ARCHIVE_TOOL) $(ARCHIVE_TOOL_FLAGS) $(TARBALLS_LOCATION)/$(ARCHIVE)
cd $(PLATFORM); patch -p0 < ../size-max.patch
cd $(PLATFORM); patch -p1 -i ../02-darwin-getentropy.patch
+ cd $(PLATFORM); patch -p1 -i ../remove-weak_import-check-for-osx.patch
+ cd $(PLATFORM); patch -p1 -i ../add-dl-as-private-lib.patch
cd $(PLATFORM); $(AUTORECONF) -vif
cd $(PLATFORM); $(CONFIGURE)
diff --git a/tools/depends/target/gnutls/add-dl-as-private-lib.patch b/tools/depends/target/gnutls/add-dl-as-private-lib.patch
new file mode 100644
index 0000000000..d49392129b
--- /dev/null
+++ b/tools/depends/target/gnutls/add-dl-as-private-lib.patch
@@ -0,0 +1,26 @@
+diff --git a/configure.ac b/configure.ac
+index db1ce841f..264712b56 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -512,6 +512,9 @@ LT_INIT([disable-static,win32-dll,shared])
+
+
+ AC_LIB_HAVE_LINKFLAGS(dl,, [#include <dlfcn.h>], [dladdr (0, 0);])
++if test "x$HAVE_LIBDL" = "xyes"; then
++ AC_SUBST([LIBDL], [-ldl])
++fi
+
+ AC_ARG_ENABLE(fips140-mode,
+ AS_HELP_STRING([--enable-fips140-mode], [enable FIPS140-2 mode]),
+diff --git a/lib/gnutls.pc.in b/lib/gnutls.pc.in
+index ffad3e168..15b990764 100644
+--- a/lib/gnutls.pc.in
++++ b/lib/gnutls.pc.in
+@@ -19,6 +19,6 @@ Description: Transport Security Layer implementation for the GNU system
+ URL: https://www.gnutls.org/
+ Version: @VERSION@
+ Libs: -L${libdir} -lgnutls
+-Libs.private: @LIBINTL@ @LIBSOCKET@ @INET_PTON_LIB@ @LIBPTHREAD@ @LIB_SELECT@ @TSS_LIBS@ @GMP_LIBS@ @LIBUNISTRING@ @LIBIDN2_LIBS@ @LIBATOMIC_LIBS@
++Libs.private: @LIBINTL@ @LIBSOCKET@ @INET_PTON_LIB@ @LIBPTHREAD@ @LIB_SELECT@ @TSS_LIBS@ @GMP_LIBS@ @LIBUNISTRING@ @LIBIDN2_LIBS@ @LIBATOMIC_LIBS@ @LIBDL@
+ @GNUTLS_REQUIRES_PRIVATE@
+ Cflags: -I${includedir}
diff --git a/tools/depends/target/gnutls/remove-weak_import-check-for-osx.patch b/tools/depends/target/gnutls/remove-weak_import-check-for-osx.patch
new file mode 100644
index 0000000000..ec2b3b0a83
--- /dev/null
+++ b/tools/depends/target/gnutls/remove-weak_import-check-for-osx.patch
@@ -0,0 +1,17 @@
+--- a/configure.ac 2020-01-25 08:26:59.223068640 -0800
++++ b/configure.ac 2020-01-25 08:26:38.846233553 -0800
+@@ -122,14 +122,6 @@
+ ;;
+ *darwin*)
+ have_macosx=yes
+- save_LDFLAGS="$LDFLAGS"
+- dnl Try to use -no_weak_imports if available. This makes sure we
+- dnl error out when linking to a function that doesn't exist in the
+- dnl intended minimum runtime version.
+- LDFLAGS="$LDFLAGS -Wl,-no_weak_imports"
+- AC_MSG_CHECKING([whether the linker supports -Wl,-no_weak_imports])
+- AC_LINK_IFELSE([AC_LANG_PROGRAM([], [])],
+- [AC_MSG_RESULT(yes)], [AC_MSG_RESULT(no); LDFLAGS="$save_LDFLAGS"])
+ ;;
+ *solaris*)
+ have_elf=yes
diff --git a/tools/depends/target/nettle/Makefile b/tools/depends/target/nettle/Makefile
index 4808ee036d..c46788b656 100644
--- a/tools/depends/target/nettle/Makefile
+++ b/tools/depends/target/nettle/Makefile
@@ -3,7 +3,7 @@ DEPS= ../../Makefile.include Makefile 01-disable_testsuite.patch
# lib name, version
LIBNAME=nettle
-VERSION=3.2
+VERSION=3.5.1
SOURCE=$(LIBNAME)-$(VERSION)
ARCHIVE=$(SOURCE).tar.gz
diff --git a/version.txt b/version.txt
index 2fafa886f5..7e1a162ba0 100644
--- a/version.txt
+++ b/version.txt
@@ -3,10 +3,10 @@ COMPANY_NAME XBMC Foundation
COPYRIGHT_YEARS 2005-2019
WEBSITE http://kodi.tv
VERSION_MAJOR 18
-VERSION_MINOR 5
+VERSION_MINOR 6
VERSION_TAG
-VERSION_CODE 18.5.0
-ADDON_API 18.5.0
+VERSION_CODE 18.6.0
+ADDON_API 18.6.0
APP_PACKAGE org.xbmc.kodi
PACKAGE_IDENTITY XBMCFoundation.Kodi
PACKAGE_PUBLISHER C62BD90A-CDD8-477F-96C3-B25992247B97
diff --git a/xbmc/CMakeLists.txt b/xbmc/CMakeLists.txt
index 50eadc1dc9..863fb854bd 100644
--- a/xbmc/CMakeLists.txt
+++ b/xbmc/CMakeLists.txt
@@ -65,6 +65,7 @@ set(HEADERS AppParamParser.h
IProgressCallback.h
InfoScanner.h
LangInfo.h
+ LockType.h
MediaSource.h
NfoFile.h
PartyModeManager.h
diff --git a/xbmc/FileItem.cpp b/xbmc/FileItem.cpp
index 9118fa2eab..928a43a776 100644
--- a/xbmc/FileItem.cpp
+++ b/xbmc/FileItem.cpp
@@ -1,63 +1,64 @@
/*
- * Copyright (C) 2005-2018 Team Kodi
+ * Copyright (C) 2005-2020 Team Kodi
* This file is part of Kodi - https://kodi.tv
*
* SPDX-License-Identifier: GPL-2.0-or-later
* See LICENSES/README.md for more information.
*/
-#include <cstdlib>
-
#include "FileItem.h"
+
+#include "CueDocument.h"
#include "ServiceBroker.h"
-#include "guilib/LocalizeStrings.h"
-#include "utils/StringUtils.h"
-#include "utils/URIUtils.h"
-#include "utils/Archive.h"
+#include "URL.h"
#include "Util.h"
-#include "playlists/PlayListFactory.h"
-#include "utils/Crc32.h"
+#include "events/IEvent.h"
+#include "filesystem/CurlFile.h"
#include "filesystem/Directory.h"
#include "filesystem/File.h"
-#include "filesystem/StackDirectory.h"
-#include "filesystem/CurlFile.h"
#include "filesystem/MultiPathDirectory.h"
#include "filesystem/MusicDatabaseDirectory.h"
+#include "filesystem/StackDirectory.h"
#include "filesystem/VideoDatabaseDirectory.h"
#include "filesystem/VideoDatabaseDirectory/QueryParams.h"
-#include "games/addons/GameClient.h"
#include "games/GameUtils.h"
+#include "games/addons/GameClient.h"
#include "games/tags/GameInfoTag.h"
-#include "music/tags/MusicInfoTagLoaderFactory.h"
-#include "CueDocument.h"
-#include "video/VideoDatabase.h"
+#include "guilib/LocalizeStrings.h"
+#include "media/MediaLockState.h"
+#include "music/Album.h"
+#include "music/Artist.h"
#include "music/MusicDatabase.h"
+#include "music/tags/MusicInfoTag.h"
+#include "music/tags/MusicInfoTagLoaderFactory.h"
+#include "pictures/PictureInfoTag.h"
+#include "playlists/PlayListFactory.h"
#include "pvr/PVRManager.h"
-#include "pvr/channels/PVRChannelGroupsContainer.h"
#include "pvr/channels/PVRChannel.h"
+#include "pvr/channels/PVRChannelGroupsContainer.h"
#include "pvr/epg/Epg.h"
#include "pvr/recordings/PVRRecording.h"
#include "pvr/timers/PVRTimerInfoTag.h"
-#include "video/Bookmark.h"
-#include "video/VideoInfoTag.h"
-#include "threads/SingleLock.h"
-#include "music/tags/MusicInfoTag.h"
-#include "pictures/PictureInfoTag.h"
-#include "music/Artist.h"
-#include "music/Album.h"
-#include "URL.h"
#include "settings/AdvancedSettings.h"
#include "settings/Settings.h"
#include "settings/SettingsComponent.h"
+#include "threads/SingleLock.h"
+#include "utils/Archive.h"
+#include "utils/Crc32.h"
#include "utils/FileExtensionProvider.h"
-#include "utils/RegExp.h"
-#include "utils/log.h"
-#include "utils/Variant.h"
#include "utils/Mime.h"
#include "utils/Random.h"
-#include "events/IEvent.h"
+#include "utils/RegExp.h"
+#include "utils/StringUtils.h"
+#include "utils/URIUtils.h"
+#include "utils/Variant.h"
+#include "utils/log.h"
+#include "video/Bookmark.h"
+#include "video/VideoDatabase.h"
+#include "video/VideoInfoTag.h"
#include <algorithm>
+#include <cstdlib>
using namespace KODI;
using namespace XFILE;
@@ -493,7 +494,7 @@ void CFileItem::Initialize()
m_idepth = 1;
m_iLockMode = LOCK_MODE_EVERYONE;
m_iBadPwdCount = 0;
- m_iHasLock = 0;
+ m_iHasLock = LOCK_STATE_NO_LOCK;
m_bCanQueue = true;
m_specialSort = SortSpecialNone;
m_doContentLookup = true;
@@ -1198,6 +1199,16 @@ bool CFileItem::IsBluray() const
return item.IsBDFile();
}
+bool CFileItem::IsProtectedBlurayDisc() const
+{
+ std::string path;
+ path = URIUtils::AddFileToFolder(GetPath(), "AACS", "Unit_Key_RO.inf");
+ if (CFile::Exists(path))
+ return true;
+
+ return false;
+}
+
bool CFileItem::IsCDDA() const
{
return URIUtils::IsCDDA(m_strPath);
diff --git a/xbmc/FileItem.h b/xbmc/FileItem.h
index 75f57db659..632855c30b 100644
--- a/xbmc/FileItem.h
+++ b/xbmc/FileItem.h
@@ -202,6 +202,7 @@ public:
bool IsDVDFile(bool bVobs = true, bool bIfos = true) const;
bool IsBDFile() const;
bool IsBluray() const;
+ bool IsProtectedBlurayDisc() const;
bool IsRAR() const;
bool IsAPK() const;
bool IsZIP() const;
@@ -749,12 +750,12 @@ public:
void ClearSortState();
- VECFILEITEMS::const_iterator begin() { return m_items.cbegin(); }
- VECFILEITEMS::const_iterator end() { return m_items.cend(); }
+ VECFILEITEMS::iterator begin() { return m_items.begin(); }
+ VECFILEITEMS::iterator end() { return m_items.end(); }
VECFILEITEMS::const_iterator begin() const { return m_items.begin(); }
VECFILEITEMS::const_iterator end() const { return m_items.end(); }
- VECFILEITEMS::const_iterator cbegin() const { return m_items.begin(); }
- VECFILEITEMS::const_iterator cend() const { return m_items.end(); }
+ VECFILEITEMS::const_iterator cbegin() const { return m_items.cbegin(); }
+ VECFILEITEMS::const_iterator cend() const { return m_items.cend(); }
private:
void Sort(FILEITEMLISTCOMPARISONFUNC func);
void FillSortFields(FILEITEMFILLFUNC func);
diff --git a/xbmc/GUIPassword.cpp b/xbmc/GUIPassword.cpp
index ef4859fa8f..07fc0b9438 100644
--- a/xbmc/GUIPassword.cpp
+++ b/xbmc/GUIPassword.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005-2018 Team Kodi
+ * Copyright (C) 2005-2020 Team Kodi
* This file is part of Kodi - https://kodi.tv
*
* SPDX-License-Identifier: GPL-2.0-or-later
@@ -7,27 +7,30 @@
*/
#include "GUIPassword.h"
+
+#include "FileItem.h"
#include "GUIUserMessages.h"
#include "ServiceBroker.h"
-#include "messaging/ApplicationMessenger.h"
+#include "Util.h"
#include "dialogs/GUIDialogGamepad.h"
+#include "dialogs/GUIDialogNumeric.h"
#include "guilib/GUIComponent.h"
#include "guilib/GUIKeyboardFactory.h"
-#include "dialogs/GUIDialogNumeric.h"
+#include "guilib/GUIWindowManager.h"
+#include "guilib/LocalizeStrings.h"
+#include "media/MediaLockState.h"
+#include "messaging/ApplicationMessenger.h"
+#include "messaging/helpers/DialogOKHelper.h"
#include "profiles/ProfileManager.h"
#include "profiles/dialogs/GUIDialogLockSettings.h"
#include "profiles/dialogs/GUIDialogProfileSettings.h"
-#include "Util.h"
#include "settings/MediaSourceSettings.h"
#include "settings/Settings.h"
#include "settings/SettingsComponent.h"
-#include "guilib/GUIWindowManager.h"
-#include "FileItem.h"
-#include "guilib/LocalizeStrings.h"
-#include "messaging/helpers/DialogOKHelper.h"
#include "utils/StringUtils.h"
-#include "view/ViewStateSettings.h"
#include "utils/Variant.h"
+#include "utils/log.h"
+#include "view/ViewStateSettings.h"
#include <utility>
@@ -40,41 +43,33 @@ CGUIPassword::CGUIPassword(void)
}
CGUIPassword::~CGUIPassword(void) = default;
-bool CGUIPassword::IsItemUnlocked(CFileItem* pItem, const std::string &strType)
+template<typename T>
+bool CGUIPassword::IsItemUnlocked(T pItem,
+ const std::string& strType,
+ const std::string& strLabel,
+ const std::string& strHeading)
{
- const std::shared_ptr<CProfileManager> profileManager = CServiceBroker::GetSettingsComponent()->GetProfileManager();
-
- // \brief Tests if the user is allowed to access the share folder
- // \param pItem The share folder item to access
- // \param strType The type of share being accessed, e.g. "music", "video", etc. See CSettings::UpdateSources()
- // \return If access is granted, returns \e true
+ const std::shared_ptr<CProfileManager> profileManager =
+ CServiceBroker::GetSettingsComponent()->GetProfileManager();
if (profileManager->GetMasterProfile().getLockMode() == LOCK_MODE_EVERYONE)
return true;
- while (pItem->m_iHasLock > 1)
+ while (pItem->m_iHasLock > LOCK_STATE_LOCK_BUT_UNLOCKED)
{
- std::string strLockCode = pItem->m_strLockCode;
- std::string strLabel = pItem->GetLabel();
- int iResult = 0; // init to user succeeded state, doing this to optimize switch statement below
- char buffer[33]; // holds 32 places plus sign character
- if(g_passwordManager.bMasterUser)// Check if we are the MasterUser!
+ const std::string strLockCode = pItem->m_strLockCode;
+ int iResult = 0; // init to user succeeded state, doing this to optimize switch statement below
+ if (!g_passwordManager.bMasterUser) // Check if we are the MasterUser!
{
- iResult = 0;
- }
- else
- {
- if (0 != CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_MASTERLOCK_MAXRETRIES) && pItem->m_iBadPwdCount >= CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_MASTERLOCK_MAXRETRIES))
- { // user previously exhausted all retries, show access denied error
+ if (0 != CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(
+ CSettings::SETTING_MASTERLOCK_MAXRETRIES) &&
+ pItem->m_iBadPwdCount >= CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(
+ CSettings::SETTING_MASTERLOCK_MAXRETRIES))
+ {
+ // user previously exhausted all retries, show access denied error
HELPERS::ShowOKDialogText(CVariant{12345}, CVariant{12346});
return false;
}
// show the appropriate lock dialog
- std::string strHeading = "";
- if (pItem->m_bIsFolder)
- strHeading = g_localizeStrings.Get(12325);
- else
- strHeading = g_localizeStrings.Get(12348);
-
iResult = VerifyPassword(pItem->m_iLockMode, strLockCode, strHeading);
}
switch (iResult)
@@ -88,20 +83,21 @@ bool CGUIPassword::IsItemUnlocked(CFileItem* pItem, const std::string &strType)
{
// password entry succeeded
pItem->m_iBadPwdCount = 0;
- pItem->m_iHasLock = 1;
- g_passwordManager.LockSource(strType,strLabel,false);
- sprintf(buffer,"%i",pItem->m_iBadPwdCount);
- CMediaSourceSettings::GetInstance().UpdateSource(strType, strLabel, "badpwdcount", buffer);
+ pItem->m_iHasLock = LOCK_STATE_LOCK_BUT_UNLOCKED;
+ g_passwordManager.LockSource(strType, strLabel, false);
+ CMediaSourceSettings::GetInstance().UpdateSource(strType, strLabel, "badpwdcount",
+ std::to_string(pItem->m_iBadPwdCount));
CMediaSourceSettings::GetInstance().Save();
break;
}
case 1:
{
// password entry failed
- if (0 != CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_MASTERLOCK_MAXRETRIES))
+ if (0 != CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(
+ CSettings::SETTING_MASTERLOCK_MAXRETRIES))
pItem->m_iBadPwdCount++;
- sprintf(buffer,"%i",pItem->m_iBadPwdCount);
- CMediaSourceSettings::GetInstance().UpdateSource(strType, strLabel, "badpwdcount", buffer);
+ CMediaSourceSettings::GetInstance().UpdateSource(strType, strLabel, "badpwdcount",
+ std::to_string(pItem->m_iBadPwdCount));
CMediaSourceSettings::GetInstance().Save();
break;
}
@@ -116,12 +112,32 @@ bool CGUIPassword::IsItemUnlocked(CFileItem* pItem, const std::string &strType)
return true;
}
+bool CGUIPassword::IsItemUnlocked(CFileItem* pItem, const std::string& strType)
+{
+ const std::string strLabel = pItem->GetLabel();
+ std::string strHeading;
+ if (pItem->m_bIsFolder)
+ strHeading = g_localizeStrings.Get(12325); // "Locked! Enter code..."
+ else
+ strHeading = g_localizeStrings.Get(12348); // "Item locked"
+
+ return IsItemUnlocked<CFileItem*>(pItem, strType, strLabel, strHeading);
+}
+
+bool CGUIPassword::IsItemUnlocked(CMediaSource* pItem, const std::string& strType)
+{
+ const std::string strLabel = pItem->strName;
+ std::string strHeading = g_localizeStrings.Get(12325); // "Locked! Enter code..."
+
+ return IsItemUnlocked<CMediaSource*>(pItem, strType, strLabel, strHeading);
+}
+
bool CGUIPassword::CheckStartUpLock()
{
// prompt user for mastercode if the mastercode was set b4 or by xml
int iVerifyPasswordResult = -1;
- std::string strHeader = g_localizeStrings.Get(20075);
+ std::string strHeader = g_localizeStrings.Get(20075); // "Enter master lock code"
if (iMasterLockRetriesLeft == -1)
iMasterLockRetriesLeft = CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_MASTERLOCK_MAXRETRIES);
@@ -143,7 +159,7 @@ bool CGUIPassword::CheckStartUpLock()
if (iVerifyPasswordResult != 0 )
{
std::string strLabel1;
- strLabel1 = g_localizeStrings.Get(12343);
+ strLabel1 = g_localizeStrings.Get(12343); // "retries left"
int iLeft = g_passwordManager.iMasterLockRetriesLeft-i;
std::string strLabel = StringUtils::Format("%i %s", iLeft, strLabel1.c_str());
@@ -175,6 +191,7 @@ bool CGUIPassword::SetMasterLockMode(bool bDetails)
if (profile)
{
CProfile::CLock locks = profile->GetLocks();
+ // prompt user for master lock
if (CGUIDialogLockSettings::ShowAndGetLock(locks, 12360, true, bDetails))
{
profile->SetLocks(locks);
@@ -224,6 +241,7 @@ bool CGUIPassword::IsProfileLockUnlocked(int iProfile, bool& bCanceled, bool pro
else
{
if (profileManager->GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE)
+ // prompt user for profile lock code
return CheckLock(profile->getLockMode(),profile->getLockCode(),20095,bCanceled);
}
}
@@ -301,14 +319,15 @@ void CGUIPassword::UpdateMasterLockRetryCount(bool bResetCount)
g_passwordManager.iMasterLockRetriesLeft = 0;
// Tell the user they ran out of retry attempts
HELPERS::ShowOKDialogText(CVariant{12345}, CVariant{12346});
- return ;
+ return;
}
}
std::string dlgLine1 = "";
if (0 < g_passwordManager.iMasterLockRetriesLeft)
- dlgLine1 = StringUtils::Format("%d %s",
- g_passwordManager.iMasterLockRetriesLeft,
- g_localizeStrings.Get(12343).c_str());
+ dlgLine1 = StringUtils::Format("%d %s", g_passwordManager.iMasterLockRetriesLeft,
+ g_localizeStrings.Get(12343).c_str()); // "retries left"
+
+ // prompt user for master lock
HELPERS::ShowOKDialogLines(CVariant{20075}, CVariant{12345}, CVariant{std::move(dlgLine1)}, CVariant{0});
}
else
@@ -427,9 +446,13 @@ bool CGUIPassword::CheckMenuLock(int iWindowID)
break;
case WINDOW_MUSIC_NAV: // Music
bCheckPW = profileManager->GetCurrentProfile().musicLocked();
+ if (!bCheckPW && strMediasourcePath != "") // check mediasource by path
+ return g_passwordManager.IsMediaPathUnlocked(strMediasourcePath, "music");
break;
case WINDOW_VIDEO_NAV: // Video
bCheckPW = profileManager->GetCurrentProfile().videoLocked();
+ if (!bCheckPW && strMediasourcePath != "") // check mediasource by path
+ return g_passwordManager.IsMediaPathUnlocked(strMediasourcePath, "video");
break;
case WINDOW_PICTURES: // Pictures
bCheckPW = profileManager->GetCurrentProfile().picturesLocked();
@@ -458,9 +481,9 @@ bool CGUIPassword::LockSource(const std::string& strType, const std::string& str
{
if (it->strName == strName)
{
- if (it->m_iHasLock > 0)
+ if (it->m_iHasLock > LOCK_STATE_NO_LOCK)
{
- it->m_iHasLock = bState?2:1;
+ it->m_iHasLock = bState ? LOCK_STATE_LOCKED : LOCK_STATE_LOCK_BUT_UNLOCKED;
bResult = true;
}
break;
@@ -481,7 +504,7 @@ void CGUIPassword::LockSources(bool lock)
VECSOURCES *shares = CMediaSourceSettings::GetInstance().GetSources(strType);
for (IVECSOURCES it=shares->begin();it != shares->end();++it)
if (it->m_iLockMode != LOCK_MODE_EVERYONE)
- it->m_iHasLock = lock ? 2 : 1;
+ it->m_iHasLock = lock ? LOCK_STATE_LOCKED : LOCK_STATE_LOCK_BUT_UNLOCKED;
}
CGUIMessage msg(GUI_MSG_NOTIFY_ALL,0,0,GUI_MSG_UPDATE_SOURCES);
CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg);
@@ -497,9 +520,11 @@ void CGUIPassword::RemoveSourceLocks()
for (IVECSOURCES it=shares->begin();it != shares->end();++it)
if (it->m_iLockMode != LOCK_MODE_EVERYONE) // remove old info
{
- it->m_iHasLock = 0;
+ it->m_iHasLock = LOCK_STATE_NO_LOCK;
it->m_iLockMode = LOCK_MODE_EVERYONE;
- CMediaSourceSettings::GetInstance().UpdateSource(strType, it->strName, "lockmode", "0"); // removes locks from xml
+
+ // remove locks from xml
+ CMediaSourceSettings::GetInstance().UpdateSource(strType, it->strName, "lockmode", "0");
}
}
CMediaSourceSettings::GetInstance().Save();
@@ -518,13 +543,40 @@ bool CGUIPassword::IsDatabasePathUnlocked(const std::string& strPath, VECSOURCES
bool bName = false;
int iIndex = CUtil::GetMatchingSource(strPath, vecSources, bName);
- if (iIndex > -1 && iIndex < (int)vecSources.size())
- if (vecSources[iIndex].m_iHasLock < 2)
+ if (iIndex > -1 && iIndex < static_cast<int>(vecSources.size()))
+ if (vecSources[iIndex].m_iHasLock < LOCK_STATE_LOCKED)
return true;
return false;
}
+bool CGUIPassword::IsMediaPathUnlocked(const std::string& strPath, const std::string& strType)
+{
+ if (StringUtils::StartsWithNoCase(strPath, "root") ||
+ StringUtils::StartsWithNoCase(strPath, "library://"))
+ {
+ // no mediasource-lookup needed
+ CLog::Log(LOGDEBUG, "CGUIPassword::IsMediaPathUnlocked - entering from {}", strPath);
+ return true;
+ }
+
+ const std::shared_ptr<CProfileManager> profileManager =
+ CServiceBroker::GetSettingsComponent()->GetProfileManager();
+ if (g_passwordManager.bMasterUser ||
+ profileManager->GetMasterProfile().getLockMode() == LOCK_MODE_EVERYONE)
+ return true;
+
+ VECSOURCES& vecSources = *CMediaSourceSettings::GetInstance().GetSources(strType);
+ bool bName = false;
+ int iIndex = CUtil::GetMatchingSource(strPath, vecSources, bName);
+ if (iIndex > -1 && iIndex < static_cast<int>(vecSources.size()))
+ return g_passwordManager.IsItemUnlocked(&vecSources[iIndex], strType);
+
+ // need to add a missing filter (root/library.. etc.)
+ CLog::Log(LOGERROR, "CGUIPassword::IsMediaPathUnlocked - missing filter: {}", strPath);
+ return true;
+}
+
void CGUIPassword::OnSettingAction(std::shared_ptr<const CSetting> setting)
{
if (setting == NULL)
diff --git a/xbmc/GUIPassword.h b/xbmc/GUIPassword.h
index 18d0179dde..94e03b032d 100644
--- a/xbmc/GUIPassword.h
+++ b/xbmc/GUIPassword.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005-2018 Team Kodi
+ * Copyright (C) 2005-2020 Team Kodi
* This file is part of Kodi - https://kodi.tv
*
* SPDX-License-Identifier: GPL-2.0-or-later
@@ -25,7 +25,22 @@ class CGUIPassword : public ISettingCallback
public:
CGUIPassword(void);
~CGUIPassword(void) override;
+ template<typename T>
+ bool IsItemUnlocked(T pItem,
+ const std::string& strType,
+ const std::string& strLabel,
+ const std::string& strHeading);
+ /*! \brief Tests if the user is allowed to access the share folder
+ \param pItem The share folder item to access
+ \param strType The type of share being accessed, e.g. "music", "video", etc. See CSettings::UpdateSources()
+ \return If access is granted, returns \e true
+ */
bool IsItemUnlocked(CFileItem* pItem, const std::string &strType);
+ /*! \brief Tests if the user is allowed to access the Mediasource
+ \param pItem The share folder item to access
+ \param strType The type of share being accessed, e.g. "music", "video", etc. See CSettings::UpdateSources()
+ \return If access is granted, returns \e true
+ */
bool IsItemUnlocked(CMediaSource* pItem, const std::string &strType);
bool CheckLock(LockType btnType, const std::string& strPassword, int iHeading);
bool CheckLock(LockType btnType, const std::string& strPassword, int iHeading, bool& bCanceled);
@@ -49,11 +64,18 @@ public:
void LockSources(bool lock);
void RemoveSourceLocks();
bool IsDatabasePathUnlocked(const std::string& strPath, VECSOURCES& vecSources);
+ /*! \brief Tests if the user is allowed to access the path by looking up the matching Mediasource
+ \param strPath The folder path to access
+ \param strType The type of share being accessed, e.g. "music", "video", etc. See CSettings::UpdateSources()
+ \return If access is granted, returns \e true
+ */
+ bool IsMediaPathUnlocked(const std::string& strPath, const std::string& strType);
void OnSettingAction(std::shared_ptr<const CSetting> setting) override;
bool bMasterUser;
int iMasterLockRetriesLeft;
+ std::string strMediasourcePath;
private:
int VerifyPassword(LockType btnType, const std::string& strPassword, const std::string& strHeading);
diff --git a/xbmc/LockType.h b/xbmc/LockType.h
index 8bdc237109..9659046db7 100644
--- a/xbmc/LockType.h
+++ b/xbmc/LockType.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005-2018 Team Kodi
+ * Copyright (C) 2005-2020 Team Kodi
* This file is part of Kodi - https://kodi.tv
*
* SPDX-License-Identifier: GPL-2.0-or-later
diff --git a/xbmc/MediaSource.cpp b/xbmc/MediaSource.cpp
index 7b42efa2da..6782ca3f1c 100644
--- a/xbmc/MediaSource.cpp
+++ b/xbmc/MediaSource.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005-2018 Team Kodi
+ * Copyright (C) 2005-2020 Team Kodi
* This file is part of Kodi - https://kodi.tv
*
* SPDX-License-Identifier: GPL-2.0-or-later
@@ -7,11 +7,13 @@
*/
#include "MediaSource.h"
-#include "Util.h"
+
#include "URL.h"
+#include "Util.h"
#include "filesystem/MultiPathDirectory.h"
-#include "utils/URIUtils.h"
+#include "media/MediaLockState.h"
#include "utils/StringUtils.h"
+#include "utils/URIUtils.h"
using namespace XFILE;
@@ -40,7 +42,7 @@ void CMediaSource::FromNameAndPaths(const std::string &category, const std::stri
m_iLockMode = LOCK_MODE_EVERYONE;
m_strLockCode = "0";
m_iBadPwdCount = 0;
- m_iHasLock = 0;
+ m_iHasLock = LOCK_STATE_NO_LOCK;
m_allowSharing = true;
if (URIUtils::IsMultiPath(strPath))
diff --git a/xbmc/MediaSource.h b/xbmc/MediaSource.h
index ea14f9281e..1afbea2ac7 100644
--- a/xbmc/MediaSource.h
+++ b/xbmc/MediaSource.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005-2018 Team Kodi
+ * Copyright (C) 2005-2020 Team Kodi
* This file is part of Kodi - https://kodi.tv
*
* SPDX-License-Identifier: GPL-2.0-or-later
@@ -8,9 +8,11 @@
#pragma once
+#include "LockType.h"
+#include "media/MediaLockState.h"
+
#include <string>
#include <vector>
-#include "LockType.h"
/*!
\ingroup windows
@@ -78,7 +80,7 @@ public:
*/
LockType m_iLockMode = LOCK_MODE_EVERYONE;
std::string m_strLockCode; ///< Input code for Lock UI to verify, can be chosen freely.
- int m_iHasLock = 0;
+ int m_iHasLock = LOCK_STATE_NO_LOCK;
int m_iBadPwdCount = 0; ///< Number of wrong passwords user has entered since share was last unlocked
std::string m_strThumbnailImage; ///< Path to a thumbnail image for the share, or blank for default
diff --git a/xbmc/TextureCache.cpp b/xbmc/TextureCache.cpp
index aebac145b1..1d832c10af 100644
--- a/xbmc/TextureCache.cpp
+++ b/xbmc/TextureCache.cpp
@@ -7,18 +7,19 @@
*/
#include "TextureCache.h"
+#include "ServiceBroker.h"
#include "TextureCacheJob.h"
+#include "URL.h"
#include "filesystem/File.h"
+#include "guilib/Texture.h"
#include "profiles/ProfileManager.h"
-#include "threads/SingleLock.h"
-#include "utils/Crc32.h"
#include "settings/AdvancedSettings.h"
#include "settings/SettingsComponent.h"
-#include "utils/log.h"
-#include "utils/URIUtils.h"
+#include "threads/SingleLock.h"
+#include "utils/Crc32.h"
#include "utils/StringUtils.h"
-#include "URL.h"
-#include "ServiceBroker.h"
+#include "utils/URIUtils.h"
+#include "utils/log.h"
using namespace XFILE;
@@ -161,7 +162,20 @@ std::string CTextureCache::CacheImage(const std::string &image, CBaseTexture **t
CTextureDetails tempDetails;
if (!details)
details = &tempDetails;
- return GetCachedImage(url, *details, true);
+
+ std::string cachedpath = GetCachedImage(url, *details, true);
+ if (!cachedpath.empty())
+ {
+ if (texture)
+ *texture = CBaseTexture::LoadFromFile(cachedpath, 0, 0);
+ }
+ else
+ {
+ CLog::Log(LOGDEBUG, "CTextureCache::%s - Return NULL texture because cache is not ready",
+ __FUNCTION__);
+ }
+
+ return cachedpath;
}
bool CTextureCache::CacheImage(const std::string &image, CTextureDetails &details)
diff --git a/xbmc/addons/Addon.cpp b/xbmc/addons/Addon.cpp
index bcdefe3649..dd553fa252 100644
--- a/xbmc/addons/Addon.cpp
+++ b/xbmc/addons/Addon.cpp
@@ -161,9 +161,7 @@ void CAddon::SaveSettings(void)
// break down the path into directories
std::string strAddon = URIUtils::GetDirectory(m_userSettingsPath);
- URIUtils::RemoveSlashAtEnd(strAddon);
std::string strRoot = URIUtils::GetDirectory(strAddon);
- URIUtils::RemoveSlashAtEnd(strRoot);
// create the individual folders
if (!CDirectory::Exists(strRoot))
diff --git a/xbmc/addons/binary-addons/AddonDll.cpp b/xbmc/addons/binary-addons/AddonDll.cpp
index 2fb2c2cd84..730c405766 100644
--- a/xbmc/addons/binary-addons/AddonDll.cpp
+++ b/xbmc/addons/binary-addons/AddonDll.cpp
@@ -487,8 +487,11 @@ bool CAddonDll::CheckAPIVersion(int type)
addonMinVersion.asString(),
addonVersion.asString());
- CEventLog &eventLog = CServiceBroker::GetEventLog();
- eventLog.AddWithNotification(EventPtr(new CNotificationEvent(Name(), 24152, EventLevel::Error)));
+ if (CServiceBroker::GetGUI())
+ {
+ CEventLog &eventLog = CServiceBroker::GetEventLog();
+ eventLog.AddWithNotification(EventPtr(new CNotificationEvent(Name(), 24152, EventLevel::Error)));
+ }
return false;
}
diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/Inputstream.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/Inputstream.h
index a5377dec44..252edbf74e 100644
--- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/Inputstream.h
+++ b/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/Inputstream.h
@@ -26,8 +26,6 @@
namespace kodi { namespace addon { class CInstanceInputStream; }}
extern "C" {
-//Increment this level always if you add features which can lead to compile failures in the addon
-#define INPUTSTREAM_VERSION_LEVEL 2
/*!
* @brief InputStream add-on capabilities. All capabilities are set to "false" as default.
@@ -52,10 +50,7 @@ extern "C" {
SUPPORTS_PAUSE = (1 << 4),
/// supports interface ITime
- SUPPORTS_ITIME = (1 << 5),
-
- /// supports interface IChapter
- SUPPORTS_ICHAPTER = (1 << 6),
+ SUPPORTS_ITIME = (1 << 5)
};
/// set of supported capabilities
@@ -254,13 +249,6 @@ extern "C" {
int64_t (__cdecl* length_stream)(const AddonInstance_InputStream* instance);
void (__cdecl* pause_stream)(const AddonInstance_InputStream* instance, double time);
bool (__cdecl* is_real_time_stream)(const AddonInstance_InputStream* instance);
-
- // IChapter
- int(__cdecl* get_chapter)(const AddonInstance_InputStream* instance);
- int(__cdecl* get_chapter_count)(const AddonInstance_InputStream* instance);
- const char*(__cdecl* get_chapter_name)(const AddonInstance_InputStream* instance, int ch);
- int64_t(__cdecl* get_chapter_pos)(const AddonInstance_InputStream* instance, int ch);
- bool(__cdecl* seek_chapter)(const AddonInstance_InputStream* instance, int ch);
} KodiToAddonFuncTable_InputStream;
typedef struct AddonInstance_InputStream /* internal */
@@ -280,13 +268,13 @@ namespace addon
class CInstanceInputStream : public IAddonInstance
{
public:
- explicit CInstanceInputStream(KODI_HANDLE instance, const std::string& kodiVersion = "0.0.0")
+ explicit CInstanceInputStream(KODI_HANDLE instance)
: IAddonInstance(ADDON_INSTANCE_INPUTSTREAM)
{
if (CAddonBase::m_interface->globalSingleInstance != nullptr)
- throw std::logic_error("kodi::addon::CInstanceInputStream: Creation of multiple together "
- "with single instance way is not allowed!");
- SetAddonStruct(instance, kodiVersion);
+ throw std::logic_error("kodi::addon::CInstanceInputStream: Creation of multiple together with single instance way is not allowed!");
+
+ SetAddonStruct(instance);
}
~CInstanceInputStream() override = default;
@@ -422,6 +410,7 @@ namespace addon
*/
virtual bool PosTime(int ms) { return false; }
+
/*!
* Check if the backend support pausing the currently playing stream
* This will enable/disable the pause button in Kodi based on the return value
@@ -472,35 +461,6 @@ namespace addon
*/
virtual void PauseStream(double time) { }
- /*!
- * Return currently selected chapter
- * @remarks
- */
- virtual int GetChapter() { return -1; };
-
- /*!
- * Return number of available chapters
- * @remarks
- */
- virtual int GetChapterCount() { return 0; };
-
- /*!
- * Return name of chapter # ch
- * @remarks
- */
- virtual const std::string GetChapterName(int ch) { return std::string(); };
-
- /*!
- * Return position if chapter # ch in milliseconds
- * @remarks
- */
- virtual int64_t GetChapterPos(int ch) { return 0; };
-
- /*!
- * Seek to the beginning of chapter # ch
- * @remarks
- */
- virtual bool SeekChapter(int ch) { return false; };
/*!
* Check for real-time streaming
@@ -538,13 +498,10 @@ namespace addon
}
private:
- void SetAddonStruct(KODI_HANDLE instance, const std::string& kodiVersion)
+ void SetAddonStruct(KODI_HANDLE instance)
{
if (instance == nullptr)
- throw std::logic_error("kodi::addon::CInstanceInputStream: Creation with empty addon "
- "structure not allowed, table must be given from Kodi!");
- int api[3] = { 0, 0, 0 };
- sscanf(kodiVersion.c_str(), "%d.%d.%d", &api[0], &api[1], &api[2]);
+ throw std::logic_error("kodi::addon::CInstanceInputStream: Creation with empty addon structure not allowed, table must be given from Kodi!");
m_instanceData = static_cast<AddonInstance_InputStream*>(instance);
m_instanceData->toAddon.addonInstance = this;
@@ -580,16 +537,6 @@ namespace addon
m_instanceData->toAddon.length_stream = ADDON_LengthStream;
m_instanceData->toAddon.pause_stream = ADDON_PauseStream;
m_instanceData->toAddon.is_real_time_stream = ADDON_IsRealTimeStream;
-
- int minChapterVersion[3] = { 2, 0, 10 };
- if (compareVersion(api, minChapterVersion) >= 0)
- {
- m_instanceData->toAddon.get_chapter = ADDON_GetChapter;
- m_instanceData->toAddon.get_chapter_count = ADDON_GetChapterCount;
- m_instanceData->toAddon.get_chapter_name = ADDON_GetChapterName;
- m_instanceData->toAddon.get_chapter_pos = ADDON_GetChapterPos;
- m_instanceData->toAddon.seek_chapter = ADDON_SeekChapter;
- }
}
inline static bool ADDON_Open(const AddonInstance_InputStream* instance, INPUTSTREAM* props)
@@ -664,14 +611,6 @@ namespace addon
instance->toAddon.addonInstance->SetVideoResolution(width, height);
}
-private:
- static int compareVersion(const int v1[3], const int v2[3])
- {
- for (unsigned i(0); i < 3; ++i)
- if (v1[i] != v2[i])
- return v1[i] - v2[i];
- return 0;
- }
// IDisplayTime
inline static int ADDON_GetTotalTime(const AddonInstance_InputStream* instance)
@@ -707,6 +646,7 @@ private:
return instance->toAddon.addonInstance->CanSeekStream();
}
+
inline static int ADDON_ReadStream(const AddonInstance_InputStream* instance, uint8_t* buffer, unsigned int bufferSize)
{
return instance->toAddon.addonInstance->ReadStream(buffer, bufferSize);
@@ -737,32 +677,8 @@ private:
return instance->toAddon.addonInstance->IsRealTimeStream();
}
- inline static int ADDON_GetChapter(const AddonInstance_InputStream* instance)
- {
- return instance->toAddon.addonInstance->GetChapter();
- }
-
- inline static int ADDON_GetChapterCount(const AddonInstance_InputStream* instance)
- {
- return instance->toAddon.addonInstance->GetChapterCount();
- }
-
- inline static const char* ADDON_GetChapterName(const AddonInstance_InputStream* instance, int ch)
- {
- return instance->toAddon.addonInstance->GetChapterName(ch).c_str();
- }
-
- inline static int64_t ADDON_GetChapterPos(const AddonInstance_InputStream* instance, int ch)
- {
- return instance->toAddon.addonInstance->GetChapterPos(ch);
- }
-
- inline static bool ADDON_SeekChapter(const AddonInstance_InputStream* instance, int ch)
- {
- return instance->toAddon.addonInstance->SeekChapter(ch);
- }
-
AddonInstance_InputStream* m_instanceData;
};
+
} /* namespace addon */
} /* namespace kodi */
diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/versions.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/versions.h
index 12782ec86b..06d75e02c5 100644
--- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/versions.h
+++ b/xbmc/addons/kodi-addon-dev-kit/include/kodi/versions.h
@@ -87,7 +87,7 @@
#define ADDON_INSTANCE_VERSION_IMAGEDECODER_XML_ID "kodi.binary.instance.imagedecoder"
#define ADDON_INSTANCE_VERSION_IMAGEDECODER_DEPENDS "addon-instance/ImageDecoder.h"
-#define ADDON_INSTANCE_VERSION_INPUTSTREAM "2.0.10"
+#define ADDON_INSTANCE_VERSION_INPUTSTREAM "2.0.8"
#define ADDON_INSTANCE_VERSION_INPUTSTREAM_MIN "2.0.7"
#define ADDON_INSTANCE_VERSION_INPUTSTREAM_XML_ID "kodi.binary.instance.inputstream"
#define ADDON_INSTANCE_VERSION_INPUTSTREAM_DEPENDS "addon-instance/Inputstream.h"
diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkAUDIOTRACK.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkAUDIOTRACK.cpp
index 0f3fadfa89..ff80aeb285 100644
--- a/xbmc/cores/AudioEngine/Sinks/AESinkAUDIOTRACK.cpp
+++ b/xbmc/cores/AudioEngine/Sinks/AESinkAUDIOTRACK.cpp
@@ -247,7 +247,6 @@ int CAESinkAUDIOTRACK::AudioTrackWrite(char* audioData, int sizeInBytes, int64_t
CAEDeviceInfo CAESinkAUDIOTRACK::m_info;
std::set<unsigned int> CAESinkAUDIOTRACK::m_sink_sampleRates;
bool CAESinkAUDIOTRACK::m_sinkSupportsFloat = false;
-bool CAESinkAUDIOTRACK::m_sinkSupportsMultiChannelFloat = false;
////////////////////////////////////////////////////////////////////////////////////////////
CAESinkAUDIOTRACK::CAESinkAUDIOTRACK()
@@ -378,12 +377,7 @@ bool CAESinkAUDIOTRACK::Initialize(AEAudioFormat &format, std::string &device)
{
m_passthrough = false;
m_format.m_sampleRate = m_sink_sampleRate;
- if (m_sinkSupportsMultiChannelFloat)
- {
- m_encoding = CJNIAudioFormat::ENCODING_PCM_FLOAT;
- m_format.m_dataFormat = AE_FMT_FLOAT;
- }
- else if (m_sinkSupportsFloat && m_format.m_channelLayout.Count() == 2)
+ if (m_sinkSupportsFloat && m_format.m_channelLayout.Count() == 2)
{
m_encoding = CJNIAudioFormat::ENCODING_PCM_FLOAT;
m_format.m_dataFormat = AE_FMT_FLOAT;
@@ -1009,10 +1003,6 @@ void CAESinkAUDIOTRACK::UpdateAvailablePCMCapabilities()
int encoding = CJNIAudioFormat::ENCODING_PCM_16BIT;
m_sinkSupportsFloat = VerifySinkConfiguration(native_sampleRate, CJNIAudioFormat::CHANNEL_OUT_STEREO, CJNIAudioFormat::ENCODING_PCM_FLOAT);
- // Only try for Android 7 or later - there are a lot of old devices that open successfully
- // but won't work correctly under the hood (famouse example: old FireTV)
- if (CJNIAudioManager::GetSDKVersion() > 23)
- m_sinkSupportsMultiChannelFloat = VerifySinkConfiguration(native_sampleRate, CJNIAudioFormat::CHANNEL_OUT_7POINT1_SURROUND, CJNIAudioFormat::ENCODING_PCM_FLOAT);
if (m_sinkSupportsFloat)
{
@@ -1020,10 +1010,6 @@ void CAESinkAUDIOTRACK::UpdateAvailablePCMCapabilities()
m_info.m_dataFormats.push_back(AE_FMT_FLOAT);
CLog::Log(LOGNOTICE, "Float is supported");
}
- if (m_sinkSupportsMultiChannelFloat)
- {
- CLog::Log(LOGNOTICE, "Multi channel Float is supported");
- }
// Still AML API 21 and 22 get hardcoded samplerates - we can drop that
// when we stop supporting API < 23 - let's only add the default
diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkAUDIOTRACK.h b/xbmc/cores/AudioEngine/Sinks/AESinkAUDIOTRACK.h
index 647ca62d47..187257c174 100644
--- a/xbmc/cores/AudioEngine/Sinks/AESinkAUDIOTRACK.h
+++ b/xbmc/cores/AudioEngine/Sinks/AESinkAUDIOTRACK.h
@@ -75,7 +75,6 @@ private:
static CAEDeviceInfo m_info;
static std::set<unsigned int> m_sink_sampleRates;
static bool m_sinkSupportsFloat;
- static bool m_sinkSupportsMultiChannelFloat;
AEAudioFormat m_format;
double m_volume;
diff --git a/xbmc/cores/RetroPlayer/rendering/VideoRenderers/RPRendererGuiTexture.cpp b/xbmc/cores/RetroPlayer/rendering/VideoRenderers/RPRendererGuiTexture.cpp
index 5485358cad..ad2bf1b984 100644
--- a/xbmc/cores/RetroPlayer/rendering/VideoRenderers/RPRendererGuiTexture.cpp
+++ b/xbmc/cores/RetroPlayer/rendering/VideoRenderers/RPRendererGuiTexture.cpp
@@ -17,6 +17,8 @@
using namespace DirectX;
#endif
+#include <cstddef>
+
using namespace KODI;
using namespace RETRO;
diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.cpp
index 2a27108fc9..8fe20cabbd 100644
--- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.cpp
+++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.cpp
@@ -18,19 +18,19 @@
#include <memory>
#include <vector>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
#include <androidjni/ByteBuffer.h>
-#include <androidjni/MediaCodecList.h>
+#include <androidjni/MediaCodec.h>
+#include <androidjni/MediaCodecBufferInfo.h>
+#include <androidjni/MediaCodecCryptoInfo.h>
#include <androidjni/MediaCodecInfo.h>
+#include <androidjni/MediaCodecList.h>
#include <androidjni/MediaCrypto.h>
#include <androidjni/Surface.h>
#include <androidjni/SurfaceTexture.h>
#include <androidjni/UUID.h>
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
-
-#include <media/NdkMediaCrypto.h>
-
#include "Application.h"
#include "DVDCodecs/DVDFactoryCodec.h"
#include "platform/android/activity/XBMCApp.h"
@@ -126,19 +126,6 @@ private:
/*****************************************************************************/
/*****************************************************************************/
-CMediaCodec::CMediaCodec(const char *name)
- : m_codec(AMediaCodec_createCodecByName(name))
-{
-}
-
-CMediaCodec::~CMediaCodec()
-{
- AMediaCodec_delete(m_codec);
-};
-
-
-/*****************************************************************************/
-/*****************************************************************************/
void CMediaCodecVideoBuffer::Set(int bufferId, int textureId,
std::shared_ptr<CJNISurfaceTexture> surfacetexture,
std::shared_ptr<CDVDMediaCodecOnFrameAvailable> frameready,
@@ -158,7 +145,8 @@ bool CMediaCodecVideoBuffer::WaitForFrame(int millis)
void CMediaCodecVideoBuffer::ReleaseOutputBuffer(bool render, int64_t displayTime, CMediaCodecVideoBufferPool* pool)
{
- std::shared_ptr<CMediaCodec> codec(static_cast<CMediaCodecVideoBufferPool*>(pool ? pool : m_pool.get())->GetMediaCodec());
+ std::shared_ptr<CJNIMediaCodec> codec(
+ static_cast<CMediaCodecVideoBufferPool*>(pool ? pool : m_pool.get())->GetMediaCodec());
if (m_bufferId < 0 || !codec)
return;
@@ -176,15 +164,17 @@ void CMediaCodecVideoBuffer::ReleaseOutputBuffer(bool render, int64_t displayTim
CLog::Log(LOGDEBUG, "CMediaCodecVideoBuffer::ReleaseOutputBuffer index(%d), render(%d), time:%lld, offset:%lld", m_bufferId, render, displayTime, diff);
}
- media_status_t mstat;
if (!render || displayTime == 0)
- mstat = AMediaCodec_releaseOutputBuffer(codec->codec(), m_bufferId, render);
+ codec->releaseOutputBuffer(m_bufferId, render);
else
- mstat = AMediaCodec_releaseOutputBufferAtTime(codec->codec(), m_bufferId, displayTime);
+ codec->releaseOutputBuffer(m_bufferId, displayTime);
m_bufferId = -1; //mark released
- if (mstat != AMEDIA_OK)
- CLog::Log(LOGERROR, "CMediaCodecVideoBuffer::ReleaseOutputBuffer error %d in render(%d)", mstat, render);
+ if (xbmc_jnienv()->ExceptionCheck())
+ {
+ xbmc_jnienv()->ExceptionClear();
+ CLog::Log(LOGERROR, "CMediaCodecVideoBuffer::ReleaseOutputBuffer error in render(%d)", render);
+ }
}
int CMediaCodecVideoBuffer::GetBufferId() const
@@ -292,7 +282,7 @@ void CMediaCodecVideoBufferPool::Return(int id)
m_freeBuffers.push_back(id);
}
-std::shared_ptr<CMediaCodec> CMediaCodecVideoBufferPool::GetMediaCodec()
+std::shared_ptr<CJNIMediaCodec> CMediaCodecVideoBufferPool::GetMediaCodec()
{
CSingleLock lock(m_criticalSection);
return m_codec;
@@ -322,9 +312,7 @@ CDVDVideoCodecAndroidMediaCodec::CDVDVideoCodecAndroidMediaCodec(CProcessInfo &p
, m_opened(false)
, m_jnivideoview(nullptr)
, m_jnisurface(nullptr)
-, m_crypto(nullptr)
, m_textureId(0)
-, m_surface(nullptr)
, m_OutputDuration(0)
, m_fpsDuration(0)
, m_lastPTS(-1)
@@ -343,7 +331,7 @@ CDVDVideoCodecAndroidMediaCodec::~CDVDVideoCodecAndroidMediaCodec()
if (m_crypto)
{
- AMediaCrypto_delete(m_crypto);
+ delete m_crypto;
m_crypto = nullptr;
}
if (m_mpeg2_sequence)
@@ -370,12 +358,7 @@ bool CDVDVideoCodecAndroidMediaCodec::Open(CDVDStreamInfo &hints, CDVDCodecOptio
{
int num_codecs;
int profile(0);
-
- const AMediaUUID* uuid(nullptr);
- const AMediaUUID wvuuid = {0xED, 0xEF, 0x8B, 0xA9, 0x79, 0xD6, 0x4A, 0xCE,
- 0xA3, 0xC8, 0x27, 0xDC, 0xD5, 0x1D, 0x21, 0xED};
- const AMediaUUID pruuid = {0x9A, 0x04, 0xF0, 0x79, 0x98, 0x40, 0x42, 0x86,
- 0xAB, 0x92, 0xE6, 0x5B, 0xE0, 0x88, 0x5F, 0x95};
+ CJNIUUID uuid(0, 0);
m_opened = false;
m_needSecureDecoder = false;
@@ -498,8 +481,16 @@ bool CDVDVideoCodecAndroidMediaCodec::Open(CDVDStreamInfo &hints, CDVDCodecOptio
}
break;
case AV_CODEC_ID_HEVC:
- m_mime = "video/hevc";
- m_formatname = "amc-h265";
+ if (m_hints.codec_tag == MKTAG('d', 'v', 'h', 'e'))
+ {
+ m_mime = "video/dolby-vision";
+ m_formatname = "amc-dvhe";
+ }
+ else
+ {
+ m_mime = "video/hevc";
+ m_formatname = "amc-hevc";
+ }
// check for hevc-hvcC and convert to h265-annex-b
if (m_hints.extradata && !m_hints.cryptoSession)
{
@@ -574,32 +565,25 @@ bool CDVDVideoCodecAndroidMediaCodec::Open(CDVDStreamInfo &hints, CDVDCodecOptio
if (m_crypto)
{
- AMediaCrypto_delete(m_crypto);
+ delete m_crypto;
m_crypto = nullptr;
}
if (m_hints.cryptoSession)
{
if (m_hints.cryptoSession->keySystem == CRYPTO_SESSION_SYSTEM_WIDEVINE)
- uuid = &wvuuid;
+ uuid = CJNIUUID(0xEDEF8BA979D64ACE, 0xA3C827DCD51D21ED);
else if (m_hints.cryptoSession->keySystem == CRYPTO_SESSION_SYSTEM_PLAYREADY)
- uuid = &pruuid;
+ uuid = CJNIUUID(0x9A04F07998404286, 0xAB92E65BE0885F95);
else
{
CLog::Log(LOGERROR, "CDVDVideoCodecAndroidMediaCodec::Open Unsupported crypto-keysystem %u",
m_hints.cryptoSession->keySystem);
goto FAIL;
}
-
- int64_t mostSigBits(0), leastSigBits(0);
- for (unsigned int i(0); i < 8; ++i)
- mostSigBits = (mostSigBits << 8) | (*uuid)[i];
- for (unsigned int i(8); i < 16; ++i)
- leastSigBits = (leastSigBits << 8) | (*uuid)[i];
- CJNIUUID juuid(mostSigBits, leastSigBits);
- CJNIMediaCrypto crypto(juuid, std::vector<char>(m_hints.cryptoSession->sessionId,
- m_hints.cryptoSession->sessionId +
- m_hints.cryptoSession->sessionIdSize));
+ CJNIMediaCrypto crypto(uuid, std::vector<char>(m_hints.cryptoSession->sessionId,
+ m_hints.cryptoSession->sessionId +
+ m_hints.cryptoSession->sessionIdSize));
m_needSecureDecoder =
crypto.requiresSecureDecoderComponent(m_mime) &&
(m_hints.cryptoSession->flags & DemuxCryptoSession::FLAG_SECURE_DECODER) != 0;
@@ -667,8 +651,9 @@ bool CDVDVideoCodecAndroidMediaCodec::Open(CDVDStreamInfo &hints, CDVDCodecOptio
{
if (types[j] == m_mime)
{
- m_codec = std::shared_ptr<CMediaCodec>(new CMediaCodec(m_codecname.c_str()));
- if (!m_codec->codec())
+ m_codec = std::shared_ptr<CJNIMediaCodec>(
+ new CJNIMediaCodec(CJNIMediaCodec::createByCodecName(m_codecname)));
+ if (!m_codec)
{
CLog::Log(LOGERROR, "CDVDVideoCodecAndroidMediaCodec::Open cannot create codec");
continue;
@@ -684,7 +669,7 @@ bool CDVDVideoCodecAndroidMediaCodec::Open(CDVDStreamInfo &hints, CDVDCodecOptio
break;
}
}
- if (m_codec->codec())
+ if (m_codec)
break;
}
if (!m_codec)
@@ -697,7 +682,10 @@ bool CDVDVideoCodecAndroidMediaCodec::Open(CDVDStreamInfo &hints, CDVDCodecOptio
{
CLog::Log(LOGDEBUG, "CDVDVideoCodecAndroidMediaCodec::Open Initializing MediaCrypto");
- m_crypto = AMediaCrypto_new(*uuid, m_hints.cryptoSession->sessionId, m_hints.cryptoSession->sessionIdSize);
+ m_crypto =
+ new CJNIMediaCrypto(uuid, std::vector<char>(m_hints.cryptoSession->sessionId,
+ m_hints.cryptoSession->sessionId +
+ m_hints.cryptoSession->sessionIdSize));
if (!m_crypto)
{
@@ -757,7 +745,7 @@ FAIL:
m_InstanceGuard.exchange(false);
if (m_crypto)
{
- AMediaCrypto_delete(m_crypto);
+ delete m_crypto;
m_crypto = nullptr;
}
@@ -790,17 +778,17 @@ void CDVDVideoCodecAndroidMediaCodec::Dispose()
m_videobuffer.iFlags = 0;
- if (m_codec->codec())
+ if (m_codec)
{
- AMediaCodec_stop(m_codec->codec());
+ m_codec->stop();
m_codec = nullptr;
m_state = MEDIACODEC_STATE_STOPPED;
}
ReleaseSurfaceTexture();
- if(m_surface)
- ANativeWindow_release(m_surface);
- m_surface = nullptr;
+ if (m_jnisurface)
+ m_jnisurface->release();
+ m_jnisurface = nullptr;
m_InstanceGuard.exchange(false);
if (m_render_surface)
@@ -836,7 +824,7 @@ bool CDVDVideoCodecAndroidMediaCodec::AddData(const DemuxPacket &packet)
{
// We received a packet but already reached EOS. Flush...
FlushInternal();
- AMediaCodec_flush(m_codec->codec());
+ m_codec->flush();
m_state = MEDIACODEC_STATE_FLUSHED;
}
@@ -877,26 +865,31 @@ bool CDVDVideoCodecAndroidMediaCodec::AddData(const DemuxPacket &packet)
if (m_state == MEDIACODEC_STATE_FLUSHED)
m_state = MEDIACODEC_STATE_RUNNING;
- size_t out_size;
- uint8_t* dst_ptr = AMediaCodec_getInputBuffer(m_codec->codec(), m_indexInputBuffer, &out_size);
+ CJNIByteBuffer buffer = m_codec->getInputBuffer(m_indexInputBuffer);
+ size_t out_size = buffer.capacity();
if ((size_t)iSize > out_size)
{
CLog::Log(LOGERROR, "CDVDVideoCodecAndroidMediaCodec::AddData, iSize(%d) > size(%d)", iSize, out_size);
iSize = out_size;
}
+ uint8_t* dst_ptr = (uint8_t*)xbmc_jnienv()->GetDirectBufferAddress(buffer.get_raw());
- AMediaCodecCryptoInfo *cryptoInfo(0);
+ CJNIMediaCodecCryptoInfo* cryptoInfo(nullptr);
if (m_crypto && packet.cryptoInfo)
{
- std::vector<size_t> clearBytes(packet.cryptoInfo->clearBytes, packet.cryptoInfo->clearBytes + packet.cryptoInfo->numSubSamples);
- std::vector<size_t> cipherBytes(packet.cryptoInfo->cipherBytes, packet.cryptoInfo->cipherBytes + packet.cryptoInfo->numSubSamples);
-
- cryptoInfo = AMediaCodecCryptoInfo_new(
- packet.cryptoInfo->numSubSamples,
- packet.cryptoInfo->kid,
- packet.cryptoInfo->iv,
- AMEDIACODECRYPTOINFO_MODE_AES_CTR,
- &clearBytes[0], &cipherBytes[0]);
+ std::vector<int> clearBytes(packet.cryptoInfo->clearBytes,
+ packet.cryptoInfo->clearBytes +
+ packet.cryptoInfo->numSubSamples);
+ std::vector<int> cipherBytes(packet.cryptoInfo->cipherBytes,
+ packet.cryptoInfo->cipherBytes +
+ packet.cryptoInfo->numSubSamples);
+
+ cryptoInfo = new CJNIMediaCodecCryptoInfo();
+
+ cryptoInfo->set(packet.cryptoInfo->numSubSamples, clearBytes, cipherBytes,
+ std::vector<char>(packet.cryptoInfo->kid, packet.cryptoInfo->kid + 16),
+ std::vector<char>(packet.cryptoInfo->iv, packet.cryptoInfo->iv + 16),
+ CJNIMediaCodec::CRYPTO_MODE_AES_CTR);
}
if (dst_ptr)
{
@@ -949,18 +942,19 @@ bool CDVDVideoCodecAndroidMediaCodec::AddData(const DemuxPacket &packet)
int flags = 0;
int offset = 0;
- media_status_t mstat;
if (!cryptoInfo)
- mstat = AMediaCodec_queueInputBuffer(m_codec->codec(), m_indexInputBuffer, offset, iSize, presentationTimeUs, flags);
+ m_codec->queueInputBuffer(m_indexInputBuffer, offset, iSize, presentationTimeUs, flags);
else
{
- mstat = AMediaCodec_queueSecureInputBuffer(m_codec->codec(), m_indexInputBuffer, offset, cryptoInfo, presentationTimeUs, flags);
- AMediaCodecCryptoInfo_delete(cryptoInfo);
+ m_codec->queueSecureInputBuffer(m_indexInputBuffer, offset, *cryptoInfo, presentationTimeUs,
+ flags);
+ delete cryptoInfo, cryptoInfo = nullptr;
}
- if (mstat != AMEDIA_OK)
+ if (xbmc_jnienv()->ExceptionCheck())
{
- CLog::Log(LOGERROR, "CDVDVideoCodecAndroidMediaCodec::AddData error(%d)", mstat);
- return false;
+ xbmc_jnienv()->ExceptionDescribe();
+ xbmc_jnienv()->ExceptionClear();
+ CLog::Log(LOGERROR, "CDVDVideoCodecAndroidMediaCodec::AddData error");
}
m_indexInputBuffer = -1;
}
@@ -975,7 +969,7 @@ void CDVDVideoCodecAndroidMediaCodec::Reset()
if (!m_opened)
return;
- if (m_codec->codec())
+ if (m_codec)
{
// flush all outputbuffers inflight, they will
// become invalid on m_codec->flush and generate
@@ -985,9 +979,10 @@ void CDVDVideoCodecAndroidMediaCodec::Reset()
// now we can flush the actual MediaCodec object
CLog::Log(LOGDEBUG, "CDVDVideoCodecAndroidMediaCodec::Reset Current state (%d)", m_state);
m_state = MEDIACODEC_STATE_FLUSHED;
- AMediaCodec_flush(m_codec->codec());
+ m_codec->flush();
- InjectExtraData(nullptr);
+ CJNIMediaFormat mediaFormat = m_codec->getOutputFormat();
+ InjectExtraData(mediaFormat);
// Invalidate our local VideoPicture bits
m_videobuffer.pts = DVD_NOPTS_VALUE;
@@ -1046,7 +1041,7 @@ CDVDVideoCodec::VCReturn CDVDVideoCodecAndroidMediaCodec::GetPicture(VideoPictur
{
// try to fetch an input buffer
if (m_indexInputBuffer < 0)
- m_indexInputBuffer = AMediaCodec_dequeueInputBuffer(m_codec->codec(), 5000 /*timout*/);
+ m_indexInputBuffer = m_codec->dequeueInputBuffer(5000 /*timout*/);
if (m_indexInputBuffer >= 0)
{
@@ -1083,7 +1078,7 @@ void CDVDVideoCodecAndroidMediaCodec::FlushInternal()
void CDVDVideoCodecAndroidMediaCodec::SignalEndOfStream()
{
CLog::Log(LOGDEBUG, "CDVDVideoCodecAndroidMediaCodec::%s: state: %d", __func__, m_state);
- if (m_codec->codec() && (m_state == MEDIACODEC_STATE_RUNNING || m_state == MEDIACODEC_STATE_ENDOFSTREAM))
+ if (m_codec && (m_state == MEDIACODEC_STATE_RUNNING || m_state == MEDIACODEC_STATE_ENDOFSTREAM))
{
// Release all mediaodec output buffers to allow drain if we don't get inputbuffer early
if (m_videoBufferPool)
@@ -1093,67 +1088,71 @@ void CDVDVideoCodecAndroidMediaCodec::SignalEndOfStream()
}
if (m_indexInputBuffer < 0)
- m_indexInputBuffer = AMediaCodec_dequeueInputBuffer(m_codec->codec(), 100000);
+ m_indexInputBuffer = m_codec->dequeueInputBuffer(100000);
+ xbmc_jnienv()->ExceptionClear();
if (m_indexInputBuffer >= 0)
{
- media_status_t status= AMediaCodec_queueInputBuffer(m_codec->codec(), m_indexInputBuffer, 0, 0, 0, AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM);
- if (status == AMEDIA_OK)
+ m_codec->queueInputBuffer(m_indexInputBuffer, 0, 0, 0,
+ CJNIMediaCodec::BUFFER_FLAG_END_OF_STREAM);
+ if (xbmc_jnienv()->ExceptionCheck())
+ {
+ xbmc_jnienv()->ExceptionClear();
+ CLog::Log(LOGWARNING, "CDVDVideoCodecAndroidMediaCodec::%s: queueInputBuffer failed",
+ __func__);
+ }
+ else
{
m_indexInputBuffer = -1;
CLog::Log(LOGDEBUG, "CDVDVideoCodecAndroidMediaCodec::%s: BUFFER_FLAG_END_OF_STREAM send", __func__);
}
- else
- CLog::Log(LOGWARNING, "CDVDVideoCodecAndroidMediaCodec::%s: AMediaCodec_queueInputBuffer returned: %d", __func__, status);
}
else
CLog::Log(LOGWARNING, "CDVDVideoCodecAndroidMediaCodec::%s: invalid index: %d", __func__, m_indexInputBuffer);
}
}
-void CDVDVideoCodecAndroidMediaCodec::InjectExtraData(AMediaFormat* mediaformat)
+void CDVDVideoCodecAndroidMediaCodec::InjectExtraData(CJNIMediaFormat& mediaformat)
{
if (!m_hints.extrasize)
return;
- if (!mediaformat && m_codec->codec())
- mediaformat = AMediaCodec_getOutputFormat(m_codec->codec());
-
- if (mediaformat)
+ CLog::Log(LOGDEBUG, "CDVDVideoCodecAndroidMediaCodec::%s", __func__);
+ size_t size = m_hints.extrasize;
+ void* src_ptr = m_hints.extradata;
+ if (m_bitstream)
{
- CLog::Log(LOGDEBUG, "CDVDVideoCodecAndroidMediaCodec::%s", __func__);
- size_t size = m_hints.extrasize;
- void *src_ptr = m_hints.extradata;
- if (m_bitstream)
- {
- size = m_bitstream->GetExtraSize();
- src_ptr = m_bitstream->GetExtraData();
- }
-
- AMediaFormat_setBuffer(mediaformat, "csd-0", src_ptr, size);
+ size = m_bitstream->GetExtraSize();
+ src_ptr = m_bitstream->GetExtraData();
}
+ // Allocate a byte buffer via allocateDirect in java instead of NewDirectByteBuffer,
+ // since the latter doesn't allocate storage of its own, and we don't know how long
+ // the codec uses the buffer.
+ CJNIByteBuffer bytebuffer = CJNIByteBuffer::allocateDirect(size);
+ void* dts_ptr = xbmc_jnienv()->GetDirectBufferAddress(bytebuffer.get_raw());
+ memcpy(dts_ptr, src_ptr, size);
+ // codec will automatically handle buffers as extradata
+ // using entries with keys "csd-0", "csd-1", etc.
+ mediaformat.setByteBuffer("csd-0", bytebuffer);
}
bool CDVDVideoCodecAndroidMediaCodec::ConfigureMediaCodec(void)
{
// setup a MediaFormat to match the video content,
// used by codec during configure
- AMediaFormat* mediaformat = AMediaFormat_new();
- AMediaFormat_setString(mediaformat, AMEDIAFORMAT_KEY_MIME, m_mime.c_str());
- AMediaFormat_setInt32(mediaformat, AMEDIAFORMAT_KEY_WIDTH, m_hints.width);
- AMediaFormat_setInt32(mediaformat, AMEDIAFORMAT_KEY_HEIGHT, m_hints.height);
- AMediaFormat_setInt32(mediaformat, AMEDIAFORMAT_KEY_MAX_INPUT_SIZE, 0);
+ CJNIMediaFormat mediaformat =
+ CJNIMediaFormat::createVideoFormat(m_mime.c_str(), m_hints.width, m_hints.height);
+ mediaformat.setInteger(CJNIMediaFormat::KEY_MAX_INPUT_SIZE, 0);
if (CJNIBase::GetSDKVersion() >= 23 && m_render_surface)
{
// Handle rotation
- AMediaFormat_setInt32(mediaformat, XMEDIAFORMAT_KEY_ROTATION, m_hints.orientation);
- AMediaFormat_setInt32(mediaformat, XMEDIAFORMAT_FEATURE_TUNNELED_PLAYBACK, 0);
+ mediaformat.setInteger(XMEDIAFORMAT_KEY_ROTATION, m_hints.orientation);
+ mediaformat.setInteger(XMEDIAFORMAT_FEATURE_TUNNELED_PLAYBACK, 0);
if (m_needSecureDecoder)
- AMediaFormat_setInt32(mediaformat, XMEDIAFORMAT_FEATURE_SECURE_PLAYBACK, 1);
+ mediaformat.setInteger(XMEDIAFORMAT_FEATURE_SECURE_PLAYBACK, 1);
}
-
// handle codec extradata
InjectExtraData(mediaformat);
@@ -1167,8 +1166,6 @@ bool CDVDVideoCodecAndroidMediaCodec::ConfigureMediaCodec(void)
m_jnivideoview.reset();
return false;
}
- m_surface = ANativeWindow_fromSurface(xbmc_jnienv(), m_jnivideosurface.get_raw());
-
m_formatname += "(S)";
}
else
@@ -1179,19 +1176,26 @@ bool CDVDVideoCodecAndroidMediaCodec::ConfigureMediaCodec(void)
// use a null MediaCrypto, our content is not encrypted.
int flags = 0;
- media_status_t mstat = AMediaCodec_configure(m_codec->codec(), mediaformat, m_surface, m_crypto, flags);
+ m_codec->configure(mediaformat, m_jnivideosurface,
+ m_crypto ? *m_crypto : CJNIMediaCrypto(jni::jhobject(NULL)), flags);
- if (mstat != AMEDIA_OK)
+ if (xbmc_jnienv()->ExceptionCheck())
{
- CLog::Log(LOGERROR, "CDVDVideoCodecAndroidMediaCodec configure error: %d", mstat);
+ xbmc_jnienv()->ExceptionClear();
+ CLog::Log(LOGERROR, "CDVDVideoCodecAndroidMediaCodec configure error");
return false;
}
+ m_codec->setVideoScalingMode(CJNIMediaCodec::VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING);
+
m_state = MEDIACODEC_STATE_CONFIGURED;
- mstat = AMediaCodec_start(m_codec->codec());
- if (mstat != AMEDIA_OK)
+ m_codec->start();
+
+ if (xbmc_jnienv()->ExceptionCheck())
{
- CLog::Log(LOGERROR, "CDVDVideoCodecAndroidMediaCodec start error: %d", mstat);
+ xbmc_jnienv()->ExceptionClear();
+ Dispose();
+ CLog::Log(LOGERROR, "CDVDVideoCodecAndroidMediaCodec start error");
return false;
}
m_state = MEDIACODEC_STATE_FLUSHED;
@@ -1208,11 +1212,11 @@ int CDVDVideoCodecAndroidMediaCodec::GetOutputPicture(void)
int rtn = 0;
int64_t timeout_us = 10000;
- AMediaCodecBufferInfo bufferInfo;
- ssize_t index = AMediaCodec_dequeueOutputBuffer(m_codec->codec(), &bufferInfo, timeout_us);
+ CJNIMediaCodecBufferInfo bufferInfo;
+ ssize_t index = m_codec->dequeueOutputBuffer(bufferInfo, timeout_us);
if (index >= 0)
{
- int64_t pts = bufferInfo.presentationTimeUs;
+ int64_t pts = bufferInfo.presentationTimeUs();
m_videobuffer.dts = DVD_NOPTS_VALUE;
m_videobuffer.pts = DVD_NOPTS_VALUE;
if (pts != AV_NOPTS_VALUE)
@@ -1227,14 +1231,15 @@ int CDVDVideoCodecAndroidMediaCodec::GetOutputPicture(void)
if (m_codecControlFlags & DVD_CODEC_CTRL_DROP)
{
m_noPictureLoop = 0;
- AMediaCodec_releaseOutputBuffer(m_codec->codec(), index, false);
+ m_codec->releaseOutputBuffer(index, false);
return -2;
}
- if (bufferInfo.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM)
+ int flags = bufferInfo.flags();
+ if (flags & CJNIMediaCodec::BUFFER_FLAG_END_OF_STREAM)
{
CLog::Log(LOGDEBUG, "CDVDVideoCodecAndroidMediaCodec:: BUFFER_FLAG_END_OF_STREAM");
- AMediaCodec_releaseOutputBuffer(m_codec->codec(), index, false);
+ m_codec->releaseOutputBuffer(index, false);
return -1;
}
@@ -1246,15 +1251,19 @@ int CDVDVideoCodecAndroidMediaCodec::GetOutputPicture(void)
rtn = 1;
}
- else if (index == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED)
+ else if (index == CJNIMediaCodec::INFO_OUTPUT_FORMAT_CHANGED)
{
- AMediaFormat* mediaformat = AMediaCodec_getOutputFormat(m_codec->codec());
- if (!mediaformat)
+ CJNIMediaFormat mediaformat = m_codec->getOutputFormat();
+ if (xbmc_jnienv()->ExceptionCheck())
+ {
+ xbmc_jnienv()->ExceptionClear();
CLog::Log(LOGERROR, "CDVDVideoCodecAndroidMediaCodec::GetOutputPicture(INFO_OUTPUT_FORMAT_CHANGED) ExceptionCheck: getOutputBuffers");
+ }
else
ConfigureOutputFormat(mediaformat);
}
- else if (index == AMEDIACODEC_INFO_TRY_AGAIN_LATER || index == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED)
+ else if (index == CJNIMediaCodec::INFO_TRY_AGAIN_LATER ||
+ index == CJNIMediaCodec::INFO_OUTPUT_BUFFERS_CHANGED)
{
// ignore
rtn = 0;
@@ -1269,7 +1278,7 @@ int CDVDVideoCodecAndroidMediaCodec::GetOutputPicture(void)
return rtn;
}
-void CDVDVideoCodecAndroidMediaCodec::ConfigureOutputFormat(AMediaFormat* mediaformat)
+void CDVDVideoCodecAndroidMediaCodec::ConfigureOutputFormat(CJNIMediaFormat& mediaformat)
{
int width = 0;
int height = 0;
@@ -1281,25 +1290,25 @@ void CDVDVideoCodecAndroidMediaCodec::ConfigureOutputFormat(AMediaFormat* mediaf
int crop_right = 0;
int crop_bottom = 0;
- int tmpVal;
- if (AMediaFormat_getInt32(mediaformat, AMEDIAFORMAT_KEY_WIDTH, &tmpVal))
- width = tmpVal;
- if (AMediaFormat_getInt32(mediaformat, AMEDIAFORMAT_KEY_HEIGHT, &tmpVal))
- height = tmpVal;
- if (AMediaFormat_getInt32(mediaformat, AMEDIAFORMAT_KEY_STRIDE, &tmpVal))
- stride = tmpVal;
- if (AMediaFormat_getInt32(mediaformat, XMEDIAFORMAT_KEY_SLICE, &tmpVal))
- slice_height = tmpVal;
- if (AMediaFormat_getInt32(mediaformat, AMEDIAFORMAT_KEY_COLOR_FORMAT, &tmpVal))
- color_format = tmpVal;
- if (AMediaFormat_getInt32(mediaformat, XMEDIAFORMAT_KEY_CROP_LEFT, &tmpVal))
- crop_left = tmpVal;
- if (AMediaFormat_getInt32(mediaformat, XMEDIAFORMAT_KEY_CROP_RIGHT, &tmpVal))
- crop_right = tmpVal;
- if (AMediaFormat_getInt32(mediaformat, XMEDIAFORMAT_KEY_CROP_TOP, &tmpVal))
- crop_top = tmpVal;
- if (AMediaFormat_getInt32(mediaformat, XMEDIAFORMAT_KEY_CROP_BOTTOM, &tmpVal))
- crop_bottom = tmpVal;
+ if (mediaformat.containsKey("width"))
+ width = mediaformat.getInteger("width");
+ if (mediaformat.containsKey("height"))
+ height = mediaformat.getInteger("height");
+ if (mediaformat.containsKey("stride"))
+ stride = mediaformat.getInteger("stride");
+ if (mediaformat.containsKey(XMEDIAFORMAT_KEY_SLICE))
+ slice_height = mediaformat.getInteger(XMEDIAFORMAT_KEY_SLICE);
+ if (mediaformat.containsKey("color-format"))
+ color_format = mediaformat.getInteger("color-format");
+ if (mediaformat.containsKey(XMEDIAFORMAT_KEY_CROP_LEFT))
+ crop_left = mediaformat.getInteger(XMEDIAFORMAT_KEY_CROP_LEFT);
+ if (mediaformat.containsKey(XMEDIAFORMAT_KEY_CROP_TOP))
+ crop_top = mediaformat.getInteger(XMEDIAFORMAT_KEY_CROP_TOP);
+ if (mediaformat.containsKey(XMEDIAFORMAT_KEY_CROP_RIGHT))
+ crop_right = mediaformat.getInteger(XMEDIAFORMAT_KEY_CROP_RIGHT);
+ if (mediaformat.containsKey(XMEDIAFORMAT_KEY_CROP_BOTTOM))
+ crop_bottom = mediaformat.getInteger(XMEDIAFORMAT_KEY_CROP_BOTTOM);
+
if (!crop_right)
crop_right = width-1;
@@ -1376,7 +1385,6 @@ void CDVDVideoCodecAndroidMediaCodec::InitSurfaceTexture(void)
// hook the surfaceTexture OnFrameAvailable callback
m_frameAvailable = std::shared_ptr<CDVDMediaCodecOnFrameAvailable>(new CDVDMediaCodecOnFrameAvailable(m_surfaceTexture));
m_jnisurface = new CJNISurface(*m_surfaceTexture);
- m_surface = ANativeWindow_fromSurface(xbmc_jnienv(), m_jnisurface->get_raw());
}
else
{
@@ -1439,8 +1447,8 @@ void CDVDVideoCodecAndroidMediaCodec::surfaceDestroyed(CJNISurfaceHolder holder)
if (m_state != MEDIACODEC_STATE_STOPPED && m_state != MEDIACODEC_STATE_UNINITIALIZED)
{
m_state = MEDIACODEC_STATE_STOPPED;
- if(m_surface)
- ANativeWindow_release(m_surface);
- AMediaCodec_stop(m_codec->codec());
+ if (m_jnisurface)
+ m_jnisurface->release();
+ m_codec->stop();
}
}
diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.h b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.h
index 6e25a13318..d07f7e1cff 100644
--- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.h
+++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.h
@@ -13,8 +13,6 @@
#include <memory>
#include <atomic>
-#include <androidjni/Surface.h>
-
#include "DVDVideoCodec.h"
#include "DVDStreamInfo.h"
#include "platform/android/activity/JNIXBMCVideoView.h"
@@ -23,19 +21,16 @@
#include "utils/Geometry.h"
#include "cores/VideoPlayer/Process/VideoBuffer.h"
-#include <media/NdkMediaCodec.h>
-#include <android/native_window.h>
-#include <android/native_window_jni.h>
-
class CJNISurface;
class CJNISurfaceTexture;
class CJNIMediaCodec;
+class CJNIMediaCrypto;
class CJNIMediaFormat;
+class CJNIMediaCodecBufferInfo;
class CDVDMediaCodecOnFrameAvailable;
class CJNIByteBuffer;
class CBitstreamConverter;
-struct AMediaCrypto;
struct DemuxCryptoInfo;
struct mpeg2_sequence;
@@ -47,16 +42,6 @@ typedef struct amc_demux {
double pts;
} amc_demux;
-struct CMediaCodec
-{
- CMediaCodec(const char *name);
- virtual ~CMediaCodec();
-
- AMediaCodec *codec() const { return m_codec; };
-private:
- AMediaCodec *m_codec;
-};
-
class CMediaCodecVideoBufferPool;
class CMediaCodecVideoBuffer : public CVideoBuffer
@@ -95,20 +80,21 @@ private:
class CMediaCodecVideoBufferPool : public IVideoBufferPool
{
public:
- CMediaCodecVideoBufferPool(std::shared_ptr<CMediaCodec> mediaCodec) : m_codec(mediaCodec) {};
+ CMediaCodecVideoBufferPool(std::shared_ptr<CJNIMediaCodec> mediaCodec)
+ : m_codec(mediaCodec){};
virtual ~CMediaCodecVideoBufferPool();
virtual CVideoBuffer* Get() override;
virtual void Return(int id) override;
- std::shared_ptr<CMediaCodec> GetMediaCodec();
+ std::shared_ptr<CJNIMediaCodec> GetMediaCodec();
void ResetMediaCodec();
void ReleaseMediaCodecBuffers();
private:
- CCriticalSection m_criticalSection;;
- std::shared_ptr<CMediaCodec> m_codec;
+ CCriticalSection m_criticalSection;
+ std::shared_ptr<CJNIMediaCodec> m_codec;
std::vector<CMediaCodecVideoBuffer*> m_videoBuffers;
std::vector<int> m_freeBuffers;
@@ -135,14 +121,14 @@ public:
virtual unsigned GetAllowedReferences() override;
protected:
- void Dispose();
- void FlushInternal(void);
- void SignalEndOfStream();
- void InjectExtraData(AMediaFormat* mediaformat);
- bool ConfigureMediaCodec(void);
- int GetOutputPicture(void);
- void ConfigureOutputFormat(AMediaFormat* mediaformat);
- void UpdateFpsDuration();
+ void Dispose();
+ void FlushInternal(void);
+ void SignalEndOfStream();
+ void InjectExtraData(CJNIMediaFormat& mediaformat);
+ bool ConfigureMediaCodec(void);
+ int GetOutputPicture(void);
+ void ConfigureOutputFormat(CJNIMediaFormat& mediaformat);
+ void UpdateFpsDuration();
// surface handling functions
static void CallbackInitSurfaceTexture(void*);
@@ -161,12 +147,11 @@ protected:
int m_noPictureLoop;
std::shared_ptr<CJNIXBMCVideoView> m_jnivideoview;
- CJNISurface* m_jnisurface;
- CJNISurface m_jnivideosurface;
- AMediaCrypto *m_crypto;
- unsigned int m_textureId;
- std::shared_ptr<CMediaCodec> m_codec;
- ANativeWindow* m_surface;
+ CJNISurface* m_jnisurface;
+ CJNISurface m_jnivideosurface;
+ unsigned int m_textureId;
+ std::shared_ptr<CJNIMediaCodec> m_codec;
+ CJNIMediaCrypto* m_crypto = nullptr;
std::shared_ptr<CJNISurfaceTexture> m_surfaceTexture;
std::shared_ptr<CDVDMediaCodecOnFrameAvailable> m_frameAvailable;
diff --git a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp
index f3432a859b..17df174488 100644
--- a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp
+++ b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp
@@ -537,6 +537,7 @@ void CDVDDemuxClient::SetStreamProps(CDemuxStream *stream, std::map<int, std::sh
toStream->uniqueId = stream->uniqueId;
toStream->codec = stream->codec;
toStream->codecName = stream->codecName;
+ toStream->codec_fourcc = stream->codec_fourcc;
toStream->flags = stream->flags;
toStream->cryptoSession = stream->cryptoSession;
toStream->externalInterfaces = stream->externalInterfaces;
diff --git a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp
index 13e78d2935..348779a626 100644
--- a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp
+++ b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp
@@ -202,11 +202,12 @@ bool CDVDDemuxFFmpeg::Aborted()
return false;
}
-bool CDVDDemuxFFmpeg::Open(std::shared_ptr<CDVDInputStream> pInput, bool streaminfo, bool fileinfo)
+bool CDVDDemuxFFmpeg::Open(std::shared_ptr<CDVDInputStream> pInput, bool fileinfo)
{
AVInputFormat* iformat = NULL;
std::string strFile;
- m_streaminfo = streaminfo;
+ m_streaminfo = !pInput->IsRealtime() && !m_reopen;
+ m_reopen = false;
m_currentPts = DVD_NOPTS_VALUE;
m_speed = DVD_PLAYSPEED_NORMAL;
m_program = UINT_MAX;
@@ -602,6 +603,7 @@ bool CDVDDemuxFFmpeg::Open(std::shared_ptr<CDVDInputStream> pInput, bool streami
int64_t duration = m_pFormatContext->duration;
std::shared_ptr<CDVDInputStream> pInputStream = m_pInput;
Dispose();
+ m_reopen = true;
if (!Open(pInputStream, false))
return false;
m_pFormatContext->duration = duration;
@@ -651,7 +653,7 @@ bool CDVDDemuxFFmpeg::Reset()
{
std::shared_ptr<CDVDInputStream> pInputStream = m_pInput;
Dispose();
- return Open(pInputStream, m_streaminfo);
+ return Open(pInputStream, false);
}
void CDVDDemuxFFmpeg::Flush()
diff --git a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.h b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.h
index 3412924fc7..d634bef4c6 100644
--- a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.h
+++ b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.h
@@ -83,7 +83,7 @@ public:
CDVDDemuxFFmpeg();
~CDVDDemuxFFmpeg() override;
- bool Open(std::shared_ptr<CDVDInputStream> pInput, bool streaminfo = true, bool fileinfo = false);
+ bool Open(std::shared_ptr<CDVDInputStream> pInput, bool fileinfo);
void Dispose();
bool Reset() override ;
void Flush() override;
@@ -169,6 +169,7 @@ protected:
}m_pkt;
bool m_streaminfo;
+ bool m_reopen = false;
bool m_checkTransportStream;
int m_displayTime = 0;
double m_dtsAtDisplayTime;
diff --git a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxVobsub.cpp b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxVobsub.cpp
index d2d4e5f0f5..4ee657b2d1 100644
--- a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxVobsub.cpp
+++ b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxVobsub.cpp
@@ -64,7 +64,7 @@ bool CDVDDemuxVobsub::Open(const std::string& filename, int source, const std::s
return false;
m_Demuxer.reset(new CDVDDemuxFFmpeg());
- if(!m_Demuxer->Open(m_Input))
+ if (!m_Demuxer->Open(m_Input, false))
return false;
CDVDStreamInfo hints;
diff --git a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDFactoryDemuxer.cpp b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDFactoryDemuxer.cpp
index 59a4b4be76..605eb3f9d1 100644
--- a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDFactoryDemuxer.cpp
+++ b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDFactoryDemuxer.cpp
@@ -61,20 +61,6 @@ CDVDDemux* CDVDFactoryDemuxer::CreateDemuxer(std::shared_ptr<CDVDInputStream> pI
return nullptr;
}
- bool streaminfo = true; /* Look for streams before playback */
- if (pInputStream->IsStreamType(DVDSTREAM_TYPE_PVRMANAGER))
- {
- /* Don't parse the streaminfo for some cases of streams to reduce the channel switch time */
- bool useFastswitch = URIUtils::IsUsingFastSwitch(pInputStream->GetFileName());
- streaminfo = !useFastswitch;
- }
-
- if (pInputStream->IsStreamType(DVDSTREAM_TYPE_FFMPEG))
- {
- bool useFastswitch = URIUtils::IsUsingFastSwitch(pInputStream->GetFileName());
- streaminfo = !useFastswitch;
- }
-
// Try to open the MultiFiles demuxer
if (pInputStream->IsStreamType(DVDSTREAM_TYPE_MULTIFILES))
{
@@ -86,7 +72,7 @@ CDVDDemux* CDVDFactoryDemuxer::CreateDemuxer(std::shared_ptr<CDVDInputStream> pI
}
std::unique_ptr<CDVDDemuxFFmpeg> demuxer(new CDVDDemuxFFmpeg());
- if(demuxer->Open(pInputStream, streaminfo, fileinfo))
+ if (demuxer->Open(pInputStream, fileinfo))
return demuxer.release();
else
return NULL;
diff --git a/xbmc/cores/VideoPlayer/DVDFileInfo.cpp b/xbmc/cores/VideoPlayer/DVDFileInfo.cpp
index 2b9e2d4143..d12f18e8fc 100644
--- a/xbmc/cores/VideoPlayer/DVDFileInfo.cpp
+++ b/xbmc/cores/VideoPlayer/DVDFileInfo.cpp
@@ -200,10 +200,10 @@ bool CDVDFileInfo::ExtractThumb(const CFileItem& fileItem,
if (pVideoCodec)
{
int nTotalLen = pDemuxer->GetStreamLength();
- int64_t nSeekTo = (pos == -1) ? nTotalLen / 3 : pos;
+ int nSeekTo = (pos == -1) ? nTotalLen / 3 : pos;
- CLog::Log(LOGDEBUG, "%s - seeking to pos %lldms (total: %dms) in %s", __FUNCTION__, nSeekTo, nTotalLen, redactPath.c_str());
- if (pDemuxer->SeekTime(static_cast<double>(nSeekTo), true))
+ CLog::Log(LOGDEBUG,"%s - seeking to pos %dms (total: %dms) in %s", __FUNCTION__, nSeekTo, nTotalLen, redactPath.c_str());
+ if (pDemuxer->SeekTime(nSeekTo, true))
{
CDVDVideoCodec::VCReturn iDecoderState = CDVDVideoCodec::VC_NONE;
VideoPicture picture = {};
@@ -377,7 +377,7 @@ bool CDVDFileInfo::DemuxerToStreamDetails(std::shared_ptr<CDVDInputStream> pInpu
CDemuxStreamVideo* vstream = static_cast<CDemuxStreamVideo*>(stream);
p->m_iWidth = vstream->iWidth;
p->m_iHeight = vstream->iHeight;
- p->m_fAspect = static_cast<float>(vstream->fAspect);
+ p->m_fAspect = vstream->fAspect;
if (p->m_fAspect == 0.0f)
p->m_fAspect = (float)p->m_iWidth / p->m_iHeight;
p->m_strCodec = pDemux->GetStreamCodecName(stream->demuxerId, stream->uniqueId);
diff --git a/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStream.h b/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStream.h
index 40f5f3d303..8dc39442c9 100644
--- a/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStream.h
+++ b/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStream.h
@@ -184,7 +184,6 @@ public:
virtual IPosTime* GetIPosTime() { return nullptr; }
virtual IDisplayTime* GetIDisplayTime() { return nullptr; }
virtual ITimes* GetITimes() { return nullptr; }
- virtual IChapter* GetIChapter() { return nullptr; }
const CVariant &GetProperty(const std::string key){ return m_item.GetProperty(key); }
diff --git a/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamBluray.cpp b/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamBluray.cpp
index 4de6c64d9d..a431f407bb 100644
--- a/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamBluray.cpp
+++ b/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamBluray.cpp
@@ -139,6 +139,7 @@ bool CDVDInputStreamBluray::Open()
std::string root;
bool openStream = false;
+ bool openDisc = false;
// The item was selected via the simple menu
if (URIUtils::IsProtocol(strPath, "bluray"))
@@ -147,6 +148,11 @@ bool CDVDInputStreamBluray::Open()
root = url.GetHostName();
filename = URIUtils::GetFileName(url.GetFileName());
+ // Check whether disc is AACS protected
+ CURL url3(root);
+ CFileItem base(url3, false);
+ openDisc = base.IsProtectedBlurayDisc();
+
// check for a menu call for an image file
if (StringUtils::EqualsNoCase(filename, "menu"))
{
@@ -155,6 +161,11 @@ bool CDVDInputStreamBluray::Open()
std::string root2 = url2.GetHostName();
CURL url(root2);
CFileItem item(url, false);
+
+ // Check whether disc is AACS protected
+ if (!openDisc)
+ openDisc = item.IsProtectedBlurayDisc();
+
if (item.IsDiscImage())
{
if (!OpenStream(item))
@@ -171,6 +182,10 @@ bool CDVDInputStreamBluray::Open()
openStream = true;
}
+ else if (m_item.IsProtectedBlurayDisc())
+ {
+ openDisc = true;
+ }
else
{
strPath = URIUtils::GetDirectory(strPath);
@@ -217,12 +232,25 @@ bool CDVDInputStreamBluray::Open()
return false;
}
}
+ else if (openDisc)
+ {
+ // This special case is required for opening original AACS protected Blu-ray discs. Otherwise
+ // things like Bus Encryption might not be handled properly and playback will fail.
+ m_rootPath = root;
+ if (!bd_open_disc(m_bd, root.c_str(), nullptr))
+ {
+ CLog::Log(LOGERROR, "CDVDInputStreamBluray::Open - failed to open %s in disc mode",
+ CURL::GetRedacted(root).c_str());
+ return false;
+ }
+ }
else
{
m_rootPath = root;
if (!bd_open_files(m_bd, &m_rootPath, CBlurayCallback::dir_open, CBlurayCallback::file_open))
{
- CLog::Log(LOGERROR, "CDVDInputStreamBluray::Open - failed to open %s", CURL::GetRedacted(root).c_str());
+ CLog::Log(LOGERROR, "CDVDInputStreamBluray::Open - failed to open %s in files mode",
+ CURL::GetRedacted(root).c_str());
return false;
}
}
@@ -990,8 +1018,12 @@ void CDVDInputStreamBluray::GetStreamInfo(int pid, std::string &language)
find_stream(pid, m_clip->audio_streams, m_clip->audio_stream_count, language);
else if (HDMV_PID_PG_FIRST <= pid && pid <= HDMV_PID_PG_LAST)
find_stream(pid, m_clip->pg_streams, m_clip->pg_stream_count, language);
+ else if (HDMV_PID_PG_HDR_FIRST <= pid && pid <= HDMV_PID_PG_HDR_LAST)
+ find_stream(pid, m_clip->pg_streams, m_clip->pg_stream_count, language);
else if (HDMV_PID_IG_FIRST <= pid && pid <= HDMV_PID_IG_LAST)
find_stream(pid, m_clip->ig_streams, m_clip->ig_stream_count, language);
+ else
+ CLog::Log(LOGDEBUG, "CDVDInputStreamBluray::GetStreamInfo - unhandled pid %d", pid);
}
CDVDInputStream::ENextStream CDVDInputStreamBluray::NextStream()
diff --git a/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamBluray.h b/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamBluray.h
index 1abd0db71c..aeaca8ce03 100644
--- a/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamBluray.h
+++ b/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamBluray.h
@@ -33,6 +33,8 @@ extern "C"
#define HDMV_PID_AUDIO_LAST 0x111f
#define HDMV_PID_PG_FIRST 0x1200
#define HDMV_PID_PG_LAST 0x121f
+#define HDMV_PID_PG_HDR_FIRST 0x12a0
+#define HDMV_PID_PG_HDR_LAST 0x12bf
#define HDMV_PID_IG_FIRST 0x1400
#define HDMV_PID_IG_LAST 0x141f
diff --git a/xbmc/cores/VideoPlayer/DVDInputStreams/InputStreamAddon.cpp b/xbmc/cores/VideoPlayer/DVDInputStreams/InputStreamAddon.cpp
index cc42c3a6ef..8829572f75 100644
--- a/xbmc/cores/VideoPlayer/DVDInputStreams/InputStreamAddon.cpp
+++ b/xbmc/cores/VideoPlayer/DVDInputStreams/InputStreamAddon.cpp
@@ -95,7 +95,6 @@ bool CInputStreamAddon::Supports(BinaryAddonBasePtr& addonBase, const CFileItem
for (auto& value : extensionsList)
{
StringUtils::Trim(value);
-
if (value == filetype)
return true;
}
@@ -478,59 +477,6 @@ bool CInputStreamAddon::IsRealtime()
return false;
}
-
-// IChapter
-CDVDInputStream::IChapter* CInputStreamAddon::GetIChapter()
-{
- if ((m_caps.m_mask & INPUTSTREAM_CAPABILITIES::SUPPORTS_ICHAPTER) == 0)
- return nullptr;
-
- return this;
-}
-
-int CInputStreamAddon::GetChapter()
-{
- if (m_struct.toAddon.get_chapter)
- return m_struct.toAddon.get_chapter(&m_struct);
-
- return -1;
-}
-
-int CInputStreamAddon::GetChapterCount()
-{
- if (m_struct.toAddon.get_chapter_count)
- return m_struct.toAddon.get_chapter_count(&m_struct);
-
- return 0;
-}
-
-void CInputStreamAddon::GetChapterName(std::string& name, int ch)
-{
- name.clear();
- if (m_struct.toAddon.get_chapter_name)
- {
- const char* res = m_struct.toAddon.get_chapter_name(&m_struct, ch);
- if (res)
- name = res;
- }
-}
-
-int64_t CInputStreamAddon::GetChapterPos(int ch)
-{
- if (m_struct.toAddon.get_chapter_pos)
- return m_struct.toAddon.get_chapter_pos(&m_struct, ch);
-
- return 0;
-}
-
-bool CInputStreamAddon::SeekChapter(int ch)
-{
- if (m_struct.toAddon.seek_chapter)
- return m_struct.toAddon.seek_chapter(&m_struct, ch);
-
- return false;
-}
-
int CInputStreamAddon::ConvertVideoCodecProfile(STREAMCODEC_PROFILE profile)
{
switch (profile)
diff --git a/xbmc/cores/VideoPlayer/DVDInputStreams/InputStreamAddon.h b/xbmc/cores/VideoPlayer/DVDInputStreams/InputStreamAddon.h
index 559ad8d5f0..e215953ab2 100644
--- a/xbmc/cores/VideoPlayer/DVDInputStreams/InputStreamAddon.h
+++ b/xbmc/cores/VideoPlayer/DVDInputStreams/InputStreamAddon.h
@@ -32,13 +32,12 @@ private:
//! \brief Input stream class
class CInputStreamAddon
- : public ADDON::IAddonInstanceHandler
- , public CDVDInputStream
- , public CDVDInputStream::IDisplayTime
- , public CDVDInputStream::ITimes
- , public CDVDInputStream::IPosTime
- , public CDVDInputStream::IDemux
- , public CDVDInputStream::IChapter
+ : public ADDON::IAddonInstanceHandler,
+ public CDVDInputStream,
+ public CDVDInputStream::IDisplayTime,
+ public CDVDInputStream::ITimes,
+ public CDVDInputStream::IPosTime,
+ public CDVDInputStream::IDemux
{
public:
CInputStreamAddon(ADDON::BinaryAddonBasePtr& addonBase, IVideoPlayer* player, const CFileItem& fileitem);
@@ -87,14 +86,6 @@ public:
void SetVideoResolution(int width, int height) override;
bool IsRealtime() override;
- // IChapter
- CDVDInputStream::IChapter* GetIChapter() override;
- int GetChapter() override;
- int GetChapterCount() override;
- void GetChapterName(std::string& name, int ch = -1) override;
- int64_t GetChapterPos(int ch = -1) override;
- bool SeekChapter(int ch) override;
-
protected:
static int ConvertVideoCodecProfile(STREAMCODEC_PROFILE profile);
diff --git a/xbmc/cores/VideoPlayer/DVDSubtitles/DVDSubtitleParserSami.cpp b/xbmc/cores/VideoPlayer/DVDSubtitles/DVDSubtitleParserSami.cpp
index bb3f0f7e3c..412d345864 100644
--- a/xbmc/cores/VideoPlayer/DVDSubtitles/DVDSubtitleParserSami.cpp
+++ b/xbmc/cores/VideoPlayer/DVDSubtitles/DVDSubtitleParserSami.cpp
@@ -34,7 +34,7 @@ bool CDVDSubtitleParserSami::Open(CDVDStreamInfo &hints)
char line[1024];
CRegExp reg(true);
- if (!reg.RegComp("<SYNC START=([0-9]+)>"))
+ if (!reg.RegComp("<SYNC START=\"?([0-9]+)\"?>"))
return false;
std::string strFileName;
diff --git a/xbmc/cores/VideoPlayer/DVDSubtitles/DVDSubtitleTagSami.cpp b/xbmc/cores/VideoPlayer/DVDSubtitles/DVDSubtitleTagSami.cpp
index 9fba640c0d..176264b76a 100644
--- a/xbmc/cores/VideoPlayer/DVDSubtitles/DVDSubtitleTagSami.cpp
+++ b/xbmc/cores/VideoPlayer/DVDSubtitles/DVDSubtitleTagSami.cpp
@@ -9,6 +9,8 @@
#include "DVDSubtitleTagSami.h"
#include "DVDSubtitleStream.h"
#include "DVDCodecs/Overlay/DVDOverlayText.h"
+#include "utils/CharsetConverter.h"
+#include "utils/HTMLUtil.h"
#include "utils/RegExp.h"
#include "utils/StringUtils.h"
@@ -184,6 +186,11 @@ void CDVDSubtitleTagSami::ConvertLine(CDVDOverlayText* pOverlay, const char* lin
if( strUTF8[strUTF8.size()-1] == '\n' )
strUTF8.erase(strUTF8.size()-1);
+ std::wstring wStrHtml, wStr;
+ g_charsetConverter.utf8ToW(strUTF8, wStrHtml, false);
+ HTML::CHTMLUtil::ConvertHTMLToW(wStrHtml, wStr);
+ g_charsetConverter.wToUTF8(wStr, strUTF8);
+
// add a new text element to our container
pOverlay->AddElement(new CDVDOverlayText::CElementText(strUTF8.c_str()));
}
diff --git a/xbmc/cores/VideoPlayer/VideoPlayer.cpp b/xbmc/cores/VideoPlayer/VideoPlayer.cpp
index 68ec48710d..459d2aacc0 100644
--- a/xbmc/cores/VideoPlayer/VideoPlayer.cpp
+++ b/xbmc/cores/VideoPlayer/VideoPlayer.cpp
@@ -2730,17 +2730,7 @@ void CVideoPlayer::HandleMessages()
offset = DVD_TIME_TO_MSEC(start) - static_cast<int>(beforeSeek);
m_callback.OnPlayBackSeekChapter(msg.GetChapter());
}
- else if (m_pInputStream)
- {
- CDVDInputStream::IChapter* pChapter = m_pInputStream->GetIChapter();
- if (pChapter && pChapter->SeekChapter(msg.GetChapter()))
- {
- FlushBuffers(start, true, true);
- int64_t beforeSeek = GetTime();
- offset = DVD_TIME_TO_MSEC(start) - static_cast<int>(beforeSeek);
- m_callback.OnPlayBackSeekChapter(msg.GetChapter());
- }
- }
+
CServiceBroker::GetGUI()->GetInfoManager().GetInfoProviders().GetPlayerInfoProvider().SetDisplayAfterSeek(2500, offset);
}
else if (pMsg->IsType(CDVDMsg::DEMUXER_RESET))
@@ -4712,7 +4702,7 @@ void CVideoPlayer::UpdatePlayState(double timeout)
state.chapters.clear();
if (m_pDemuxer->GetChapterCount() > 0)
{
- for (int i = 0, ie = m_pDemuxer->GetChapterCount(); i < ie; ++i)
+ for (int i = 0; i < m_pDemuxer->GetChapterCount(); ++i)
{
std::string name;
m_pDemuxer->GetChapterName(name, i + 1);
@@ -4732,26 +4722,6 @@ void CVideoPlayer::UpdatePlayState(double timeout)
if (m_pInputStream)
{
- CDVDInputStream::IChapter* pChapter = m_pInputStream->GetIChapter();
- if (pChapter)
- {
- if (IsInMenuInternal())
- state.chapter = 0;
- else
- state.chapter = pChapter->GetChapter();
-
- state.chapters.clear();
- if (pChapter->GetChapterCount() > 0)
- {
- for (int i = 0, ie = pChapter->GetChapterCount(); i < ie; ++i)
- {
- std::string name;
- pChapter->GetChapterName(name, i + 1);
- state.chapters.push_back(make_pair(name, pChapter->GetChapterPos(i + 1)));
- }
- }
- }
-
CDVDInputStream::ITimes* pTimes = m_pInputStream->GetITimes();
CDVDInputStream::IDisplayTime* pDisplayTime = m_pInputStream->GetIDisplayTime();
diff --git a/xbmc/cores/playercorefactory/PlayerSelectionRule.cpp b/xbmc/cores/playercorefactory/PlayerSelectionRule.cpp
index 59e641638b..439a69a8cf 100644
--- a/xbmc/cores/playercorefactory/PlayerSelectionRule.cpp
+++ b/xbmc/cores/playercorefactory/PlayerSelectionRule.cpp
@@ -45,6 +45,7 @@ void CPlayerSelectionRule::Initialize(TiXmlElement* pRule)
m_tRemote = GetTristate(pRule->Attribute("remote"));
m_tAudio = GetTristate(pRule->Attribute("audio"));
m_tVideo = GetTristate(pRule->Attribute("video"));
+ m_tGame = GetTristate(pRule->Attribute("game"));
m_tBD = GetTristate(pRule->Attribute("bd"));
m_tDVD = GetTristate(pRule->Attribute("dvd"));
@@ -110,6 +111,8 @@ void CPlayerSelectionRule::GetPlayers(const CFileItem& item, std::vector<std::st
return;
if (m_tVideo >= 0 && (m_tVideo > 0) != item.IsVideo())
return;
+ if (m_tGame >= 0 && (m_tGame > 0) != item.IsGame())
+ return;
if (m_tInternetStream >= 0 && (m_tInternetStream > 0) != item.IsInternetStream())
return;
if (m_tRemote >= 0 && (m_tRemote > 0) != item.IsRemote())
diff --git a/xbmc/cores/playercorefactory/PlayerSelectionRule.h b/xbmc/cores/playercorefactory/PlayerSelectionRule.h
index bdc65927ac..991631e1df 100644
--- a/xbmc/cores/playercorefactory/PlayerSelectionRule.h
+++ b/xbmc/cores/playercorefactory/PlayerSelectionRule.h
@@ -35,6 +35,7 @@ private:
int m_tAudio;
int m_tVideo;
+ int m_tGame;
int m_tInternetStream;
int m_tRemote;
diff --git a/xbmc/dbwrappers/Database.cpp b/xbmc/dbwrappers/Database.cpp
index 014521d41b..5ed93ee44b 100644
--- a/xbmc/dbwrappers/Database.cpp
+++ b/xbmc/dbwrappers/Database.cpp
@@ -173,6 +173,12 @@ bool CDatabase::DatasetLayout::GetFetch(int fieldno)
return false;
}
+void CDatabase::DatasetLayout::SetFetch(int fieldno, bool bFetch /*= true*/)
+{
+ if (fieldno >= 0 && fieldno < static_cast<int>(m_fields.size()))
+ m_fields[fieldno].fetch = bFetch;
+}
+
bool CDatabase::DatasetLayout::GetOutput(int fieldno)
{
if (fieldno >= 0 && fieldno < static_cast<int>(m_fields.size()))
diff --git a/xbmc/dbwrappers/Database.h b/xbmc/dbwrappers/Database.h
index 7b6e31cd3b..24377e6bab 100644
--- a/xbmc/dbwrappers/Database.h
+++ b/xbmc/dbwrappers/Database.h
@@ -67,6 +67,7 @@ public:
void SetField(int fieldNo, const std::string &strField, bool bOutput = false);
void AdjustRecordNumbers(int offset);
bool GetFetch(int fieldno);
+ void SetFetch(int fieldno, bool bFetch = true);
bool GetOutput(int fieldno);
int GetRecNo(int fieldno);
const std::string GetFields();
diff --git a/xbmc/dialogs/GUIDialogContextMenu.cpp b/xbmc/dialogs/GUIDialogContextMenu.cpp
index 5841234261..af92fc2430 100644
--- a/xbmc/dialogs/GUIDialogContextMenu.cpp
+++ b/xbmc/dialogs/GUIDialogContextMenu.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005-2018 Team Kodi
+ * Copyright (C) 2005-2020 Team Kodi
* This file is part of Kodi - https://kodi.tv
*
* SPDX-License-Identifier: GPL-2.0-or-later
@@ -7,33 +7,35 @@
*/
#include "GUIDialogContextMenu.h"
-#include "guilib/GUIComponent.h"
-#include "guilib/GUIButtonControl.h"
-#include "guilib/GUIControlGroupList.h"
+
+#include "FileItem.h"
#include "GUIDialogFileBrowser.h"
-#include "GUIUserMessages.h"
+#include "GUIDialogMediaSource.h"
+#include "GUIDialogYesNo.h"
#include "GUIPassword.h"
+#include "GUIUserMessages.h"
#include "ServiceBroker.h"
+#include "TextureCache.h"
+#include "URL.h"
#include "Util.h"
-#include "utils/URIUtils.h"
+#include "addons/Scraper.h"
+#include "filesystem/File.h"
+#include "guilib/GUIButtonControl.h"
+#include "guilib/GUIComponent.h"
+#include "guilib/GUIControlGroupList.h"
+#include "guilib/GUIWindowManager.h"
+#include "guilib/LocalizeStrings.h"
+#include "input/Key.h"
+#include "media/MediaLockState.h"
+#include "profiles/ProfileManager.h"
+#include "profiles/dialogs/GUIDialogLockSettings.h"
#include "settings/MediaSourceSettings.h"
#include "settings/Settings.h"
#include "settings/SettingsComponent.h"
-#include "GUIDialogMediaSource.h"
-#include "profiles/ProfileManager.h"
-#include "profiles/dialogs/GUIDialogLockSettings.h"
#include "storage/MediaManager.h"
-#include "guilib/GUIWindowManager.h"
-#include "input/Key.h"
-#include "GUIDialogYesNo.h"
-#include "FileItem.h"
-#include "filesystem/File.h"
-#include "guilib/LocalizeStrings.h"
-#include "TextureCache.h"
-#include "URL.h"
#include "utils/StringUtils.h"
+#include "utils/URIUtils.h"
#include "utils/Variant.h"
-#include "addons/Scraper.h"
#define BACKGROUND_IMAGE 999
#define GROUP_LIST 996
@@ -248,11 +250,15 @@ void CGUIDialogContextMenu::GetContextButtons(const std::string &type, const CFi
}
if (share && LOCK_MODE_EVERYONE != CServiceBroker::GetSettingsComponent()->GetProfileManager()->GetMasterProfile().getLockMode())
{
- if (share->m_iHasLock == 0 && (CServiceBroker::GetSettingsComponent()->GetProfileManager()->GetCurrentProfile().canWriteSources() || g_passwordManager.bMasterUser))
+ if (share->m_iHasLock == LOCK_STATE_NO_LOCK && (CServiceBroker::GetSettingsComponent()
+ ->GetProfileManager()
+ ->GetCurrentProfile()
+ .canWriteSources() ||
+ g_passwordManager.bMasterUser))
buttons.Add(CONTEXT_BUTTON_ADD_LOCK, 12332);
- else if (share->m_iHasLock == 1)
+ else if (share->m_iHasLock == LOCK_STATE_LOCK_BUT_UNLOCKED)
buttons.Add(CONTEXT_BUTTON_REMOVE_LOCK, 12335);
- else if (share->m_iHasLock == 2)
+ else if (share->m_iHasLock == LOCK_STATE_LOCKED)
{
buttons.Add(CONTEXT_BUTTON_REMOVE_LOCK, 12335);
@@ -266,7 +272,7 @@ void CGUIDialogContextMenu::GetContextButtons(const std::string &type, const CFi
buttons.Add(CONTEXT_BUTTON_CHANGE_LOCK, 12356);
}
}
- if (share && !g_passwordManager.bMasterUser && item->m_iHasLock == 1)
+ if (share && !g_passwordManager.bMasterUser && item->m_iHasLock == LOCK_STATE_LOCK_BUT_UNLOCKED)
buttons.Add(CONTEXT_BUTTON_REACTIVATE_LOCK, 12353);
}
@@ -436,7 +442,7 @@ bool CGUIDialogContextMenu::OnContextButton(const std::string &type, const CFile
if (!CGUIDialogLockSettings::ShowAndGetLock(share->m_iLockMode,strNewPassword))
return false;
// password entry and re-entry succeeded, write out the lock data
- share->m_iHasLock = 2;
+ share->m_iHasLock = LOCK_STATE_LOCKED;
CMediaSourceSettings::GetInstance().UpdateSource(type, share->strName, "lockcode", strNewPassword);
strNewPassword = StringUtils::Format("%i", share->m_iLockMode);
CMediaSourceSettings::GetInstance().UpdateSource(type, share->strName, "lockmode", strNewPassword);
@@ -464,10 +470,11 @@ bool CGUIDialogContextMenu::OnContextButton(const std::string &type, const CFile
if (!g_passwordManager.IsMasterLockUnlocked(true))
return false;
+ // prompt user if they want to really remove the lock
if (!CGUIDialogYesNo::ShowAndGetInput(CVariant{12335}, CVariant{750}))
return false;
- share->m_iHasLock = 0;
+ share->m_iHasLock = LOCK_STATE_NO_LOCK;
CMediaSourceSettings::GetInstance().UpdateSource(type, share->strName, "lockmode", "0");
CMediaSourceSettings::GetInstance().UpdateSource(type, share->strName, "lockcode", "0");
CMediaSourceSettings::GetInstance().UpdateSource(type, share->strName, "badpwdcount", "0");
diff --git a/xbmc/dialogs/GUIDialogKaiToast.cpp b/xbmc/dialogs/GUIDialogKaiToast.cpp
index 95221a7e6d..239afaca31 100644
--- a/xbmc/dialogs/GUIDialogKaiToast.cpp
+++ b/xbmc/dialogs/GUIDialogKaiToast.cpp
@@ -7,11 +7,13 @@
*/
#include "GUIDialogKaiToast.h"
+
+#include "ServiceBroker.h"
+#include "guilib/GUIFadeLabelControl.h"
#include "guilib/GUIMessage.h"
#include "peripherals/Peripherals.h"
#include "threads/SingleLock.h"
#include "utils/TimeUtils.h"
-#include "ServiceBroker.h"
#define POPUP_ICON 400
#define POPUP_CAPTION_TEXT 401
@@ -89,6 +91,13 @@ bool CGUIDialogKaiToast::DoWork()
if (!m_notifications.empty() &&
CTimeUtils::GetFrameTime() - m_timer > m_toastMessageTime)
{
+ // if we have a fade label control for the text to display, ensure the whole text was shown
+ // (scrolled to the end) before we move on to the next message
+ const CGUIFadeLabelControl* notificationText =
+ dynamic_cast<const CGUIFadeLabelControl*>(GetControl(POPUP_NOTIFICATION_BUTTON));
+ if (notificationText && !notificationText->AllLabelsShown())
+ return false;
+
Notification toast = m_notifications.front();
m_notifications.pop();
lock.Leave();
@@ -147,7 +156,22 @@ void CGUIDialogKaiToast::FrameMove()
// now check if we should exit
if (CTimeUtils::GetFrameTime() - m_timer > m_toastDisplayTime)
- Close();
+ {
+ bool bClose = true;
+
+ // if we have a fade label control for the text to display, ensure the whole text was shown
+ // (scrolled to the end) before we're closing the toast dialog
+ const CGUIFadeLabelControl* notificationText =
+ dynamic_cast<const CGUIFadeLabelControl*>(GetControl(POPUP_NOTIFICATION_BUTTON));
+ if (notificationText)
+ {
+ CSingleLock lock(m_critical);
+ bClose = notificationText->AllLabelsShown() && m_notifications.empty();
+ }
+
+ if (bClose)
+ Close();
+ }
CGUIDialog::FrameMove();
}
diff --git a/xbmc/favourites/GUIDialogFavourites.cpp b/xbmc/favourites/GUIDialogFavourites.cpp
index 27c4657bf6..4176bb1bda 100644
--- a/xbmc/favourites/GUIDialogFavourites.cpp
+++ b/xbmc/favourites/GUIDialogFavourites.cpp
@@ -93,10 +93,11 @@ void CGUIDialogFavourites::OnClick(int item)
if (item < 0 || item >= m_favourites->Size())
return;
- Close();
-
CGUIMessage message(GUI_MSG_EXECUTE, 0, GetID());
message.SetStringParam(m_favouritesService.GetExecutePath(*(*m_favourites)[item], GetID()));
+
+ Close();
+
CServiceBroker::GetGUI()->GetWindowManager().SendMessage(message);
}
diff --git a/xbmc/filesystem/CurlFile.cpp b/xbmc/filesystem/CurlFile.cpp
index e48c238de9..cb2c9d145c 100644
--- a/xbmc/filesystem/CurlFile.cpp
+++ b/xbmc/filesystem/CurlFile.cpp
@@ -601,8 +601,11 @@ void CCurlFile::SetCommonOptions(CReadState* state, bool failOnError /* = true *
StringUtils::Format(":%d", m_proxyport);
g_curlInterface.easy_setopt(h, CURLOPT_PROXY, hostport.c_str());
- const std::string userpass =
- m_proxyuser + std::string(":") + m_proxypassword;
+ std::string userpass;
+
+ if (!m_proxyuser.empty() && !m_proxypassword.empty())
+ userpass = CURL::Encode(m_proxyuser) + ":" + CURL::Encode(m_proxypassword);
+
if (!userpass.empty())
g_curlInterface.easy_setopt(h, CURLOPT_PROXYUSERPWD, userpass.c_str());
}
diff --git a/xbmc/filesystem/FileDirectoryFactory.cpp b/xbmc/filesystem/FileDirectoryFactory.cpp
index a3144f60d9..4cc5ef577b 100644
--- a/xbmc/filesystem/FileDirectoryFactory.cpp
+++ b/xbmc/filesystem/FileDirectoryFactory.cpp
@@ -86,13 +86,21 @@ IFileDirectory* CFileDirectoryFactory::Create(const CURL& url, CFileItem* pItem,
*pItem = *wrap->m_items[0];
}
else
- { // compressed or more than one file -> create a dir
+ {
+ // compressed or more than one file -> create a dir
pItem->SetPath(wrap->m_items.GetPath());
- return wrap;
}
+
+ // Check for folder, if yes return also wrap.
+ // Needed to fix for e.g. RAR files with only one file inside
+ pItem->m_bIsFolder = URIUtils::HasSlashAtEnd(pItem->GetPath());
+ if (pItem->m_bIsFolder)
+ return wrap;
}
else
+ {
pItem->m_bIsFolder = true;
+ }
delete wrap;
return nullptr;
diff --git a/xbmc/filesystem/SourcesDirectory.cpp b/xbmc/filesystem/SourcesDirectory.cpp
index 702b2cd629..08d1c11363 100644
--- a/xbmc/filesystem/SourcesDirectory.cpp
+++ b/xbmc/filesystem/SourcesDirectory.cpp
@@ -1,22 +1,24 @@
/*
- * Copyright (C) 2005-2018 Team Kodi
+ * Copyright (C) 2005-2020 Team Kodi
* This file is part of Kodi - https://kodi.tv
*
* SPDX-License-Identifier: GPL-2.0-or-later
* See LICENSES/README.md for more information.
*/
-#include "ServiceBroker.h"
#include "SourcesDirectory.h"
-#include "utils/URIUtils.h"
+
+#include "File.h"
+#include "FileItem.h"
+#include "ServiceBroker.h"
#include "URL.h"
#include "Util.h"
-#include "FileItem.h"
-#include "File.h"
+#include "guilib/TextureManager.h"
+#include "media/MediaLockState.h"
#include "profiles/ProfileManager.h"
#include "settings/MediaSourceSettings.h"
-#include "guilib/TextureManager.h"
#include "storage/MediaManager.h"
+#include "utils/URIUtils.h"
using namespace XFILE;
@@ -87,7 +89,8 @@ bool CSourcesDirectory::GetDirectory(const VECSOURCES &sources, CFileItemList &i
strIcon = "DefaultHardDisk.png";
pItem->SetIconImage(strIcon);
- if (share.m_iHasLock == 2 && m_profileManager->GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE)
+ if (share.m_iHasLock == LOCK_STATE_LOCKED &&
+ m_profileManager->GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE)
pItem->SetOverlayImage(CGUIListItem::ICON_OVERLAY_LOCKED);
else
pItem->SetOverlayImage(CGUIListItem::ICON_OVERLAY_NONE);
diff --git a/xbmc/filesystem/ZipFile.cpp b/xbmc/filesystem/ZipFile.cpp
index 071f926914..46e06c785f 100644
--- a/xbmc/filesystem/ZipFile.cpp
+++ b/xbmc/filesystem/ZipFile.cpp
@@ -398,12 +398,47 @@ int CZipFile::UnpackFromMemory(std::string& strDest, const std::string& strInput
if (!isGZ)
{
CZipManager::readHeader(strInput.data()+iPos,mZipItem);
- if( mZipItem.header != ZIP_LOCAL_HEADER )
+ if (mZipItem.header == ZIP_DATA_RECORD_HEADER)
+ {
+ // this header concerns a file we already processed, so we can just skip it
+ iPos += DREC_SIZE;
+ continue;
+ }
+ if (mZipItem.header != ZIP_LOCAL_HEADER)
return iResult;
if( (mZipItem.flags & 8) == 8 )
{
- CLog::Log(LOGERROR,"FileZip: extended local header, not supported!");
- return iResult;
+ // if an extended local header (=data record header) is present,
+ // the following fields are 0 in the local header and we need to read
+ // them from the extended local header
+
+ // search for the extended local header
+ unsigned int i = iPos + LHDR_SIZE + mZipItem.flength + mZipItem.elength;
+ while (1)
+ {
+ if (i + DREC_SIZE > strInput.size())
+ {
+ CLog::Log(LOGERROR, "FileZip: extended local header expected, but not present!");
+ return iResult;
+ }
+ if ((strInput[i] == 0x50) && (strInput[i + 1] == 0x4b) &&
+ (strInput[i + 2] == 0x07) && (strInput[i + 3] == 0x08))
+ break; // header found
+ i++;
+ }
+ // ZIP is little endian:
+ mZipItem.crc32 = static_cast<uint8_t>(strInput[i + 4]) |
+ static_cast<uint8_t>(strInput[i + 5]) << 8 |
+ static_cast<uint8_t>(strInput[i + 6]) << 16 |
+ static_cast<uint8_t>(strInput[i + 7]) << 24;
+ mZipItem.csize = static_cast<uint8_t>(strInput[i + 8]) |
+ static_cast<uint8_t>(strInput[i + 9]) << 8 |
+ static_cast<uint8_t>(strInput[i + 10]) << 16 |
+ static_cast<uint8_t>(strInput[i + 11]) << 24;
+ mZipItem.usize = static_cast<uint8_t>(strInput[i + 12]) |
+ static_cast<uint8_t>(strInput[i + 13]) << 8 |
+ static_cast<uint8_t>(strInput[i + 14]) << 16 |
+ static_cast<uint8_t>(strInput[i + 15]) << 24;
}
}
if (!InitDecompress())
diff --git a/xbmc/filesystem/ZipManager.h b/xbmc/filesystem/ZipManager.h
index f24d45944c..45754152eb 100644
--- a/xbmc/filesystem/ZipManager.h
+++ b/xbmc/filesystem/ZipManager.h
@@ -15,6 +15,7 @@
#define ZIP_END_CENTRAL_HEADER 0x06054b50
#define ZIP_SPLIT_ARCHIVE_HEADER 0x30304b50
#define LHDR_SIZE 30
+#define DREC_SIZE 16
#define CHDR_SIZE 46
#define ECDREC_SIZE 22
diff --git a/xbmc/filesystem/test/TestZipFile.cpp b/xbmc/filesystem/test/TestZipFile.cpp
index 5029cf73d0..4ac3690bff 100644
--- a/xbmc/filesystem/test/TestZipFile.cpp
+++ b/xbmc/filesystem/test/TestZipFile.cpp
@@ -9,12 +9,13 @@
#include "ServiceBroker.h"
#include "filesystem/Directory.h"
#include "filesystem/File.h"
-#include "utils/StringUtils.h"
-#include "utils/URIUtils.h"
+#include "filesystem/ZipFile.h"
#include "FileItem.h"
#include "settings/Settings.h"
#include "settings/SettingsComponent.h"
#include "test/TestUtils.h"
+#include "utils/StringUtils.h"
+#include "utils/URIUtils.h"
#include "URL.h"
#include <errno.h>
@@ -207,3 +208,22 @@ TEST_F(TestZipFile, CorruptedFile)
file->Close();
XBMC_DELETETEMPFILE(file);
}
+
+TEST_F(TestZipFile, ExtendedLocalHeader)
+{
+ XFILE::CFile file;
+ ssize_t readlen;
+ char zipdata[20000]; // size of zip file is 15352 Bytes
+
+ ASSERT_TRUE(file.Open(XBMC_REF_FILE_PATH("xbmc/filesystem/test/extendedlocalheader.zip")));
+ readlen = file.Read(zipdata, sizeof(zipdata));
+ EXPECT_TRUE(readlen);
+
+ XFILE::CZipFile zipfile;
+ std::string strBuffer;
+
+ int iSize = zipfile.UnpackFromMemory(strBuffer, std::string(zipdata, readlen), false);
+ EXPECT_EQ(152774, iSize); // sum of uncompressed size of all files in zip
+ EXPECT_TRUE(strBuffer.substr(0, 6) == "<Data>");
+ file.Close();
+}
diff --git a/xbmc/filesystem/test/extendedlocalheader.zip b/xbmc/filesystem/test/extendedlocalheader.zip
new file mode 100644
index 0000000000..b30d92e128
--- /dev/null
+++ b/xbmc/filesystem/test/extendedlocalheader.zip
Binary files differ
diff --git a/xbmc/games/windows/GUIWindowGames.cpp b/xbmc/games/windows/GUIWindowGames.cpp
index 355442386f..bef066dfb1 100644
--- a/xbmc/games/windows/GUIWindowGames.cpp
+++ b/xbmc/games/windows/GUIWindowGames.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012-2018 Team Kodi
+ * Copyright (C) 2012-2020 Team Kodi
* This file is part of Kodi - https://kodi.tv
*
* SPDX-License-Identifier: GPL-2.0-or-later
@@ -7,24 +7,26 @@
*/
#include "GUIWindowGames.h"
-#include "addons/GUIDialogAddonInfo.h"
+
#include "Application.h"
+#include "FileItem.h"
+#include "GUIPassword.h"
+#include "PlayListPlayer.h"
+#include "ServiceBroker.h"
+#include "URL.h"
+#include "Util.h"
+#include "addons/GUIDialogAddonInfo.h"
#include "dialogs/GUIDialogContextMenu.h"
#include "dialogs/GUIDialogMediaSource.h"
#include "dialogs/GUIDialogProgress.h"
-#include "FileItem.h"
#include "games/addons/GameClient.h"
#include "guilib/GUIComponent.h"
#include "guilib/GUIWindowManager.h"
#include "guilib/WindowIDs.h"
-#include "GUIPassword.h"
-#include "PlayListPlayer.h"
-#include "ServiceBroker.h"
+#include "media/MediaLockState.h"
#include "settings/MediaSourceSettings.h"
#include "settings/Settings.h"
#include "settings/SettingsComponent.h"
-#include "URL.h"
-#include "Util.h"
#include "utils/StringUtils.h"
#include "utils/URIUtils.h"
@@ -264,6 +266,13 @@ bool CGUIWindowGames::GetDirectory(const std::string &strDirectory, CFileItemLis
if (!content.empty())
items.SetContent(content);
+ // Ensure a game info tag is created so that files are recognized as games
+ for (const CFileItemPtr& item : items)
+ {
+ if (!item->m_bIsFolder)
+ item->GetGameInfoTag();
+ }
+
return true;
}
@@ -284,7 +293,7 @@ std::string CGUIWindowGames::GetStartFolder(const std::string &dir)
int iIndex = CUtil::GetMatchingSource(dir, shares, bIsSourceName);
if (iIndex >= 0)
{
- if (iIndex < (int)shares.size() && shares[iIndex].m_iHasLock == 2)
+ if (iIndex < static_cast<int>(shares.size()) && shares[iIndex].m_iHasLock == LOCK_STATE_LOCKED)
{
CFileItem item(shares[iIndex]);
if (!g_passwordManager.IsItemUnlocked(&item, "games"))
diff --git a/xbmc/guilib/GUIFadeLabelControl.cpp b/xbmc/guilib/GUIFadeLabelControl.cpp
index 3eaa2c5e5d..51b087f145 100644
--- a/xbmc/guilib/GUIFadeLabelControl.cpp
+++ b/xbmc/guilib/GUIFadeLabelControl.cpp
@@ -44,6 +44,7 @@ CGUIFadeLabelControl::CGUIFadeLabelControl(const CGUIFadeLabelControl &from)
m_shortText = from.m_shortText;
m_scroll = from.m_scroll;
m_randomized = from.m_randomized;
+ m_allLabelsShown = from.m_allLabelsShown;
}
CGUIFadeLabelControl::~CGUIFadeLabelControl(void) = default;
@@ -52,6 +53,7 @@ void CGUIFadeLabelControl::SetInfo(const std::vector<GUIINFO::CGUIInfoLabel> &in
{
m_lastLabel = -1;
m_infoLabels = infoLabels;
+ m_allLabelsShown = m_infoLabels.empty();
if (m_randomized)
KODI::UTILS::RandomShuffle(m_infoLabels.begin(), m_infoLabels.end());
}
@@ -59,6 +61,7 @@ void CGUIFadeLabelControl::SetInfo(const std::vector<GUIINFO::CGUIInfoLabel> &in
void CGUIFadeLabelControl::AddLabel(const std::string &label)
{
m_infoLabels.push_back(GUIINFO::CGUIInfoLabel(label, "", GetParentID()));
+ m_allLabelsShown = false;
}
void CGUIFadeLabelControl::Process(unsigned int currentTime, CDirtyRegionList &dirtyregions)
@@ -89,6 +92,10 @@ void CGUIFadeLabelControl::Process(unsigned int currentTime, CDirtyRegionList &d
}
MarkDirtyRegion();
}
+
+ if (m_shortText && m_infoLabels.size() == 1)
+ m_allLabelsShown = true;
+
if (m_currentLabel != m_lastLabel)
{ // new label - reset scrolling
m_scrollInfo.Reset();
@@ -131,7 +138,10 @@ void CGUIFadeLabelControl::Process(unsigned int currentTime, CDirtyRegionList &d
if (m_fadeAnim.GetProcess() != ANIM_PROCESS_NORMAL)
{
if (++m_currentLabel >= m_infoLabels.size())
+ {
m_currentLabel = 0;
+ m_allLabelsShown = true;
+ }
m_scrollInfo.Reset();
m_fadeAnim.QueueAnimation(ANIM_PROCESS_REVERSE);
}
@@ -216,6 +226,7 @@ bool CGUIFadeLabelControl::OnMessage(CGUIMessage& message)
{
m_lastLabel = -1;
m_infoLabels.clear();
+ m_allLabelsShown = true;
m_scrollInfo.Reset();
return true;
}
@@ -223,6 +234,7 @@ bool CGUIFadeLabelControl::OnMessage(CGUIMessage& message)
{
m_lastLabel = -1;
m_infoLabels.clear();
+ m_allLabelsShown = true;
m_scrollInfo.Reset();
AddLabel(message.GetLabel());
return true;
diff --git a/xbmc/guilib/GUIFadeLabelControl.h b/xbmc/guilib/GUIFadeLabelControl.h
index 3f145f832e..bfb7be69cf 100644
--- a/xbmc/guilib/GUIFadeLabelControl.h
+++ b/xbmc/guilib/GUIFadeLabelControl.h
@@ -39,6 +39,8 @@ public:
void SetInfo(const std::vector<KODI::GUILIB::GUIINFO::CGUIInfoLabel> &vecInfo);
void SetScrolling(bool scroll) { m_scroll = scroll; }
+ bool AllLabelsShown() const { return m_allLabelsShown; }
+
protected:
bool UpdateColors() override;
std::string GetDescription() const override;
@@ -71,5 +73,6 @@ protected:
unsigned int m_scrollSpeed;
bool m_resetOnLabelChange;
bool m_randomized;
+ bool m_allLabelsShown = true;
};
diff --git a/xbmc/guilib/GUIWindowManager.cpp b/xbmc/guilib/GUIWindowManager.cpp
index 3b1e63da05..5ac45daad1 100644
--- a/xbmc/guilib/GUIWindowManager.cpp
+++ b/xbmc/guilib/GUIWindowManager.cpp
@@ -776,9 +776,18 @@ void CGUIWindowManager::ActivateWindow_Internal(int iWindowID, const std::vector
// debug
CLog::Log(LOGDEBUG, "Activating window ID: %i", iWindowID);
+ // make sure we check mediasources from home
+ if (GetActiveWindow() == WINDOW_HOME)
+ g_passwordManager.strMediasourcePath = !params.empty() ? params[0] : "";
+ else
+ g_passwordManager.strMediasourcePath = "";
+
if (!g_passwordManager.CheckMenuLock(iWindowID))
{
- CLog::Log(LOGERROR, "MasterCode is Wrong: Window with id %d will not be loaded! Enter a correct MasterCode!", iWindowID);
+ CLog::Log(LOGERROR,
+ "MasterCode or Mediasource-code is wrong: Window with id {} will not be loaded! "
+ "Enter a correct code!",
+ iWindowID);
if (GetActiveWindow() == WINDOW_INVALID && iWindowID != WINDOW_HOME)
ActivateWindow(WINDOW_HOME);
return;
diff --git a/xbmc/input/InputManager.cpp b/xbmc/input/InputManager.cpp
index a4a4325c63..e10505e79e 100644
--- a/xbmc/input/InputManager.cpp
+++ b/xbmc/input/InputManager.cpp
@@ -418,12 +418,6 @@ bool CInputManager::OnEvent(XBMC_Event& newEvent)
CApplicationMessenger::GetInstance().PostMsg(TMSG_GUI_ACTION, WINDOW_INVALID, -1, static_cast<void*>(new CAction(actionId)));
}
- // Post an unfocus message for touch device after the action.
- if (newEvent.touch.action == ACTION_GESTURE_END || newEvent.touch.action == ACTION_TOUCH_TAP)
- {
- CGUIMessage msg(GUI_MSG_UNFOCUS_ALL, 0, 0, 0, 0);
- CApplicationMessenger::GetInstance().SendGUIMessage(msg);
- }
break;
} //case
case XBMC_BUTTON:
diff --git a/xbmc/interfaces/json-rpc/FileOperations.cpp b/xbmc/interfaces/json-rpc/FileOperations.cpp
index b4d316db30..b498211731 100644
--- a/xbmc/interfaces/json-rpc/FileOperations.cpp
+++ b/xbmc/interfaces/json-rpc/FileOperations.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005-2018 Team Kodi
+ * Copyright (C) 2005-2020 Team Kodi
* This file is part of Kodi - https://kodi.tv
*
* SPDX-License-Identifier: GPL-2.0-or-later
@@ -7,21 +7,23 @@
*/
#include "FileOperations.h"
-#include "VideoLibrary.h"
+
#include "AudioLibrary.h"
+#include "FileItem.h"
#include "MediaSource.h"
#include "ServiceBroker.h"
+#include "URL.h"
+#include "Util.h"
+#include "VideoLibrary.h"
#include "filesystem/Directory.h"
#include "filesystem/File.h"
-#include "FileItem.h"
+#include "media/MediaLockState.h"
#include "settings/AdvancedSettings.h"
#include "settings/MediaSourceSettings.h"
#include "settings/SettingsComponent.h"
-#include "Util.h"
-#include "URL.h"
#include "utils/FileExtensionProvider.h"
-#include "utils/URIUtils.h"
#include "utils/FileUtils.h"
+#include "utils/URIUtils.h"
#include "utils/Variant.h"
#include "video/VideoDatabase.h"
@@ -40,7 +42,7 @@ JSONRPC_STATUS CFileOperations::GetRootDirectory(const std::string &method, ITra
for (unsigned int i = 0; i < (unsigned int)sources->size(); i++)
{
// Do not show sources which are locked
- if (sources->at(i).m_iHasLock == 2)
+ if (sources->at(i).m_iHasLock == LOCK_STATE_LOCKED)
continue;
items.Add(CFileItemPtr(new CFileItem(sources->at(i))));
diff --git a/xbmc/interfaces/legacy/ModuleXbmc.cpp b/xbmc/interfaces/legacy/ModuleXbmc.cpp
index 8e194e59bf..a9a3a5a3c7 100644
--- a/xbmc/interfaces/legacy/ModuleXbmc.cpp
+++ b/xbmc/interfaces/legacy/ModuleXbmc.cpp
@@ -450,7 +450,11 @@ namespace XBMCAddon
else if (strcmpi(id, "time") == 0)
{
result = g_langInfo.GetTimeFormat();
- StringUtils::Replace(result, "H", "%H");
+
+ if (StringUtils::StartsWith(result, "HH"))
+ StringUtils::Replace(result, "HH", "%H");
+ else
+ StringUtils::Replace(result, "H", "%H");
StringUtils::Replace(result, "h", "%I");
StringUtils::Replace(result, "mm", "%M");
StringUtils::Replace(result, "ss", "%S");
diff --git a/xbmc/media/CMakeLists.txt b/xbmc/media/CMakeLists.txt
index dc8f67a834..76b0737684 100644
--- a/xbmc/media/CMakeLists.txt
+++ b/xbmc/media/CMakeLists.txt
@@ -1,5 +1,6 @@
set(SOURCES MediaType.cpp)
-set(HEADERS MediaType.h)
+set(HEADERS MediaLockState.h
+ MediaType.h)
core_add_library(media)
diff --git a/xbmc/media/MediaLockState.h b/xbmc/media/MediaLockState.h
new file mode 100644
index 0000000000..48c1183569
--- /dev/null
+++ b/xbmc/media/MediaLockState.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (C) 2005-2020 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+typedef enum
+{
+ LOCK_STATE_NO_LOCK = 0,
+ LOCK_STATE_LOCK_BUT_UNLOCKED = 1,
+ LOCK_STATE_LOCKED = 2,
+} MediaLockState;
diff --git a/xbmc/music/MusicDatabase.cpp b/xbmc/music/MusicDatabase.cpp
index 1d72b8dd2e..9d7ca5ff6a 100644
--- a/xbmc/music/MusicDatabase.cpp
+++ b/xbmc/music/MusicDatabase.cpp
@@ -5036,31 +5036,36 @@ bool CMusicDatabase::GetArtistsByWhereJSON(const std::set<std::string>& fields,
joinFilter.AppendOrder("a1.idArtist");
joinFilter.AppendGroup("a1.idArtist");
// Album artists and song artists
- if (joinLayout.GetFetch(joinToArtist_isalbumartist) ||
+ if ((joinLayout.GetFetch(joinToArtist_isalbumartist) && !albumArtistsOnly) ||
joinLayout.GetFetch(joinToArtist_idSourceAlbum) ||
joinLayout.GetFetch(joinToArtist_idSongGenreAlbum) ||
joinLayout.GetFetch(joinToArtist_strRole))
{
bJoinAlbumArtist = true;
- albumArtistFilter.AppendGroup("album_artist.idArtist");
albumArtistFilter.AppendField("album_artist.idArtist AS id");
if (!albumArtistsOnly || joinLayout.GetFetch(joinToArtist_strRole))
{
bJoinSongArtist = true;
- songArtistFilter.AppendGroup("song_artist.idArtist");
songArtistFilter.AppendField("song_artist.idArtist AS id");
songArtistFilter.AppendField("1 AS isSong");
albumArtistFilter.AppendField("0 AS isSong");
joinLayout.SetField(joinToArtist_isSong, JSONtoDBArtist[index_firstjoin + joinToArtist_isSong].fieldDB);
+ joinFilter.AppendGroup(JSONtoDBArtist[index_firstjoin + joinToArtist_isSong].fieldDB);
joinFilter.AppendOrder(JSONtoDBArtist[index_firstjoin + joinToArtist_isSong].fieldDB);
}
}
+ else if (joinLayout.GetFetch(joinToArtist_isalbumartist))
+ {
+ // Filtering album artists only and isalbumartist requested but not source, songgenres or roles,
+ // so no need for join to album_artist table. Set fetching fetch false so that
+ // joinLayout.HasFilterFields() is false
+ joinLayout.SetFetch(joinToArtist_isalbumartist, false);
+ }
// Sources
if (joinLayout.GetFetch(joinToArtist_idSourceAlbum))
{ // Left join as source may have been removed but leaving lib entries
albumArtistFilter.AppendJoin("LEFT JOIN album_source ON album_source.idAlbum = album_artist.idAlbum");
- albumArtistFilter.AppendGroup("album_source.idSource");
albumArtistFilter.AppendField(JSONtoDBArtist[index_firstjoin + joinToArtist_idSourceAlbum].SQL);
joinFilter.AppendGroup(JSONtoDBArtist[index_firstjoin + joinToArtist_idSourceAlbum].fieldDB);
joinFilter.AppendOrder(JSONtoDBArtist[index_firstjoin + joinToArtist_idSourceAlbum].fieldDB);
@@ -5068,7 +5073,6 @@ bool CMusicDatabase::GetArtistsByWhereJSON(const std::set<std::string>& fields,
{
songArtistFilter.AppendJoin("JOIN song ON song.idSong = song_artist.idSong");
songArtistFilter.AppendJoin("LEFT JOIN album_source ON album_source.idAlbum = song.idAlbum");
- songArtistFilter.AppendGroup("album_source.idSource");
songArtistFilter.AppendField("-1 AS " + JSONtoDBArtist[index_firstjoin + joinToArtist_idSourceAlbum].fieldDB);
songArtistFilter.AppendField(JSONtoDBArtist[index_firstjoin + joinToArtist_idSourceSong].SQL);
albumArtistFilter.AppendField("-1 AS " + JSONtoDBArtist[index_firstjoin + joinToArtist_idSourceSong].fieldDB);
@@ -5088,7 +5092,6 @@ bool CMusicDatabase::GetArtistsByWhereJSON(const std::set<std::string>& fields,
albumArtistFilter.AppendJoin("JOIN song ON song.idAlbum = album_artist.idAlbum");
albumArtistFilter.AppendJoin("LEFT JOIN song_genre ON song_genre.idSong = song.idSong");
albumArtistFilter.AppendJoin("LEFT JOIN genre ON genre.idGenre = song_genre.idGenre");
- albumArtistFilter.AppendGroup("genre.idGenre");
albumArtistFilter.AppendField(JSONtoDBArtist[index_firstjoin + joinToArtist_idSongGenreAlbum].SQL);
albumArtistFilter.AppendField(JSONtoDBArtist[index_firstjoin + joinToArtist_strSongGenreAlbum].SQL);
joinLayout.SetField(joinToArtist_strSongGenreAlbum, JSONtoDBArtist[index_firstjoin + joinToArtist_strSongGenreAlbum].fieldDB);
@@ -5098,7 +5101,6 @@ bool CMusicDatabase::GetArtistsByWhereJSON(const std::set<std::string>& fields,
{ // Left join genre as songs may not have genre
songArtistFilter.AppendJoin("LEFT JOIN song_genre ON song_genre.idSong = song_artist.idSong");
songArtistFilter.AppendJoin("LEFT JOIN genre ON genre.idGenre = song_genre.idGenre");
- songArtistFilter.AppendGroup("genre.idGenre");
songArtistFilter.AppendField("-1 AS " + JSONtoDBArtist[index_firstjoin + joinToArtist_idSongGenreAlbum].fieldDB);
songArtistFilter.AppendField("'' AS " + JSONtoDBArtist[index_firstjoin + joinToArtist_strSongGenreAlbum].fieldDB);
songArtistFilter.AppendField(JSONtoDBArtist[index_firstjoin + joinToArtist_idSongGenreSong].SQL);
@@ -5191,6 +5193,8 @@ bool CMusicDatabase::GetArtistsByWhereJSON(const std::set<std::string>& fields,
joinFilter.AppendJoin("AND art.type = 'thumb'");
}
}
+ else if (bJoinSongArtist)
+ joinFilter.group.clear(); // UNION only so no GROUP BY needed
// Build JOIN part of query (if we have one)
std::string strSQLJoin;
@@ -5300,12 +5304,13 @@ bool CMusicDatabase::GetArtistsByWhereJSON(const std::set<std::string>& fields,
artistObj["artistid"] = artistId;
artistObj["label"] = record->at(1).get_asString();
artistObj["artist"] = record->at(1).get_asString(); // Always have "artist"
- bIsAlbumArtist = bJoinAlbumArtist; //Album artist by default
- if (bJoinSongArtist)
+ bIsAlbumArtist = true; //Album artist by default
+ if (joinLayout.GetOutput(joinToArtist_isalbumartist))
{
- bIsAlbumArtist = !record->at(joinLayout.GetRecNo(joinToArtist_isSong)).get_asBool();
- if (joinLayout.GetOutput(joinToArtist_isalbumartist))
- artistObj["isalbumartist"] = bIsAlbumArtist;
+ // Not album artist when fetching song artists too and first row for artist isSong=true
+ if (bJoinSongArtist)
+ bIsAlbumArtist = !record->at(joinLayout.GetRecNo(joinToArtist_isSong)).get_asBool();
+ artistObj["isalbumartist"] = bIsAlbumArtist;
}
for (size_t i = 0; i < dbfieldindex.size(); i++)
if (dbfieldindex[i] > -1)
diff --git a/xbmc/music/windows/GUIWindowMusicBase.cpp b/xbmc/music/windows/GUIWindowMusicBase.cpp
index d29fcc6883..e8b58f0dce 100644
--- a/xbmc/music/windows/GUIWindowMusicBase.cpp
+++ b/xbmc/music/windows/GUIWindowMusicBase.cpp
@@ -902,8 +902,13 @@ bool CGUIWindowMusicBase::GetDirectory(const std::string &strDirectory, CFileIte
bool bResult = CGUIMediaWindow::GetDirectory(strDirectory, items);
if (bResult)
{
- // We always want to expand disc images in music windows.
- CDirectory::FilterFileDirectories(items, ".iso", true);
+ // We want to expand disc images when browsing in file view but not on library, smartplaylist
+ // or node menu music windows
+ if (!items.GetPath().empty() &&
+ !StringUtils::StartsWithNoCase(items.GetPath(), "musicdb://") &&
+ !StringUtils::StartsWithNoCase(items.GetPath(), "special://") &&
+ !StringUtils::StartsWithNoCase(items.GetPath(), "library://"))
+ CDirectory::FilterFileDirectories(items, ".iso", true);
CMusicThumbLoader loader;
loader.FillThumb(items);
diff --git a/xbmc/network/httprequesthandler/HTTPVfsHandler.cpp b/xbmc/network/httprequesthandler/HTTPVfsHandler.cpp
index cbf5abd159..ccca1f37e6 100644
--- a/xbmc/network/httprequesthandler/HTTPVfsHandler.cpp
+++ b/xbmc/network/httprequesthandler/HTTPVfsHandler.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011-2018 Team Kodi
+ * Copyright (C) 2011-2020 Team Kodi
* This file is part of Kodi - https://kodi.tv
*
* SPDX-License-Identifier: GPL-2.0-or-later
@@ -9,9 +9,12 @@
#include "HTTPVfsHandler.h"
#include "MediaSource.h"
#include "URL.h"
+#include "Util.h"
#include "filesystem/File.h"
+#include "media/MediaLockState.h"
#include "network/WebServer.h"
#include "settings/MediaSourceSettings.h"
+#include "storage/MediaManager.h"
#include "utils/URIUtils.h"
CHTTPVfsHandler::CHTTPVfsHandler(const HTTPRequest &request)
@@ -39,6 +42,7 @@ CHTTPVfsHandler::CHTTPVfsHandler(const HTTPRequest &request)
while (URIUtils::IsInArchive(realPath))
realPath = CURL(realPath).GetHostName();
+ // Check manually configured sources
VECSOURCES *sources = NULL;
for (unsigned int index = 0; index < size && !accessible; index++)
{
@@ -49,7 +53,7 @@ CHTTPVfsHandler::CHTTPVfsHandler(const HTTPRequest &request)
for (VECSOURCES::const_iterator source = sources->begin(); source != sources->end() && !accessible; ++source)
{
// don't allow access to locked / disabled sharing sources
- if (source->m_iHasLock == 2 || !source->m_allowSharing)
+ if (source->m_iHasLock == LOCK_STATE_LOCKED || !source->m_allowSharing)
continue;
for (std::vector<std::string>::const_iterator path = source->vecPaths.begin(); path != source->vecPaths.end(); ++path)
@@ -62,6 +66,19 @@ CHTTPVfsHandler::CHTTPVfsHandler(const HTTPRequest &request)
}
}
}
+
+ // Check auto-mounted sources
+ if (!accessible)
+ {
+ bool isSource;
+ VECSOURCES removableSources;
+ g_mediaManager.GetRemovableDrives(removableSources);
+ int sourceIndex = CUtil::GetMatchingSource(realPath, removableSources, isSource);
+ if (sourceIndex >= 0 && sourceIndex < static_cast<int>(removableSources.size()) &&
+ removableSources.at(sourceIndex).m_iHasLock != LOCK_STATE_LOCKED &&
+ removableSources.at(sourceIndex).m_allowSharing)
+ accessible = true;
+ }
}
}
diff --git a/xbmc/pictures/GUIWindowPictures.cpp b/xbmc/pictures/GUIWindowPictures.cpp
index 8448b509f3..e9854f2fe9 100644
--- a/xbmc/pictures/GUIWindowPictures.cpp
+++ b/xbmc/pictures/GUIWindowPictures.cpp
@@ -1,41 +1,43 @@
/*
- * Copyright (C) 2005-2018 Team Kodi
+ * Copyright (C) 2005-2020 Team Kodi
* This file is part of Kodi - https://kodi.tv
*
* SPDX-License-Identifier: GPL-2.0-or-later
* See LICENSES/README.md for more information.
*/
-#include "threads/SystemClock.h"
#include "GUIWindowPictures.h"
+
+#include "Application.h"
+#include "Autorun.h"
+#include "GUIDialogPictureInfo.h"
+#include "GUIPassword.h"
+#include "GUIWindowSlideShow.h"
+#include "PictureInfoLoader.h"
+#include "PlayListPlayer.h"
#include "ServiceBroker.h"
#include "URL.h"
#include "Util.h"
-#include "Application.h"
-#include "GUIPassword.h"
-#include "GUIDialogPictureInfo.h"
#include "addons/GUIDialogAddonInfo.h"
#include "dialogs/GUIDialogMediaSource.h"
#include "dialogs/GUIDialogProgress.h"
-#include "playlists/PlayListFactory.h"
-#include "PictureInfoLoader.h"
#include "guilib/GUIComponent.h"
#include "guilib/GUIWindowManager.h"
-#include "view/GUIViewState.h"
+#include "interfaces/AnnouncementManager.h"
+#include "media/MediaLockState.h"
#include "messaging/helpers/DialogOKHelper.h"
-#include "PlayListPlayer.h"
#include "playlists/PlayList.h"
+#include "playlists/PlayListFactory.h"
#include "settings/MediaSourceSettings.h"
#include "settings/Settings.h"
#include "settings/SettingsComponent.h"
-#include "utils/log.h"
-#include "utils/URIUtils.h"
-#include "utils/Variant.h"
-#include "Autorun.h"
-#include "interfaces/AnnouncementManager.h"
+#include "threads/SystemClock.h"
#include "utils/SortUtils.h"
#include "utils/StringUtils.h"
-#include "GUIWindowSlideShow.h"
+#include "utils/URIUtils.h"
+#include "utils/Variant.h"
+#include "utils/log.h"
+#include "view/GUIViewState.h"
#ifdef TARGET_POSIX
#include "platform/linux/XTimeUtils.h"
@@ -602,7 +604,7 @@ std::string CGUIWindowPictures::GetStartFolder(const std::string &dir)
int iIndex = CUtil::GetMatchingSource(dir, shares, bIsSourceName);
if (iIndex > -1)
{
- if (iIndex < (int)shares.size() && shares[iIndex].m_iHasLock == 2)
+ if (iIndex < static_cast<int>(shares.size()) && shares[iIndex].m_iHasLock == LOCK_STATE_LOCKED)
{
CFileItem item(shares[iIndex]);
if (!g_passwordManager.IsItemUnlocked(&item,"pictures"))
diff --git a/xbmc/pictures/SlideShowPicture.cpp b/xbmc/pictures/SlideShowPicture.cpp
index 05848191d2..08fc754471 100644
--- a/xbmc/pictures/SlideShowPicture.cpp
+++ b/xbmc/pictures/SlideShowPicture.cpp
@@ -32,6 +32,8 @@ using namespace DirectX;
using namespace Microsoft::WRL;
#endif
+#include <cstddef>
+
#define IMMEDIATE_TRANSITION_TIME 20
#define PICTURE_MOVE_AMOUNT 0.02f
diff --git a/xbmc/platform/android/activity/XBMCApp.cpp b/xbmc/platform/android/activity/XBMCApp.cpp
index 7eb51fe57e..dc741d50c6 100644
--- a/xbmc/platform/android/activity/XBMCApp.cpp
+++ b/xbmc/platform/android/activity/XBMCApp.cpp
@@ -214,6 +214,7 @@ void CXBMCApp::onStart()
intentFilter.addAction("android.intent.action.BATTERY_CHANGED");
intentFilter.addAction("android.intent.action.SCREEN_ON");
intentFilter.addAction("android.intent.action.HEADSET_PLUG");
+ intentFilter.addAction("android.media.AUDIO_BECOMING_NOISY");
// We currently use HDMI_AUDIO_PLUG for mode switch, don't use it on TV's (device_type = "0"
if (m_hdmiSource)
intentFilter.addAction("android.media.action.HDMI_AUDIO_PLUG");
@@ -1028,6 +1029,12 @@ void CXBMCApp::onReceive(CJNIIntent intent)
if (m_playback_state & PLAYBACK_STATE_VIDEO)
CApplicationMessenger::GetInstance().PostMsg(TMSG_GUI_ACTION, WINDOW_INVALID, -1, static_cast<void*>(new CAction(ACTION_STOP)));
}
+ else if (action == "android.media.AUDIO_BECOMING_NOISY")
+ {
+ if ((m_playback_state & PLAYBACK_STATE_PLAYING) && (m_playback_state & PLAYBACK_STATE_AUDIO))
+ CApplicationMessenger::GetInstance().PostMsg(TMSG_GUI_ACTION, WINDOW_INVALID, -1,
+ static_cast<void*>(new CAction(ACTION_PAUSE)));
+ }
else if (action == "android.intent.action.MEDIA_BUTTON")
{
if (m_playback_state == PLAYBACK_STATE_STOPPED)
@@ -1181,10 +1188,9 @@ int CXBMCApp::WaitForActivityResult(const CJNIIntent &intent, int requestCode, C
void CXBMCApp::onVolumeChanged(int volume)
{
- // System volume was used; Reset Kodi volume to 100% if it isn't, already
- if (g_application.GetVolume(false) != 1.0)
- CApplicationMessenger::GetInstance().PostMsg(TMSG_GUI_ACTION, WINDOW_INVALID, -1, static_cast<void*>(
- new CAction(ACTION_VOLUME_SET, static_cast<float>(CXBMCApp::GetMaxSystemVolume()))));
+ // don't do anything. User wants to use kodi's internal volume freely while
+ // using the external volume to change it relatively
+ // See: https://forum.kodi.tv/showthread.php?tid=350764
}
void CXBMCApp::onAudioFocusChange(int focusChange)
diff --git a/xbmc/platform/darwin/ios/IOSEAGLView.mm b/xbmc/platform/darwin/ios/IOSEAGLView.mm
index 29658fb295..61cc64d454 100644
--- a/xbmc/platform/darwin/ios/IOSEAGLView.mm
+++ b/xbmc/platform/darwin/ios/IOSEAGLView.mm
@@ -60,7 +60,7 @@ using namespace KODI::MESSAGING;
//--------------------------------------------------------------
- (void) resizeFrameBuffer
{
- auto frame = currentScreen == UIScreen.mainScreen ? self.bounds : currentScreen.bounds;
+ auto frame = currentScreen.bounds;
CAEAGLLayer *eaglLayer = (CAEAGLLayer *)[self layer];
//allow a maximum framebuffer size of 1080p
//needed for tvout on iPad3/4 and iphone4/5 and maybe AppleTV3
@@ -410,6 +410,7 @@ using namespace KODI::MESSAGING;
CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_startFullScreen = true;
CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_canWindowed = false;
xbmcAlive = TRUE;
+ [g_xbmcController onXbmcAlive];
try
{
CCocoaAutoPool innerpool;
diff --git a/xbmc/platform/darwin/ios/IOSScreenManager.mm b/xbmc/platform/darwin/ios/IOSScreenManager.mm
index c49458acd6..5c458e0bc8 100644
--- a/xbmc/platform/darwin/ios/IOSScreenManager.mm
+++ b/xbmc/platform/darwin/ios/IOSScreenManager.mm
@@ -118,6 +118,7 @@ static CEvent screenChangeEvent;
{
[[IOSScreenManager sharedInstance] fadeFromBlack:timeSwitchingToInternalSecs];
}
+ [g_xbmcController setGUIInsetsFromMainThread:YES];
int w = [[newScreen currentMode] size].width;
int h = [[newScreen currentMode] size].height;
diff --git a/xbmc/platform/darwin/ios/XBMCController.h b/xbmc/platform/darwin/ios/XBMCController.h
index 8fffbefc3c..1b9a5c00cb 100644
--- a/xbmc/platform/darwin/ios/XBMCController.h
+++ b/xbmc/platform/darwin/ios/XBMCController.h
@@ -67,6 +67,8 @@ typedef enum
- (void) sendKey: (XBMCKey) key;
- (void) observeDefaultCenterStuff: (NSNotification *) notification;
- (CGRect)fullscreenSubviewFrame;
+- (void)onXbmcAlive;
+- (void)setGUIInsetsFromMainThread:(BOOL)isMainThread;
- (void) setFramebuffer;
- (bool) presentFramebuffer;
- (CGSize) getScreenSize;
diff --git a/xbmc/platform/darwin/ios/XBMCController.mm b/xbmc/platform/darwin/ios/XBMCController.mm
index b8930a84dc..acded1c068 100644
--- a/xbmc/platform/darwin/ios/XBMCController.mm
+++ b/xbmc/platform/darwin/ios/XBMCController.mm
@@ -11,6 +11,7 @@
#include "ServiceBroker.h"
#include "settings/AdvancedSettings.h"
+#include "settings/DisplaySettings.h"
#include "settings/Settings.h"
#include "FileItem.h"
#include "music/tags/MusicInfoTag.h"
@@ -572,8 +573,7 @@ XBMCController *g_xbmcController;
self.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
self.view.autoresizesSubviews = YES;
- m_glView = [[IOSEAGLView alloc] initWithFrame:[self fullscreenSubviewFrame]
- withScreen:UIScreen.mainScreen];
+ m_glView = [[IOSEAGLView alloc] initWithFrame:self.view.bounds withScreen:UIScreen.mainScreen];
[[IOSScreenManager sharedInstance] setView:m_glView];
[m_glView setMultipleTouchEnabled:YES];
@@ -686,6 +686,46 @@ XBMCController *g_xbmcController;
return rect;
}
//--------------------------------------------------------------
+- (void)onXbmcAlive
+{
+ [self setGUIInsetsFromMainThread:NO];
+}
+//--------------------------------------------------------------
+- (void)setGUIInsetsFromMainThread:(BOOL)isMainThread
+{
+ auto& guiInsets = CDisplaySettings::GetInstance().GetCurrentResolutionInfo().guiInsets;
+
+ // disable insets for external screen
+ if ([[IOSScreenManager sharedInstance] isExternalScreen])
+ {
+ guiInsets = EdgeInsets{};
+ return;
+ }
+
+ // apply safe area to Kodi GUI
+ if (@available(ios 11.0, *))
+ {
+ UIEdgeInsets __block insets;
+ auto getInsets = ^{
+ insets = m_window.safeAreaInsets;
+ };
+ if (isMainThread)
+ getInsets();
+ else
+ dispatch_sync(dispatch_get_main_queue(), getInsets);
+
+ CLog::Log(LOGDEBUG, "insets: {}\nwindow: {}\nscreen: {}",
+ NSStringFromUIEdgeInsets(insets).UTF8String, m_window.description.UTF8String,
+ m_glView.currentScreen.description.UTF8String);
+ if (UIEdgeInsetsEqualToEdgeInsets(insets, UIEdgeInsetsZero))
+ return;
+
+ auto scale = [m_glView getScreenScale:m_glView.currentScreen];
+ guiInsets = EdgeInsets(insets.left * scale, insets.top * scale, insets.right * scale,
+ insets.bottom * scale);
+ }
+}
+//--------------------------------------------------------------
- (void) setFramebuffer
{
[m_glView setFramebuffer];
diff --git a/xbmc/playlists/PlayListXML.cpp b/xbmc/playlists/PlayListXML.cpp
index 8d13db3abf..5876ba78b3 100644
--- a/xbmc/playlists/PlayListXML.cpp
+++ b/xbmc/playlists/PlayListXML.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005-2018 Team Kodi
+ * Copyright (C) 2005-2020 Team Kodi
* This file is part of Kodi - https://kodi.tv
*
* SPDX-License-Identifier: GPL-2.0-or-later
@@ -7,13 +7,15 @@
*/
#include "PlayListXML.h"
-#include "filesystem/File.h"
+
#include "Util.h"
-#include "utils/log.h"
+#include "filesystem/File.h"
+#include "media/MediaLockState.h"
#include "utils/StringUtils.h"
#include "utils/URIUtils.h"
-#include "utils/XMLUtils.h"
#include "utils/Variant.h"
+#include "utils/XMLUtils.h"
+#include "utils/log.h"
using namespace PLAYLIST;
using namespace XFILE;
@@ -135,7 +137,7 @@ bool CPlayListXML::Load( const std::string& strFileName )
if ( !lockpass.empty() )
{
newItem->m_strLockCode = lockpass;
- newItem->m_iHasLock = 2;
+ newItem->m_iHasLock = LOCK_STATE_LOCKED;
newItem->m_iLockMode = LOCK_MODE_NUMERIC;
}
@@ -180,7 +182,7 @@ void CPlayListXML::Save(const std::string& strFileName) const
if ( !item->GetProperty("remotechannel").empty() )
write += StringUtils::Format(" <channel>%s</channel>", item->GetProperty("remotechannel").c_str() );
- if ( item->m_iHasLock > 0 )
+ if (item->m_iHasLock > LOCK_STATE_NO_LOCK)
write += StringUtils::Format(" <lockpassword>%s<lockpassword>", item->m_strLockCode.c_str() );
write += StringUtils::Format(" </stream>\n\n" );
diff --git a/xbmc/profiles/ProfileManager.cpp b/xbmc/profiles/ProfileManager.cpp
index d92e6e92c2..d4c3807844 100644
--- a/xbmc/profiles/ProfileManager.cpp
+++ b/xbmc/profiles/ProfileManager.cpp
@@ -130,6 +130,12 @@ void CProfileManager::OnSettingsLoaded()
CDirectory::Create(URIUtils::AddFileToFolder(strDir,"mixed"));
}
+void CProfileManager::OnSettingsSaved() const
+{
+ // save mastercode
+ Save();
+}
+
void CProfileManager::OnSettingsCleared()
{
Clear();
@@ -429,17 +435,11 @@ void CProfileManager::FinalizeLoadProfile()
// Load initial window
int firstWindow = g_SkinInfo->GetFirstWindow();
- // the startup window is considered part of the initialization as it most likely switches to the final window
- bool uiInitializationFinished = firstWindow != WINDOW_STARTUP_ANIM;
-
CServiceBroker::GetGUI()->GetWindowManager().ChangeActiveWindow(firstWindow);
- // if the user interfaces has been fully initialized let everyone know
- if (uiInitializationFinished)
- {
- CGUIMessage msg(GUI_MSG_NOTIFY_ALL, WINDOW_SETTINGS_PROFILES, 0, GUI_MSG_UI_READY);
- CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg);
- }
+ //the user interfaces has been fully initialized, let everyone know
+ CGUIMessage msg(GUI_MSG_NOTIFY_ALL, WINDOW_SETTINGS_PROFILES, 0, GUI_MSG_UI_READY);
+ CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg);
}
void CProfileManager::LogOff()
diff --git a/xbmc/profiles/ProfileManager.h b/xbmc/profiles/ProfileManager.h
index c05a3d3b09..91efcdc709 100644
--- a/xbmc/profiles/ProfileManager.h
+++ b/xbmc/profiles/ProfileManager.h
@@ -35,6 +35,7 @@ public:
void Uninitialize();
void OnSettingsLoaded() override;
+ void OnSettingsSaved() const override;
void OnSettingsCleared() override;
bool Load();
diff --git a/xbmc/profiles/dialogs/GUIDialogProfileSettings.cpp b/xbmc/profiles/dialogs/GUIDialogProfileSettings.cpp
index 222d1fa2c8..070ea0ae46 100644
--- a/xbmc/profiles/dialogs/GUIDialogProfileSettings.cpp
+++ b/xbmc/profiles/dialogs/GUIDialogProfileSettings.cpp
@@ -33,6 +33,8 @@
#include "utils/Variant.h"
#include "ServiceBroker.h"
+#include <cassert>
+
#define SETTING_PROFILE_NAME "profile.name"
#define SETTING_PROFILE_IMAGE "profile.image"
#define SETTING_PROFILE_DIRECTORY "profile.directory"
diff --git a/xbmc/programs/GUIWindowPrograms.cpp b/xbmc/programs/GUIWindowPrograms.cpp
index 813d6d7b97..b0894ae9a7 100644
--- a/xbmc/programs/GUIWindowPrograms.cpp
+++ b/xbmc/programs/GUIWindowPrograms.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005-2018 Team Kodi
+ * Copyright (C) 2005-2020 Team Kodi
* This file is part of Kodi - https://kodi.tv
*
* SPDX-License-Identifier: GPL-2.0-or-later
@@ -7,18 +7,20 @@
*/
#include "GUIWindowPrograms.h"
-#include "Util.h"
+
+#include "Autorun.h"
+#include "FileItem.h"
#include "GUIPassword.h"
+#include "ServiceBroker.h"
+#include "Util.h"
#include "addons/GUIDialogAddonInfo.h"
-#include "Autorun.h"
#include "dialogs/GUIDialogMediaSource.h"
#include "guilib/GUIComponent.h"
#include "guilib/GUIWindowManager.h"
-#include "FileItem.h"
-#include "settings/MediaSourceSettings.h"
#include "input/Key.h"
+#include "media/MediaLockState.h"
+#include "settings/MediaSourceSettings.h"
#include "utils/StringUtils.h"
-#include "ServiceBroker.h"
#define CONTROL_BTNVIEWASICONS 2
#define CONTROL_BTNSORTBY 3
@@ -157,7 +159,7 @@ std::string CGUIWindowPrograms::GetStartFolder(const std::string &dir)
int iIndex = CUtil::GetMatchingSource(dir, shares, bIsSourceName);
if (iIndex > -1)
{
- if (iIndex < (int)shares.size() && shares[iIndex].m_iHasLock == 2)
+ if (iIndex < static_cast<int>(shares.size()) && shares[iIndex].m_iHasLock == LOCK_STATE_LOCKED)
{
CFileItem item(shares[iIndex]);
if (!g_passwordManager.IsItemUnlocked(&item,"programs"))
diff --git a/xbmc/pvr/PVRGUIInfo.cpp b/xbmc/pvr/PVRGUIInfo.cpp
index 7988e610c5..91daa2a2d3 100644
--- a/xbmc/pvr/PVRGUIInfo.cpp
+++ b/xbmc/pvr/PVRGUIInfo.cpp
@@ -396,6 +396,8 @@ bool CPVRGUIInfo::GetListItemAndPlayerLabel(const CFileItem *item, const CGUIInf
case VIDEOPLAYER_EPISODENAME:
case LISTITEM_EPISODENAME:
strValue = recording->EpisodeName();
+ // fixup multiline episode name strings (which do not fit in any way in our GUI)
+ StringUtils::Replace(strValue, "\n", ", ");
return true;
case VIDEOPLAYER_CHANNEL_NAME:
case LISTITEM_CHANNEL_NAME:
@@ -574,7 +576,11 @@ bool CPVRGUIInfo::GetListItemAndPlayerLabel(const CFileItem *item, const CGUIInf
case VIDEOPLAYER_EPISODENAME:
case LISTITEM_EPISODENAME:
if (!CServiceBroker::GetPVRManager().IsParentalLocked(epgTag))
+ {
strValue = epgTag->EpisodeName();
+ // fixup multiline episode name strings (which do not fit in any way in our GUI)
+ StringUtils::Replace(strValue, "\n", ", ");
+ }
return true;
case VIDEOPLAYER_CAST:
case LISTITEM_CAST:
diff --git a/xbmc/pvr/epg/EpgContainer.cpp b/xbmc/pvr/epg/EpgContainer.cpp
index 22092616dc..c8fadbfdbe 100644
--- a/xbmc/pvr/epg/EpgContainer.cpp
+++ b/xbmc/pvr/epg/EpgContainer.cpp
@@ -112,8 +112,9 @@ CPVREpgContainer::~CPVREpgContainer(void)
CPVREpgDatabasePtr CPVREpgContainer::GetEpgDatabase() const
{
CSingleLock lock(m_critSection);
- if (!m_database || !m_database->IsOpen())
- CLog::LogF(LOGERROR, "Failed to open the EPG database");
+
+ if (!m_database->IsOpen())
+ m_database->Open();
return m_database;
}
@@ -190,8 +191,6 @@ void CPVREpgContainer::Start(bool bAsync)
{
CSingleLock lock(m_critSection);
- m_database->Open();
-
m_bIsInitialising = true;
m_bStop = false;
@@ -267,11 +266,12 @@ void CPVREpgContainer::LoadFromDB(void)
CPVRGUIProgressHandler* progressHandler = new CPVRGUIProgressHandler(g_localizeStrings.Get(19250)); // Loading guide from database
const CDateTime cleanupTime(CDateTime::GetUTCDateTime() - CDateTimeSpan(GetPastDaysToDisplay(), 0, 0, 0));
- m_database->Lock();
- m_iNextEpgId = m_database->GetLastEPGId();
- m_database->DeleteEpgEntries(cleanupTime);
- const std::vector<std::shared_ptr<CPVREpg>> result = m_database->GetAll();
- m_database->Unlock();
+ const std::shared_ptr<CPVREpgDatabase> database = GetEpgDatabase();
+ database->Lock();
+ m_iNextEpgId = database->GetLastEPGId();
+ database->DeleteEpgEntries(cleanupTime);
+ const std::vector<std::shared_ptr<CPVREpg>> result = database->GetAll();
+ database->Unlock();
for (const auto& entry : result)
InsertFromDB(entry);
@@ -284,7 +284,7 @@ void CPVREpgContainer::LoadFromDB(void)
progressHandler->UpdateProgress(epgEntry.second->Name(), ++iCounter, m_epgIdToEpgMap.size());
lock.Leave();
- epgEntry.second->Load(GetEpgDatabase());
+ epgEntry.second->Load(database);
lock.Enter();
}
@@ -574,7 +574,7 @@ bool CPVREpgContainer::RemoveOldEntries(void)
/* remove the old entries from the database */
if (!IgnoreDB())
- m_database->DeleteEpgEntries(cleanupTime);
+ GetEpgDatabase()->DeleteEpgEntries(cleanupTime);
CSingleLock lock(m_critSection);
CDateTime::GetCurrentDateTime().GetAsUTCDateTime().GetAsTime(m_iLastEpgCleanup);
@@ -600,7 +600,7 @@ bool CPVREpgContainer::DeleteEpg(const CPVREpgPtr &epg, bool bDeleteFromDatabase
CLog::LogFC(LOGDEBUG, LOGEPG, "Deleting EPG table %s (%d)", epg->Name().c_str(), epg->EpgID());
if (bDeleteFromDatabase && !IgnoreDB())
- m_database->Delete(*epgEntry->second);
+ GetEpgDatabase()->Delete(*epgEntry->second);
epgEntry->second->UnregisterObserver(this);
m_epgIdToEpgMap.erase(epgEntry);
diff --git a/xbmc/settings/MediaSourceSettings.cpp b/xbmc/settings/MediaSourceSettings.cpp
index 48120af130..84fde88448 100644
--- a/xbmc/settings/MediaSourceSettings.cpp
+++ b/xbmc/settings/MediaSourceSettings.cpp
@@ -1,27 +1,29 @@
/*
- * Copyright (C) 2013-2018 Team Kodi
+ * Copyright (C) 2013-2020 Team Kodi
* This file is part of Kodi - https://kodi.tv
*
* SPDX-License-Identifier: GPL-2.0-or-later
* See LICENSES/README.md for more information.
*/
-#include <cstdlib>
-#include <string>
-
#include "MediaSourceSettings.h"
+
+#include "ServiceBroker.h"
#include "URL.h"
#include "Util.h"
#include "filesystem/File.h"
+#include "media/MediaLockState.h"
+#include "network/WakeOnAccess.h"
#include "profiles/ProfileManager.h"
#include "settings/SettingsComponent.h"
-#include "utils/log.h"
#include "utils/StringUtils.h"
#include "utils/URIUtils.h"
#include "utils/XBMCTinyXML.h"
#include "utils/XMLUtils.h"
-#include "network/WakeOnAccess.h"
-#include "ServiceBroker.h"
+#include "utils/log.h"
+
+#include <cstdlib>
+#include <string>
#define SOURCES_FILE "sources.xml"
#define XML_SOURCES "sources"
@@ -398,7 +400,7 @@ bool CMediaSourceSettings::GetSource(const std::string &category, const TiXmlNod
if (pLockMode)
{
share.m_iLockMode = (LockType)std::strtol(pLockMode->FirstChild()->Value(), NULL, 10);
- share.m_iHasLock = 2;
+ share.m_iHasLock = LOCK_STATE_LOCKED;
}
if (pLockCode && pLockCode->FirstChild())
diff --git a/xbmc/utils/FileUtils.cpp b/xbmc/utils/FileUtils.cpp
index 9f19808b4e..a39f4f0f1b 100644
--- a/xbmc/utils/FileUtils.cpp
+++ b/xbmc/utils/FileUtils.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010-2018 Team Kodi
+ * Copyright (C) 2010-2020 Team Kodi
* This file is part of Kodi - https://kodi.tv
*
* SPDX-License-Identifier: GPL-2.0-or-later
@@ -7,24 +7,26 @@
*/
#include "FileUtils.h"
-#include "ServiceBroker.h"
-#include "guilib/GUIKeyboardFactory.h"
-#include "utils/log.h"
-#include "guilib/LocalizeStrings.h"
-#include "JobManager.h"
+
#include "FileOperationJob.h"
+#include "JobManager.h"
+#include "ServiceBroker.h"
+#include "StringUtils.h"
#include "URIUtils.h"
+#include "URL.h"
+#include "Util.h"
#include "filesystem/MultiPathDirectory.h"
#include "filesystem/SpecialProtocol.h"
#include "filesystem/StackDirectory.h"
+#include "guilib/GUIKeyboardFactory.h"
+#include "guilib/LocalizeStrings.h"
+#include "media/MediaLockState.h"
#include "settings/MediaSourceSettings.h"
-#include "Util.h"
-#include "StringUtils.h"
-#include "URL.h"
#include "settings/Settings.h"
#include "settings/SettingsComponent.h"
#include "storage/MediaManager.h"
#include "utils/Variant.h"
+#include "utils/log.h"
#if defined(TARGET_WINDOWS)
#include "platform/win32/WIN32Util.h"
@@ -144,7 +146,9 @@ bool CFileUtils::RemoteAccessAllowed(const std::string &strPath)
{
VECSOURCES* sources = CMediaSourceSettings::GetInstance().GetSources(sourceName);
int sourceIndex = CUtil::GetMatchingSource(realPath, *sources, isSource);
- if (sourceIndex >= 0 && sourceIndex < (int)sources->size() && sources->at(sourceIndex).m_iHasLock != 2 && sources->at(sourceIndex).m_allowSharing)
+ if (sourceIndex >= 0 && sourceIndex < static_cast<int>(sources->size()) &&
+ sources->at(sourceIndex).m_iHasLock != LOCK_STATE_LOCKED &&
+ sources->at(sourceIndex).m_allowSharing)
return true;
}
// Check auto-mounted sources
@@ -152,8 +156,9 @@ bool CFileUtils::RemoteAccessAllowed(const std::string &strPath)
g_mediaManager.GetRemovableDrives(sources); // Sources returned allways have m_allowsharing = true
//! @todo Make sharing of auto-mounted sources user configurable
int sourceIndex = CUtil::GetMatchingSource(realPath, sources, isSource);
- if (sourceIndex >= 0 && sourceIndex < static_cast<int>(sources.size()) &&
- sources.at(sourceIndex).m_iHasLock != 2 && sources.at(sourceIndex).m_allowSharing)
+ if (sourceIndex >= 0 && sourceIndex < static_cast<int>(sources.size()) &&
+ sources.at(sourceIndex).m_iHasLock != LOCK_STATE_LOCKED &&
+ sources.at(sourceIndex).m_allowSharing)
return true;
return false;
diff --git a/xbmc/utils/LangCodeExpander.cpp b/xbmc/utils/LangCodeExpander.cpp
index 7edcd7567f..8c7ea59259 100644
--- a/xbmc/utils/LangCodeExpander.cpp
+++ b/xbmc/utils/LangCodeExpander.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005-2018 Team Kodi
+ * Copyright (C) 2005-2020 Team Kodi
* This file is part of Kodi - https://kodi.tv
*
* SPDX-License-Identifier: GPL-2.0-or-later
@@ -22,8 +22,8 @@ typedef struct LCENTRY
const char *name;
} LCENTRY;
-extern const std::array<struct LCENTRY, 185> g_iso639_1;
-extern const std::array<struct LCENTRY, 538> g_iso639_2;
+extern const std::array<struct LCENTRY, 186> g_iso639_1;
+extern const std::array<struct LCENTRY, 540> g_iso639_2;
struct ISO639
{
@@ -40,7 +40,7 @@ struct ISO3166_1
};
// declared as extern to allow forward declaration
-extern const std::array<ISO639, 189> LanguageCodes;
+extern const std::array<ISO639, 190> LanguageCodes;
extern const std::array<ISO3166_1, 245> RegionCodes;
CLangCodeExpander::CLangCodeExpander() = default;
@@ -535,7 +535,7 @@ std::string CLangCodeExpander::ConvertToISO6392T(const std::string& lang)
return lang;
}
-const std::array<struct LCENTRY, 185> g_iso639_1 =
+const std::array<struct LCENTRY, 186> g_iso639_1 =
{ {
{ MAKECODE('\0','\0','a','a'), "Afar" },
{ MAKECODE('\0','\0','a','b'), "Abkhazian" },
@@ -668,6 +668,8 @@ const std::array<struct LCENTRY, 185> g_iso639_1 =
{ MAKECODE('\0','\0','p','l'), "Polish" },
{ MAKECODE('\0','\0','p','s'), "Pashto, Pushto" },
{ MAKECODE('\0','\0','p','t'), "Portuguese" },
+ // pb = unofficial language code for Brazilian Portuguese
+ { MAKECODE('\0','\0','p','b'), "Portuguese (Brazil)" },
{ MAKECODE('\0','\0','q','u'), "Quechua" },
{ MAKECODE('\0','\0','r','m'), "Romansh" },
{ MAKECODE('\0','\0','r','n'), "Kirundi" },
@@ -724,7 +726,7 @@ const std::array<struct LCENTRY, 185> g_iso639_1 =
{ MAKECODE('\0','\0','z','u'), "Zulu" },
} };
-const std::array<struct LCENTRY, 538> g_iso639_2 =
+const std::array<struct LCENTRY, 540> g_iso639_2 =
{ {
{ MAKECODE('\0','a','b','k'), "Abkhaz" },
{ MAKECODE('\0','a','b','k'), "Abkhazian" },
@@ -901,6 +903,7 @@ const std::array<struct LCENTRY, 538> g_iso639_2 =
{ MAKECODE('\0','n','d','s'), "German, Low" },
{ MAKECODE('\0','g','m','h'), "German, Middle High (ca.1050-1500)" },
{ MAKECODE('\0','g','o','h'), "German, Old High (ca.750-1050)" },
+ { MAKECODE('\0','g','s','w'), "German, Swiss German"},
{ MAKECODE('\0','g','e','m'), "Germanic (Other)" },
{ MAKECODE('\0','k','i','k'), "Gikuyu" },
{ MAKECODE('\0','g','i','l'), "Gilbertese" },
@@ -1121,6 +1124,8 @@ const std::array<struct LCENTRY, 538> g_iso639_2 =
{ MAKECODE('\0','p','o','n'), "Pohnpeian" },
{ MAKECODE('\0','p','o','l'), "Polish" },
{ MAKECODE('\0','p','o','r'), "Portuguese" },
+ // pob = unofficial language code for Brazilian Portuguese
+ { MAKECODE('\0','p','o','b'), "Portuguese (Brazil)" },
{ MAKECODE('\0','p','r','a'), "Prakrit languages" },
{ MAKECODE('\0','o','c','i'), "Proven\xC3\xA7""al" },
{ MAKECODE('\0','p','r','o'), "Proven\xC3\xA7""al, Old (to 1500)" },
@@ -1268,7 +1273,7 @@ const std::array<struct LCENTRY, 538> g_iso639_2 =
} };
-const std::array<ISO639, 189> LanguageCodes =
+const std::array<ISO639, 190> LanguageCodes =
{ {
{ "aa", "aar", NULL, NULL },
{ "ab", "abk", NULL, NULL },
@@ -1397,6 +1402,8 @@ const std::array<ISO639, 189> LanguageCodes =
{ "om", "orm", NULL, NULL },
{ "os", "oss", NULL, NULL },
{ "pa", "pan", NULL, NULL },
+ // pb / pob = unofficial language code for Brazilian Portuguese
+ { "pb", "pob", NULL, NULL },
{ "pi", "pli", NULL, NULL },
{ "pl", "pol", "plk", NULL },
{ "pt", "por", "ptg", NULL },
diff --git a/xbmc/utils/Mime.cpp b/xbmc/utils/Mime.cpp
index 4f2a9cbac6..3b1291e706 100644
--- a/xbmc/utils/Mime.cpp
+++ b/xbmc/utils/Mime.cpp
@@ -20,6 +20,7 @@
const std::map<std::string, std::string> CMime::m_mimetypes =
{{{"3dm", "x-world/x-3dmf"},
{"3dmf", "x-world/x-3dmf"},
+ {"3fr", "image/3fr"},
{"a", "application/octet-stream"},
{"aab", "application/x-authorware-bin"},
{"aam", "application/x-authorware-map"},
@@ -78,6 +79,7 @@ const std::map<std::string, std::string> CMime::m_mimetypes =
{"crl", "application/pkcs-crl"},
{"crt", "application/pkix-cert"},
{"cr2", "image/cr2"},
+ {"crw", "image/crw"},
{"csh", "application/x-csh"},
{"css", "text/css"},
{"cxx", "text/plain"},
@@ -106,6 +108,7 @@ const std::map<std::string, std::string> CMime::m_mimetypes =
{"elc", "application/x-elc"},
{"env", "application/x-envoy"},
{"eps", "application/postscript"},
+ {"erf", "image/erf"},
{"es", "application/x-esrehber"},
{"etx", "text/x-setext"},
{"evy", "application/envoy"},
@@ -188,6 +191,7 @@ const std::map<std::string, std::string> CMime::m_mimetypes =
{"json", "application/json"},
{"jut", "image/jutvision"},
{"kar", "music/x-karaoke"},
+ {"kdc", "image/kdc"},
{"ksh", "text/x-script.ksh"},
{"la", "audio/nspaudio"},
{"lam", "audio/x-liveaudio"},
@@ -216,7 +220,9 @@ const std::map<std::string, std::string> CMime::m_mimetypes =
{"mcd", "application/x-mathcad"},
{"mcf", "text/mcf"},
{"mcp", "application/netmc"},
+ {"mdc", "image/mdc"},
{"me", "application/x-troff-me"},
+ {"mef", "image/mef"},
{"mht", "message/rfc822"},
{"mhtml", "message/rfc822"},
{"mid", "audio/midi"},
@@ -234,6 +240,7 @@ const std::map<std::string, std::string> CMime::m_mimetypes =
{"moov", "video/quicktime"},
{"mov", "video/quicktime"},
{"movie", "video/x-sgi-movie"},
+ {"mos", "image/mos"},
{"mp2", "audio/mpeg"},
{"mp3", "audio/mpeg3"},
{"mp4", "video/mp4"},
@@ -248,6 +255,7 @@ const std::map<std::string, std::string> CMime::m_mimetypes =
{"mpv", "application/x-project"},
{"mpx", "application/x-project"},
{"mrc", "application/marc"},
+ {"mrw", "image/mrw"},
{"ms", "application/x-troff-ms"},
{"mv", "video/x-sgi-movie"},
{"my", "audio/make"},
@@ -261,6 +269,7 @@ const std::map<std::string, std::string> CMime::m_mimetypes =
{"nif", "image/x-niff"},
{"niff", "image/x-niff"},
{"nix", "application/x-mix-transfer"},
+ {"nrw", "image/nrw"},
{"nsc", "application/x-conference"},
{"nvd", "application/x-navidoc"},
{"o", "application/octet-stream"},
@@ -269,6 +278,7 @@ const std::map<std::string, std::string> CMime::m_mimetypes =
{"omc", "application/x-omc"},
{"omcd", "application/x-omcdatamaker"},
{"omcr", "application/x-omcregerator"},
+ {"orf", "image/orf"},
{"p", "text/x-pascal"},
{"p10", "application/pkcs10"},
{"p12", "application/pkcs-12"},
@@ -285,6 +295,7 @@ const std::map<std::string, std::string> CMime::m_mimetypes =
{"pcx", "image/x-pcx"},
{"pdb", "chemical/x-pdb"},
{"pdf", "application/pdf"},
+ {"pef", "image/pef"},
{"pfunk", "audio/make.my.funk"},
{"pgm", "image/x-portable-greymap"},
{"pic", "image/pict"},
@@ -322,9 +333,11 @@ const std::map<std::string, std::string> CMime::m_mimetypes =
{"qti", "image/x-quicktime"},
{"qtif", "image/x-quicktime"},
{"ra", "audio/x-realaudio"},
+ {"raf", "image/raf"},
{"ram", "audio/x-pn-realaudio"},
{"ras", "image/cmu-raster"},
{"rast", "image/cmu-raster"},
+ {"raw", "image/raw"},
{"rexx", "text/x-script.rexx"},
{"rf", "image/vnd.rn-realflash"},
{"rgb", "image/x-rgb"},
@@ -341,6 +354,7 @@ const std::map<std::string, std::string> CMime::m_mimetypes =
{"rtf", "text/richtext"},
{"rtx", "text/richtext"},
{"rv", "video/vnd.rn-realvideo"},
+ {"rw2", "image/rw2"},
{"s", "text/x-asm"},
{"s3m", "audio/s3m"},
{"saveme", "application/octet-stream"},
@@ -372,6 +386,7 @@ const std::map<std::string, std::string> CMime::m_mimetypes =
{"spr", "application/x-sprite"},
{"sprite", "application/x-sprite"},
{"src", "application/x-wais-source"},
+ {"srw", "image/srw"},
{"ssi", "text/x-server-parsed-html"},
{"ssm", "application/streamingmedia"},
{"sst", "application/vnd.ms-pki.certstore"},
@@ -462,6 +477,7 @@ const std::map<std::string, std::string> CMime::m_mimetypes =
{"wsc", "text/scriplet"},
{"wsrc", "application/x-wais-source"},
{"wtk", "application/x-wintalk"},
+ {"x3f", "image/x3f"},
{"xbm", "image/xbm"},
{"xdr", "video/x-amt-demorun"},
{"xgz", "xgl/drawing"},
diff --git a/xbmc/utils/URIUtils.cpp b/xbmc/utils/URIUtils.cpp
index 3df997841c..f6073e5e8a 100644
--- a/xbmc/utils/URIUtils.cpp
+++ b/xbmc/utils/URIUtils.cpp
@@ -1371,7 +1371,8 @@ std::string URIUtils::resolvePath(const std::string &path)
// put together the path
realPath += StringUtils::Join(realParts, delim);
// re-add any / or \ at the end
- if (path.at(path.size() - 1) == delim.at(0) && realPath.at(realPath.size() - 1) != delim.at(0))
+ if (path.at(path.size() - 1) == delim.at(0) &&
+ realPath.size() > 0 && realPath.at(realPath.size() - 1) != delim.at(0))
realPath += delim;
return realPath;
@@ -1416,8 +1417,3 @@ bool URIUtils::UpdateUrlEncoding(std::string &strFilename)
strFilename = newFilename;
return true;
}
-
-bool URIUtils::IsUsingFastSwitch(const std::string& strFile)
-{
- return IsUDP(strFile) || IsTCP(strFile) || IsPVRChannel(strFile);
-}
diff --git a/xbmc/utils/URIUtils.h b/xbmc/utils/URIUtils.h
index 4ba8bed55b..fec95ce23c 100644
--- a/xbmc/utils/URIUtils.h
+++ b/xbmc/utils/URIUtils.h
@@ -154,7 +154,6 @@ public:
static bool IsLibraryContent(const std::string& strFile);
static bool IsPVRChannel(const std::string& strFile);
static bool IsPVRGuideItem(const std::string& strFile);
- static bool IsUsingFastSwitch(const std::string& strFile);
static std::string AppendSlash(std::string strFolder);
static void AddSlashAtEnd(std::string& strFolder);
diff --git a/xbmc/video/VideoInfoTag.cpp b/xbmc/video/VideoInfoTag.cpp
index 810b5547db..447f0bff80 100644
--- a/xbmc/video/VideoInfoTag.cpp
+++ b/xbmc/video/VideoInfoTag.cpp
@@ -833,7 +833,10 @@ void CVideoInfoTag::ParseNative(const TiXmlElement* movie, bool prioritise)
r.rating = r.rating / max_value * 10; // Normalise the Movie Rating to between 1 and 10
SetRating(r, name);
bool isDefault = false;
- if ((child->QueryBoolAttribute("default", &isDefault) == TIXML_SUCCESS) && isDefault)
+ // guard against assert in tinyxml
+ const char* rAtt = child->Attribute("default", static_cast<int*>(nullptr));
+ if (rAtt && strlen(rAtt) != 0 &&
+ (child->QueryBoolAttribute("default", &isDefault) == TIXML_SUCCESS) && isDefault)
m_strDefaultRating = name;
}
}
diff --git a/xbmc/video/tags/VideoTagLoaderNFO.cpp b/xbmc/video/tags/VideoTagLoaderNFO.cpp
index 1ca311f49e..2f688d6902 100644
--- a/xbmc/video/tags/VideoTagLoaderNFO.cpp
+++ b/xbmc/video/tags/VideoTagLoaderNFO.cpp
@@ -94,7 +94,7 @@ std::string CVideoTagLoaderNFO::FindNFO(const CFileItem& item,
if (URIUtils::IsInRAR(item.GetPath())) // we have a rarred item - we want to check outside the rars
{
CFileItem item2(item);
- CURL url(m_item.GetPath());
+ CURL url(item.GetPath());
std::string strPath = URIUtils::GetDirectory(url.GetHostName());
item2.SetPath(URIUtils::AddFileToFolder(strPath,
URIUtils::GetFileName(item.GetPath())));
diff --git a/xbmc/video/windows/GUIWindowVideoNav.cpp b/xbmc/video/windows/GUIWindowVideoNav.cpp
index 6cb8dde8c9..8d78213e63 100644
--- a/xbmc/video/windows/GUIWindowVideoNav.cpp
+++ b/xbmc/video/windows/GUIWindowVideoNav.cpp
@@ -1019,9 +1019,8 @@ bool CGUIWindowVideoNav::OnContextButton(int itemNumber, CONTEXT_BUTTON button)
item = m_vecItems->Get(itemNumber);
if (CGUIDialogContextMenu::OnContextButton("video", item, button))
{
- //! @todo should we search DB for entries from plugins?
- if (button == CONTEXT_BUTTON_REMOVE_SOURCE && !item->IsPlugin()
- && !item->IsLiveTV() &&!item->IsRSS() && !URIUtils::IsUPnP(item->GetPath()))
+ if (button == CONTEXT_BUTTON_REMOVE_SOURCE && !item->IsLiveTV()
+ && !item->IsRSS() && !URIUtils::IsUPnP(item->GetPath()))
{
// if the source has been properly removed, remove the cached source list because the list has changed
if (OnUnAssignContent(item->GetPath(), 20375, 20340))
diff --git a/xbmc/windowing/GraphicContext.cpp b/xbmc/windowing/GraphicContext.cpp
index 1ced49671b..7a37ce2851 100644
--- a/xbmc/windowing/GraphicContext.cpp
+++ b/xbmc/windowing/GraphicContext.cpp
@@ -24,6 +24,8 @@
#include "guilib/GUIWindowManager.h"
#include "guilib/TextureManager.h"
+#include <cassert>
+
using namespace KODI::MESSAGING;
CGraphicContext::CGraphicContext(void) = default;
@@ -672,10 +674,10 @@ void CGraphicContext::GetGUIScaling(const RESOLUTION_INFO &res, float &scaleX, f
RESOLUTION_INFO info = GetResInfo();
float fFromWidth = (float)res.iWidth;
float fFromHeight = (float)res.iHeight;
- float fToPosX = (float)info.Overscan.left;
- float fToPosY = (float)info.Overscan.top;
- float fToWidth = (float)info.Overscan.right - fToPosX;
- float fToHeight = (float)info.Overscan.bottom - fToPosY;
+ auto fToPosX = info.Overscan.left + info.guiInsets.left;
+ auto fToPosY = info.Overscan.top + info.guiInsets.top;
+ auto fToWidth = info.Overscan.right - info.guiInsets.right - fToPosX;
+ auto fToHeight = info.Overscan.bottom - info.guiInsets.bottom - fToPosY;
float fZoom = (100 + CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_LOOKANDFEEL_SKINZOOM)) * 0.01f;
diff --git a/xbmc/windowing/Resolution.cpp b/xbmc/windowing/Resolution.cpp
index 19a2dde602..4b67a550de 100644
--- a/xbmc/windowing/Resolution.cpp
+++ b/xbmc/windowing/Resolution.cpp
@@ -19,6 +19,10 @@
#include <cstdlib>
+EdgeInsets::EdgeInsets(float l, float t, float r, float b) : left(l), top(t), right(r), bottom(b)
+{
+}
+
RESOLUTION_INFO::RESOLUTION_INFO(int width, int height, float aspect, const std::string &mode) :
strMode(mode)
{
@@ -33,11 +37,12 @@ RESOLUTION_INFO::RESOLUTION_INFO(int width, int height, float aspect, const std:
dwFlags = iSubtitles = 0;
}
-RESOLUTION_INFO::RESOLUTION_INFO(const RESOLUTION_INFO& res) :
- Overscan(res.Overscan),
- strMode(res.strMode),
- strOutput(res.strOutput),
- strId(res.strId)
+RESOLUTION_INFO::RESOLUTION_INFO(const RESOLUTION_INFO& res)
+ : Overscan(res.Overscan),
+ guiInsets(res.guiInsets),
+ strMode(res.strMode),
+ strOutput(res.strOutput),
+ strId(res.strId)
{
bFullScreen = res.bFullScreen;
iWidth = res.iWidth; iHeight = res.iHeight;
diff --git a/xbmc/windowing/Resolution.h b/xbmc/windowing/Resolution.h
index 1567b4c93a..6709d22d03 100644
--- a/xbmc/windowing/Resolution.h
+++ b/xbmc/windowing/Resolution.h
@@ -41,9 +41,21 @@ public:
}
};
+struct EdgeInsets
+{
+ float left = 0.0f;
+ float top = 0.0f;
+ float right = 0.0f;
+ float bottom = 0.0f;
+
+ EdgeInsets() = default;
+ EdgeInsets(float l, float t, float r, float b);
+};
+
struct RESOLUTION_INFO
{
OVERSCAN Overscan;
+ EdgeInsets guiInsets;
bool bFullScreen;
int iWidth;
int iHeight;
diff --git a/xbmc/windowing/android/WinSystemAndroid.cpp b/xbmc/windowing/android/WinSystemAndroid.cpp
index f48de072cd..f9c4797a45 100644
--- a/xbmc/windowing/android/WinSystemAndroid.cpp
+++ b/xbmc/windowing/android/WinSystemAndroid.cpp
@@ -206,6 +206,8 @@ void CWinSystemAndroid::UpdateResolutions(bool bUpdateDesktopRes)
CDisplaySettings::GetInstance().GetResolutionInfo(RES_WINDOW) = res;
}
}
+
+ CDisplaySettings::GetInstance().ApplyCalibrations();
}
void CWinSystemAndroid::OnTimeout()