diff options
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 Binary files differindex 880349919d..23b8c9ed16 100644 --- a/media/splash.jpg +++ b/media/splash.jpg 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 Binary files differnew file mode 100644 index 0000000000..b30d92e128 --- /dev/null +++ b/xbmc/filesystem/test/extendedlocalheader.zip 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() |