diff options
404 files changed, 4163 insertions, 3364 deletions
diff --git a/addons/resource.language.en_gb/resources/strings.po b/addons/resource.language.en_gb/resources/strings.po index 9fb3dcb2b0..cbf612389c 100644 --- a/addons/resource.language.en_gb/resources/strings.po +++ b/addons/resource.language.en_gb/resources/strings.po @@ -8078,15 +8078,7 @@ msgctxt "#14078" msgid "Colours" msgstr "" -#: system/settings/settings.xml -msgctxt "#14079" -msgid "Timezone country" -msgstr "" - -#: system/settings/settings.xml -msgctxt "#14080" -msgid "Timezone" -msgstr "" +#empty strings from id 14072 to 14073 #: system/settings/settings.xml msgctxt "#14081" @@ -19221,17 +19213,7 @@ msgctxt "#36116" msgid "Choose which character set is used for displaying text in the user interface. This doesn't change the character set used for subtitles, for that go to Player > Language." msgstr "" -#. Description of setting with label #14079 "Timezone country" -#: system/settings/settings.xml -msgctxt "#36117" -msgid "Select country location." -msgstr "" - -#. Description of setting with label #14080 "Timezone" -#: system/settings/settings.xml -msgctxt "#36118" -msgid "Select your current timezone." -msgstr "" +#empty strings from id 36117 to 36118 #. Description of setting with label #285 "Preferred audio language" #: system/settings/settings.xml diff --git a/cmake/modules/FindFFMPEG.cmake b/cmake/modules/FindFFMPEG.cmake index 6c6bf973de..76857b0cca 100644 --- a/cmake/modules/FindFFMPEG.cmake +++ b/cmake/modules/FindFFMPEG.cmake @@ -55,6 +55,11 @@ macro(buildFFMPEG) -DOS=${OS} -DCMAKE_AR=${CMAKE_AR}) endif() + + if(USE_LTO) + list(APPEND FFMPEG_OPTIONS -DUSE_LTO=ON) + endif() + set(LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS}) list(APPEND LINKER_FLAGS ${SYSTEM_LDFLAGS}) diff --git a/cmake/modules/FindFlatBuffers.cmake b/cmake/modules/FindFlatBuffers.cmake index 6ddfa389c1..aba609933a 100644 --- a/cmake/modules/FindFlatBuffers.cmake +++ b/cmake/modules/FindFlatBuffers.cmake @@ -9,15 +9,10 @@ find_package(FlatC REQUIRED) if(NOT TARGET flatbuffers::flatbuffers) - if(ENABLE_INTERNAL_FLATBUFFERS) - include(cmake/scripts/common/ModuleHelpers.cmake) - set(MODULE_LC flatbuffers) - # Duplicate URL may exist from FindFlatC.cmake - # unset otherwise it thinks we are providing a local file location and incorrect concatenation happens - unset(FLATBUFFERS_URL) - SETUP_BUILD_VARS() + include(cmake/scripts/common/ModuleHelpers.cmake) + macro(buildflatbuffers) # Override build type detection and always build as release set(FLATBUFFERS_BUILD_TYPE Release) @@ -33,6 +28,22 @@ if(NOT TARGET flatbuffers::flatbuffers) set(BUILD_BYPRODUCTS ${DEPENDS_PATH}/include/flatbuffers/flatbuffers.h) BUILD_DEP_TARGET() + endmacro() + + set(MODULE_LC flatbuffers) + + SETUP_BUILD_VARS() + + find_package(flatbuffers CONFIG + HINTS ${DEPENDS_PATH}/lib/cmake + ${${CORE_PLATFORM_NAME_LC}_SEARCH_CONFIG}) + + # Check for existing Flatbuffers. If version >= FLATBUFFERS-VERSION file version, dont build + # A corner case, but if a linux/freebsd user WANTS to build internal flatbuffers, build anyway + if((flatbuffers_VERSION VERSION_LESS ${${MODULE}_VER} AND ENABLE_INTERNAL_FLATBUFFERS) OR + ((CORE_SYSTEM_NAME STREQUAL linux OR CORE_SYSTEM_NAME STREQUAL freebsd) AND ENABLE_INTERNAL_FLATBUFFERS)) + + buildflatbuffers() else() find_path(FLATBUFFERS_INCLUDE_DIR NAMES flatbuffers/flatbuffers.h HINTS ${DEPENDS_PATH}/include @@ -54,5 +65,22 @@ if(NOT TARGET flatbuffers::flatbuffers) if(TARGET flatbuffers) add_dependencies(flatbuffers::flatbuffers flatbuffers) endif() + + # Add internal build target when a Multi Config Generator is used + # We cant add a dependency based off a generator expression for targeted build types, + # https://gitlab.kitware.com/cmake/cmake/-/issues/19467 + # therefore if the find heuristics only find the library, we add the internal build + # target to the project to allow user to manually trigger for any build type they need + # in case only a specific build type is actually available (eg Release found, Debug Required) + # This is mainly targeted for windows who required different runtime libs for different + # types, and they arent compatible + if(_multiconfig_generator) + if(NOT TARGET flatbuffers) + buildflatbuffers() + set_target_properties(flatbuffers PROPERTIES EXCLUDE_FROM_ALL TRUE) + endif() + add_dependencies(build_internal_depends flatbuffers) + endif() + set_property(GLOBAL APPEND PROPERTY INTERNAL_DEPS_PROP flatbuffers::flatbuffers) endif() diff --git a/cmake/modules/FindNFS.cmake b/cmake/modules/FindNFS.cmake index 9da2a3ca56..2250093749 100644 --- a/cmake/modules/FindNFS.cmake +++ b/cmake/modules/FindNFS.cmake @@ -16,6 +16,14 @@ if(NOT TARGET libnfs::nfs) -DENABLE_UTILS=OFF -DENABLE_EXAMPLES=OFF) + if(WIN32 OR WINDOWS_STORE) + set(${MODULE}_C_FLAGS "/sdl-") + set(${MODULE}_CXX_FLAGS "/sdl-") + + set(patches "${CORE_SOURCE_DIR}/tools/depends/target/${MODULE_LC}/01-MSUWP-compat.patch") + generate_patchcommand("${patches}") + endif() + BUILD_DEP_TARGET() set(_nfs_definitions HAS_NFS_SET_TIMEOUT diff --git a/cmake/modules/FindPCRE.cmake b/cmake/modules/FindPCRE.cmake index 578c4b8923..e662d82116 100644 --- a/cmake/modules/FindPCRE.cmake +++ b/cmake/modules/FindPCRE.cmake @@ -33,11 +33,16 @@ macro(buildPCRE) -DPCRE_SUPPORT_UNICODE_PROPERTIES=ON -DPCRE_SUPPORT_LIBZ=OFF -DPCRE_SUPPORT_LIBBZ2=OFF + -DPCRE_BUILD_PCRECPP=OFF -DPCRE_BUILD_PCREGREP=OFF -DPCRE_BUILD_TESTS=OFF) if(WIN32 OR WINDOWS_STORE) list(APPEND CMAKE_ARGS -DINSTALL_MSVC_PDB=ON) + + # PCRE fails due to C4703 and C4146 when /SDL is enabled + set(PCRE_C_FLAGS "/sdl-") + set(PCRE_CXX_FLAGS "/sdl-") elseif(CORE_SYSTEM_NAME STREQUAL android) # CMake CheckFunctionExists incorrectly detects strtoq for android list(APPEND CMAKE_ARGS -DHAVE_STRTOQ=0) diff --git a/cmake/modules/FindTagLib.cmake b/cmake/modules/FindTagLib.cmake index 6a85cc4383..78a0eeeccb 100644 --- a/cmake/modules/FindTagLib.cmake +++ b/cmake/modules/FindTagLib.cmake @@ -57,8 +57,8 @@ if(NOT TARGET TagLib::TagLib) SETUP_BUILD_VARS() # Taglib installs a shell script for all platforms. This can provide version universally - find_program(TAGLIB-CONFIG NAMES taglib-config taglib-config.command - HINTS ${DEPENDSPATH}/bin) + find_program(TAGLIB-CONFIG NAMES taglib-config taglib-config.cmd + HINTS ${DEPENDS_PATH}/bin) if(TAGLIB-CONFIG) execute_process(COMMAND "${TAGLIB-CONFIG}" --version diff --git a/cmake/modules/buildtools/FindFlatC.cmake b/cmake/modules/buildtools/FindFlatC.cmake index 121bcdbdfe..e234d0eff3 100644 --- a/cmake/modules/buildtools/FindFlatC.cmake +++ b/cmake/modules/buildtools/FindFlatC.cmake @@ -22,25 +22,24 @@ if(NOT TARGET flatbuffers::flatc) string(REGEX REPLACE ".* version (.*)" "\\1" FLATBUFFERS_FLATC_VERSION "${FLATBUFFERS_FLATC_VERSION}") endif() - set(MODULE_LC flatbuffers) - set(LIB_TYPE native) - # Duplicate URL may exist from FindFlatbuffers.cmake - # unset otherwise it thinks we are providing a local file location and incorrect concatenation happens - unset(FLATBUFFERS_URL) + set(MODULE_LC flatc) + set(${MODULE_LC}_MODULE_LOCATION flatbuffers) + set(${MODULE_LC}_LIB_TYPE native) + SETUP_BUILD_VARS() if(NOT FLATBUFFERS_FLATC_EXECUTABLE OR - (ENABLE_INTERNAL_FLATBUFFERS AND NOT "${FLATBUFFERS_FLATC_VERSION}" VERSION_EQUAL "${FLATBUFFERS_VER}")) + (ENABLE_INTERNAL_FLATBUFFERS AND NOT "${FLATBUFFERS_FLATC_VERSION}" VERSION_EQUAL "${FLATC_VER}")) # Override build type detection and always build as release - set(FLATBUFFERS_BUILD_TYPE Release) + set(FLATC_BUILD_TYPE Release) if(NATIVEPREFIX) set(INSTALL_DIR "${NATIVEPREFIX}/bin") - set(FLATBUFFERS_INSTALL_PREFIX ${NATIVEPREFIX}) + set(FLATC_INSTALL_PREFIX ${NATIVEPREFIX}) else() set(INSTALL_DIR "${CMAKE_BINARY_DIR}/${CORE_BUILD_DIR}/bin") - set(FLATBUFFERS_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/${CORE_BUILD_DIR}) + set(FLATC_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/${CORE_BUILD_DIR}) endif() set(CMAKE_ARGS -DFLATBUFFERS_CODE_COVERAGE=OFF @@ -54,20 +53,18 @@ if(NOT TARGET flatbuffers::flatc) # Set host build info for buildtool if(EXISTS "${NATIVEPREFIX}/share/Toolchain-Native.cmake") - set(FLATBUFFERS_TOOLCHAIN_FILE "${NATIVEPREFIX}/share/Toolchain-Native.cmake") + set(FLATC_TOOLCHAIN_FILE "${NATIVEPREFIX}/share/Toolchain-Native.cmake") endif() if(WIN32 OR WINDOWS_STORE) # Make sure we generate for host arch, not target - set(FLATBUFFERS_GENERATOR_PLATFORM CMAKE_GENERATOR_PLATFORM ${HOSTTOOLSET}) - set(WIN_DISABLE_PROJECT_FLAGS 1) + set(FLATC_GENERATOR_PLATFORM CMAKE_GENERATOR_PLATFORM ${HOSTTOOLSET}) endif() set(FLATBUFFERS_FLATC_EXECUTABLE ${INSTALL_DIR}/flatc) - set(BUILD_NAME flatc) set(BUILD_BYPRODUCTS ${FLATBUFFERS_FLATC_EXECUTABLE}) - set(FLATBUFFERS_FLATC_VERSION ${FLATBUFFERS_VER}) + set(FLATBUFFERS_FLATC_VERSION ${FLATC_VER}) BUILD_DEP_TARGET() endif() diff --git a/cmake/modules/buildtools/FindJsonSchemaBuilder.cmake b/cmake/modules/buildtools/FindJsonSchemaBuilder.cmake index 0b7b56481d..1b9f2b031d 100644 --- a/cmake/modules/buildtools/FindJsonSchemaBuilder.cmake +++ b/cmake/modules/buildtools/FindJsonSchemaBuilder.cmake @@ -28,7 +28,7 @@ if(NOT TARGET JsonSchemaBuilder::JsonSchemaBuilder) else() set(MODULE_LC JsonSchemaBuilder) - set(LIB_TYPE native) + set(${MODULE_LC}_LIB_TYPE native) set(JSONSCHEMABUILDER_DISABLE_VERSION ON) SETUP_BUILD_VARS() @@ -52,8 +52,7 @@ if(NOT TARGET JsonSchemaBuilder::JsonSchemaBuilder) if(WIN32 OR WINDOWS_STORE) # Make sure we generate for host arch, not target - set(JSONSCHEMABUILDER_GENERATOR_PLATFORM CMAKE_GENERATOR_PLATFORM WIN32) - set(WIN_DISABLE_PROJECT_FLAGS 1) + set(JSONSCHEMABUILDER_GENERATOR_PLATFORM CMAKE_GENERATOR_PLATFORM ${HOSTTOOLSET}) set(APP_EXTENSION ".exe") endif() diff --git a/cmake/platform/android/android.cmake b/cmake/platform/android/android.cmake index 49105e353d..6a7f71e1ef 100644 --- a/cmake/platform/android/android.cmake +++ b/cmake/platform/android/android.cmake @@ -6,6 +6,6 @@ list(APPEND PLATFORM_OPTIONAL_DEPS LibDovi) # Store SDK compile version set(TARGET_SDK 34) # Minimum supported SDK version -set(TARGET_MINSDK 21) +set(TARGET_MINSDK 24) set(${CORE_PLATFORM_NAME_LC}_SEARCH_CONFIG NO_DEFAULT_PATH CACHE STRING "") diff --git a/cmake/scripts/common/ModuleHelpers.cmake b/cmake/scripts/common/ModuleHelpers.cmake index 3cf706e372..cd5288d923 100644 --- a/cmake/scripts/common/ModuleHelpers.cmake +++ b/cmake/scripts/common/ModuleHelpers.cmake @@ -10,12 +10,12 @@ function(get_versionfile_data) # Dependency path - set(MODULE_PATH "${PROJECTSOURCE}/tools/depends/${LIB_TYPE}/${MODULE_LC}") + set(MODULE_PATH "${PROJECTSOURCE}/tools/depends/${${MODULE_LC}_LIB_TYPE}/${${MODULE_LC}_MODULE_LOCATION}") - if(NOT EXISTS "${MODULE_PATH}/${MODULE}-VERSION") - MESSAGE(FATAL_ERROR "${MODULE}-VERSION does not exist at ${MODULE_PATH}.") + if(NOT EXISTS "${MODULE_PATH}/${${MODULE_LC}_MODULE_VERSION}-VERSION") + MESSAGE(FATAL_ERROR "${${MODULE_LC}_MODULE_VERSION}-VERSION does not exist at ${MODULE_PATH}.") else() - set(${MODULE}_FILE "${MODULE_PATH}/${MODULE}-VERSION") + set(${MODULE}_FILE "${MODULE_PATH}/${${MODULE_LC}_MODULE_VERSION}-VERSION") endif() file(STRINGS ${${MODULE}_FILE} ${MODULE}_LNAME REGEX "^[ \t]*LIBNAME=") @@ -123,13 +123,22 @@ endfunction() macro(SETUP_BUILD_VARS) string(TOUPPER ${MODULE_LC} MODULE) + if(DEFINED ${MODULE_LC}_MODULE_LOCATION) + string(TOUPPER ${${MODULE_LC}_MODULE_LOCATION} _MODULE_UPPER) + set(${MODULE_LC}_MODULE_VERSION ${_MODULE_UPPER}) + unset(_MODULE_UPPER) + else() + set(${MODULE_LC}_MODULE_LOCATION ${MODULE_LC}) + set(${MODULE_LC}_MODULE_VERSION ${MODULE}) + endif() + # Fall through to target build module dir if not explicitly set - if(NOT DEFINED LIB_TYPE) - set(LIB_TYPE "target") + if(NOT DEFINED ${MODULE_LC}_LIB_TYPE) + set(${MODULE_LC}_LIB_TYPE "target") endif() # Location for build type, native or target - if(LIB_TYPE STREQUAL "target") + if(${MODULE_LC}_LIB_TYPE STREQUAL "target") set(DEP_LOCATION "${DEPENDS_PATH}") else() set(DEP_LOCATION "${NATIVEPREFIX}") @@ -155,19 +164,17 @@ macro(SETUP_BUILD_VARS) endif() if(VERBOSE) message(STATUS "MODULE: ${MODULE}") - message(STATUS "LIB_TYPE: ${LIB_TYPE}") + message(STATUS "${MODULE_LC}_LIB_TYPE: ${${MODULE_LC}_LIB_TYPE}") message(STATUS "DEP_LOCATION: ${DEP_LOCATION}") message(STATUS "PROJECTSOURCE: ${PROJECTSOURCE}") message(STATUS "${MODULE}_URL: ${${MODULE}_URL}") endif() - unset(LIB_TYPE) endmacro() macro(CLEAR_BUILD_VARS) # unset all generic variables to insure clean state between macro calls # Potentially an issue with scope when a macro is used inside a dep that uses a macro unset(PROJECTSOURCE) - unset(LIB_TYPE) unset(BUILD_NAME) unset(INSTALL_DIR) unset(CMAKE_ARGS) @@ -186,6 +193,7 @@ macro(CLEAR_BUILD_VARS) unset(${MODULE}_GENERATOR_PLATFORM) unset(${MODULE}_INSTALL_PREFIX) unset(${MODULE}_TOOLCHAIN_FILE) + unset(${MODULE_LC}_LIB_TYPE) endmacro() # Macro to create externalproject_add target @@ -231,7 +239,8 @@ macro(BUILD_DEP_TARGET) # We can disable adding them with WIN_DISABLE_PROJECT_FLAGS. This is potentially required # for host build tools (eg flatc) that may be a different arch to the core app if(WIN32 OR WINDOWS_STORE) - if(NOT DEFINED WIN_DISABLE_PROJECT_FLAGS) + if(NOT (DEFINED WIN_DISABLE_PROJECT_FLAGS OR + ${MODULE_LC}_LIB_TYPE STREQUAL "native")) list(APPEND CMAKE_ARGS "-DCMAKE_C_FLAGS=${CMAKE_C_FLAGS} $<$<CONFIG:Debug>:${CMAKE_C_FLAGS_DEBUG}> $<$<CONFIG:Release>:${CMAKE_C_FLAGS_RELEASE}> ${${MODULE}_C_FLAGS}" "-DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS} $<$<CONFIG:Debug>:${CMAKE_CXX_FLAGS_DEBUG}> $<$<CONFIG:Release>:${CMAKE_CXX_FLAGS_RELEASE}> ${${MODULE}_CXX_FLAGS}" "-DCMAKE_EXE_LINKER_FLAGS=${CMAKE_EXE_LINKER_FLAGS} $<$<CONFIG:Debug>:${CMAKE_EXE_LINKER_FLAGS_DEBUG}> $<$<CONFIG:Release>:${CMAKE_EXE_LINKER_FLAGS_RELEASE}> ${${MODULE}_EXE_LINKER_FLAGS}") @@ -287,6 +296,16 @@ macro(BUILD_DEP_TARGET) set(${MODULE}_GENERATOR CMAKE_GENERATOR "Unix Makefiles") endif() elseif(MSVC) + # Only apply SYSTEM variables for target build libs + if(${MODULE_LC}_LIB_TYPE STREQUAL "target") + if(DEFINED CMAKE_SYSTEM_VERSION) + list(APPEND CMAKE_ARGS -DCMAKE_SYSTEM_VERSION=${CMAKE_SYSTEM_VERSION}) + endif() + if(DEFINED CMAKE_SYSTEM_NAME) + list(APPEND CMAKE_ARGS -DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME}) + endif() + endif() + if(NOT ${MODULE}_GENERATOR) set(${MODULE}_GENERATOR CMAKE_GENERATOR "${CMAKE_GENERATOR}") endif() diff --git a/docs/README.Android.md b/docs/README.Android.md index 08d04c82a2..72fcf75e7f 100644 --- a/docs/README.Android.md +++ b/docs/README.Android.md @@ -73,8 +73,8 @@ sudo apt install autoconf bison build-essential curl default-jdk flex gawk git g **[back to top](#table-of-contents)** ## 3. Prerequisites -Building Kodi for Android requires Android NDK revision 20b. For the SDK just use the latest available. -Kodi CI/CD platforms currently use r21e for build testing and releases, so we recommend using r21e for the most tested build experience +Building Kodi for Android requires Android NDK revision 26c. For the SDK just use the latest available. +Kodi CI/CD platforms currently use r26c for build testing and releases, so we recommend using r26c for the most tested build experience * **[Android SDK](https://developer.android.com/studio/index.html)** (Look for `Get just the command line tools`) @@ -100,7 +100,7 @@ cd $HOME/android-tools/android-sdk-linux/cmdline-tools/bin ./sdkmanager --sdk_root=$(pwd)/../.. platform-tools ./sdkmanager --sdk_root=$(pwd)/../.. "platforms;android-34" ./sdkmanager --sdk_root=$(pwd)/../.. "build-tools;33.0.1" -./sdkmanager --sdk_root=$(pwd)/../.. "ndk;21.4.7075529" +./sdkmanager --sdk_root=$(pwd)/../.. "ndk;26.2.11394342" ``` ### 3.3. Create a key to sign debug APKs @@ -135,22 +135,22 @@ cd $HOME/kodi/tools/depends Configure build for aarch64: ``` -./configure --with-tarballs=$HOME/android-tools/xbmc-tarballs --host=aarch64-linux-android --with-sdk-path=$HOME/android-tools/android-sdk-linux --with-ndk-path=$HOME/android-tools/android-sdk-linux/ndk/21.4.7075529 --prefix=$HOME/android-tools/xbmc-depends +./configure --with-tarballs=$HOME/android-tools/xbmc-tarballs --host=aarch64-linux-android --with-sdk-path=$HOME/android-tools/android-sdk-linux --with-ndk-path=$HOME/android-tools/android-sdk-linux/ndk/26.2.11394342 --prefix=$HOME/android-tools/xbmc-depends ``` Or configure build for arm: ``` -./configure --with-tarballs=$HOME/android-tools/xbmc-tarballs --host=arm-linux-androideabi --with-sdk-path=$HOME/android-tools/android-sdk-linux --with-ndk-path=$HOME/android-tools/android-sdk-linux/ndk/21.4.7075529 --prefix=$HOME/android-tools/xbmc-depends +./configure --with-tarballs=$HOME/android-tools/xbmc-tarballs --host=arm-linux-androideabi --with-sdk-path=$HOME/android-tools/android-sdk-linux --with-ndk-path=$HOME/android-tools/android-sdk-linux/ndk/26.2.11394342 --prefix=$HOME/android-tools/xbmc-depends ``` Or configure build for x86: ``` -./configure --with-tarballs=$HOME/android-tools/xbmc-tarballs --host=i686-linux-android --with-sdk-path=$HOME/android-tools/android-sdk-linux --with-ndk-path=$HOME/android-tools/android-sdk-linux/ndk/21.4.7075529 --prefix=$HOME/android-tools/xbmc-depends +./configure --with-tarballs=$HOME/android-tools/xbmc-tarballs --host=i686-linux-android --with-sdk-path=$HOME/android-tools/android-sdk-linux --with-ndk-path=$HOME/android-tools/android-sdk-linux/ndk/26.2.11394342 --prefix=$HOME/android-tools/xbmc-depends ``` Or configure build for x86_64: ``` -./configure --with-tarballs=$HOME/android-tools/xbmc-tarballs --host=x86_64-linux-android --with-sdk-path=$HOME/android-tools/android-sdk-linux --with-ndk-path=$HOME/android-tools/android-sdk-linux/ndk/21.4.7075529 --prefix=$HOME/android-tools/xbmc-depends +./configure --with-tarballs=$HOME/android-tools/xbmc-tarballs --host=x86_64-linux-android --with-sdk-path=$HOME/android-tools/android-sdk-linux --with-ndk-path=$HOME/android-tools/android-sdk-linux/ndk/26.2.11394342 --prefix=$HOME/android-tools/xbmc-depends ``` > [!NOTE] @@ -238,7 +238,7 @@ make -j$(getconf _NPROCESSORS_ONLN) ``` --with-ndk-api=<ndk number> ``` - specify ndk level (optional for android), default is 21.] + specify ndk level (optional for android), default is 24.] ``` --with-ndk-path=<path> diff --git a/project/BuildDependencies/scripts/0_package.target-win10-arm.list b/project/BuildDependencies/scripts/0_package.target-win10-arm.list index 50074ebcc1..a3490f9e16 100644 --- a/project/BuildDependencies/scripts/0_package.target-win10-arm.list +++ b/project/BuildDependencies/scripts/0_package.target-win10-arm.list @@ -7,7 +7,7 @@ ; -> ... ;PLEASE KEEP THIS LIST IN ALPHABETICAL ORDER! curl-7.67.0-win10-arm-v141-20200105.7z -dav1d-1.2.0-win10-arm-v142-20230513.7z +dav1d-1.4.1-win10-arm-v142-20240331.7z freetype-2.10.1-win10-arm-v141-20200105.7z fstrcmp-0.7-win10-arm-v141-20200105.7z GoogleTest-1.10.0-win10-arm-v141-20200410.7z diff --git a/project/BuildDependencies/scripts/0_package.target-win10-win32.list b/project/BuildDependencies/scripts/0_package.target-win10-win32.list index bfd07c2644..fda954334d 100644 --- a/project/BuildDependencies/scripts/0_package.target-win10-win32.list +++ b/project/BuildDependencies/scripts/0_package.target-win10-win32.list @@ -7,7 +7,7 @@ ; -> ... ;PLEASE KEEP THIS LIST IN ALPHABETICAL ORDER! curl-7.67.0-win10-win32-v141-20200105.7z -dav1d-1.2.0-win10-win32-v142-20230513.7z +dav1d-1.4.1-win10-win32-v142-20240331.7z freetype-2.10.1-win10-win32-v141-20200105.7z fstrcmp-0.7-win10-win32-v141-20200105.7z GoogleTest-1.10.0-win10-win32-v141-20200410.7z diff --git a/project/BuildDependencies/scripts/0_package.target-win10-x64.list b/project/BuildDependencies/scripts/0_package.target-win10-x64.list index d4d4a26517..2c2635be57 100644 --- a/project/BuildDependencies/scripts/0_package.target-win10-x64.list +++ b/project/BuildDependencies/scripts/0_package.target-win10-x64.list @@ -7,7 +7,7 @@ ; -> ... ;PLEASE KEEP THIS LIST IN ALPHABETICAL ORDER! curl-7.67.0-win10-x64-v141-20200105.7z -dav1d-1.2.0-win10-x64-v142-20230513.7z +dav1d-1.4.1-win10-x64-v142-20240331.7z freetype-2.10.1-win10-x64-v141-20200105.7z fstrcmp-0.7-win10-x64-v141-20200105.7z GoogleTest-1.10.0-win10-x64-v141-20200410.7z diff --git a/project/BuildDependencies/scripts/0_package.target-win32.list b/project/BuildDependencies/scripts/0_package.target-win32.list index 4d531330bb..b0c882344d 100644 --- a/project/BuildDependencies/scripts/0_package.target-win32.list +++ b/project/BuildDependencies/scripts/0_package.target-win32.list @@ -7,7 +7,7 @@ ; -> ... ;PLEASE KEEP THIS LIST IN ALPHABETICAL ORDER! curl-7.67.0-win32-v141-20200105.7z -dav1d-1.2.0-win32-v142-20230513.7z +dav1d-1.4.1-win32-v142-20240331.7z detours-64ec13-win32-v141-20200105.7z dnssd-878.260.1-win32-v141-20200105.7z freetype-2.10.1-win32-v141-20200105.7z diff --git a/project/BuildDependencies/scripts/0_package.target-x64.list b/project/BuildDependencies/scripts/0_package.target-x64.list index eacfd4629d..7ae89f8c4c 100644 --- a/project/BuildDependencies/scripts/0_package.target-x64.list +++ b/project/BuildDependencies/scripts/0_package.target-x64.list @@ -7,7 +7,7 @@ ; -> ... ;PLEASE KEEP THIS LIST IN ALPHABETICAL ORDER! curl-7.67.0-x64-v141-20200105.7z -dav1d-1.2.0-x64-v142-20230513.7z +dav1d-1.4.1-x64-v142-20240331.7z detours-64ec13-x64-v141-20200105.7z dnssd-878.260.1-x64-v141-20200105.7z freetype-2.10.1-x64-v141-20200105.7z diff --git a/system/settings/android.xml b/system/settings/android.xml index 661a978e32..838990389a 100644 --- a/system/settings/android.xml +++ b/system/settings/android.xml @@ -29,16 +29,4 @@ </group> </category> </section> - <section id="interface"> - <category id="regional"> - <group id="2"> - <setting id="locale.timezonecountry"> - <visible>false</visible> - </setting> - <setting id="locale.timezone"> - <visible>false</visible> - </setting> - </group> - </category> - </section> </settings> diff --git a/system/settings/settings.xml b/system/settings/settings.xml index e48fcf1c08..2317cdf90c 100755 --- a/system/settings/settings.xml +++ b/system/settings/settings.xml @@ -4030,25 +4030,6 @@ </dependencies> <control type="list" format="string" /> </setting> - <setting id="locale.timezonecountry" type="string" label="14079" help="36117"> - <level>1</level> - <default>default</default> <!-- will be properly set on startup --> - <constraints> - <options>timezonecountries</options> - </constraints> - <control type="list" format="string" /> - </setting> - <setting id="locale.timezone" type="string" label="14080" help="36118"> - <level>1</level> - <default>default</default> <!-- will be properly set on startup --> - <constraints> - <options>timezones</options> - </constraints> - <dependencies> - <dependency type="update" setting="locale.timezonecountry" /> - </dependencies> - <control type="list" format="string" /> - </setting> <setting id="locale.shortdateformat" type="string" label="14109" help="36173"> <level>2</level> <default>regional</default> diff --git a/system/settings/windows.xml b/system/settings/windows.xml index 163cb5c2d3..523d0c9cab 100644 --- a/system/settings/windows.xml +++ b/system/settings/windows.xml @@ -58,16 +58,4 @@ </group> </category> </section> - <section id="interface"> - <category id="regional"> - <group id="2"> - <setting id="locale.timezonecountry"> - <visible>false</visible> - </setting> - <setting id="locale.timezone"> - <visible>false</visible> - </setting> - </group> - </category> - </section> </settings> diff --git a/system/shaders/GL/1.2/gl_shader_vert_clip.glsl b/system/shaders/GL/1.2/gl_shader_vert_clip.glsl new file mode 100644 index 0000000000..37d67946f5 --- /dev/null +++ b/system/shaders/GL/1.2/gl_shader_vert_clip.glsl @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2024 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. + */ + +#version 120 + +attribute vec4 m_attrpos; +attribute vec4 m_attrcol; +attribute vec4 m_attrcord0; +attribute vec4 m_attrcord1; +varying vec4 m_cord0; +varying vec4 m_cord1; +varying vec4 m_colour; +uniform mat4 m_matrix; +uniform vec4 m_shaderClip; +uniform vec4 m_cordStep; + +// this shader can be used in cases where clipping via glScissor() is not +// possible (e.g. when rotating). it can't discard triangles, but it may +// degenerate them. + +void main () +{ + // limit the vertices to the clipping area + vec4 position = m_attrpos; + position.xy = clamp(position.xy, m_shaderClip.xy, m_shaderClip.zw); + gl_Position = m_matrix * position; + + // correct texture coordinates for clipped vertices + vec2 clipDist = m_attrpos.xy - position.xy; + m_cord0.xy = m_attrcord0.xy - clipDist * m_cordStep.xy; + m_cord1.xy = m_attrcord1.xy - clipDist * m_cordStep.zw; + + m_colour = m_attrcol; +} diff --git a/system/shaders/GL/1.2/gl_shader_vert_simple.glsl b/system/shaders/GL/1.2/gl_shader_vert_simple.glsl new file mode 100644 index 0000000000..f06893a085 --- /dev/null +++ b/system/shaders/GL/1.2/gl_shader_vert_simple.glsl @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2024 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. + */ + +#version 120 + +attribute vec4 m_attrpos; +attribute vec4 m_attrcol; +attribute vec4 m_attrcord0; +attribute vec4 m_attrcord1; +varying vec4 m_cord0; +varying vec4 m_cord1; +varying vec4 m_colour; +uniform mat4 m_matrix; + +void main () +{ + gl_Position = m_matrix * m_attrpos; + m_colour = m_attrcol; + m_cord0 = m_attrcord0; + m_cord1 = m_attrcord1; +} diff --git a/system/shaders/GL/1.5/gl_shader_vert_clip.glsl b/system/shaders/GL/1.5/gl_shader_vert_clip.glsl new file mode 100644 index 0000000000..2fa1c63da1 --- /dev/null +++ b/system/shaders/GL/1.5/gl_shader_vert_clip.glsl @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2024 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. + */ + +#version 150 + +in vec4 m_attrpos; +in vec4 m_attrcol; +in vec4 m_attrcord0; +in vec4 m_attrcord1; +out vec4 m_cord0; +out vec4 m_cord1; +out vec4 m_colour; +uniform mat4 m_matrix; +uniform vec4 m_shaderClip; +uniform vec4 m_cordStep; + +// this shader can be used in cases where clipping via glScissor() is not +// possible (e.g. when rotating). it can't discard triangles, but it may +// degenerate them. + +void main () +{ + // limit the vertices to the clipping area + vec4 position = m_attrpos; + position.xy = clamp(position.xy, m_shaderClip.xy, m_shaderClip.zw); + gl_Position = m_matrix * position; + + // correct texture coordinates for clipped vertices + vec2 clipDist = m_attrpos.xy - position.xy; + m_cord0.xy = m_attrcord0.xy - clipDist * m_cordStep.xy; + m_cord1.xy = m_attrcord1.xy - clipDist * m_cordStep.zw; + + m_colour = m_attrcol; +} diff --git a/system/shaders/GL/1.5/gl_shader_vert_simple.glsl b/system/shaders/GL/1.5/gl_shader_vert_simple.glsl new file mode 100644 index 0000000000..9c1552d7a4 --- /dev/null +++ b/system/shaders/GL/1.5/gl_shader_vert_simple.glsl @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2024 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. + */ + +#version 150 + +in vec4 m_attrpos; +in vec4 m_attrcol; +in vec4 m_attrcord0; +in vec4 m_attrcord1; +out vec4 m_cord0; +out vec4 m_cord1; +out vec4 m_colour; +uniform mat4 m_matrix; + +void main () +{ + gl_Position = m_matrix * m_attrpos; + m_colour = m_attrcol; + m_cord0 = m_attrcord0; + m_cord1 = m_attrcord1; +} diff --git a/system/shaders/GLES/2.0/gles_shader_clip.vert b/system/shaders/GLES/2.0/gles_shader_clip.vert new file mode 100644 index 0000000000..513a24456c --- /dev/null +++ b/system/shaders/GLES/2.0/gles_shader_clip.vert @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2024 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. + */ + +#version 100 + +attribute vec4 m_attrpos; +attribute vec4 m_attrcol; +attribute vec4 m_attrcord0; +attribute vec4 m_attrcord1; +varying vec4 m_cord0; +varying vec4 m_cord1; +varying vec4 m_colour; +uniform mat4 m_matrix; +uniform vec4 m_shaderClip; +uniform vec4 m_cordStep; + +// this shader can be used in cases where clipping via glScissor() is not +// possible (e.g. when rotating). it can't discard triangles, but it may +// degenerate them. + +void main() +{ + // limit the vertices to the clipping area + vec4 position = m_attrpos; + position.xy = clamp(position.xy, m_shaderClip.xy, m_shaderClip.zw); + gl_Position = m_matrix * position; + + // correct texture coordinates for clipped vertices + vec2 clipDist = m_attrpos.xy - position.xy; + m_cord0.xy = m_attrcord0.xy - clipDist * m_cordStep.xy; + m_cord1.xy = m_attrcord1.xy - clipDist * m_cordStep.zw; + + m_colour = m_attrcol; +} diff --git a/system/shaders/GLES/2.0/gles_shader_simple.vert b/system/shaders/GLES/2.0/gles_shader_simple.vert new file mode 100644 index 0000000000..6d49788b65 --- /dev/null +++ b/system/shaders/GLES/2.0/gles_shader_simple.vert @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2024 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. + */ + +#version 100 + +attribute vec4 m_attrpos; +attribute vec4 m_attrcol; +attribute vec4 m_attrcord0; +attribute vec4 m_attrcord1; +varying vec4 m_cord0; +varying vec4 m_cord1; +varying vec4 m_colour; +uniform mat4 m_matrix; + +void main() +{ + gl_Position = m_matrix * m_attrpos; + m_colour = m_attrcol; + m_cord0 = m_attrcord0; + m_cord1 = m_attrcord1; +} diff --git a/tools/android/packaging/xbmc/build.gradle.in b/tools/android/packaging/xbmc/build.gradle.in index 14c9c2b6d1..71f94a8ffa 100644 --- a/tools/android/packaging/xbmc/build.gradle.in +++ b/tools/android/packaging/xbmc/build.gradle.in @@ -47,6 +47,9 @@ android { } packagingOptions{ doNotStrip '**.setup' + jniLibs { + useLegacyPackaging = true + } } } diff --git a/tools/android/packaging/xbmc/src/Splash.java.in b/tools/android/packaging/xbmc/src/Splash.java.in index ddc3291cd8..19e33a676f 100644 --- a/tools/android/packaging/xbmc/src/Splash.java.in +++ b/tools/android/packaging/xbmc/src/Splash.java.in @@ -397,11 +397,7 @@ public class Splash extends Activity AlertDialog.Builder builder = new AlertDialog.Builder(act); builder.setTitle(title); builder.setIcon(android.R.drawable.ic_dialog_alert); - if (Build.VERSION.SDK_INT >= 24) { - builder.setMessage(Html.fromHtml(message, Html.FROM_HTML_MODE_LEGACY)); - } else { - builder.setMessage(Html.fromHtml(message)); - } + builder.setMessage(Html.fromHtml(message, Html.FROM_HTML_MODE_LEGACY)); builder.setPositiveButton("Exit", (dialog, arg1) -> { dialog.dismiss(); act.finish(); @@ -514,16 +510,13 @@ public class Splash extends Activity retVal = true; } } - else if (Build.VERSION.SDK_INT > 22) + else { int permissionCheck; permissionCheck = checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE); if (permissionCheck == PERMISSION_GRANTED) retVal = true; } - else - retVal= true; - return retVal; } diff --git a/tools/buildsteps/defaultenv b/tools/buildsteps/defaultenv index b4013ac349..c14478aca9 100644 --- a/tools/buildsteps/defaultenv +++ b/tools/buildsteps/defaultenv @@ -56,8 +56,8 @@ case $XBMC_PLATFORM_DIR in ;; android) - DEFAULT_NDK_VERSION="21e" # NDK package version (newer API can be inside) - DEFAULT_NDK_API="21" # Lollipop API level (21) defined in package ./sysroot/usr/include/android/api-level.h + DEFAULT_NDK_VERSION="26c" # NDK package version (newer API can be inside) + DEFAULT_NDK_API="24" # Nougat API level (24) defined in package ./sysroot/usr/include/android/api-level.h DEFAULT_XBMC_DEPENDS_ROOT=$WORKSPACE/tools/depends/xbmc-depends DEFAULT_CONFIGURATION="RelWithDebInfo" ;; diff --git a/tools/depends/configure.ac b/tools/depends/configure.ac index b09b586dc5..9bce943cc0 100644 --- a/tools/depends/configure.ac +++ b/tools/depends/configure.ac @@ -87,9 +87,9 @@ AC_ARG_WITH([sdk], AC_ARG_WITH([ndk-api], [AS_HELP_STRING([--with-ndk-api], - [specify ndk level (optional for android), default is 21.])], + [specify ndk level (optional for android), default is 24.])], [use_ndk_api=$withval], - [use_ndk_api=21]) + [use_ndk_api=24]) AC_ARG_ENABLE([gplv3], [AS_HELP_STRING([--enable-gplv3], diff --git a/tools/depends/native/TexturePacker/src/decoder/JPGDecoder.cpp b/tools/depends/native/TexturePacker/src/decoder/JPGDecoder.cpp index 452c865bdd..450adc1e93 100644 --- a/tools/depends/native/TexturePacker/src/decoder/JPGDecoder.cpp +++ b/tools/depends/native/TexturePacker/src/decoder/JPGDecoder.cpp @@ -22,6 +22,8 @@ #include "SimpleFS.h" +#include <cstdint> +#include <limits> #include <memory> #include <jpeglib.h> @@ -80,8 +82,6 @@ bool JPGDecoder::LoadFile(const std::string &filename, DecodedFrames &frames) struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; - int ImageSize; - cinfo.err = jpeg_std_error(&jerr); jpeg_create_decompress(&cinfo); @@ -89,12 +89,18 @@ bool JPGDecoder::LoadFile(const std::string &filename, DecodedFrames &frames) jpeg_read_header(&cinfo, TRUE); jpeg_start_decompress(&cinfo); - // Image Size is calculated as (width * height * bytes per pixel = 4 - ImageSize = cinfo.image_width * cinfo.image_height * 4; + // Image Size is calculated as width * height * bytes per pixel = 4 + // Since image_width and image_height can be at most 0xFFFF, this is safe from overflows + const std::uint64_t ImageSize = + static_cast<std::uint64_t>(cinfo.image_width) * cinfo.image_height * 4; + + // Check if the conversion to std::size_t is lossless + if (ImageSize > std::numeric_limits<std::size_t>::max()) + return false; DecodedFrame frame; - frame.rgbaImage.pixels.resize(ImageSize); + frame.rgbaImage.pixels.resize(static_cast<std::size_t>(ImageSize)); std::vector<unsigned char> scanlinebuff; scanlinebuff.resize(3 * cinfo.image_width); diff --git a/tools/depends/target/dav1d/DAV1D-VERSION b/tools/depends/target/dav1d/DAV1D-VERSION index 7897d53556..f803959d0f 100644 --- a/tools/depends/target/dav1d/DAV1D-VERSION +++ b/tools/depends/target/dav1d/DAV1D-VERSION @@ -1,5 +1,5 @@ LIBNAME=dav1d -VERSION=1.1.0 +VERSION=1.4.1 ARCHIVE=$(LIBNAME)-$(VERSION).tar.bz2 -SHA512=2eb177b415d1ac7bd08d54b16375afedec61f0771a5181fa93e5e6215856fc26504a7cb47de08abbea5bf18fac5ff91ca31044e7054681c380e0ab152e53aabc +SHA512=b2dcdeeb3d6c37788b4c697b497b9282738b758927ffbdbe72b05b1b26a61aa967dfba0ce05828b5bd5bcac93eb3394b0eafbb57e325d037867cf720d64ba099 BYPRODUCT=libdav1d.a diff --git a/tools/depends/target/ffmpeg/CMakeLists.txt b/tools/depends/target/ffmpeg/CMakeLists.txt index 0bbc23540a..5cadafe294 100644 --- a/tools/depends/target/ffmpeg/CMakeLists.txt +++ b/tools/depends/target/ffmpeg/CMakeLists.txt @@ -121,6 +121,10 @@ if(CPU MATCHES x86 OR CPU MATCHES x86_64) list(APPEND ffmpeg_conf --x86asmexe=${NASM_EXECUTABLE}) endif() +if(USE_LTO) + list(APPEND ffmpeg_conf --enable-lto) +endif() + if(ENABLE_DAV1D) list(APPEND ffmpeg_conf --enable-libdav1d) set(pkgconf_path "PKG_CONFIG_PATH=${PKG_CONFIG_PATH}") diff --git a/tools/depends/target/libass/Makefile b/tools/depends/target/libass/Makefile index 4be63dce6f..94bfcac3fa 100644 --- a/tools/depends/target/libass/Makefile +++ b/tools/depends/target/libass/Makefile @@ -1,12 +1,6 @@ include ../../Makefile.include LIBASS-VERSION ../../download-files.include DEPS = ../../Makefile.include Makefile LIBASS-VERSION ../../download-files.include -ifeq ($(OS),android) - # Android API Level 21/22 requires explicit link. - # This doesnt appear to be required for API Level 23+ (Android 6+) - export LDFLAGS+= -lstdc++ -endif - # configuration settings CONFIGURE=cp -f $(CONFIG_SUB) $(CONFIG_GUESS) .; \ ./configure --prefix=$(PREFIX) \ diff --git a/tools/depends/target/libnfs/01-MSUWP-compat.patch b/tools/depends/target/libnfs/01-MSUWP-compat.patch new file mode 100644 index 0000000000..70cac0b767 --- /dev/null +++ b/tools/depends/target/libnfs/01-MSUWP-compat.patch @@ -0,0 +1,11 @@ +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -39,7 +39,7 @@ + add_definitions(-Dlibnfs_EXPORTS) + endif() + +-if(CMAKE_SYSTEM_NAME STREQUAL Windows) ++if(CMAKE_SYSTEM_NAME MATCHES "Windows") + add_definitions("-D_U_=" -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE) + list(APPEND SYSTEM_LIBRARIES ws2_32) + add_subdirectory(win32) diff --git a/tools/depends/target/libnfs/Makefile b/tools/depends/target/libnfs/Makefile index f4cfd33a37..e069bbf790 100644 --- a/tools/depends/target/libnfs/Makefile +++ b/tools/depends/target/libnfs/Makefile @@ -1,5 +1,6 @@ include ../../Makefile.include LIBNFS-VERSION ../../download-files.include -DEPS= ../../Makefile.include Makefile LIBNFS-VERSION ../../download-files.include +DEPS= ../../Makefile.include Makefile LIBNFS-VERSION ../../download-files.include \ + 01-MSUWP-compat.patch # configuration settings CMAKE_OPTIONS=-DBUILD_SHARED_LIBS=OFF \ @@ -16,6 +17,7 @@ $(PLATFORM): $(DEPS) | $(TARBALLS_LOCATION)/$(ARCHIVE).$(HASH_TYPE) -rm -rf $(PLATFORM); mkdir -p $(PLATFORM) cd $(PLATFORM); $(ARCHIVE_TOOL) $(ARCHIVE_TOOL_FLAGS) $(TARBALLS_LOCATION)/$(ARCHIVE) cd $(PLATFORM); mkdir -p build + cd $(PLATFORM); patch -p1 -i ../01-MSUWP-compat.patch cd $(PLATFORM)/build; $(CMAKE) $(CMAKE_OPTIONS) .. $(LIBDYLIB): $(PLATFORM) diff --git a/tools/depends/target/pcre/Makefile b/tools/depends/target/pcre/Makefile index 3c682a4949..679a6c058b 100644 --- a/tools/depends/target/pcre/Makefile +++ b/tools/depends/target/pcre/Makefile @@ -18,6 +18,7 @@ CMAKE_OPTIONS=-DPCRE_NEWLINE=ANYCRLF \ -DPCRE_SUPPORT_UNICODE_PROPERTIES=ON \ -DPCRE_SUPPORT_LIBZ=OFF \ -DPCRE_SUPPORT_LIBBZ2=OFF \ + -DPCRE_BUILD_PCRECPP=OFF \ -DPCRE_BUILD_PCREGREP=OFF \ -DPCRE_BUILD_TESTS=OFF \ -DCMAKE_BUILD_TYPE=Release diff --git a/tools/depends/target/samba-gplv3/samba_android.patch b/tools/depends/target/samba-gplv3/samba_android.patch index 3d194cfa8f..a6c4007e1a 100644 --- a/tools/depends/target/samba-gplv3/samba_android.patch +++ b/tools/depends/target/samba-gplv3/samba_android.patch @@ -1,36 +1,3 @@ ---- a/lib/util/charset/iconv.c -+++ b/lib/util/charset/iconv.c -@@ -31,6 +31,10 @@ - #include <unicode/utrans.h> - #endif - -+#if defined(ANDROID) && (!defined(__ANDROID_API__) || __ANDROID_API__ < 28) -+#include <byteswap.h> -+#endif -+ - #ifdef strcasecmp - #undef strcasecmp - #endif -@@ -755,6 +755,19 @@ - return 0; - } - -+#if defined(ANDROID) && (!defined(__ANDROID_API__) || __ANDROID_API__ < 28) -+void swab(const void *from, void*to, ssize_t n) -+{ -+ ssize_t i; -+ -+ if (n < 0) -+ return; -+ -+ for (i = 0; i < (n/2)*2; i += 2) -+ *((uint16_t*)to+i) = bswap_16(*((uint16_t*)from+i)); -+} -+#endif -+ - static size_t iconv_swab(void *cd, const char **inbuf, size_t *inbytesleft, - char **outbuf, size_t *outbytesleft) - { --- a/nsswitch/libwbclient/wbc_pwd.c +++ b/nsswitch/libwbclient/wbc_pwd.c @@ -46,7 +46,9 @@ @@ -97,14 +64,3 @@ typedef struct winbindd_gr { fstring gr_name; ---- a/lib/replace/wscript -+++ b/lib/replace/wscript -@@ -225,7 +225,7 @@ - headers='sys/socket.h netinet/in.h arpa/inet.h netdb.h') - conf.DEFINE('REPLACE_REQUIRES_LIBSOCKET_LIBNSL', 1) - -- conf.CHECK_FUNCS('memset_s memset_explicit') -+ conf.undefine('HAVE_MEMSET_EXPLICIT') - - conf.CHECK_CODE(''' - #include <string.h> diff --git a/tools/depends/target/samba/samba_android.patch b/tools/depends/target/samba/samba_android.patch index 62600f71b6..0295e041f9 100644 --- a/tools/depends/target/samba/samba_android.patch +++ b/tools/depends/target/samba/samba_android.patch @@ -9,40 +9,6 @@ /* On Linux we lose the ability to dump core when we change our user * ID. We know how to dump core safely, so let's make sure we have our * dumpable flag set. ---- a/source/lib/iconv.c -+++ b/source/lib/iconv.c -@@ -20,7 +20,10 @@ - */ - - #include "includes.h" -- -+#if defined(ANDROID) -+#include <stdint.h> -+#include <asm/byteorder.h> -+#endif - /* - * We have to use strcasecmp here as the character conversions - * haven't been initialised yet. JRA. -@@ -489,6 +492,19 @@ - return 0; - } - -+#if defined(ANDROID) -+void swab(const void *from, void*to, ssize_t n) -+{ -+ ssize_t i; -+ -+ if (n < 0) -+ return; -+ -+ for (i = 0; i < (n/2)*2; i += 2) -+ *((uint16_t*)to+i) = __arch__swab16(*((uint16_t*)from+i)); -+} -+#endif -+ - static size_t iconv_swab(void *cd, const char **inbuf, size_t *inbytesleft, - char **outbuf, size_t *outbytesleft) - { --- a/source/lib/replace/system/passwd.h +++ b/source/lib/replace/system/passwd.h @@ -62,6 +62,8 @@ diff --git a/xbmc/AutoSwitch.cpp b/xbmc/AutoSwitch.cpp index 14adb8e2bc..0dd710f757 100644 --- a/xbmc/AutoSwitch.cpp +++ b/xbmc/AutoSwitch.cpp @@ -9,6 +9,7 @@ #include "AutoSwitch.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "guilib/GUIComponent.h" #include "guilib/GUIWindowManager.h" diff --git a/xbmc/Autorun.cpp b/xbmc/Autorun.cpp index 6c672b208d..aad71cf3c8 100644 --- a/xbmc/Autorun.cpp +++ b/xbmc/Autorun.cpp @@ -9,6 +9,7 @@ #include "Autorun.h" #include "FileItem.h" +#include "FileItemList.h" #include "GUIPassword.h" #include "GUIUserMessages.h" #include "PlayListPlayer.h" @@ -31,6 +32,7 @@ #include "settings/SettingsComponent.h" #include "settings/lib/Setting.h" #include "settings/lib/SettingDefinitions.h" +#include "video/VideoFileItemClassify.h" #include <stdlib.h> #ifndef TARGET_WINDOWS @@ -51,6 +53,7 @@ using namespace XFILE; using namespace MEDIA_DETECT; using namespace KODI::MESSAGING; +using namespace KODI::VIDEO; using namespace std::chrono_literals; using KODI::MESSAGING::HELPERS::DialogResponse; @@ -399,7 +402,7 @@ bool CAutorun::RunDisc(IDirectory* pDir, const std::string& strDrive, int& nAdde for (int i = 0; i < tempItems.Size(); i++) { CFileItemPtr pItem = tempItems[i]; - if (!pItem->m_bIsFolder && pItem->IsVideo()) + if (!pItem->m_bIsFolder && IsVideo(*pItem)) { bPlaying = true; if (pItem->IsStack()) diff --git a/xbmc/BackgroundInfoLoader.cpp b/xbmc/BackgroundInfoLoader.cpp index 55d221ab04..de3d5a3a9e 100644 --- a/xbmc/BackgroundInfoLoader.cpp +++ b/xbmc/BackgroundInfoLoader.cpp @@ -9,6 +9,7 @@ #include "BackgroundInfoLoader.h" #include "FileItem.h" +#include "FileItemList.h" #include "URL.h" #include "threads/Thread.h" #include "utils/log.h" diff --git a/xbmc/CMakeLists.txt b/xbmc/CMakeLists.txt index b7c838b3da..689f4af296 100644 --- a/xbmc/CMakeLists.txt +++ b/xbmc/CMakeLists.txt @@ -8,6 +8,7 @@ set(SOURCES AutoSwitch.cpp DbUrl.cpp DynamicDll.cpp FileItem.cpp + FileItemList.cpp FileItemListModification.cpp GUIInfoManager.cpp GUILargeTextureManager.cpp @@ -45,6 +46,7 @@ set(HEADERS AutoSwitch.h DllPaths_win32.h DynamicDll.h FileItem.h + FileItemList.h FileItemListModification.h GUIInfoManager.h GUILargeTextureManager.h diff --git a/xbmc/CueDocument.cpp b/xbmc/CueDocument.cpp index 674a94aa51..abc5185e63 100644 --- a/xbmc/CueDocument.cpp +++ b/xbmc/CueDocument.cpp @@ -43,6 +43,7 @@ #include "CueDocument.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "Util.h" #include "filesystem/Directory.h" diff --git a/xbmc/FileItem.cpp b/xbmc/FileItem.cpp index 239d4325ab..558a5a2ad8 100644 --- a/xbmc/FileItem.cpp +++ b/xbmc/FileItem.cpp @@ -9,6 +9,7 @@ #include "FileItem.h" #include "CueDocument.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "URL.h" #include "Util.h" @@ -17,7 +18,7 @@ #include "filesystem/Directory.h" #include "filesystem/File.h" #include "filesystem/MultiPathDirectory.h" -#include "filesystem/MusicDatabaseDirectory.h" +#include "filesystem/MusicDatabaseDirectory/QueryParams.h" #include "filesystem/StackDirectory.h" #include "filesystem/VideoDatabaseDirectory.h" #include "filesystem/VideoDatabaseDirectory/QueryParams.h" @@ -48,10 +49,8 @@ #include "settings/SettingsComponent.h" #include "settings/lib/Setting.h" #include "utils/Archive.h" -#include "utils/Crc32.h" #include "utils/FileExtensionProvider.h" #include "utils/Mime.h" -#include "utils/Random.h" #include "utils/RegExp.h" #include "utils/StringUtils.h" #include "utils/URIUtils.h" @@ -59,14 +58,15 @@ #include "utils/log.h" #include "video/Bookmark.h" #include "video/VideoDatabase.h" +#include "video/VideoFileItemClassify.h" #include "video/VideoInfoTag.h" +#include "video/VideoUtils.h" -#include <algorithm> #include <cstdlib> #include <memory> -#include <mutex> using namespace KODI; +using namespace KODI::VIDEO; using namespace XFILE; using namespace PLAYLIST; using namespace MUSIC_INFO; @@ -850,7 +850,7 @@ bool CFileItem::Exists(bool bUseCache /* = true */) const || IsPVR()) return true; - if (IsVideoDb() && HasVideoInfoTag()) + if (IsVideoDb(*this) && HasVideoInfoTag()) { CFileItem dbItem(m_bIsFolder ? GetVideoInfoTag()->m_strPath : GetVideoInfoTag()->m_strFileNameAndPath, m_bIsFolder); return dbItem.Exists(); @@ -872,51 +872,6 @@ bool CFileItem::Exists(bool bUseCache /* = true */) const return false; } -bool CFileItem::IsVideo() const -{ - /* check preset mime type */ - if(StringUtils::StartsWithNoCase(m_mimetype, "video/")) - return true; - - if (HasVideoInfoTag()) - return true; - - if (HasGameInfoTag()) - return false; - - if (HasMusicInfoTag()) - return false; - - if (HasPictureInfoTag()) - return false; - - // TV recordings are videos... - if (!m_bIsFolder && URIUtils::IsPVRTVRecordingFileOrFolder(GetPath())) - return true; - - // ... all other PVR items are not. - if (IsPVR()) - return false; - - if (URIUtils::IsDVD(m_strPath)) - return true; - - std::string extension; - if(StringUtils::StartsWithNoCase(m_mimetype, "application/")) - { /* check for some standard types */ - extension = m_mimetype.substr(12); - if( StringUtils::EqualsNoCase(extension, "ogg") - || StringUtils::EqualsNoCase(extension, "mp4") - || StringUtils::EqualsNoCase(extension, "mxf") ) - return true; - } - - //! @todo If the file is a zip file, ask the game clients if any support this - // file before assuming it is video. - - return URIUtils::HasExtension(m_strPath, CServiceBroker::GetFileExtensionProvider().GetVideoExtensions()); -} - bool CFileItem::IsEPG() const { return HasEPGInfoTag(); @@ -957,17 +912,6 @@ bool CFileItem::IsPVRTimer() const return HasPVRTimerInfoTag(); } -bool CFileItem::IsDiscStub() const -{ - if (IsVideoDb() && HasVideoInfoTag()) - { - CFileItem dbItem(m_bIsFolder ? GetVideoInfoTag()->m_strPath : GetVideoInfoTag()->m_strFileNameAndPath, m_bIsFolder); - return dbItem.IsDiscStub(); - } - - return URIUtils::HasExtension(m_strPath, CServiceBroker::GetFileExtensionProvider().GetDiscStubExtensions()); -} - bool CFileItem::IsAudio() const { /* check preset mime type */ @@ -1072,11 +1016,6 @@ bool CFileItem::IsLyrics() const return URIUtils::HasExtension(m_strPath, ".cdg|.lrc"); } -bool CFileItem::IsSubtitle() const -{ - return URIUtils::HasExtension(m_strPath, CServiceBroker::GetFileExtensionProvider().GetSubtitleExtensions()); -} - bool CFileItem::IsCUESheet() const { return URIUtils::HasExtension(m_strPath, ".cue"); @@ -1184,12 +1123,6 @@ bool CFileItem::IsNFO() const return URIUtils::HasExtension(m_strPath, ".nfo"); } -bool CFileItem::IsVideoExtras() const -{ - return m_bIsFolder && - StringUtils::EqualsNoCase(URIUtils::GetFileOrFolderName(m_strPath), "extras"); -} - bool CFileItem::IsDiscImage() const { return URIUtils::IsDiscImage(GetDynPath()); @@ -1197,38 +1130,10 @@ bool CFileItem::IsDiscImage() const bool CFileItem::IsOpticalMediaFile() const { - if (IsDVDFile(false, true)) + if (IsDVDFile(*this, false, true)) return true; - return IsBDFile(); -} - -bool CFileItem::IsDVDFile(bool bVobs /*= true*/, bool bIfos /*= true*/) const -{ - std::string strFileName = URIUtils::GetFileName(GetDynPath()); - if (bIfos) - { - if (StringUtils::EqualsNoCase(strFileName, "video_ts.ifo")) - return true; - if (StringUtils::StartsWithNoCase(strFileName, "vts_") && StringUtils::EndsWithNoCase(strFileName, "_0.ifo") && strFileName.length() == 12) - return true; - } - if (bVobs) - { - if (StringUtils::EqualsNoCase(strFileName, "video_ts.vob")) - return true; - if (StringUtils::StartsWithNoCase(strFileName, "vts_") && StringUtils::EndsWithNoCase(strFileName, ".vob")) - return true; - } - - return false; -} - -bool CFileItem::IsBDFile() const -{ - std::string strFileName = URIUtils::GetFileName(GetDynPath()); - return (StringUtils::EqualsNoCase(strFileName, "index.bdmv") || StringUtils::EqualsNoCase(strFileName, "MovieObject.bdmv") - || StringUtils::EqualsNoCase(strFileName, "INDEX.BDM") || StringUtils::EqualsNoCase(strFileName, "MOVIEOBJ.BDM")); + return IsBDFile(*this); } bool CFileItem::IsRAR() const @@ -1308,19 +1213,9 @@ bool CFileItem::IsBluray() const if (URIUtils::IsBluray(m_strPath)) return true; - CFileItem item = CFileItem(GetOpticalMediaPath(), false); - - 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; + CFileItem item = CFileItem(VIDEO_UTILS::GetOpticalMediaPath(*this), false); - return false; + return IsBDFile(item); } bool CFileItem::IsCDDA() const @@ -1388,11 +1283,6 @@ bool CFileItem::IsMusicDb() const return URIUtils::IsMusicDb(m_strPath); } -bool CFileItem::IsVideoDb() const -{ - return URIUtils::IsVideoDb(m_strPath); -} - bool CFileItem::IsVirtualDirectoryRoot() const { return (m_bIsFolder && m_strPath.empty()); @@ -1476,7 +1366,7 @@ void CFileItem::FillInDefaultIcon() // audio SetArt("icon", "DefaultAudio.png"); } - else if ( IsVideo() ) + else if (IsVideo(*this)) { // video SetArt("icon", "DefaultVideo.png"); @@ -1700,7 +1590,7 @@ bool CFileItem::IsSamePath(const CFileItem *item) const dbItem.SetProperty("item_start", GetProperty("item_start")); return dbItem.IsSamePath(item); } - if (IsVideoDb() && HasVideoInfoTag()) + if (IsVideoDb(*this) && HasVideoInfoTag()) { CFileItem dbItem(GetVideoInfoTag()->m_strFileNameAndPath, false); if (HasProperty("item_start")) @@ -1714,7 +1604,7 @@ bool CFileItem::IsSamePath(const CFileItem *item) const dbItem.SetProperty("item_start", item->GetProperty("item_start")); return IsSamePath(&dbItem); } - if (item->IsVideoDb() && item->HasVideoInfoTag()) + if (IsVideoDb(*item) && item->HasVideoInfoTag()) { CFileItem dbItem(item->GetVideoInfoTag()->m_strFileNameAndPath, false); if (item->HasProperty("item_start")) @@ -1865,7 +1755,7 @@ void CFileItem::MergeInfo(const CFileItem& item) SetLabel2(item.GetLabel2()); if (!item.GetArt().empty()) { - if (item.IsVideo()) + if (IsVideo(item)) AppendArt(item.GetArt()); else SetArt(item.GetArt()); @@ -2008,37 +1898,6 @@ void CFileItem::SetFromSong(const CSong &song) FillInMimeType(false); } -std::string CFileItem::GetOpticalMediaPath() const -{ - std::string path; - path = URIUtils::AddFileToFolder(GetPath(), "VIDEO_TS.IFO"); - if (CFile::Exists(path)) - return path; - - path = URIUtils::AddFileToFolder(GetPath(), "VIDEO_TS", "VIDEO_TS.IFO"); - if (CFile::Exists(path)) - return path; - -#ifdef HAVE_LIBBLURAY - path = URIUtils::AddFileToFolder(GetPath(), "index.bdmv"); - if (CFile::Exists(path)) - return path; - - path = URIUtils::AddFileToFolder(GetPath(), "BDMV", "index.bdmv"); - if (CFile::Exists(path)) - return path; - - path = URIUtils::AddFileToFolder(GetPath(), "INDEX.BDM"); - if (CFile::Exists(path)) - return path; - - path = URIUtils::AddFileToFolder(GetPath(), "BDMV", "INDEX.BDM"); - if (CFile::Exists(path)) - return path; -#endif - return std::string(); -} - /** * @todo Ideally this (and SetPath) would not be available outside of construction * for CFileItem objects, or at least restricted to essentially be equivalent @@ -2195,1083 +2054,6 @@ bool CFileItem::LoadTracksFromCueDocument(CFileItemList& scannedItems) return tracksFound != 0; } -///////////////////////////////////////////////////////////////////////////////// -///// -///// CFileItemList -///// -////////////////////////////////////////////////////////////////////////////////// - -CFileItemList::CFileItemList() -: CFileItem("", true) -{ -} - -CFileItemList::CFileItemList(const std::string& strPath) -: CFileItem(strPath, true) -{ -} - -CFileItemList::~CFileItemList() -{ - Clear(); -} - -CFileItemPtr CFileItemList::operator[] (int iItem) -{ - return Get(iItem); -} - -const CFileItemPtr CFileItemList::operator[] (int iItem) const -{ - return Get(iItem); -} - -CFileItemPtr CFileItemList::operator[] (const std::string& strPath) -{ - return Get(strPath); -} - -const CFileItemPtr CFileItemList::operator[] (const std::string& strPath) const -{ - return Get(strPath); -} - -void CFileItemList::SetIgnoreURLOptions(bool ignoreURLOptions) -{ - m_ignoreURLOptions = ignoreURLOptions; - - if (m_fastLookup) - { - m_fastLookup = false; // Force SetFastlookup to clear map - SetFastLookup(true); // and regenerate map - } -} - -void CFileItemList::SetFastLookup(bool fastLookup) -{ - std::unique_lock<CCriticalSection> lock(m_lock); - - if (fastLookup && !m_fastLookup) - { // generate the map - m_map.clear(); - for (unsigned int i=0; i < m_items.size(); i++) - { - CFileItemPtr pItem = m_items[i]; - m_map.insert(MAPFILEITEMSPAIR(m_ignoreURLOptions ? CURL(pItem->GetPath()).GetWithoutOptions() : pItem->GetPath(), pItem)); - } - } - if (!fastLookup && m_fastLookup) - m_map.clear(); - m_fastLookup = fastLookup; -} - -bool CFileItemList::Contains(const std::string& fileName) const -{ - std::unique_lock<CCriticalSection> lock(m_lock); - - if (m_fastLookup) - return m_map.find(m_ignoreURLOptions ? CURL(fileName).GetWithoutOptions() : fileName) != m_map.end(); - - // slow method... - for (unsigned int i = 0; i < m_items.size(); i++) - { - const CFileItemPtr pItem = m_items[i]; - if (pItem->IsPath(m_ignoreURLOptions ? CURL(fileName).GetWithoutOptions() : fileName)) - return true; - } - return false; -} - -void CFileItemList::Clear() -{ - std::unique_lock<CCriticalSection> lock(m_lock); - - ClearItems(); - m_sortDescription.sortBy = SortByNone; - m_sortDescription.sortOrder = SortOrderNone; - m_sortDescription.sortAttributes = SortAttributeNone; - m_sortIgnoreFolders = false; - m_cacheToDisc = CACHE_IF_SLOW; - m_sortDetails.clear(); - m_replaceListing = false; - m_content.clear(); -} - -void CFileItemList::ClearItems() -{ - std::unique_lock<CCriticalSection> lock(m_lock); - // make sure we free the memory of the items (these are GUIControls which may have allocated resources) - FreeMemory(); - for (unsigned int i = 0; i < m_items.size(); i++) - { - CFileItemPtr item = m_items[i]; - item->FreeMemory(); - } - m_items.clear(); - m_map.clear(); -} - -void CFileItemList::Add(CFileItemPtr pItem) -{ - std::unique_lock<CCriticalSection> lock(m_lock); - if (m_fastLookup) - m_map.insert(MAPFILEITEMSPAIR(m_ignoreURLOptions ? CURL(pItem->GetPath()).GetWithoutOptions() : pItem->GetPath(), pItem)); - m_items.emplace_back(std::move(pItem)); -} - -void CFileItemList::Add(CFileItem&& item) -{ - std::unique_lock<CCriticalSection> lock(m_lock); - auto ptr = std::make_shared<CFileItem>(std::move(item)); - if (m_fastLookup) - m_map.insert(MAPFILEITEMSPAIR(m_ignoreURLOptions ? CURL(ptr->GetPath()).GetWithoutOptions() : ptr->GetPath(), ptr)); - m_items.emplace_back(std::move(ptr)); -} - -void CFileItemList::AddFront(const CFileItemPtr &pItem, int itemPosition) -{ - std::unique_lock<CCriticalSection> lock(m_lock); - - if (itemPosition >= 0) - { - m_items.insert(m_items.begin()+itemPosition, pItem); - } - else - { - m_items.insert(m_items.begin()+(m_items.size()+itemPosition), pItem); - } - if (m_fastLookup) - { - m_map.insert(MAPFILEITEMSPAIR(m_ignoreURLOptions ? CURL(pItem->GetPath()).GetWithoutOptions() : pItem->GetPath(), pItem)); - } -} - -void CFileItemList::Remove(CFileItem* pItem) -{ - std::unique_lock<CCriticalSection> lock(m_lock); - - for (IVECFILEITEMS it = m_items.begin(); it != m_items.end(); ++it) - { - if (pItem == it->get()) - { - m_items.erase(it); - if (m_fastLookup) - { - m_map.erase(m_ignoreURLOptions ? CURL(pItem->GetPath()).GetWithoutOptions() : pItem->GetPath()); - } - break; - } - } -} - -VECFILEITEMS::iterator CFileItemList::erase(VECFILEITEMS::iterator first, - VECFILEITEMS::iterator last) -{ - std::unique_lock<CCriticalSection> lock(m_lock); - return m_items.erase(first, last); -} - -void CFileItemList::Remove(int iItem) -{ - std::unique_lock<CCriticalSection> lock(m_lock); - - if (iItem >= 0 && iItem < Size()) - { - CFileItemPtr pItem = *(m_items.begin() + iItem); - if (m_fastLookup) - { - m_map.erase(m_ignoreURLOptions ? CURL(pItem->GetPath()).GetWithoutOptions() : pItem->GetPath()); - } - m_items.erase(m_items.begin() + iItem); - } -} - -void CFileItemList::Append(const CFileItemList& itemlist) -{ - std::unique_lock<CCriticalSection> lock(m_lock); - - for (int i = 0; i < itemlist.Size(); ++i) - Add(itemlist[i]); -} - -void CFileItemList::Assign(const CFileItemList& itemlist, bool append) -{ - std::unique_lock<CCriticalSection> lock(m_lock); - if (!append) - Clear(); - Append(itemlist); - SetPath(itemlist.GetPath()); - SetLabel(itemlist.GetLabel()); - m_sortDetails = itemlist.m_sortDetails; - m_sortDescription = itemlist.m_sortDescription; - m_replaceListing = itemlist.m_replaceListing; - m_content = itemlist.m_content; - m_mapProperties = itemlist.m_mapProperties; - m_cacheToDisc = itemlist.m_cacheToDisc; -} - -bool CFileItemList::Copy(const CFileItemList& items, bool copyItems /* = true */) -{ - // assign all CFileItem parts - *static_cast<CFileItem*>(this) = static_cast<const CFileItem&>(items); - - // assign the rest of the CFileItemList properties - m_replaceListing = items.m_replaceListing; - m_content = items.m_content; - m_mapProperties = items.m_mapProperties; - m_cacheToDisc = items.m_cacheToDisc; - m_sortDetails = items.m_sortDetails; - m_sortDescription = items.m_sortDescription; - m_sortIgnoreFolders = items.m_sortIgnoreFolders; - - if (copyItems) - { - // make a copy of each item - for (int i = 0; i < items.Size(); i++) - { - CFileItemPtr newItem(new CFileItem(*items[i])); - Add(newItem); - } - } - - return true; -} - -CFileItemPtr CFileItemList::Get(int iItem) const -{ - std::unique_lock<CCriticalSection> lock(m_lock); - - if (iItem > -1 && iItem < (int)m_items.size()) - return m_items[iItem]; - - return CFileItemPtr(); -} - -CFileItemPtr CFileItemList::Get(const std::string& strPath) const -{ - std::unique_lock<CCriticalSection> lock(m_lock); - - if (m_fastLookup) - { - MAPFILEITEMS::const_iterator it = - m_map.find(m_ignoreURLOptions ? CURL(strPath).GetWithoutOptions() : strPath); - if (it != m_map.end()) - return it->second; - - return CFileItemPtr(); - } - // slow method... - for (unsigned int i = 0; i < m_items.size(); i++) - { - CFileItemPtr pItem = m_items[i]; - if (pItem->IsPath(m_ignoreURLOptions ? CURL(strPath).GetWithoutOptions() : strPath)) - return pItem; - } - - return CFileItemPtr(); -} - -int CFileItemList::Size() const -{ - std::unique_lock<CCriticalSection> lock(m_lock); - return (int)m_items.size(); -} - -bool CFileItemList::IsEmpty() const -{ - std::unique_lock<CCriticalSection> lock(m_lock); - return m_items.empty(); -} - -void CFileItemList::Reserve(size_t iCount) -{ - std::unique_lock<CCriticalSection> lock(m_lock); - m_items.reserve(iCount); -} - -void CFileItemList::Sort(FILEITEMLISTCOMPARISONFUNC func) -{ - std::unique_lock<CCriticalSection> lock(m_lock); - std::stable_sort(m_items.begin(), m_items.end(), func); -} - -void CFileItemList::FillSortFields(FILEITEMFILLFUNC func) -{ - std::unique_lock<CCriticalSection> lock(m_lock); - std::for_each(m_items.begin(), m_items.end(), func); -} - -void CFileItemList::Sort(SortBy sortBy, SortOrder sortOrder, SortAttribute sortAttributes /* = SortAttributeNone */) -{ - if (sortBy == SortByNone || - (m_sortDescription.sortBy == sortBy && m_sortDescription.sortOrder == sortOrder && - m_sortDescription.sortAttributes == sortAttributes)) - return; - - SortDescription sorting; - sorting.sortBy = sortBy; - sorting.sortOrder = sortOrder; - sorting.sortAttributes = sortAttributes; - - Sort(sorting); - m_sortDescription = sorting; -} - -void CFileItemList::Sort(SortDescription sortDescription) -{ - if (sortDescription.sortBy == SortByFile || sortDescription.sortBy == SortBySortTitle || - sortDescription.sortBy == SortByOriginalTitle || sortDescription.sortBy == SortByDateAdded || - sortDescription.sortBy == SortByRating || sortDescription.sortBy == SortByYear || - sortDescription.sortBy == SortByPlaylistOrder || sortDescription.sortBy == SortByLastPlayed || - sortDescription.sortBy == SortByPlaycount) - sortDescription.sortAttributes = (SortAttribute)((int)sortDescription.sortAttributes | SortAttributeIgnoreFolders); - - if (sortDescription.sortBy == SortByNone || - (m_sortDescription.sortBy == sortDescription.sortBy && m_sortDescription.sortOrder == sortDescription.sortOrder && - m_sortDescription.sortAttributes == sortDescription.sortAttributes)) - return; - - if (m_sortIgnoreFolders) - sortDescription.sortAttributes = (SortAttribute)((int)sortDescription.sortAttributes | SortAttributeIgnoreFolders); - - const Fields fields = SortUtils::GetFieldsForSorting(sortDescription.sortBy); - SortItems sortItems((size_t)Size()); - for (int index = 0; index < Size(); index++) - { - sortItems[index] = std::make_shared<SortItem>(); - m_items[index]->ToSortable(*sortItems[index], fields); - (*sortItems[index])[FieldId] = index; - } - - // do the sorting - SortUtils::Sort(sortDescription, sortItems); - - // apply the new order to the existing CFileItems - VECFILEITEMS sortedFileItems; - sortedFileItems.reserve(Size()); - for (SortItems::const_iterator it = sortItems.begin(); it != sortItems.end(); ++it) - { - CFileItemPtr item = m_items[(int)(*it)->at(FieldId).asInteger()]; - // Set the sort label in the CFileItem - item->SetSortLabel((*it)->at(FieldSort).asWideString()); - - sortedFileItems.push_back(item); - } - - // replace the current list with the re-ordered one - m_items = std::move(sortedFileItems); -} - -void CFileItemList::Randomize() -{ - std::unique_lock<CCriticalSection> lock(m_lock); - KODI::UTILS::RandomShuffle(m_items.begin(), m_items.end()); -} - -void CFileItemList::Archive(CArchive& ar) -{ - std::unique_lock<CCriticalSection> lock(m_lock); - if (ar.IsStoring()) - { - CFileItem::Archive(ar); - - int i = 0; - if (!m_items.empty() && m_items[0]->IsParentFolder()) - i = 1; - - ar << (int)(m_items.size() - i); - - ar << m_ignoreURLOptions; - - ar << m_fastLookup; - - ar << (int)m_sortDescription.sortBy; - ar << (int)m_sortDescription.sortOrder; - ar << (int)m_sortDescription.sortAttributes; - ar << m_sortIgnoreFolders; - ar << (int)m_cacheToDisc; - - ar << (int)m_sortDetails.size(); - for (unsigned int j = 0; j < m_sortDetails.size(); ++j) - { - const GUIViewSortDetails &details = m_sortDetails[j]; - ar << (int)details.m_sortDescription.sortBy; - ar << (int)details.m_sortDescription.sortOrder; - ar << (int)details.m_sortDescription.sortAttributes; - ar << details.m_buttonLabel; - ar << details.m_labelMasks.m_strLabelFile; - ar << details.m_labelMasks.m_strLabelFolder; - ar << details.m_labelMasks.m_strLabel2File; - ar << details.m_labelMasks.m_strLabel2Folder; - } - - ar << m_content; - - for (; i < (int)m_items.size(); ++i) - { - CFileItemPtr pItem = m_items[i]; - ar << *pItem; - } - } - else - { - CFileItemPtr pParent; - if (!IsEmpty()) - { - CFileItemPtr pItem=m_items[0]; - if (pItem->IsParentFolder()) - pParent = std::make_shared<CFileItem>(*pItem); - } - - SetIgnoreURLOptions(false); - SetFastLookup(false); - Clear(); - - CFileItem::Archive(ar); - - int iSize = 0; - ar >> iSize; - if (iSize <= 0) - return ; - - if (pParent) - { - m_items.reserve(iSize + 1); - m_items.push_back(pParent); - } - else - m_items.reserve(iSize); - - bool ignoreURLOptions = false; - ar >> ignoreURLOptions; - - bool fastLookup = false; - ar >> fastLookup; - - int tempint; - ar >> tempint; - m_sortDescription.sortBy = (SortBy)tempint; - ar >> tempint; - m_sortDescription.sortOrder = (SortOrder)tempint; - ar >> tempint; - m_sortDescription.sortAttributes = (SortAttribute)tempint; - ar >> m_sortIgnoreFolders; - ar >> tempint; - m_cacheToDisc = CACHE_TYPE(tempint); - - unsigned int detailSize = 0; - ar >> detailSize; - for (unsigned int j = 0; j < detailSize; ++j) - { - GUIViewSortDetails details; - ar >> tempint; - details.m_sortDescription.sortBy = (SortBy)tempint; - ar >> tempint; - details.m_sortDescription.sortOrder = (SortOrder)tempint; - ar >> tempint; - details.m_sortDescription.sortAttributes = (SortAttribute)tempint; - ar >> details.m_buttonLabel; - ar >> details.m_labelMasks.m_strLabelFile; - ar >> details.m_labelMasks.m_strLabelFolder; - ar >> details.m_labelMasks.m_strLabel2File; - ar >> details.m_labelMasks.m_strLabel2Folder; - m_sortDetails.push_back(details); - } - - ar >> m_content; - - for (int i = 0; i < iSize; ++i) - { - CFileItemPtr pItem(new CFileItem); - ar >> *pItem; - Add(pItem); - } - - SetIgnoreURLOptions(ignoreURLOptions); - SetFastLookup(fastLookup); - } -} - -void CFileItemList::FillInDefaultIcons() -{ - std::unique_lock<CCriticalSection> lock(m_lock); - for (int i = 0; i < (int)m_items.size(); ++i) - { - CFileItemPtr pItem = m_items[i]; - pItem->FillInDefaultIcon(); - } -} - -int CFileItemList::GetFolderCount() const -{ - std::unique_lock<CCriticalSection> lock(m_lock); - int nFolderCount = 0; - for (int i = 0; i < (int)m_items.size(); i++) - { - CFileItemPtr pItem = m_items[i]; - if (pItem->m_bIsFolder) - nFolderCount++; - } - - return nFolderCount; -} - -int CFileItemList::GetObjectCount() const -{ - std::unique_lock<CCriticalSection> lock(m_lock); - - int numObjects = (int)m_items.size(); - if (numObjects && m_items[0]->IsParentFolder()) - numObjects--; - - return numObjects; -} - -int CFileItemList::GetFileCount() const -{ - std::unique_lock<CCriticalSection> lock(m_lock); - int nFileCount = 0; - for (int i = 0; i < (int)m_items.size(); i++) - { - CFileItemPtr pItem = m_items[i]; - if (!pItem->m_bIsFolder) - nFileCount++; - } - - return nFileCount; -} - -int CFileItemList::GetSelectedCount() const -{ - std::unique_lock<CCriticalSection> lock(m_lock); - int count = 0; - for (int i = 0; i < (int)m_items.size(); i++) - { - CFileItemPtr pItem = m_items[i]; - if (pItem->IsSelected()) - count++; - } - - return count; -} - -void CFileItemList::FilterCueItems() -{ - std::unique_lock<CCriticalSection> lock(m_lock); - // Handle .CUE sheet files... - std::vector<std::string> itemstodelete; - for (int i = 0; i < (int)m_items.size(); i++) - { - CFileItemPtr pItem = m_items[i]; - if (!pItem->m_bIsFolder) - { // see if it's a .CUE sheet - if (pItem->IsCUESheet()) - { - CCueDocumentPtr cuesheet(new CCueDocument); - if (cuesheet->ParseFile(pItem->GetPath())) - { - std::vector<std::string> MediaFileVec; - cuesheet->GetMediaFiles(MediaFileVec); - - // queue the cue sheet and the underlying media file for deletion - for (std::vector<std::string>::iterator itMedia = MediaFileVec.begin(); - itMedia != MediaFileVec.end(); ++itMedia) - { - std::string strMediaFile = *itMedia; - std::string fileFromCue = strMediaFile; // save the file from the cue we're matching against, - // as we're going to search for others here... - bool bFoundMediaFile = CFile::Exists(strMediaFile); - if (!bFoundMediaFile) - { - // try file in same dir, not matching case... - if (Contains(strMediaFile)) - { - bFoundMediaFile = true; - } - else - { - // try removing the .cue extension... - strMediaFile = pItem->GetPath(); - URIUtils::RemoveExtension(strMediaFile); - CFileItem item(strMediaFile, false); - if (item.IsAudio() && Contains(strMediaFile)) - { - bFoundMediaFile = true; - } - else - { // try replacing the extension with one of our allowed ones. - std::vector<std::string> extensions = StringUtils::Split(CServiceBroker::GetFileExtensionProvider().GetMusicExtensions(), "|"); - for (std::vector<std::string>::const_iterator i = extensions.begin(); i != extensions.end(); ++i) - { - strMediaFile = URIUtils::ReplaceExtension(pItem->GetPath(), *i); - CFileItem item(strMediaFile, false); - if (!item.IsCUESheet() && !item.IsPlayList() && Contains(strMediaFile)) - { - bFoundMediaFile = true; - break; - } - } - } - } - } - if (bFoundMediaFile) - { - cuesheet->UpdateMediaFile(fileFromCue, strMediaFile); - // apply CUE for later processing - for (int j = 0; j < (int)m_items.size(); j++) - { - CFileItemPtr pItem = m_items[j]; - if (StringUtils::CompareNoCase(pItem->GetPath(), strMediaFile) == 0) - pItem->SetCueDocument(cuesheet); - } - } - } - } - itemstodelete.push_back(pItem->GetPath()); - } - } - } - // now delete the .CUE files. - for (int i = 0; i < (int)itemstodelete.size(); i++) - { - for (int j = 0; j < (int)m_items.size(); j++) - { - CFileItemPtr pItem = m_items[j]; - if (StringUtils::CompareNoCase(pItem->GetPath(), itemstodelete[i]) == 0) - { // delete this item - m_items.erase(m_items.begin() + j); - break; - } - } - } -} - -// Remove the extensions from the filenames -void CFileItemList::RemoveExtensions() -{ - std::unique_lock<CCriticalSection> lock(m_lock); - for (int i = 0; i < Size(); ++i) - m_items[i]->RemoveExtension(); -} - -void CFileItemList::Stack(bool stackFiles /* = true */) -{ - std::unique_lock<CCriticalSection> lock(m_lock); - - // not allowed here - if (IsVirtualDirectoryRoot() || - IsLiveTV() || - IsSourcesPath() || - IsLibraryFolder()) - return; - - SetProperty("isstacked", true); - - // items needs to be sorted for stuff below to work properly - Sort(SortByLabel, SortOrderAscending); - - StackFolders(); - - if (stackFiles) - StackFiles(); -} - -void CFileItemList::StackFolders() -{ - // Precompile our REs - VECCREGEXP folderRegExps; - CRegExp folderRegExp(true, CRegExp::autoUtf8); - const std::vector<std::string>& strFolderRegExps = CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_folderStackRegExps; - - std::vector<std::string>::const_iterator strExpression = strFolderRegExps.begin(); - while (strExpression != strFolderRegExps.end()) - { - if (!folderRegExp.RegComp(*strExpression)) - CLog::Log(LOGERROR, "{}: Invalid folder stack RegExp:'{}'", __FUNCTION__, - strExpression->c_str()); - else - folderRegExps.push_back(folderRegExp); - - ++strExpression; - } - - if (!folderRegExp.IsCompiled()) - { - CLog::Log(LOGDEBUG, "{}: No stack expressions available. Skipping folder stacking", - __FUNCTION__); - return; - } - - // stack folders - for (int i = 0; i < Size(); i++) - { - CFileItemPtr item = Get(i); - // combined the folder checks - if (item->m_bIsFolder) - { - // only check known fast sources? - // NOTES: - // 1. rars and zips may be on slow sources? is this supposed to be allowed? - if( !item->IsRemote() - || item->IsSmb() - || item->IsNfs() - || URIUtils::IsInRAR(item->GetPath()) - || URIUtils::IsInZIP(item->GetPath()) - || URIUtils::IsOnLAN(item->GetPath()) - ) - { - // stack cd# folders if contains only a single video file - - bool bMatch(false); - - VECCREGEXP::iterator expr = folderRegExps.begin(); - while (!bMatch && expr != folderRegExps.end()) - { - //CLog::Log(LOGDEBUG,"{}: Running expression {} on {}", __FUNCTION__, expr->GetPattern(), item->GetLabel()); - bMatch = (expr->RegFind(item->GetLabel().c_str()) != -1); - if (bMatch) - { - CFileItemList items; - CDirectory::GetDirectory(item->GetPath(), items, - CServiceBroker::GetFileExtensionProvider().GetVideoExtensions(), - DIR_FLAG_DEFAULTS); - // optimized to only traverse listing once by checking for filecount - // and recording last file item for later use - int nFiles = 0; - int index = -1; - for (int j = 0; j < items.Size(); j++) - { - if (!items[j]->m_bIsFolder) - { - nFiles++; - index = j; - } - - if (nFiles > 1) - break; - } - - if (nFiles == 1) - *item = *items[index]; - } - ++expr; - } - - // check for dvd folders - if (!bMatch) - { - std::string dvdPath = item->GetOpticalMediaPath(); - - if (!dvdPath.empty()) - { - // NOTE: should this be done for the CD# folders too? - item->m_bIsFolder = false; - item->SetPath(dvdPath); - item->SetLabel2(""); - item->SetLabelPreformatted(true); - m_sortDescription.sortBy = SortByNone; /* sorting is now broken */ - } - } - } - } - } -} - -void CFileItemList::StackFiles() -{ - // Precompile our REs - VECCREGEXP stackRegExps; - CRegExp tmpRegExp(true, CRegExp::autoUtf8); - const std::vector<std::string>& strStackRegExps = CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_videoStackRegExps; - std::vector<std::string>::const_iterator strRegExp = strStackRegExps.begin(); - while (strRegExp != strStackRegExps.end()) - { - if (tmpRegExp.RegComp(*strRegExp)) - { - if (tmpRegExp.GetCaptureTotal() == 4) - stackRegExps.push_back(tmpRegExp); - else - CLog::Log(LOGERROR, "Invalid video stack RE ({}). Must have 4 captures.", *strRegExp); - } - ++strRegExp; - } - - // now stack the files, some of which may be from the previous stack iteration - int i = 0; - while (i < Size()) - { - CFileItemPtr item1 = Get(i); - - // skip folders, nfo files, playlists - if (item1->m_bIsFolder - || item1->IsParentFolder() - || item1->IsNFO() - || item1->IsPlayList() - ) - { - // increment index - i++; - continue; - } - - int64_t size = 0; - size_t offset = 0; - std::string stackName; - std::string file1; - std::string filePath; - std::vector<int> stack; - VECCREGEXP::iterator expr = stackRegExps.begin(); - - URIUtils::Split(item1->GetPath(), filePath, file1); - if (URIUtils::HasEncodedFilename(CURL(filePath))) - file1 = CURL::Decode(file1); - - int j; - while (expr != stackRegExps.end()) - { - if (expr->RegFind(file1, offset) != -1) - { - std::string Title1 = expr->GetMatch(1), - Volume1 = expr->GetMatch(2), - Ignore1 = expr->GetMatch(3), - Extension1 = expr->GetMatch(4); - if (offset) - Title1 = file1.substr(0, expr->GetSubStart(2)); - j = i + 1; - while (j < Size()) - { - CFileItemPtr item2 = Get(j); - - // skip folders, nfo files, playlists - if (item2->m_bIsFolder - || item2->IsParentFolder() - || item2->IsNFO() - || item2->IsPlayList() - ) - { - // increment index - j++; - continue; - } - - std::string file2, filePath2; - URIUtils::Split(item2->GetPath(), filePath2, file2); - if (URIUtils::HasEncodedFilename(CURL(filePath2)) ) - file2 = CURL::Decode(file2); - - if (expr->RegFind(file2, offset) != -1) - { - std::string Title2 = expr->GetMatch(1), - Volume2 = expr->GetMatch(2), - Ignore2 = expr->GetMatch(3), - Extension2 = expr->GetMatch(4); - if (offset) - Title2 = file2.substr(0, expr->GetSubStart(2)); - if (StringUtils::EqualsNoCase(Title1, Title2)) - { - if (!StringUtils::EqualsNoCase(Volume1, Volume2)) - { - if (StringUtils::EqualsNoCase(Ignore1, Ignore2) && - StringUtils::EqualsNoCase(Extension1, Extension2)) - { - if (stack.empty()) - { - stackName = Title1 + Ignore1 + Extension1; - stack.push_back(i); - size += item1->m_dwSize; - } - stack.push_back(j); - size += item2->m_dwSize; - } - else // Sequel - { - offset = 0; - ++expr; - break; - } - } - else if (!StringUtils::EqualsNoCase(Ignore1, Ignore2)) // False positive, try again with offset - { - offset = expr->GetSubStart(3); - break; - } - else // Extension mismatch - { - offset = 0; - ++expr; - break; - } - } - else // Title mismatch - { - offset = 0; - ++expr; - break; - } - } - else // No match 2, next expression - { - offset = 0; - ++expr; - break; - } - j++; - } - if (j == Size()) - expr = stackRegExps.end(); - } - else // No match 1 - { - offset = 0; - ++expr; - } - if (stack.size() > 1) - { - // have a stack, remove the items and add the stacked item - // dont actually stack a multipart rar set, just remove all items but the first - std::string stackPath; - if (Get(stack[0])->IsRAR()) - stackPath = Get(stack[0])->GetPath(); - else - { - CStackDirectory dir; - stackPath = dir.ConstructStackPath(*this, stack); - } - item1->SetPath(stackPath); - // clean up list - for (unsigned k = 1; k < stack.size(); k++) - Remove(i+1); - // item->m_bIsFolder = true; // don't treat stacked files as folders - // the label may be in a different char set from the filename (eg over smb - // the label is converted from utf8, but the filename is not) - if (!CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_FILELISTS_SHOWEXTENSIONS)) - URIUtils::RemoveExtension(stackName); - - item1->SetLabel(stackName); - item1->m_dwSize = size; - break; - } - } - i++; - } -} - -bool CFileItemList::Load(int windowID) -{ - CFile file; - auto path = GetDiscFileCache(windowID); - try - { - if (file.Open(path)) - { - CArchive ar(&file, CArchive::load); - ar >> *this; - CLog::Log(LOGDEBUG, "Loading items: {}, directory: {} sort method: {}, ascending: {}", Size(), - CURL::GetRedacted(GetPath()), m_sortDescription.sortBy, - m_sortDescription.sortOrder == SortOrderAscending ? "true" : "false"); - ar.Close(); - file.Close(); - return true; - } - } - catch(const std::out_of_range&) - { - CLog::Log(LOGERROR, "Corrupt archive: {}", CURL::GetRedacted(path)); - } - - return false; -} - -bool CFileItemList::Save(int windowID) -{ - int iSize = Size(); - if (iSize <= 0) - return false; - - CLog::Log(LOGDEBUG, "Saving fileitems [{}]", CURL::GetRedacted(GetPath())); - - CFile file; - std::string cachefile = GetDiscFileCache(windowID); - if (file.OpenForWrite(cachefile, true)) // overwrite always - { - // Before caching save simplified cache file name in every item so the cache file can be - // identifed and removed if the item is updated. List path and options (used for file - // name when list cached) can not be accurately derived from item path. - StringUtils::Replace(cachefile, "special://temp/archive_cache/", ""); - StringUtils::Replace(cachefile, ".fi", ""); - for (const auto& item : m_items) - item->SetProperty("cachefilename", cachefile); - - CArchive ar(&file, CArchive::store); - ar << *this; - CLog::Log(LOGDEBUG, " -- items: {}, sort method: {}, ascending: {}", iSize, - m_sortDescription.sortBy, - m_sortDescription.sortOrder == SortOrderAscending ? "true" : "false"); - ar.Close(); - file.Close(); - return true; - } - - return false; -} - -void CFileItemList::RemoveDiscCache(int windowID) const -{ - RemoveDiscCache(GetDiscFileCache(windowID)); -} - -void CFileItemList::RemoveDiscCache(const std::string& cacheFile) const -{ - if (CFile::Exists(cacheFile)) - { - CLog::Log(LOGDEBUG, "Clearing cached fileitems [{}]", CURL::GetRedacted(GetPath())); - CFile::Delete(cacheFile); - } -} - -void CFileItemList::RemoveDiscCacheCRC(const std::string& crc) const -{ - std::string cachefile = StringUtils::Format("special://temp/archive_cache/{}.fi", crc); - RemoveDiscCache(cachefile); -} - -std::string CFileItemList::GetDiscFileCache(int windowID) const -{ - std::string strPath(GetPath()); - URIUtils::RemoveSlashAtEnd(strPath); - - uint32_t crc = Crc32::ComputeFromLowerCase(strPath); - - if (IsCDDA() || IsOnDVD()) - return StringUtils::Format("special://temp/archive_cache/r-{:08x}.fi", crc); - - if (IsMusicDb()) - return StringUtils::Format("special://temp/archive_cache/mdb-{:08x}.fi", crc); - - if (IsVideoDb()) - return StringUtils::Format("special://temp/archive_cache/vdb-{:08x}.fi", crc); - - if (IsSmartPlayList()) - return StringUtils::Format("special://temp/archive_cache/sp-{:08x}.fi", crc); - - if (windowID) - return StringUtils::Format("special://temp/archive_cache/{}-{:08x}.fi", windowID, crc); - - return StringUtils::Format("special://temp/archive_cache/{:08x}.fi", crc); -} - -bool CFileItemList::AlwaysCache() const -{ - // some database folders are always cached - if (IsMusicDb()) - return CMusicDatabaseDirectory::CanCache(GetPath()); - if (IsVideoDb()) - return CVideoDatabaseDirectory::CanCache(GetPath()); - if (IsEPG()) - return true; // always cache - return false; -} - std::string CFileItem::GetUserMusicThumb(bool alwaysCheckRemote /* = false */, bool fallbackToFolder /* = false */) const { if (m_strPath.empty() @@ -3605,7 +2387,7 @@ std::string CFileItem::GetBaseMoviePath(bool bUseFolderNames) const std::string CFileItem::GetLocalFanart() const { - if (IsVideoDb()) + if (IsVideoDb(*this)) { if (!HasVideoInfoTag()) return ""; // nothing can be done @@ -3779,7 +2561,7 @@ bool CFileItem::LoadGameTag() bool CFileItem::LoadDetails() { - if (IsVideoDb()) + if (IsVideoDb(*this)) { if (HasVideoInfoTag()) return true; @@ -3839,7 +2621,7 @@ bool CFileItem::LoadDetails() return false; } - if (!IsPlayList() && IsVideo()) + if (!IsPlayList() && IsVideo(*this)) { if (HasVideoInfoTag()) return true; @@ -3871,7 +2653,7 @@ bool CFileItem::LoadDetails() if (playlist->Load(GetPath()) && playlist->size() == 1) { const auto item{(*playlist)[0]}; - if (item->IsVideo()) + if (IsVideo(*item)) { CVideoDatabase db; if (!db.Open()) @@ -3959,66 +2741,6 @@ bool CFileItem::LoadDetails() return false; } -void CFileItemList::Swap(unsigned int item1, unsigned int item2) -{ - if (item1 != item2 && item1 < m_items.size() && item2 < m_items.size()) - std::swap(m_items[item1], m_items[item2]); -} - -bool CFileItemList::UpdateItem(const CFileItem *item) -{ - if (!item) - return false; - - std::unique_lock<CCriticalSection> lock(m_lock); - for (unsigned int i = 0; i < m_items.size(); i++) - { - CFileItemPtr pItem = m_items[i]; - if (pItem->IsSamePath(item)) - { - pItem->UpdateInfo(*item); - return true; - } - } - return false; -} - -void CFileItemList::AddSortMethod(SortBy sortBy, int buttonLabel, const LABEL_MASKS &labelMasks, SortAttribute sortAttributes /* = SortAttributeNone */) -{ - AddSortMethod(sortBy, sortAttributes, buttonLabel, labelMasks); -} - -void CFileItemList::AddSortMethod(SortBy sortBy, SortAttribute sortAttributes, int buttonLabel, const LABEL_MASKS &labelMasks) -{ - SortDescription sorting; - sorting.sortBy = sortBy; - sorting.sortAttributes = sortAttributes; - - AddSortMethod(sorting, buttonLabel, labelMasks); -} - -void CFileItemList::AddSortMethod(SortDescription sortDescription, int buttonLabel, const LABEL_MASKS &labelMasks) -{ - GUIViewSortDetails sort; - sort.m_sortDescription = sortDescription; - sort.m_buttonLabel = buttonLabel; - sort.m_labelMasks = labelMasks; - - m_sortDetails.push_back(sort); -} - -void CFileItemList::SetReplaceListing(bool replace) -{ - m_replaceListing = replace; -} - -void CFileItemList::ClearSortState() -{ - m_sortDescription.sortBy = SortByNone; - m_sortDescription.sortOrder = SortOrderNone; - m_sortDescription.sortAttributes = SortAttributeNone; -} - bool CFileItem::HasVideoInfoTag() const { // Note: CPVRRecording is derived from CVideoInfoTag diff --git a/xbmc/FileItem.h b/xbmc/FileItem.h index 7e9c2285c7..473c11c9d7 100644 --- a/xbmc/FileItem.h +++ b/xbmc/FileItem.h @@ -157,30 +157,12 @@ public: bool Exists(bool bUseCache = true) const; /*! - \brief Check whether an item is an optical media folder or its parent. - This will return the non-empty path to the playable entry point of the media - one or two levels down (VIDEO_TS.IFO for DVDs or index.bdmv for BDs). - The returned path will be empty if folder does not meet this criterion. - \return non-empty string if item is optical media folder, empty otherwise. - */ - std::string GetOpticalMediaPath() const; - /*! - \brief Check whether an item is a video item. Note that this returns true for - anything with a video info tag, so that may include eg. folders. - \return true if item is video, false otherwise. - */ - bool IsVideo() const; - - bool IsDiscStub() const; - - /*! \brief Check whether an item is a picture item. Note that this returns true for anything with a picture info tag, so that may include eg. folders. \return true if item is picture, false otherwise. */ bool IsPicture() const; bool IsLyrics() const; - bool IsSubtitle() const; /*! \brief Check whether an item is an audio item. Note that this returns true for @@ -214,13 +196,9 @@ public: bool IsAddonsPath() const; bool IsSourcesPath() const; bool IsNFO() const; - bool IsVideoExtras() const; bool IsDiscImage() const; bool IsOpticalMediaFile() const; - 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; @@ -240,7 +218,6 @@ public: bool IsFavourite() const; bool IsMultiPath() const; bool IsMusicDb() const; - bool IsVideoDb() const; bool IsEPG() const; bool IsPVRChannel() const; bool IsPVRChannelGroup() const; @@ -633,6 +610,7 @@ public: void LoadEmbeddedCue(); bool HasCueDocument() const; bool LoadTracksFromCueDocument(CFileItemList& scannedItems); + private: /*! \brief initialize all members of this class (not CGUIListItem members) to default values. Called from constructors, and from Reset() @@ -716,181 +694,4 @@ typedef std::map<std::string, CFileItemPtr > MAPFILEITEMS; typedef std::pair<std::string, CFileItemPtr > MAPFILEITEMSPAIR; typedef bool (*FILEITEMLISTCOMPARISONFUNC) (const CFileItemPtr &pItem1, const CFileItemPtr &pItem2); -typedef void (*FILEITEMFILLFUNC) (CFileItemPtr &item); - -/*! - \brief Represents a list of files - \sa CFileItemList, CFileItem - */ -class CFileItemList : public CFileItem -{ -public: - enum CACHE_TYPE { CACHE_NEVER = 0, CACHE_IF_SLOW, CACHE_ALWAYS }; - - CFileItemList(); - explicit CFileItemList(const std::string& strPath); - ~CFileItemList() override; - void Archive(CArchive& ar) override; - CFileItemPtr operator[] (int iItem); - const CFileItemPtr operator[] (int iItem) const; - CFileItemPtr operator[] (const std::string& strPath); - const CFileItemPtr operator[] (const std::string& strPath) const; - void Clear(); - void ClearItems(); - void Add(CFileItemPtr item); - void Add(CFileItem&& item); - void AddFront(const CFileItemPtr &pItem, int itemPosition); - void Remove(CFileItem* pItem); - void Remove(int iItem); - CFileItemPtr Get(int iItem) const; - const VECFILEITEMS& GetList() const { return m_items; } - CFileItemPtr Get(const std::string& strPath) const; - int Size() const; - bool IsEmpty() const; - void Append(const CFileItemList& itemlist); - void Assign(const CFileItemList& itemlist, bool append = false); - bool Copy (const CFileItemList& item, bool copyItems = true); - void Reserve(size_t iCount); - void Sort(SortBy sortBy, SortOrder sortOrder, SortAttribute sortAttributes = SortAttributeNone); - /* \brief Sorts the items based on the given sorting options - - In contrast to Sort (see above) this does not change the internal - state by storing the sorting method and order used and therefore - will always execute the sorting even if the list of items has - already been sorted with the same options before. - */ - void Sort(SortDescription sortDescription); - void Randomize(); - void FillInDefaultIcons(); - int GetFolderCount() const; - int GetFileCount() const; - int GetSelectedCount() const; - int GetObjectCount() const; - void FilterCueItems(); - void RemoveExtensions(); - void SetIgnoreURLOptions(bool ignoreURLOptions); - void SetFastLookup(bool fastLookup); - bool Contains(const std::string& fileName) const; - bool GetFastLookup() const { return m_fastLookup; } - - /*! \brief stack a CFileItemList - By default we stack all items (files and folders) in a CFileItemList - \param stackFiles whether to stack all items or just collapse folders (defaults to true) - \sa StackFiles,StackFolders - */ - void Stack(bool stackFiles = true); - - SortOrder GetSortOrder() const { return m_sortDescription.sortOrder; } - SortBy GetSortMethod() const { return m_sortDescription.sortBy; } - void SetSortOrder(SortOrder sortOrder) { m_sortDescription.sortOrder = sortOrder; } - void SetSortMethod(SortBy sortBy) { m_sortDescription.sortBy = sortBy; } - - /*! \brief load a CFileItemList out of the cache - - The file list may be cached based on which window we're viewing in, as different - windows will be listing different portions of the same URL (eg viewing music files - versus viewing video files) - - \param windowID id of the window that's loading this list (defaults to 0) - \return true if we loaded from the cache, false otherwise. - \sa Save,RemoveDiscCache - */ - bool Load(int windowID = 0); - - /*! \brief save a CFileItemList to the cache - - The file list may be cached based on which window we're viewing in, as different - windows will be listing different portions of the same URL (eg viewing music files - versus viewing video files) - - \param windowID id of the window that's saving this list (defaults to 0) - \return true if successful, false otherwise. - \sa Load,RemoveDiscCache - */ - bool Save(int windowID = 0); - void SetCacheToDisc(CACHE_TYPE cacheToDisc) { m_cacheToDisc = cacheToDisc; } - bool CacheToDiscAlways() const { return m_cacheToDisc == CACHE_ALWAYS; } - bool CacheToDiscIfSlow() const { return m_cacheToDisc == CACHE_IF_SLOW; } - /*! \brief remove a previously cached CFileItemList from the cache - - The file list may be cached based on which window we're viewing in, as different - windows will be listing different portions of the same URL (eg viewing music files - versus viewing video files) - - \param windowID id of the window whose cache we which to remove (defaults to 0) - \sa Save,Load - */ - void RemoveDiscCache(int windowID = 0) const; - void RemoveDiscCache(const std::string& cachefile) const; - void RemoveDiscCacheCRC(const std::string& crc) const; - bool AlwaysCache() const; - - void Swap(unsigned int item1, unsigned int item2); - - /*! \brief Update an item in the item list - \param item the new item, which we match based on path to an existing item in the list - \return true if the item exists in the list (and was thus updated), false otherwise. - */ - bool UpdateItem(const CFileItem *item); - - void AddSortMethod(SortBy sortBy, int buttonLabel, const LABEL_MASKS &labelMasks, SortAttribute sortAttributes = SortAttributeNone); - void AddSortMethod(SortBy sortBy, SortAttribute sortAttributes, int buttonLabel, const LABEL_MASKS &labelMasks); - void AddSortMethod(SortDescription sortDescription, int buttonLabel, const LABEL_MASKS &labelMasks); - bool HasSortDetails() const { return m_sortDetails.size() != 0; } - const std::vector<GUIViewSortDetails> &GetSortDetails() const { return m_sortDetails; } - - /*! \brief Specify whether this list should be sorted with folders separate from files - By default we sort with folders listed (and sorted separately) except for those sort modes - which should be explicitly sorted with folders interleaved with files (eg SORT_METHOD_FILES). - With this set the folder state will be ignored, allowing folders and files to sort interleaved. - \param sort whether to ignore the folder state. - */ - void SetSortIgnoreFolders(bool sort) { m_sortIgnoreFolders = sort; } - bool GetReplaceListing() const { return m_replaceListing; } - void SetReplaceListing(bool replace); - void SetContent(const std::string& content) { m_content = content; } - const std::string& GetContent() const { return m_content; } - - void ClearSortState(); - - VECFILEITEMS::iterator begin() { return m_items.begin(); } - VECFILEITEMS::iterator end() { return m_items.end(); } - VECFILEITEMS::iterator erase(VECFILEITEMS::iterator first, VECFILEITEMS::iterator last); - 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.cbegin(); } - VECFILEITEMS::const_iterator cend() const { return m_items.cend(); } - std::reverse_iterator<VECFILEITEMS::const_iterator> rbegin() const { return m_items.rbegin(); } - std::reverse_iterator<VECFILEITEMS::const_iterator> rend() const { return m_items.rend(); } - -private: - void Sort(FILEITEMLISTCOMPARISONFUNC func); - void FillSortFields(FILEITEMFILLFUNC func); - std::string GetDiscFileCache(int windowID) const; - - /*! - \brief stack files in a CFileItemList - \sa Stack - */ - void StackFiles(); - - /*! - \brief stack folders in a CFileItemList - \sa Stack - */ - void StackFolders(); - - VECFILEITEMS m_items; - MAPFILEITEMS m_map; - bool m_ignoreURLOptions = false; - bool m_fastLookup = false; - SortDescription m_sortDescription; - bool m_sortIgnoreFolders = false; - CACHE_TYPE m_cacheToDisc = CACHE_IF_SLOW; - bool m_replaceListing = false; - std::string m_content; - - std::vector<GUIViewSortDetails> m_sortDetails; - - mutable CCriticalSection m_lock; -}; +typedef void (*FILEITEMFILLFUNC)(CFileItemPtr& item); diff --git a/xbmc/FileItemList.cpp b/xbmc/FileItemList.cpp new file mode 100644 index 0000000000..0ba0abbc8c --- /dev/null +++ b/xbmc/FileItemList.cpp @@ -0,0 +1,1174 @@ +/* + * 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 "FileItemList.h" + +#include "CueDocument.h" +#include "ServiceBroker.h" +#include "URL.h" +#include "filesystem/Directory.h" +#include "filesystem/File.h" +#include "filesystem/MusicDatabaseDirectory.h" +#include "filesystem/StackDirectory.h" +#include "filesystem/VideoDatabaseDirectory.h" +#include "settings/AdvancedSettings.h" +#include "settings/Settings.h" +#include "settings/SettingsComponent.h" +#include "utils/Archive.h" +#include "utils/Crc32.h" +#include "utils/FileExtensionProvider.h" +#include "utils/Random.h" +#include "utils/RegExp.h" +#include "utils/URIUtils.h" +#include "utils/log.h" +#include "video/VideoFileItemClassify.h" +#include "video/VideoUtils.h" + +#include <algorithm> + +using namespace KODI; +using namespace XFILE; + +CFileItemList::CFileItemList() : CFileItem("", true) +{ +} + +CFileItemList::CFileItemList(const std::string& strPath) : CFileItem(strPath, true) +{ +} + +CFileItemList::~CFileItemList() +{ + Clear(); +} + +CFileItemPtr CFileItemList::operator[](int iItem) +{ + return Get(iItem); +} + +const CFileItemPtr CFileItemList::operator[](int iItem) const +{ + return Get(iItem); +} + +CFileItemPtr CFileItemList::operator[](const std::string& strPath) +{ + return Get(strPath); +} + +const CFileItemPtr CFileItemList::operator[](const std::string& strPath) const +{ + return Get(strPath); +} + +void CFileItemList::SetIgnoreURLOptions(bool ignoreURLOptions) +{ + m_ignoreURLOptions = ignoreURLOptions; + + if (m_fastLookup) + { + m_fastLookup = false; // Force SetFastlookup to clear map + SetFastLookup(true); // and regenerate map + } +} + +void CFileItemList::SetFastLookup(bool fastLookup) +{ + std::unique_lock<CCriticalSection> lock(m_lock); + + if (fastLookup && !m_fastLookup) + { // generate the map + m_map.clear(); + for (unsigned int i = 0; i < m_items.size(); i++) + { + CFileItemPtr pItem = m_items[i]; + m_map.insert(MAPFILEITEMSPAIR(m_ignoreURLOptions ? CURL(pItem->GetPath()).GetWithoutOptions() + : pItem->GetPath(), + pItem)); + } + } + if (!fastLookup && m_fastLookup) + m_map.clear(); + m_fastLookup = fastLookup; +} + +bool CFileItemList::Contains(const std::string& fileName) const +{ + std::unique_lock<CCriticalSection> lock(m_lock); + + if (m_fastLookup) + return m_map.find(m_ignoreURLOptions ? CURL(fileName).GetWithoutOptions() : fileName) != + m_map.end(); + + // slow method... + for (unsigned int i = 0; i < m_items.size(); i++) + { + const CFileItemPtr pItem = m_items[i]; + if (pItem->IsPath(m_ignoreURLOptions ? CURL(fileName).GetWithoutOptions() : fileName)) + return true; + } + return false; +} + +void CFileItemList::Clear() +{ + std::unique_lock<CCriticalSection> lock(m_lock); + + ClearItems(); + m_sortDescription.sortBy = SortByNone; + m_sortDescription.sortOrder = SortOrderNone; + m_sortDescription.sortAttributes = SortAttributeNone; + m_sortIgnoreFolders = false; + m_cacheToDisc = CACHE_IF_SLOW; + m_sortDetails.clear(); + m_replaceListing = false; + m_content.clear(); +} + +void CFileItemList::ClearItems() +{ + std::unique_lock<CCriticalSection> lock(m_lock); + // make sure we free the memory of the items (these are GUIControls which may have allocated resources) + FreeMemory(); + for (unsigned int i = 0; i < m_items.size(); i++) + { + CFileItemPtr item = m_items[i]; + item->FreeMemory(); + } + m_items.clear(); + m_map.clear(); +} + +void CFileItemList::Add(CFileItemPtr pItem) +{ + std::unique_lock<CCriticalSection> lock(m_lock); + if (m_fastLookup) + m_map.insert(MAPFILEITEMSPAIR( + m_ignoreURLOptions ? CURL(pItem->GetPath()).GetWithoutOptions() : pItem->GetPath(), pItem)); + m_items.emplace_back(std::move(pItem)); +} + +void CFileItemList::Add(CFileItem&& item) +{ + std::unique_lock<CCriticalSection> lock(m_lock); + auto ptr = std::make_shared<CFileItem>(std::move(item)); + if (m_fastLookup) + m_map.insert(MAPFILEITEMSPAIR( + m_ignoreURLOptions ? CURL(ptr->GetPath()).GetWithoutOptions() : ptr->GetPath(), ptr)); + m_items.emplace_back(std::move(ptr)); +} + +void CFileItemList::AddFront(const CFileItemPtr& pItem, int itemPosition) +{ + std::unique_lock<CCriticalSection> lock(m_lock); + + if (itemPosition >= 0) + { + m_items.insert(m_items.begin() + itemPosition, pItem); + } + else + { + m_items.insert(m_items.begin() + (m_items.size() + itemPosition), pItem); + } + if (m_fastLookup) + { + m_map.insert(MAPFILEITEMSPAIR( + m_ignoreURLOptions ? CURL(pItem->GetPath()).GetWithoutOptions() : pItem->GetPath(), pItem)); + } +} + +void CFileItemList::Remove(CFileItem* pItem) +{ + std::unique_lock<CCriticalSection> lock(m_lock); + + for (IVECFILEITEMS it = m_items.begin(); it != m_items.end(); ++it) + { + if (pItem == it->get()) + { + m_items.erase(it); + if (m_fastLookup) + { + m_map.erase(m_ignoreURLOptions ? CURL(pItem->GetPath()).GetWithoutOptions() + : pItem->GetPath()); + } + break; + } + } +} + +VECFILEITEMS::iterator CFileItemList::erase(VECFILEITEMS::iterator first, + VECFILEITEMS::iterator last) +{ + std::unique_lock<CCriticalSection> lock(m_lock); + return m_items.erase(first, last); +} + +void CFileItemList::Remove(int iItem) +{ + std::unique_lock<CCriticalSection> lock(m_lock); + + if (iItem >= 0 && iItem < Size()) + { + CFileItemPtr pItem = *(m_items.begin() + iItem); + if (m_fastLookup) + { + m_map.erase(m_ignoreURLOptions ? CURL(pItem->GetPath()).GetWithoutOptions() + : pItem->GetPath()); + } + m_items.erase(m_items.begin() + iItem); + } +} + +void CFileItemList::Append(const CFileItemList& itemlist) +{ + std::unique_lock<CCriticalSection> lock(m_lock); + + for (int i = 0; i < itemlist.Size(); ++i) + Add(itemlist[i]); +} + +void CFileItemList::Assign(const CFileItemList& itemlist, bool append) +{ + std::unique_lock<CCriticalSection> lock(m_lock); + if (!append) + Clear(); + Append(itemlist); + SetPath(itemlist.GetPath()); + SetLabel(itemlist.GetLabel()); + m_sortDetails = itemlist.m_sortDetails; + m_sortDescription = itemlist.m_sortDescription; + m_replaceListing = itemlist.m_replaceListing; + m_content = itemlist.m_content; + m_mapProperties = itemlist.m_mapProperties; + m_cacheToDisc = itemlist.m_cacheToDisc; +} + +bool CFileItemList::Copy(const CFileItemList& items, bool copyItems /* = true */) +{ + // assign all CFileItem parts + *static_cast<CFileItem*>(this) = static_cast<const CFileItem&>(items); + + // assign the rest of the CFileItemList properties + m_replaceListing = items.m_replaceListing; + m_content = items.m_content; + m_mapProperties = items.m_mapProperties; + m_cacheToDisc = items.m_cacheToDisc; + m_sortDetails = items.m_sortDetails; + m_sortDescription = items.m_sortDescription; + m_sortIgnoreFolders = items.m_sortIgnoreFolders; + + if (copyItems) + { + // make a copy of each item + for (int i = 0; i < items.Size(); i++) + { + CFileItemPtr newItem(new CFileItem(*items[i])); + Add(newItem); + } + } + + return true; +} + +CFileItemPtr CFileItemList::Get(int iItem) const +{ + std::unique_lock<CCriticalSection> lock(m_lock); + + if (iItem > -1 && iItem < (int)m_items.size()) + return m_items[iItem]; + + return CFileItemPtr(); +} + +CFileItemPtr CFileItemList::Get(const std::string& strPath) const +{ + std::unique_lock<CCriticalSection> lock(m_lock); + + if (m_fastLookup) + { + MAPFILEITEMS::const_iterator it = + m_map.find(m_ignoreURLOptions ? CURL(strPath).GetWithoutOptions() : strPath); + if (it != m_map.end()) + return it->second; + + return CFileItemPtr(); + } + // slow method... + for (unsigned int i = 0; i < m_items.size(); i++) + { + CFileItemPtr pItem = m_items[i]; + if (pItem->IsPath(m_ignoreURLOptions ? CURL(strPath).GetWithoutOptions() : strPath)) + return pItem; + } + + return CFileItemPtr(); +} + +int CFileItemList::Size() const +{ + std::unique_lock<CCriticalSection> lock(m_lock); + return (int)m_items.size(); +} + +bool CFileItemList::IsEmpty() const +{ + std::unique_lock<CCriticalSection> lock(m_lock); + return m_items.empty(); +} + +void CFileItemList::Reserve(size_t iCount) +{ + std::unique_lock<CCriticalSection> lock(m_lock); + m_items.reserve(iCount); +} + +void CFileItemList::Sort(FILEITEMLISTCOMPARISONFUNC func) +{ + std::unique_lock<CCriticalSection> lock(m_lock); + std::stable_sort(m_items.begin(), m_items.end(), func); +} + +void CFileItemList::FillSortFields(FILEITEMFILLFUNC func) +{ + std::unique_lock<CCriticalSection> lock(m_lock); + std::for_each(m_items.begin(), m_items.end(), func); +} + +void CFileItemList::Sort(SortBy sortBy, + SortOrder sortOrder, + SortAttribute sortAttributes /* = SortAttributeNone */) +{ + if (sortBy == SortByNone || + (m_sortDescription.sortBy == sortBy && m_sortDescription.sortOrder == sortOrder && + m_sortDescription.sortAttributes == sortAttributes)) + return; + + SortDescription sorting; + sorting.sortBy = sortBy; + sorting.sortOrder = sortOrder; + sorting.sortAttributes = sortAttributes; + + Sort(sorting); + m_sortDescription = sorting; +} + +void CFileItemList::Sort(SortDescription sortDescription) +{ + if (sortDescription.sortBy == SortByFile || sortDescription.sortBy == SortBySortTitle || + sortDescription.sortBy == SortByOriginalTitle || sortDescription.sortBy == SortByDateAdded || + sortDescription.sortBy == SortByRating || sortDescription.sortBy == SortByYear || + sortDescription.sortBy == SortByPlaylistOrder || sortDescription.sortBy == SortByLastPlayed || + sortDescription.sortBy == SortByPlaycount) + sortDescription.sortAttributes = + (SortAttribute)((int)sortDescription.sortAttributes | SortAttributeIgnoreFolders); + + if (sortDescription.sortBy == SortByNone || + (m_sortDescription.sortBy == sortDescription.sortBy && + m_sortDescription.sortOrder == sortDescription.sortOrder && + m_sortDescription.sortAttributes == sortDescription.sortAttributes)) + return; + + if (m_sortIgnoreFolders) + sortDescription.sortAttributes = + (SortAttribute)((int)sortDescription.sortAttributes | SortAttributeIgnoreFolders); + + const Fields fields = SortUtils::GetFieldsForSorting(sortDescription.sortBy); + SortItems sortItems((size_t)Size()); + for (int index = 0; index < Size(); index++) + { + sortItems[index] = std::make_shared<SortItem>(); + m_items[index]->ToSortable(*sortItems[index], fields); + (*sortItems[index])[FieldId] = index; + } + + // do the sorting + SortUtils::Sort(sortDescription, sortItems); + + // apply the new order to the existing CFileItems + VECFILEITEMS sortedFileItems; + sortedFileItems.reserve(Size()); + for (SortItems::const_iterator it = sortItems.begin(); it != sortItems.end(); ++it) + { + CFileItemPtr item = m_items[(int)(*it)->at(FieldId).asInteger()]; + // Set the sort label in the CFileItem + item->SetSortLabel((*it)->at(FieldSort).asWideString()); + + sortedFileItems.push_back(item); + } + + // replace the current list with the re-ordered one + m_items = std::move(sortedFileItems); +} + +void CFileItemList::Randomize() +{ + std::unique_lock<CCriticalSection> lock(m_lock); + KODI::UTILS::RandomShuffle(m_items.begin(), m_items.end()); +} + +void CFileItemList::Archive(CArchive& ar) +{ + std::unique_lock<CCriticalSection> lock(m_lock); + if (ar.IsStoring()) + { + CFileItem::Archive(ar); + + int i = 0; + if (!m_items.empty() && m_items[0]->IsParentFolder()) + i = 1; + + ar << (int)(m_items.size() - i); + + ar << m_ignoreURLOptions; + + ar << m_fastLookup; + + ar << (int)m_sortDescription.sortBy; + ar << (int)m_sortDescription.sortOrder; + ar << (int)m_sortDescription.sortAttributes; + ar << m_sortIgnoreFolders; + ar << (int)m_cacheToDisc; + + ar << (int)m_sortDetails.size(); + for (unsigned int j = 0; j < m_sortDetails.size(); ++j) + { + const GUIViewSortDetails& details = m_sortDetails[j]; + ar << (int)details.m_sortDescription.sortBy; + ar << (int)details.m_sortDescription.sortOrder; + ar << (int)details.m_sortDescription.sortAttributes; + ar << details.m_buttonLabel; + ar << details.m_labelMasks.m_strLabelFile; + ar << details.m_labelMasks.m_strLabelFolder; + ar << details.m_labelMasks.m_strLabel2File; + ar << details.m_labelMasks.m_strLabel2Folder; + } + + ar << m_content; + + for (; i < (int)m_items.size(); ++i) + { + CFileItemPtr pItem = m_items[i]; + ar << *pItem; + } + } + else + { + CFileItemPtr pParent; + if (!IsEmpty()) + { + CFileItemPtr pItem = m_items[0]; + if (pItem->IsParentFolder()) + pParent = std::make_shared<CFileItem>(*pItem); + } + + SetIgnoreURLOptions(false); + SetFastLookup(false); + Clear(); + + CFileItem::Archive(ar); + + int iSize = 0; + ar >> iSize; + if (iSize <= 0) + return; + + if (pParent) + { + m_items.reserve(iSize + 1); + m_items.push_back(pParent); + } + else + m_items.reserve(iSize); + + bool ignoreURLOptions = false; + ar >> ignoreURLOptions; + + bool fastLookup = false; + ar >> fastLookup; + + int tempint; + ar >> tempint; + m_sortDescription.sortBy = (SortBy)tempint; + ar >> tempint; + m_sortDescription.sortOrder = (SortOrder)tempint; + ar >> tempint; + m_sortDescription.sortAttributes = (SortAttribute)tempint; + ar >> m_sortIgnoreFolders; + ar >> tempint; + m_cacheToDisc = CACHE_TYPE(tempint); + + unsigned int detailSize = 0; + ar >> detailSize; + for (unsigned int j = 0; j < detailSize; ++j) + { + GUIViewSortDetails details; + ar >> tempint; + details.m_sortDescription.sortBy = (SortBy)tempint; + ar >> tempint; + details.m_sortDescription.sortOrder = (SortOrder)tempint; + ar >> tempint; + details.m_sortDescription.sortAttributes = (SortAttribute)tempint; + ar >> details.m_buttonLabel; + ar >> details.m_labelMasks.m_strLabelFile; + ar >> details.m_labelMasks.m_strLabelFolder; + ar >> details.m_labelMasks.m_strLabel2File; + ar >> details.m_labelMasks.m_strLabel2Folder; + m_sortDetails.push_back(details); + } + + ar >> m_content; + + for (int i = 0; i < iSize; ++i) + { + CFileItemPtr pItem(new CFileItem); + ar >> *pItem; + Add(pItem); + } + + SetIgnoreURLOptions(ignoreURLOptions); + SetFastLookup(fastLookup); + } +} + +void CFileItemList::FillInDefaultIcons() +{ + std::unique_lock<CCriticalSection> lock(m_lock); + for (int i = 0; i < (int)m_items.size(); ++i) + { + CFileItemPtr pItem = m_items[i]; + pItem->FillInDefaultIcon(); + } +} + +int CFileItemList::GetFolderCount() const +{ + std::unique_lock<CCriticalSection> lock(m_lock); + int nFolderCount = 0; + for (int i = 0; i < (int)m_items.size(); i++) + { + CFileItemPtr pItem = m_items[i]; + if (pItem->m_bIsFolder) + nFolderCount++; + } + + return nFolderCount; +} + +int CFileItemList::GetObjectCount() const +{ + std::unique_lock<CCriticalSection> lock(m_lock); + + int numObjects = (int)m_items.size(); + if (numObjects && m_items[0]->IsParentFolder()) + numObjects--; + + return numObjects; +} + +int CFileItemList::GetFileCount() const +{ + std::unique_lock<CCriticalSection> lock(m_lock); + int nFileCount = 0; + for (int i = 0; i < (int)m_items.size(); i++) + { + CFileItemPtr pItem = m_items[i]; + if (!pItem->m_bIsFolder) + nFileCount++; + } + + return nFileCount; +} + +int CFileItemList::GetSelectedCount() const +{ + std::unique_lock<CCriticalSection> lock(m_lock); + int count = 0; + for (int i = 0; i < (int)m_items.size(); i++) + { + CFileItemPtr pItem = m_items[i]; + if (pItem->IsSelected()) + count++; + } + + return count; +} + +void CFileItemList::FilterCueItems() +{ + std::unique_lock<CCriticalSection> lock(m_lock); + // Handle .CUE sheet files... + std::vector<std::string> itemstodelete; + for (int i = 0; i < (int)m_items.size(); i++) + { + CFileItemPtr pItem = m_items[i]; + if (!pItem->m_bIsFolder) + { // see if it's a .CUE sheet + if (pItem->IsCUESheet()) + { + CCueDocumentPtr cuesheet(new CCueDocument); + if (cuesheet->ParseFile(pItem->GetPath())) + { + std::vector<std::string> MediaFileVec; + cuesheet->GetMediaFiles(MediaFileVec); + + // queue the cue sheet and the underlying media file for deletion + for (std::vector<std::string>::iterator itMedia = MediaFileVec.begin(); + itMedia != MediaFileVec.end(); ++itMedia) + { + std::string strMediaFile = *itMedia; + std::string fileFromCue = + strMediaFile; // save the file from the cue we're matching against, + // as we're going to search for others here... + bool bFoundMediaFile = CFile::Exists(strMediaFile); + if (!bFoundMediaFile) + { + // try file in same dir, not matching case... + if (Contains(strMediaFile)) + { + bFoundMediaFile = true; + } + else + { + // try removing the .cue extension... + strMediaFile = pItem->GetPath(); + URIUtils::RemoveExtension(strMediaFile); + CFileItem item(strMediaFile, false); + if (item.IsAudio() && Contains(strMediaFile)) + { + bFoundMediaFile = true; + } + else + { // try replacing the extension with one of our allowed ones. + std::vector<std::string> extensions = StringUtils::Split( + CServiceBroker::GetFileExtensionProvider().GetMusicExtensions(), "|"); + for (std::vector<std::string>::const_iterator i = extensions.begin(); + i != extensions.end(); ++i) + { + strMediaFile = URIUtils::ReplaceExtension(pItem->GetPath(), *i); + CFileItem item(strMediaFile, false); + if (!item.IsCUESheet() && !item.IsPlayList() && Contains(strMediaFile)) + { + bFoundMediaFile = true; + break; + } + } + } + } + } + if (bFoundMediaFile) + { + cuesheet->UpdateMediaFile(fileFromCue, strMediaFile); + // apply CUE for later processing + for (int j = 0; j < (int)m_items.size(); j++) + { + CFileItemPtr pItem = m_items[j]; + if (StringUtils::CompareNoCase(pItem->GetPath(), strMediaFile) == 0) + pItem->SetCueDocument(cuesheet); + } + } + } + } + itemstodelete.push_back(pItem->GetPath()); + } + } + } + // now delete the .CUE files. + for (int i = 0; i < (int)itemstodelete.size(); i++) + { + for (int j = 0; j < (int)m_items.size(); j++) + { + CFileItemPtr pItem = m_items[j]; + if (StringUtils::CompareNoCase(pItem->GetPath(), itemstodelete[i]) == 0) + { // delete this item + m_items.erase(m_items.begin() + j); + break; + } + } + } +} + +// Remove the extensions from the filenames +void CFileItemList::RemoveExtensions() +{ + std::unique_lock<CCriticalSection> lock(m_lock); + for (int i = 0; i < Size(); ++i) + m_items[i]->RemoveExtension(); +} + +void CFileItemList::Stack(bool stackFiles /* = true */) +{ + std::unique_lock<CCriticalSection> lock(m_lock); + + // not allowed here + if (IsVirtualDirectoryRoot() || IsLiveTV() || IsSourcesPath() || IsLibraryFolder()) + return; + + SetProperty("isstacked", true); + + // items needs to be sorted for stuff below to work properly + Sort(SortByLabel, SortOrderAscending); + + StackFolders(); + + if (stackFiles) + StackFiles(); +} + +void CFileItemList::StackFolders() +{ + // Precompile our REs + VECCREGEXP folderRegExps; + CRegExp folderRegExp(true, CRegExp::autoUtf8); + const std::vector<std::string>& strFolderRegExps = + CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_folderStackRegExps; + + std::vector<std::string>::const_iterator strExpression = strFolderRegExps.begin(); + while (strExpression != strFolderRegExps.end()) + { + if (!folderRegExp.RegComp(*strExpression)) + CLog::Log(LOGERROR, "{}: Invalid folder stack RegExp:'{}'", __FUNCTION__, + strExpression->c_str()); + else + folderRegExps.push_back(folderRegExp); + + ++strExpression; + } + + if (!folderRegExp.IsCompiled()) + { + CLog::Log(LOGDEBUG, "{}: No stack expressions available. Skipping folder stacking", + __FUNCTION__); + return; + } + + // stack folders + for (int i = 0; i < Size(); i++) + { + CFileItemPtr item = Get(i); + // combined the folder checks + if (item->m_bIsFolder) + { + // only check known fast sources? + // NOTES: + // 1. rars and zips may be on slow sources? is this supposed to be allowed? + if (!item->IsRemote() || item->IsSmb() || item->IsNfs() || + URIUtils::IsInRAR(item->GetPath()) || URIUtils::IsInZIP(item->GetPath()) || + URIUtils::IsOnLAN(item->GetPath())) + { + // stack cd# folders if contains only a single video file + + bool bMatch(false); + + VECCREGEXP::iterator expr = folderRegExps.begin(); + while (!bMatch && expr != folderRegExps.end()) + { + //CLog::Log(LOGDEBUG,"{}: Running expression {} on {}", __FUNCTION__, expr->GetPattern(), item->GetLabel()); + bMatch = (expr->RegFind(item->GetLabel().c_str()) != -1); + if (bMatch) + { + CFileItemList items; + CDirectory::GetDirectory( + item->GetPath(), items, + CServiceBroker::GetFileExtensionProvider().GetVideoExtensions(), DIR_FLAG_DEFAULTS); + // optimized to only traverse listing once by checking for filecount + // and recording last file item for later use + int nFiles = 0; + int index = -1; + for (int j = 0; j < items.Size(); j++) + { + if (!items[j]->m_bIsFolder) + { + nFiles++; + index = j; + } + + if (nFiles > 1) + break; + } + + if (nFiles == 1) + *item = *items[index]; + } + ++expr; + } + + // check for dvd folders + if (!bMatch) + { + std::string dvdPath = VIDEO_UTILS::GetOpticalMediaPath(*item); + + if (!dvdPath.empty()) + { + // NOTE: should this be done for the CD# folders too? + item->m_bIsFolder = false; + item->SetPath(dvdPath); + item->SetLabel2(""); + item->SetLabelPreformatted(true); + m_sortDescription.sortBy = SortByNone; /* sorting is now broken */ + } + } + } + } + } +} + +void CFileItemList::StackFiles() +{ + // Precompile our REs + VECCREGEXP stackRegExps; + CRegExp tmpRegExp(true, CRegExp::autoUtf8); + const std::vector<std::string>& strStackRegExps = + CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_videoStackRegExps; + std::vector<std::string>::const_iterator strRegExp = strStackRegExps.begin(); + while (strRegExp != strStackRegExps.end()) + { + if (tmpRegExp.RegComp(*strRegExp)) + { + if (tmpRegExp.GetCaptureTotal() == 4) + stackRegExps.push_back(tmpRegExp); + else + CLog::Log(LOGERROR, "Invalid video stack RE ({}). Must have 4 captures.", *strRegExp); + } + ++strRegExp; + } + + // now stack the files, some of which may be from the previous stack iteration + int i = 0; + while (i < Size()) + { + CFileItemPtr item1 = Get(i); + + // skip folders, nfo files, playlists + if (item1->m_bIsFolder || item1->IsParentFolder() || item1->IsNFO() || item1->IsPlayList()) + { + // increment index + i++; + continue; + } + + int64_t size = 0; + size_t offset = 0; + std::string stackName; + std::string file1; + std::string filePath; + std::vector<int> stack; + VECCREGEXP::iterator expr = stackRegExps.begin(); + + URIUtils::Split(item1->GetPath(), filePath, file1); + if (URIUtils::HasEncodedFilename(CURL(filePath))) + file1 = CURL::Decode(file1); + + int j; + while (expr != stackRegExps.end()) + { + if (expr->RegFind(file1, offset) != -1) + { + std::string Title1 = expr->GetMatch(1), Volume1 = expr->GetMatch(2), + Ignore1 = expr->GetMatch(3), Extension1 = expr->GetMatch(4); + if (offset) + Title1 = file1.substr(0, expr->GetSubStart(2)); + j = i + 1; + while (j < Size()) + { + CFileItemPtr item2 = Get(j); + + // skip folders, nfo files, playlists + if (item2->m_bIsFolder || item2->IsParentFolder() || item2->IsNFO() || + item2->IsPlayList()) + { + // increment index + j++; + continue; + } + + std::string file2, filePath2; + URIUtils::Split(item2->GetPath(), filePath2, file2); + if (URIUtils::HasEncodedFilename(CURL(filePath2))) + file2 = CURL::Decode(file2); + + if (expr->RegFind(file2, offset) != -1) + { + std::string Title2 = expr->GetMatch(1), Volume2 = expr->GetMatch(2), + Ignore2 = expr->GetMatch(3), Extension2 = expr->GetMatch(4); + if (offset) + Title2 = file2.substr(0, expr->GetSubStart(2)); + if (StringUtils::EqualsNoCase(Title1, Title2)) + { + if (!StringUtils::EqualsNoCase(Volume1, Volume2)) + { + if (StringUtils::EqualsNoCase(Ignore1, Ignore2) && + StringUtils::EqualsNoCase(Extension1, Extension2)) + { + if (stack.empty()) + { + stackName = Title1 + Ignore1 + Extension1; + stack.push_back(i); + size += item1->m_dwSize; + } + stack.push_back(j); + size += item2->m_dwSize; + } + else // Sequel + { + offset = 0; + ++expr; + break; + } + } + else if (!StringUtils::EqualsNoCase(Ignore1, + Ignore2)) // False positive, try again with offset + { + offset = expr->GetSubStart(3); + break; + } + else // Extension mismatch + { + offset = 0; + ++expr; + break; + } + } + else // Title mismatch + { + offset = 0; + ++expr; + break; + } + } + else // No match 2, next expression + { + offset = 0; + ++expr; + break; + } + j++; + } + if (j == Size()) + expr = stackRegExps.end(); + } + else // No match 1 + { + offset = 0; + ++expr; + } + if (stack.size() > 1) + { + // have a stack, remove the items and add the stacked item + // dont actually stack a multipart rar set, just remove all items but the first + std::string stackPath; + if (Get(stack[0])->IsRAR()) + stackPath = Get(stack[0])->GetPath(); + else + { + CStackDirectory dir; + stackPath = dir.ConstructStackPath(*this, stack); + } + item1->SetPath(stackPath); + // clean up list + for (unsigned k = 1; k < stack.size(); k++) + Remove(i + 1); + // item->m_bIsFolder = true; // don't treat stacked files as folders + // the label may be in a different char set from the filename (eg over smb + // the label is converted from utf8, but the filename is not) + if (!CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool( + CSettings::SETTING_FILELISTS_SHOWEXTENSIONS)) + URIUtils::RemoveExtension(stackName); + + item1->SetLabel(stackName); + item1->m_dwSize = size; + break; + } + } + i++; + } +} + +bool CFileItemList::Load(int windowID) +{ + CFile file; + auto path = GetDiscFileCache(windowID); + try + { + if (file.Open(path)) + { + CArchive ar(&file, CArchive::load); + ar >> *this; + CLog::Log(LOGDEBUG, "Loading items: {}, directory: {} sort method: {}, ascending: {}", Size(), + CURL::GetRedacted(GetPath()), m_sortDescription.sortBy, + m_sortDescription.sortOrder == SortOrderAscending ? "true" : "false"); + ar.Close(); + file.Close(); + return true; + } + } + catch (const std::out_of_range&) + { + CLog::Log(LOGERROR, "Corrupt archive: {}", CURL::GetRedacted(path)); + } + + return false; +} + +bool CFileItemList::Save(int windowID) +{ + int iSize = Size(); + if (iSize <= 0) + return false; + + CLog::Log(LOGDEBUG, "Saving fileitems [{}]", CURL::GetRedacted(GetPath())); + + CFile file; + std::string cachefile = GetDiscFileCache(windowID); + if (file.OpenForWrite(cachefile, true)) // overwrite always + { + // Before caching save simplified cache file name in every item so the cache file can be + // identifed and removed if the item is updated. List path and options (used for file + // name when list cached) can not be accurately derived from item path. + StringUtils::Replace(cachefile, "special://temp/archive_cache/", ""); + StringUtils::Replace(cachefile, ".fi", ""); + for (const auto& item : m_items) + item->SetProperty("cachefilename", cachefile); + + CArchive ar(&file, CArchive::store); + ar << *this; + CLog::Log(LOGDEBUG, " -- items: {}, sort method: {}, ascending: {}", iSize, + m_sortDescription.sortBy, + m_sortDescription.sortOrder == SortOrderAscending ? "true" : "false"); + ar.Close(); + file.Close(); + return true; + } + + return false; +} + +void CFileItemList::RemoveDiscCache(int windowID) const +{ + RemoveDiscCache(GetDiscFileCache(windowID)); +} + +void CFileItemList::RemoveDiscCache(const std::string& cacheFile) const +{ + if (CFile::Exists(cacheFile)) + { + CLog::Log(LOGDEBUG, "Clearing cached fileitems [{}]", CURL::GetRedacted(GetPath())); + CFile::Delete(cacheFile); + } +} + +void CFileItemList::RemoveDiscCacheCRC(const std::string& crc) const +{ + std::string cachefile = StringUtils::Format("special://temp/archive_cache/{}.fi", crc); + RemoveDiscCache(cachefile); +} + +std::string CFileItemList::GetDiscFileCache(int windowID) const +{ + std::string strPath(GetPath()); + URIUtils::RemoveSlashAtEnd(strPath); + + uint32_t crc = Crc32::ComputeFromLowerCase(strPath); + + if (IsCDDA() || IsOnDVD()) + return StringUtils::Format("special://temp/archive_cache/r-{:08x}.fi", crc); + + if (IsMusicDb()) + return StringUtils::Format("special://temp/archive_cache/mdb-{:08x}.fi", crc); + + if (VIDEO::IsVideoDb(*this)) + return StringUtils::Format("special://temp/archive_cache/vdb-{:08x}.fi", crc); + + if (IsSmartPlayList()) + return StringUtils::Format("special://temp/archive_cache/sp-{:08x}.fi", crc); + + if (windowID) + return StringUtils::Format("special://temp/archive_cache/{}-{:08x}.fi", windowID, crc); + + return StringUtils::Format("special://temp/archive_cache/{:08x}.fi", crc); +} + +bool CFileItemList::AlwaysCache() const +{ + // some database folders are always cached + if (IsMusicDb()) + return CMusicDatabaseDirectory::CanCache(GetPath()); + if (VIDEO::IsVideoDb(*this)) + return CVideoDatabaseDirectory::CanCache(GetPath()); + if (IsEPG()) + return true; // always cache + return false; +} + +void CFileItemList::Swap(unsigned int item1, unsigned int item2) +{ + if (item1 != item2 && item1 < m_items.size() && item2 < m_items.size()) + std::swap(m_items[item1], m_items[item2]); +} + +bool CFileItemList::UpdateItem(const CFileItem* item) +{ + if (!item) + return false; + + std::unique_lock<CCriticalSection> lock(m_lock); + for (unsigned int i = 0; i < m_items.size(); i++) + { + CFileItemPtr pItem = m_items[i]; + if (pItem->IsSamePath(item)) + { + pItem->UpdateInfo(*item); + return true; + } + } + return false; +} + +void CFileItemList::AddSortMethod(SortBy sortBy, + int buttonLabel, + const LABEL_MASKS& labelMasks, + SortAttribute sortAttributes /* = SortAttributeNone */) +{ + AddSortMethod(sortBy, sortAttributes, buttonLabel, labelMasks); +} + +void CFileItemList::AddSortMethod(SortBy sortBy, + SortAttribute sortAttributes, + int buttonLabel, + const LABEL_MASKS& labelMasks) +{ + SortDescription sorting; + sorting.sortBy = sortBy; + sorting.sortAttributes = sortAttributes; + + AddSortMethod(sorting, buttonLabel, labelMasks); +} + +void CFileItemList::AddSortMethod(SortDescription sortDescription, + int buttonLabel, + const LABEL_MASKS& labelMasks) +{ + GUIViewSortDetails sort; + sort.m_sortDescription = sortDescription; + sort.m_buttonLabel = buttonLabel; + sort.m_labelMasks = labelMasks; + + m_sortDetails.push_back(sort); +} + +void CFileItemList::SetReplaceListing(bool replace) +{ + m_replaceListing = replace; +} + +void CFileItemList::ClearSortState() +{ + m_sortDescription.sortBy = SortByNone; + m_sortDescription.sortOrder = SortOrderNone; + m_sortDescription.sortAttributes = SortAttributeNone; +} diff --git a/xbmc/FileItemList.h b/xbmc/FileItemList.h new file mode 100644 index 0000000000..5f04f179d2 --- /dev/null +++ b/xbmc/FileItemList.h @@ -0,0 +1,206 @@ +/* + * Copyright (C) 2005-2018 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 + +/*! + \file FileItemList.h + \brief + */ + +#include "FileItem.h" + +/*! + \brief Represents a list of files + \sa CFileItemList, CFileItem + */ +class CFileItemList : public CFileItem +{ +public: + enum CACHE_TYPE + { + CACHE_NEVER = 0, + CACHE_IF_SLOW, + CACHE_ALWAYS + }; + + CFileItemList(); + explicit CFileItemList(const std::string& strPath); + ~CFileItemList() override; + void Archive(CArchive& ar) override; + CFileItemPtr operator[](int iItem); + const CFileItemPtr operator[](int iItem) const; + CFileItemPtr operator[](const std::string& strPath); + const CFileItemPtr operator[](const std::string& strPath) const; + void Clear(); + void ClearItems(); + void Add(CFileItemPtr item); + void Add(CFileItem&& item); + void AddFront(const CFileItemPtr& pItem, int itemPosition); + void Remove(CFileItem* pItem); + void Remove(int iItem); + CFileItemPtr Get(int iItem) const; + const VECFILEITEMS& GetList() const { return m_items; } + CFileItemPtr Get(const std::string& strPath) const; + int Size() const; + bool IsEmpty() const; + void Append(const CFileItemList& itemlist); + void Assign(const CFileItemList& itemlist, bool append = false); + bool Copy(const CFileItemList& item, bool copyItems = true); + void Reserve(size_t iCount); + void Sort(SortBy sortBy, SortOrder sortOrder, SortAttribute sortAttributes = SortAttributeNone); + /* \brief Sorts the items based on the given sorting options + + In contrast to Sort (see above) this does not change the internal + state by storing the sorting method and order used and therefore + will always execute the sorting even if the list of items has + already been sorted with the same options before. + */ + void Sort(SortDescription sortDescription); + void Randomize(); + void FillInDefaultIcons(); + int GetFolderCount() const; + int GetFileCount() const; + int GetSelectedCount() const; + int GetObjectCount() const; + void FilterCueItems(); + void RemoveExtensions(); + void SetIgnoreURLOptions(bool ignoreURLOptions); + void SetFastLookup(bool fastLookup); + bool Contains(const std::string& fileName) const; + bool GetFastLookup() const { return m_fastLookup; } + + /*! \brief stack a CFileItemList + By default we stack all items (files and folders) in a CFileItemList + \param stackFiles whether to stack all items or just collapse folders (defaults to true) + \sa StackFiles,StackFolders + */ + void Stack(bool stackFiles = true); + + SortOrder GetSortOrder() const { return m_sortDescription.sortOrder; } + SortBy GetSortMethod() const { return m_sortDescription.sortBy; } + void SetSortOrder(SortOrder sortOrder) { m_sortDescription.sortOrder = sortOrder; } + void SetSortMethod(SortBy sortBy) { m_sortDescription.sortBy = sortBy; } + + /*! \brief load a CFileItemList out of the cache + + The file list may be cached based on which window we're viewing in, as different + windows will be listing different portions of the same URL (eg viewing music files + versus viewing video files) + + \param windowID id of the window that's loading this list (defaults to 0) + \return true if we loaded from the cache, false otherwise. + \sa Save,RemoveDiscCache + */ + bool Load(int windowID = 0); + + /*! \brief save a CFileItemList to the cache + + The file list may be cached based on which window we're viewing in, as different + windows will be listing different portions of the same URL (eg viewing music files + versus viewing video files) + + \param windowID id of the window that's saving this list (defaults to 0) + \return true if successful, false otherwise. + \sa Load,RemoveDiscCache + */ + bool Save(int windowID = 0); + void SetCacheToDisc(CACHE_TYPE cacheToDisc) { m_cacheToDisc = cacheToDisc; } + bool CacheToDiscAlways() const { return m_cacheToDisc == CACHE_ALWAYS; } + bool CacheToDiscIfSlow() const { return m_cacheToDisc == CACHE_IF_SLOW; } + /*! \brief remove a previously cached CFileItemList from the cache + + The file list may be cached based on which window we're viewing in, as different + windows will be listing different portions of the same URL (eg viewing music files + versus viewing video files) + + \param windowID id of the window whose cache we which to remove (defaults to 0) + \sa Save,Load + */ + void RemoveDiscCache(int windowID = 0) const; + void RemoveDiscCache(const std::string& cachefile) const; + void RemoveDiscCacheCRC(const std::string& crc) const; + bool AlwaysCache() const; + + void Swap(unsigned int item1, unsigned int item2); + + /*! \brief Update an item in the item list + \param item the new item, which we match based on path to an existing item in the list + \return true if the item exists in the list (and was thus updated), false otherwise. + */ + bool UpdateItem(const CFileItem* item); + + void AddSortMethod(SortBy sortBy, + int buttonLabel, + const LABEL_MASKS& labelMasks, + SortAttribute sortAttributes = SortAttributeNone); + void AddSortMethod(SortBy sortBy, + SortAttribute sortAttributes, + int buttonLabel, + const LABEL_MASKS& labelMasks); + void AddSortMethod(SortDescription sortDescription, + int buttonLabel, + const LABEL_MASKS& labelMasks); + bool HasSortDetails() const { return m_sortDetails.size() != 0; } + const std::vector<GUIViewSortDetails>& GetSortDetails() const { return m_sortDetails; } + + /*! \brief Specify whether this list should be sorted with folders separate from files + By default we sort with folders listed (and sorted separately) except for those sort modes + which should be explicitly sorted with folders interleaved with files (eg SORT_METHOD_FILES). + With this set the folder state will be ignored, allowing folders and files to sort interleaved. + \param sort whether to ignore the folder state. + */ + void SetSortIgnoreFolders(bool sort) { m_sortIgnoreFolders = sort; } + bool GetReplaceListing() const { return m_replaceListing; } + void SetReplaceListing(bool replace); + void SetContent(const std::string& content) { m_content = content; } + const std::string& GetContent() const { return m_content; } + + void ClearSortState(); + + VECFILEITEMS::iterator begin() { return m_items.begin(); } + VECFILEITEMS::iterator end() { return m_items.end(); } + VECFILEITEMS::iterator erase(VECFILEITEMS::iterator first, VECFILEITEMS::iterator last); + 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.cbegin(); } + VECFILEITEMS::const_iterator cend() const { return m_items.cend(); } + std::reverse_iterator<VECFILEITEMS::const_iterator> rbegin() const { return m_items.rbegin(); } + std::reverse_iterator<VECFILEITEMS::const_iterator> rend() const { return m_items.rend(); } + +private: + void Sort(FILEITEMLISTCOMPARISONFUNC func); + void FillSortFields(FILEITEMFILLFUNC func); + std::string GetDiscFileCache(int windowID) const; + + /*! + \brief stack files in a CFileItemList + \sa Stack + */ + void StackFiles(); + + /*! + \brief stack folders in a CFileItemList + \sa Stack + */ + void StackFolders(); + + VECFILEITEMS m_items; + MAPFILEITEMS m_map; + bool m_ignoreURLOptions = false; + bool m_fastLookup = false; + SortDescription m_sortDescription; + bool m_sortIgnoreFolders = false; + CACHE_TYPE m_cacheToDisc = CACHE_IF_SLOW; + bool m_replaceListing = false; + std::string m_content; + + std::vector<GUIViewSortDetails> m_sortDetails; + + mutable CCriticalSection m_lock; +}; diff --git a/xbmc/GUIInfoManager.cpp b/xbmc/GUIInfoManager.cpp index 3725ca1c3c..5a0c79d609 100644 --- a/xbmc/GUIInfoManager.cpp +++ b/xbmc/GUIInfoManager.cpp @@ -793,18 +793,6 @@ const infomap integer_bools[] = {{ "isequal", INTEGER_IS_EQUAL }, /// @skinning_v18 **[New Infolabel]** \link Player_Icon `Player.Icon`\endlink /// <p> /// } -/// \table_row3{ <b>`Player.Cutlist`</b>, -/// \anchor Player_Cutlist -/// _string_, -/// @return The cutlist of the currently playing item as csv in the format start1\,end1\,start2\,end2\,... -/// Tokens must have values in the range from 0.0 to 100.0. end token must be less or equal than start token. -/// <p> -/// @deprecated \link Player_Cutlist `Player.Cutlist`\endlink is deprecated and will be removed in the next version. -/// <p><hr> -/// @skinning_v19 **[New Infolabel]** \link Player_Cutlist `Player.Cutlist`\endlink -/// @skinning_v20 \link Player_Cutlist `Player.Cutlist`\endlink is deprecated\, use \link Player_Cuts `Player.Cuts`\endlink instead -/// <p> -/// } /// \table_row3{ <b>`Player.Editlist`</b>, /// \anchor Player_Editlist /// _string_, @@ -919,7 +907,6 @@ const infomap player_labels[] = {{"hasmedia", PLAYER_HAS_MEDIA}, {"hasresolutions", PLAYER_HAS_RESOLUTIONS}, {"frameadvance", PLAYER_FRAMEADVANCE}, {"icon", PLAYER_ICON}, - {"cutlist", PLAYER_CUTLIST}, {"editlist", PLAYER_EDITLIST}, {"cuts", PLAYER_CUTS}, {"scenemarkers", PLAYER_SCENE_MARKERS}, @@ -1763,14 +1750,15 @@ const infomap weather[] = {{ "isfetched", WEATHER_IS_FETCHED }, /// _string_, /// @return Locale-specific information depending on the requested type. /// @param type - Can be one of the following: -/// - <b>timezonecountry</b> The country name for the current time zone. -/// - <b>timezone</b> The full timezone name with country and optional region. /// - <b>region</b> The currently selected region name within the selected language ( \link System_Language `System.Language` \endlink). /// - <b>iso</b> The country code of the currently selected region as specified in <a href="https://kodi.wiki/view/Language_support#What_is_langinfo.xml">langinfo.xml</a>. /// <p><hr> /// @skinning_v21 **[New Infolabel]** \link System_Locale /// `System.Locale(type)`\endlink /// <p> +/// @skinning_v22 **[Removed options]** `timezonecountry` and `timezone` from \link System_Locale +/// `System.Locale(type)`\endlink +/// <p> /// } /// \table_row3{ <b>`System.ProfileName`</b>, /// \anchor System_ProfileName @@ -9835,6 +9823,11 @@ const infomap slideshow[] = {{ "ispaused", SLIDESHOW_ISPAUSED /// \page modules__infolabels_boolean_conditions /// \section modules_rm_infolabels_booleans Additional revision history for Infolabels and Boolean Conditions /// <hr> +/// \subsection modules_rm_infolabels_booleans_v22 Kodi v22 +/// @skinning_v22 **[Removed Infolabels]** The following infolabels have been removed: +/// - `Player.Cutlist` - Please use \link Player_Editlist `Player.EditList`\endlink for the EDL list and \link Player_Cuts `Player.Cuts`\endlink for the cut markers +/// +/// <hr> /// \subsection modules_rm_infolabels_booleans_v21 Kodi v21 (Omega) /// @skinning_v21 **[Removed Infolabels]** The following infolabels have been removed: /// - `Network.DHCPAddress` - this info did not return any meaningful value (always an empty string) @@ -10227,15 +10220,7 @@ int CGUIInfoManager::TranslateSingleString(const std::string &strCondition, bool return AddMultiInfo(CGUIInfo(SYSTEM_IDLE_TIME, atoi(param.c_str()))); else if (prop.name == "locale") { - if (param == "timezonecountry") - { - return SYSTEM_LOCALE_TIMEZONECOUNTRY; - } - else if (param == "timezone") - { - return SYSTEM_LOCALE_TIMEZONE; - } - else if (param == "region") + if (param == "region") { return SYSTEM_LOCALE_REGION; } diff --git a/xbmc/NfoFile.cpp b/xbmc/NfoFile.cpp index 2a11da2c17..f74d0efd20 100644 --- a/xbmc/NfoFile.cpp +++ b/xbmc/NfoFile.cpp @@ -12,6 +12,7 @@ #include "NfoFile.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "addons/AddonManager.h" #include "addons/AddonSystemSettings.h" diff --git a/xbmc/PartyModeManager.cpp b/xbmc/PartyModeManager.cpp index 829a9191f5..dd74bad29e 100644 --- a/xbmc/PartyModeManager.cpp +++ b/xbmc/PartyModeManager.cpp @@ -9,6 +9,7 @@ #include "PartyModeManager.h" #include "FileItem.h" +#include "FileItemList.h" #include "GUIUserMessages.h" #include "PlayListPlayer.h" #include "ServiceBroker.h" diff --git a/xbmc/PlayListPlayer.cpp b/xbmc/PlayListPlayer.cpp index 950a0cd97d..feaa7f4fb4 100644 --- a/xbmc/PlayListPlayer.cpp +++ b/xbmc/PlayListPlayer.cpp @@ -9,6 +9,7 @@ #include "PlayListPlayer.h" #include "FileItem.h" +#include "FileItemList.h" #include "GUIUserMessages.h" #include "PartyModeManager.h" #include "ServiceBroker.h" @@ -37,9 +38,11 @@ #include "utils/Variant.h" #include "utils/log.h" #include "video/VideoDatabase.h" +#include "video/VideoFileItemClassify.h" using namespace PLAYLIST; using namespace KODI::MESSAGING; +using namespace KODI::VIDEO; CPlayListPlayer::CPlayListPlayer(void) { @@ -266,7 +269,7 @@ bool CPlayListPlayer::PlayItemIdx(int itemIdx) bool CPlayListPlayer::Play(const CFileItemPtr& pItem, const std::string& player) { Id playlistId; - bool isVideo{pItem->IsVideo()}; + bool isVideo{IsVideo(*pItem)}; bool isAudio{pItem->IsAudio()}; if (isAudio && !isVideo) @@ -331,7 +334,7 @@ bool CPlayListPlayer::Play(int iSong, m_iCurrentSong = iSong; CFileItemPtr item = playlist[m_iCurrentSong]; - if (item->IsVideoDb() && !item->HasVideoInfoTag()) + if (IsVideoDb(*item) && !item->HasVideoInfoTag()) *(item->GetVideoInfoTag()) = XFILE::CVideoDatabaseFile::GetVideoTag(CURL(item->GetDynPath())); playlist.SetPlayed(true); @@ -949,7 +952,7 @@ void PLAYLIST::CPlayListPlayer::OnApplicationMessage(KODI::MESSAGING::ThreadMess Id playlistId = TYPE_MUSIC; for (int i = 0; i < list->Size(); i++) { - if ((*list)[i]->IsVideo()) + if (IsVideo(*list->Get(i))) { playlistId = TYPE_VIDEO; break; @@ -967,7 +970,7 @@ void PLAYLIST::CPlayListPlayer::OnApplicationMessage(KODI::MESSAGING::ThreadMess { return; } - if (item->IsAudio() || item->IsVideo()) + if (item->IsAudio() || IsVideo(*item)) Play(item, pMsg->strParam); else g_application.PlayMedia(*item, pMsg->strParam, playlistId); diff --git a/xbmc/URL.cpp b/xbmc/URL.cpp index 99b661e36f..073d1104e0 100644 --- a/xbmc/URL.cpp +++ b/xbmc/URL.cpp @@ -7,15 +7,17 @@ */ #include "URL.h" -#include "utils/log.h" -#include "utils/URIUtils.h" -#include "utils/StringUtils.h" + +#include "FileItem.h" +#include "FileItemList.h" +#include "ServiceBroker.h" #include "Util.h" #include "filesystem/File.h" -#include "FileItem.h" #include "filesystem/StackDirectory.h" #include "network/Network.h" -#include "ServiceBroker.h" +#include "utils/StringUtils.h" +#include "utils/URIUtils.h" +#include "utils/log.h" #ifndef TARGET_POSIX #include <sys\stat.h> #endif diff --git a/xbmc/Util.cpp b/xbmc/Util.cpp index a4ee52645c..dea659099c 100644 --- a/xbmc/Util.cpp +++ b/xbmc/Util.cpp @@ -7,6 +7,7 @@ */ #include "network/Network.h" +#include "video/VideoFileItemClassify.h" #if defined(TARGET_DARWIN) #include <sys/param.h> #include <mach-o/dyld.h> @@ -92,6 +93,7 @@ using namespace MEDIA_DETECT; using namespace XFILE; using namespace PLAYLIST; using KODI::UTILITY::CDigest; +using namespace KODI::VIDEO; #if !defined(TARGET_WINDOWS) unsigned int CUtil::s_randomSeed = time(NULL); @@ -2054,10 +2056,8 @@ void CUtil::ScanForExternalSubtitles(const std::string& strMovie, std::vector<st auto start = std::chrono::steady_clock::now(); CFileItem item(strMovie, false); - if ((item.IsInternetStream() && !URIUtils::IsOnLAN(item.GetDynPath())) - || item.IsPlayList() - || item.IsLiveTV() - || !item.IsVideo()) + if ((item.IsInternetStream() && !URIUtils::IsOnLAN(item.GetDynPath())) || item.IsPlayList() || + item.IsLiveTV() || !IsVideo(item)) return; CLog::Log(LOGDEBUG, "{}: Searching for subtitles...", __FUNCTION__); @@ -2346,11 +2346,8 @@ std::string CUtil::GetVobSubIdxFromSub(const std::string& vobSub) void CUtil::ScanForExternalAudio(const std::string& videoPath, std::vector<std::string>& vecAudio) { CFileItem item(videoPath, false); - if ( item.IsInternetStream() - || item.IsPlayList() - || item.IsLiveTV() - || item.IsPVR() - || !item.IsVideo()) + if (item.IsInternetStream() || item.IsPlayList() || item.IsLiveTV() || item.IsPVR() || + !IsVideo(item)) return; std::string strBasePath; diff --git a/xbmc/addons/AddonManager.cpp b/xbmc/addons/AddonManager.cpp index 2922b66974..7c69b56425 100644 --- a/xbmc/addons/AddonManager.cpp +++ b/xbmc/addons/AddonManager.cpp @@ -10,6 +10,7 @@ #include "CompileInfo.h" #include "FileItem.h" +#include "FileItemList.h" #include "LangInfo.h" #include "ServiceBroker.h" #include "addons/AddonBuilder.h" diff --git a/xbmc/addons/AddonManager.h b/xbmc/addons/AddonManager.h index 10668125c0..fd7ee70f66 100644 --- a/xbmc/addons/AddonManager.h +++ b/xbmc/addons/AddonManager.h @@ -16,6 +16,7 @@ #include <mutex> #include <set> #include <string> +#include <utility> #include <vector> namespace ADDON @@ -37,10 +38,10 @@ using ADDON_INFO_LIST = std::map<std::string, AddonInfoPtr>; class IAddon; using AddonPtr = std::shared_ptr<IAddon>; +using AddonWithUpdate = std::pair<std::shared_ptr<IAddon>, std::shared_ptr<IAddon>>; using VECADDONS = std::vector<AddonPtr>; struct AddonEvent; -struct AddonWithUpdate; struct DependencyInfo; struct RepositoryDirInfo; diff --git a/xbmc/addons/AddonRepos.cpp b/xbmc/addons/AddonRepos.cpp index 5455ca4487..362f051b97 100644 --- a/xbmc/addons/AddonRepos.cpp +++ b/xbmc/addons/AddonRepos.cpp @@ -122,20 +122,16 @@ bool CAddonRepos::LoadAddonsFromDatabase(const std::string& addonId, { if (m_addonMgr.IsCompatible(addon)) { - m_addonsByRepoMap[addon->Origin()].insert({addon->ID(), addon}); + m_addonsByRepoMap[addon->Origin()].emplace(addon->ID(), addon); } } - for (const auto& repo : m_addonsByRepoMap) + for (const auto& [repoId, addonsPerRepo] : m_addonsByRepoMap) { - CLog::LogFC(LOGDEBUG, LOGADDONS, "{} - {} addon(s) loaded", repo.first, repo.second.size()); + CLog::LogFC(LOGDEBUG, LOGADDONS, "{} - {} addon(s) loaded", repoId, addonsPerRepo.size()); - const auto& addonsPerRepo = repo.second; - - for (const auto& addonMapEntry : addonsPerRepo) + for (const auto& [addonId, addonToAdd] : addonsPerRepo) { - const auto& addonToAdd = addonMapEntry.second; - if (IsFromOfficialRepo(addonToAdd, CheckAddonPath::CHOICE_YES)) { AddAddonIfLatest(addonToAdd, m_latestOfficialVersions); @@ -146,7 +142,7 @@ bool CAddonRepos::LoadAddonsFromDatabase(const std::string& addonId, } // add to latestVersionsByRepo - AddAddonIfLatest(repo.first, addonToAdd, m_latestVersionsByRepo); + AddAddonIfLatest(repoId, addonToAdd, m_latestVersionsByRepo); } } @@ -156,8 +152,8 @@ bool CAddonRepos::LoadAddonsFromDatabase(const std::string& addonId, void CAddonRepos::AddAddonIfLatest(const std::shared_ptr<IAddon>& addonToAdd, std::map<std::string, std::shared_ptr<IAddon>>& map) const { - const auto& latestKnown = map.find(addonToAdd->ID()); - if (latestKnown == map.end() || addonToAdd->Version() > latestKnown->second->Version()) + const auto latestKnownIt = map.find(addonToAdd->ID()); + if (latestKnownIt == map.end() || addonToAdd->Version() > latestKnownIt->second->Version()) map[addonToAdd->ID()] = addonToAdd; } @@ -166,21 +162,23 @@ void CAddonRepos::AddAddonIfLatest( const std::shared_ptr<IAddon>& addonToAdd, std::map<std::string, std::map<std::string, std::shared_ptr<IAddon>>>& map) const { - const auto& latestVersionByRepo = map.find(repoId); + bool doInsert{true}; - if (latestVersionByRepo == map.end()) // repo not found - { - map[repoId].insert({addonToAdd->ID(), addonToAdd}); - } - else + const auto latestVersionByRepoIt = map.find(repoId); + if (latestVersionByRepoIt != map.end()) // we already have this repository in the outer map { - const auto& latestVersionEntryByRepo = latestVersionByRepo->second; - const auto& latestKnown = latestVersionEntryByRepo.find(addonToAdd->ID()); + const auto& latestVersionEntryByRepo = latestVersionByRepoIt->second; + const auto latestKnownIt = latestVersionEntryByRepo.find(addonToAdd->ID()); - if (latestKnown == latestVersionEntryByRepo.end() || - addonToAdd->Version() > latestKnown->second->Version()) - map[repoId][addonToAdd->ID()] = addonToAdd; + if (latestKnownIt != latestVersionEntryByRepo.end() && + addonToAdd->Version() <= latestKnownIt->second->Version()) + { + doInsert = false; + } } + + if (doInsert) + map[repoId][addonToAdd->ID()] = addonToAdd; } void CAddonRepos::BuildUpdateOrOutdatedList(const std::vector<std::shared_ptr<IAddon>>& installed, @@ -212,7 +210,7 @@ void CAddonRepos::BuildAddonsWithUpdateList( { if (DoAddonUpdateCheck(addon, update)) { - addonsWithUpdate.insert({addon->ID(), {addon, update}}); + addonsWithUpdate.try_emplace(addon->ID(), addon, update); } } } @@ -253,10 +251,10 @@ bool CAddonRepos::DoAddonUpdateCheck(const std::shared_ptr<IAddon>& addon, else { // ...we check for updates in the origin repo only - const auto& repoEntry = m_latestVersionsByRepo.find(addon->Origin()); - if (repoEntry != m_latestVersionsByRepo.end()) + const auto repoEntryIt = m_latestVersionsByRepo.find(addon->Origin()); + if (repoEntryIt != m_latestVersionsByRepo.end()) { - if (!FindAddonAndCheckForUpdate(addon, repoEntry->second, update)) + if (!FindAddonAndCheckForUpdate(addon, repoEntryIt->second, update)) { return false; } @@ -280,14 +278,14 @@ bool CAddonRepos::FindAddonAndCheckForUpdate( const std::map<std::string, std::shared_ptr<IAddon>>& map, std::shared_ptr<IAddon>& update) const { - const auto& remote = map.find(addonToCheck->ID()); - if (remote != map.end()) // is addon in the desired map? + const auto remoteIt = map.find(addonToCheck->ID()); + if (remoteIt != map.end()) // is addon in the desired map? { - if ((remote->second->Version() > addonToCheck->Version()) || + if ((remoteIt->second->Version() > addonToCheck->Version()) || m_addonMgr.IsAddonDisabledWithReason(addonToCheck->ID(), AddonDisabledReason::INCOMPATIBLE)) { // return addon update - update = remote->second; + update = remoteIt->second; return true; // update found } } @@ -300,10 +298,10 @@ bool CAddonRepos::GetLatestVersionByMap(const std::string& addonId, const std::map<std::string, std::shared_ptr<IAddon>>& map, std::shared_ptr<IAddon>& addon) const { - const auto& remote = map.find(addonId); - if (remote != map.end()) // is addon in the desired map? + const auto remoteIt = map.find(addonId); + if (remoteIt != map.end()) // is addon in the desired map? { - addon = remote->second; + addon = remoteIt->second; return true; } @@ -356,14 +354,15 @@ void CAddonRepos::GetLatestAddonVersions(std::vector<std::shared_ptr<IAddon>>& a // then we insert private addon versions if they don't exist in the official map // or installation from ANY_REPOSITORY is allowed and the private version is higher - for (const auto& privateVersion : m_latestPrivateVersions) + for (const auto& [privateVersionId, privateVersion] : m_latestPrivateVersions) { - const auto& officialVersion = m_latestOfficialVersions.find(privateVersion.first); - if (officialVersion == m_latestOfficialVersions.end() || + const auto officialVersionIt = m_latestOfficialVersions.find(privateVersionId); + + if (officialVersionIt == m_latestOfficialVersions.end() || (updateMode == AddonRepoUpdateMode::ANY_REPOSITORY && - privateVersion.second->Version() > officialVersion->second->Version())) + privateVersion->Version() > officialVersionIt->second->Version())) { - addonList.emplace_back(privateVersion.second); + addonList.emplace_back(privateVersion); } } } @@ -390,18 +389,18 @@ void CAddonRepos::GetLatestAddonVersionsFromAllRepos( // so we need to filter them out if (std::none_of(officialRepoInfos.begin(), officialRepoInfos.end(), - [&](const ADDON::RepoInfo& officialRepo) { - return repo.first == officialRepo.m_repoId; - })) + [&repo](const ADDON::RepoInfo& officialRepo) + { return repo.first == officialRepo.m_repoId; })) { - for (const auto& latestAddon : repo.second) + for (const auto& [latestAddonId, latestAddon] : repo.second) { - const auto& officialVersion = m_latestOfficialVersions.find(latestAddon.first); - if (officialVersion == m_latestOfficialVersions.end() || + const auto officialVersionIt = m_latestOfficialVersions.find(latestAddonId); + + if (officialVersionIt == m_latestOfficialVersions.end() || (updateMode == AddonRepoUpdateMode::ANY_REPOSITORY && - latestAddon.second->Version() > officialVersion->second->Version())) + latestAddon->Version() > officialVersionIt->second->Version())) { - addonList.emplace_back(latestAddon.second); + addonList.emplace_back(latestAddon); } } } @@ -469,10 +468,10 @@ bool CAddonRepos::FindDependencyByParentRepo(const std::string& dependsId, const std::string& parentRepoId, std::shared_ptr<IAddon>& dependencyToInstall) const { - const auto& repoEntry = m_latestVersionsByRepo.find(parentRepoId); - if (repoEntry != m_latestVersionsByRepo.end()) + const auto repoEntryIt = m_latestVersionsByRepo.find(parentRepoId); + if (repoEntryIt != m_latestVersionsByRepo.end()) { - if (GetLatestVersionByMap(dependsId, repoEntry->second, dependencyToInstall)) + if (GetLatestVersionByMap(dependsId, repoEntryIt->second, dependencyToInstall)) return true; } diff --git a/xbmc/addons/AddonRepos.h b/xbmc/addons/AddonRepos.h index bb9be3473c..4284674f01 100644 --- a/xbmc/addons/AddonRepos.h +++ b/xbmc/addons/AddonRepos.h @@ -13,6 +13,7 @@ #include <map> #include <memory> #include <string> +#include <utility> #include <vector> namespace ADDON @@ -30,14 +31,7 @@ enum class CheckAddonPath CHOICE_NO = false, }; -/** - * Struct - CAddonWithUpdate - */ -struct AddonWithUpdate -{ - std::shared_ptr<IAddon> m_installed; - std::shared_ptr<IAddon> m_update; -}; +using AddonWithUpdate = std::pair<std::shared_ptr<IAddon>, std::shared_ptr<IAddon>>; /** * Class - CAddonRepos diff --git a/xbmc/addons/FilesystemInstaller.cpp b/xbmc/addons/FilesystemInstaller.cpp index 0f7b32de64..f6dd80131a 100644 --- a/xbmc/addons/FilesystemInstaller.cpp +++ b/xbmc/addons/FilesystemInstaller.cpp @@ -8,6 +8,7 @@ #include "FilesystemInstaller.h" #include "FileItem.h" +#include "FileItemList.h" #include "filesystem/Directory.h" #include "filesystem/File.h" #include "filesystem/SpecialProtocol.h" diff --git a/xbmc/addons/Scraper.cpp b/xbmc/addons/Scraper.cpp index 66cedcb969..b759dc84e7 100644 --- a/xbmc/addons/Scraper.cpp +++ b/xbmc/addons/Scraper.cpp @@ -9,6 +9,7 @@ #include "Scraper.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "URL.h" #include "Util.h" diff --git a/xbmc/addons/Skin.cpp b/xbmc/addons/Skin.cpp index a6192d902b..746800776c 100644 --- a/xbmc/addons/Skin.cpp +++ b/xbmc/addons/Skin.cpp @@ -9,6 +9,7 @@ #include "Skin.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "Util.h" #include "addons/addoninfo/AddonType.h" diff --git a/xbmc/addons/VFSEntry.h b/xbmc/addons/VFSEntry.h index c11fca05da..414f9593af 100644 --- a/xbmc/addons/VFSEntry.h +++ b/xbmc/addons/VFSEntry.h @@ -8,6 +8,7 @@ #pragma once #include "FileItem.h" +#include "FileItemList.h" #include "addons/binary-addons/AddonDll.h" #include "addons/binary-addons/AddonInstanceHandler.h" #include "addons/kodi-dev-kit/include/kodi/addon-instance/VFS.h" diff --git a/xbmc/addons/addoninfo/AddonInfo.cpp b/xbmc/addons/addoninfo/AddonInfo.cpp index f891e73bc9..0f2f7fba5f 100644 --- a/xbmc/addons/addoninfo/AddonInfo.cpp +++ b/xbmc/addons/addoninfo/AddonInfo.cpp @@ -9,6 +9,7 @@ #include "AddonInfo.h" #include "FileItem.h" +#include "FileItemList.h" #include "LangInfo.h" #include "ServiceBroker.h" #include "addons/AddonManager.h" diff --git a/xbmc/addons/gui/GUIDialogAddonInfo.cpp b/xbmc/addons/gui/GUIDialogAddonInfo.cpp index 671e55dcf4..172af8b216 100644 --- a/xbmc/addons/gui/GUIDialogAddonInfo.cpp +++ b/xbmc/addons/gui/GUIDialogAddonInfo.cpp @@ -9,6 +9,7 @@ #include "GUIDialogAddonInfo.h" #include "FileItem.h" +#include "FileItemList.h" #include "GUIPassword.h" #include "ServiceBroker.h" #include "Util.h" diff --git a/xbmc/addons/gui/GUIDialogAddonSettings.cpp b/xbmc/addons/gui/GUIDialogAddonSettings.cpp index 4830283e4d..60cbaa2a2e 100644 --- a/xbmc/addons/gui/GUIDialogAddonSettings.cpp +++ b/xbmc/addons/gui/GUIDialogAddonSettings.cpp @@ -9,6 +9,7 @@ #include "GUIDialogAddonSettings.h" #include "FileItem.h" +#include "FileItemList.h" #include "GUIPassword.h" #include "GUIUserMessages.h" #include "ServiceBroker.h" diff --git a/xbmc/addons/gui/GUIViewStateAddonBrowser.cpp b/xbmc/addons/gui/GUIViewStateAddonBrowser.cpp index 5504f33ecd..7ecb3cbcf8 100644 --- a/xbmc/addons/gui/GUIViewStateAddonBrowser.cpp +++ b/xbmc/addons/gui/GUIViewStateAddonBrowser.cpp @@ -9,6 +9,7 @@ #include "GUIViewStateAddonBrowser.h" #include "FileItem.h" +#include "FileItemList.h" #include "filesystem/File.h" #include "guilib/WindowIDs.h" #include "utils/StringUtils.h" diff --git a/xbmc/addons/gui/GUIWindowAddonBrowser.cpp b/xbmc/addons/gui/GUIWindowAddonBrowser.cpp index f130bacad1..880e784835 100644 --- a/xbmc/addons/gui/GUIWindowAddonBrowser.cpp +++ b/xbmc/addons/gui/GUIWindowAddonBrowser.cpp @@ -10,6 +10,7 @@ #include "ContextMenuManager.h" #include "FileItem.h" +#include "FileItemList.h" #include "GUIDialogAddonInfo.h" #include "GUIUserMessages.h" #include "LangInfo.h" diff --git a/xbmc/addons/interfaces/Filesystem.cpp b/xbmc/addons/interfaces/Filesystem.cpp index c063b48fd6..9f22b67ecc 100644 --- a/xbmc/addons/interfaces/Filesystem.cpp +++ b/xbmc/addons/interfaces/Filesystem.cpp @@ -9,6 +9,7 @@ #include "Filesystem.h" #include "FileItem.h" +#include "FileItemList.h" #include "Util.h" #include "addons/binary-addons/AddonDll.h" #include "filesystem/CurlFile.h" diff --git a/xbmc/addons/interfaces/gui/Window.cpp b/xbmc/addons/interfaces/gui/Window.cpp index b817d443a3..831b89fdbd 100644 --- a/xbmc/addons/interfaces/gui/Window.cpp +++ b/xbmc/addons/interfaces/gui/Window.cpp @@ -9,6 +9,7 @@ #include "addons/kodi-dev-kit/include/kodi/gui/Window.h" #include "FileItem.h" +#include "FileItemList.h" #include "GUITranslator.h" #include "General.h" #include "ServiceBroker.h" diff --git a/xbmc/addons/settings/AddonSettings.cpp b/xbmc/addons/settings/AddonSettings.cpp index 2fc9f26fae..b3bd9bb124 100644 --- a/xbmc/addons/settings/AddonSettings.cpp +++ b/xbmc/addons/settings/AddonSettings.cpp @@ -9,6 +9,7 @@ #include "AddonSettings.h" #include "FileItem.h" +#include "FileItemList.h" #include "GUIInfoManager.h" #include "LangInfo.h" #include "ServiceBroker.h" diff --git a/xbmc/application/AppParamParser.cpp b/xbmc/application/AppParamParser.cpp index ca9cd2acef..20b54e7869 100644 --- a/xbmc/application/AppParamParser.cpp +++ b/xbmc/application/AppParamParser.cpp @@ -10,6 +10,7 @@ #include "CompileInfo.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "application/AppParams.h" #include "utils/StringUtils.h" diff --git a/xbmc/application/AppParams.cpp b/xbmc/application/AppParams.cpp index 97c09e3934..8b174467b4 100644 --- a/xbmc/application/AppParams.cpp +++ b/xbmc/application/AppParams.cpp @@ -8,12 +8,14 @@ #include "AppParams.h" -#include "FileItem.h" +#include "FileItemList.h" CAppParams::CAppParams() : m_playlist(std::make_unique<CFileItemList>()) { } +CAppParams::~CAppParams() = default; + void CAppParams::SetRawArgs(std::vector<std::string> args) { m_rawArgs = std::move(args); diff --git a/xbmc/application/AppParams.h b/xbmc/application/AppParams.h index 6999249719..12d7aba2b9 100644 --- a/xbmc/application/AppParams.h +++ b/xbmc/application/AppParams.h @@ -21,7 +21,7 @@ class CAppParams { public: CAppParams(); - virtual ~CAppParams() = default; + virtual ~CAppParams(); int GetLogLevel() const { return m_logLevel; } void SetLogLevel(int logLevel) { m_logLevel = logLevel; } diff --git a/xbmc/application/Application.cpp b/xbmc/application/Application.cpp index 3413a18c4c..6541a22759 100644 --- a/xbmc/application/Application.cpp +++ b/xbmc/application/Application.cpp @@ -60,6 +60,7 @@ #include "filesystem/DirectoryFactory.h" #include "filesystem/DllLibCurl.h" #include "filesystem/File.h" +#include "video/VideoFileItemClassify.h" #ifdef HAS_FILESYSTEM_NFS #include "filesystem/NFSFile.h" #endif @@ -198,6 +199,7 @@ using namespace PVR; using namespace PERIPHERALS; using namespace KODI; using namespace KODI::MESSAGING; +using namespace KODI::VIDEO; using namespace ActiveAE; using namespace XbmcThreads; @@ -2301,11 +2303,11 @@ bool CApplication::PlayFile(CFileItem item, const std::string& player, bool bRes m_nextPlaylistItem = -1; stackHelper->Clear(); - if (item.IsVideo()) + if (IsVideo(item)) CUtil::ClearSubtitles(); } - if (item.IsDiscStub()) + if (IsDiscStub(item)) { return CServiceBroker::GetMediaManager().playStubFile(item); } @@ -2346,7 +2348,7 @@ bool CApplication::PlayFile(CFileItem item, const std::string& player, bool bRes { // the following code block is only applicable when bRestart is false OR to ISO stacks - if (item.IsVideo()) + if (IsVideo(item)) { // open the d/b and retrieve the bookmarks for the current movie CVideoDatabase dbs; @@ -2354,7 +2356,7 @@ bool CApplication::PlayFile(CFileItem item, const std::string& player, bool bRes std::string path = item.GetPath(); std::string videoInfoTagPath(item.GetVideoInfoTag()->m_strFileNameAndPath); - if (videoInfoTagPath.find("removable://") == 0 || item.IsVideoDb()) + if (videoInfoTagPath.find("removable://") == 0 || IsVideoDb(item)) path = videoInfoTagPath; // Note that we need to load the tag from database also if the item already has a tag, @@ -2424,7 +2426,7 @@ bool CApplication::PlayFile(CFileItem item, const std::string& player, bool bRes // a disc image might be Blu-Ray disc if (!(options.startpercent > 0.0 || options.starttime > 0.0) && - (item.IsBDFile() || item.IsDiscImage())) + (IsBDFile(item) || item.IsDiscImage())) { // No video selection when using external or remote players (they handle it if supported) const bool isSimpleMenuAllowed = [&]() @@ -2458,7 +2460,7 @@ bool CApplication::PlayFile(CFileItem item, const std::string& player, bool bRes CSettings::SETTING_MUSICFILES_SELECTACTION) && !CMediaSettings::GetInstance().DoesMediaStartWindowed(); } - else if (item.IsVideo() && playlistId == PLAYLIST::TYPE_VIDEO && + else if (IsVideo(item) && playlistId == PLAYLIST::TYPE_VIDEO && CServiceBroker::GetPlaylistPlayer().GetPlaylist(playlistId).size() > 1) { // playing from a playlist by the looks // don't switch to fullscreen if we are not playing the first item... @@ -2783,9 +2785,9 @@ bool CApplication::OnMessage(CGUIMessage& message) bool bNothingToQueue = false; const auto appPlayer = GetComponent<CApplicationPlayer>(); - if (!file.IsVideo() && appPlayer->IsPlayingVideo()) + if (!IsVideo(file) && appPlayer->IsPlayingVideo()) bNothingToQueue = true; - else if ((!file.IsAudio() || file.IsVideo()) && appPlayer->IsPlayingAudio()) + else if ((!file.IsAudio() || IsVideo(file)) && appPlayer->IsPlayingAudio()) bNothingToQueue = true; if (bNothingToQueue) @@ -3053,7 +3055,7 @@ bool CApplication::ExecuteXBMCAction(std::string actionStr, } else #endif - if (item.IsAudio() || item.IsVideo() || item.IsGame()) + if (item.IsAudio() || IsVideo(item) || item.IsGame()) { // an audio or video file PlayFile(item, ""); } @@ -3174,10 +3176,8 @@ void CApplication::ProcessSlow() // Temporarily pause pausable jobs when viewing video/picture int currentWindow = CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow(); - if (CurrentFileItem().IsVideo() || - CurrentFileItem().IsPicture() || - currentWindow == WINDOW_FULLSCREEN_VIDEO || - currentWindow == WINDOW_FULLSCREEN_GAME || + if (IsVideo(CurrentFileItem()) || CurrentFileItem().IsPicture() || + currentWindow == WINDOW_FULLSCREEN_VIDEO || currentWindow == WINDOW_FULLSCREEN_GAME || currentWindow == WINDOW_SLIDESHOW) { CServiceBroker::GetJobManager()->PauseJobs(); diff --git a/xbmc/application/ApplicationPlayer.cpp b/xbmc/application/ApplicationPlayer.cpp index b517c78fd0..d088f46b6a 100644 --- a/xbmc/application/ApplicationPlayer.cpp +++ b/xbmc/application/ApplicationPlayer.cpp @@ -17,9 +17,11 @@ #include "guilib/GUIWindowManager.h" #include "settings/AdvancedSettings.h" #include "settings/SettingsComponent.h" +#include "video/VideoFileItemClassify.h" #include <mutex> +using namespace KODI; using namespace std::chrono_literals; std::shared_ptr<const IPlayer> CApplicationPlayer::GetInternal() const @@ -99,7 +101,7 @@ bool CApplicationPlayer::OpenFile(const CFileItem& item, const CPlayerOptions& o { bool needToClose = false; - if (item.IsDiscImage() || item.IsDVDFile()) + if (item.IsDiscImage() || VIDEO::IsDVDFile(item)) needToClose = true; if (player->m_name != newPlayer) diff --git a/xbmc/application/ApplicationPlayerCallback.cpp b/xbmc/application/ApplicationPlayerCallback.cpp index ed36a27e18..637f67ddcc 100644 --- a/xbmc/application/ApplicationPlayerCallback.cpp +++ b/xbmc/application/ApplicationPlayerCallback.cpp @@ -32,10 +32,13 @@ #include "utils/URIUtils.h" #include "utils/log.h" #include "video/VideoDatabase.h" +#include "video/VideoFileItemClassify.h" #include "video/VideoInfoTag.h" #include <memory> +using namespace KODI::VIDEO; + CApplicationPlayerCallback::CApplicationPlayerCallback() { } @@ -54,7 +57,7 @@ void CApplicationPlayerCallback::OnPlayBackStarted(const CFileItem& file) std::shared_ptr<CFileItem> itemCurrentFile; // check if VideoPlayer should set file item stream details from its current streams - const bool isBlu_dvd_image_or_stream = (URIUtils::IsBluray(file.GetPath()) || file.IsDVDFile() || + const bool isBlu_dvd_image_or_stream = (URIUtils::IsBluray(file.GetPath()) || IsDVDFile(file) || file.IsDiscImage() || file.IsInternetStream()); const bool hasNoStreamDetails = @@ -80,7 +83,7 @@ void CApplicationPlayerCallback::OnPlayBackStarted(const CFileItem& file) * This should speed up player startup for files on internet filesystems (eg. webdav) and * increase performance on low powered systems (Atom/ARM). */ - if (file.IsVideo() || file.IsGame()) + if (IsVideo(file) || file.IsGame()) { CServiceBroker::GetJobManager()->PauseJobs(); } @@ -128,7 +131,7 @@ void CApplicationPlayerCallback::OnPlayerCloseFile(const CFileItem& file, if ((fileItem.IsAudio() && advancedSettings->m_audioPlayCountMinimumPercent > 0 && percent >= advancedSettings->m_audioPlayCountMinimumPercent) || - (fileItem.IsVideo() && advancedSettings->m_videoPlayCountMinimumPercent > 0 && + (IsVideo(fileItem) && advancedSettings->m_videoPlayCountMinimumPercent > 0 && percent >= advancedSettings->m_videoPlayCountMinimumPercent)) { playCountUpdate = true; diff --git a/xbmc/application/ApplicationSkinHandling.cpp b/xbmc/application/ApplicationSkinHandling.cpp index bf73f14363..5f916060ac 100644 --- a/xbmc/application/ApplicationSkinHandling.cpp +++ b/xbmc/application/ApplicationSkinHandling.cpp @@ -9,6 +9,7 @@ #include "ApplicationSkinHandling.h" #include "FileItem.h" +#include "FileItemList.h" #include "GUIInfoManager.h" #include "GUILargeTextureManager.h" #include "GUIUserMessages.h" diff --git a/xbmc/application/ApplicationStackHelper.cpp b/xbmc/application/ApplicationStackHelper.cpp index 27b7808a2a..515c52b5aa 100644 --- a/xbmc/application/ApplicationStackHelper.cpp +++ b/xbmc/application/ApplicationStackHelper.cpp @@ -9,6 +9,7 @@ #include "ApplicationStackHelper.h" #include "FileItem.h" +#include "FileItemList.h" #include "URL.h" #include "Util.h" #include "cores/VideoPlayer/DVDFileInfo.h" diff --git a/xbmc/cdrip/CDDARipper.cpp b/xbmc/cdrip/CDDARipper.cpp index 41dcc8d5d6..b174c8bbd3 100644 --- a/xbmc/cdrip/CDDARipper.cpp +++ b/xbmc/cdrip/CDDARipper.cpp @@ -10,6 +10,7 @@ #include "CDDARipJob.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "Util.h" #include "addons/AddonManager.h" diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp index 908b087b98..528822ddbb 100644 --- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp +++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp @@ -1313,7 +1313,7 @@ void CActiveAE::Configure(AEAudioFormat *desiredFmt) format.m_streamInfo.m_type = CAEStreamInfo::STREAM_TYPE_AC3; format.m_streamInfo.m_channels = 2; format.m_streamInfo.m_sampleRate = 48000; - format.m_streamInfo.m_ac3FrameSize = m_encoderFormat.m_frames; + format.m_streamInfo.m_frameSize = m_encoderFormat.m_frames; //! @todo implement if (m_encoderBuffers && initSink) { diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResampleFFMPEG.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResampleFFMPEG.cpp index 02c8eb1b83..e897cbd3ea 100644 --- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResampleFFMPEG.cpp +++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResampleFFMPEG.cpp @@ -148,21 +148,21 @@ bool CActiveAEResampleFFMPEG::Init(SampleConfig dstConfig, SampleConfig srcConfi AVChannel outChan = av_channel_layout_channel_from_index(&dstChLayout, out); switch (outChan) { - case AV_CH_FRONT_LEFT: - case AV_CH_BACK_LEFT: - case AV_CH_SIDE_LEFT: + case AV_CHAN_FRONT_LEFT: + case AV_CHAN_BACK_LEFT: + case AV_CHAN_SIDE_LEFT: m_rematrix[out][0] = 1.0; break; - case AV_CH_FRONT_RIGHT: - case AV_CH_BACK_RIGHT: - case AV_CH_SIDE_RIGHT: + case AV_CHAN_FRONT_RIGHT: + case AV_CHAN_BACK_RIGHT: + case AV_CHAN_SIDE_RIGHT: m_rematrix[out][1] = 1.0; break; - case AV_CH_FRONT_CENTER: + case AV_CHAN_FRONT_CENTER: m_rematrix[out][0] = 0.5; m_rematrix[out][1] = 0.5; break; - case AV_CH_LOW_FREQUENCY: + case AV_CHAN_LOW_FREQUENCY: m_rematrix[out][0] = 0.5; m_rematrix[out][1] = 0.5; break; diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkAUDIOTRACK.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkAUDIOTRACK.cpp index 6da358f792..e0a42c62a4 100644 --- a/xbmc/cores/AudioEngine/Sinks/AESinkAUDIOTRACK.cpp +++ b/xbmc/cores/AudioEngine/Sinks/AESinkAUDIOTRACK.cpp @@ -162,7 +162,8 @@ int CAESinkAUDIOTRACK::AudioTrackWrite(char* audioData, int offsetInBytes, int s if (m_floatbuf.size() != (sizeInBytes - offsetInBytes) / sizeof(float)) m_floatbuf.resize((sizeInBytes - offsetInBytes) / sizeof(float)); memcpy(m_floatbuf.data(), audioData + offsetInBytes, sizeInBytes - offsetInBytes); - written = m_at_jni->write(m_floatbuf, 0, (sizeInBytes - offsetInBytes) / sizeof(float), CJNIAudioTrack::WRITE_BLOCKING); + written = m_at_jni->write(m_floatbuf, 0, (sizeInBytes - offsetInBytes) / sizeof(float), + CJNIAudioTrack::WRITE_BLOCKING); written *= sizeof(float); } else if (m_jniAudioFormat == CJNIAudioFormat::ENCODING_IEC61937) @@ -170,10 +171,8 @@ int CAESinkAUDIOTRACK::AudioTrackWrite(char* audioData, int offsetInBytes, int s if (m_shortbuf.size() != (sizeInBytes - offsetInBytes) / sizeof(int16_t)) m_shortbuf.resize((sizeInBytes - offsetInBytes) / sizeof(int16_t)); memcpy(m_shortbuf.data(), audioData + offsetInBytes, sizeInBytes - offsetInBytes); - if (CJNIBase::GetSDKVersion() >= 23) - written = m_at_jni->write(m_shortbuf, 0, (sizeInBytes - offsetInBytes) / sizeof(int16_t), CJNIAudioTrack::WRITE_BLOCKING); - else - written = m_at_jni->write(m_shortbuf, 0, (sizeInBytes - offsetInBytes) / sizeof(int16_t)); + written = m_at_jni->write(m_shortbuf, 0, (sizeInBytes - offsetInBytes) / sizeof(int16_t), + CJNIAudioTrack::WRITE_BLOCKING); written *= sizeof(uint16_t); } else @@ -181,10 +180,8 @@ int CAESinkAUDIOTRACK::AudioTrackWrite(char* audioData, int offsetInBytes, int s if (static_cast<int>(m_charbuf.size()) != (sizeInBytes - offsetInBytes)) m_charbuf.resize(sizeInBytes - offsetInBytes); memcpy(m_charbuf.data(), audioData + offsetInBytes, sizeInBytes - offsetInBytes); - if (CJNIBase::GetSDKVersion() >= 23) - written = m_at_jni->write(m_charbuf, 0, sizeInBytes - offsetInBytes, CJNIAudioTrack::WRITE_BLOCKING); - else - written = m_at_jni->write(m_charbuf, 0, sizeInBytes - offsetInBytes); + written = + m_at_jni->write(m_charbuf, 0, sizeInBytes - offsetInBytes, CJNIAudioTrack::WRITE_BLOCKING); } return written; @@ -461,15 +458,15 @@ bool CAESinkAUDIOTRACK::Initialize(AEAudioFormat &format, std::string &device) rawlength_in_seconds = 8 * m_format.m_streamInfo.GetDuration() / 1000; break; case CAEStreamInfo::STREAM_TYPE_AC3: - ac3FrameSize = m_format.m_streamInfo.m_ac3FrameSize; - if (ac3FrameSize == 0) - ac3FrameSize = 1536; // fallback if not set, e.g. Transcoding - m_min_buffer_size = std::max(m_min_buffer_size * 3, ac3FrameSize * 8); - m_format.m_frames = m_min_buffer_size; - multiplier = m_min_buffer_size / ac3FrameSize; // int division is wanted - rawlength_in_seconds = multiplier * m_format.m_streamInfo.GetDuration() / 1000; + ac3FrameSize = m_format.m_streamInfo.m_frameSize; + if (ac3FrameSize == 0) + ac3FrameSize = 1536; // fallback if not set, e.g. Transcoding + m_min_buffer_size = std::max(m_min_buffer_size * 3, ac3FrameSize * 8); + m_format.m_frames = m_min_buffer_size; + multiplier = m_min_buffer_size / ac3FrameSize; // int division is wanted + rawlength_in_seconds = multiplier * m_format.m_streamInfo.GetDuration() / 1000; break; - // EAC3 is currently not supported + // EAC3 is currently not supported case CAEStreamInfo::STREAM_TYPE_EAC3: m_min_buffer_size = 2 * 10752; // least common multiple of 1792 and 1536 m_format.m_frames = m_min_buffer_size; // needs testing @@ -1119,26 +1116,23 @@ void CAESinkAUDIOTRACK::UpdateAvailablePassthroughCapabilities(bool isRaw) } } - if (CJNIAudioManager::GetSDKVersion() >= 23) + if (CJNIAudioFormat::ENCODING_DTS_HD != -1) { - if (CJNIAudioFormat::ENCODING_DTS_HD != -1) + if (VerifySinkConfiguration(48000, AEChannelMapToAUDIOTRACKChannelMask(AE_CH_LAYOUT_7_1), + CJNIAudioFormat::ENCODING_DTS_HD, true)) { - if (VerifySinkConfiguration(48000, AEChannelMapToAUDIOTRACKChannelMask(AE_CH_LAYOUT_7_1), - CJNIAudioFormat::ENCODING_DTS_HD, true)) - { - CLog::Log(LOGDEBUG, "Firmware implements DTS-HD RAW"); - m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_DTSHD); - m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_DTSHD_MA); - } + CLog::Log(LOGDEBUG, "Firmware implements DTS-HD RAW"); + m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_DTSHD); + m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_DTSHD_MA); } - if (CJNIAudioFormat::ENCODING_DOLBY_TRUEHD != -1) + } + if (CJNIAudioFormat::ENCODING_DOLBY_TRUEHD != -1) + { + if (VerifySinkConfiguration(48000, AEChannelMapToAUDIOTRACKChannelMask(AE_CH_LAYOUT_7_1), + CJNIAudioFormat::ENCODING_DOLBY_TRUEHD, true)) { - if (VerifySinkConfiguration(48000, AEChannelMapToAUDIOTRACKChannelMask(AE_CH_LAYOUT_7_1), - CJNIAudioFormat::ENCODING_DOLBY_TRUEHD, true)) - { - CLog::Log(LOGDEBUG, "Firmware implements TrueHD RAW"); - m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_TRUEHD); - } + CLog::Log(LOGDEBUG, "Firmware implements TrueHD RAW"); + m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_TRUEHD); } } } @@ -1200,10 +1194,9 @@ void CAESinkAUDIOTRACK::UpdateAvailablePCMCapabilities() int encoding = CJNIAudioFormat::ENCODING_PCM_16BIT; m_sinkSupportsFloat = VerifySinkConfiguration(native_sampleRate, CJNIAudioFormat::CHANNEL_OUT_STEREO, CJNIAudioFormat::ENCODING_PCM_FLOAT); - if (CJNIAudioManager::GetSDKVersion() >= 21) - m_sinkSupportsMultiChannelFloat = - VerifySinkConfiguration(native_sampleRate, CJNIAudioFormat::CHANNEL_OUT_7POINT1_SURROUND, - CJNIAudioFormat::ENCODING_PCM_FLOAT); + m_sinkSupportsMultiChannelFloat = + VerifySinkConfiguration(native_sampleRate, CJNIAudioFormat::CHANNEL_OUT_7POINT1_SURROUND, + CJNIAudioFormat::ENCODING_PCM_FLOAT); if (m_sinkSupportsFloat) { diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkDARWINTVOS.mm b/xbmc/cores/AudioEngine/Sinks/AESinkDARWINTVOS.mm index 5d66474ca0..162b5c9650 100644 --- a/xbmc/cores/AudioEngine/Sinks/AESinkDARWINTVOS.mm +++ b/xbmc/cores/AudioEngine/Sinks/AESinkDARWINTVOS.mm @@ -784,15 +784,15 @@ bool CAESinkDARWINTVOS::Initialize(AEAudioFormat& format, std::string& device) switch (format.m_streamInfo.m_type) { case CAEStreamInfo::STREAM_TYPE_AC3: - if (!format.m_streamInfo.m_ac3FrameSize) - format.m_streamInfo.m_ac3FrameSize = 1536; - format.m_frames = format.m_streamInfo.m_ac3FrameSize; + if (!format.m_streamInfo.m_frameSize) + format.m_streamInfo.m_frameSize = 1536; + format.m_frames = format.m_streamInfo.m_frameSize; buffer_size = format.m_frames * 8; break; case CAEStreamInfo::STREAM_TYPE_EAC3: - if (!format.m_streamInfo.m_ac3FrameSize) - format.m_streamInfo.m_ac3FrameSize = 1536; - format.m_frames = format.m_streamInfo.m_ac3FrameSize; + if (!format.m_streamInfo.m_frameSize) + format.m_streamInfo.m_frameSize = 1536; + format.m_frames = format.m_streamInfo.m_frameSize; buffer_size = format.m_frames * 8; break; case CAEStreamInfo::STREAM_TYPE_DTS_512: diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkDirectSound.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkDirectSound.cpp index 4b450ec5cb..ca02e2bafa 100644 --- a/xbmc/cores/AudioEngine/Sinks/AESinkDirectSound.cpp +++ b/xbmc/cores/AudioEngine/Sinks/AESinkDirectSound.cpp @@ -218,10 +218,10 @@ bool CAESinkDirectSound::Initialize(AEAudioFormat &format, std::string &device) m_AvgBytesPerSec = wfxex.Format.nAvgBytesPerSec; - unsigned int uiFrameCount = (int)(format.m_sampleRate * 0.015); //default to 15ms chunks + const unsigned int uiFrameCount = static_cast<int>(format.m_sampleRate * 0.050); // 50ms chunks m_dwFrameSize = wfxex.Format.nBlockAlign; m_dwChunkSize = m_dwFrameSize * uiFrameCount; - m_dwBufferLen = m_dwChunkSize * 12; //180ms total buffer + m_dwBufferLen = m_dwChunkSize * 8; // 400ms total buffer // fill in the secondary sound buffer descriptor DSBUFFERDESC dsbdesc = {}; diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkStarfish.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkStarfish.cpp index 0d07b44fa3..d9c8859cc4 100644 --- a/xbmc/cores/AudioEngine/Sinks/AESinkStarfish.cpp +++ b/xbmc/cores/AudioEngine/Sinks/AESinkStarfish.cpp @@ -21,10 +21,17 @@ namespace { constexpr unsigned int STARFISH_AUDIO_BUFFERS = 8; constexpr unsigned int AC3_SYNCFRAME_SIZE = 2560; +constexpr unsigned int DTDHD_MA_MIN_SYNCFRAME_SIZE = 2012 + 2764; static constexpr auto ms_audioCodecMap = make_map<CAEStreamInfo::DataType, std::string_view>({ {CAEStreamInfo::STREAM_TYPE_AC3, "AC3"}, {CAEStreamInfo::STREAM_TYPE_EAC3, "AC3 PLUS"}, + {CAEStreamInfo::STREAM_TYPE_DTS_512, "DTS"}, + {CAEStreamInfo::STREAM_TYPE_DTS_1024, "DTS"}, + {CAEStreamInfo::STREAM_TYPE_DTS_2048, "DTS"}, + {CAEStreamInfo::STREAM_TYPE_DTSHD, "DTS"}, + {CAEStreamInfo::STREAM_TYPE_DTSHD_CORE, "DTS"}, + {CAEStreamInfo::STREAM_TYPE_DTSHD_MA, "DTS"}, }); } // namespace @@ -63,6 +70,12 @@ void CAESinkStarfish::EnumerateDevicesEx(AEDeviceInfoList& list, bool force) info.m_deviceType = AE_DEVTYPE_IEC958; info.m_streamTypes.emplace_back(CAEStreamInfo::STREAM_TYPE_AC3); info.m_streamTypes.emplace_back(CAEStreamInfo::STREAM_TYPE_EAC3); + info.m_streamTypes.emplace_back(CAEStreamInfo::STREAM_TYPE_DTS_512); + info.m_streamTypes.emplace_back(CAEStreamInfo::STREAM_TYPE_DTS_1024); + info.m_streamTypes.emplace_back(CAEStreamInfo::STREAM_TYPE_DTS_2048); + info.m_streamTypes.emplace_back(CAEStreamInfo::STREAM_TYPE_DTSHD); + info.m_streamTypes.emplace_back(CAEStreamInfo::STREAM_TYPE_DTSHD_CORE); + info.m_streamTypes.emplace_back(CAEStreamInfo::STREAM_TYPE_DTSHD_MA); info.m_sampleRates.emplace_back(32000); info.m_sampleRates.emplace_back(44100); @@ -89,8 +102,6 @@ bool CAESinkStarfish::Initialize(AEAudioFormat& format, std::string& device) } m_format.m_frameSize = 1; - format = m_format; - CVariant payload; payload["isAudioOnly"] = true; payload["mediaTransportType"] = "BUFFERSTREAM"; @@ -107,10 +118,10 @@ bool CAESinkStarfish::Initialize(AEAudioFormat& format, std::string& device) { case CAEStreamInfo::STREAM_TYPE_AC3: { - if (!format.m_streamInfo.m_ac3FrameSize) - format.m_streamInfo.m_ac3FrameSize = AC3_SYNCFRAME_SIZE; - format.m_frames = format.m_streamInfo.m_ac3FrameSize; - m_bufferSize = format.m_frames * STARFISH_AUDIO_BUFFERS; + if (!m_format.m_streamInfo.m_frameSize) + m_format.m_streamInfo.m_frameSize = AC3_SYNCFRAME_SIZE; + m_format.m_frames = m_format.m_streamInfo.m_frameSize; + m_bufferSize = m_format.m_frames * STARFISH_AUDIO_BUFFERS; break; } case CAEStreamInfo::STREAM_TYPE_EAC3: @@ -119,10 +130,30 @@ bool CAESinkStarfish::Initialize(AEAudioFormat& format, std::string& device) payload["option"]["externalStreamingInfo"]["contents"]["ac3PlusInfo"]["frequency"] = static_cast<double>(m_format.m_streamInfo.m_sampleRate) / 1000; - if (!format.m_streamInfo.m_ac3FrameSize) - format.m_streamInfo.m_ac3FrameSize = AC3_SYNCFRAME_SIZE; - format.m_frames = format.m_streamInfo.m_ac3FrameSize; - m_bufferSize = format.m_frames * STARFISH_AUDIO_BUFFERS; + if (!m_format.m_streamInfo.m_frameSize) + m_format.m_streamInfo.m_frameSize = AC3_SYNCFRAME_SIZE; + m_format.m_frames = m_format.m_streamInfo.m_frameSize; + m_bufferSize = m_format.m_frames * STARFISH_AUDIO_BUFFERS; + break; + } + case CAEStreamInfo::STREAM_TYPE_DTSHD_CORE: + case CAEStreamInfo::STREAM_TYPE_DTS_512: + case CAEStreamInfo::STREAM_TYPE_DTS_1024: + case CAEStreamInfo::STREAM_TYPE_DTS_2048: + case CAEStreamInfo::STREAM_TYPE_DTSHD: + case CAEStreamInfo::STREAM_TYPE_DTSHD_MA: + { + payload["option"]["externalStreamingInfo"]["contents"]["dtsInfo"]["channels"] = + m_format.m_streamInfo.m_channels; + payload["option"]["externalStreamingInfo"]["contents"]["dtsInfo"]["frequency"] = + static_cast<double>(m_format.m_streamInfo.m_sampleRate) / 1000; + + m_format.m_frames = m_format.m_streamInfo.m_frameSize; + + // DTSHD_MA has dynamic frame sizes but we need to ensure that the buffer is large enough + if (m_format.m_streamInfo.m_type == CAEStreamInfo::STREAM_TYPE_DTSHD_MA) + m_format.m_frames = DTDHD_MA_MIN_SYNCFRAME_SIZE * 2 - 1; + m_bufferSize = m_format.m_frames * STARFISH_AUDIO_BUFFERS; break; } default: @@ -140,7 +171,7 @@ bool CAESinkStarfish::Initialize(AEAudioFormat& format, std::string& device) m_bufferSize; // Internal buffer? payload["option"]["externalStreamingInfo"]["bufferingCtrInfo"]["srcBufferLevelAudio"]["minimum"] = - format.m_frames; + m_format.m_frames; payload["option"]["externalStreamingInfo"]["bufferingCtrInfo"]["srcBufferLevelAudio"]["maximum"] = m_bufferSize; @@ -159,6 +190,8 @@ bool CAESinkStarfish::Initialize(AEAudioFormat& format, std::string& device) return false; } + format = m_format; + return true; } diff --git a/xbmc/cores/AudioEngine/Utils/AEStreamInfo.cpp b/xbmc/cores/AudioEngine/Utils/AEStreamInfo.cpp index b045a19d10..359cd26b4e 100644 --- a/xbmc/cores/AudioEngine/Utils/AEStreamInfo.cpp +++ b/xbmc/cores/AudioEngine/Utils/AEStreamInfo.cpp @@ -369,7 +369,7 @@ bool CAEStreamParser::TrySyncAC3(uint8_t* data, // no need to resync => return true return true; } - m_info.m_ac3FrameSize = fsizeMain; + m_info.m_frameSize = fsizeMain; if (TrySyncAC3(data + fsizeMain, size - fsizeMain, resyncing, true)) { // concatenate the main and dependent frames @@ -393,7 +393,7 @@ bool CAEStreamParser::TrySyncAC3(uint8_t* data, m_info.m_channels = AC3Channels[acmod] + lfeon; m_syncFunc = &CAEStreamParser::SyncAC3; m_info.m_type = CAEStreamInfo::STREAM_TYPE_AC3; - m_info.m_ac3FrameSize += m_fsize; + m_info.m_frameSize += m_fsize; m_info.m_repeat = 1; CLog::Log(LOGINFO, "CAEStreamParser::TrySyncAC3 - AC3 stream detected ({} channels, {}Hz)", @@ -452,7 +452,7 @@ bool CAEStreamParser::TrySyncAC3(uint8_t* data, // no need to resync => return true return true; } - m_info.m_ac3FrameSize = fsizeMain; + m_info.m_frameSize = fsizeMain; if (TrySyncAC3(data + fsizeMain, size - fsizeMain, resyncing, true)) { // concatenate the main and dependent frames @@ -469,7 +469,7 @@ bool CAEStreamParser::TrySyncAC3(uint8_t* data, m_info.m_channels = AC3Channels[acmod] + lfeon; m_syncFunc = &CAEStreamParser::SyncAC3; m_info.m_type = CAEStreamInfo::STREAM_TYPE_EAC3; - m_info.m_ac3FrameSize += m_fsize; + m_info.m_frameSize += m_fsize; CLog::Log(LOGINFO, "CAEStreamParser::TrySyncAC3 - E-AC3 stream detected ({} channels, {}Hz)", m_info.m_channels, m_info.m_sampleRate); @@ -673,6 +673,7 @@ unsigned int CAEStreamParser::SyncDTS(uint8_t* data, unsigned int size) m_dtsBlocks = dtsBlocks; m_info.m_channels = DTSChannels[amode] + (lfe ? 1 : 0); m_syncFunc = &CAEStreamParser::SyncDTS; + m_info.m_frameSize = m_fsize; m_info.m_repeat = 1; if (dataType == CAEStreamInfo::STREAM_TYPE_DTSHD_MA) @@ -812,6 +813,7 @@ unsigned int CAEStreamParser::SyncTrueHD(uint8_t* data, unsigned int size) m_fsize = length; m_info.m_type = CAEStreamInfo::STREAM_TYPE_TRUEHD; m_syncFunc = &CAEStreamParser::SyncTrueHD; + m_info.m_frameSize = length; m_info.m_repeat = 1; return skip; } diff --git a/xbmc/cores/AudioEngine/Utils/AEStreamInfo.h b/xbmc/cores/AudioEngine/Utils/AEStreamInfo.h index dff809d137..acfa77d987 100644 --- a/xbmc/cores/AudioEngine/Utils/AEStreamInfo.h +++ b/xbmc/cores/AudioEngine/Utils/AEStreamInfo.h @@ -45,7 +45,7 @@ public: bool m_dataIsLE = true; unsigned int m_dtsPeriod = 0; unsigned int m_repeat = 0; - unsigned int m_ac3FrameSize = 0; + unsigned int m_frameSize = 0; }; class CAEStreamParser diff --git a/xbmc/cores/DllLoader/exports/emu_msvcrt.cpp b/xbmc/cores/DllLoader/exports/emu_msvcrt.cpp index a2084261b1..b86fa65414 100644 --- a/xbmc/cores/DllLoader/exports/emu_msvcrt.cpp +++ b/xbmc/cores/DllLoader/exports/emu_msvcrt.cpp @@ -44,6 +44,7 @@ #endif #include "CompileInfo.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "URL.h" #include "Util.h" diff --git a/xbmc/cores/DllLoader/exports/wrapper.c b/xbmc/cores/DllLoader/exports/wrapper.c index 0d3d54bc1d..455ec0b8ca 100644 --- a/xbmc/cores/DllLoader/exports/wrapper.c +++ b/xbmc/cores/DllLoader/exports/wrapper.c @@ -36,7 +36,6 @@ typedef fpos_t fpos64_t; #endif struct mntent; -struct statvfs64; void* dllmalloc(size_t ); void* dllcalloc( size_t , size_t ); @@ -92,7 +91,6 @@ int dll_ftrylockfile(FILE *file); void dll_funlockfile(FILE *file); int dll_fstat64(int fd, struct stat64 *buf); int dll_fstat(int fd, struct _stat *buf); -int dll_fstatvfs64(int fildes, struct statvfs64 *buf); FILE* dll_popen(const char *command, const char *mode); void* dll_dlopen(const char *filename, int flag); int dll_setvbuf(FILE *stream, char *buf, int type, size_t size); @@ -445,11 +443,6 @@ int __wrap_fstat64(int fd, struct stat64* buf) return dll_fstat64(fd, buf); } -int __wrap_fstatvfs64(int fd, struct statvfs64* buf) -{ - return dll_fstatvfs64(fd, buf); -} - int __wrap_setvbuf(FILE *stream, char *buf, int type, size_t size) { return dll_setvbuf(stream, buf, type, size); diff --git a/xbmc/cores/DllLoader/exports/wrapper_mach_alias b/xbmc/cores/DllLoader/exports/wrapper_mach_alias index 88ff67554f..dfee67eefd 100644 --- a/xbmc/cores/DllLoader/exports/wrapper_mach_alias +++ b/xbmc/cores/DllLoader/exports/wrapper_mach_alias @@ -20,7 +20,6 @@ ___wrap_fread _fread ___wrap_freopen _freopen ___wrap_fseek _fseek ___wrap_fsetpos _fsetpos -___wrap_fstatvfs64 _fstatvfs64 ___wrap_ftell _ftell ___wrap_ftrylockfile _ftrylockfile ___wrap_funlockfile _funlockfile diff --git a/xbmc/cores/RetroPlayer/savestates/SavestateDatabase.cpp b/xbmc/cores/RetroPlayer/savestates/SavestateDatabase.cpp index 7864a15261..a6deeddb94 100644 --- a/xbmc/cores/RetroPlayer/savestates/SavestateDatabase.cpp +++ b/xbmc/cores/RetroPlayer/savestates/SavestateDatabase.cpp @@ -9,6 +9,7 @@ #include "SavestateDatabase.h" #include "FileItem.h" +#include "FileItemList.h" #include "SavestateFlatBuffer.h" #include "URL.h" #include "XBDateTime.h" diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.cpp index c83d263968..ce6de6f20d 100644 --- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.cpp +++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.cpp @@ -353,14 +353,10 @@ bool CDVDVideoCodecAndroidMediaCodec::Open(CDVDStreamInfo &hints, CDVDCodecOptio CLog::Log(LOGERROR, "CDVDVideoCodecAndroidMediaCodec::Open - {}", "null size, cannot handle"); goto FAIL; } - else if (hints.orientation && m_render_surface && CJNIBase::GetSDKVersion() < 23) - { - CLog::Log(LOGERROR, "CDVDVideoCodecAndroidMediaCodec::Open - {}", - "Surface does not support orientation before API 23"); - goto FAIL; - } - else if (!CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_VIDEOPLAYER_USEMEDIACODEC) && - !CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_VIDEOPLAYER_USEMEDIACODECSURFACE)) + else if (!CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool( + CSettings::SETTING_VIDEOPLAYER_USEMEDIACODEC) && + !CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool( + CSettings::SETTING_VIDEOPLAYER_USEMEDIACODECSURFACE)) goto FAIL; CLog::Log( @@ -553,44 +549,41 @@ bool CDVDVideoCodecAndroidMediaCodec::Open(CDVDStreamInfo &hints, CDVDCodecOptio m_formatname = isDvhe ? "amc-dvhe" : "amc-dvh1"; profile = 0; // not an HEVC profile - if (CJNIBase::GetSDKVersion() >= 24) + switch (m_hints.dovi.dv_profile) { - switch (m_hints.dovi.dv_profile) - { - case 0: - case 1: - case 2: - case 3: - case 6: - // obsolete profiles that are not supported in current applications. - // 0 is ignored in case the AVDOVIDecoderConfigurationRecord hint is unset. - break; - case 4: - profile = CJNIMediaCodecInfoCodecProfileLevel::DolbyVisionProfileDvheDtr; - break; - case 5: - profile = CJNIMediaCodecInfoCodecProfileLevel::DolbyVisionProfileDvheStn; - break; - case 7: - // set profile 8 when converting - if (convertDovi && CJNIBase::GetSDKVersion() >= 27) - profile = CJNIMediaCodecInfoCodecProfileLevel::DolbyVisionProfileDvheSt; - - // Profile 7 is not commonly supported. Not setting the profile here - // allows to pick the first available Dolby Vision codec. - // profile = CJNIMediaCodecInfoCodecProfileLevel::DolbyVisionProfileDvheDtb; - break; - case 8: - if (CJNIBase::GetSDKVersion() >= 27) - profile = CJNIMediaCodecInfoCodecProfileLevel::DolbyVisionProfileDvheSt; - break; - case 9: - if (CJNIBase::GetSDKVersion() >= 27) - profile = CJNIMediaCodecInfoCodecProfileLevel::DolbyVisionProfileDvavSe; - break; - default: - break; - } + case 0: + case 1: + case 2: + case 3: + case 6: + // obsolete profiles that are not supported in current applications. + // 0 is ignored in case the AVDOVIDecoderConfigurationRecord hint is unset. + break; + case 4: + profile = CJNIMediaCodecInfoCodecProfileLevel::DolbyVisionProfileDvheDtr; + break; + case 5: + profile = CJNIMediaCodecInfoCodecProfileLevel::DolbyVisionProfileDvheStn; + break; + case 7: + // set profile 8 when converting + if (convertDovi && CJNIBase::GetSDKVersion() >= 27) + profile = CJNIMediaCodecInfoCodecProfileLevel::DolbyVisionProfileDvheSt; + + // Profile 7 is not commonly supported. Not setting the profile here + // allows to pick the first available Dolby Vision codec. + // profile = CJNIMediaCodecInfoCodecProfileLevel::DolbyVisionProfileDvheDtb; + break; + case 8: + if (CJNIBase::GetSDKVersion() >= 27) + profile = CJNIMediaCodecInfoCodecProfileLevel::DolbyVisionProfileDvheSt; + break; + case 9: + if (CJNIBase::GetSDKVersion() >= 27) + profile = CJNIMediaCodecInfoCodecProfileLevel::DolbyVisionProfileDvavSe; + break; + default: + break; } } } @@ -1389,7 +1382,8 @@ void CDVDVideoCodecAndroidMediaCodec::SignalEndOfStream() { xbmc_jnienv()->ExceptionDescribe(); xbmc_jnienv()->ExceptionClear(); - CLog::Log(LOGERROR, "CDVDVideoCodecAndroidMediaCodec::{}: queueInputBuffer failed"); + CLog::Log(LOGERROR, "CDVDVideoCodecAndroidMediaCodec::{}: queueInputBuffer failed", + __func__); } else { @@ -1476,7 +1470,7 @@ bool CDVDVideoCodecAndroidMediaCodec::ConfigureMediaCodec(void) CJNIMediaFormat::createVideoFormat(m_mime, m_hints.width, m_hints.height); mediaformat.setInteger(CJNIMediaFormat::KEY_MAX_INPUT_SIZE, 0); - if (CJNIBase::GetSDKVersion() >= 23 && m_render_surface) + if (m_render_surface) { // Handle rotation mediaformat.setInteger(CJNIMediaFormat::KEY_ROTATION, m_hints.orientation); @@ -1487,89 +1481,86 @@ bool CDVDVideoCodecAndroidMediaCodec::ConfigureMediaCodec(void) true); } - if (CJNIBase::GetSDKVersion() >= 24) + switch (m_hints.colorRange) { - switch (m_hints.colorRange) - { - case AVCOL_RANGE_UNSPECIFIED: - CLog::Log(LOGDEBUG, "CDVDVideoCodecAndroidMediaCodec::ConfigureMediaCodec Color range: " - "AVCOL_RANGE_UNSPECIFIED"); - break; - case AVCOL_RANGE_MPEG: - mediaformat.setInteger(CJNIMediaFormat::KEY_COLOR_RANGE, - CJNIMediaFormat::COLOR_RANGE_LIMITED); - break; - case AVCOL_RANGE_JPEG: - mediaformat.setInteger(CJNIMediaFormat::KEY_COLOR_RANGE, CJNIMediaFormat::COLOR_RANGE_FULL); - break; - default: - CLog::Log(LOGWARNING, - "CDVDVideoCodecAndroidMediaCodec::ConfigureMediaCodec Unhandled Color range: {}", - m_hints.colorRange); - break; - } + case AVCOL_RANGE_UNSPECIFIED: + CLog::Log(LOGDEBUG, "CDVDVideoCodecAndroidMediaCodec::ConfigureMediaCodec Color range: " + "AVCOL_RANGE_UNSPECIFIED"); + break; + case AVCOL_RANGE_MPEG: + mediaformat.setInteger(CJNIMediaFormat::KEY_COLOR_RANGE, + CJNIMediaFormat::COLOR_RANGE_LIMITED); + break; + case AVCOL_RANGE_JPEG: + mediaformat.setInteger(CJNIMediaFormat::KEY_COLOR_RANGE, CJNIMediaFormat::COLOR_RANGE_FULL); + break; + default: + CLog::Log(LOGWARNING, + "CDVDVideoCodecAndroidMediaCodec::ConfigureMediaCodec Unhandled Color range: {}", + m_hints.colorRange); + break; + } - switch (m_hints.colorPrimaries) - { - case AVCOL_PRI_UNSPECIFIED: - CLog::Log(LOGDEBUG, "CDVDVideoCodecAndroidMediaCodec::ConfigureMediaCodec Color primaries: " - "AVCOL_PRI_UNSPECIFIED"); - break; - case AVCOL_PRI_BT709: - mediaformat.setInteger(CJNIMediaFormat::KEY_COLOR_STANDARD, - CJNIMediaFormat::COLOR_STANDARD_BT709); - break; - case AVCOL_PRI_BT2020: - mediaformat.setInteger(CJNIMediaFormat::KEY_COLOR_STANDARD, - CJNIMediaFormat::COLOR_STANDARD_BT2020); - break; - default: - CLog::Log( - LOGWARNING, - "CDVDVideoCodecAndroidMediaCodec::ConfigureMediaCodec Unhandled Color primaries: {}", - m_hints.colorPrimaries); - break; - } + switch (m_hints.colorPrimaries) + { + case AVCOL_PRI_UNSPECIFIED: + CLog::Log(LOGDEBUG, "CDVDVideoCodecAndroidMediaCodec::ConfigureMediaCodec Color primaries: " + "AVCOL_PRI_UNSPECIFIED"); + break; + case AVCOL_PRI_BT709: + mediaformat.setInteger(CJNIMediaFormat::KEY_COLOR_STANDARD, + CJNIMediaFormat::COLOR_STANDARD_BT709); + break; + case AVCOL_PRI_BT2020: + mediaformat.setInteger(CJNIMediaFormat::KEY_COLOR_STANDARD, + CJNIMediaFormat::COLOR_STANDARD_BT2020); + break; + default: + CLog::Log( + LOGWARNING, + "CDVDVideoCodecAndroidMediaCodec::ConfigureMediaCodec Unhandled Color primaries: {}", + m_hints.colorPrimaries); + break; + } - switch (m_hints.colorTransferCharacteristic) - { - case AVCOL_TRC_UNSPECIFIED: - CLog::Log(LOGDEBUG, "CDVDVideoCodecAndroidMediaCodec::ConfigureMediaCodec Transfer " - "characteristic: AVCOL_TRC_UNSPECIFIED"); - break; - case AVCOL_TRC_LINEAR: - mediaformat.setInteger(CJNIMediaFormat::KEY_COLOR_TRANSFER, - CJNIMediaFormat::COLOR_TRANSFER_LINEAR); - break; - case AVCOL_TRC_BT709: - case AVCOL_TRC_SMPTE170M: - mediaformat.setInteger(CJNIMediaFormat::KEY_COLOR_TRANSFER, - CJNIMediaFormat::COLOR_TRANSFER_SDR_VIDEO); - break; - case AVCOL_TRC_SMPTE2084: - mediaformat.setInteger(CJNIMediaFormat::KEY_COLOR_TRANSFER, - CJNIMediaFormat::COLOR_TRANSFER_ST2084); - break; - case AVCOL_TRC_ARIB_STD_B67: - mediaformat.setInteger(CJNIMediaFormat::KEY_COLOR_TRANSFER, - CJNIMediaFormat::COLOR_TRANSFER_HLG); - break; - default: - CLog::Log(LOGWARNING, - "CDVDVideoCodecAndroidMediaCodec::ConfigureMediaCodec Unhandled Transfer " - "characteristic: {}", - m_hints.colorTransferCharacteristic); - break; - } + switch (m_hints.colorTransferCharacteristic) + { + case AVCOL_TRC_UNSPECIFIED: + CLog::Log(LOGDEBUG, "CDVDVideoCodecAndroidMediaCodec::ConfigureMediaCodec Transfer " + "characteristic: AVCOL_TRC_UNSPECIFIED"); + break; + case AVCOL_TRC_LINEAR: + mediaformat.setInteger(CJNIMediaFormat::KEY_COLOR_TRANSFER, + CJNIMediaFormat::COLOR_TRANSFER_LINEAR); + break; + case AVCOL_TRC_BT709: + case AVCOL_TRC_SMPTE170M: + mediaformat.setInteger(CJNIMediaFormat::KEY_COLOR_TRANSFER, + CJNIMediaFormat::COLOR_TRANSFER_SDR_VIDEO); + break; + case AVCOL_TRC_SMPTE2084: + mediaformat.setInteger(CJNIMediaFormat::KEY_COLOR_TRANSFER, + CJNIMediaFormat::COLOR_TRANSFER_ST2084); + break; + case AVCOL_TRC_ARIB_STD_B67: + mediaformat.setInteger(CJNIMediaFormat::KEY_COLOR_TRANSFER, + CJNIMediaFormat::COLOR_TRANSFER_HLG); + break; + default: + CLog::Log(LOGWARNING, + "CDVDVideoCodecAndroidMediaCodec::ConfigureMediaCodec Unhandled Transfer " + "characteristic: {}", + m_hints.colorTransferCharacteristic); + break; + } - std::vector<uint8_t> hdr_static_data = GetHDRStaticMetadata(); - if (!hdr_static_data.empty()) - { - CJNIByteBuffer bytebuffer = CJNIByteBuffer::allocateDirect(hdr_static_data.size()); - void* dts_ptr = xbmc_jnienv()->GetDirectBufferAddress(bytebuffer.get_raw()); - memcpy(dts_ptr, hdr_static_data.data(), hdr_static_data.size()); - mediaformat.setByteBuffer(CJNIMediaFormat::KEY_HDR_STATIC_INFO, bytebuffer); - } + std::vector<uint8_t> hdr_static_data = GetHDRStaticMetadata(); + if (!hdr_static_data.empty()) + { + CJNIByteBuffer bytebuffer = CJNIByteBuffer::allocateDirect(hdr_static_data.size()); + void* dts_ptr = xbmc_jnienv()->GetDirectBufferAddress(bytebuffer.get_raw()); + memcpy(dts_ptr, hdr_static_data.data(), hdr_static_data.size()); + mediaformat.setByteBuffer(CJNIMediaFormat::KEY_HDR_STATIC_INFO, bytebuffer); } // handle codec extradata @@ -1740,14 +1731,10 @@ void CDVDVideoCodecAndroidMediaCodec::ConfigureOutputFormat(CJNIMediaFormat& med height = mediaformat.getInteger(CJNIMediaFormat::KEY_HEIGHT); if (mediaformat.containsKey(CJNIMediaFormat::KEY_COLOR_FORMAT)) color_format = mediaformat.getInteger(CJNIMediaFormat::KEY_COLOR_FORMAT); - - if (CJNIBase::GetSDKVersion() >= 23) - { - if (mediaformat.containsKey(CJNIMediaFormat::KEY_STRIDE)) - stride = mediaformat.getInteger(CJNIMediaFormat::KEY_STRIDE); - if (mediaformat.containsKey(CJNIMediaFormat::KEY_SLICE_HEIGHT)) - slice_height = mediaformat.getInteger(CJNIMediaFormat::KEY_SLICE_HEIGHT); - } + if (mediaformat.containsKey(CJNIMediaFormat::KEY_STRIDE)) + stride = mediaformat.getInteger(CJNIMediaFormat::KEY_STRIDE); + if (mediaformat.containsKey(CJNIMediaFormat::KEY_SLICE_HEIGHT)) + slice_height = mediaformat.getInteger(CJNIMediaFormat::KEY_SLICE_HEIGHT); if (CJNIBase::GetSDKVersion() >= 33) { diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecStarfish.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecStarfish.cpp index 7e9988de84..e286ea40e0 100644 --- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecStarfish.cpp +++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecStarfish.cpp @@ -12,17 +12,14 @@ #include "DVDCodecs/DVDFactoryCodec.h" #include "ServiceBroker.h" #include "cores/VideoPlayer/Buffers/VideoBuffer.h" -#include "cores/VideoPlayer/Interface/DemuxCrypto.h" #include "cores/VideoPlayer/Interface/TimingConstants.h" #include "cores/VideoPlayer/VideoRenderers/RenderManager.h" -#include "media/decoderfilter/DecoderFilterManager.h" #include "messaging/ApplicationMessenger.h" #include "settings/SettingUtils.h" #include "settings/Settings.h" #include "settings/SettingsComponent.h" #include "settings/lib/Setting.h" #include "utils/BitstreamConverter.h" -#include "utils/CPUInfo.h" #include "utils/JSONVariantWriter.h" #include "utils/log.h" #include "windowing/wayland/WinSystemWaylandWebOS.h" @@ -172,9 +169,6 @@ bool CDVDVideoCodecStarfish::OpenInternal(CDVDStreamInfo& hints, CDVDCodecOption bool isDvhe = (m_hints.codec_tag == MKTAG('d', 'v', 'h', 'e')); bool isDvh1 = (m_hints.codec_tag == MKTAG('d', 'v', 'h', '1')); - bool payloadDoviProfile = m_hints.dovi.dv_profile; - bool payloadElPresentFlag = m_hints.dovi.el_present_flag; - // some files don't have dvhe or dvh1 tag set up but have Dolby Vision side data if (!isDvhe && !isDvh1 && m_hints.hdrType == StreamHdrType::HDR_TYPE_DOLBYVISION) { @@ -185,25 +179,6 @@ bool CDVDVideoCodecStarfish::OpenInternal(CDVDStreamInfo& hints, CDVDCodecOption isDvhe = true; } - // set profile 8 and single layer when converting - if (!removeDovi && convertDovi && m_hints.dovi.dv_profile == 7) - { - payloadDoviProfile = 8; - payloadElPresentFlag = false; - } - - if (!removeDovi && (isDvhe || isDvh1)) - { - m_formatname = isDvhe ? "starfish-dvhe" : "starfish-dvh1"; - - payloadArg["option"]["externalStreamingInfo"]["contents"]["DolbyHdrInfo"] - ["encryptionType"] = "clear"; //"clear", "bl", "el", "all" - payloadArg["option"]["externalStreamingInfo"]["contents"]["DolbyHdrInfo"]["profileId"] = - payloadDoviProfile; // profile 0-9 - payloadArg["option"]["externalStreamingInfo"]["contents"]["DolbyHdrInfo"]["trackType"] = - payloadElPresentFlag ? "dual" : "single"; // "single" / "dual" - } - // check for hevc-hvcC and convert to h265-annex-b if (m_hints.extradata && !m_hints.cryptoSession) { @@ -222,11 +197,31 @@ bool CDVDVideoCodecStarfish::OpenInternal(CDVDStreamInfo& hints, CDVDCodecOption m_bitstream->SetRemoveHdr10Plus(true); // Only set for profile 7, container hint allows to skip parsing unnecessarily - if (m_hints.dovi.dv_profile == 7) - m_bitstream->SetConvertDovi(convertDovi); + // set profile 8 and single layer when converting + if (!removeDovi && convertDovi && m_hints.dovi.dv_profile == 7) + { + m_hints.dovi.dv_profile = 8; + m_hints.dovi.el_present_flag = false; + m_bitstream->SetConvertDovi(true); + } } } + if (!removeDovi && (isDvhe || isDvh1)) + { + m_formatname = isDvhe ? "starfish-dvhe" : "starfish-dvh1"; + + payloadArg["option"]["externalStreamingInfo"]["contents"]["DolbyHdrInfo"] + ["encryptionType"] = "clear"; //"clear", "bl", "el", "all" + payloadArg["option"]["externalStreamingInfo"]["contents"]["DolbyHdrInfo"]["profileId"] = + m_hints.dovi.dv_profile; // profile 0-9 + payloadArg["option"]["externalStreamingInfo"]["contents"]["DolbyHdrInfo"]["trackType"] = + m_hints.dovi.el_present_flag ? "dual" : "single"; // "single" / "dual" + } + + if (removeDovi && (isDvhe || isDvh1)) + m_hints.hdrType = StreamHdrType::HDR_TYPE_HDR10; + break; } case AV_CODEC_ID_AV1: @@ -514,62 +509,79 @@ void CDVDVideoCodecStarfish::SetSpeed(int iSpeed) void CDVDVideoCodecStarfish::SetHDR() { + if (m_hints.hdrType != StreamHdrType::HDR_TYPE_HDR10 && + m_hints.hdrType != StreamHdrType::HDR_TYPE_HLG) + return; + + CVariant hdrData; + CVariant sei; + + if (ms_hdrInfoMap.find(m_hints.colorTransferCharacteristic) != ms_hdrInfoMap.cend()) + hdrData["hdrType"] = ms_hdrInfoMap.at(m_hints.colorTransferCharacteristic).data(); + else + hdrData["hdrType"] = "none"; + if (m_hints.masteringMetadata) { - CVariant hdrData; - - if (ms_hdrInfoMap.find(m_hints.colorTransferCharacteristic) != ms_hdrInfoMap.cend()) - hdrData["hdrType"] = ms_hdrInfoMap.at(m_hints.colorTransferCharacteristic).data(); - else - hdrData["hdrType"] = "none"; - - CVariant sei; - // for more information, see CTA+861.3-A standard document - constexpr double maxChromaticity = 50000; - constexpr double maxLuminance = 10000; - sei["displayPrimariesX0"] = static_cast<unsigned short>( - av_q2d(m_hints.masteringMetadata->display_primaries[0][0]) * maxChromaticity + 0.5); - sei["displayPrimariesY0"] = static_cast<unsigned short>( - av_q2d(m_hints.masteringMetadata->display_primaries[0][1]) * maxChromaticity + 0.5); - sei["displayPrimariesX1"] = static_cast<unsigned short>( - av_q2d(m_hints.masteringMetadata->display_primaries[1][0]) * maxChromaticity + 0.5); - sei["displayPrimariesY1"] = static_cast<unsigned short>( - av_q2d(m_hints.masteringMetadata->display_primaries[1][1]) * maxChromaticity + 0.5); - sei["displayPrimariesX2"] = static_cast<unsigned short>( - av_q2d(m_hints.masteringMetadata->display_primaries[2][0]) * maxChromaticity + 0.5); - sei["displayPrimariesY2"] = static_cast<unsigned short>( - av_q2d(m_hints.masteringMetadata->display_primaries[2][1]) * maxChromaticity + 0.5); - sei["whitePointX"] = static_cast<unsigned short>( - av_q2d(m_hints.masteringMetadata->white_point[0]) * maxChromaticity + 0.5); - sei["whitePointY"] = static_cast<unsigned short>( - av_q2d(m_hints.masteringMetadata->white_point[1]) * maxChromaticity + 0.5); - sei["minDisplayMasteringLuminance"] = - static_cast<unsigned short>(av_q2d(m_hints.masteringMetadata->min_luminance) + 0.5); - sei["maxDisplayMasteringLuminance"] = static_cast<unsigned short>( - av_q2d(m_hints.masteringMetadata->max_luminance) * maxLuminance + 0.5); - // we can have HDR content that does not provide content light level metadata - if (m_hints.contentLightMetadata) + if (m_hints.masteringMetadata->has_primaries) { - sei["maxContentLightLevel"] = - static_cast<unsigned short>(m_hints.contentLightMetadata->MaxCLL); - sei["maxPicAverageLightLevel"] = - static_cast<unsigned short>(m_hints.contentLightMetadata->MaxFALL); + // for more information, see CTA+861.3-A standard document + constexpr int maxChromaticity = 50000; + // expected input is in gbr order + sei["displayPrimariesX0"] = static_cast<int>( + std::round(av_q2d(m_hints.masteringMetadata->display_primaries[1][0]) * maxChromaticity)); + sei["displayPrimariesY0"] = static_cast<int>( + std::round(av_q2d(m_hints.masteringMetadata->display_primaries[1][1]) * maxChromaticity)); + sei["displayPrimariesX1"] = static_cast<int>( + std::round(av_q2d(m_hints.masteringMetadata->display_primaries[2][0]) * maxChromaticity)); + sei["displayPrimariesY1"] = static_cast<int>( + std::round(av_q2d(m_hints.masteringMetadata->display_primaries[2][1]) * maxChromaticity)); + sei["displayPrimariesX2"] = static_cast<int>( + std::round(av_q2d(m_hints.masteringMetadata->display_primaries[0][0]) * maxChromaticity)); + sei["displayPrimariesY2"] = static_cast<int>( + std::round(av_q2d(m_hints.masteringMetadata->display_primaries[0][1]) * maxChromaticity)); + sei["whitePointX"] = static_cast<int>( + std::round(av_q2d(m_hints.masteringMetadata->white_point[0]) * maxChromaticity)); + sei["whitePointY"] = static_cast<int>( + std::round(av_q2d(m_hints.masteringMetadata->white_point[1]) * maxChromaticity)); } - hdrData["sei"] = sei; - - CVariant vui; - vui["transferCharacteristics"] = static_cast<int>(m_hints.colorTransferCharacteristic); - vui["colorPrimaries"] = static_cast<int>(m_hints.colorPrimaries); - vui["matrixCoeffs"] = static_cast<int>(m_hints.colorSpace); - vui["videoFullRangeFlag"] = m_hints.colorRange == AVCOL_RANGE_JPEG; - hdrData["vui"] = vui; - std::string payload; - CJSONVariantWriter::Write(hdrData, payload, true); + if (m_hints.masteringMetadata->has_luminance) + { + constexpr int maxLuminance = 10000; + sei["minDisplayMasteringLuminance"] = static_cast<int>( + std::round(av_q2d(m_hints.masteringMetadata->min_luminance) * maxLuminance)); + sei["maxDisplayMasteringLuminance"] = static_cast<int>( + std::round(av_q2d(m_hints.masteringMetadata->max_luminance) * maxLuminance)); + } + } - CLog::LogFC(LOGDEBUG, LOGVIDEO, "CDVDVideoCodecStarfish: Setting HDR data payload {}", payload); - m_starfishMediaAPI->setHdrInfo(payload.c_str()); + // we can have HDR content that does not provide content light level metadata + if (m_hints.contentLightMetadata) + { + sei["maxContentLightLevel"] = m_hints.contentLightMetadata->MaxCLL; + sei["maxPicAverageLightLevel"] = m_hints.contentLightMetadata->MaxFALL; } + + // Some TVs crash on a hdr info message without SEI information + // This data is often not available from ffmpeg from the stream (av_stream_get_side_data) + // So return here early and let the TV detect the presence of HDR metadata on its own + if (sei.empty()) + return; + hdrData["sei"] = sei; + + CVariant vui; + vui["transferCharacteristics"] = static_cast<int>(m_hints.colorTransferCharacteristic); + vui["colorPrimaries"] = static_cast<int>(m_hints.colorPrimaries); + vui["matrixCoeffs"] = static_cast<int>(m_hints.colorSpace); + vui["videoFullRangeFlag"] = m_hints.colorRange == AVCOL_RANGE_JPEG; + hdrData["vui"] = vui; + + std::string payload; + CJSONVariantWriter::Write(hdrData, payload, true); + + CLog::LogFC(LOGDEBUG, LOGVIDEO, "CDVDVideoCodecStarfish: Setting HDR data payload {}", payload); + m_starfishMediaAPI->setHdrInfo(payload.c_str()); } void CDVDVideoCodecStarfish::UpdateFpsDuration() diff --git a/xbmc/cores/VideoPlayer/DVDFileInfo.cpp b/xbmc/cores/VideoPlayer/DVDFileInfo.cpp index bd89cb4629..65dfc539de 100644 --- a/xbmc/cores/VideoPlayer/DVDFileInfo.cpp +++ b/xbmc/cores/VideoPlayer/DVDFileInfo.cpp @@ -11,6 +11,7 @@ #include "DVDInputStreams/DVDInputStream.h" #include "DVDStreamInfo.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "filesystem/StackDirectory.h" #include "guilib/Texture.h" @@ -20,6 +21,7 @@ #include "utils/MemUtils.h" #include "utils/URIUtils.h" #include "utils/log.h" +#include "video/VideoFileItemClassify.h" #include "video/VideoInfoTag.h" #ifdef HAVE_LIBBLURAY #include "DVDInputStreams/DVDInputStreamBluray.h" @@ -49,6 +51,8 @@ extern "C" { #include <libswscale/swscale.h> } +using namespace KODI; + bool CDVDFileInfo::GetFileDuration(const std::string &path, int& duration) { std::unique_ptr<CDVDDemux> demux; @@ -258,12 +262,12 @@ bool CDVDFileInfo::CanExtract(const CFileItem& fileItem) URIUtils::IsPVRRecording(fileItem.GetDynPath()) || // plugin path not fully resolved URIUtils::IsPlugin(fileItem.GetDynPath()) || URIUtils::IsUPnP(fileItem.GetPath()) || - fileItem.IsInternetStream() || fileItem.IsDiscStub() || fileItem.IsPlayList()) + fileItem.IsInternetStream() || VIDEO::IsDiscStub(fileItem) || fileItem.IsPlayList()) return false; // mostly can't extract from discs and files from discs. - if (URIUtils::IsBluray(fileItem.GetPath()) || fileItem.IsBDFile() || fileItem.IsDVD() || - fileItem.IsDiscImage() || fileItem.IsDVDFile(false, true)) + if (URIUtils::IsBluray(fileItem.GetPath()) || VIDEO::IsBDFile(fileItem) || fileItem.IsDVD() || + fileItem.IsDiscImage() || VIDEO::IsDVDFile(fileItem, false, true)) return false; // For HTTP/FTP we only allow extraction when on a LAN diff --git a/xbmc/cores/VideoPlayer/DVDInputStreams/DVDFactoryInputStream.cpp b/xbmc/cores/VideoPlayer/DVDInputStreams/DVDFactoryInputStream.cpp index e25e35dcaf..2b65938437 100644 --- a/xbmc/cores/VideoPlayer/DVDInputStreams/DVDFactoryInputStream.cpp +++ b/xbmc/cores/VideoPlayer/DVDInputStreams/DVDFactoryInputStream.cpp @@ -32,9 +32,12 @@ #include "storage/MediaManager.h" #include "utils/FileUtils.h" #include "utils/URIUtils.h" +#include "video/VideoFileItemClassify.h" #include <memory> +using namespace KODI; + std::shared_ptr<CDVDInputStream> CDVDFactoryInputStream::CreateInputStream(IVideoPlayer* pPlayer, const CFileItem &fileitem, bool scanforextaudio) { using namespace ADDON; @@ -101,7 +104,7 @@ std::shared_ptr<CDVDInputStream> CDVDFactoryInputStream::CreateInputStream(IVide } #endif - if (fileitem.IsDVDFile(false, true)) + if (VIDEO::IsDVDFile(fileitem, false, true)) return std::make_shared<CDVDInputStreamNavigator>(pPlayer, fileitem); else if (URIUtils::IsPVRChannel(file)) return std::make_shared<CInputStreamPVRChannel>(pPlayer, fileitem); diff --git a/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamBluray.cpp b/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamBluray.cpp index a87888c7be..8936399b94 100644 --- a/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamBluray.cpp +++ b/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamBluray.cpp @@ -27,6 +27,7 @@ #include "utils/URIUtils.h" #include "utils/XTimeUtils.h" #include "utils/log.h" +#include "video/VideoFileItemClassify.h" #include <functional> #include <limits> @@ -37,6 +38,7 @@ #define LIBBLURAY_BYTESEEK 0 +using namespace KODI; using namespace XFILE; using namespace std::chrono_literals; @@ -152,7 +154,7 @@ bool CDVDInputStreamBluray::Open() // Check whether disc is AACS protected CURL url3(root); CFileItem base(url3, false); - openDisc = base.IsProtectedBlurayDisc(); + openDisc = VIDEO::IsProtectedBlurayDisc(base); // check for a menu call for an image file if (StringUtils::EqualsNoCase(filename, "menu")) @@ -166,7 +168,7 @@ bool CDVDInputStreamBluray::Open() // Check whether disc is AACS protected if (!openDisc) - openDisc = item.IsProtectedBlurayDisc(); + openDisc = VIDEO::IsProtectedBlurayDisc(item); if (item.IsDiscImage()) { @@ -184,7 +186,7 @@ bool CDVDInputStreamBluray::Open() openStream = true; } - else if (m_item.IsProtectedBlurayDisc()) + else if (VIDEO::IsProtectedBlurayDisc(m_item)) { openDisc = true; } diff --git a/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamFile.cpp b/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamFile.cpp index 4214673f08..9ebd8d2c53 100644 --- a/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamFile.cpp +++ b/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamFile.cpp @@ -12,7 +12,9 @@ #include "filesystem/IFile.h" #include "utils/URIUtils.h" #include "utils/log.h" +#include "video/VideoFileItemClassify.h" +using namespace KODI; using namespace XFILE; CDVDInputStreamFile::CDVDInputStreamFile(const CFileItem& fileitem, unsigned int flags) @@ -44,7 +46,7 @@ bool CDVDInputStreamFile::Open() unsigned int flags = m_flags; // If this file is audio and/or video (= not a subtitle) flag to caller - if (!m_item.IsSubtitle()) + if (!VIDEO::IsSubtitle(m_item)) flags |= READ_AUDIO_VIDEO; std::string content = m_item.GetMimeType(); diff --git a/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamStack.cpp b/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamStack.cpp index 1f018617ac..3788295b01 100644 --- a/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamStack.cpp +++ b/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamStack.cpp @@ -9,6 +9,7 @@ #include "DVDInputStreamStack.h" #include "FileItem.h" +#include "FileItemList.h" #include "filesystem/File.h" #include "filesystem/StackDirectory.h" #include "utils/log.h" diff --git a/xbmc/cores/VideoPlayer/DVDSubtitles/DVDSubtitlesLibass.cpp b/xbmc/cores/VideoPlayer/DVDSubtitles/DVDSubtitlesLibass.cpp index 7ac7ec7e71..a8a5e0e35f 100644 --- a/xbmc/cores/VideoPlayer/DVDSubtitles/DVDSubtitlesLibass.cpp +++ b/xbmc/cores/VideoPlayer/DVDSubtitles/DVDSubtitlesLibass.cpp @@ -9,6 +9,7 @@ #include "DVDSubtitlesLibass.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "cores/VideoPlayer/Interface/TimingConstants.h" #include "filesystem/Directory.h" diff --git a/xbmc/cores/VideoPlayer/VideoPlayer.cpp b/xbmc/cores/VideoPlayer/VideoPlayer.cpp index 5bfa52efe7..b43fe8c622 100644 --- a/xbmc/cores/VideoPlayer/VideoPlayer.cpp +++ b/xbmc/cores/VideoPlayer/VideoPlayer.cpp @@ -782,7 +782,9 @@ bool CVideoPlayer::OpenInputStream() { // find any available external subtitles std::vector<std::string> filenames; - CUtil::ScanForExternalSubtitles(m_item.GetDynPath(), filenames); + + if (!URIUtils::IsUPnP(m_item.GetPath())) + CUtil::ScanForExternalSubtitles(m_item.GetDynPath(), filenames); // load any subtitles from file item std::string key("subtitle:1"); diff --git a/xbmc/cores/VideoPlayer/VideoPlayerVideo.cpp b/xbmc/cores/VideoPlayer/VideoPlayerVideo.cpp index 0924703702..c42f8f3dd7 100644 --- a/xbmc/cores/VideoPlayer/VideoPlayerVideo.cpp +++ b/xbmc/cores/VideoPlayer/VideoPlayerVideo.cpp @@ -112,7 +112,7 @@ bool CVideoPlayerVideo::OpenStream(CDVDStreamInfo hint) if (hint.codec == AV_CODEC_ID_NONE || hint.codec == AV_CODEC_ID_MPEG1VIDEO || hint.codec == AV_CODEC_ID_MPEG2VIDEO || - hint.codec == AV_CODEC_ID_H264 || + (hint.codec == AV_CODEC_ID_H264 && (hint.codec_tag == 0 || hint.codec_tag == MKTAG('a','v','c','1') || hint.codec_tag == MKTAG('a','v','c','2'))) || hint.codec == AV_CODEC_ID_HEVC || hint.codec == AV_CODEC_ID_MPEG4 || hint.codec == AV_CODEC_ID_WMV3 || diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/LinuxRendererGLES.cpp b/xbmc/cores/VideoPlayer/VideoRenderers/LinuxRendererGLES.cpp index 45e3435b74..a0ed2c1ab4 100644 --- a/xbmc/cores/VideoPlayer/VideoRenderers/LinuxRendererGLES.cpp +++ b/xbmc/cores/VideoPlayer/VideoRenderers/LinuxRendererGLES.cpp @@ -718,6 +718,7 @@ void CLinuxRendererGLES::UnInit() m_bConfigured = false; CServiceBroker::GetWinSystem()->SetHDR(nullptr); + m_passthroughHDR = false; } bool CLinuxRendererGLES::CreateTexture(int index) diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/OverlayRendererGL.cpp b/xbmc/cores/VideoPlayer/VideoRenderers/OverlayRendererGL.cpp index 3caa28e4bf..8559d22eae 100644 --- a/xbmc/cores/VideoPlayer/VideoRenderers/OverlayRendererGL.cpp +++ b/xbmc/cores/VideoPlayer/VideoRenderers/OverlayRendererGL.cpp @@ -293,6 +293,11 @@ void COverlayGlyphGL::Render(SRenderState& state) GLint posLoc = renderSystem->ShaderGetPos(); GLint colLoc = renderSystem->ShaderGetCol(); GLint tex0Loc = renderSystem->ShaderGetCoord0(); + GLint matrixUniformLoc = renderSystem->ShaderGetMatrix(); + + CMatrixGL matrix = glMatrixProject.Get(); + matrix.MultMatrixf(glMatrixModview.Get()); + glUniformMatrix4fv(matrixUniformLoc, 1, GL_FALSE, matrix); std::vector<VERTEX> vecVertices(6 * m_vertex.size() / 4); VERTEX* vertices = vecVertices.data(); diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/OverlayRendererGLES.cpp b/xbmc/cores/VideoPlayer/VideoRenderers/OverlayRendererGLES.cpp index cf3b31324a..237afacc42 100644 --- a/xbmc/cores/VideoPlayer/VideoRenderers/OverlayRendererGLES.cpp +++ b/xbmc/cores/VideoPlayer/VideoRenderers/OverlayRendererGLES.cpp @@ -352,6 +352,11 @@ void COverlayGlyphGLES::Render(SRenderState& state) GLint posLoc = renderSystem->GUIShaderGetPos(); GLint colLoc = renderSystem->GUIShaderGetCol(); GLint tex0Loc = renderSystem->GUIShaderGetCoord0(); + GLint matrixUniformLoc = renderSystem->GUIShaderGetMatrix(); + + CMatrixGL matrix = glMatrixProject.Get(); + matrix.MultMatrixf(glMatrixModview.Get()); + glUniformMatrix4fv(matrixUniformLoc, 1, GL_FALSE, matrix); // stack object until VBOs will be used std::vector<VERTEX> vecVertices(6 * m_vertex.size() / 4); diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoPlayer/VideoRenderers/RenderManager.cpp index b6722ff1d8..b0473573d8 100644 --- a/xbmc/cores/VideoPlayer/VideoRenderers/RenderManager.cpp +++ b/xbmc/cores/VideoPlayer/VideoRenderers/RenderManager.cpp @@ -304,7 +304,7 @@ void CRenderManager::FrameMove() lock.unlock(); if (!Configure()) return; - + UpdateLatencyTweak(); firstFrame = true; FrameWait(50ms); } @@ -890,11 +890,14 @@ void CRenderManager::PresentBlend(bool clear, DWORD flags, DWORD alpha) void CRenderManager::UpdateLatencyTweak() { float fps = CServiceBroker::GetWinSystem()->GetGfxContext().GetFPS(); + const bool isHDREnabled = CServiceBroker::GetWinSystem()->GetOSHDRStatus() == HDR_STATUS::HDR_ON; + float refresh = fps; if (CServiceBroker::GetWinSystem()->GetGfxContext().GetVideoResolution() == RES_WINDOW) refresh = 0; // No idea about refresh rate when windowed, just get the default latency m_latencyTweak = static_cast<double>( - CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->GetLatencyTweak(refresh)); + CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->GetLatencyTweak(refresh, + isHDREnabled)); } void CRenderManager::UpdateResolution() diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/VideoShaders/YUV2RGBShaderGL.h b/xbmc/cores/VideoPlayer/VideoRenderers/VideoShaders/YUV2RGBShaderGL.h index 6604291049..d551ad3d06 100644 --- a/xbmc/cores/VideoPlayer/VideoRenderers/VideoShaders/YUV2RGBShaderGL.h +++ b/xbmc/cores/VideoPlayer/VideoRenderers/VideoShaders/YUV2RGBShaderGL.h @@ -82,7 +82,7 @@ protected: bool m_hasLightMetadata = false; AVContentLightMetadata m_lightMetadata; bool m_toneMapping = false; - ETONEMAPMETHOD m_toneMappingMethod = VS_TONEMAPMETHOD_REINHARD; + ETONEMAPMETHOD m_toneMappingMethod = VS_TONEMAPMETHOD_OFF; float m_toneMappingParam = 1.0; bool m_colorConversion{false}; diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/VideoShaders/YUV2RGBShaderGLES.h b/xbmc/cores/VideoPlayer/VideoRenderers/VideoShaders/YUV2RGBShaderGLES.h index 44b1a8221a..917f0f35f4 100644 --- a/xbmc/cores/VideoPlayer/VideoRenderers/VideoShaders/YUV2RGBShaderGLES.h +++ b/xbmc/cores/VideoPlayer/VideoRenderers/VideoShaders/YUV2RGBShaderGLES.h @@ -69,7 +69,7 @@ class BaseYUV2RGBGLSLShader : public CGLSLShaderProgram bool m_hasLightMetadata{false}; AVContentLightMetadata m_lightMetadata; bool m_toneMapping{false}; - ETONEMAPMETHOD m_toneMappingMethod{VS_TONEMAPMETHOD_REINHARD}; + ETONEMAPMETHOD m_toneMappingMethod{VS_TONEMAPMETHOD_OFF}; float m_toneMappingParam{1.0}; bool m_colorConversion{false}; diff --git a/xbmc/cores/VideoSettings.cpp b/xbmc/cores/VideoSettings.cpp index ec474b3ff9..6764e4c5f1 100644 --- a/xbmc/cores/VideoSettings.cpp +++ b/xbmc/cores/VideoSettings.cpp @@ -39,7 +39,7 @@ CVideoSettings::CVideoSettings() m_StereoMode = 0; m_StereoInvert = false; m_VideoStream = -1; - m_ToneMapMethod = VS_TONEMAPMETHOD_REINHARD; + m_ToneMapMethod = VS_TONEMAPMETHOD_OFF; m_ToneMapParam = 1.0f; m_Orientation = 0; m_CenterMixLevel = 0; diff --git a/xbmc/cores/paplayer/AudioDecoder.cpp b/xbmc/cores/paplayer/AudioDecoder.cpp index 03dc907c0b..a960776287 100644 --- a/xbmc/cores/paplayer/AudioDecoder.cpp +++ b/xbmc/cores/paplayer/AudioDecoder.cpp @@ -75,7 +75,7 @@ bool CAudioDecoder::Create(const CFileItem &file, int64_t seekOffset) filecache = settings->GetInt(CSettings::SETTING_CACHE_HARDDISK); else if ( file.IsOnDVD() ) filecache = settings->GetInt(CSettings::SETTING_CACHEAUDIO_DVDROM); - else if ( file.IsOnLAN() ) + else if (file.IsOnLAN()) filecache = settings->GetInt(CSettings::SETTING_CACHEAUDIO_LAN); // create our codec diff --git a/xbmc/cores/playercorefactory/PlayerCoreFactory.cpp b/xbmc/cores/playercorefactory/PlayerCoreFactory.cpp index f9472c027e..4518796b30 100644 --- a/xbmc/cores/playercorefactory/PlayerCoreFactory.cpp +++ b/xbmc/cores/playercorefactory/PlayerCoreFactory.cpp @@ -25,12 +25,15 @@ #include "utils/StringUtils.h" #include "utils/XMLUtils.h" #include "utils/log.h" +#include "video/VideoFileItemClassify.h" #include <mutex> #include <sstream> #define PLAYERCOREFACTORY_XML "playercorefactory.xml" +using namespace KODI; + CPlayerCoreFactory::CPlayerCoreFactory(const CProfileManager& profileManager) : m_settings(CServiceBroker::GetSettingsComponent()->GetSettings()), m_profileManager(profileManager) @@ -141,7 +144,7 @@ void CPlayerCoreFactory::GetPlayers(const CFileItem& item, std::vector<std::stri // "videodefaultplayer" if (defaultInputstreamPlayerOverride == ForcedPlayer::VIDEO_DEFAULT || (defaultInputstreamPlayerOverride == ForcedPlayer::NONE && - (item.IsVideo() || (!item.IsAudio() && !item.IsGame())))) + (VIDEO::IsVideo(item) || (!item.IsAudio() && !item.IsGame())))) { int idx = GetPlayerIndex("videodefaultplayer"); if (idx > -1) diff --git a/xbmc/cores/playercorefactory/PlayerSelectionRule.cpp b/xbmc/cores/playercorefactory/PlayerSelectionRule.cpp index cad7399346..d8441dd0c6 100644 --- a/xbmc/cores/playercorefactory/PlayerSelectionRule.cpp +++ b/xbmc/cores/playercorefactory/PlayerSelectionRule.cpp @@ -19,10 +19,13 @@ #include "utils/XBMCTinyXML.h" #include "utils/XMLUtils.h" #include "utils/log.h" +#include "video/VideoFileItemClassify.h" #include "video/VideoInfoTag.h" #include <algorithm> +using namespace KODI; + CPlayerSelectionRule::CPlayerSelectionRule(TiXmlElement* pRule) { Initialize(pRule); @@ -63,9 +66,11 @@ void CPlayerSelectionRule::Initialize(TiXmlElement* pRule) m_videoCodec = XMLUtils::GetAttribute(pRule, "videocodec"); m_videoResolution = XMLUtils::GetAttribute(pRule, "videoresolution"); m_videoAspect = XMLUtils::GetAttribute(pRule, "videoaspect"); + m_hdrType = XMLUtils::GetAttribute(pRule, "hdrtype"); m_bStreamDetails = m_audioCodec.length() > 0 || m_audioChannels.length() > 0 || - m_videoCodec.length() > 0 || m_videoResolution.length() > 0 || m_videoAspect.length() > 0; + m_videoCodec.length() > 0 || m_videoResolution.length() > 0 || + m_videoAspect.length() > 0 || m_hdrType.length() > 0; if (m_bStreamDetails && !CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_MYVIDEOS_EXTRACTFLAGS)) { @@ -114,7 +119,7 @@ void CPlayerSelectionRule::GetPlayers(const CFileItem& item, std::vector<std::st return; if (m_tAudio >= 0 && (m_tAudio > 0) != item.IsAudio()) return; - if (m_tVideo >= 0 && (m_tVideo > 0) != item.IsVideo()) + if (m_tVideo >= 0 && (m_tVideo > 0) != VIDEO::IsVideo(item)) return; if (m_tGame >= 0 && (m_tGame > 0) != item.IsGame()) return; @@ -123,11 +128,11 @@ void CPlayerSelectionRule::GetPlayers(const CFileItem& item, std::vector<std::st if (m_tRemote >= 0 && (m_tRemote > 0) != item.IsRemote()) return; - if (m_tBD >= 0 && (m_tBD > 0) != (item.IsBDFile() && item.IsOnDVD())) + if (m_tBD >= 0 && (m_tBD > 0) != (VIDEO::IsBDFile(item) && item.IsOnDVD())) return; if (m_tDVD >= 0 && (m_tDVD > 0) != item.IsDVD()) return; - if (m_tDVDFile >= 0 && (m_tDVDFile > 0) != item.IsDVDFile()) + if (m_tDVDFile >= 0 && (m_tDVDFile > 0) != VIDEO::IsDVDFile(item)) return; if (m_tDiscImage >= 0 && (m_tDiscImage > 0) != item.IsDiscImage()) return; @@ -166,6 +171,13 @@ void CPlayerSelectionRule::GetPlayers(const CFileItem& item, std::vector<std::st if (CompileRegExp(m_videoAspect, regExp) && !MatchesRegExp(CStreamDetails::VideoAspectToAspectDescription(streamDetails.GetVideoAspect()), regExp)) return; + + std::string hdrType{streamDetails.GetVideoHdrType()}; + if (hdrType.length() == 0) + hdrType = "none"; + + if (CompileRegExp(m_hdrType, regExp) && !MatchesRegExp(hdrType, regExp)) + return; } CURL url(item.GetDynPath()); diff --git a/xbmc/cores/playercorefactory/PlayerSelectionRule.h b/xbmc/cores/playercorefactory/PlayerSelectionRule.h index b818d8cb45..694d5c9fb6 100644 --- a/xbmc/cores/playercorefactory/PlayerSelectionRule.h +++ b/xbmc/cores/playercorefactory/PlayerSelectionRule.h @@ -55,6 +55,7 @@ private: std::string m_videoCodec; std::string m_videoResolution; std::string m_videoAspect; + std::string m_hdrType; std::string m_playerName; diff --git a/xbmc/dialogs/GUIDialogColorPicker.cpp b/xbmc/dialogs/GUIDialogColorPicker.cpp index b4bc59c355..58814de392 100644 --- a/xbmc/dialogs/GUIDialogColorPicker.cpp +++ b/xbmc/dialogs/GUIDialogColorPicker.cpp @@ -9,6 +9,7 @@ #include "GUIDialogColorPicker.h" #include "FileItem.h" +#include "FileItemList.h" #include "filesystem/SpecialProtocol.h" #include "guilib/GUIColorManager.h" #include "guilib/GUIMessage.h" diff --git a/xbmc/dialogs/GUIDialogFileBrowser.cpp b/xbmc/dialogs/GUIDialogFileBrowser.cpp index 9181313747..8fecfb62b6 100644 --- a/xbmc/dialogs/GUIDialogFileBrowser.cpp +++ b/xbmc/dialogs/GUIDialogFileBrowser.cpp @@ -10,6 +10,7 @@ #include "AutoSwitch.h" #include "FileItem.h" +#include "FileItemList.h" #include "GUIDialogContextMenu.h" #include "GUIDialogMediaSource.h" #include "GUIDialogYesNo.h" diff --git a/xbmc/dialogs/GUIDialogMediaFilter.cpp b/xbmc/dialogs/GUIDialogMediaFilter.cpp index 14340c85bb..55b1013967 100644 --- a/xbmc/dialogs/GUIDialogMediaFilter.cpp +++ b/xbmc/dialogs/GUIDialogMediaFilter.cpp @@ -10,6 +10,7 @@ #include "DbUrl.h" #include "FileItem.h" +#include "FileItemList.h" #include "GUIUserMessages.h" #include "ServiceBroker.h" #include "XBDateTime.h" diff --git a/xbmc/dialogs/GUIDialogMediaSource.cpp b/xbmc/dialogs/GUIDialogMediaSource.cpp index 72b80bff53..0afbc2d060 100644 --- a/xbmc/dialogs/GUIDialogMediaSource.cpp +++ b/xbmc/dialogs/GUIDialogMediaSource.cpp @@ -9,6 +9,7 @@ #include "GUIDialogMediaSource.h" #include "FileItem.h" +#include "FileItemList.h" #include "GUIDialogFileBrowser.h" #include "GUIDialogYesNo.h" #include "PasswordManager.h" diff --git a/xbmc/dialogs/GUIDialogSelect.cpp b/xbmc/dialogs/GUIDialogSelect.cpp index c6add4bd16..0f99e2765b 100644 --- a/xbmc/dialogs/GUIDialogSelect.cpp +++ b/xbmc/dialogs/GUIDialogSelect.cpp @@ -9,6 +9,7 @@ #include "GUIDialogSelect.h" #include "FileItem.h" +#include "FileItemList.h" #include "guilib/GUIMessage.h" #include "guilib/LocalizeStrings.h" #include "input/actions/ActionIDs.h" diff --git a/xbmc/dialogs/GUIDialogSimpleMenu.cpp b/xbmc/dialogs/GUIDialogSimpleMenu.cpp index 0d4d11a830..61016f477a 100644 --- a/xbmc/dialogs/GUIDialogSimpleMenu.cpp +++ b/xbmc/dialogs/GUIDialogSimpleMenu.cpp @@ -10,6 +10,7 @@ #include "GUIDialogSimpleMenu.h" #include "FileItem.h" +#include "FileItemList.h" #include "GUIDialogSelect.h" #include "ServiceBroker.h" #include "URL.h" @@ -25,8 +26,11 @@ #include "utils/URIUtils.h" #include "utils/Variant.h" #include "utils/log.h" +#include "video/VideoFileItemClassify.h" #include "video/VideoInfoTag.h" +using namespace KODI; + namespace { class CGetDirectoryItems : public IRunnable @@ -54,7 +58,7 @@ bool CGUIDialogSimpleMenu::ShowPlaySelection(CFileItem& item) if (CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_DISC_PLAYBACK) != BD_PLAYBACK_SIMPLE_MENU) return true; - if (item.IsBDFile()) + if (VIDEO::IsBDFile(item)) { std::string root = URIUtils::GetParentPath(item.GetDynPath()); URIUtils::RemoveSlashAtEnd(root); diff --git a/xbmc/dialogs/GUIDialogSmartPlaylistEditor.cpp b/xbmc/dialogs/GUIDialogSmartPlaylistEditor.cpp index 98714d38dc..24a0675c40 100644 --- a/xbmc/dialogs/GUIDialogSmartPlaylistEditor.cpp +++ b/xbmc/dialogs/GUIDialogSmartPlaylistEditor.cpp @@ -9,6 +9,7 @@ #include "GUIDialogSmartPlaylistEditor.h" #include "FileItem.h" +#include "FileItemList.h" #include "GUIDialogContextMenu.h" #include "GUIDialogSelect.h" #include "GUIDialogSmartPlaylistRule.h" diff --git a/xbmc/dialogs/GUIDialogSmartPlaylistRule.cpp b/xbmc/dialogs/GUIDialogSmartPlaylistRule.cpp index 671219bc38..9040f48340 100644 --- a/xbmc/dialogs/GUIDialogSmartPlaylistRule.cpp +++ b/xbmc/dialogs/GUIDialogSmartPlaylistRule.cpp @@ -9,6 +9,7 @@ #include "GUIDialogSmartPlaylistRule.h" #include "FileItem.h" +#include "FileItemList.h" #include "GUIDialogFileBrowser.h" #include "GUIDialogSelect.h" #include "ServiceBroker.h" diff --git a/xbmc/events/windows/GUIViewStateEventLog.cpp b/xbmc/events/windows/GUIViewStateEventLog.cpp index 1f6dd6654f..8734f12571 100644 --- a/xbmc/events/windows/GUIViewStateEventLog.cpp +++ b/xbmc/events/windows/GUIViewStateEventLog.cpp @@ -9,6 +9,7 @@ #include "GUIViewStateEventLog.h" #include "FileItem.h" +#include "FileItemList.h" #include "guilib/WindowIDs.h" #include "view/ViewState.h" #include "windowing/GraphicContext.h" diff --git a/xbmc/events/windows/GUIWindowEventLog.cpp b/xbmc/events/windows/GUIWindowEventLog.cpp index fdd9a37b00..90e8c29f71 100644 --- a/xbmc/events/windows/GUIWindowEventLog.cpp +++ b/xbmc/events/windows/GUIWindowEventLog.cpp @@ -9,6 +9,7 @@ #include "GUIWindowEventLog.h" #include "FileItem.h" +#include "FileItemList.h" #include "GUIUserMessages.h" #include "ServiceBroker.h" #include "URL.h" diff --git a/xbmc/favourites/FavouritesService.cpp b/xbmc/favourites/FavouritesService.cpp index 97f55073c3..b175a6c089 100644 --- a/xbmc/favourites/FavouritesService.cpp +++ b/xbmc/favourites/FavouritesService.cpp @@ -21,9 +21,12 @@ #include "utils/URIUtils.h" #include "utils/XBMCTinyXML2.h" #include "utils/log.h" +#include "video/VideoFileItemClassify.h" #include <mutex> +using namespace KODI; + namespace { bool IsMediasourceOfFavItemUnlocked(const std::shared_ptr<CFileItem>& item) @@ -71,7 +74,7 @@ bool IsMediasourceOfFavItemUnlocked(const std::shared_ptr<CFileItem>& item) if (action == CFavouritesURL::Action::PLAY_MEDIA) { - if (itemToCheck.IsVideo()) + if (VIDEO::IsVideo(itemToCheck)) { if (!profileManager->GetCurrentProfile().videoLocked()) return g_passwordManager.IsMediaFileUnlocked("video", itemToCheck.GetPath()); diff --git a/xbmc/favourites/FavouritesService.h b/xbmc/favourites/FavouritesService.h index ccda06253d..468961ecb3 100644 --- a/xbmc/favourites/FavouritesService.h +++ b/xbmc/favourites/FavouritesService.h @@ -9,6 +9,7 @@ #pragma once #include "FileItem.h" +#include "FileItemList.h" #include "threads/CriticalSection.h" #include "utils/EventStream.h" diff --git a/xbmc/favourites/GUIViewStateFavourites.cpp b/xbmc/favourites/GUIViewStateFavourites.cpp index 7bb5ff1195..3343167b5c 100644 --- a/xbmc/favourites/GUIViewStateFavourites.cpp +++ b/xbmc/favourites/GUIViewStateFavourites.cpp @@ -8,7 +8,7 @@ #include "GUIViewStateFavourites.h" -#include "FileItem.h" +#include "FileItemList.h" #include "guilib/WindowIDs.h" CGUIViewStateFavourites::CGUIViewStateFavourites(const CFileItemList& items) : CGUIViewState(items) diff --git a/xbmc/filesystem/AddonsDirectory.cpp b/xbmc/filesystem/AddonsDirectory.cpp index 1439ae054b..aba97cae08 100644 --- a/xbmc/filesystem/AddonsDirectory.cpp +++ b/xbmc/filesystem/AddonsDirectory.cpp @@ -9,6 +9,7 @@ #include "AddonsDirectory.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "URL.h" #include "addons/AddonDatabase.h" @@ -789,29 +790,27 @@ void CAddonsDirectory::GenerateAddonListing(const CURL& path, addon->Version()); bool disabled = CServiceBroker::GetAddonMgr().IsAddonDisabled(addon->ID()); - std::function<bool(bool)> CheckOutdatedOrUpdate = [&](bool checkOutdated) -> bool { - auto mapEntry = addonsWithUpdate.find(addon->ID()); - if (mapEntry != addonsWithUpdate.end()) - { - const std::shared_ptr<IAddon>& checkedObject = - checkOutdated ? mapEntry->second.m_installed : mapEntry->second.m_update; - - return (checkedObject->Origin() == addon->Origin() && - checkedObject->Version() == addon->Version()); - } - return false; - }; - - bool isUpdate = CheckOutdatedOrUpdate(false); // check if it's an available update - bool hasUpdate = CheckOutdatedOrUpdate(true); // check if it's an outdated addon - + bool isUpdate{false}; + bool hasUpdate{false}; std::string validUpdateVersion; std::string validUpdateOrigin; - if (hasUpdate) + + auto _ = addonsWithUpdate.find(addon->ID()); + if (_ != addonsWithUpdate.end()) { - auto mapEntry = addonsWithUpdate.find(addon->ID()); - validUpdateVersion = mapEntry->second.m_update->Version().asString(); - validUpdateOrigin = mapEntry->second.m_update->Origin(); + auto [installed, update] = _->second; + + auto CheckAddon = [&addon](const std::shared_ptr<IAddon>& _) + { return _->Origin() == addon->Origin() && _->Version() == addon->Version(); }; + + isUpdate = CheckAddon(update); // check if listed add-on is update to an installed add-on + hasUpdate = CheckAddon(installed); // check if installed add-on has an update available + + if (hasUpdate) + { + validUpdateVersion = update->Version().asString(); + validUpdateOrigin = update->Origin(); + } } bool fromOfficialRepo = CAddonRepos::IsFromOfficialRepo(addon, CheckAddonPath::CHOICE_NO); diff --git a/xbmc/filesystem/AudioBookFileDirectory.cpp b/xbmc/filesystem/AudioBookFileDirectory.cpp index 4b56c6ccc2..2ca214c74e 100644 --- a/xbmc/filesystem/AudioBookFileDirectory.cpp +++ b/xbmc/filesystem/AudioBookFileDirectory.cpp @@ -8,6 +8,7 @@ #include "AudioBookFileDirectory.h" #include "FileItem.h" +#include "FileItemList.h" #include "TextureDatabase.h" #include "URL.h" #include "Util.h" diff --git a/xbmc/filesystem/BlurayCallback.cpp b/xbmc/filesystem/BlurayCallback.cpp index 4849eef1a7..72b745381a 100644 --- a/xbmc/filesystem/BlurayCallback.cpp +++ b/xbmc/filesystem/BlurayCallback.cpp @@ -9,6 +9,7 @@ #include "BlurayCallback.h" #include "FileItem.h" +#include "FileItemList.h" #include "filesystem/Directory.h" #include "filesystem/File.h" #include "utils/URIUtils.h" diff --git a/xbmc/filesystem/BlurayDirectory.cpp b/xbmc/filesystem/BlurayDirectory.cpp index b6c339a110..322b662fd9 100644 --- a/xbmc/filesystem/BlurayDirectory.cpp +++ b/xbmc/filesystem/BlurayDirectory.cpp @@ -9,6 +9,7 @@ #include "File.h" #include "FileItem.h" +#include "FileItemList.h" #include "LangInfo.h" #include "URL.h" #include "filesystem/BlurayCallback.h" diff --git a/xbmc/filesystem/CDDADirectory.cpp b/xbmc/filesystem/CDDADirectory.cpp index 9b6beaaeea..8520347108 100644 --- a/xbmc/filesystem/CDDADirectory.cpp +++ b/xbmc/filesystem/CDDADirectory.cpp @@ -10,6 +10,7 @@ #include "File.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "music/MusicDatabase.h" #include "storage/MediaManager.h" diff --git a/xbmc/filesystem/DAVDirectory.cpp b/xbmc/filesystem/DAVDirectory.cpp index 0a203e7807..08905fca31 100644 --- a/xbmc/filesystem/DAVDirectory.cpp +++ b/xbmc/filesystem/DAVDirectory.cpp @@ -12,6 +12,7 @@ #include "DAVCommon.h" #include "DAVFile.h" #include "FileItem.h" +#include "FileItemList.h" #include "URL.h" #include "utils/StringUtils.h" #include "utils/URIUtils.h" diff --git a/xbmc/filesystem/Directorization.h b/xbmc/filesystem/Directorization.h index f413635e6d..d41c71bae9 100644 --- a/xbmc/filesystem/Directorization.h +++ b/xbmc/filesystem/Directorization.h @@ -9,6 +9,7 @@ #pragma once #include "FileItem.h" +#include "FileItemList.h" #include "URL.h" #include "utils/CharsetConverter.h" #include "utils/StringUtils.h" diff --git a/xbmc/filesystem/Directory.cpp b/xbmc/filesystem/Directory.cpp index fbcdb4d0d4..cfa0fd9b53 100644 --- a/xbmc/filesystem/Directory.cpp +++ b/xbmc/filesystem/Directory.cpp @@ -12,6 +12,7 @@ #include "DirectoryFactory.h" #include "FileDirectoryFactory.h" #include "FileItem.h" +#include "FileItemList.h" #include "PasswordManager.h" #include "ServiceBroker.h" #include "URL.h" @@ -25,7 +26,9 @@ #include "utils/JobManager.h" #include "utils/URIUtils.h" #include "utils/log.h" +#include "video/VideoFileItemClassify.h" +using namespace KODI; using namespace XFILE; using namespace std::chrono_literals; @@ -282,7 +285,8 @@ bool CDirectory::GetDirectory(const CURL& url, // Should any of the files we read be treated as a directory? // Disable for database folders, as they already contain the extracted items - if (!(hints.flags & DIR_FLAG_NO_FILE_DIRS) && !items.IsMusicDb() && !items.IsVideoDb() && !items.IsSmartPlayList()) + if (!(hints.flags & DIR_FLAG_NO_FILE_DIRS) && !items.IsMusicDb() && !VIDEO::IsVideoDb(items) && + !items.IsSmartPlayList()) FilterFileDirectories(items, hints.mask); // Correct items for path substitution diff --git a/xbmc/filesystem/DirectoryCache.cpp b/xbmc/filesystem/DirectoryCache.cpp index f3fd1fb7ae..f1053a904b 100644 --- a/xbmc/filesystem/DirectoryCache.cpp +++ b/xbmc/filesystem/DirectoryCache.cpp @@ -10,6 +10,7 @@ #include "Directory.h" #include "FileItem.h" +#include "FileItemList.h" #include "URL.h" #include "utils/StringUtils.h" #include "utils/URIUtils.h" diff --git a/xbmc/filesystem/EventsDirectory.cpp b/xbmc/filesystem/EventsDirectory.cpp index d21261944b..bc8cfdf0af 100644 --- a/xbmc/filesystem/EventsDirectory.cpp +++ b/xbmc/filesystem/EventsDirectory.cpp @@ -10,6 +10,7 @@ #include "EventsDirectory.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "URL.h" #include "events/EventLog.h" diff --git a/xbmc/filesystem/FTPDirectory.cpp b/xbmc/filesystem/FTPDirectory.cpp index 46d3d7d748..2b7117a7a8 100644 --- a/xbmc/filesystem/FTPDirectory.cpp +++ b/xbmc/filesystem/FTPDirectory.cpp @@ -11,6 +11,7 @@ #include "CurlFile.h" #include "FTPParse.h" #include "FileItem.h" +#include "FileItemList.h" #include "URL.h" #include "utils/CharsetConverter.h" #include "utils/StringUtils.h" diff --git a/xbmc/filesystem/HTTPDirectory.cpp b/xbmc/filesystem/HTTPDirectory.cpp index 0097b7f15c..1db70696d1 100644 --- a/xbmc/filesystem/HTTPDirectory.cpp +++ b/xbmc/filesystem/HTTPDirectory.cpp @@ -10,6 +10,7 @@ #include "CurlFile.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "URL.h" #include "settings/AdvancedSettings.h" diff --git a/xbmc/filesystem/ISO9660Directory.cpp b/xbmc/filesystem/ISO9660Directory.cpp index 542f12c577..a396b996b0 100644 --- a/xbmc/filesystem/ISO9660Directory.cpp +++ b/xbmc/filesystem/ISO9660Directory.cpp @@ -9,6 +9,7 @@ #include "ISO9660Directory.h" #include "FileItem.h" +#include "FileItemList.h" #include "URL.h" #include "utils/URIUtils.h" diff --git a/xbmc/filesystem/LibraryDirectory.cpp b/xbmc/filesystem/LibraryDirectory.cpp index 8f814950ae..ec5a16bfc0 100644 --- a/xbmc/filesystem/LibraryDirectory.cpp +++ b/xbmc/filesystem/LibraryDirectory.cpp @@ -10,6 +10,7 @@ #include "Directory.h" #include "FileItem.h" +#include "FileItemList.h" #include "GUIInfoManager.h" #include "SmartPlaylistDirectory.h" #include "URL.h" diff --git a/xbmc/filesystem/MultiPathDirectory.cpp b/xbmc/filesystem/MultiPathDirectory.cpp index 4cdcfcc4ce..b57dd98427 100644 --- a/xbmc/filesystem/MultiPathDirectory.cpp +++ b/xbmc/filesystem/MultiPathDirectory.cpp @@ -10,6 +10,7 @@ #include "Directory.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "URL.h" #include "Util.h" diff --git a/xbmc/filesystem/MusicDatabaseDirectory.cpp b/xbmc/filesystem/MusicDatabaseDirectory.cpp index f998d559f7..0365f86617 100644 --- a/xbmc/filesystem/MusicDatabaseDirectory.cpp +++ b/xbmc/filesystem/MusicDatabaseDirectory.cpp @@ -9,6 +9,7 @@ #include "MusicDatabaseDirectory.h" #include "FileItem.h" +#include "FileItemList.h" #include "MusicDatabaseDirectory/QueryParams.h" #include "ServiceBroker.h" #include "filesystem/File.h" diff --git a/xbmc/filesystem/MusicDatabaseDirectory/DirectoryNode.cpp b/xbmc/filesystem/MusicDatabaseDirectory/DirectoryNode.cpp index 00e1bce6f3..cb143c1ecc 100644 --- a/xbmc/filesystem/MusicDatabaseDirectory/DirectoryNode.cpp +++ b/xbmc/filesystem/MusicDatabaseDirectory/DirectoryNode.cpp @@ -25,6 +25,7 @@ #include "DirectoryNodeSongTop100.h" #include "DirectoryNodeTop100.h" #include "FileItem.h" +#include "FileItemList.h" #include "QueryParams.h" #include "URL.h" #include "utils/StringUtils.h" diff --git a/xbmc/filesystem/MusicDatabaseDirectory/DirectoryNodeAlbumRecentlyAdded.cpp b/xbmc/filesystem/MusicDatabaseDirectory/DirectoryNodeAlbumRecentlyAdded.cpp index f274b59341..013c30bd65 100644 --- a/xbmc/filesystem/MusicDatabaseDirectory/DirectoryNodeAlbumRecentlyAdded.cpp +++ b/xbmc/filesystem/MusicDatabaseDirectory/DirectoryNodeAlbumRecentlyAdded.cpp @@ -9,6 +9,7 @@ #include "DirectoryNodeAlbumRecentlyAdded.h" #include "FileItem.h" +#include "FileItemList.h" #include "guilib/LocalizeStrings.h" #include "music/MusicDatabase.h" #include "utils/StringUtils.h" diff --git a/xbmc/filesystem/MusicDatabaseDirectory/DirectoryNodeAlbumRecentlyPlayed.cpp b/xbmc/filesystem/MusicDatabaseDirectory/DirectoryNodeAlbumRecentlyPlayed.cpp index 77940c27f1..8080d5e7e0 100644 --- a/xbmc/filesystem/MusicDatabaseDirectory/DirectoryNodeAlbumRecentlyPlayed.cpp +++ b/xbmc/filesystem/MusicDatabaseDirectory/DirectoryNodeAlbumRecentlyPlayed.cpp @@ -9,6 +9,7 @@ #include "DirectoryNodeAlbumRecentlyPlayed.h" #include "FileItem.h" +#include "FileItemList.h" #include "guilib/LocalizeStrings.h" #include "music/MusicDatabase.h" #include "utils/StringUtils.h" diff --git a/xbmc/filesystem/MusicDatabaseDirectory/DirectoryNodeAlbumTop100.cpp b/xbmc/filesystem/MusicDatabaseDirectory/DirectoryNodeAlbumTop100.cpp index 88ffaff77a..753b756ac8 100644 --- a/xbmc/filesystem/MusicDatabaseDirectory/DirectoryNodeAlbumTop100.cpp +++ b/xbmc/filesystem/MusicDatabaseDirectory/DirectoryNodeAlbumTop100.cpp @@ -9,6 +9,7 @@ #include "DirectoryNodeAlbumTop100.h" #include "FileItem.h" +#include "FileItemList.h" #include "music/MusicDatabase.h" #include "utils/StringUtils.h" diff --git a/xbmc/filesystem/MusicDatabaseDirectory/DirectoryNodeOverview.cpp b/xbmc/filesystem/MusicDatabaseDirectory/DirectoryNodeOverview.cpp index fefeb6d666..cca955e4b7 100644 --- a/xbmc/filesystem/MusicDatabaseDirectory/DirectoryNodeOverview.cpp +++ b/xbmc/filesystem/MusicDatabaseDirectory/DirectoryNodeOverview.cpp @@ -9,6 +9,7 @@ #include "DirectoryNodeOverview.h" #include "FileItem.h" +#include "FileItemList.h" #include "guilib/LocalizeStrings.h" #include "music/MusicDatabase.h" #include "utils/StringUtils.h" diff --git a/xbmc/filesystem/MusicDatabaseDirectory/DirectoryNodeTop100.cpp b/xbmc/filesystem/MusicDatabaseDirectory/DirectoryNodeTop100.cpp index fff9228b58..36bacfeb55 100644 --- a/xbmc/filesystem/MusicDatabaseDirectory/DirectoryNodeTop100.cpp +++ b/xbmc/filesystem/MusicDatabaseDirectory/DirectoryNodeTop100.cpp @@ -9,6 +9,7 @@ #include "DirectoryNodeTop100.h" #include "FileItem.h" +#include "FileItemList.h" #include "guilib/LocalizeStrings.h" #include "utils/StringUtils.h" diff --git a/xbmc/filesystem/MusicFileDirectory.cpp b/xbmc/filesystem/MusicFileDirectory.cpp index b3c7749c47..51340b54eb 100644 --- a/xbmc/filesystem/MusicFileDirectory.cpp +++ b/xbmc/filesystem/MusicFileDirectory.cpp @@ -9,6 +9,7 @@ #include "MusicFileDirectory.h" #include "FileItem.h" +#include "FileItemList.h" #include "URL.h" #include "guilib/LocalizeStrings.h" #include "utils/StringUtils.h" diff --git a/xbmc/filesystem/MusicSearchDirectory.cpp b/xbmc/filesystem/MusicSearchDirectory.cpp index 1d1868ab1a..2f8c8200cc 100644 --- a/xbmc/filesystem/MusicSearchDirectory.cpp +++ b/xbmc/filesystem/MusicSearchDirectory.cpp @@ -9,6 +9,7 @@ #include "MusicSearchDirectory.h" #include "FileItem.h" +#include "FileItemList.h" #include "URL.h" #include "guilib/LocalizeStrings.h" #include "music/MusicDatabase.h" diff --git a/xbmc/filesystem/NFSDirectory.cpp b/xbmc/filesystem/NFSDirectory.cpp index 7feba534c7..6d3588dccc 100644 --- a/xbmc/filesystem/NFSDirectory.cpp +++ b/xbmc/filesystem/NFSDirectory.cpp @@ -13,6 +13,7 @@ #endif #include "FileItem.h" +#include "FileItemList.h" #include "NFSDirectory.h" #include "utils/StringUtils.h" #include "utils/URIUtils.h" diff --git a/xbmc/filesystem/PlaylistDirectory.cpp b/xbmc/filesystem/PlaylistDirectory.cpp index 8be88dc581..f656c77dab 100644 --- a/xbmc/filesystem/PlaylistDirectory.cpp +++ b/xbmc/filesystem/PlaylistDirectory.cpp @@ -9,6 +9,7 @@ #include "PlaylistDirectory.h" #include "FileItem.h" +#include "FileItemList.h" #include "PlayListPlayer.h" #include "ServiceBroker.h" #include "URL.h" diff --git a/xbmc/filesystem/PlaylistFileDirectory.cpp b/xbmc/filesystem/PlaylistFileDirectory.cpp index 2bdb243680..108c9c9a65 100644 --- a/xbmc/filesystem/PlaylistFileDirectory.cpp +++ b/xbmc/filesystem/PlaylistFileDirectory.cpp @@ -9,6 +9,7 @@ #include "PlaylistFileDirectory.h" #include "FileItem.h" +#include "FileItemList.h" #include "URL.h" #include "filesystem/File.h" #include "playlists/PlayList.h" diff --git a/xbmc/filesystem/PluginDirectory.cpp b/xbmc/filesystem/PluginDirectory.cpp index cf3ded1286..4269fa4236 100644 --- a/xbmc/filesystem/PluginDirectory.cpp +++ b/xbmc/filesystem/PluginDirectory.cpp @@ -9,6 +9,7 @@ #include "PluginDirectory.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "URL.h" #include "addons/AddonInstaller.h" diff --git a/xbmc/filesystem/RSSDirectory.cpp b/xbmc/filesystem/RSSDirectory.cpp index 65bc876c6c..ac0a704221 100644 --- a/xbmc/filesystem/RSSDirectory.cpp +++ b/xbmc/filesystem/RSSDirectory.cpp @@ -10,6 +10,7 @@ #include "CurlFile.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "URL.h" #include "settings/AdvancedSettings.h" diff --git a/xbmc/filesystem/ResourceDirectory.cpp b/xbmc/filesystem/ResourceDirectory.cpp index c3623d0ce0..6526fb56be 100644 --- a/xbmc/filesystem/ResourceDirectory.cpp +++ b/xbmc/filesystem/ResourceDirectory.cpp @@ -9,6 +9,7 @@ #include "ResourceDirectory.h" #include "FileItem.h" +#include "FileItemList.h" #include "URL.h" #include "filesystem/Directory.h" #include "filesystem/ResourceFile.h" diff --git a/xbmc/filesystem/SmartPlaylistDirectory.cpp b/xbmc/filesystem/SmartPlaylistDirectory.cpp index a45e796071..b3d361ecc2 100644 --- a/xbmc/filesystem/SmartPlaylistDirectory.cpp +++ b/xbmc/filesystem/SmartPlaylistDirectory.cpp @@ -9,6 +9,7 @@ #include "SmartPlaylistDirectory.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "filesystem/Directory.h" #include "filesystem/File.h" diff --git a/xbmc/filesystem/SourcesDirectory.cpp b/xbmc/filesystem/SourcesDirectory.cpp index b83ee2ed49..0f36fbb88e 100644 --- a/xbmc/filesystem/SourcesDirectory.cpp +++ b/xbmc/filesystem/SourcesDirectory.cpp @@ -9,6 +9,7 @@ #include "SourcesDirectory.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "URL.h" #include "Util.h" @@ -19,7 +20,9 @@ #include "storage/MediaManager.h" #include "utils/FileUtils.h" #include "utils/URIUtils.h" +#include "video/VideoFileItemClassify.h" +using namespace KODI; using namespace XFILE; CSourcesDirectory::CSourcesDirectory(void) = default; @@ -68,10 +71,8 @@ bool CSourcesDirectory::GetDirectory(const VECSOURCES &sources, CFileItemList &i else if ( pItem->IsPath("special://musicplaylists/") || pItem->IsPath("special://videoplaylists/")) strIcon = "DefaultPlaylist.png"; - else if ( pItem->IsVideoDb() - || pItem->IsMusicDb() - || pItem->IsPlugin() - || pItem->IsPath("musicsearch://")) + else if (VIDEO::IsVideoDb(*pItem) || pItem->IsMusicDb() || pItem->IsPlugin() || + pItem->IsPath("musicsearch://")) strIcon = "DefaultFolder.png"; else if (pItem->IsRemote()) strIcon = "DefaultNetwork.png"; diff --git a/xbmc/filesystem/SpecialProtocolDirectory.cpp b/xbmc/filesystem/SpecialProtocolDirectory.cpp index e4a970ea99..d1af8b0345 100644 --- a/xbmc/filesystem/SpecialProtocolDirectory.cpp +++ b/xbmc/filesystem/SpecialProtocolDirectory.cpp @@ -10,6 +10,7 @@ #include "Directory.h" #include "FileItem.h" +#include "FileItemList.h" #include "SpecialProtocol.h" #include "URL.h" #include "utils/URIUtils.h" diff --git a/xbmc/filesystem/StackDirectory.cpp b/xbmc/filesystem/StackDirectory.cpp index 58cbe9dff9..9b6aae53b0 100644 --- a/xbmc/filesystem/StackDirectory.cpp +++ b/xbmc/filesystem/StackDirectory.cpp @@ -9,6 +9,7 @@ #include "StackDirectory.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "URL.h" #include "settings/AdvancedSettings.h" diff --git a/xbmc/filesystem/UDFDirectory.cpp b/xbmc/filesystem/UDFDirectory.cpp index 236b281303..b22b496d1d 100644 --- a/xbmc/filesystem/UDFDirectory.cpp +++ b/xbmc/filesystem/UDFDirectory.cpp @@ -12,6 +12,7 @@ #include "UDFDirectory.h" #include "FileItem.h" +#include "FileItemList.h" #include "URL.h" #include "Util.h" #include "filesystem/UDFBlockInput.h" diff --git a/xbmc/filesystem/UPnPDirectory.cpp b/xbmc/filesystem/UPnPDirectory.cpp index 4d6608acfa..2b2af57598 100644 --- a/xbmc/filesystem/UPnPDirectory.cpp +++ b/xbmc/filesystem/UPnPDirectory.cpp @@ -13,6 +13,7 @@ #include "UPnPDirectory.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "URL.h" #include "network/upnp/UPnP.h" diff --git a/xbmc/filesystem/VideoDatabaseDirectory.cpp b/xbmc/filesystem/VideoDatabaseDirectory.cpp index 2c9caa7080..4242b095ce 100644 --- a/xbmc/filesystem/VideoDatabaseDirectory.cpp +++ b/xbmc/filesystem/VideoDatabaseDirectory.cpp @@ -10,6 +10,7 @@ #include "File.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "VideoDatabaseDirectory/QueryParams.h" #include "guilib/LocalizeStrings.h" diff --git a/xbmc/filesystem/VideoDatabaseDirectory/DirectoryNode.cpp b/xbmc/filesystem/VideoDatabaseDirectory/DirectoryNode.cpp index b62839c9bc..f181b4514a 100644 --- a/xbmc/filesystem/VideoDatabaseDirectory/DirectoryNode.cpp +++ b/xbmc/filesystem/VideoDatabaseDirectory/DirectoryNode.cpp @@ -24,6 +24,7 @@ #include "DirectoryNodeTitleTvShows.h" #include "DirectoryNodeTvShowsOverview.h" #include "FileItem.h" +#include "FileItemList.h" #include "QueryParams.h" #include "URL.h" #include "utils/StringUtils.h" diff --git a/xbmc/filesystem/VideoDatabaseDirectory/DirectoryNodeEpisodes.cpp b/xbmc/filesystem/VideoDatabaseDirectory/DirectoryNodeEpisodes.cpp index 9f629baa69..c75471cb0f 100644 --- a/xbmc/filesystem/VideoDatabaseDirectory/DirectoryNodeEpisodes.cpp +++ b/xbmc/filesystem/VideoDatabaseDirectory/DirectoryNodeEpisodes.cpp @@ -9,6 +9,7 @@ #include "DirectoryNodeEpisodes.h" #include "FileItem.h" +#include "FileItemList.h" #include "QueryParams.h" #include "video/VideoDatabase.h" diff --git a/xbmc/filesystem/VideoDatabaseDirectory/DirectoryNodeInProgressTvShows.cpp b/xbmc/filesystem/VideoDatabaseDirectory/DirectoryNodeInProgressTvShows.cpp index 044f8b3c74..f0a652232e 100644 --- a/xbmc/filesystem/VideoDatabaseDirectory/DirectoryNodeInProgressTvShows.cpp +++ b/xbmc/filesystem/VideoDatabaseDirectory/DirectoryNodeInProgressTvShows.cpp @@ -9,6 +9,7 @@ #include "DirectoryNodeInProgressTvShows.h" #include "FileItem.h" +#include "FileItemList.h" #include "video/VideoDatabase.h" using namespace XFILE::VIDEODATABASEDIRECTORY; diff --git a/xbmc/filesystem/VideoDatabaseDirectory/DirectoryNodeMoviesOverview.cpp b/xbmc/filesystem/VideoDatabaseDirectory/DirectoryNodeMoviesOverview.cpp index 9f415d09da..33d70051d8 100644 --- a/xbmc/filesystem/VideoDatabaseDirectory/DirectoryNodeMoviesOverview.cpp +++ b/xbmc/filesystem/VideoDatabaseDirectory/DirectoryNodeMoviesOverview.cpp @@ -9,6 +9,7 @@ #include "DirectoryNodeMoviesOverview.h" #include "FileItem.h" +#include "FileItemList.h" #include "guilib/LocalizeStrings.h" #include "utils/StringUtils.h" #include "video/VideoDatabase.h" diff --git a/xbmc/filesystem/VideoDatabaseDirectory/DirectoryNodeMusicVideosOverview.cpp b/xbmc/filesystem/VideoDatabaseDirectory/DirectoryNodeMusicVideosOverview.cpp index b71d8f1d2b..9c7290abc5 100644 --- a/xbmc/filesystem/VideoDatabaseDirectory/DirectoryNodeMusicVideosOverview.cpp +++ b/xbmc/filesystem/VideoDatabaseDirectory/DirectoryNodeMusicVideosOverview.cpp @@ -9,6 +9,7 @@ #include "DirectoryNodeMusicVideosOverview.h" #include "FileItem.h" +#include "FileItemList.h" #include "guilib/LocalizeStrings.h" #include "utils/StringUtils.h" #include "video/VideoDbUrl.h" diff --git a/xbmc/filesystem/VideoDatabaseDirectory/DirectoryNodeOverview.cpp b/xbmc/filesystem/VideoDatabaseDirectory/DirectoryNodeOverview.cpp index b52ae24dc5..0aeed45edc 100644 --- a/xbmc/filesystem/VideoDatabaseDirectory/DirectoryNodeOverview.cpp +++ b/xbmc/filesystem/VideoDatabaseDirectory/DirectoryNodeOverview.cpp @@ -9,6 +9,7 @@ #include "DirectoryNodeOverview.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "guilib/LocalizeStrings.h" #include "settings/Settings.h" diff --git a/xbmc/filesystem/VideoDatabaseDirectory/DirectoryNodeRecentlyAddedEpisodes.cpp b/xbmc/filesystem/VideoDatabaseDirectory/DirectoryNodeRecentlyAddedEpisodes.cpp index fe50dad926..317c761002 100644 --- a/xbmc/filesystem/VideoDatabaseDirectory/DirectoryNodeRecentlyAddedEpisodes.cpp +++ b/xbmc/filesystem/VideoDatabaseDirectory/DirectoryNodeRecentlyAddedEpisodes.cpp @@ -9,6 +9,7 @@ #include "DirectoryNodeRecentlyAddedEpisodes.h" #include "FileItem.h" +#include "FileItemList.h" #include "video/VideoDatabase.h" using namespace XFILE::VIDEODATABASEDIRECTORY; diff --git a/xbmc/filesystem/VideoDatabaseDirectory/DirectoryNodeRecentlyAddedMovies.cpp b/xbmc/filesystem/VideoDatabaseDirectory/DirectoryNodeRecentlyAddedMovies.cpp index 202d6f7b4a..41b372beb6 100644 --- a/xbmc/filesystem/VideoDatabaseDirectory/DirectoryNodeRecentlyAddedMovies.cpp +++ b/xbmc/filesystem/VideoDatabaseDirectory/DirectoryNodeRecentlyAddedMovies.cpp @@ -9,6 +9,7 @@ #include "DirectoryNodeRecentlyAddedMovies.h" #include "FileItem.h" +#include "FileItemList.h" #include "video/VideoDatabase.h" using namespace XFILE::VIDEODATABASEDIRECTORY; diff --git a/xbmc/filesystem/VideoDatabaseDirectory/DirectoryNodeRecentlyAddedMusicVideos.cpp b/xbmc/filesystem/VideoDatabaseDirectory/DirectoryNodeRecentlyAddedMusicVideos.cpp index d8ba5ef74d..2f57643b43 100644 --- a/xbmc/filesystem/VideoDatabaseDirectory/DirectoryNodeRecentlyAddedMusicVideos.cpp +++ b/xbmc/filesystem/VideoDatabaseDirectory/DirectoryNodeRecentlyAddedMusicVideos.cpp @@ -9,6 +9,7 @@ #include "DirectoryNodeRecentlyAddedMusicVideos.h" #include "FileItem.h" +#include "FileItemList.h" #include "video/VideoDatabase.h" using namespace XFILE::VIDEODATABASEDIRECTORY; diff --git a/xbmc/filesystem/VideoDatabaseDirectory/DirectoryNodeTitleMovies.cpp b/xbmc/filesystem/VideoDatabaseDirectory/DirectoryNodeTitleMovies.cpp index 45a83cee8f..0e82fcca9e 100644 --- a/xbmc/filesystem/VideoDatabaseDirectory/DirectoryNodeTitleMovies.cpp +++ b/xbmc/filesystem/VideoDatabaseDirectory/DirectoryNodeTitleMovies.cpp @@ -9,6 +9,7 @@ #include "DirectoryNodeTitleMovies.h" #include "FileItem.h" +#include "FileItemList.h" #include "QueryParams.h" #include "video/VideoDatabase.h" diff --git a/xbmc/filesystem/VideoDatabaseDirectory/DirectoryNodeTitleMusicVideos.cpp b/xbmc/filesystem/VideoDatabaseDirectory/DirectoryNodeTitleMusicVideos.cpp index 95fe30010b..d35398b153 100644 --- a/xbmc/filesystem/VideoDatabaseDirectory/DirectoryNodeTitleMusicVideos.cpp +++ b/xbmc/filesystem/VideoDatabaseDirectory/DirectoryNodeTitleMusicVideos.cpp @@ -9,6 +9,7 @@ #include "DirectoryNodeTitleMusicVideos.h" #include "FileItem.h" +#include "FileItemList.h" #include "QueryParams.h" #include "video/VideoDatabase.h" diff --git a/xbmc/filesystem/VideoDatabaseDirectory/DirectoryNodeTitleTvShows.cpp b/xbmc/filesystem/VideoDatabaseDirectory/DirectoryNodeTitleTvShows.cpp index b1a247ca7f..52f903fffd 100644 --- a/xbmc/filesystem/VideoDatabaseDirectory/DirectoryNodeTitleTvShows.cpp +++ b/xbmc/filesystem/VideoDatabaseDirectory/DirectoryNodeTitleTvShows.cpp @@ -9,6 +9,7 @@ #include "DirectoryNodeTitleTvShows.h" #include "FileItem.h" +#include "FileItemList.h" #include "QueryParams.h" #include "video/VideoDatabase.h" diff --git a/xbmc/filesystem/VideoDatabaseDirectory/DirectoryNodeTvShowsOverview.cpp b/xbmc/filesystem/VideoDatabaseDirectory/DirectoryNodeTvShowsOverview.cpp index 07e5ff4aee..5a490a53d7 100644 --- a/xbmc/filesystem/VideoDatabaseDirectory/DirectoryNodeTvShowsOverview.cpp +++ b/xbmc/filesystem/VideoDatabaseDirectory/DirectoryNodeTvShowsOverview.cpp @@ -9,6 +9,7 @@ #include "DirectoryNodeTvShowsOverview.h" #include "FileItem.h" +#include "FileItemList.h" #include "guilib/LocalizeStrings.h" #include "utils/StringUtils.h" #include "video/VideoDbUrl.h" diff --git a/xbmc/filesystem/VirtualDirectory.cpp b/xbmc/filesystem/VirtualDirectory.cpp index 4fb0205d1e..f764645cf9 100644 --- a/xbmc/filesystem/VirtualDirectory.cpp +++ b/xbmc/filesystem/VirtualDirectory.cpp @@ -11,6 +11,7 @@ #include "Directory.h" #include "DirectoryFactory.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "SourcesDirectory.h" #include "URL.h" diff --git a/xbmc/filesystem/ZeroconfDirectory.cpp b/xbmc/filesystem/ZeroconfDirectory.cpp index f34b6b2f1f..d05184e394 100644 --- a/xbmc/filesystem/ZeroconfDirectory.cpp +++ b/xbmc/filesystem/ZeroconfDirectory.cpp @@ -10,6 +10,7 @@ #include "Directory.h" #include "FileItem.h" +#include "FileItemList.h" #include "URL.h" #include "network/ZeroconfBrowser.h" #include "utils/URIUtils.h" diff --git a/xbmc/filesystem/test/TestDirectory.cpp b/xbmc/filesystem/test/TestDirectory.cpp index e99408c9dc..8f65b06356 100644 --- a/xbmc/filesystem/test/TestDirectory.cpp +++ b/xbmc/filesystem/test/TestDirectory.cpp @@ -7,6 +7,7 @@ */ #include "FileItem.h" +#include "FileItemList.h" #include "filesystem/Directory.h" #include "filesystem/IDirectory.h" #include "filesystem/SpecialProtocol.h" diff --git a/xbmc/filesystem/test/TestHTTPDirectory.cpp b/xbmc/filesystem/test/TestHTTPDirectory.cpp index 773630770b..8288bda46f 100644 --- a/xbmc/filesystem/test/TestHTTPDirectory.cpp +++ b/xbmc/filesystem/test/TestHTTPDirectory.cpp @@ -7,6 +7,7 @@ */ #include "FileItem.h" +#include "FileItemList.h" #include "URL.h" #include "filesystem/CurlFile.h" #include "filesystem/HTTPDirectory.h" diff --git a/xbmc/filesystem/test/TestZipFile.cpp b/xbmc/filesystem/test/TestZipFile.cpp index 3ff518b8dc..ffb4478cdd 100644 --- a/xbmc/filesystem/test/TestZipFile.cpp +++ b/xbmc/filesystem/test/TestZipFile.cpp @@ -7,6 +7,7 @@ */ #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "URL.h" #include "filesystem/Directory.h" diff --git a/xbmc/games/addons/GameClientProperties.cpp b/xbmc/games/addons/GameClientProperties.cpp index f3d97858bd..ae081afa92 100644 --- a/xbmc/games/addons/GameClientProperties.cpp +++ b/xbmc/games/addons/GameClientProperties.cpp @@ -9,6 +9,7 @@ #include "GameClientProperties.h" #include "FileItem.h" +#include "FileItemList.h" #include "GameClient.h" #include "ServiceBroker.h" #include "addons/AddonManager.h" diff --git a/xbmc/games/agents/windows/GUIAgentControllerList.cpp b/xbmc/games/agents/windows/GUIAgentControllerList.cpp index 55bb3e2296..7da49e72d2 100644 --- a/xbmc/games/agents/windows/GUIAgentControllerList.cpp +++ b/xbmc/games/agents/windows/GUIAgentControllerList.cpp @@ -9,6 +9,7 @@ #include "GUIAgentControllerList.h" #include "FileItem.h" +#include "FileItemList.h" #include "GUIAgentDefines.h" #include "GUIAgentWindow.h" #include "ServiceBroker.h" diff --git a/xbmc/games/controllers/dialogs/ControllerInstaller.cpp b/xbmc/games/controllers/dialogs/ControllerInstaller.cpp index 9b0fe6fc87..18f7634a01 100644 --- a/xbmc/games/controllers/dialogs/ControllerInstaller.cpp +++ b/xbmc/games/controllers/dialogs/ControllerInstaller.cpp @@ -9,6 +9,7 @@ #include "ControllerInstaller.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "addons/Addon.h" #include "addons/AddonInstaller.h" diff --git a/xbmc/games/controllers/dialogs/ControllerSelect.cpp b/xbmc/games/controllers/dialogs/ControllerSelect.cpp index 2ef9941dea..8219731120 100644 --- a/xbmc/games/controllers/dialogs/ControllerSelect.cpp +++ b/xbmc/games/controllers/dialogs/ControllerSelect.cpp @@ -9,6 +9,7 @@ #include "ControllerSelect.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "dialogs/GUIDialogSelect.h" #include "games/controllers/Controller.h" diff --git a/xbmc/games/dialogs/GUIDialogSelectGameClient.cpp b/xbmc/games/dialogs/GUIDialogSelectGameClient.cpp index f4c754aee0..08d6b71ffb 100644 --- a/xbmc/games/dialogs/GUIDialogSelectGameClient.cpp +++ b/xbmc/games/dialogs/GUIDialogSelectGameClient.cpp @@ -9,6 +9,7 @@ #include "GUIDialogSelectGameClient.h" #include "FileItem.h" +#include "FileItemList.h" #include "dialogs/GUIDialogSelect.h" #include "filesystem/AddonsDirectory.h" #include "games/addons/GameClient.h" diff --git a/xbmc/games/dialogs/osd/DialogGameSaves.cpp b/xbmc/games/dialogs/osd/DialogGameSaves.cpp index a2c08d606f..239b78ab4e 100644 --- a/xbmc/games/dialogs/osd/DialogGameSaves.cpp +++ b/xbmc/games/dialogs/osd/DialogGameSaves.cpp @@ -9,6 +9,7 @@ #include "DialogGameSaves.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "addons/Addon.h" #include "addons/AddonManager.h" diff --git a/xbmc/games/dialogs/osd/DialogGameStretchMode.cpp b/xbmc/games/dialogs/osd/DialogGameStretchMode.cpp index 98c1e077e8..67f4cad1ff 100644 --- a/xbmc/games/dialogs/osd/DialogGameStretchMode.cpp +++ b/xbmc/games/dialogs/osd/DialogGameStretchMode.cpp @@ -9,6 +9,7 @@ #include "DialogGameStretchMode.h" #include "FileItem.h" +#include "FileItemList.h" #include "cores/RetroPlayer/RetroPlayerUtils.h" #include "cores/RetroPlayer/guibridge/GUIGameVideoHandle.h" #include "guilib/LocalizeStrings.h" diff --git a/xbmc/games/dialogs/osd/DialogGameVideoFilter.h b/xbmc/games/dialogs/osd/DialogGameVideoFilter.h index 237720d65d..6c659da6e0 100644 --- a/xbmc/games/dialogs/osd/DialogGameVideoFilter.h +++ b/xbmc/games/dialogs/osd/DialogGameVideoFilter.h @@ -10,6 +10,7 @@ #include "DialogGameVideoSelect.h" #include "FileItem.h" +#include "FileItemList.h" namespace KODI { diff --git a/xbmc/games/dialogs/osd/DialogGameVideoRotation.cpp b/xbmc/games/dialogs/osd/DialogGameVideoRotation.cpp index 7037a6b35c..3fe6baa778 100644 --- a/xbmc/games/dialogs/osd/DialogGameVideoRotation.cpp +++ b/xbmc/games/dialogs/osd/DialogGameVideoRotation.cpp @@ -9,6 +9,7 @@ #include "DialogGameVideoRotation.h" #include "FileItem.h" +#include "FileItemList.h" #include "guilib/LocalizeStrings.h" #include "guilib/WindowIDs.h" #include "settings/GameSettings.h" diff --git a/xbmc/games/dialogs/osd/DialogGameVideoSelect.cpp b/xbmc/games/dialogs/osd/DialogGameVideoSelect.cpp index a69b26f772..0bf1529244 100644 --- a/xbmc/games/dialogs/osd/DialogGameVideoSelect.cpp +++ b/xbmc/games/dialogs/osd/DialogGameVideoSelect.cpp @@ -9,6 +9,7 @@ #include "DialogGameVideoSelect.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "cores/RetroPlayer/guibridge/GUIGameRenderManager.h" #include "cores/RetroPlayer/guibridge/GUIGameVideoHandle.h" diff --git a/xbmc/games/dialogs/osd/DialogInGameSaves.h b/xbmc/games/dialogs/osd/DialogInGameSaves.h index 5c1c3176c7..8fdb7b0b6c 100644 --- a/xbmc/games/dialogs/osd/DialogInGameSaves.h +++ b/xbmc/games/dialogs/osd/DialogInGameSaves.h @@ -10,6 +10,7 @@ #include "DialogGameVideoSelect.h" #include "FileItem.h" +#include "FileItemList.h" #include "guilib/GUIListItem.h" #include <string> diff --git a/xbmc/games/ports/guicontrols/GUIActivePortList.cpp b/xbmc/games/ports/guicontrols/GUIActivePortList.cpp index 851ca86266..f0e89f6e8d 100644 --- a/xbmc/games/ports/guicontrols/GUIActivePortList.cpp +++ b/xbmc/games/ports/guicontrols/GUIActivePortList.cpp @@ -9,6 +9,7 @@ #include "GUIActivePortList.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "addons/AddonEvents.h" #include "addons/AddonManager.h" diff --git a/xbmc/games/ports/windows/GUIPortList.cpp b/xbmc/games/ports/windows/GUIPortList.cpp index c0e46e0bac..9db78747be 100644 --- a/xbmc/games/ports/windows/GUIPortList.cpp +++ b/xbmc/games/ports/windows/GUIPortList.cpp @@ -9,6 +9,7 @@ #include "GUIPortList.h" #include "FileItem.h" +#include "FileItemList.h" #include "GUIPortDefines.h" #include "GUIPortWindow.h" #include "ServiceBroker.h" diff --git a/xbmc/games/windows/GUIViewStateWindowGames.cpp b/xbmc/games/windows/GUIViewStateWindowGames.cpp index e388d8ff83..3f45122ac7 100644 --- a/xbmc/games/windows/GUIViewStateWindowGames.cpp +++ b/xbmc/games/windows/GUIViewStateWindowGames.cpp @@ -9,6 +9,7 @@ #include "GUIViewStateWindowGames.h" #include "FileItem.h" +#include "FileItemList.h" #include "games/GameUtils.h" #include "guilib/LocalizeStrings.h" #include "guilib/WindowIDs.h" diff --git a/xbmc/games/windows/GUIWindowGames.cpp b/xbmc/games/windows/GUIWindowGames.cpp index a74186db84..2d9eb600db 100644 --- a/xbmc/games/windows/GUIWindowGames.cpp +++ b/xbmc/games/windows/GUIWindowGames.cpp @@ -9,6 +9,7 @@ #include "GUIWindowGames.h" #include "FileItem.h" +#include "FileItemList.h" #include "GUIPassword.h" #include "ServiceBroker.h" #include "URL.h" diff --git a/xbmc/guilib/GUIBaseContainer.cpp b/xbmc/guilib/GUIBaseContainer.cpp index c22eb71284..65d604c18f 100644 --- a/xbmc/guilib/GUIBaseContainer.cpp +++ b/xbmc/guilib/GUIBaseContainer.cpp @@ -9,10 +9,12 @@ #include "GUIBaseContainer.h" #include "FileItem.h" +#include "FileItemList.h" #include "GUIInfoManager.h" #include "GUIListItemLayout.h" #include "GUIMessage.h" #include "ServiceBroker.h" +#include "guilib/GUIListItem.h" #include "guilib/guiinfo/GUIInfoLabels.h" #include "guilib/listproviders/IListProvider.h" #include "input/actions/Action.h" @@ -875,10 +877,16 @@ bool CGUIBaseContainer::OnClick(int actionID) int selected = GetSelectedItem(); if (selected >= 0 && selected < static_cast<int>(m_items.size())) { + // One of the actions could trigger a reload of the GUI which destroys + // this CGUIBaseContainer and therefore the m_items[selected] we are + // going to process. The shared_ptr ensures that item survives until + // it has been processed. + std::shared_ptr<CGUIListItem> item = m_items[selected]; + if (m_clickActions.HasActionsMeetingCondition()) - m_clickActions.ExecuteActions(0, GetParentID(), m_items[selected]); + m_clickActions.ExecuteActions(0, GetParentID(), item); else - m_listProvider->OnClick(m_items[selected]); + m_listProvider->OnClick(item); } return true; } diff --git a/xbmc/guilib/GUIControl.cpp b/xbmc/guilib/GUIControl.cpp index 689c55f257..0c6a902ebb 100644 --- a/xbmc/guilib/GUIControl.cpp +++ b/xbmc/guilib/GUIControl.cpp @@ -180,6 +180,10 @@ void CGUIControl::Process(unsigned int currentTime, CDirtyRegionList &dirtyregio // 3. reset the animation transform void CGUIControl::DoRender() { + if (IsControlRenderable() && + !m_renderRegion.Intersects(CServiceBroker::GetWinSystem()->GetGfxContext().GetScissors())) + return; + if (IsVisible() && !m_isCulled) { bool hasStereo = @@ -954,6 +958,24 @@ void CGUIControl::UpdateControlStats() } } +bool CGUIControl::IsControlRenderable() +{ + switch (ControlType) + { + case GUICONTAINER_EPGGRID: + case GUICONTAINER_FIXEDLIST: + case GUICONTAINER_LIST: + case GUICONTAINER_PANEL: + case GUICONTAINER_WRAPLIST: + case GUICONTROL_GROUP: + case GUICONTROL_GROUPLIST: + case GUICONTROL_LISTGROUP: + return false; + default: + return true; + } +} + void CGUIControl::SetHitRect(const CRect& rect, const UTILS::COLOR::Color& color) { m_hitRect = rect; diff --git a/xbmc/guilib/GUIControl.h b/xbmc/guilib/GUIControl.h index 4cedee0761..a57f02243b 100644 --- a/xbmc/guilib/GUIControl.h +++ b/xbmc/guilib/GUIControl.h @@ -306,6 +306,11 @@ public: }; GUICONTROLTYPES GetControlType() const { return ControlType; } + /*! \brief Test whether the control is "drawable" (not a group or similar) + \return true if the control has textures/labels it wants to render + */ + bool IsControlRenderable(); + enum GUIVISIBLE { HIDDEN = 0, DELAYED, VISIBLE }; enum GUISCROLLVALUE { FOCUS = 0, NEVER, ALWAYS }; diff --git a/xbmc/guilib/GUIFont.cpp b/xbmc/guilib/GUIFont.cpp index 784dd75971..bf0c014a0a 100644 --- a/xbmc/guilib/GUIFont.cpp +++ b/xbmc/guilib/GUIFont.cpp @@ -234,18 +234,18 @@ void CGUIFont::DrawScrollingText(float x, shadowColors.emplace_back((renderColor & 0xff000000) != 0 ? shadowColor : 0); for (float dx = -offset; dx < maxWidth; dx += scrollInfo.m_totalWidth) { - m_font->DrawTextInternal(context, x + dx + 1, y + 1, shadowColors, text, alignment, - textPixelWidth, scroll); - m_font->DrawTextInternal(context, x + dx + scrollInfo.m_textWidth + 1, y + 1, shadowColors, - scrollInfo.m_suffix, alignment, suffixPixelWidth, scroll); + m_font->DrawTextInternal(context, x + 1, y + 1, shadowColors, text, alignment, textPixelWidth, + scroll, dx); + m_font->DrawTextInternal(context, x + scrollInfo.m_textWidth + 1, y + 1, shadowColors, + scrollInfo.m_suffix, alignment, suffixPixelWidth, scroll, dx); } } for (float dx = -offset; dx < maxWidth; dx += scrollInfo.m_totalWidth) { - m_font->DrawTextInternal(context, x + dx, y, renderColors, text, alignment, textPixelWidth, - scroll); - m_font->DrawTextInternal(context, x + dx + scrollInfo.m_textWidth, y, renderColors, - scrollInfo.m_suffix, alignment, suffixPixelWidth, scroll); + m_font->DrawTextInternal(context, x, y, renderColors, text, alignment, textPixelWidth, scroll, + dx); + m_font->DrawTextInternal(context, x + scrollInfo.m_textWidth, y, renderColors, + scrollInfo.m_suffix, alignment, suffixPixelWidth, scroll, dx); } context.RestoreClipRegion(); diff --git a/xbmc/guilib/GUIFontManager.cpp b/xbmc/guilib/GUIFontManager.cpp index 9170cc0406..93f88666a0 100644 --- a/xbmc/guilib/GUIFontManager.cpp +++ b/xbmc/guilib/GUIFontManager.cpp @@ -8,6 +8,7 @@ #include "GUIFontManager.h" +#include "FileItemList.h" #include "GUIComponent.h" #include "GUIFontTTF.h" #include "GUIWindowManager.h" diff --git a/xbmc/guilib/GUIFontTTF.cpp b/xbmc/guilib/GUIFontTTF.cpp index 50d0e07a44..ff11db14f8 100644 --- a/xbmc/guilib/GUIFontTTF.cpp +++ b/xbmc/guilib/GUIFontTTF.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2018 Team Kodi + * Copyright (C) 2005-2024 Team Kodi * This file is part of Kodi - https://kodi.tv * * SPDX-License-Identifier: GPL-2.0-or-later @@ -369,7 +369,9 @@ void CGUIFontTTF::DrawTextInternal(CGraphicContext& context, const vecText& text, uint32_t alignment, float maxPixelWidth, - bool scrolling) + bool scrolling, + float dx, + float dy) { if (text.empty()) { @@ -379,15 +381,40 @@ void CGUIFontTTF::DrawTextInternal(CGraphicContext& context, Begin(); uint32_t rawAlignment = alignment; bool dirtyCache(false); + +#if not defined(HAS_DX) + // round coordinates to the pixel grid. otherwise, we might sample at the wrong positions. + if (!scrolling) + x = std::round(x); + y = std::round(y); +#else + x += dx; + y += dy; +#endif + +#if not defined(HAS_DX) + // GL can scissor and shader clip + const bool hardwareClipping = true; +#else + // FIXME: remove static (CPU based) clipping for GLES/DX const bool hardwareClipping = m_renderSystem->ScissorsCanEffectClipping(); +#endif + + // FIXME: remove positional stuff once GLES/DX are brought up to date CGUIFontCacheStaticPosition staticPos(x, y); CGUIFontCacheDynamicPosition dynamicPos; + +#if not defined(HAS_DX) + // dummy positions for the time being + dynamicPos = CGUIFontCacheDynamicPosition(0.0f, 0.0f, 0.0f); +#else if (hardwareClipping) { dynamicPos = CGUIFontCacheDynamicPosition(context.ScaleFinalXCoord(x, y), context.ScaleFinalYCoord(x, y), context.ScaleFinalZCoord(x, y)); } +#endif CVertexBuffer unusedVertexBuffer; CVertexBuffer& vertexBuffer = @@ -425,8 +452,14 @@ void CGUIFontTTF::DrawTextInternal(CGraphicContext& context, const std::vector<Glyph> glyphs = GetHarfBuzzShapedGlyphs(text); // save the origin, which is scaled separately +#if not defined(HAS_DX) + // the origin is now at [0,0], and not at "random" locations anymore. positioning is done in the vertex shader. + m_originX = 0; + m_originY = 0; +#else m_originX = x; m_originY = y; +#endif // cache the ellipses width if (!m_ellipseCached) @@ -677,7 +710,11 @@ void CGUIFontTTF::DrawTextInternal(CGraphicContext& context, scrolling, std::chrono::steady_clock::now(), dirtyCache); CVertexBuffer newVertexBuffer = CreateVertexBuffer(*tempVertices); vertexBuffer = newVertexBuffer; +#if not defined(HAS_DX) + m_vertexTrans.emplace_back(x, y, 0.0f, &vertexBuffer, context.GetClipRegion(), dx, dy); +#else m_vertexTrans.emplace_back(.0f, .0f, .0f, &vertexBuffer, context.GetClipRegion()); +#endif } else { @@ -691,8 +728,12 @@ void CGUIFontTTF::DrawTextInternal(CGraphicContext& context, else { if (hardwareClipping) +#if not defined(HAS_DX) + m_vertexTrans.emplace_back(x, y, 0.0f, &vertexBuffer, context.GetClipRegion(), dx, dy); +#else m_vertexTrans.emplace_back(dynamicPos.m_x, dynamicPos.m_y, dynamicPos.m_z, &vertexBuffer, context.GetClipRegion()); +#endif else /* Append the vertices from the cache to the set collected since the first Begin() call */ m_vertex.insert(m_vertex.end(), vertices->begin(), vertices->end()); @@ -1098,12 +1139,19 @@ void CGUIFontTTF::RenderCharacter(CGraphicContext& context, // posX and posY are relative to our origin, and the textcell is offset // from our (posX, posY). Plus, these are unscaled quantities compared to the underlying GUI resolution +#if not defined(HAS_DX) + CRect vertex((posX + ch->m_offsetX), (posY + ch->m_offsetY), (posX + ch->m_offsetX + width), + (posY + ch->m_offsetY + height)); +#else CRect vertex((posX + ch->m_offsetX) * context.GetGUIScaleX(), (posY + ch->m_offsetY) * context.GetGUIScaleY(), (posX + ch->m_offsetX + width) * context.GetGUIScaleX(), (posY + ch->m_offsetY + height) * context.GetGUIScaleY()); vertex += CPoint(m_originX, m_originY); +#endif CRect texture(ch->m_left, ch->m_top, ch->m_right, ch->m_bottom); + +#if defined(HAS_DX) if (!m_renderSystem->ScissorsCanEffectClipping()) context.ClipRect(vertex, texture); @@ -1163,6 +1211,14 @@ void CGUIFontTTF::RenderCharacter(CGraphicContext& context, const float tr = texture.x2 * m_textureScaleX; const float tt = texture.y1 * m_textureScaleY; const float tb = texture.y2 * m_textureScaleY; +#else + // when scaling by shader, we have to grow the vertex and texture coords + // by .5 or we would ommit pixels when animating. + const float tl = (texture.x1 - .5f) * m_textureScaleX; + const float tr = (texture.x2 + .5f) * m_textureScaleX; + const float tt = (texture.y1 - .5f) * m_textureScaleY; + const float tb = (texture.y2 + .5f) * m_textureScaleY; +#endif vertices.resize(vertices.size() + VERTEX_PER_GLYPH); SVertex* v = &vertices[vertices.size() - VERTEX_PER_GLYPH]; @@ -1208,29 +1264,38 @@ void CGUIFontTTF::RenderCharacter(CGraphicContext& context, v[3].v = tb; #else // GL / GLES uses triangle strips, not quads, so have to rearrange the vertex order + // GL uses vertex shaders to manipulate text rotation/translation/scaling/clipping. + + // nudge position to align with raster grid. messes up kerning, but also avoids + // linear filtering (when not scaled/rotated). + float xOffset = 0.0f; + if (roundX) + xOffset = (vertex.x1 - std::floor(vertex.x1)); + float yOffset = (vertex.y1 - std::floor(vertex.y1)); + v[0].u = tl; v[0].v = tt; - v[0].x = x[0]; - v[0].y = y[0]; - v[0].z = z[0]; + v[0].x = vertex.x1 - xOffset - 0.5f; + v[0].y = vertex.y1 - yOffset - 0.5f; + v[0].z = 0; v[1].u = tl; v[1].v = tb; - v[1].x = x[3]; - v[1].y = y[3]; - v[1].z = z[3]; + v[1].x = vertex.x1 - xOffset - 0.5f; + v[1].y = vertex.y2 - yOffset + 0.5f; + v[1].z = 0; v[2].u = tr; v[2].v = tt; - v[2].x = x[1]; - v[2].y = y[1]; - v[2].z = z[1]; + v[2].x = vertex.x2 - xOffset + 0.5f; + v[2].y = vertex.y1 - yOffset - 0.5f; + v[2].z = 0; v[3].u = tr; v[3].v = tb; - v[3].x = x[2]; - v[3].y = y[2]; - v[3].z = z[2]; + v[3].x = vertex.x2 - xOffset + 0.5f; + v[3].y = vertex.y2 - yOffset + 0.5f; + v[3].z = 0; #endif } diff --git a/xbmc/guilib/GUIFontTTF.h b/xbmc/guilib/GUIFontTTF.h index 2ed270343d..02a0ac16df 100644 --- a/xbmc/guilib/GUIFontTTF.h +++ b/xbmc/guilib/GUIFontTTF.h @@ -164,7 +164,9 @@ protected: const vecText& text, uint32_t alignment, float maxPixelWidth, - bool scrolling); + bool scrolling, + float dx = 0.0f, + float dy = 0.0f); float m_height{0.0f}; @@ -238,16 +240,22 @@ protected: float m_translateX; float m_translateY; float m_translateZ; + float m_offsetX; // skews the "raw" mesh before applying UI matrix (useful for scrolling) + float m_offsetY; const CVertexBuffer* m_vertexBuffer; CRect m_clip; CTranslatedVertices(float translateX, float translateY, float translateZ, const CVertexBuffer* vertexBuffer, - const CRect& clip) + const CRect& clip, + float offsetX = 0.0f, + float offsetY = 0.0f) : m_translateX(translateX), m_translateY(translateY), m_translateZ(translateZ), + m_offsetX(offsetX), + m_offsetY(offsetY), m_vertexBuffer(vertexBuffer), m_clip(clip) { diff --git a/xbmc/guilib/GUIFontTTFGL.cpp b/xbmc/guilib/GUIFontTTFGL.cpp index 12889c9b1d..3706883911 100644 --- a/xbmc/guilib/GUIFontTTFGL.cpp +++ b/xbmc/guilib/GUIFontTTFGL.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2018 Team Kodi + * Copyright (C) 2005-2024 Team Kodi * This file is part of Kodi - https://kodi.tv * * SPDX-License-Identifier: GPL-2.0-or-later @@ -16,6 +16,8 @@ #include "gui3d.h" #include "rendering/MatrixGL.h" #include "rendering/gl/RenderSystemGL.h" +#include "settings/AdvancedSettings.h" +#include "settings/SettingsComponent.h" #include "utils/GLUtils.h" #include "utils/log.h" #include "windowing/GraphicContext.h" @@ -63,7 +65,18 @@ bool CGUIFontTTFGL::FirstBegin() internalFormat = GL_R8; else internalFormat = GL_LUMINANCE; + renderSystem->EnableShader(ShaderMethodGL::SM_FONTS); + if (renderSystem->ScissorsCanEffectClipping()) + { + m_scissorClip = true; + } + else + { + m_scissorClip = false; + renderSystem->ResetScissors(); + renderSystem->EnableShader(ShaderMethodGL::SM_FONTS_SHADER_CLIP); + } if (m_textureStatus == TEXTURE_REALLOCATED) { @@ -88,6 +101,16 @@ bool CGUIFontTTFGL::FirstBegin() glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, m_texture->GetWidth(), m_texture->GetHeight(), 0, pixformat, GL_UNSIGNED_BYTE, 0); +#ifdef GL_TEXTURE_MAX_ANISOTROPY_EXT + if (CServiceBroker::GetRenderSystem()->IsExtSupported("GL_EXT_texture_filter_anisotropic")) + { + int32_t aniso = + CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_guiAnisotropicFiltering; + if (aniso > 1) + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso); + } +#endif + VerifyGLState(); m_textureStatus = TEXTURE_UPDATED; } @@ -117,6 +140,9 @@ bool CGUIFontTTFGL::FirstBegin() void CGUIFontTTFGL::LastEnd() { + // static vertex arrays are not supported anymore + assert(m_vertex.empty()); + CWinSystemBase* const winSystem = CServiceBroker::GetWinSystem(); if (!winSystem) return; @@ -126,7 +152,9 @@ void CGUIFontTTFGL::LastEnd() GLint posLoc = renderSystem->ShaderGetPos(); GLint colLoc = renderSystem->ShaderGetCol(); GLint tex0Loc = renderSystem->ShaderGetCoord0(); - GLint modelLoc = renderSystem->ShaderGetModel(); + GLint clipUniformLoc = renderSystem->ShaderGetClip(); + GLint coordStepUniformLoc = renderSystem->ShaderGetCoordStep(); + GLint matrixUniformLoc = renderSystem->ShaderGetMatrix(); CreateStaticVertexBuffers(); @@ -135,44 +163,6 @@ void CGUIFontTTFGL::LastEnd() glEnableVertexAttribArray(colLoc); glEnableVertexAttribArray(tex0Loc); - if (!m_vertex.empty()) - { - - // Deal with vertices that had to use software clipping - std::vector<SVertex> vecVertices(6 * (m_vertex.size() / 4)); - SVertex* vertices = &vecVertices[0]; - for (size_t i = 0; i < m_vertex.size(); i += 4) - { - *vertices++ = m_vertex[i]; - *vertices++ = m_vertex[i + 1]; - *vertices++ = m_vertex[i + 2]; - - *vertices++ = m_vertex[i + 1]; - *vertices++ = m_vertex[i + 3]; - *vertices++ = m_vertex[i + 2]; - } - vertices = &vecVertices[0]; - - GLuint VertexVBO; - - glGenBuffers(1, &VertexVBO); - glBindBuffer(GL_ARRAY_BUFFER, VertexVBO); - glBufferData(GL_ARRAY_BUFFER, sizeof(SVertex) * vecVertices.size(), &vecVertices[0], - GL_STATIC_DRAW); - - glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, sizeof(SVertex), - reinterpret_cast<const GLvoid*>(offsetof(SVertex, x))); - glVertexAttribPointer(colLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(SVertex), - reinterpret_cast<const GLvoid*>(offsetof(SVertex, r))); - glVertexAttribPointer(tex0Loc, 2, GL_FLOAT, GL_FALSE, sizeof(SVertex), - reinterpret_cast<const GLvoid*>(offsetof(SVertex, u))); - - glDrawArrays(GL_TRIANGLES, 0, vecVertices.size()); - - glBindBuffer(GL_ARRAY_BUFFER, 0); - glDeleteBuffers(1, &VertexVBO); - } - if (!m_vertexTrans.empty()) { // Deal with the vertices that can be hardware clipped and therefore translated @@ -199,14 +189,55 @@ void CGUIFontTTFGL::LastEnd() // skip empty clip if (clip.IsEmpty()) continue; + } + + if (m_scissorClip) + { + // clip using scissors renderSystem->SetScissors(clip); } + else + { + // clip using vertex shader + renderSystem->ResetScissors(); + + float x1 = + m_vertexTrans[i].m_clip.x1 - m_vertexTrans[i].m_translateX - m_vertexTrans[i].m_offsetX; + float y1 = + m_vertexTrans[i].m_clip.y1 - m_vertexTrans[i].m_translateY - m_vertexTrans[i].m_offsetY; + float x2 = + m_vertexTrans[i].m_clip.x2 - m_vertexTrans[i].m_translateX - m_vertexTrans[i].m_offsetX; + float y2 = + m_vertexTrans[i].m_clip.y2 - m_vertexTrans[i].m_translateY - m_vertexTrans[i].m_offsetY; + + glUniform4f(clipUniformLoc, x1, y1, x2, y2); + + // setup texture step + float stepX = context.GetGUIScaleX() / (static_cast<float>(m_textureWidth)); + float stepY = context.GetGUIScaleY() / (static_cast<float>(m_textureHeight)); + glUniform4f(coordStepUniformLoc, stepX, stepY, 1.0f, 1.0f); + } - // Apply the translation to the currently active (top-of-stack) model view matrix - glMatrixModview.Push(); - glMatrixModview.Get().Translatef(m_vertexTrans[i].m_translateX, m_vertexTrans[i].m_translateY, - m_vertexTrans[i].m_translateZ); - glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glMatrixModview.Get()); + // calculate the fractional offset to the ideal position + float fractX = + context.ScaleFinalXCoord(m_vertexTrans[i].m_translateX, m_vertexTrans[i].m_translateY); + float fractY = + context.ScaleFinalYCoord(m_vertexTrans[i].m_translateX, m_vertexTrans[i].m_translateY); + fractX = -fractX + std::round(fractX); + fractY = -fractY + std::round(fractY); + + // proj * model * gui * scroll * translation * scaling * correction factor + CMatrixGL matrix = glMatrixProject.Get(); + matrix.MultMatrixf(glMatrixModview.Get()); + matrix.MultMatrixf(CMatrixGL(context.GetGUIMatrix())); + matrix.Translatef(m_vertexTrans[i].m_offsetX, m_vertexTrans[i].m_offsetY, 0.0f); + matrix.Translatef(m_vertexTrans[i].m_translateX, m_vertexTrans[i].m_translateY, 0.0f); + // the gui matrix messes with the scale. correct it here for now. + matrix.Scalef(context.GetGUIScaleX(), context.GetGUIScaleY(), 1.0f); + // the gui matrix doesn't align to exact pixel coords atm. correct it here for now. + matrix.Translatef(fractX, fractY, 0.0f); + + glUniformMatrix4fv(matrixUniformLoc, 1, GL_FALSE, matrix); // Bind the buffer to the OpenGL context's GL_ARRAY_BUFFER binding point glBindBuffer(GL_ARRAY_BUFFER, m_vertexTrans[i].m_vertexBuffer->bufferHandle); @@ -233,13 +264,12 @@ void CGUIFontTTFGL::LastEnd() glDrawElements(GL_TRIANGLES, 6 * count, GL_UNSIGNED_SHORT, 0); } - - glMatrixModview.Pop(); } + // Restore the original scissor rectangle - renderSystem->SetScissors(scissor); - // Restore the original model view matrix - glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glMatrixModview.Get()); + if (m_scissorClip) + renderSystem->SetScissors(scissor); + // Unbind GL_ARRAY_BUFFER and GL_ELEMENT_ARRAY_BUFFER glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); diff --git a/xbmc/guilib/GUIFontTTFGL.h b/xbmc/guilib/GUIFontTTFGL.h index 22fbe6419b..e59a54a23c 100644 --- a/xbmc/guilib/GUIFontTTFGL.h +++ b/xbmc/guilib/GUIFontTTFGL.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2018 Team Kodi + * Copyright (C) 2005-2024 Team Kodi * This file is part of Kodi - https://kodi.tv * * SPDX-License-Identifier: GPL-2.0-or-later @@ -55,4 +55,6 @@ private: TextureStatus m_textureStatus{TEXTURE_VOID}; static bool m_staticVertexBufferCreated; + + bool m_scissorClip{false}; }; diff --git a/xbmc/guilib/GUIFontTTFGLES.cpp b/xbmc/guilib/GUIFontTTFGLES.cpp index ad18836be3..67cceae441 100644 --- a/xbmc/guilib/GUIFontTTFGLES.cpp +++ b/xbmc/guilib/GUIFontTTFGLES.cpp @@ -16,6 +16,8 @@ #include "gui3d.h" #include "rendering/MatrixGL.h" #include "rendering/gles/RenderSystemGLES.h" +#include "settings/AdvancedSettings.h" +#include "settings/SettingsComponent.h" #include "utils/GLUtils.h" #include "utils/log.h" #include "windowing/GraphicContext.h" @@ -60,6 +62,17 @@ bool CGUIFontTTFGLES::FirstBegin() GLenum pixformat = GL_ALPHA; // deprecated GLenum internalFormat = GL_ALPHA; + if (renderSystem->ScissorsCanEffectClipping()) + { + m_scissorClip = true; + } + else + { + m_scissorClip = false; + renderSystem->ResetScissors(); + renderSystem->EnableGUIShader(ShaderMethodGLES::SM_FONTS_SHADER_CLIP); + } + if (m_textureStatus == TEXTURE_REALLOCATED) { if (glIsTexture(m_nTexture)) @@ -83,6 +96,16 @@ bool CGUIFontTTFGLES::FirstBegin() glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, m_texture->GetWidth(), m_texture->GetHeight(), 0, pixformat, GL_UNSIGNED_BYTE, 0); +#ifdef GL_TEXTURE_MAX_ANISOTROPY_EXT + if (CServiceBroker::GetRenderSystem()->IsExtSupported("GL_EXT_texture_filter_anisotropic")) + { + int32_t aniso = + CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_guiAnisotropicFiltering; + if (aniso > 1) + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso); + } +#endif + VerifyGLState(); m_textureStatus = TEXTURE_UPDATED; } @@ -112,6 +135,9 @@ bool CGUIFontTTFGLES::FirstBegin() void CGUIFontTTFGLES::LastEnd() { + // static vertex arrays are not supported anymore + assert(m_vertex.empty()); + CWinSystemBase* const winSystem = CServiceBroker::GetWinSystem(); if (!winSystem) return; @@ -122,7 +148,9 @@ void CGUIFontTTFGLES::LastEnd() GLint posLoc = renderSystem->GUIShaderGetPos(); GLint colLoc = renderSystem->GUIShaderGetCol(); GLint tex0Loc = renderSystem->GUIShaderGetCoord0(); - GLint modelLoc = renderSystem->GUIShaderGetModel(); + GLint clipUniformLoc = renderSystem->GUIShaderGetClip(); + GLint coordStepUniformLoc = renderSystem->GUIShaderGetCoordStep(); + GLint matrixUniformLoc = renderSystem->GUIShaderGetMatrix(); CreateStaticVertexBuffers(); @@ -131,35 +159,6 @@ void CGUIFontTTFGLES::LastEnd() glEnableVertexAttribArray(colLoc); glEnableVertexAttribArray(tex0Loc); - if (!m_vertex.empty()) - { - // Deal with vertices that had to use software clipping - std::vector<SVertex> vecVertices(6 * (m_vertex.size() / 4)); - SVertex* vertices = &vecVertices[0]; - - for (size_t i = 0; i < m_vertex.size(); i += 4) - { - *vertices++ = m_vertex[i]; - *vertices++ = m_vertex[i + 1]; - *vertices++ = m_vertex[i + 2]; - - *vertices++ = m_vertex[i + 1]; - *vertices++ = m_vertex[i + 3]; - *vertices++ = m_vertex[i + 2]; - } - - vertices = &vecVertices[0]; - - glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, sizeof(SVertex), - reinterpret_cast<char*>(vertices) + offsetof(SVertex, x)); - glVertexAttribPointer(colLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(SVertex), - reinterpret_cast<char*>(vertices) + offsetof(SVertex, r)); - glVertexAttribPointer(tex0Loc, 2, GL_FLOAT, GL_FALSE, sizeof(SVertex), - reinterpret_cast<char*>(vertices) + offsetof(SVertex, u)); - - glDrawArrays(GL_TRIANGLES, 0, vecVertices.size()); - } - if (!m_vertexTrans.empty()) { // Deal with the vertices that can be hardware clipped and therefore translated @@ -186,14 +185,54 @@ void CGUIFontTTFGLES::LastEnd() // skip empty clip if (clip.IsEmpty()) continue; + } + if (m_scissorClip) + { + // clip using scissors renderSystem->SetScissors(clip); } + else + { + // clip using vertex shader + renderSystem->ResetScissors(); + + float x1 = + m_vertexTrans[i].m_clip.x1 - m_vertexTrans[i].m_translateX - m_vertexTrans[i].m_offsetX; + float y1 = + m_vertexTrans[i].m_clip.y1 - m_vertexTrans[i].m_translateY - m_vertexTrans[i].m_offsetY; + float x2 = + m_vertexTrans[i].m_clip.x2 - m_vertexTrans[i].m_translateX - m_vertexTrans[i].m_offsetX; + float y2 = + m_vertexTrans[i].m_clip.y2 - m_vertexTrans[i].m_translateY - m_vertexTrans[i].m_offsetY; + + glUniform4f(clipUniformLoc, x1, y1, x2, y2); + + // setup texture step + float stepX = context.GetGUIScaleX() / (static_cast<float>(m_textureWidth)); + float stepY = context.GetGUIScaleY() / (static_cast<float>(m_textureHeight)); + glUniform4f(coordStepUniformLoc, stepX, stepY, 1.0f, 1.0f); + } - // Apply the translation to the currently active (top-of-stack) model view matrix - glMatrixModview.Push(); - glMatrixModview.Get().Translatef(m_vertexTrans[i].m_translateX, m_vertexTrans[i].m_translateY, - m_vertexTrans[i].m_translateZ); - glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glMatrixModview.Get()); + // calculate the fractional offset to the ideal position + float fractX = + context.ScaleFinalXCoord(m_vertexTrans[i].m_translateX, m_vertexTrans[i].m_translateY); + float fractY = + context.ScaleFinalYCoord(m_vertexTrans[i].m_translateX, m_vertexTrans[i].m_translateY); + fractX = -fractX + std::round(fractX); + fractY = -fractY + std::round(fractY); + + // proj * model * gui * scroll * translation * scaling * correction factor + CMatrixGL matrix = glMatrixProject.Get(); + matrix.MultMatrixf(glMatrixModview.Get()); + matrix.MultMatrixf(CMatrixGL(context.GetGUIMatrix())); + matrix.Translatef(m_vertexTrans[i].m_offsetX, m_vertexTrans[i].m_offsetY, 0.0f); + matrix.Translatef(m_vertexTrans[i].m_translateX, m_vertexTrans[i].m_translateY, 0.0f); + // the gui matrix messes with the scale. correct it here for now. + matrix.Scalef(context.GetGUIScaleX(), context.GetGUIScaleY(), 1.0f); + // the gui matrix doesn't align to exact pixel coords atm. correct it here for now. + matrix.Translatef(fractX, fractY, 0.0f); + + glUniformMatrix4fv(matrixUniformLoc, 1, GL_FALSE, matrix); // Bind the buffer to the OpenGL context's GL_ARRAY_BUFFER binding point glBindBuffer(GL_ARRAY_BUFFER, m_vertexTrans[i].m_vertexBuffer->bufferHandle); @@ -224,9 +263,8 @@ void CGUIFontTTFGLES::LastEnd() glMatrixModview.Pop(); } // Restore the original scissor rectangle - renderSystem->SetScissors(scissor); - // Restore the original model view matrix - glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glMatrixModview.Get()); + if (m_scissorClip) + renderSystem->SetScissors(scissor); // Unbind GL_ARRAY_BUFFER and GL_ELEMENT_ARRAY_BUFFER glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); diff --git a/xbmc/guilib/GUIFontTTFGLES.h b/xbmc/guilib/GUIFontTTFGLES.h index ae03da74e6..264d1a7611 100644 --- a/xbmc/guilib/GUIFontTTFGLES.h +++ b/xbmc/guilib/GUIFontTTFGLES.h @@ -55,4 +55,5 @@ private: TextureStatus m_textureStatus{TEXTURE_VOID}; static bool m_staticVertexBufferCreated; + bool m_scissorClip{false}; }; diff --git a/xbmc/guilib/GUIIncludes.cpp b/xbmc/guilib/GUIIncludes.cpp index 55d967346f..da8f3a33c9 100644 --- a/xbmc/guilib/GUIIncludes.cpp +++ b/xbmc/guilib/GUIIncludes.cpp @@ -529,7 +529,8 @@ void CGUIIncludes::InsertNested(TiXmlElement *controls, TiXmlElement *include, T } child = child->NextSiblingElement(); } - target->RemoveChild(nested); + if (nested != node) + target->RemoveChild(nested); } } diff --git a/xbmc/guilib/GUILabelControl.dox b/xbmc/guilib/GUILabelControl.dox index 8501c93114..44bce19494 100644 --- a/xbmc/guilib/GUILabelControl.dox +++ b/xbmc/guilib/GUILabelControl.dox @@ -68,9 +68,7 @@ want to be able to give it more content than will fit on one line, then setting: <wrapmultiline>true</wrapmultiline> ~~~~~~~~~~~~~ -will cause the text to be cut up (at the spaces in the text) onto multiple lines. -Note that if a single word is larger than <b>`<width>`</b> then it will not be cut, and -will still overflow. +Will cause the text to be cut up onto multiple lines. -------------------------------------------------------------------------------- diff --git a/xbmc/guilib/GUIMultiImage.cpp b/xbmc/guilib/GUIMultiImage.cpp index e42dc8b1b3..efc5c18b4b 100644 --- a/xbmc/guilib/GUIMultiImage.cpp +++ b/xbmc/guilib/GUIMultiImage.cpp @@ -9,6 +9,7 @@ #include "GUIMultiImage.h" #include "FileItem.h" +#include "FileItemList.h" #include "GUIMessage.h" #include "ServiceBroker.h" #include "TextureCache.h" diff --git a/xbmc/guilib/GUITextLayout.cpp b/xbmc/guilib/GUITextLayout.cpp index 1a300f4bb2..11c671b110 100644 --- a/xbmc/guilib/GUITextLayout.cpp +++ b/xbmc/guilib/GUITextLayout.cpp @@ -14,6 +14,9 @@ #include "GUIFont.h" #include "utils/CharsetConverter.h" #include "utils/StringUtils.h" +#include "utils/log.h" + +#include <limits> CGUIString::CGUIString(iString start, iString end, bool carriageReturn) { @@ -262,7 +265,7 @@ void CGUITextLayout::UpdateStyled(const vecText& text, m_colors = colors; // if we need to wrap the text, then do so - if (m_wrap && maxWidth > 0) + if (m_wrap) WrapText(text, maxWidth); else LineBreakText(text, m_lines); @@ -540,75 +543,103 @@ void CGUITextLayout::WrapText(const vecText &text, float maxWidth) if (!m_font) return; - int nMaxLines = (m_maxHeight > 0 && m_font->GetLineHeight() > 0)?(int)ceilf(m_maxHeight / m_font->GetLineHeight()):-1; - m_lines.clear(); + if (maxWidth < 0) + { + CLog::LogF(LOGWARNING, "Cannot wrap the text due to invalid max width value."); + return; + } + + if (maxWidth == 0) // Unlimited max width + { + LineBreakText(text, m_lines); + return; + } + std::vector<CGUIString> lines; LineBreakText(text, lines); - for (unsigned int i = 0; i < lines.size(); i++) + size_t nMaxLines; + if (m_maxHeight > 0 && m_font->GetLineHeight() > 0) + nMaxLines = static_cast<size_t>(std::ceil(m_maxHeight / m_font->GetLineHeight())); + else + nMaxLines = std::numeric_limits<size_t>::max(); + + // Split lines that exceed the maximum width, + // lines can be split by last space char or if there are no spaces by character + // to mimics the line behavior of word processors + for (const CGUIString& line : lines) { - const CGUIString &line = lines[i]; - vecText::const_iterator lastSpace = line.m_text.begin(); + if (m_lines.size() >= nMaxLines) + return; + + if (line.m_text.empty()) // Blank line + { + m_lines.emplace_back(line); + continue; + } + vecText::const_iterator pos = line.m_text.begin(); - unsigned int lastSpaceInLine = 0; + vecText::const_iterator lastBeginPos = line.m_text.begin(); + vecText::const_iterator lastSpacePos = line.m_text.end(); vecText curLine; - while (pos != line.m_text.end()) + + while (pos < line.m_text.end()) { // Get the current letter in the string - character_t letter = *pos; - // check for a space - if (CanWrapAtLetter(letter)) + const character_t& letter = *pos; + + if (CanWrapAtLetter(letter)) // Check for a space char + lastSpacePos = pos; + + curLine.emplace_back(letter); + + const float currWidth = m_font->GetTextWidth(curLine); + + if (currWidth > maxWidth) { - float width = m_font->GetTextWidth(curLine); - if (width > maxWidth) + if (lastSpacePos > pos) // No space char where split the line, so split by char { - if (lastSpace != line.m_text.begin() && lastSpaceInLine > 0) - { - CGUIString string(curLine.begin(), curLine.begin() + lastSpaceInLine, false); - m_lines.push_back(string); - // check for exceeding our number of lines - if (nMaxLines > 0 && m_lines.size() >= (size_t)nMaxLines) - return; - // skip over spaces - pos = lastSpace; - while (pos != line.m_text.end() && IsSpace(*pos)) - ++pos; - curLine.clear(); - lastSpaceInLine = 0; - lastSpace = line.m_text.begin(); - continue; - } + // If the pos is equal to lastBeginPos, maxWidth is not large enough to contain 1 character + // Push a line with the single character and move on to the next character. + if (pos == lastBeginPos) + ++pos; + + CGUIString linePart{lastBeginPos, pos, false}; + m_lines.emplace_back(linePart); } - lastSpace = pos; - lastSpaceInLine = curLine.size(); + else + { + CGUIString linePart{lastBeginPos, lastSpacePos, false}; + m_lines.emplace_back(linePart); + + pos = lastSpacePos + 1; + lastSpacePos = line.m_text.end(); + } + + curLine.clear(); + lastBeginPos = pos; + + if (m_lines.size() >= nMaxLines) + return; + + continue; } - curLine.push_back(letter); + ++pos; } - // now add whatever we have left to the string - float width = m_font->GetTextWidth(curLine); - if (width > maxWidth) + + // Add the remaining text part + if (!curLine.empty()) { - // too long - put up to the last space on if we can + remove it from what's left. - if (lastSpace != line.m_text.begin() && lastSpaceInLine > 0) - { - CGUIString string(curLine.begin(), curLine.begin() + lastSpaceInLine, false); - m_lines.push_back(string); - // check for exceeding our number of lines - if (nMaxLines > 0 && m_lines.size() >= (size_t)nMaxLines) - return; - curLine.erase(curLine.begin(), curLine.begin() + lastSpaceInLine); - while (curLine.size() && IsSpace(curLine.at(0))) - curLine.erase(curLine.begin()); - } + CGUIString linePart{curLine.begin(), curLine.end(), false}; + m_lines.emplace_back(linePart); } - CGUIString string(curLine.begin(), curLine.end(), true); - m_lines.push_back(string); - // check for exceeding our number of lines - if (nMaxLines > 0 && m_lines.size() >= (size_t)nMaxLines) - return; + + // Restore carriage return marker for the end of paragraph + if (!m_lines.empty()) + m_lines.back().m_carriageReturn = line.m_carriageReturn; } } diff --git a/xbmc/guilib/TextureGL.cpp b/xbmc/guilib/TextureGL.cpp index a2cf428b23..300098dbb1 100644 --- a/xbmc/guilib/TextureGL.cpp +++ b/xbmc/guilib/TextureGL.cpp @@ -12,6 +12,7 @@ #include "guilib/TextureManager.h" #include "rendering/RenderSystem.h" #include "settings/AdvancedSettings.h" +#include "settings/SettingsComponent.h" #include "utils/GLUtils.h" #include "utils/MemUtils.h" #include "utils/log.h" @@ -91,6 +92,16 @@ void CGLTexture::LoadToGPU() glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); +#ifdef GL_TEXTURE_MAX_ANISOTROPY_EXT + if (CServiceBroker::GetRenderSystem()->IsExtSupported("GL_EXT_texture_filter_anisotropic")) + { + int32_t aniso = + CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_guiAnisotropicFiltering; + if (aniso > 1) + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso); + } +#endif + unsigned int maxSize = CServiceBroker::GetRenderSystem()->GetMaxTextureSize(); if (m_textureHeight > maxSize) { diff --git a/xbmc/guilib/guiinfo/GUIInfoLabels.h b/xbmc/guilib/guiinfo/GUIInfoLabels.h index 8c17ce2a49..68faf15e98 100644 --- a/xbmc/guilib/guiinfo/GUIInfoLabels.h +++ b/xbmc/guilib/guiinfo/GUIInfoLabels.h @@ -72,7 +72,6 @@ #define PLAYER_HAS_RESOLUTIONS 64 #define PLAYER_FRAMEADVANCE 65 #define PLAYER_ICON 66 -#define PLAYER_CUTLIST 67 #define PLAYER_CHAPTERS 68 #define PLAYER_EDITLIST 69 #define PLAYER_CUTS 70 @@ -568,8 +567,6 @@ #define SYSTEM_BUILD_VERSION_CODE 1007 #define SYSTEM_BUILD_VERSION_GIT 1008 -static constexpr unsigned int SYSTEM_LOCALE_TIMEZONECOUNTRY = 1009; -static constexpr unsigned int SYSTEM_LOCALE_TIMEZONE = 1010; static constexpr unsigned int SYSTEM_LOCALE_REGION = 1011; static constexpr unsigned int SYSTEM_LOCALE = 1012; diff --git a/xbmc/guilib/guiinfo/LibraryGUIInfo.cpp b/xbmc/guilib/guiinfo/LibraryGUIInfo.cpp index f7aceadb7f..0ffcafee4b 100644 --- a/xbmc/guilib/guiinfo/LibraryGUIInfo.cpp +++ b/xbmc/guilib/guiinfo/LibraryGUIInfo.cpp @@ -9,6 +9,7 @@ #include "guilib/guiinfo/LibraryGUIInfo.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "URL.h" #include "filesystem/Directory.h" diff --git a/xbmc/guilib/guiinfo/PicturesGUIInfo.cpp b/xbmc/guilib/guiinfo/PicturesGUIInfo.cpp index e2af0e1792..e5920850fe 100644 --- a/xbmc/guilib/guiinfo/PicturesGUIInfo.cpp +++ b/xbmc/guilib/guiinfo/PicturesGUIInfo.cpp @@ -20,11 +20,13 @@ #include "utils/StringUtils.h" #include "utils/URIUtils.h" #include "utils/log.h" +#include "video/VideoFileItemClassify.h" #include <map> #include <memory> using namespace KODI::GUILIB::GUIINFO; +using namespace KODI; static const std::map<int, int> listitem2slideshow_map = { @@ -251,7 +253,7 @@ bool CPicturesGUIInfo::GetBool(bool& value, const CGUIListItem *gitem, int conte case SLIDESHOW_ISVIDEO: { CSlideShowDelegator& slideShow = CServiceBroker::GetSlideShowDelegator(); - value = slideShow.GetCurrentSlide() && slideShow.GetCurrentSlide()->IsVideo(); + value = slideShow.GetCurrentSlide() && VIDEO::IsVideo(*slideShow.GetCurrentSlide()); return true; } } diff --git a/xbmc/guilib/guiinfo/PlayerGUIInfo.cpp b/xbmc/guilib/guiinfo/PlayerGUIInfo.cpp index 3a8e6729e9..4ec5d88952 100644 --- a/xbmc/guilib/guiinfo/PlayerGUIInfo.cpp +++ b/xbmc/guilib/guiinfo/PlayerGUIInfo.cpp @@ -296,7 +296,6 @@ bool CPlayerGUIInfo::GetLabel(std::string& value, const CFileItem *item, int con case PLAYER_EDITLIST: case PLAYER_CUTS: case PLAYER_SCENE_MARKERS: - case PLAYER_CUTLIST: case PLAYER_CHAPTERS: value = GetContentRanges(info.m_info); return true; @@ -637,7 +636,6 @@ std::string CPlayerGUIInfo::GetContentRanges(int iInfo) const switch (iInfo) { case PLAYER_EDITLIST: - case PLAYER_CUTLIST: ranges = GetEditList(data, duration); break; case PLAYER_CUTS: diff --git a/xbmc/guilib/guiinfo/SystemGUIInfo.cpp b/xbmc/guilib/guiinfo/SystemGUIInfo.cpp index 9a05031e0e..bfad92a308 100644 --- a/xbmc/guilib/guiinfo/SystemGUIInfo.cpp +++ b/xbmc/guilib/guiinfo/SystemGUIInfo.cpp @@ -9,6 +9,7 @@ #include "guilib/guiinfo/SystemGUIInfo.h" #include "FileItem.h" +#include "FileItemList.h" #include "GUIPassword.h" #include "LangInfo.h" #include "ServiceBroker.h" @@ -327,20 +328,6 @@ bool CSystemGUIInfo::GetLabel(std::string& value, const CFileItem *item, int con return true; } - case SYSTEM_LOCALE_TIMEZONECOUNTRY: - { - value = CServiceBroker::GetSettingsComponent()->GetSettings()->GetString( - CSettings::SETTING_LOCALE_TIMEZONECOUNTRY); - return true; - } - - case SYSTEM_LOCALE_TIMEZONE: - { - value = CServiceBroker::GetSettingsComponent()->GetSettings()->GetString( - CSettings::SETTING_LOCALE_TIMEZONE); - return true; - } - case SYSTEM_LOCALE_REGION: { value = g_langInfo.GetCurrentRegion(); diff --git a/xbmc/guilib/guiinfo/VideoGUIInfo.cpp b/xbmc/guilib/guiinfo/VideoGUIInfo.cpp index 3c2e32a279..9e440b2539 100644 --- a/xbmc/guilib/guiinfo/VideoGUIInfo.cpp +++ b/xbmc/guilib/guiinfo/VideoGUIInfo.cpp @@ -35,6 +35,7 @@ #include "utils/StringUtils.h" #include "utils/URIUtils.h" #include "utils/log.h" +#include "video/VideoFileItemClassify.h" #include "video/VideoInfoTag.h" #include "video/VideoManagerTypes.h" #include "video/VideoThumbLoader.h" @@ -43,6 +44,7 @@ using namespace KODI::GUILIB; using namespace KODI::GUILIB::GUIINFO; +using namespace KODI; CVideoGUIInfo::CVideoGUIInfo() : m_appPlayer(CServiceBroker::GetAppComponents().GetComponent<CApplicationPlayer>()) @@ -61,7 +63,7 @@ int CVideoGUIInfo::GetPercentPlayed(const CVideoInfoTag* tag) const bool CVideoGUIInfo::InitCurrentItem(CFileItem *item) { - if (item && item->IsVideo()) + if (item && VIDEO::IsVideo(*item)) { // special case where .strm is used to start an audio stream if (item->IsInternetStream() && m_appPlayer->IsPlayingAudio()) @@ -479,7 +481,7 @@ bool CVideoGUIInfo::GetLabel(std::string& value, const CFileItem *item, int cont return true; case LISTITEM_FILENAME: case LISTITEM_FILE_EXTENSION: - if (item->IsVideoDb()) + if (VIDEO::IsVideoDb(*item)) value = URIUtils::GetFileName(tag->m_strFileNameAndPath); else if (item->HasMusicInfoTag()) // special handling for music videos, which have both a videotag and a musictag break; @@ -494,7 +496,7 @@ bool CVideoGUIInfo::GetLabel(std::string& value, const CFileItem *item, int cont return true; case LISTITEM_FOLDERNAME: case LISTITEM_PATH: - if (item->IsVideoDb()) + if (VIDEO::IsVideoDb(*item)) { if (item->m_bIsFolder) value = tag->m_strPath; @@ -515,7 +517,7 @@ bool CVideoGUIInfo::GetLabel(std::string& value, const CFileItem *item, int cont } return true; case LISTITEM_FILENAME_AND_PATH: - if (item->IsVideoDb()) + if (VIDEO::IsVideoDb(*item)) value = tag->m_strFileNameAndPath; else if (item->HasMusicInfoTag()) // special handling for music videos, which have both a videotag and a musictag break; diff --git a/xbmc/guilib/listproviders/DirectoryProvider.cpp b/xbmc/guilib/listproviders/DirectoryProvider.cpp index 71233786bc..16e54b958a 100644 --- a/xbmc/guilib/listproviders/DirectoryProvider.cpp +++ b/xbmc/guilib/listproviders/DirectoryProvider.cpp @@ -34,6 +34,7 @@ #include "utils/XMLUtils.h" #include "utils/guilib/GUIContentUtils.h" #include "utils/log.h" +#include "video/VideoFileItemClassify.h" #include "video/VideoInfoTag.h" #include "video/VideoThumbLoader.h" #include "video/VideoUtils.h" @@ -47,6 +48,7 @@ using namespace XFILE; using namespace KODI::MESSAGING; +using namespace KODI::VIDEO; using namespace PVR; class CDirectoryJob : public CJob @@ -133,7 +135,7 @@ public: std::shared_ptr<CThumbLoader> getThumbLoader(const CGUIStaticItemPtr& item) { - if (item->IsVideo()) + if (IsVideo(*item)) { initThumbLoader<CVideoThumbLoader>(InfoTagType::VIDEO); return m_thumbloaders[InfoTagType::VIDEO]; diff --git a/xbmc/input/keyboard/KeyboardLayoutManager.cpp b/xbmc/input/keyboard/KeyboardLayoutManager.cpp index 4727a633ed..98ba2c5020 100644 --- a/xbmc/input/keyboard/KeyboardLayoutManager.cpp +++ b/xbmc/input/keyboard/KeyboardLayoutManager.cpp @@ -9,6 +9,7 @@ #include "KeyboardLayoutManager.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "URL.h" #include "filesystem/Directory.h" diff --git a/xbmc/input/keymaps/ButtonTranslator.cpp b/xbmc/input/keymaps/ButtonTranslator.cpp index a7d3e50e57..34aa0164bd 100644 --- a/xbmc/input/keymaps/ButtonTranslator.cpp +++ b/xbmc/input/keymaps/ButtonTranslator.cpp @@ -10,6 +10,7 @@ #include "AppTranslator.h" #include "FileItem.h" +#include "FileItemList.h" #include "filesystem/Directory.h" #include "guilib/WindowIDs.h" #include "input/WindowTranslator.h" diff --git a/xbmc/interfaces/AnnouncementManager.cpp b/xbmc/interfaces/AnnouncementManager.cpp index 2718adf0d5..46fd378615 100644 --- a/xbmc/interfaces/AnnouncementManager.cpp +++ b/xbmc/interfaces/AnnouncementManager.cpp @@ -18,6 +18,7 @@ #include "utils/Variant.h" #include "utils/log.h" #include "video/VideoDatabase.h" +#include "video/VideoFileItemClassify.h" #include <memory> #include <mutex> @@ -26,6 +27,7 @@ #define LOOKUP_PROPERTY "database-lookup" using namespace ANNOUNCEMENT; +using namespace KODI::VIDEO; const std::string CAnnouncementManager::ANNOUNCEMENT_SENDER = "xbmc"; @@ -296,7 +298,7 @@ void CAnnouncementManager::DoAnnounce(AnnouncementFlag flag, object["item"]["artist"] = item->GetMusicInfoTag()->GetArtist(); } } - else if (item->IsVideo()) + else if (IsVideo(*item)) { // video item but has no video info tag. type = "movie"; diff --git a/xbmc/interfaces/builtins/PlayerBuiltins.cpp b/xbmc/interfaces/builtins/PlayerBuiltins.cpp index d8ff27f1ca..2173959123 100644 --- a/xbmc/interfaces/builtins/PlayerBuiltins.cpp +++ b/xbmc/interfaces/builtins/PlayerBuiltins.cpp @@ -9,6 +9,7 @@ #include "PlayerBuiltins.h" #include "FileItem.h" +#include "FileItemList.h" #include "GUIUserMessages.h" #include "PartyModeManager.h" #include "PlayListPlayer.h" @@ -38,6 +39,7 @@ #include "utils/URIUtils.h" #include "utils/log.h" #include "video/PlayerController.h" +#include "video/VideoFileItemClassify.h" #include "video/VideoUtils.h" #include "video/guilib/VideoGUIUtils.h" #include "video/guilib/VideoSelectActionProcessor.h" @@ -48,6 +50,8 @@ #include "Autorun.h" #endif +using namespace KODI::VIDEO; + /*! \brief Clear current playlist * \param params (ignored) */ @@ -434,7 +438,7 @@ void GetItemsForPlayList(const std::shared_ptr<CFileItem>& item, CFileItemList& PLAYLIST::Id GetPlayListId(const CFileItem& item) { PLAYLIST::Id playlistId{PLAYLIST::TYPE_NONE}; - if (item.IsVideo()) + if (IsVideo(item)) playlistId = PLAYLIST::TYPE_VIDEO; else if (item.IsAudio()) playlistId = PLAYLIST::TYPE_MUSIC; @@ -538,7 +542,7 @@ int PlayOrQueueMedia(const std::vector<std::string>& params, bool forcePlay) bool containsVideo = false; for (const auto& i : items) { - const bool isVideo = i->IsVideo(); + const bool isVideo = IsVideo(*i); containsMusic |= !isVideo; containsVideo |= isVideo; @@ -556,7 +560,7 @@ int PlayOrQueueMedia(const std::vector<std::string>& params, bool forcePlay) { for (int i = items.Size() - 1; i >= 0; i--) //remove music entries { - if (!items[i]->IsVideo()) + if (!IsVideo(*items[i])) items.Remove(i); } } @@ -615,7 +619,7 @@ int PlayOrQueueMedia(const std::vector<std::string>& params, bool forcePlay) if (forcePlay) { - if ((item.IsAudio() || item.IsVideo()) && !item.IsSmartPlayList() && !item.IsPVR()) + if ((item.IsAudio() || IsVideo(item)) && !item.IsSmartPlayList() && !item.IsPVR()) { if (!item.HasProperty("playlist_type_hint")) item.SetProperty("playlist_type_hint", GetPlayListId(item)); diff --git a/xbmc/interfaces/json-rpc/AddonsOperations.cpp b/xbmc/interfaces/json-rpc/AddonsOperations.cpp index db6c90a191..3daac8cc0b 100644 --- a/xbmc/interfaces/json-rpc/AddonsOperations.cpp +++ b/xbmc/interfaces/json-rpc/AddonsOperations.cpp @@ -11,7 +11,6 @@ #include "JSONUtils.h" #include "ServiceBroker.h" #include "TextureCache.h" -#include "addons/AddonDatabase.h" #include "addons/AddonManager.h" #include "addons/PluginSource.h" #include "addons/addoninfo/AddonInfo.h" @@ -122,9 +121,8 @@ JSONRPC_STATUS CAddonsOperations::GetAddons(const std::string &method, ITranspor int start, end; HandleLimits(parameterObject, result, addons.size(), start, end); - CAddonDatabase addondb; for (int index = start; index < end; index++) - FillDetails(addons.at(index), parameterObject["properties"], result["addons"], addondb, true); + FillDetails(addons.at(index), parameterObject["properties"], result["addons"], true); return OK; } @@ -138,8 +136,7 @@ JSONRPC_STATUS CAddonsOperations::GetAddonDetails(const std::string &method, ITr addon->Type() >= AddonType::MAX_TYPES) return InvalidParams; - CAddonDatabase addondb; - FillDetails(addon, parameterObject["properties"], result["addon"], addondb); + FillDetails(addon, parameterObject["properties"], result["addon"], false); return OK; } @@ -272,8 +269,7 @@ static CVariant Serialize(const AddonPtr& addon) void CAddonsOperations::FillDetails(const std::shared_ptr<ADDON::IAddon>& addon, const CVariant& fields, CVariant& result, - CAddonDatabase& addondb, - bool append /* = false */) + bool append) { if (addon.get() == NULL) return; diff --git a/xbmc/interfaces/json-rpc/AddonsOperations.h b/xbmc/interfaces/json-rpc/AddonsOperations.h index 727f418999..cf78a2dba0 100644 --- a/xbmc/interfaces/json-rpc/AddonsOperations.h +++ b/xbmc/interfaces/json-rpc/AddonsOperations.h @@ -35,7 +35,6 @@ namespace JSONRPC static void FillDetails(const std::shared_ptr<ADDON::IAddon>& addon, const CVariant& fields, CVariant& result, - ADDON::CAddonDatabase& addondb, - bool append = false); + bool append); }; } diff --git a/xbmc/interfaces/json-rpc/AudioLibrary.cpp b/xbmc/interfaces/json-rpc/AudioLibrary.cpp index 3d6fa79d79..951cd7ae8d 100644 --- a/xbmc/interfaces/json-rpc/AudioLibrary.cpp +++ b/xbmc/interfaces/json-rpc/AudioLibrary.cpp @@ -9,6 +9,7 @@ #include "AudioLibrary.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "TextureDatabase.h" #include "Util.h" diff --git a/xbmc/interfaces/json-rpc/FileItemHandler.cpp b/xbmc/interfaces/json-rpc/FileItemHandler.cpp index 07426447e1..7a524fd337 100644 --- a/xbmc/interfaces/json-rpc/FileItemHandler.cpp +++ b/xbmc/interfaces/json-rpc/FileItemHandler.cpp @@ -9,6 +9,7 @@ #include "FileItemHandler.h" #include "AudioLibrary.h" +#include "FileItemList.h" #include "FileOperations.h" #include "ServiceBroker.h" #include "TextureDatabase.h" diff --git a/xbmc/interfaces/json-rpc/FileOperations.cpp b/xbmc/interfaces/json-rpc/FileOperations.cpp index 4658e99353..a495607ff9 100644 --- a/xbmc/interfaces/json-rpc/FileOperations.cpp +++ b/xbmc/interfaces/json-rpc/FileOperations.cpp @@ -10,6 +10,7 @@ #include "AudioLibrary.h" #include "FileItem.h" +#include "FileItemList.h" #include "MediaSource.h" #include "ServiceBroker.h" #include "URL.h" diff --git a/xbmc/interfaces/json-rpc/PVROperations.cpp b/xbmc/interfaces/json-rpc/PVROperations.cpp index 0ec809481c..07c8d93222 100644 --- a/xbmc/interfaces/json-rpc/PVROperations.cpp +++ b/xbmc/interfaces/json-rpc/PVROperations.cpp @@ -9,6 +9,7 @@ #include "PVROperations.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "pvr/PVRManager.h" #include "pvr/PVRPlaybackState.h" diff --git a/xbmc/interfaces/json-rpc/PlayerOperations.cpp b/xbmc/interfaces/json-rpc/PlayerOperations.cpp index 5029549541..02747f18fb 100644 --- a/xbmc/interfaces/json-rpc/PlayerOperations.cpp +++ b/xbmc/interfaces/json-rpc/PlayerOperations.cpp @@ -10,6 +10,7 @@ #include "AudioLibrary.h" #include "FileItem.h" +#include "FileItemList.h" #include "GUIInfoManager.h" #include "GUIUserMessages.h" #include "PartyModeManager.h" diff --git a/xbmc/interfaces/json-rpc/PlaylistOperations.cpp b/xbmc/interfaces/json-rpc/PlaylistOperations.cpp index 61e04ac711..49955bc68f 100644 --- a/xbmc/interfaces/json-rpc/PlaylistOperations.cpp +++ b/xbmc/interfaces/json-rpc/PlaylistOperations.cpp @@ -9,6 +9,7 @@ #include "PlaylistOperations.h" #include "FileItem.h" +#include "FileItemList.h" #include "GUIUserMessages.h" #include "PlayListPlayer.h" #include "ServiceBroker.h" diff --git a/xbmc/interfaces/json-rpc/ProfilesOperations.cpp b/xbmc/interfaces/json-rpc/ProfilesOperations.cpp index adfb010430..17facb7b0e 100644 --- a/xbmc/interfaces/json-rpc/ProfilesOperations.cpp +++ b/xbmc/interfaces/json-rpc/ProfilesOperations.cpp @@ -9,6 +9,7 @@ #include "ProfilesOperations.h" #include "FileItem.h" +#include "FileItemList.h" #include "GUIPassword.h" #include "ServiceBroker.h" #include "guilib/LocalizeStrings.h" diff --git a/xbmc/interfaces/json-rpc/TextureOperations.cpp b/xbmc/interfaces/json-rpc/TextureOperations.cpp index d6ffcc8761..d6915314bf 100644 --- a/xbmc/interfaces/json-rpc/TextureOperations.cpp +++ b/xbmc/interfaces/json-rpc/TextureOperations.cpp @@ -9,6 +9,7 @@ #include "TextureOperations.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "TextureCache.h" #include "TextureDatabase.h" diff --git a/xbmc/interfaces/json-rpc/VideoLibrary.cpp b/xbmc/interfaces/json-rpc/VideoLibrary.cpp index 0f7499ec0e..cb69a5f002 100644 --- a/xbmc/interfaces/json-rpc/VideoLibrary.cpp +++ b/xbmc/interfaces/json-rpc/VideoLibrary.cpp @@ -9,6 +9,7 @@ #include "VideoLibrary.h" #include "FileItem.h" +#include "FileItemList.h" #include "PVROperations.h" #include "ServiceBroker.h" #include "TextureDatabase.h" diff --git a/xbmc/interfaces/legacy/Control.cpp b/xbmc/interfaces/legacy/Control.cpp index 2ad9c2197e..d75778b5f5 100644 --- a/xbmc/interfaces/legacy/Control.cpp +++ b/xbmc/interfaces/legacy/Control.cpp @@ -9,6 +9,7 @@ #include "Control.h" #include "AddonUtils.h" +#include "FileItemList.h" #include "LanguageHook.h" #include "ServiceBroker.h" #include "WindowException.h" diff --git a/xbmc/interfaces/legacy/Dialog.cpp b/xbmc/interfaces/legacy/Dialog.cpp index 55812f9099..9674875ea1 100644 --- a/xbmc/interfaces/legacy/Dialog.cpp +++ b/xbmc/interfaces/legacy/Dialog.cpp @@ -7,6 +7,7 @@ */ #include "Dialog.h" +#include "FileItemList.h" #include "LanguageHook.h" #include "ListItem.h" #include "ModuleXbmcgui.h" diff --git a/xbmc/interfaces/legacy/ModuleXbmcplugin.cpp b/xbmc/interfaces/legacy/ModuleXbmcplugin.cpp index 0af97b71ac..bc399cc1c9 100644 --- a/xbmc/interfaces/legacy/ModuleXbmcplugin.cpp +++ b/xbmc/interfaces/legacy/ModuleXbmcplugin.cpp @@ -9,6 +9,7 @@ #include "ModuleXbmcplugin.h" #include "FileItem.h" +#include "FileItemList.h" #include "filesystem/PluginDirectory.h" namespace XBMCAddon diff --git a/xbmc/interfaces/legacy/ModuleXbmcvfs.cpp b/xbmc/interfaces/legacy/ModuleXbmcvfs.cpp index c6858e3617..0d2391523f 100644 --- a/xbmc/interfaces/legacy/ModuleXbmcvfs.cpp +++ b/xbmc/interfaces/legacy/ModuleXbmcvfs.cpp @@ -9,6 +9,7 @@ #include "ModuleXbmcvfs.h" #include "FileItem.h" +#include "FileItemList.h" #include "LanguageHook.h" #include "URL.h" #include "Util.h" diff --git a/xbmc/interfaces/legacy/PlayList.cpp b/xbmc/interfaces/legacy/PlayList.cpp index d6d19d8866..649bc89892 100644 --- a/xbmc/interfaces/legacy/PlayList.cpp +++ b/xbmc/interfaces/legacy/PlayList.cpp @@ -8,6 +8,7 @@ #include "PlayList.h" +#include "FileItemList.h" #include "PlayListPlayer.h" #include "ServiceBroker.h" #include "playlists/PlayListFactory.h" diff --git a/xbmc/interfaces/legacy/Player.cpp b/xbmc/interfaces/legacy/Player.cpp index 4fc961cd88..b3aff2dfd5 100644 --- a/xbmc/interfaces/legacy/Player.cpp +++ b/xbmc/interfaces/legacy/Player.cpp @@ -9,6 +9,7 @@ #include "Player.h" #include "AddonUtils.h" +#include "FileItemList.h" #include "GUIInfoManager.h" #include "GUIUserMessages.h" #include "ListItem.h" diff --git a/xbmc/interfaces/legacy/WindowXML.cpp b/xbmc/interfaces/legacy/WindowXML.cpp index 65dc6c47f9..b127496783 100644 --- a/xbmc/interfaces/legacy/WindowXML.cpp +++ b/xbmc/interfaces/legacy/WindowXML.cpp @@ -8,6 +8,7 @@ #include "WindowXML.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "WindowException.h" #include "WindowInterceptor.h" diff --git a/xbmc/music/ContextMenus.cpp b/xbmc/music/ContextMenus.cpp index 9d146083bc..22df28acd2 100644 --- a/xbmc/music/ContextMenus.cpp +++ b/xbmc/music/ContextMenus.cpp @@ -19,10 +19,12 @@ #include "playlists/PlayListTypes.h" #include "tags/MusicInfoTag.h" #include "utils/Variant.h" +#include "video/VideoFileItemClassify.h" #include <utility> using namespace CONTEXTMENU; +using namespace KODI; CMusicInfo::CMusicInfo(MediaType mediaType) : CStaticContextMenuAction(19033), m_mediaType(std::move(mediaType)) @@ -32,8 +34,10 @@ CMusicInfo::CMusicInfo(MediaType mediaType) bool CMusicInfo::IsVisible(const CFileItem& item) const { return (item.HasMusicInfoTag() && item.GetMusicInfoTag()->GetType() == m_mediaType) || - (m_mediaType == MediaTypeArtist && item.IsVideoDb() && item.HasProperty("artist_musicid")) || - (m_mediaType == MediaTypeAlbum && item.IsVideoDb() && item.HasProperty("album_musicid")); + (m_mediaType == MediaTypeArtist && VIDEO::IsVideoDb(item) && + item.HasProperty("artist_musicid")) || + (m_mediaType == MediaTypeAlbum && VIDEO::IsVideoDb(item) && + item.HasProperty("album_musicid")); } bool CMusicInfo::Execute(const std::shared_ptr<CFileItem>& item) const diff --git a/xbmc/music/GUIViewStateMusic.cpp b/xbmc/music/GUIViewStateMusic.cpp index f14f5015e4..a34d9170a2 100644 --- a/xbmc/music/GUIViewStateMusic.cpp +++ b/xbmc/music/GUIViewStateMusic.cpp @@ -9,6 +9,7 @@ #include "GUIViewStateMusic.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "filesystem/Directory.h" #include "filesystem/MusicDatabaseDirectory.h" @@ -23,8 +24,10 @@ #include "utils/FileExtensionProvider.h" #include "utils/SortUtils.h" #include "utils/log.h" +#include "video/VideoFileItemClassify.h" #include "view/ViewStateSettings.h" +using namespace KODI; using namespace XFILE; using namespace MUSICDATABASEDIRECTORY; @@ -503,7 +506,8 @@ CGUIViewStateWindowMusicNav::CGUIViewStateWindowMusicNav(const CFileItemList& it } else { - if (items.IsVideoDb() && items.Size() > (settings->GetBool(CSettings::SETTING_FILELISTS_SHOWPARENTDIRITEMS)?1:0)) + if (VIDEO::IsVideoDb(items) && + items.Size() > (settings->GetBool(CSettings::SETTING_FILELISTS_SHOWPARENTDIRITEMS) ? 1 : 0)) { XFILE::VIDEODATABASEDIRECTORY::CQueryParams params; XFILE::CVideoDatabaseDirectory::GetQueryParams(items[settings->GetBool(CSettings::SETTING_FILELISTS_SHOWPARENTDIRITEMS) ? 1 : 0]->GetPath(), params); diff --git a/xbmc/music/MusicDatabase.cpp b/xbmc/music/MusicDatabase.cpp index b5ba07ef8a..a98db00388 100644 --- a/xbmc/music/MusicDatabase.cpp +++ b/xbmc/music/MusicDatabase.cpp @@ -11,6 +11,7 @@ #include "Album.h" #include "Artist.h" #include "FileItem.h" +#include "FileItemList.h" #include "GUIInfoManager.h" #include "LangInfo.h" #include "ServiceBroker.h" diff --git a/xbmc/music/MusicInfoLoader.cpp b/xbmc/music/MusicInfoLoader.cpp index 7cfa0352ff..3ecaa4a417 100644 --- a/xbmc/music/MusicInfoLoader.cpp +++ b/xbmc/music/MusicInfoLoader.cpp @@ -11,6 +11,7 @@ #include "Album.h" #include "Artist.h" #include "FileItem.h" +#include "FileItemList.h" #include "MusicDatabase.h" #include "MusicThumbLoader.h" #include "ServiceBroker.h" diff --git a/xbmc/music/MusicUtils.cpp b/xbmc/music/MusicUtils.cpp index 0b0d13e556..1984cbb2e8 100644 --- a/xbmc/music/MusicUtils.cpp +++ b/xbmc/music/MusicUtils.cpp @@ -9,6 +9,7 @@ #include "MusicUtils.h" #include "FileItem.h" +#include "FileItemList.h" #include "GUIPassword.h" #include "PartyModeManager.h" #include "PlayListPlayer.h" @@ -40,10 +41,12 @@ #include "utils/StringUtils.h" #include "utils/URIUtils.h" #include "utils/log.h" +#include "video/VideoFileItemClassify.h" #include "view/GUIViewState.h" #include <memory> +using namespace KODI::VIDEO; using namespace MUSIC_INFO; using namespace XFILE; using namespace std::chrono_literals; @@ -606,7 +609,7 @@ void CAsyncGetItemsForPlaylist::GetItemsForPlaylist(const std::shared_ptr<CFileI // python files can be played m_queuedItems.Add(item); } - else if (!item->IsNFO() && (item->IsAudio() || item->IsVideo())) + else if (!item->IsNFO() && (item->IsAudio() || IsVideo(*item))) { const auto itemCheck = m_queuedItems.Get(item->GetPath()); if (!itemCheck || itemCheck->GetStartOffset() != item->GetStartOffset()) @@ -873,7 +876,7 @@ bool IsItemPlayable(const CFileItem& item) return false; // Exclude all video library items - if (item.IsVideoDb() || StringUtils::StartsWithNoCase(item.GetPath(), "library://video/")) + if (IsVideoDb(item) || StringUtils::StartsWithNoCase(item.GetPath(), "library://video/")) return false; // Exclude other components diff --git a/xbmc/music/dialogs/GUIDialogMusicInfo.cpp b/xbmc/music/dialogs/GUIDialogMusicInfo.cpp index d1559f77fd..fab40e850f 100644 --- a/xbmc/music/dialogs/GUIDialogMusicInfo.cpp +++ b/xbmc/music/dialogs/GUIDialogMusicInfo.cpp @@ -9,6 +9,7 @@ #include "GUIDialogMusicInfo.h" #include "FileItem.h" +#include "FileItemList.h" #include "GUIPassword.h" #include "GUIUserMessages.h" #include "ServiceBroker.h" diff --git a/xbmc/music/dialogs/GUIDialogSongInfo.h b/xbmc/music/dialogs/GUIDialogSongInfo.h index 274f1acc0f..7aba18a52a 100644 --- a/xbmc/music/dialogs/GUIDialogSongInfo.h +++ b/xbmc/music/dialogs/GUIDialogSongInfo.h @@ -9,6 +9,7 @@ #pragma once #include "FileItem.h" +#include "FileItemList.h" #include "guilib/GUIDialog.h" #include "threads/Event.h" diff --git a/xbmc/music/infoscanner/MusicInfoScanner.cpp b/xbmc/music/infoscanner/MusicInfoScanner.cpp index f828b44914..3236470c78 100644 --- a/xbmc/music/infoscanner/MusicInfoScanner.cpp +++ b/xbmc/music/infoscanner/MusicInfoScanner.cpp @@ -9,6 +9,7 @@ #include "MusicInfoScanner.h" #include "FileItem.h" +#include "FileItemList.h" #include "GUIInfoManager.h" #include "GUIUserMessages.h" #include "MusicAlbumInfo.h" diff --git a/xbmc/music/windows/GUIWindowMusicBase.cpp b/xbmc/music/windows/GUIWindowMusicBase.cpp index 9dc4e2dddd..b6ced56366 100644 --- a/xbmc/music/windows/GUIWindowMusicBase.cpp +++ b/xbmc/music/windows/GUIWindowMusicBase.cpp @@ -10,6 +10,7 @@ #include "Autorun.h" #include "FileItem.h" +#include "FileItemList.h" #include "GUIInfoManager.h" #include "GUIPassword.h" #include "GUIUserMessages.h" @@ -22,6 +23,7 @@ #include "application/Application.h" #include "application/ApplicationComponents.h" #include "application/ApplicationPlayer.h" +#include "video/VideoFileItemClassify.h" #ifdef HAS_CDDA_RIPPER #include "cdrip/CDDARipper.h" #endif @@ -73,6 +75,7 @@ using namespace MUSIC_GRABBER; using namespace MUSIC_INFO; using namespace KODI::MESSAGING; using KODI::MESSAGING::HELPERS::DialogResponse; +using namespace KODI::VIDEO; using namespace std::chrono_literals; @@ -297,7 +300,7 @@ void CGUIWindowMusicBase::OnItemInfo(int iItem) CFileItemPtr item = m_vecItems->Get(iItem); // Match visibility test of CMusicInfo::IsVisible - if (item->IsVideoDb() && item->HasVideoInfoTag() && + if (IsVideoDb(*item) && item->HasVideoInfoTag() && (item->HasProperty("artist_musicid") || item->HasProperty("album_musicid"))) { // Music video artist or album (navigation by music > music video > artist)) @@ -305,7 +308,7 @@ void CGUIWindowMusicBase::OnItemInfo(int iItem) return; } - if (item->IsVideo() && item->HasVideoInfoTag() && + if (IsVideo(*item) && item->HasVideoInfoTag() && item->GetVideoInfoTag()->m_type == MediaTypeMusicVideo) { // Music video on a mixed current playlist or navigation by music > music video > artist > video CGUIDialogVideoInfo::ShowFor(*item); @@ -348,7 +351,8 @@ void CGUIWindowMusicBase::RetrieveMusicInfo() for (int i = 0; i < m_vecItems->Size(); ++i) { CFileItemPtr pItem = (*m_vecItems)[i]; - if (pItem->m_bIsFolder || pItem->IsPlayList() || pItem->IsPicture() || pItem->IsLyrics() || pItem->IsVideo()) + if (pItem->m_bIsFolder || pItem->IsPlayList() || pItem->IsPicture() || pItem->IsLyrics() || + IsVideo(*pItem)) continue; CMusicInfoTag& tag = *pItem->GetMusicInfoTag(); @@ -728,7 +732,7 @@ bool CGUIWindowMusicBase::OnPlayMedia(int iItem, const std::string &player) void CGUIWindowMusicBase::OnRetrieveMusicInfo(CFileItemList& items) { // No need to attempt to read music file tags for music videos - if (items.IsVideoDb()) + if (IsVideoDb(items)) return; if (items.GetFolderCount()==items.Size() || items.IsMusicDb() || (!CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_MUSICFILES_USETAGS) && !items.IsCDDA())) diff --git a/xbmc/music/windows/GUIWindowMusicNav.cpp b/xbmc/music/windows/GUIWindowMusicNav.cpp index a544090204..086cbe607f 100644 --- a/xbmc/music/windows/GUIWindowMusicNav.cpp +++ b/xbmc/music/windows/GUIWindowMusicNav.cpp @@ -9,6 +9,7 @@ #include "GUIWindowMusicNav.h" #include "FileItem.h" +#include "FileItemList.h" #include "GUIPassword.h" #include "GUIUserMessages.h" #include "PartyModeManager.h" @@ -45,6 +46,7 @@ #include "utils/Variant.h" #include "utils/log.h" #include "video/VideoDatabase.h" +#include "video/VideoFileItemClassify.h" #include "video/dialogs/GUIDialogVideoInfo.h" #include "video/windows/GUIWindowVideoNav.h" #include "view/GUIViewState.h" @@ -53,6 +55,7 @@ using namespace XFILE; using namespace PLAYLIST; using namespace MUSICDATABASEDIRECTORY; using namespace KODI::MESSAGING; +using namespace KODI::VIDEO; #define CONTROL_BTNVIEWASICONS 2 #define CONTROL_BTNSORTBY 3 @@ -386,7 +389,7 @@ bool CGUIWindowMusicNav::GetDirectory(const std::string &strDirectory, CFileItem } // update our content in the info manager - if (StringUtils::StartsWithNoCase(strDirectory, "videodb://") || items.IsVideoDb()) + if (StringUtils::StartsWithNoCase(strDirectory, "videodb://") || IsVideoDb(items)) { CVideoDatabaseDirectory dir; VIDEODATABASEDIRECTORY::NODE_TYPE node = dir.GetDirectoryChildType(items.GetPath()); @@ -624,8 +627,8 @@ void CGUIWindowMusicNav::GetContextButtons(int itemNumber, CContextButtons &butt if (!item->IsParentFolder() && !dir.IsAllItem(item->GetPath())) { - if (item->m_bIsFolder && !item->IsVideoDb() && - !item->IsPlugin() && !StringUtils::StartsWithNoCase(item->GetPath(), "musicsearch://")) + if (item->m_bIsFolder && !IsVideoDb(*item) && !item->IsPlugin() && + !StringUtils::StartsWithNoCase(item->GetPath(), "musicsearch://")) { if (item->IsAlbum()) // enable query all albums button only in album view @@ -718,7 +721,7 @@ bool CGUIWindowMusicNav::OnContextButton(int itemNumber, CONTEXT_BUTTON button) { case CONTEXT_BUTTON_INFO: { - if (!item->IsVideoDb()) + if (!IsVideoDb(*item)) return CGUIWindowMusicBase::OnContextButton(itemNumber,button); // music videos - artists @@ -807,7 +810,7 @@ bool CGUIWindowMusicNav::OnContextButton(int itemNumber, CONTEXT_BUTTON button) } case CONTEXT_BUTTON_RENAME: - if (!item->IsVideoDb() && !item->IsReadOnly()) + if (!IsVideoDb(*item) && !item->IsReadOnly()) OnRenameItem(itemNumber); CGUIDialogVideoInfo::UpdateVideoItemTitle(item); @@ -823,7 +826,7 @@ bool CGUIWindowMusicNav::OnContextButton(int itemNumber, CONTEXT_BUTTON button) if (gui && gui->ConfirmDelete(item->GetPath())) CFileUtils::DeleteItem(item); } - else if (!item->IsVideoDb()) + else if (!IsVideoDb(*item)) OnDeleteItem(itemNumber); else { diff --git a/xbmc/music/windows/GUIWindowMusicPlaylist.cpp b/xbmc/music/windows/GUIWindowMusicPlaylist.cpp index fe1d72a163..85252b86f9 100644 --- a/xbmc/music/windows/GUIWindowMusicPlaylist.cpp +++ b/xbmc/music/windows/GUIWindowMusicPlaylist.cpp @@ -9,6 +9,7 @@ #include "GUIWindowMusicPlaylist.h" #include "FileItem.h" +#include "FileItemList.h" #include "GUIUserMessages.h" #include "PartyModeManager.h" #include "PlayListPlayer.h" diff --git a/xbmc/music/windows/GUIWindowMusicPlaylistEditor.cpp b/xbmc/music/windows/GUIWindowMusicPlaylistEditor.cpp index cf9e73e817..16ecdd0c3c 100644 --- a/xbmc/music/windows/GUIWindowMusicPlaylistEditor.cpp +++ b/xbmc/music/windows/GUIWindowMusicPlaylistEditor.cpp @@ -10,6 +10,7 @@ #include "Autorun.h" #include "FileItem.h" +#include "FileItemList.h" #include "GUIUserMessages.h" #include "ServiceBroker.h" #include "Util.h" diff --git a/xbmc/music/windows/MusicFileItemListModifier.cpp b/xbmc/music/windows/MusicFileItemListModifier.cpp index fe04aed423..5aef6139f2 100644 --- a/xbmc/music/windows/MusicFileItemListModifier.cpp +++ b/xbmc/music/windows/MusicFileItemListModifier.cpp @@ -9,6 +9,7 @@ #include "MusicFileItemListModifier.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "filesystem/MusicDatabaseDirectory/DirectoryNode.h" #include "guilib/LocalizeStrings.h" diff --git a/xbmc/network/AirPlayServer.cpp b/xbmc/network/AirPlayServer.cpp index eaa0aa58fd..6b30e11e06 100644 --- a/xbmc/network/AirPlayServer.cpp +++ b/xbmc/network/AirPlayServer.cpp @@ -12,6 +12,7 @@ #include "AirPlayServer.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "URL.h" #include "application/ApplicationComponents.h" diff --git a/xbmc/network/upnp/UPnPInternal.cpp b/xbmc/network/upnp/UPnPInternal.cpp index 734e7fd067..f03cab5e27 100644 --- a/xbmc/network/upnp/UPnPInternal.cpp +++ b/xbmc/network/upnp/UPnPInternal.cpp @@ -28,6 +28,7 @@ #include "utils/StringUtils.h" #include "utils/URIUtils.h" #include "utils/log.h" +#include "video/VideoFileItemClassify.h" #include "video/VideoInfoTag.h" #include <algorithm> @@ -38,6 +39,7 @@ #include <Platinum/Source/Platinum/Platinum.h> +using namespace KODI; using namespace MUSIC_INFO; using namespace XFILE; @@ -203,13 +205,13 @@ NPT_String GetMimeType(const CFileItem& item, const PLT_HttpRequestContext* cont /* fallback to generic mime type if not found */ if (mime.IsEmpty()) { - if (item.IsVideo() || item.IsVideoDb()) + if (VIDEO::IsVideo(item) || VIDEO::IsVideoDb(item)) mime = "video/" + ext; else if (item.IsAudio() || item.IsMusicDb()) mime = "audio/" + ext; else if (item.IsPicture()) mime = "image/" + ext; - else if (item.IsSubtitle()) + else if (VIDEO::IsSubtitle(item)) mime = "text/" + ext; } @@ -528,7 +530,7 @@ PLT_MediaObject* BuildObject(CFileItem& item, PopulateObjectFromTag(*tag, *object, &file_path, &resource, quirks, upnp_service); } } - else if (item.IsVideoDb() || item.IsVideo()) + else if (VIDEO::IsVideoDb(item) || VIDEO::IsVideo(item)) { object->m_ObjectClass.type = "object.item.videoItem"; @@ -672,7 +674,7 @@ PLT_MediaObject* BuildObject(CFileItem& item, break; } } - else if (item.IsVideoDb()) + else if (VIDEO::IsVideoDb(item)) { VIDEODATABASEDIRECTORY::NODE_TYPE node = CVideoDatabaseDirectory::GetDirectoryType(item.GetPath()); @@ -818,7 +820,7 @@ PLT_MediaObject* BuildObject(CFileItem& item, // look for and add external subtitle if we are processing a video file and // we are being called by a UPnP player or renderer or the user has chosen // to look for external subtitles - if (upnp_server != NULL && item.IsVideo() && + if (upnp_server != nullptr && VIDEO::IsVideo(item) && (upnp_service == UPnPPlayer || upnp_service == UPnPRenderer || settings->GetBool(CSettings::SETTING_SERVICES_UPNPLOOKFOREXTERNALSUBTITLES))) { diff --git a/xbmc/network/upnp/UPnPPlayer.cpp b/xbmc/network/upnp/UPnPPlayer.cpp index 0080141db6..93ef3a58a9 100644 --- a/xbmc/network/upnp/UPnPPlayer.cpp +++ b/xbmc/network/upnp/UPnPPlayer.cpp @@ -24,6 +24,7 @@ #include "utils/StringUtils.h" #include "utils/TimeUtils.h" #include "utils/log.h" +#include "video/VideoFileItemClassify.h" #include "video/VideoThumbLoader.h" #include <mutex> @@ -33,6 +34,7 @@ #include <Platinum/Source/Platinum/Platinum.h> using namespace KODI::MESSAGING; +using namespace KODI; using KODI::MESSAGING::HELPERS::DialogResponse; using namespace std::chrono_literals; @@ -223,7 +225,7 @@ int CUPnPPlayer::PlayFile(const CFileItem& file, NPT_CHECK_POINTER_LABEL_SEVERE(m_delegate, failed); - if (file.IsVideoDb()) + if (VIDEO::IsVideoDb(file)) thumb_loader = NPT_Reference<CThumbLoader>(new CVideoThumbLoader()); else if (item.IsMusicDb()) thumb_loader = NPT_Reference<CThumbLoader>(new CMusicThumbLoader()); @@ -383,7 +385,7 @@ bool CUPnPPlayer::OpenFile(const CFileItem& file, const CPlayerOptions& options) m_stopremote = true; m_started = true; - if (file.IsVideo()) + if (VIDEO::IsVideo(file)) { m_hasVideo = true; } @@ -417,7 +419,7 @@ bool CUPnPPlayer::QueueNextFile(const CFileItem& file) NPT_String path(file.GetPath().c_str()); NPT_String tmp; - if (file.IsVideoDb()) + if (VIDEO::IsVideoDb(file)) thumb_loader = NPT_Reference<CThumbLoader>(new CVideoThumbLoader()); else if (item.IsMusicDb()) thumb_loader = NPT_Reference<CThumbLoader>(new CMusicThumbLoader()); diff --git a/xbmc/network/upnp/UPnPRenderer.cpp b/xbmc/network/upnp/UPnPRenderer.cpp index a2374458b5..acc25a81a9 100644 --- a/xbmc/network/upnp/UPnPRenderer.cpp +++ b/xbmc/network/upnp/UPnPRenderer.cpp @@ -8,6 +8,7 @@ #include "UPnPRenderer.h" #include "FileItem.h" +#include "FileItemList.h" #include "GUIInfoManager.h" #include "GUIUserMessages.h" #include "ServiceBroker.h" @@ -30,12 +31,15 @@ #include "utils/StringUtils.h" #include "utils/URIUtils.h" #include "utils/Variant.h" +#include "video/VideoFileItemClassify.h" #include <inttypes.h> #include <mutex> #include <Platinum/Source/Platinum/Platinum.h> +using namespace KODI::VIDEO; + NPT_SET_LOCAL_LOGGER("xbmc.upnp.renderer") namespace UPNP @@ -628,7 +632,7 @@ NPT_Result CUPnPRenderer::OnSetNextAVTransportURI(PLT_ActionReference& action) { PLAYLIST::Id playlistId = PLAYLIST::TYPE_MUSIC; - if (item->IsVideo()) + if (IsVideo(*item)) playlistId = PLAYLIST::TYPE_VIDEO; // note: auto-deleted when the message is consumed diff --git a/xbmc/network/upnp/UPnPServer.cpp b/xbmc/network/upnp/UPnPServer.cpp index 3618708a5d..17e9cbebc9 100644 --- a/xbmc/network/upnp/UPnPServer.cpp +++ b/xbmc/network/upnp/UPnPServer.cpp @@ -7,6 +7,7 @@ */ #include "UPnPServer.h" +#include "FileItemList.h" #include "GUIUserMessages.h" #include "ServiceBroker.h" #include "TextureDatabase.h" @@ -38,6 +39,7 @@ #include "utils/Variant.h" #include "utils/log.h" #include "video/VideoDatabase.h" +#include "video/VideoFileItemClassify.h" #include "video/VideoLibraryQueue.h" #include "video/VideoThumbLoader.h" #include "view/GUIViewState.h" @@ -49,6 +51,7 @@ NPT_SET_LOCAL_LOGGER("xbmc.upnp.server") using namespace ANNOUNCEMENT; +using namespace KODI::VIDEO; using namespace XFILE; using KODI::UTILITY::CDigest; @@ -713,7 +716,7 @@ NPT_Result CUPnPServer::OnBrowseMetadata(PLT_ActionReference& action, parent = "sources://video/"; // this can only match video sources } - if (item->IsVideoDb()) + if (IsVideoDb(*item)) { thumb_loader = NPT_Reference<CThumbLoader>(new CVideoThumbLoader()); } @@ -1306,7 +1309,7 @@ NPT_Result CUPnPServer::OnUpdateObject(PLT_ActionReference& action, NPT_CHECK_LABEL(FindServiceById("urn:upnp-org:serviceId:ContentDirectory", service), error); NPT_CHECK_LABEL(service->PauseEventing(), error); - if (updated.IsVideoDb()) + if (IsVideoDb(updated)) { CVideoDatabase db; NPT_CHECK_LABEL(!db.Open(), error); @@ -1408,7 +1411,7 @@ NPT_Result CUPnPServer::OnUpdateObject(PLT_ActionReference& action, if (updatelisting) { updated.SetPath(path); - if (updated.IsVideoDb()) + if (IsVideoDb(updated)) CUtil::DeleteVideoDatabaseDirectoryCache(); else if (updated.IsMusicDb()) CUtil::DeleteMusicDatabaseDirectoryCache(); @@ -1525,7 +1528,7 @@ NPT_Result CUPnPServer::ServeFile(const NPT_HttpRequest& request, void CUPnPServer::DefaultSortItems(CFileItemList& items) { CGUIViewState* viewState = - CGUIViewState::GetViewState(items.IsVideoDb() ? WINDOW_VIDEO_NAV : -1, items); + CGUIViewState::GetViewState(IsVideoDb(items) ? WINDOW_VIDEO_NAV : -1, items); if (viewState) { SortDescription sorting = viewState->GetSortMethod(); diff --git a/xbmc/peripherals/addons/PeripheralAddon.cpp b/xbmc/peripherals/addons/PeripheralAddon.cpp index d55dfb55ce..2b7aca7584 100644 --- a/xbmc/peripherals/addons/PeripheralAddon.cpp +++ b/xbmc/peripherals/addons/PeripheralAddon.cpp @@ -9,6 +9,7 @@ #include "PeripheralAddon.h" #include "FileItem.h" +#include "FileItemList.h" #include "PeripheralAddonTranslator.h" #include "addons/addoninfo/AddonInfo.h" #include "addons/addoninfo/AddonType.h" diff --git a/xbmc/peripherals/bus/PeripheralBus.cpp b/xbmc/peripherals/bus/PeripheralBus.cpp index b59ba1dca3..f33b80181b 100644 --- a/xbmc/peripherals/bus/PeripheralBus.cpp +++ b/xbmc/peripherals/bus/PeripheralBus.cpp @@ -9,6 +9,7 @@ #include "PeripheralBus.h" #include "FileItem.h" +#include "FileItemList.h" #include "guilib/LocalizeStrings.h" #include "peripherals/Peripherals.h" #include "peripherals/devices/Peripheral.h" diff --git a/xbmc/peripherals/dialogs/GUIDialogPeripherals.h b/xbmc/peripherals/dialogs/GUIDialogPeripherals.h index 8a54e01aca..4eedb2e390 100644 --- a/xbmc/peripherals/dialogs/GUIDialogPeripherals.h +++ b/xbmc/peripherals/dialogs/GUIDialogPeripherals.h @@ -9,6 +9,7 @@ #pragma once #include "FileItem.h" +#include "FileItemList.h" #include "dialogs/GUIDialogSelect.h" #include "threads/CriticalSection.h" #include "utils/Observer.h" diff --git a/xbmc/pictures/GUIDialogPictureInfo.cpp b/xbmc/pictures/GUIDialogPictureInfo.cpp index 263b48238f..2a4b8cc665 100644 --- a/xbmc/pictures/GUIDialogPictureInfo.cpp +++ b/xbmc/pictures/GUIDialogPictureInfo.cpp @@ -9,6 +9,7 @@ #include "GUIDialogPictureInfo.h" #include "FileItem.h" +#include "FileItemList.h" #include "GUIInfoManager.h" #include "ServiceBroker.h" #include "guilib/GUIComponent.h" diff --git a/xbmc/pictures/GUIViewStatePictures.cpp b/xbmc/pictures/GUIViewStatePictures.cpp index 47d0cdff7a..5b9ebfd208 100644 --- a/xbmc/pictures/GUIViewStatePictures.cpp +++ b/xbmc/pictures/GUIViewStatePictures.cpp @@ -9,6 +9,7 @@ #include "GUIViewStatePictures.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "filesystem/Directory.h" #include "guilib/LocalizeStrings.h" diff --git a/xbmc/pictures/GUIWindowPictures.cpp b/xbmc/pictures/GUIWindowPictures.cpp index fa7ec34ade..b7345526fd 100644 --- a/xbmc/pictures/GUIWindowPictures.cpp +++ b/xbmc/pictures/GUIWindowPictures.cpp @@ -10,6 +10,7 @@ #include "Autorun.h" #include "FileItem.h" +#include "FileItemList.h" #include "GUIDialogPictureInfo.h" #include "GUIPassword.h" #include "GUIWindowSlideShow.h" @@ -40,6 +41,7 @@ #include "utils/Variant.h" #include "utils/XTimeUtils.h" #include "utils/log.h" +#include "video/VideoFileItemClassify.h" #include "view/GUIViewState.h" #define CONTROL_BTNSORTASC 4 @@ -47,6 +49,7 @@ using namespace XFILE; using namespace KODI::MESSAGING; +using namespace KODI::VIDEO; using namespace std::chrono_literals; @@ -294,7 +297,7 @@ bool CGUIWindowPictures::GetDirectory(const std::string &strDirectory, CFileItem bool CGUIWindowPictures::OnPlayMedia(int iItem, const std::string &player) { - if (m_vecItems->Get(iItem)->IsVideo()) + if (IsVideo(*m_vecItems->Get(iItem))) return CGUIMediaWindow::OnPlayMedia(iItem); return ShowPicture(iItem, false); @@ -327,7 +330,7 @@ bool CGUIWindowPictures::ShowPicture(int iItem, bool startSlideShow) { if (!pItem->m_bIsFolder && !(URIUtils::IsRAR(pItem->GetPath()) || URIUtils::IsZIP(pItem->GetPath())) && - (pItem->IsPicture() || (bShowVideos && pItem->IsVideo()))) + (pItem->IsPicture() || (bShowVideos && IsVideo(*pItem)))) { slideShow.Add(pItem.get()); } diff --git a/xbmc/pictures/GUIWindowSlideShow.cpp b/xbmc/pictures/GUIWindowSlideShow.cpp index b70745342e..4a47726dc8 100644 --- a/xbmc/pictures/GUIWindowSlideShow.cpp +++ b/xbmc/pictures/GUIWindowSlideShow.cpp @@ -9,6 +9,7 @@ #include "GUIWindowSlideShow.h" #include "FileItem.h" +#include "FileItemList.h" #include "GUIDialogPictureInfo.h" #include "GUIInfoManager.h" #include "GUIUserMessages.h" @@ -42,11 +43,13 @@ #include "utils/Variant.h" #include "utils/XTimeUtils.h" #include "utils/log.h" +#include "video/VideoFileItemClassify.h" #include <memory> #include <random> using namespace KODI; +using namespace KODI::VIDEO; using namespace MESSAGING; using namespace XFILE; using namespace std::chrono_literals; @@ -293,7 +296,7 @@ void CGUIWindowSlideShow::Add(const CFileItem *picture) // item without tag; get mimetype then we can tell whether it's video item item->FillInMimeType(); - if (!item->IsVideo()) + if (!IsVideo(*item)) // then it is a picture and force tag generation item->GetPictureInfoTag(); } @@ -446,13 +449,13 @@ void CGUIWindowSlideShow::Process(unsigned int currentTime, CDirtyRegionList &re { CLog::Log(LOGERROR, "Error loading the current image {}: {}", m_iCurrentSlide, m_slides.at(m_iCurrentSlide)->GetPath()); - if (!m_slides.at(m_iCurrentPic)->IsVideo()) + if (!IsVideo(*m_slides.at(m_iCurrentPic))) { // try next if we are in slideshow CLog::Log(LOGINFO, "set image {} unplayable", m_slides.at(m_iCurrentSlide)->GetPath()); m_slides.at(m_iCurrentSlide)->SetProperty("unplayable", true); } - if (m_bLoadNextPic || (bSlideShow && !m_bPause && !m_slides.at(m_iCurrentPic)->IsVideo())) + if (m_bLoadNextPic || (bSlideShow && !m_bPause && !IsVideo(*m_slides.at(m_iCurrentPic)))) { // change to next item, wait loading. m_iCurrentSlide = m_iNextSlide; @@ -467,7 +470,7 @@ void CGUIWindowSlideShow::Process(unsigned int currentTime, CDirtyRegionList &re CLog::Log(LOGERROR, "Error loading the next image {}: {}", m_iNextSlide, m_slides.at(m_iNextSlide)->GetPath()); // load next image failed, then skip to load next of next if next is not video. - if (!m_slides.at(m_iNextSlide)->IsVideo()) + if (!IsVideo(*m_slides.at(m_iNextSlide))) { CLog::Log(LOGINFO, "set image {} unplayable", m_slides.at(m_iNextSlide)->GetPath()); m_slides.at(m_iNextSlide)->SetProperty("unplayable", true); @@ -502,7 +505,7 @@ void CGUIWindowSlideShow::Process(unsigned int currentTime, CDirtyRegionList &re std::string picturePath = GetPicturePath(item.get()); if (!picturePath.empty()) { - if (item->IsVideo()) + if (IsVideo(*item)) CLog::Log(LOGDEBUG, "Loading the thumb {} for current video {}: {}", picturePath, m_iCurrentSlide, item->GetPath()); else @@ -532,9 +535,9 @@ void CGUIWindowSlideShow::Process(unsigned int currentTime, CDirtyRegionList &re m_iLastFailedNextSlide = -1; CFileItemPtr item = m_slides.at(m_iNextSlide); std::string picturePath = GetPicturePath(item.get()); - if (!picturePath.empty() && (!item->IsVideo() || !m_bSlideShow || m_bPause)) + if (!picturePath.empty() && (!IsVideo(*item) || !m_bSlideShow || m_bPause)) { - if (item->IsVideo()) + if (IsVideo(*item)) CLog::Log(LOGDEBUG, "Loading the thumb {} for next video {}: {}", picturePath, m_iNextSlide, item->GetPath()); else @@ -548,7 +551,7 @@ void CGUIWindowSlideShow::Process(unsigned int currentTime, CDirtyRegionList &re } } - bool bPlayVideo = m_slides.at(m_iCurrentSlide)->IsVideo() && m_iVideoSlide != m_iCurrentSlide; + bool bPlayVideo = IsVideo(*m_slides.at(m_iCurrentSlide)) && m_iVideoSlide != m_iCurrentSlide; if (bPlayVideo) bSlideShow = false; @@ -577,7 +580,7 @@ void CGUIWindowSlideShow::Process(unsigned int currentTime, CDirtyRegionList &re // render the next image if (m_Image[m_iCurrentPic]->DrawNextImage()) { - if (m_bSlideShow && !m_bPause && m_slides.at(m_iNextSlide)->IsVideo()) + if (m_bSlideShow && !m_bPause && IsVideo(*m_slides.at(m_iNextSlide))) { // do not show thumb of video when playing slideshow } @@ -599,7 +602,7 @@ void CGUIWindowSlideShow::Process(unsigned int currentTime, CDirtyRegionList &re m_Image[1 - m_iCurrentPic]->SetTransitionTime(0, m_Image[m_iCurrentPic]->GetTransitionTime(1)); m_Image[1 - m_iCurrentPic]->Pause(!m_bSlideShow || m_bPause || - m_slides.at(m_iNextSlide)->IsVideo()); + IsVideo(*m_slides.at(m_iNextSlide))); m_Image[1 - m_iCurrentPic]->Process(currentTime, regions); } else // next pic isn't loaded. We should hang around if it is in progress @@ -650,7 +653,7 @@ void CGUIWindowSlideShow::Process(unsigned int currentTime, CDirtyRegionList &re m_iCurrentSlide = m_iNextSlide; m_iNextSlide = GetNextSlide(); - bPlayVideo = m_slides.at(m_iCurrentSlide)->IsVideo() && m_iVideoSlide != m_iCurrentSlide; + bPlayVideo = IsVideo(*m_slides.at(m_iCurrentSlide)) && m_iVideoSlide != m_iCurrentSlide; } AnnouncePlayerPlay(m_slides.at(m_iCurrentSlide)); @@ -666,7 +669,7 @@ void CGUIWindowSlideShow::Process(unsigned int currentTime, CDirtyRegionList &re CServiceBroker::GetGUI()->GetInfoManager().GetInfoProviders().GetPicturesInfoProvider().SetCurrentSlide(m_slides.at(m_iCurrentSlide).get()); RenderPause(); - if (m_slides.at(m_iCurrentSlide)->IsVideo() && appPlayer && appPlayer->IsRenderingGuiLayer()) + if (IsVideo(*m_slides.at(m_iCurrentSlide)) && appPlayer && appPlayer->IsRenderingGuiLayer()) { MarkDirtyRegion(); } @@ -682,7 +685,7 @@ void CGUIWindowSlideShow::Render() CGraphicContext& gfxCtx = CServiceBroker::GetWinSystem()->GetGfxContext(); gfxCtx.Clear(0xff000000); - if (m_slides.at(m_iCurrentSlide)->IsVideo()) + if (IsVideo(*m_slides.at(m_iCurrentSlide))) { gfxCtx.SetViewWindow(0, 0, m_coordsRes.iWidth, m_coordsRes.iHeight); gfxCtx.SetRenderingResolution(gfxCtx.GetVideoResolution(), false); @@ -722,7 +725,7 @@ void CGUIWindowSlideShow::Render() void CGUIWindowSlideShow::RenderEx() { - if (m_slides.at(m_iCurrentSlide)->IsVideo()) + if (IsVideo(*m_slides.at(m_iCurrentSlide))) { auto& components = CServiceBroker::GetAppComponents(); const auto appPlayer = components.GetComponent<CApplicationPlayer>(); @@ -883,7 +886,7 @@ bool CGUIWindowSlideShow::OnAction(const CAction &action) case ACTION_PLAYER_PLAY: if (m_slides.size() == 0) break; - if (m_slides.at(m_iCurrentSlide)->IsVideo()) + if (IsVideo(*m_slides.at(m_iCurrentSlide))) { if (!m_bPlayingVideo) { @@ -1169,7 +1172,7 @@ void CGUIWindowSlideShow::Move(float fX, float fY) bool CGUIWindowSlideShow::PlayVideo() { CFileItemPtr item = m_slides.at(m_iCurrentSlide); - if (!item || !item->IsVideo()) + if (!item || !IsVideo(*item)) return false; CLog::Log(LOGDEBUG, "Playing current video slide {}", item->GetPath()); m_bPlayingVideo = true; @@ -1189,7 +1192,7 @@ bool CGUIWindowSlideShow::PlayVideo() CSlideShowPic::DISPLAY_EFFECT CGUIWindowSlideShow::GetDisplayEffect(int iSlideNumber) const { - if (m_bSlideShow && !m_bPause && !m_slides.at(iSlideNumber)->IsVideo()) + if (m_bSlideShow && !m_bPause && !IsVideo(*m_slides.at(iSlideNumber))) return CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_SLIDESHOW_DISPLAYEFFECTS) ? CSlideShowPic::EFFECT_RANDOM : CSlideShowPic::EFFECT_NONE; else return CSlideShowPic::EFFECT_NO_TIMEOUT; @@ -1376,7 +1379,7 @@ void CGUIWindowSlideShow::GetCheckedSize(float width, float height, int &maxWidt std::string CGUIWindowSlideShow::GetPicturePath(CFileItem *item) { - bool isVideo = item->IsVideo(); + bool isVideo = IsVideo(*item); std::string picturePath = item->GetDynPath(); if (isVideo) { diff --git a/xbmc/pictures/PictureFolderImageFileLoader.cpp b/xbmc/pictures/PictureFolderImageFileLoader.cpp index 1eb58f21b0..b80749b086 100644 --- a/xbmc/pictures/PictureFolderImageFileLoader.cpp +++ b/xbmc/pictures/PictureFolderImageFileLoader.cpp @@ -9,6 +9,7 @@ #include "PictureFolderImageFileLoader.h" #include "FileItem.h" +#include "FileItemList.h" #include "Picture.h" #include "ServiceBroker.h" #include "TextureCache.h" diff --git a/xbmc/pictures/PictureInfoLoader.cpp b/xbmc/pictures/PictureInfoLoader.cpp index 81b8cfac92..14a880bcec 100644 --- a/xbmc/pictures/PictureInfoLoader.cpp +++ b/xbmc/pictures/PictureInfoLoader.cpp @@ -9,10 +9,14 @@ #include "PictureInfoLoader.h" #include "FileItem.h" +#include "FileItemList.h" #include "PictureInfoTag.h" #include "ServiceBroker.h" #include "settings/Settings.h" #include "settings/SettingsComponent.h" +#include "video/VideoFileItemClassify.h" + +using namespace KODI; CPictureInfoLoader::CPictureInfoLoader() { @@ -50,7 +54,8 @@ bool CPictureInfoLoader::LoadItem(CFileItem* pItem) bool CPictureInfoLoader::LoadItemCached(CFileItem* pItem) { - if (!pItem->IsPicture() || pItem->IsZIP() || pItem->IsRAR() || pItem->IsCBR() || pItem->IsCBZ() || pItem->IsInternetStream() || pItem->IsVideo()) + if (!pItem->IsPicture() || pItem->IsZIP() || pItem->IsRAR() || pItem->IsCBR() || pItem->IsCBZ() || + pItem->IsInternetStream() || VIDEO::IsVideo(*pItem)) return false; if (pItem->HasPictureInfoTag()) @@ -73,7 +78,8 @@ bool CPictureInfoLoader::LoadItemLookup(CFileItem* pItem) if (m_pProgressCallback && !pItem->m_bIsFolder) m_pProgressCallback->SetProgressAdvance(); - if (!pItem->IsPicture() || pItem->IsZIP() || pItem->IsRAR() || pItem->IsCBR() || pItem->IsCBZ() || pItem->IsInternetStream() || pItem->IsVideo()) + if (!pItem->IsPicture() || pItem->IsZIP() || pItem->IsRAR() || pItem->IsCBR() || pItem->IsCBZ() || + pItem->IsInternetStream() || VIDEO::IsVideo(*pItem)) return false; if (pItem->HasPictureInfoTag()) diff --git a/xbmc/pictures/PictureThumbLoader.cpp b/xbmc/pictures/PictureThumbLoader.cpp index 97114e304e..0745c6e3ca 100644 --- a/xbmc/pictures/PictureThumbLoader.cpp +++ b/xbmc/pictures/PictureThumbLoader.cpp @@ -9,6 +9,7 @@ #include "PictureThumbLoader.h" #include "FileItem.h" +#include "FileItemList.h" #include "Picture.h" #include "ServiceBroker.h" #include "TextureCache.h" @@ -23,8 +24,10 @@ #include "utils/FileExtensionProvider.h" #include "utils/FileUtils.h" #include "utils/URIUtils.h" +#include "video/VideoFileItemClassify.h" #include "video/VideoThumbLoader.h" +using namespace KODI::VIDEO; using namespace XFILE; CPictureThumbLoader::CPictureThumbLoader() : CThumbLoader() @@ -78,7 +81,8 @@ bool CPictureThumbLoader::LoadItemCached(CFileItem* pItem) { // load the thumb from the image file thumb = pItem->HasArt("thumb") ? pItem->GetArt("thumb") : CTextureUtils::GetWrappedThumbURL(pItem->GetPath()); } - else if (pItem->IsVideo() && !pItem->IsZIP() && !pItem->IsRAR() && !pItem->IsCBZ() && !pItem->IsCBR() && !pItem->IsPlayList()) + else if (IsVideo(*pItem) && !pItem->IsZIP() && !pItem->IsRAR() && !pItem->IsCBZ() && + !pItem->IsCBR() && !pItem->IsPlayList()) { // video CVideoThumbLoader loader; loader.LoadItemCached(pItem); diff --git a/xbmc/platform/android/activity/XBMCApp.cpp b/xbmc/platform/android/activity/XBMCApp.cpp index 745d9a6b2c..437c7371d9 100644 --- a/xbmc/platform/android/activity/XBMCApp.cpp +++ b/xbmc/platform/android/activity/XBMCApp.cpp @@ -47,6 +47,7 @@ #include "utils/URIUtils.h" #include "utils/Variant.h" #include "utils/log.h" +#include "video/VideoFileItemClassify.h" #include "video/VideoInfoTag.h" #include "windowing/GraphicContext.h" #include "windowing/WinEvents.h" @@ -55,7 +56,6 @@ #include "platform/android/activity/IInputDeviceCallbacks.h" #include "platform/android/activity/IInputDeviceEventHandler.h" -#include "platform/android/network/NetworkAndroid.h" #include "platform/android/powermanagement/AndroidPowerSyscall.h" #include <memory> @@ -118,6 +118,7 @@ using namespace ANNOUNCEMENT; using namespace jni; using namespace KODI::GUILIB; +using namespace KODI::VIDEO; using namespace std::chrono_literals; std::shared_ptr<CNativeWindow> CNativeWindow::CreateFromSurface(CJNISurfaceHolder holder) @@ -214,14 +215,23 @@ void CXBMCApp::Announce(ANNOUNCEMENT::AnnouncementFlag flag, else if (message == "OnStop") OnPlayBackStopped(); else if (message == "OnSeek") + { + m_mediaSessionUpdated = false; UpdateSessionState(); + } else if (message == "OnSpeedChanged") + { + m_mediaSessionUpdated = false; UpdateSessionState(); + } } else if (flag & Info) { if (message == "OnChanged") + { + m_mediaSessionUpdated = false; UpdateSessionMetadata(); + } } } @@ -677,29 +687,6 @@ bool CXBMCApp::SetBuffersGeometry(int width, int height, int format) return false; } -void CXBMCApp::SetRefreshRateCallback(void* rateVariant) -{ - CVariant* rateV = static_cast<CVariant*>(rateVariant); - float rate = rateV->asFloat(); - delete rateV; - - CJNIWindow window = getWindow(); - if (window) - { - CJNIWindowManagerLayoutParams params = window.getAttributes(); - if (fabs(params.getpreferredRefreshRate() - rate) > 0.001f) - { - params.setpreferredRefreshRate(rate); - if (params.getpreferredRefreshRate() > 0.0f) - { - window.setAttributes(params); - return; - } - } - } - CXBMCApp::Get().m_displayChangeEvent.Set(); -} - void CXBMCApp::SetDisplayModeCallback(void* modeVariant) { CVariant* modeV = static_cast<CVariant*>(modeVariant); @@ -720,30 +707,6 @@ void CXBMCApp::SetDisplayModeCallback(void* modeVariant) CXBMCApp::Get().m_displayChangeEvent.Set(); } -void CXBMCApp::SetRefreshRate(float rate) -{ - if (rate < 1.0f) - return; - - CJNIWindow window = getWindow(); - if (window) - { - CJNIWindowManagerLayoutParams params = window.getAttributes(); - if (fabs(params.getpreferredRefreshRate() - rate) <= 0.001f) - return; - } - - m_refreshRate = rate; - m_displayChangeEvent.Reset(); - - if (m_hdmiSource) - dynamic_cast<CWinSystemAndroid*>(CServiceBroker::GetWinSystem())->InitiateModeChange(); - - CVariant *variant = new CVariant(rate); - runNativeOnUiThread(SetRefreshRateCallback, variant); - m_displayChangeEvent.Wait(5000ms); -} - void CXBMCApp::SetDisplayMode(int mode, float rate) { if (mode < 1.0) @@ -785,7 +748,7 @@ int CXBMCApp::android_printf(const char* format, ...) int len = vsnprintf(0, 0, format, args_copy); message.resize(len); result = vsnprintf(&message[0], len + 1, format, args); - CLog::Log(LOGDEBUG, message); + CLog::Log(LOGDEBUG, "{}", message); } else { @@ -885,6 +848,7 @@ void CXBMCApp::UpdateSessionState() float speed = 0.0; const auto& components = CServiceBroker::GetAppComponents(); const auto appPlayer = components.GetComponent<CApplicationPlayer>(); + uint32_t oldPlayState = m_playback_state; if (m_playback_state != PLAYBACK_STATE_STOPPED) { if (appPlayer->HasVideo()) @@ -908,9 +872,13 @@ void CXBMCApp::UpdateSessionState() else state = CJNIPlaybackState::STATE_STOPPED; - builder.setState(state, pos, speed, CJNISystemClock::elapsedRealtime()) - .setActions(CJNIPlaybackState::PLAYBACK_POSITION_UNKNOWN); - m_mediaSession->updatePlaybackState(builder.build()); + if ((oldPlayState != m_playback_state) || !m_mediaSessionUpdated) + { + builder.setState(state, pos, speed, CJNISystemClock::elapsedRealtime()) + .setActions(CJNIPlaybackState::PLAYBACK_POSITION_UNKNOWN); + m_mediaSession->updatePlaybackState(builder.build()); + m_mediaSessionUpdated = true; + } } void CXBMCApp::OnPlayBackStarted() @@ -928,6 +896,7 @@ void CXBMCApp::OnPlayBackStarted() m_playback_state |= PLAYBACK_STATE_CANNOT_PAUSE; m_mediaSession->activate(true); + m_mediaSessionUpdated = false; UpdateSessionState(); CJNIIntent intent(ACTION_XBMC_RESUME, CJNIURI::EMPTY, *this, get_class(CJNIContext::get_raw())); @@ -944,6 +913,7 @@ void CXBMCApp::OnPlayBackPaused() CLog::Log(LOGDEBUG, "{}", __PRETTY_FUNCTION__); m_playback_state &= ~PLAYBACK_STATE_PLAYING; + m_mediaSessionUpdated = false; UpdateSessionState(); RequestVisibleBehind(false); @@ -957,6 +927,7 @@ void CXBMCApp::OnPlayBackStopped() m_playback_state = PLAYBACK_STATE_STOPPED; UpdateSessionState(); m_mediaSession->activate(false); + m_mediaSessionUpdated = false; RequestVisibleBehind(false); CAndroidKey::SetHandleMediaKeys(true); @@ -977,7 +948,8 @@ std::vector<int> CXBMCApp::GetInputDeviceIds() void CXBMCApp::ProcessSlow() { - if ((m_playback_state & PLAYBACK_STATE_PLAYING) && m_mediaSession->isActive()) + if ((m_playback_state & PLAYBACK_STATE_PLAYING) && !m_mediaSessionUpdated && + m_mediaSession->isActive()) UpdateSessionState(); } @@ -1333,22 +1305,21 @@ void CXBMCApp::onReceive(CJNIIntent intent) } else if (action == CJNIAudioManager::ACTION_HDMI_AUDIO_PLUG) { - m_supportsHdmiAudioPlug = true; - const bool hdmiPlugged = (intent.getIntExtra(CJNIAudioManager::EXTRA_AUDIO_PLUG_STATE, 0) != 0); - android_printf("-- HDMI is plugged in: %s", hdmiPlugged ? "yes" : "no"); + m_hdmiPlugged = (intent.getIntExtra(CJNIAudioManager::EXTRA_AUDIO_PLUG_STATE, 0) != 0); + android_printf("-- HDMI is plugged in: %s", m_hdmiPlugged ? "yes" : "no"); if (g_application.IsInitialized()) { CWinSystemBase* winSystem = CServiceBroker::GetWinSystem(); if (winSystem && dynamic_cast<CWinSystemAndroid*>(winSystem)) - dynamic_cast<CWinSystemAndroid*>(winSystem)->SetHdmiState(hdmiPlugged); + dynamic_cast<CWinSystemAndroid*>(winSystem)->SetHdmiState(m_hdmiPlugged); } - if (hdmiPlugged && m_aeReset) + if (m_hdmiPlugged && m_aeReset) { android_printf("CXBMCApp::onReceive: Reset audio engine"); CServiceBroker::GetActiveAE()->DeviceChange(); m_aeReset = false; } - if (hdmiPlugged && m_wakeUp) + if (m_hdmiPlugged && m_wakeUp) { OnWakeup(); m_wakeUp = false; @@ -1362,11 +1333,11 @@ void CXBMCApp::onReceive(CJNIIntent intent) // screen but it is actually sent in response to changes in the overall interactive state of // the device. CLog::Log(LOGINFO, "Got device wakeup intent"); - if (m_supportsHdmiAudioPlug) + if (m_hdmiPlugged) + OnWakeup(); + else // wake-up sequence continues in ACTION_HDMI_AUDIO_PLUG intent m_wakeUp = true; - else - OnWakeup(); } else if (action == CJNIIntent::ACTION_SCREEN_OFF) { @@ -1412,18 +1383,6 @@ void CXBMCApp::onReceive(CJNIIntent intent) else if (keycode == CJNIKeyEvent::KEYCODE_MEDIA_STOP) CAndroidKey::XBMC_Key(keycode, XBMCK_MEDIA_STOP, 0, 0, up); } - else if (action == CJNIConnectivityManager::CONNECTIVITY_ACTION) - { - if (g_application.IsInitialized()) - { - if (CJNIBase::GetSDKVersion() < 24) - { - CNetworkBase& net = CServiceBroker::GetNetwork(); - CNetworkAndroid* netdroid = static_cast<CNetworkAndroid*>(&net); - netdroid->RetrieveInterfaces(); - } - } - } } void CXBMCApp::OnSleep() @@ -1494,7 +1453,7 @@ void CXBMCApp::onNewIntent(CJNIIntent intent) else { CFileItem* item = new CFileItem(targetFile, false); - if (item->IsVideoDb()) + if (IsVideoDb(*item)) { *(item->GetVideoInfoTag()) = XFILE::CVideoDatabaseFile::GetVideoTag(CURL(item->GetPath())); item->SetPath(item->GetVideoInfoTag()->m_strFileNameAndPath); diff --git a/xbmc/platform/android/activity/XBMCApp.h b/xbmc/platform/android/activity/XBMCApp.h index 93644c55b4..2e2d8670a0 100644 --- a/xbmc/platform/android/activity/XBMCApp.h +++ b/xbmc/platform/android/activity/XBMCApp.h @@ -179,7 +179,6 @@ public: static float GetSystemVolume(); static void SetSystemVolume(float percent); - void SetRefreshRate(float rate); void SetDisplayMode(int mode, float rate); int GetDPI() const; @@ -242,7 +241,6 @@ private: void run(); void stop(); void SetupEnv(); - static void SetRefreshRateCallback(void* rateVariant); static void SetDisplayModeCallback(void* modeVariant); static void KeepScreenOnCallback(void* onVariant); @@ -257,7 +255,8 @@ private: bool m_hdmiSource{false}; bool m_wakeUp{false}; bool m_aeReset{false}; - bool m_supportsHdmiAudioPlug{false}; + bool m_hdmiPlugged{true}; + bool m_mediaSessionUpdated{false}; IInputDeviceCallbacks* m_inputDeviceCallbacks{nullptr}; IInputDeviceEventHandler* m_inputDeviceEventHandler{nullptr}; bool m_hasReqVisible{false}; diff --git a/xbmc/platform/android/filesystem/APKDirectory.cpp b/xbmc/platform/android/filesystem/APKDirectory.cpp index df890bfed6..4cdcf5c529 100644 --- a/xbmc/platform/android/filesystem/APKDirectory.cpp +++ b/xbmc/platform/android/filesystem/APKDirectory.cpp @@ -10,6 +10,7 @@ #include "APKFile.h" #include "FileItem.h" +#include "FileItemList.h" #include "utils/CharsetConverter.h" #include "utils/StringUtils.h" #include "utils/URIUtils.h" diff --git a/xbmc/platform/android/filesystem/AndroidAppDirectory.cpp b/xbmc/platform/android/filesystem/AndroidAppDirectory.cpp index c2af2aae47..132f666618 100644 --- a/xbmc/platform/android/filesystem/AndroidAppDirectory.cpp +++ b/xbmc/platform/android/filesystem/AndroidAppDirectory.cpp @@ -10,6 +10,7 @@ #include "CompileInfo.h" #include "FileItem.h" +#include "FileItemList.h" #include "URL.h" #include "filesystem/File.h" #include "utils/StringUtils.h" diff --git a/xbmc/platform/android/network/NetworkAndroid.cpp b/xbmc/platform/android/network/NetworkAndroid.cpp index 3ebb3b1782..0db2e99c3b 100644 --- a/xbmc/platform/android/network/NetworkAndroid.cpp +++ b/xbmc/platform/android/network/NetworkAndroid.cpp @@ -237,11 +237,8 @@ CNetworkAndroid::CNetworkAndroid() : CNetworkBase(), CJNIXBMCConnectivityManager { RetrieveInterfaces(); - if (CJNIBase::GetSDKVersion() >= 24) - { - CJNIConnectivityManager connman{CXBMCApp::getSystemService(CJNIContext::CONNECTIVITY_SERVICE)}; - connman.registerDefaultNetworkCallback(this->get_raw()); - } + CJNIConnectivityManager connman{CXBMCApp::getSystemService(CJNIContext::CONNECTIVITY_SERVICE)}; + connman.registerDefaultNetworkCallback(this->get_raw()); } CNetworkAndroid::~CNetworkAndroid() @@ -251,11 +248,8 @@ CNetworkAndroid::~CNetworkAndroid() for (auto intf : m_oldInterfaces) delete intf; - if (CJNIBase::GetSDKVersion() >= 24) - { - CJNIConnectivityManager connman{CXBMCApp::getSystemService(CJNIContext::CONNECTIVITY_SERVICE)}; - connman.unregisterNetworkCallback(this->get_raw()); - } + CJNIConnectivityManager connman{CXBMCApp::getSystemService(CJNIContext::CONNECTIVITY_SERVICE)}; + connman.unregisterNetworkCallback(this->get_raw()); } bool CNetworkAndroid::GetHostName(std::string& hostname) diff --git a/xbmc/platform/android/storage/AndroidStorageProvider.cpp b/xbmc/platform/android/storage/AndroidStorageProvider.cpp index db9b71f1e4..1993d45e42 100644 --- a/xbmc/platform/android/storage/AndroidStorageProvider.cpp +++ b/xbmc/platform/android/storage/AndroidStorageProvider.cpp @@ -145,11 +145,19 @@ void CAndroidStorageProvider::GetLocalDrives(VECSOURCES &localDrives) void CAndroidStorageProvider::GetRemovableDrives(VECSOURCES& removableDrives) { - if (CJNIBase::GetSDKVersion() >= 24) + bool inError = false; + + CJNIStorageManager manager(CJNIContext::getSystemService(CJNIContext::STORAGE_SERVICE)); + if (xbmc_jnienv()->ExceptionCheck()) { - bool inError = false; + xbmc_jnienv()->ExceptionDescribe(); + xbmc_jnienv()->ExceptionClear(); + inError = true; + } - CJNIStorageManager manager(CJNIContext::getSystemService(CJNIContext::STORAGE_SERVICE)); + if (!inError) + { + CJNIStorageVolumes vols = manager.getStorageVolumes(); if (xbmc_jnienv()->ExceptionCheck()) { xbmc_jnienv()->ExceptionDescribe(); @@ -159,24 +167,36 @@ void CAndroidStorageProvider::GetRemovableDrives(VECSOURCES& removableDrives) if (!inError) { - CJNIStorageVolumes vols = manager.getStorageVolumes(); - if (xbmc_jnienv()->ExceptionCheck()) - { - xbmc_jnienv()->ExceptionDescribe(); - xbmc_jnienv()->ExceptionClear(); - inError = true; - } + VECSOURCES droidDrives; - if (!inError) + for (int i = 0; i < vols.size(); ++i) { - VECSOURCES droidDrives; + CJNIStorageVolume vol = vols.get(i); + // CLog::Log(LOGDEBUG, "-- Volume: {}({}) -- {}", vol.getPath(), vol.getUserLabel(), vol.getState()); + + bool removable = vol.isRemovable(); + if (xbmc_jnienv()->ExceptionCheck()) + { + xbmc_jnienv()->ExceptionDescribe(); + xbmc_jnienv()->ExceptionClear(); + inError = true; + break; + } - for (int i = 0; i < vols.size(); ++i) + std::string state = vol.getState(); + if (xbmc_jnienv()->ExceptionCheck()) { - CJNIStorageVolume vol = vols.get(i); - // CLog::Log(LOGDEBUG, "-- Volume: {}({}) -- {}", vol.getPath(), vol.getUserLabel(), vol.getState()); + xbmc_jnienv()->ExceptionDescribe(); + xbmc_jnienv()->ExceptionClear(); + inError = true; + break; + } - bool removable = vol.isRemovable(); + if (removable && state == CJNIEnvironment::MEDIA_MOUNTED) + { + CMediaSource share; + + share.strPath = vol.getPath(); if (xbmc_jnienv()->ExceptionCheck()) { xbmc_jnienv()->ExceptionDescribe(); @@ -185,7 +205,7 @@ void CAndroidStorageProvider::GetRemovableDrives(VECSOURCES& removableDrives) break; } - std::string state = vol.getState(); + share.strName = vol.getUserLabel(); if (xbmc_jnienv()->ExceptionCheck()) { xbmc_jnienv()->ExceptionDescribe(); @@ -194,43 +214,20 @@ void CAndroidStorageProvider::GetRemovableDrives(VECSOURCES& removableDrives) break; } - if (removable && state == CJNIEnvironment::MEDIA_MOUNTED) - { - CMediaSource share; - - share.strPath = vol.getPath(); - if (xbmc_jnienv()->ExceptionCheck()) - { - xbmc_jnienv()->ExceptionDescribe(); - xbmc_jnienv()->ExceptionClear(); - inError = true; - break; - } - - share.strName = vol.getUserLabel(); - if (xbmc_jnienv()->ExceptionCheck()) - { - xbmc_jnienv()->ExceptionDescribe(); - xbmc_jnienv()->ExceptionClear(); - inError = true; - break; - } + StringUtils::Trim(share.strName); + if (share.strName.empty() || share.strName == "?" || + StringUtils::EqualsNoCase(share.strName, "null")) + share.strName = URIUtils::GetFileName(share.strPath); - StringUtils::Trim(share.strName); - if (share.strName.empty() || share.strName == "?" || - StringUtils::EqualsNoCase(share.strName, "null")) - share.strName = URIUtils::GetFileName(share.strPath); - - share.m_ignore = true; - droidDrives.emplace_back(share); - } + share.m_ignore = true; + droidDrives.emplace_back(share); } + } - if (!inError) - { - removableDrives.insert(removableDrives.end(), droidDrives.begin(), droidDrives.end()); - return; - } + if (!inError) + { + removableDrives.insert(removableDrives.end(), droidDrives.begin(), droidDrives.end()); + return; } } } diff --git a/xbmc/platform/darwin/osx/MediaKeys.mm b/xbmc/platform/darwin/osx/MediaKeys.mm index 1b939da0eb..f2280e51b0 100644 --- a/xbmc/platform/darwin/osx/MediaKeys.mm +++ b/xbmc/platform/darwin/osx/MediaKeys.mm @@ -17,24 +17,32 @@ #import <AppKit/AppKit.h> #import <IOKit/hidsystem/ev_keymap.h> +#import <dispatch/dispatch.h> namespace { CGEventRef MediaKeyCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void* refcon) { - auto tap = (__bridge CMediaKeyTap*)refcon; - NSEvent* nsEvent = [NSEvent eventWithCGEvent:event]; - if (nsEvent.type == NSEventTypeSystemDefined && nsEvent.subtype == NX_SUBTYPE_AUX_CONTROL_BUTTONS) - { - const int keyCode = (([nsEvent data1] & 0xFFFF0000) >> 16); - const int keyFlags = ([nsEvent data1] & 0x0000FFFF); - const int keyState = (((keyFlags & 0xFF00) >> 8)) == 0xA; - if (keyState == 1) // if pressed + __block bool keyHandled = false; + dispatch_sync(dispatch_get_main_queue(), ^{ + auto tap = (__bridge CMediaKeyTap*)refcon; + NSEvent* nsEvent = [NSEvent eventWithCGEvent:event]; + if (nsEvent.type == NSEventTypeSystemDefined && + nsEvent.subtype == NX_SUBTYPE_AUX_CONTROL_BUTTONS) { - if ([tap HandleMediaKey:keyCode]) - return nullptr; + const int keyCode = (([nsEvent data1] & 0xFFFF0000) >> 16); + const int keyFlags = ([nsEvent data1] & 0x0000FFFF); + const int keyState = (((keyFlags & 0xFF00) >> 8)) == 0xA; + if (keyState == 1) // if pressed + { + if ([tap HandleMediaKey:keyCode]) + keyHandled = true; + } } - } + }); + if (keyHandled) + return nullptr; + return event; } } // namespace diff --git a/xbmc/platform/darwin/tvos/TVOSTopShelf.mm b/xbmc/platform/darwin/tvos/TVOSTopShelf.mm index 94690fea00..fb4770f5cd 100644 --- a/xbmc/platform/darwin/tvos/TVOSTopShelf.mm +++ b/xbmc/platform/darwin/tvos/TVOSTopShelf.mm @@ -10,6 +10,7 @@ #include "DatabaseManager.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "application/Application.h" #include "filesystem/File.h" diff --git a/xbmc/platform/darwin/tvos/filesystem/TVOSDirectory.cpp b/xbmc/platform/darwin/tvos/filesystem/TVOSDirectory.cpp index 0463943505..d0d25df5d6 100644 --- a/xbmc/platform/darwin/tvos/filesystem/TVOSDirectory.cpp +++ b/xbmc/platform/darwin/tvos/filesystem/TVOSDirectory.cpp @@ -21,6 +21,7 @@ #include "TVOSDirectory.h" #include "FileItem.h" +#include "FileItemList.h" #include "URL.h" #include "filesystem/SpecialProtocol.h" #include "utils/URIUtils.h" diff --git a/xbmc/platform/posix/CMakeLists.txt b/xbmc/platform/posix/CMakeLists.txt index 7907159cf9..aa6c2fca79 100644 --- a/xbmc/platform/posix/CMakeLists.txt +++ b/xbmc/platform/posix/CMakeLists.txt @@ -6,7 +6,6 @@ set(SOURCES ConvUtils.cpp PlatformPosix.cpp PosixMountProvider.cpp PosixResourceCounter.cpp - PosixTimezone.cpp XHandle.cpp XTimeUtils.cpp) @@ -17,7 +16,6 @@ set(HEADERS ConvUtils.h PlatformPosix.h PosixMountProvider.h PosixResourceCounter.h - PosixTimezone.h XHandle.h) core_add_library(platform_posix) diff --git a/xbmc/platform/posix/PosixTimezone.cpp b/xbmc/platform/posix/PosixTimezone.cpp deleted file mode 100644 index e76fd722e9..0000000000 --- a/xbmc/platform/posix/PosixTimezone.cpp +++ /dev/null @@ -1,285 +0,0 @@ -/* - * Copyright (C) 2005-2018 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 "PosixTimezone.h" - -#include "ServiceBroker.h" -#include "XBDateTime.h" -#include "settings/Settings.h" -#include "settings/SettingsComponent.h" -#include "settings/lib/Setting.h" -#include "settings/lib/SettingDefinitions.h" -#include "utils/StringUtils.h" -#include "utils/SystemInfo.h" - -#include <algorithm> -#include <climits> -#include <cstdlib> -#include <ctime> - -#include "PlatformDefs.h" - -CPosixTimezone::CPosixTimezone() -{ - char* line = NULL; - size_t linelen = 0; - int nameonfourthfield = 0; - std::string s; - std::vector<std::string> tokens; - - // Load timezones - FILE* fp = fopen("/usr/share/zoneinfo/zone.tab", "r"); - if (fp) - { - std::string countryCode; - std::string timezoneName; - - while (getdelim(&line, &linelen, '\n', fp) > 0) - { - tokens.clear(); - s = line; - StringUtils::Trim(s); - - if (s.length() == 0) - continue; - - if (s[0] == '#') - continue; - - StringUtils::Tokenize(s, tokens, " \t"); - if (tokens.size() < 3) - continue; - - countryCode = tokens[0]; - timezoneName = tokens[2]; - - if (m_timezonesByCountryCode.count(countryCode) == 0) - { - std::vector<std::string> timezones; - timezones.push_back(timezoneName); - m_timezonesByCountryCode[countryCode] = timezones; - } - else - { - std::vector<std::string>& timezones = m_timezonesByCountryCode[countryCode]; - timezones.push_back(timezoneName); - } - - m_countriesByTimezoneName[timezoneName] = countryCode; - } - fclose(fp); - } - - if (line) - { - free(line); - line = NULL; - linelen = 0; - } - - // Load countries - fp = fopen("/usr/share/zoneinfo/iso3166.tab", "r"); - if (!fp) - { - fp = fopen("/usr/share/misc/iso3166", "r"); - nameonfourthfield = 1; - } - if (fp) - { - std::string countryCode; - std::string countryName; - - while (getdelim(&line, &linelen, '\n', fp) > 0) - { - s = line; - StringUtils::Trim(s); - - //! @todo STRING_CLEANUP - if (s.length() == 0) - continue; - - if (s[0] == '#') - continue; - - // Search for the first non space from the 2nd character and on - int i = 2; - while (s[i] == ' ' || s[i] == '\t') i++; - - if (nameonfourthfield) - { - // skip three letter - while (s[i] != ' ' && s[i] != '\t') i++; - while (s[i] == ' ' || s[i] == '\t') i++; - // skip number - while (s[i] != ' ' && s[i] != '\t') i++; - while (s[i] == ' ' || s[i] == '\t') i++; - } - - countryCode = s.substr(0, 2); - countryName = s.substr(i); - - m_counties.push_back(countryName); - m_countryByCode[countryCode] = countryName; - m_countryByName[countryName] = countryCode; - } - sort(m_counties.begin(), m_counties.end(), sortstringbyname()); - fclose(fp); - } - free(line); -} - -void CPosixTimezone::OnSettingChanged(const std::shared_ptr<const CSetting>& setting) -{ - if (setting == NULL) - return; - - const std::string &settingId = setting->GetId(); - if (settingId == CSettings::SETTING_LOCALE_TIMEZONE) - { - SetTimezone(std::static_pointer_cast<const CSettingString>(setting)->GetValue()); - - CDateTime::ResetTimezoneBias(); - } - else if (settingId == CSettings::SETTING_LOCALE_TIMEZONECOUNTRY) - { - // nothing to do here. Changing locale.timezonecountry will trigger an - // update of locale.timezone and automatically adjust its value - // and execute OnSettingChanged() for it as well (see above) - } -} - -void CPosixTimezone::OnSettingsLoaded() -{ - SetTimezone(CServiceBroker::GetSettingsComponent()->GetSettings()->GetString(CSettings::SETTING_LOCALE_TIMEZONE)); - CDateTime::ResetTimezoneBias(); -} - -std::vector<std::string> CPosixTimezone::GetCounties() -{ - return m_counties; -} - -std::vector<std::string> CPosixTimezone::GetTimezonesByCountry(const std::string& country) -{ - return m_timezonesByCountryCode[m_countryByName[country]]; -} - -std::string CPosixTimezone::GetCountryByTimezone(const std::string& timezone) -{ -#if defined(TARGET_DARWIN) - return "?"; -#else - return m_countryByCode[m_countriesByTimezoneName[timezone]]; -#endif -} - -void CPosixTimezone::SetTimezone(const std::string& timezoneName) -{ -#if !defined(TARGET_DARWIN) - bool use_timezone = true; -#else - bool use_timezone = false; -#endif - - if (use_timezone) - { - static char env_var[255]; - snprintf(env_var, sizeof(env_var), "TZ=:%s", timezoneName.c_str()); - putenv(env_var); - tzset(); - } -} - -std::string CPosixTimezone::GetOSConfiguredTimezone() -{ - std::string timezoneName; - - // try Slackware approach first - timezoneName = ReadFromLocaltime("/etc/localtime-copied-from"); - - // RHEL and maybe other distros make /etc/localtime a symlink - if (timezoneName.empty()) - timezoneName = ReadFromLocaltime("/etc/localtime"); - - // now try Debian approach - if (timezoneName.empty()) - timezoneName = ReadFromTimezone("/etc/timezone"); - - return timezoneName; -} - -std::string CPosixTimezone::ReadFromLocaltime(const std::string_view filename) -{ - char path[PATH_MAX]; - if(realpath(filename.data(), path) == nullptr) - return ""; - - // Read the timezone starting from the second last occurrence of / - std::string str = path; - size_t pos = str.rfind('/'); - if (pos == std::string::npos) - return ""; - - pos = str.rfind('/', pos - 1); - if (pos == std::string::npos) - return ""; - - return str.substr(pos + 1); -} - -std::string CPosixTimezone::ReadFromTimezone(const std::string_view filename) -{ - std::string timezoneName; - std::FILE* file = std::fopen(filename.data(), "r"); - - if (file != nullptr) - { - char tz[255]; - if (std::fgets(tz, sizeof(tz), file) != nullptr) - { - timezoneName = tz; - } - - std::fclose(file); - } - - return timezoneName; -} - -void CPosixTimezone::SettingOptionsTimezoneCountriesFiller( - const std::shared_ptr<const CSetting>& setting, - std::vector<StringSettingOption>& list, - std::string& current, - void* data) -{ - std::vector<std::string> countries = g_timezone.GetCounties(); - for (unsigned int i = 0; i < countries.size(); i++) - list.emplace_back(countries[i], countries[i]); -} - -void CPosixTimezone::SettingOptionsTimezonesFiller(const std::shared_ptr<const CSetting>& setting, - std::vector<StringSettingOption>& list, - std::string& current, - void* data) -{ - current = std::static_pointer_cast<const CSettingString>(setting)->GetValue(); - bool found = false; - std::vector<std::string> timezones = g_timezone.GetTimezonesByCountry(CServiceBroker::GetSettingsComponent()->GetSettings()->GetString(CSettings::SETTING_LOCALE_TIMEZONECOUNTRY)); - for (unsigned int i = 0; i < timezones.size(); i++) - { - if (!found && StringUtils::EqualsNoCase(timezones[i], current)) - found = true; - - list.emplace_back(timezones[i], timezones[i]); - } - - if (!found && !timezones.empty()) - current = timezones[0]; -} - -CPosixTimezone g_timezone; diff --git a/xbmc/platform/posix/PosixTimezone.h b/xbmc/platform/posix/PosixTimezone.h deleted file mode 100644 index 26a7f09340..0000000000 --- a/xbmc/platform/posix/PosixTimezone.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2005-2018 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 - -#include "settings/lib/ISettingCallback.h" -#include "settings/lib/ISettingsHandler.h" - -#include <map> -#include <string> -#include <vector> - -class CSetting; -struct StringSettingOption; - -class CPosixTimezone : public ISettingCallback, public ISettingsHandler -{ -public: - CPosixTimezone(); - - void OnSettingChanged(const std::shared_ptr<const CSetting>& setting) override; - - void OnSettingsLoaded() override; - - std::string GetOSConfiguredTimezone(); - - std::vector<std::string> GetCounties(); - std::vector<std::string> GetTimezonesByCountry(const std::string& country); - std::string GetCountryByTimezone(const std::string& timezone); - - void SetTimezone(const std::string& timezone); - int m_IsDST = 0; - - static void SettingOptionsTimezoneCountriesFiller(const std::shared_ptr<const CSetting>& setting, - std::vector<StringSettingOption>& list, - std::string& current, - void* data); - static void SettingOptionsTimezonesFiller(const std::shared_ptr<const CSetting>& setting, - std::vector<StringSettingOption>& list, - std::string& current, - void* data); - -private: - std::string ReadFromLocaltime(std::string_view filename); - std::string ReadFromTimezone(std::string_view filename); - std::vector<std::string> m_counties; - std::map<std::string, std::string> m_countryByCode; - std::map<std::string, std::string> m_countryByName; - - std::map<std::string, std::vector<std::string>> m_timezonesByCountryCode; - std::map<std::string, std::string> m_countriesByTimezoneName; -}; - -extern CPosixTimezone g_timezone; - diff --git a/xbmc/platform/posix/XTimeUtils.cpp b/xbmc/platform/posix/XTimeUtils.cpp index e78e5cff48..914bf0e72c 100644 --- a/xbmc/platform/posix/XTimeUtils.cpp +++ b/xbmc/platform/posix/XTimeUtils.cpp @@ -8,8 +8,6 @@ #include "utils/XTimeUtils.h" -#include "PosixTimezone.h" - #include <errno.h> #include <mutex> #include <time.h> @@ -63,8 +61,6 @@ void GetLocalTime(SystemTime* systemTime) systemTime->minute = now.tm_min; systemTime->second = now.tm_sec; systemTime->milliseconds = 0; - // NOTE: localtime_r() is not required to set this, but we Assume that it's set here. - g_timezone.m_IsDST = now.tm_isdst; } int FileTimeToLocalFileTime(const FileTime* fileTime, FileTime* localFileTime) @@ -101,7 +97,6 @@ int SystemTimeToFileTime(const SystemTime* systemTime, FileTime* fileTime) sysTime.tm_min = systemTime->minute; sysTime.tm_sec = systemTime->second; sysTime.tm_yday = dayoffset[sysTime.tm_mon] + (sysTime.tm_mday - 1); - sysTime.tm_isdst = g_timezone.m_IsDST; // If this is a leap year, and we're past the 28th of Feb, increment tm_yday. if (IsLeapYear(systemTime->year) && (sysTime.tm_yday > 58)) diff --git a/xbmc/platform/posix/filesystem/PosixDirectory.cpp b/xbmc/platform/posix/filesystem/PosixDirectory.cpp index 6685c0e1db..761b8d53b4 100644 --- a/xbmc/platform/posix/filesystem/PosixDirectory.cpp +++ b/xbmc/platform/posix/filesystem/PosixDirectory.cpp @@ -9,6 +9,7 @@ #include "PosixDirectory.h" #include "FileItem.h" +#include "FileItemList.h" #include "URL.h" #include "utils/AliasShortcutUtils.h" #include "utils/CharsetConverter.h" diff --git a/xbmc/platform/posix/filesystem/SMBDirectory.cpp b/xbmc/platform/posix/filesystem/SMBDirectory.cpp index e2305afb4a..12fe62683e 100644 --- a/xbmc/platform/posix/filesystem/SMBDirectory.cpp +++ b/xbmc/platform/posix/filesystem/SMBDirectory.cpp @@ -20,6 +20,7 @@ #include "SMBDirectory.h" #include "FileItem.h" +#include "FileItemList.h" #include "PasswordManager.h" #include "ServiceBroker.h" #include "guilib/LocalizeStrings.h" diff --git a/xbmc/platform/posix/filesystem/SMBWSDiscovery.cpp b/xbmc/platform/posix/filesystem/SMBWSDiscovery.cpp index 8bab0aa9e9..c2f247da10 100644 --- a/xbmc/platform/posix/filesystem/SMBWSDiscovery.cpp +++ b/xbmc/platform/posix/filesystem/SMBWSDiscovery.cpp @@ -9,6 +9,7 @@ #include "SMBWSDiscovery.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "network/IWSDiscovery.h" #include "utils/StringUtils.h" diff --git a/xbmc/platform/win10/filesystem/WinLibraryDirectory.cpp b/xbmc/platform/win10/filesystem/WinLibraryDirectory.cpp index bba7074400..4bd0a0db4c 100644 --- a/xbmc/platform/win10/filesystem/WinLibraryDirectory.cpp +++ b/xbmc/platform/win10/filesystem/WinLibraryDirectory.cpp @@ -9,6 +9,7 @@ #include "WinLibraryDirectory.h" #include "FileItem.h" +#include "FileItemList.h" #include "URL.h" #include "utils/StringUtils.h" #include "utils/URIUtils.h" diff --git a/xbmc/platform/win32/filesystem/Win32Directory.cpp b/xbmc/platform/win32/filesystem/Win32Directory.cpp index 5e4050fdd4..3d06e8dfbc 100644 --- a/xbmc/platform/win32/filesystem/Win32Directory.cpp +++ b/xbmc/platform/win32/filesystem/Win32Directory.cpp @@ -9,6 +9,7 @@ #include "Win32Directory.h" #include "FileItem.h" +#include "FileItemList.h" #include "URL.h" #include "utils/CharsetConverter.h" #include "utils/SystemInfo.h" diff --git a/xbmc/platform/win32/filesystem/Win32SMBDirectory.cpp b/xbmc/platform/win32/filesystem/Win32SMBDirectory.cpp index 2075f957c8..c227351ad4 100644 --- a/xbmc/platform/win32/filesystem/Win32SMBDirectory.cpp +++ b/xbmc/platform/win32/filesystem/Win32SMBDirectory.cpp @@ -9,6 +9,7 @@ #include "Win32SMBDirectory.h" #include "FileItem.h" +#include "FileItemList.h" #include "PasswordManager.h" #include "ServiceBroker.h" #include "URL.h" diff --git a/xbmc/playlists/PlayList.cpp b/xbmc/playlists/PlayList.cpp index 82031bad2e..b47c782541 100644 --- a/xbmc/playlists/PlayList.cpp +++ b/xbmc/playlists/PlayList.cpp @@ -9,6 +9,7 @@ #include "PlayList.h" #include "FileItem.h" +#include "FileItemList.h" #include "PlayListFactory.h" #include "ServiceBroker.h" #include "filesystem/File.h" diff --git a/xbmc/playlists/PlayListM3U.cpp b/xbmc/playlists/PlayListM3U.cpp index 8853a31275..cb8a9e9077 100644 --- a/xbmc/playlists/PlayListM3U.cpp +++ b/xbmc/playlists/PlayListM3U.cpp @@ -16,10 +16,12 @@ #include "utils/CharsetConverter.h" #include "utils/URIUtils.h" #include "utils/log.h" +#include "video/VideoFileItemClassify.h" #include "video/VideoInfoTag.h" #include <inttypes.h> +using namespace KODI; using namespace PLAYLIST; using namespace XFILE; @@ -183,7 +185,8 @@ bool CPlayListM3U::Load(const std::string& strFileName) if (iEndOffset) lDuration = static_cast<int>(CUtil::ConvertMilliSecsToSecsIntRounded(iEndOffset - iStartOffset)); } - if (newItem->IsVideo() && !newItem->HasVideoInfoTag()) // File is a video and needs a VideoInfoTag + if (VIDEO::IsVideo(*newItem) && + !newItem->HasVideoInfoTag()) // File is a video and needs a VideoInfoTag newItem->GetVideoInfoTag()->Reset(); // Force VideoInfoTag creation if (lDuration && newItem->IsAudio()) newItem->GetMusicInfoTag()->SetDuration(lDuration); diff --git a/xbmc/playlists/PlayListPLS.cpp b/xbmc/playlists/PlayListPLS.cpp index 369804dba2..d06d5d0ead 100644 --- a/xbmc/playlists/PlayListPLS.cpp +++ b/xbmc/playlists/PlayListPLS.cpp @@ -19,6 +19,7 @@ #include "utils/XBMCTinyXML.h" #include "utils/XMLUtils.h" #include "utils/log.h" +#include "video/VideoFileItemClassify.h" #include "video/VideoInfoTag.h" #include <iostream> @@ -26,6 +27,7 @@ #include <string> #include <vector> +using namespace KODI; using namespace XFILE; using namespace PLAYLIST; @@ -272,7 +274,8 @@ bool CPlayListASX::LoadAsxIniInfo(std::istream &stream) CLog::Log(LOGINFO, "Adding element {}={}", name, value); CFileItemPtr newItem(new CFileItem(value)); newItem->SetPath(value); - if (newItem->IsVideo() && !newItem->HasVideoInfoTag()) // File is a video and needs a VideoInfoTag + if (VIDEO::IsVideo(*newItem) && + !newItem->HasVideoInfoTag()) // File is a video and needs a VideoInfoTag newItem->GetVideoInfoTag()->Reset(); // Force VideoInfoTag creation Add(newItem); } diff --git a/xbmc/playlists/SmartPlaylistFileItemListModifier.cpp b/xbmc/playlists/SmartPlaylistFileItemListModifier.cpp index 7249bb5c0d..443dabcd4e 100644 --- a/xbmc/playlists/SmartPlaylistFileItemListModifier.cpp +++ b/xbmc/playlists/SmartPlaylistFileItemListModifier.cpp @@ -9,6 +9,7 @@ #include "SmartPlaylistFileItemListModifier.h" #include "FileItem.h" +#include "FileItemList.h" #include "URL.h" #include "playlists/SmartPlayList.h" #include "utils/StringUtils.h" diff --git a/xbmc/profiles/dialogs/GUIDialogProfileSettings.cpp b/xbmc/profiles/dialogs/GUIDialogProfileSettings.cpp index dcdf8c47a4..9f455c4a6b 100644 --- a/xbmc/profiles/dialogs/GUIDialogProfileSettings.cpp +++ b/xbmc/profiles/dialogs/GUIDialogProfileSettings.cpp @@ -9,6 +9,7 @@ #include "GUIDialogProfileSettings.h" #include "FileItem.h" +#include "FileItemList.h" #include "GUIPassword.h" #include "ServiceBroker.h" #include "Util.h" diff --git a/xbmc/profiles/windows/GUIWindowSettingsProfile.cpp b/xbmc/profiles/windows/GUIWindowSettingsProfile.cpp index d3690adb63..503516c0f6 100644 --- a/xbmc/profiles/windows/GUIWindowSettingsProfile.cpp +++ b/xbmc/profiles/windows/GUIWindowSettingsProfile.cpp @@ -9,6 +9,7 @@ #include "GUIWindowSettingsProfile.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "dialogs/GUIDialogContextMenu.h" #include "dialogs/GUIDialogSelect.h" diff --git a/xbmc/programs/GUIViewStatePrograms.cpp b/xbmc/programs/GUIViewStatePrograms.cpp index 05e4cfd978..0b08a42864 100644 --- a/xbmc/programs/GUIViewStatePrograms.cpp +++ b/xbmc/programs/GUIViewStatePrograms.cpp @@ -9,6 +9,7 @@ #include "GUIViewStatePrograms.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "filesystem/Directory.h" #include "guilib/LocalizeStrings.h" diff --git a/xbmc/programs/GUIWindowPrograms.cpp b/xbmc/programs/GUIWindowPrograms.cpp index 862bdb2249..7a57f1cc0b 100644 --- a/xbmc/programs/GUIWindowPrograms.cpp +++ b/xbmc/programs/GUIWindowPrograms.cpp @@ -10,6 +10,7 @@ #include "Autorun.h" #include "FileItem.h" +#include "FileItemList.h" #include "GUIPassword.h" #include "ServiceBroker.h" #include "Util.h" diff --git a/xbmc/pvr/PVRChannelGroupImageFileLoader.cpp b/xbmc/pvr/PVRChannelGroupImageFileLoader.cpp index e539ca55bd..b66ef00902 100644 --- a/xbmc/pvr/PVRChannelGroupImageFileLoader.cpp +++ b/xbmc/pvr/PVRChannelGroupImageFileLoader.cpp @@ -9,6 +9,7 @@ #include "PVRChannelGroupImageFileLoader.h" #include "FileItem.h" +#include "FileItemList.h" #include "filesystem/PVRGUIDirectory.h" #include "guilib/Texture.h" #include "pictures/Picture.h" diff --git a/xbmc/pvr/PVRThumbLoader.cpp b/xbmc/pvr/PVRThumbLoader.cpp index 3f5fa63822..8f41a80b0c 100644 --- a/xbmc/pvr/PVRThumbLoader.cpp +++ b/xbmc/pvr/PVRThumbLoader.cpp @@ -9,6 +9,7 @@ #include "PVRThumbLoader.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "TextureCache.h" #include "pvr/PVRManager.h" diff --git a/xbmc/pvr/dialogs/GUIDialogPVRChannelGuide.cpp b/xbmc/pvr/dialogs/GUIDialogPVRChannelGuide.cpp index b057b338bc..563aa126cd 100644 --- a/xbmc/pvr/dialogs/GUIDialogPVRChannelGuide.cpp +++ b/xbmc/pvr/dialogs/GUIDialogPVRChannelGuide.cpp @@ -9,6 +9,7 @@ #include "GUIDialogPVRChannelGuide.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "pvr/PVRManager.h" #include "pvr/PVRPlaybackState.h" diff --git a/xbmc/pvr/dialogs/GUIDialogPVRChannelManager.cpp b/xbmc/pvr/dialogs/GUIDialogPVRChannelManager.cpp index d6665fcf4b..efae8e7279 100644 --- a/xbmc/pvr/dialogs/GUIDialogPVRChannelManager.cpp +++ b/xbmc/pvr/dialogs/GUIDialogPVRChannelManager.cpp @@ -9,6 +9,7 @@ #include "GUIDialogPVRChannelManager.h" #include "FileItem.h" +#include "FileItemList.h" #include "GUIPassword.h" #include "ServiceBroker.h" #include "TextureCache.h" diff --git a/xbmc/pvr/dialogs/GUIDialogPVRChannelsOSD.cpp b/xbmc/pvr/dialogs/GUIDialogPVRChannelsOSD.cpp index 9c079c8e7e..c349bd0623 100644 --- a/xbmc/pvr/dialogs/GUIDialogPVRChannelsOSD.cpp +++ b/xbmc/pvr/dialogs/GUIDialogPVRChannelsOSD.cpp @@ -9,6 +9,7 @@ #include "GUIDialogPVRChannelsOSD.h" #include "FileItem.h" +#include "FileItemList.h" #include "GUIInfoManager.h" #include "ServiceBroker.h" #include "guilib/GUIComponent.h" diff --git a/xbmc/pvr/dialogs/GUIDialogPVRGroupManager.cpp b/xbmc/pvr/dialogs/GUIDialogPVRGroupManager.cpp index c0d6d801d7..1fa8cd5175 100644 --- a/xbmc/pvr/dialogs/GUIDialogPVRGroupManager.cpp +++ b/xbmc/pvr/dialogs/GUIDialogPVRGroupManager.cpp @@ -9,6 +9,7 @@ #include "GUIDialogPVRGroupManager.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "dialogs/GUIDialogContextMenu.h" #include "dialogs/GUIDialogYesNo.h" diff --git a/xbmc/pvr/dialogs/GUIDialogPVRItemsViewBase.cpp b/xbmc/pvr/dialogs/GUIDialogPVRItemsViewBase.cpp index 2add783cf2..72b4694528 100644 --- a/xbmc/pvr/dialogs/GUIDialogPVRItemsViewBase.cpp +++ b/xbmc/pvr/dialogs/GUIDialogPVRItemsViewBase.cpp @@ -10,6 +10,7 @@ #include "ContextMenuManager.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "dialogs/GUIDialogContextMenu.h" #include "input/actions/Action.h" diff --git a/xbmc/pvr/filesystem/PVRGUIDirectory.cpp b/xbmc/pvr/filesystem/PVRGUIDirectory.cpp index 8def92d871..2b15428347 100644 --- a/xbmc/pvr/filesystem/PVRGUIDirectory.cpp +++ b/xbmc/pvr/filesystem/PVRGUIDirectory.cpp @@ -9,6 +9,7 @@ #include "PVRGUIDirectory.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "guilib/LocalizeStrings.h" #include "guilib/WindowIDs.h" diff --git a/xbmc/pvr/guilib/GUIEPGGridContainer.cpp b/xbmc/pvr/guilib/GUIEPGGridContainer.cpp index de3ef1059e..d990f3f9db 100644 --- a/xbmc/pvr/guilib/GUIEPGGridContainer.cpp +++ b/xbmc/pvr/guilib/GUIEPGGridContainer.cpp @@ -9,6 +9,7 @@ #include "GUIEPGGridContainer.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "guilib/DirtyRegion.h" #include "guilib/GUIAction.h" diff --git a/xbmc/pvr/guilib/GUIEPGGridContainerModel.cpp b/xbmc/pvr/guilib/GUIEPGGridContainerModel.cpp index f99515160c..df6f7e41cd 100644 --- a/xbmc/pvr/guilib/GUIEPGGridContainerModel.cpp +++ b/xbmc/pvr/guilib/GUIEPGGridContainerModel.cpp @@ -9,6 +9,7 @@ #include "GUIEPGGridContainerModel.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "pvr/PVRManager.h" #include "pvr/channels/PVRChannel.h" diff --git a/xbmc/pvr/guilib/PVRGUIActionsDatabase.cpp b/xbmc/pvr/guilib/PVRGUIActionsDatabase.cpp index 53bbf815f6..1bf613dc4e 100644 --- a/xbmc/pvr/guilib/PVRGUIActionsDatabase.cpp +++ b/xbmc/pvr/guilib/PVRGUIActionsDatabase.cpp @@ -9,6 +9,7 @@ #include "PVRGUIActionsDatabase.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "dialogs/GUIDialogProgress.h" #include "dialogs/GUIDialogSelect.h" diff --git a/xbmc/pvr/guilib/PVRGUIActionsPlayback.cpp b/xbmc/pvr/guilib/PVRGUIActionsPlayback.cpp index 15c8af4208..ed11f9ec2a 100644 --- a/xbmc/pvr/guilib/PVRGUIActionsPlayback.cpp +++ b/xbmc/pvr/guilib/PVRGUIActionsPlayback.cpp @@ -9,6 +9,7 @@ #include "PVRGUIActionsPlayback.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "application/ApplicationEnums.h" #include "cores/DataCacheCore.h" diff --git a/xbmc/pvr/guilib/PVRGUIActionsRecordings.cpp b/xbmc/pvr/guilib/PVRGUIActionsRecordings.cpp index c69c909b9a..9609617be9 100644 --- a/xbmc/pvr/guilib/PVRGUIActionsRecordings.cpp +++ b/xbmc/pvr/guilib/PVRGUIActionsRecordings.cpp @@ -9,6 +9,7 @@ #include "PVRGUIActionsRecordings.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "Util.h" #include "dialogs/GUIDialogBusy.h" diff --git a/xbmc/pvr/guilib/PVRGUIActionsUtils.cpp b/xbmc/pvr/guilib/PVRGUIActionsUtils.cpp index 907c645dd3..c6399f1a26 100644 --- a/xbmc/pvr/guilib/PVRGUIActionsUtils.cpp +++ b/xbmc/pvr/guilib/PVRGUIActionsUtils.cpp @@ -9,6 +9,7 @@ #include "PVRGUIActionsUtils.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "filesystem/Directory.h" #include "pvr/PVRManager.h" diff --git a/xbmc/pvr/guilib/PVRGUIChannelIconUpdater.cpp b/xbmc/pvr/guilib/PVRGUIChannelIconUpdater.cpp index 26859dd63a..11045c98d8 100644 --- a/xbmc/pvr/guilib/PVRGUIChannelIconUpdater.cpp +++ b/xbmc/pvr/guilib/PVRGUIChannelIconUpdater.cpp @@ -9,6 +9,7 @@ #include "PVRGUIChannelIconUpdater.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "Util.h" #include "filesystem/Directory.h" diff --git a/xbmc/pvr/windows/GUIViewStatePVR.cpp b/xbmc/pvr/windows/GUIViewStatePVR.cpp index d86f6fc2a6..a5004d8ba9 100644 --- a/xbmc/pvr/windows/GUIViewStatePVR.cpp +++ b/xbmc/pvr/windows/GUIViewStatePVR.cpp @@ -9,6 +9,7 @@ #include "GUIViewStatePVR.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "pvr/PVRManager.h" #include "pvr/addons/PVRClients.h" diff --git a/xbmc/pvr/windows/GUIWindowPVRBase.cpp b/xbmc/pvr/windows/GUIWindowPVRBase.cpp index 71a800feda..ce891a80f7 100644 --- a/xbmc/pvr/windows/GUIWindowPVRBase.cpp +++ b/xbmc/pvr/windows/GUIWindowPVRBase.cpp @@ -9,6 +9,7 @@ #include "GUIWindowPVRBase.h" #include "FileItem.h" +#include "FileItemList.h" #include "GUIUserMessages.h" #include "ServiceBroker.h" #include "addons/AddonManager.h" diff --git a/xbmc/pvr/windows/GUIWindowPVRChannels.cpp b/xbmc/pvr/windows/GUIWindowPVRChannels.cpp index e323c319be..8ccbdd68fa 100644 --- a/xbmc/pvr/windows/GUIWindowPVRChannels.cpp +++ b/xbmc/pvr/windows/GUIWindowPVRChannels.cpp @@ -9,6 +9,7 @@ #include "GUIWindowPVRChannels.h" #include "FileItem.h" +#include "FileItemList.h" #include "GUIInfoManager.h" #include "ServiceBroker.h" #include "dialogs/GUIDialogContextMenu.h" diff --git a/xbmc/pvr/windows/GUIWindowPVRGuide.cpp b/xbmc/pvr/windows/GUIWindowPVRGuide.cpp index 3923cae6bb..6ce75fd5f2 100644 --- a/xbmc/pvr/windows/GUIWindowPVRGuide.cpp +++ b/xbmc/pvr/windows/GUIWindowPVRGuide.cpp @@ -9,6 +9,7 @@ #include "GUIWindowPVRGuide.h" #include "FileItem.h" +#include "FileItemList.h" #include "GUIUserMessages.h" #include "ServiceBroker.h" #include "addons/Skin.h" diff --git a/xbmc/pvr/windows/GUIWindowPVRRecordings.cpp b/xbmc/pvr/windows/GUIWindowPVRRecordings.cpp index 363011a379..284bebb93e 100644 --- a/xbmc/pvr/windows/GUIWindowPVRRecordings.cpp +++ b/xbmc/pvr/windows/GUIWindowPVRRecordings.cpp @@ -8,6 +8,7 @@ #include "GUIWindowPVRRecordings.h" +#include "FileItemList.h" #include "GUIInfoManager.h" #include "ServiceBroker.h" #include "guilib/GUIComponent.h" diff --git a/xbmc/pvr/windows/GUIWindowPVRSearch.cpp b/xbmc/pvr/windows/GUIWindowPVRSearch.cpp index 0c129c3e00..4a9ad6b10e 100644 --- a/xbmc/pvr/windows/GUIWindowPVRSearch.cpp +++ b/xbmc/pvr/windows/GUIWindowPVRSearch.cpp @@ -9,6 +9,7 @@ #include "GUIWindowPVRSearch.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "dialogs/GUIDialogBusy.h" #include "dialogs/GUIDialogYesNo.h" diff --git a/xbmc/pvr/windows/GUIWindowPVRTimerRules.cpp b/xbmc/pvr/windows/GUIWindowPVRTimerRules.cpp index 1b203d403d..1d532fa1ac 100644 --- a/xbmc/pvr/windows/GUIWindowPVRTimerRules.cpp +++ b/xbmc/pvr/windows/GUIWindowPVRTimerRules.cpp @@ -9,6 +9,7 @@ #include "GUIWindowPVRTimerRules.h" #include "FileItem.h" +#include "FileItemList.h" #include "pvr/timers/PVRTimersPath.h" #include "utils/URIUtils.h" diff --git a/xbmc/pvr/windows/GUIWindowPVRTimers.cpp b/xbmc/pvr/windows/GUIWindowPVRTimers.cpp index 610571bcd5..0bc955d6c8 100644 --- a/xbmc/pvr/windows/GUIWindowPVRTimers.cpp +++ b/xbmc/pvr/windows/GUIWindowPVRTimers.cpp @@ -9,6 +9,7 @@ #include "GUIWindowPVRTimers.h" #include "FileItem.h" +#include "FileItemList.h" #include "pvr/timers/PVRTimersPath.h" #include "utils/URIUtils.h" diff --git a/xbmc/pvr/windows/GUIWindowPVRTimersBase.cpp b/xbmc/pvr/windows/GUIWindowPVRTimersBase.cpp index 41677eb873..68b1501e2b 100644 --- a/xbmc/pvr/windows/GUIWindowPVRTimersBase.cpp +++ b/xbmc/pvr/windows/GUIWindowPVRTimersBase.cpp @@ -9,6 +9,7 @@ #include "GUIWindowPVRTimersBase.h" #include "FileItem.h" +#include "FileItemList.h" #include "GUIInfoManager.h" #include "ServiceBroker.h" #include "guilib/GUIComponent.h" diff --git a/xbmc/rendering/gl/GLShader.cpp b/xbmc/rendering/gl/GLShader.cpp index e91af97b56..77dd6e4ed2 100644 --- a/xbmc/rendering/gl/GLShader.cpp +++ b/xbmc/rendering/gl/GLShader.cpp @@ -1,12 +1,11 @@ /* - * Copyright (C) 2005-2018 Team Kodi + * Copyright (C) 2005-2024 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 "GLShader.h" #include "ServiceBroker.h" @@ -49,6 +48,9 @@ void CGLShader::OnCompiledAndLinked() // Variables passed directly to the Vertex shader m_hProj = glGetUniformLocation(ProgramHandle(), "m_proj"); m_hModel = glGetUniformLocation(ProgramHandle(), "m_model"); + m_hMatrix = glGetUniformLocation(ProgramHandle(), "m_matrix"); + m_hShaderClip = glGetUniformLocation(ProgramHandle(), "m_shaderClip"); + m_hCoordStep = glGetUniformLocation(ProgramHandle(), "m_cordStep"); // Vertex attributes m_hPos = glGetAttribLocation(ProgramHandle(), "m_attrpos"); diff --git a/xbmc/rendering/gl/GLShader.h b/xbmc/rendering/gl/GLShader.h index d5b82f3a07..791c44926b 100644 --- a/xbmc/rendering/gl/GLShader.h +++ b/xbmc/rendering/gl/GLShader.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2018 Team Kodi + * Copyright (C) 2005-2024 Team Kodi * This file is part of Kodi - https://kodi.tv * * SPDX-License-Identifier: GPL-2.0-or-later @@ -27,6 +27,9 @@ public: GLint GetCord1Loc() {return m_hCord1;} GLint GetUniColLoc() {return m_hUniCol;} GLint GetModelLoc() {return m_hModel; } + GLint GetMatrixLoc() { return m_hMatrix; } + GLint GetShaderClipLoc() { return m_hShaderClip; } + GLint GetShaderCoordStepLoc() { return m_hCoordStep; } bool HardwareClipIsPossible() {return m_clipPossible; } GLfloat GetClipXFactor() {return m_clipXFactor; } GLfloat GetClipXOffset() {return m_clipXOffset; } @@ -39,6 +42,9 @@ protected: GLint m_hUniCol = 0; GLint m_hProj = 0; GLint m_hModel = 0; + GLint m_hMatrix{0}; // m_hProj * m_hModel + GLint m_hShaderClip{0}; // clipping rect vec4(x1,y1,x2,y2) + GLint m_hCoordStep{0}; // step (1/resolution) for the two textures vec4(t1.x,t1.y,t2.x,t2.y) GLint m_hPos = 0; GLint m_hCol = 0; GLint m_hCord0 = 0; diff --git a/xbmc/rendering/gl/RenderSystemGL.cpp b/xbmc/rendering/gl/RenderSystemGL.cpp index 4b80014d41..516027ef49 100644 --- a/xbmc/rendering/gl/RenderSystemGL.cpp +++ b/xbmc/rendering/gl/RenderSystemGL.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2018 Team Kodi + * Copyright (C) 2005-2024 Team Kodi * This file is part of Kodi - https://kodi.tv * * SPDX-License-Identifier: GPL-2.0-or-later @@ -682,13 +682,24 @@ void CRenderSystemGL::InitialiseShaders() CLog::Log(LOGERROR, "GUI Shader gl_shader_frag_multi.glsl - compile and link failed"); } - m_pShader[ShaderMethodGL::SM_FONTS] = - std::make_unique<CGLShader>("gl_shader_frag_fonts.glsl", defines); + m_pShader[ShaderMethodGL::SM_FONTS] = std::make_unique<CGLShader>( + "gl_shader_vert_simple.glsl", "gl_shader_frag_fonts.glsl", defines); if (!m_pShader[ShaderMethodGL::SM_FONTS]->CompileAndLink()) { m_pShader[ShaderMethodGL::SM_FONTS]->Free(); m_pShader[ShaderMethodGL::SM_FONTS].reset(); - CLog::Log(LOGERROR, "GUI Shader gl_shader_frag_fonts.glsl - compile and link failed"); + CLog::Log(LOGERROR, "GUI Shader gl_shader_vert_simple.glsl + gl_shader_frag_fonts.glsl - " + "compile and link failed"); + } + + m_pShader[ShaderMethodGL::SM_FONTS_SHADER_CLIP] = + std::make_unique<CGLShader>("gl_shader_vert_clip.glsl", "gl_shader_frag_fonts.glsl", defines); + if (!m_pShader[ShaderMethodGL::SM_FONTS_SHADER_CLIP]->CompileAndLink()) + { + m_pShader[ShaderMethodGL::SM_FONTS_SHADER_CLIP]->Free(); + m_pShader[ShaderMethodGL::SM_FONTS_SHADER_CLIP].reset(); + CLog::Log(LOGERROR, "GUI Shader gl_shader_vert_clip.glsl + gl_shader_frag_fonts.glsl - compile " + "and link failed"); } m_pShader[ShaderMethodGL::SM_TEXTURE_NOBLEND] = @@ -732,6 +743,10 @@ void CRenderSystemGL::ReleaseShaders() m_pShader[ShaderMethodGL::SM_FONTS]->Free(); m_pShader[ShaderMethodGL::SM_FONTS].reset(); + if (m_pShader[ShaderMethodGL::SM_FONTS_SHADER_CLIP]) + m_pShader[ShaderMethodGL::SM_FONTS_SHADER_CLIP]->Free(); + m_pShader[ShaderMethodGL::SM_FONTS_SHADER_CLIP].reset(); + if (m_pShader[ShaderMethodGL::SM_TEXTURE_NOBLEND]) m_pShader[ShaderMethodGL::SM_TEXTURE_NOBLEND]->Free(); m_pShader[ShaderMethodGL::SM_TEXTURE_NOBLEND].reset(); @@ -811,6 +826,30 @@ GLint CRenderSystemGL::ShaderGetModel() return -1; } +GLint CRenderSystemGL::ShaderGetMatrix() +{ + if (m_pShader[m_method]) + return m_pShader[m_method]->GetMatrixLoc(); + + return -1; +} + +GLint CRenderSystemGL::ShaderGetClip() +{ + if (m_pShader[m_method]) + return m_pShader[m_method]->GetShaderClipLoc(); + + return -1; +} + +GLint CRenderSystemGL::ShaderGetCoordStep() +{ + if (m_pShader[m_method]) + return m_pShader[m_method]->GetShaderCoordStepLoc(); + + return -1; +} + std::string CRenderSystemGL::GetShaderPath(const std::string &filename) { std::string path = "GL/1.2/"; diff --git a/xbmc/rendering/gl/RenderSystemGL.h b/xbmc/rendering/gl/RenderSystemGL.h index 191c97ff96..520c552e45 100644 --- a/xbmc/rendering/gl/RenderSystemGL.h +++ b/xbmc/rendering/gl/RenderSystemGL.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2018 Team Kodi + * Copyright (C) 2005-2024 Team Kodi * This file is part of Kodi - https://kodi.tv * * SPDX-License-Identifier: GPL-2.0-or-later @@ -27,6 +27,7 @@ enum class ShaderMethodGL SM_TEXTURE_LIM, SM_MULTI, SM_FONTS, + SM_FONTS_SHADER_CLIP, SM_TEXTURE_NOBLEND, SM_MULTI_BLENDCOLOR, SM_MAX @@ -52,6 +53,7 @@ private: {ShaderMethodGL::SM_TEXTURE_LIM, "texture limited"}, {ShaderMethodGL::SM_MULTI, "multi"}, {ShaderMethodGL::SM_FONTS, "fonts"}, + {ShaderMethodGL::SM_FONTS_SHADER_CLIP, "fonts with vertex shader based clipping"}, {ShaderMethodGL::SM_TEXTURE_NOBLEND, "texture no blending"}, {ShaderMethodGL::SM_MULTI_BLENDCOLOR, "multi blend colour"}, }); @@ -114,6 +116,9 @@ public: GLint ShaderGetCoord1(); GLint ShaderGetUniCol(); GLint ShaderGetModel(); + GLint ShaderGetMatrix(); + GLint ShaderGetClip(); + GLint ShaderGetCoordStep(); protected: virtual void SetVSyncImpl(bool enable) = 0; diff --git a/xbmc/rendering/gles/GLESShader.cpp b/xbmc/rendering/gles/GLESShader.cpp index 961c3f7961..ba7b83175d 100644 --- a/xbmc/rendering/gles/GLESShader.cpp +++ b/xbmc/rendering/gles/GLESShader.cpp @@ -54,6 +54,9 @@ void CGLESShader::OnCompiledAndLinked() m_hProj = glGetUniformLocation(ProgramHandle(), "m_proj"); m_hModel = glGetUniformLocation(ProgramHandle(), "m_model"); m_hCoord0Matrix = glGetUniformLocation(ProgramHandle(), "m_coord0Matrix"); + m_hMatrix = glGetUniformLocation(ProgramHandle(), "m_matrix"); + m_hShaderClip = glGetUniformLocation(ProgramHandle(), "m_shaderClip"); + m_hCoordStep = glGetUniformLocation(ProgramHandle(), "m_cordStep"); // Vertex attributes m_hPos = glGetAttribLocation(ProgramHandle(), "m_attrpos"); diff --git a/xbmc/rendering/gles/GLESShader.h b/xbmc/rendering/gles/GLESShader.h index 1f59895740..ddc31202c5 100644 --- a/xbmc/rendering/gles/GLESShader.h +++ b/xbmc/rendering/gles/GLESShader.h @@ -32,6 +32,9 @@ public: GLint GetContrastLoc() { return m_hContrast; } GLint GetBrightnessLoc() { return m_hBrightness; } GLint GetModelLoc() { return m_hModel; } + GLint GetMatrixLoc() { return m_hMatrix; } + GLint GetShaderClipLoc() { return m_hShaderClip; } + GLint GetShaderCoordStepLoc() { return m_hCoordStep; } bool HardwareClipIsPossible() { return m_clipPossible; } GLfloat GetClipXFactor() { return m_clipXFactor; } GLfloat GetClipXOffset() { return m_clipXOffset; } @@ -44,6 +47,9 @@ protected: GLint m_hUniCol = 0; GLint m_hProj = 0; GLint m_hModel = 0; + GLint m_hMatrix{0}; // m_hProj * m_hModel + GLint m_hShaderClip{0}; // clipping rect vec4(x1,y1,x2,y2) + GLint m_hCoordStep{0}; // step (1/resolution) for the two textures vec4(t1.x,t1.y,t2.x,t2.y) GLint m_hPos = 0; GLint m_hCol = 0; GLint m_hCord0 = 0; diff --git a/xbmc/rendering/gles/RenderSystemGLES.cpp b/xbmc/rendering/gles/RenderSystemGLES.cpp index f25f783960..a5c02803b0 100644 --- a/xbmc/rendering/gles/RenderSystemGLES.cpp +++ b/xbmc/rendering/gles/RenderSystemGLES.cpp @@ -425,7 +425,7 @@ void CRenderSystemGLES::InitialiseShaders() } m_pShader[ShaderMethodGLES::SM_FONTS] = - std::make_unique<CGLESShader>("gles_shader_fonts.frag", defines); + std::make_unique<CGLESShader>("gles_shader_simple.vert", "gles_shader_fonts.frag", defines); if (!m_pShader[ShaderMethodGLES::SM_FONTS]->CompileAndLink()) { m_pShader[ShaderMethodGLES::SM_FONTS]->Free(); @@ -433,6 +433,16 @@ void CRenderSystemGLES::InitialiseShaders() CLog::Log(LOGERROR, "GUI Shader gles_shader_fonts.frag - compile and link failed"); } + m_pShader[ShaderMethodGLES::SM_FONTS_SHADER_CLIP] = + std::make_unique<CGLESShader>("gles_shader_clip.vert", "gles_shader_fonts.frag", defines); + if (!m_pShader[ShaderMethodGLES::SM_FONTS_SHADER_CLIP]->CompileAndLink()) + { + m_pShader[ShaderMethodGLES::SM_FONTS_SHADER_CLIP]->Free(); + m_pShader[ShaderMethodGLES::SM_FONTS_SHADER_CLIP].reset(); + CLog::Log(LOGERROR, "GUI Shader gles_shader_clip.vert + gles_shader_fonts.frag - compile " + "and link failed"); + } + m_pShader[ShaderMethodGLES::SM_TEXTURE_NOBLEND] = std::make_unique<CGLESShader>("gles_shader_texture_noblend.frag", defines); if (!m_pShader[ShaderMethodGLES::SM_TEXTURE_NOBLEND]->CompileAndLink()) @@ -528,6 +538,10 @@ void CRenderSystemGLES::ReleaseShaders() m_pShader[ShaderMethodGLES::SM_FONTS]->Free(); m_pShader[ShaderMethodGLES::SM_FONTS].reset(); + if (m_pShader[ShaderMethodGLES::SM_FONTS_SHADER_CLIP]) + m_pShader[ShaderMethodGLES::SM_FONTS_SHADER_CLIP]->Free(); + m_pShader[ShaderMethodGLES::SM_FONTS_SHADER_CLIP].reset(); + if (m_pShader[ShaderMethodGLES::SM_TEXTURE_NOBLEND]) m_pShader[ShaderMethodGLES::SM_TEXTURE_NOBLEND]->Free(); m_pShader[ShaderMethodGLES::SM_TEXTURE_NOBLEND].reset(); @@ -675,3 +689,27 @@ GLint CRenderSystemGLES::GUIShaderGetModel() return -1; } + +GLint CRenderSystemGLES::GUIShaderGetMatrix() +{ + if (m_pShader[m_method]) + return m_pShader[m_method]->GetMatrixLoc(); + + return -1; +} + +GLint CRenderSystemGLES::GUIShaderGetClip() +{ + if (m_pShader[m_method]) + return m_pShader[m_method]->GetShaderClipLoc(); + + return -1; +} + +GLint CRenderSystemGLES::GUIShaderGetCoordStep() +{ + if (m_pShader[m_method]) + return m_pShader[m_method]->GetShaderCoordStepLoc(); + + return -1; +} diff --git a/xbmc/rendering/gles/RenderSystemGLES.h b/xbmc/rendering/gles/RenderSystemGLES.h index e0cd72b9c1..7986f2c0a4 100644 --- a/xbmc/rendering/gles/RenderSystemGLES.h +++ b/xbmc/rendering/gles/RenderSystemGLES.h @@ -25,6 +25,7 @@ enum class ShaderMethodGLES SM_TEXTURE, SM_MULTI, SM_FONTS, + SM_FONTS_SHADER_CLIP, SM_TEXTURE_NOBLEND, SM_MULTI_BLENDCOLOR, SM_TEXTURE_RGBA, @@ -55,6 +56,7 @@ private: {ShaderMethodGLES::SM_TEXTURE, "texture"}, {ShaderMethodGLES::SM_MULTI, "multi"}, {ShaderMethodGLES::SM_FONTS, "fonts"}, + {ShaderMethodGLES::SM_FONTS_SHADER_CLIP, "fonts with vertex shader based clipping"}, {ShaderMethodGLES::SM_TEXTURE_NOBLEND, "texture no blending"}, {ShaderMethodGLES::SM_MULTI_BLENDCOLOR, "multi blend colour"}, {ShaderMethodGLES::SM_TEXTURE_RGBA, "texure rgba"}, @@ -124,6 +126,9 @@ public: GLint GUIShaderGetContrast(); GLint GUIShaderGetBrightness(); GLint GUIShaderGetModel(); + GLint GUIShaderGetMatrix(); + GLint GUIShaderGetClip(); + GLint GUIShaderGetCoordStep(); protected: virtual void SetVSyncImpl(bool enable) = 0; diff --git a/xbmc/settings/AdvancedSettings.cpp b/xbmc/settings/AdvancedSettings.cpp index b59ba893bd..a9f0f41cc5 100644 --- a/xbmc/settings/AdvancedSettings.cpp +++ b/xbmc/settings/AdvancedSettings.cpp @@ -170,6 +170,7 @@ void CAdvancedSettings::Initialize() m_videoPreferStereoStream = false; m_videoDefaultLatency = 0.0; + m_videoDefaultHdrExtraLatency = 0.0; m_musicUseTimeSeeking = true; m_musicTimeSeekForward = 10; @@ -743,7 +744,7 @@ void CAdvancedSettings::ParseSettingsFile(const std::string &file) TiXmlElement* pVideoLatency = pElement->FirstChildElement("latency"); if (pVideoLatency) { - float refresh, refreshmin, refreshmax, delay; + float refresh, refreshmin, refreshmax; TiXmlElement* pRefreshVideoLatency = pVideoLatency->FirstChildElement("refresh"); while (pRefreshVideoLatency) @@ -761,8 +762,9 @@ void CAdvancedSettings::ParseSettingsFile(const std::string &file) videolatency.refreshmin = refreshmin; videolatency.refreshmax = refreshmax; } - if (XMLUtils::GetFloat(pRefreshVideoLatency, "delay", delay, -600.0f, 600.0f)) - videolatency.delay = delay; + XMLUtils::GetFloat(pRefreshVideoLatency, "delay", videolatency.delay, -600.0f, 600.0f); + XMLUtils::GetFloat(pRefreshVideoLatency, "hdrextradelay", videolatency.hdrextradelay, + -600.0f, 600.0f); if (videolatency.refreshmin > 0.0f && videolatency.refreshmax >= videolatency.refreshmin) m_videoRefreshLatency.push_back(videolatency); @@ -774,8 +776,10 @@ void CAdvancedSettings::ParseSettingsFile(const std::string &file) pRefreshVideoLatency = pRefreshVideoLatency->NextSiblingElement("refresh"); } - // Get default global display latency + // Get default global display latency values XMLUtils::GetFloat(pVideoLatency, "delay", m_videoDefaultLatency, -600.0f, 600.0f); + XMLUtils::GetFloat(pVideoLatency, "hdrextradelay", m_videoDefaultHdrExtraLatency, -600.0f, + 600.0f); } } @@ -1219,6 +1223,7 @@ void CAdvancedSettings::ParseSettingsFile(const std::string &file) XMLUtils::GetBoolean(pElement, "visualizedirtyregions", m_guiVisualizeDirtyRegions); XMLUtils::GetInt(pElement, "algorithmdirtyregions", m_guiAlgorithmDirtyRegions); XMLUtils::GetBoolean(pElement, "smartredraw", m_guiSmartRedraw); + XMLUtils::GetInt(pElement, "anisotropicfiltering", m_guiAnisotropicFiltering); } std::string seekSteps; @@ -1385,16 +1390,26 @@ void CAdvancedSettings::AddSettingsFile(const std::string &filename) m_settingsFiles.push_back(filename); } -float CAdvancedSettings::GetLatencyTweak(float refreshrate) +float CAdvancedSettings::GetLatencyTweak(float refreshrate, bool isHDREnabled) { - float delay = m_videoDefaultLatency; - for (int i = 0; i < (int) m_videoRefreshLatency.size(); i++) + float delay{}; + const auto& latency = + std::find_if(m_videoRefreshLatency.cbegin(), m_videoRefreshLatency.cend(), + [refreshrate](const auto& param) + { return refreshrate >= param.refreshmin && refreshrate <= param.refreshmax; }); + + if (latency != m_videoRefreshLatency.cend()) //refresh rate specific setting is found { - RefreshVideoLatency& videolatency = m_videoRefreshLatency[i]; - if (refreshrate >= videolatency.refreshmin && refreshrate <= videolatency.refreshmax) - delay = videolatency.delay; + delay = latency->delay == 0.0f ? m_videoDefaultLatency : latency->delay; + if (isHDREnabled) + delay += + latency->hdrextradelay == 0.0f ? m_videoDefaultHdrExtraLatency : latency->hdrextradelay; + } + else //apply default delay settings + { + delay = isHDREnabled ? m_videoDefaultLatency + m_videoDefaultHdrExtraLatency + : m_videoDefaultLatency; } - return delay; // in milliseconds } diff --git a/xbmc/settings/AdvancedSettings.h b/xbmc/settings/AdvancedSettings.h index b5df5118dd..8db9a89a56 100644 --- a/xbmc/settings/AdvancedSettings.h +++ b/xbmc/settings/AdvancedSettings.h @@ -94,6 +94,7 @@ struct RefreshVideoLatency float refreshmax; float delay; + float hdrextradelay; }; typedef std::vector<TVShowRegexp> SETTINGS_TVSHOWLIST; @@ -163,6 +164,7 @@ class CAdvancedSettings : public ISettingCallback, public ISettingsHandler std::vector<RefreshOverride> m_videoAdjustRefreshOverrides; std::vector<RefreshVideoLatency> m_videoRefreshLatency; float m_videoDefaultLatency; + float m_videoDefaultHdrExtraLatency; int m_videoCaptureUseOcclusionQuery; bool m_DXVACheckCompatibility; bool m_DXVACheckCompatibilityPresent; @@ -331,6 +333,7 @@ class CAdvancedSettings : public ISettingCallback, public ISettingsHandler bool m_guiVisualizeDirtyRegions; int m_guiAlgorithmDirtyRegions; bool m_guiSmartRedraw; + int32_t m_guiAnisotropicFiltering{0}; unsigned int m_addonPackageFolderSize; bool m_jsonOutputCompact; @@ -340,7 +343,7 @@ class CAdvancedSettings : public ISettingCallback, public ISettingsHandler std::vector<std::string> m_settingsFiles; void ParseSettingsFile(const std::string &file); - float GetLatencyTweak(float refreshrate); + float GetLatencyTweak(float refreshrate, bool isHDREnabled); bool m_initialized; void SetDebugMode(bool debug); diff --git a/xbmc/settings/MediaSettings.cpp b/xbmc/settings/MediaSettings.cpp index 09aad05861..e3027df998 100644 --- a/xbmc/settings/MediaSettings.cpp +++ b/xbmc/settings/MediaSettings.cpp @@ -119,7 +119,7 @@ bool CMediaSettings::Load(const TiXmlNode *settings) int toneMapMethod; if (!XMLUtils::GetInt(pElement, "tonemapmethod", toneMapMethod, VS_TONEMAPMETHOD_OFF, VS_TONEMAPMETHOD_MAX)) - toneMapMethod = VS_TONEMAPMETHOD_REINHARD; + toneMapMethod = VS_TONEMAPMETHOD_HABLE; m_defaultVideoSettings.m_ToneMapMethod = static_cast<ETONEMAPMETHOD>(toneMapMethod); if (!XMLUtils::GetFloat(pElement, "tonemapparam", m_defaultVideoSettings.m_ToneMapParam, 0.1f, 5.0f)) diff --git a/xbmc/settings/Settings.cpp b/xbmc/settings/Settings.cpp index e8e28a59f9..5d940f674c 100644 --- a/xbmc/settings/Settings.cpp +++ b/xbmc/settings/Settings.cpp @@ -21,9 +21,6 @@ #include "input/keyboard/KeyboardLayoutManager.h" #include <mutex> -#if defined(TARGET_POSIX) -#include "platform/posix/PosixTimezone.h" -#endif // defined(TARGET_POSIX) #include "network/upnp/UPnPSettings.h" #include "network/WakeOnAccess.h" #if defined(TARGET_DARWIN_OSX) and defined(HAS_XBMCHELPER) @@ -327,31 +324,9 @@ void CSettings::InitializeControls() GetSettingsManager()->RegisterSettingControl("colorbutton", this); } -void CSettings::InitializeVisibility() -{ - // hide some settings if necessary -#if defined(TARGET_DARWIN_EMBEDDED) - std::shared_ptr<CSettingString> timezonecountry = std::static_pointer_cast<CSettingString>(GetSettingsManager()->GetSetting(CSettings::SETTING_LOCALE_TIMEZONECOUNTRY)); - std::shared_ptr<CSettingString> timezone = std::static_pointer_cast<CSettingString>(GetSettingsManager()->GetSetting(CSettings::SETTING_LOCALE_TIMEZONE)); - - timezonecountry->SetRequirementsMet(false); - timezone->SetRequirementsMet(false); -#endif -} - void CSettings::InitializeDefaults() { // set some default values if necessary -#if defined(TARGET_POSIX) - std::shared_ptr<CSettingString> timezonecountry = std::static_pointer_cast<CSettingString>(GetSettingsManager()->GetSetting(CSettings::SETTING_LOCALE_TIMEZONECOUNTRY)); - std::shared_ptr<CSettingString> timezone = std::static_pointer_cast<CSettingString>(GetSettingsManager()->GetSetting(CSettings::SETTING_LOCALE_TIMEZONE)); - - if (timezonecountry->IsVisible()) - timezonecountry->SetDefault(g_timezone.GetCountryByTimezone(g_timezone.GetOSConfiguredTimezone())); - if (timezone->IsVisible()) - timezone->SetDefault(g_timezone.GetOSConfiguredTimezone()); -#endif // defined(TARGET_POSIX) - #if defined(TARGET_WINDOWS) // We prefer a fake fullscreen mode (window covering the screen rather than dedicated fullscreen) // as it works nicer with switching to other applications. However on some systems vsync is broken @@ -432,10 +407,6 @@ void CSettings::InitializeOptionFillers() GetSettingsManager()->RegisterSettingOptionsFiller("skincolors", ADDON::CSkinInfo::SettingOptionsSkinColorsFiller); GetSettingsManager()->RegisterSettingOptionsFiller("skinfonts", ADDON::CSkinInfo::SettingOptionsSkinFontsFiller); GetSettingsManager()->RegisterSettingOptionsFiller("skinthemes", ADDON::CSkinInfo::SettingOptionsSkinThemesFiller); -#ifdef TARGET_LINUX - GetSettingsManager()->RegisterSettingOptionsFiller("timezonecountries", CPosixTimezone::SettingOptionsTimezoneCountriesFiller); - GetSettingsManager()->RegisterSettingOptionsFiller("timezones", CPosixTimezone::SettingOptionsTimezonesFiller); -#endif GetSettingsManager()->RegisterSettingOptionsFiller( "keyboardlayouts", KEYBOARD::CKeyboardLayoutManager::SettingOptionsKeyboardLayoutsFiller); GetSettingsManager()->RegisterSettingOptionsFiller( @@ -532,9 +503,6 @@ void CSettings::InitializeISettingsHandlers() GetSettingsManager()->RegisterSettingsHandler(&CWakeOnAccess::GetInstance()); GetSettingsManager()->RegisterSettingsHandler(&CRssManager::GetInstance()); GetSettingsManager()->RegisterSettingsHandler(&g_langInfo); -#if defined(TARGET_LINUX) && !defined(TARGET_ANDROID) && !defined(__UCLIBC__) - GetSettingsManager()->RegisterSettingsHandler(&g_timezone); -#endif GetSettingsManager()->RegisterSettingsHandler(&CMediaSettings::GetInstance()); } @@ -542,9 +510,6 @@ void CSettings::UninitializeISettingsHandlers() { // unregister ISettingsHandler implementations GetSettingsManager()->UnregisterSettingsHandler(&CMediaSettings::GetInstance()); -#if defined(TARGET_LINUX) - GetSettingsManager()->UnregisterSettingsHandler(&g_timezone); -#endif // defined(TARGET_LINUX) GetSettingsManager()->UnregisterSettingsHandler(&g_langInfo); GetSettingsManager()->UnregisterSettingsHandler(&CRssManager::GetInstance()); GetSettingsManager()->UnregisterSettingsHandler(&CWakeOnAccess::GetInstance()); @@ -629,13 +594,6 @@ void CSettings::InitializeISettingCallbacks() settingSet.insert(CSettings::SETTING_LOOKANDFEEL_RSSEDIT); GetSettingsManager()->RegisterCallback(&CRssManager::GetInstance(), settingSet); -#if defined(TARGET_LINUX) - settingSet.clear(); - settingSet.insert(CSettings::SETTING_LOCALE_TIMEZONE); - settingSet.insert(CSettings::SETTING_LOCALE_TIMEZONECOUNTRY); - GetSettingsManager()->RegisterCallback(&g_timezone, settingSet); -#endif - #if defined(TARGET_DARWIN_OSX) and defined(HAS_XBMCHELPER) settingSet.clear(); settingSet.insert(CSettings::SETTING_INPUT_APPLEREMOTEMODE); @@ -678,9 +636,6 @@ void CSettings::UninitializeISettingCallbacks() GetSettingsManager()->UnregisterCallback(&g_langInfo); GetSettingsManager()->UnregisterCallback(&g_passwordManager); GetSettingsManager()->UnregisterCallback(&CRssManager::GetInstance()); -#if defined(TARGET_LINUX) - GetSettingsManager()->UnregisterCallback(&g_timezone); -#endif // defined(TARGET_LINUX) #if defined(TARGET_DARWIN_OSX) and defined(HAS_XBMCHELPER) GetSettingsManager()->UnregisterCallback(&XBMCHelper::GetInstance()); #endif diff --git a/xbmc/settings/Settings.h b/xbmc/settings/Settings.h index bfc5e6072c..35ea531b14 100644 --- a/xbmc/settings/Settings.h +++ b/xbmc/settings/Settings.h @@ -45,8 +45,6 @@ public: static constexpr auto SETTING_LOCALE_CHARSET = "locale.charset"; static constexpr auto SETTING_LOCALE_KEYBOARDLAYOUTS = "locale.keyboardlayouts"; static constexpr auto SETTING_LOCALE_ACTIVEKEYBOARDLAYOUT = "locale.activekeyboardlayout"; - static constexpr auto SETTING_LOCALE_TIMEZONECOUNTRY = "locale.timezonecountry"; - static constexpr auto SETTING_LOCALE_TIMEZONE = "locale.timezone"; static constexpr auto SETTING_LOCALE_SHORTDATEFORMAT = "locale.shortdateformat"; static constexpr auto SETTING_LOCALE_LONGDATEFORMAT = "locale.longdateformat"; static constexpr auto SETTING_LOCALE_TIMEFORMAT = "locale.timeformat"; @@ -602,7 +600,6 @@ protected: void UninitializeOptionFillers() override; void InitializeConditions() override; void UninitializeConditions() override; - void InitializeVisibility() override; void InitializeDefaults() override; void InitializeISettingsHandlers() override; void UninitializeISettingsHandlers() override; diff --git a/xbmc/settings/dialogs/GUIDialogSettingsBase.cpp b/xbmc/settings/dialogs/GUIDialogSettingsBase.cpp index 50af6f9b59..1d878dbb2d 100644 --- a/xbmc/settings/dialogs/GUIDialogSettingsBase.cpp +++ b/xbmc/settings/dialogs/GUIDialogSettingsBase.cpp @@ -466,17 +466,20 @@ void CGUIDialogSettingsBase::FreeControls() control->ClearAll(); } m_categories.clear(); - FreeSettingsControls(); -} -void CGUIDialogSettingsBase::DeleteControls() -{ + // If we created our own edit control instead of borrowing it then clean it up if (m_newOriginalEdit) { delete m_pOriginalEdit; - m_pOriginalEdit = NULL; + m_pOriginalEdit = nullptr; + m_newOriginalEdit = false; } + FreeSettingsControls(); +} + +void CGUIDialogSettingsBase::DeleteControls() +{ m_resetSetting.reset(); m_dummyCategory.reset(); } diff --git a/xbmc/settings/windows/GUIControlSettings.cpp b/xbmc/settings/windows/GUIControlSettings.cpp index fdb1a439fd..ea45b0deed 100644 --- a/xbmc/settings/windows/GUIControlSettings.cpp +++ b/xbmc/settings/windows/GUIControlSettings.cpp @@ -9,6 +9,7 @@ #include "GUIControlSettings.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "Util.h" #include "addons/AddonManager.h" diff --git a/xbmc/test/TestBasicEnvironment.cpp b/xbmc/test/TestBasicEnvironment.cpp index 7a357765a0..7a33e9d851 100644 --- a/xbmc/test/TestBasicEnvironment.cpp +++ b/xbmc/test/TestBasicEnvironment.cpp @@ -9,6 +9,7 @@ #include "TestBasicEnvironment.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "ServiceManager.h" #include "TestUtils.h" diff --git a/xbmc/utils/ExecString.cpp b/xbmc/utils/ExecString.cpp index cd392c26db..f4767ff958 100644 --- a/xbmc/utils/ExecString.cpp +++ b/xbmc/utils/ExecString.cpp @@ -18,8 +18,11 @@ #include "utils/StringUtils.h" #include "utils/Variant.h" #include "utils/log.h" +#include "video/VideoFileItemClassify.h" #include "video/VideoInfoTag.h" +using namespace KODI; + CExecString::CExecString(const std::string& execString) { m_valid = Parse(execString); @@ -123,7 +126,7 @@ bool CExecString::Parse(const CFileItem& item, const std::string& contextWindow) Build("StartAndroidActivity", {StringUtils::Paramify(item.GetPath().substr(26))}); else // assume a media file { - if (item.IsVideoDb() && item.HasVideoInfoTag()) + if (VIDEO::IsVideoDb(item) && item.HasVideoInfoTag()) BuildPlayMedia(item, StringUtils::Paramify(item.GetVideoInfoTag()->m_strFileNameAndPath)); else if (item.IsMusicDb() && item.HasMusicInfoTag()) BuildPlayMedia(item, StringUtils::Paramify(item.GetMusicInfoTag()->GetURL())); diff --git a/xbmc/utils/FileOperationJob.h b/xbmc/utils/FileOperationJob.h index 7284c62b6b..5dad5403bd 100644 --- a/xbmc/utils/FileOperationJob.h +++ b/xbmc/utils/FileOperationJob.h @@ -9,6 +9,7 @@ #pragma once #include "FileItem.h" +#include "FileItemList.h" #include "filesystem/IFileTypes.h" #include "utils/ProgressJob.h" diff --git a/xbmc/utils/FontUtils.cpp b/xbmc/utils/FontUtils.cpp index 2c23b90c69..8e6af68907 100644 --- a/xbmc/utils/FontUtils.cpp +++ b/xbmc/utils/FontUtils.cpp @@ -9,6 +9,7 @@ #include "FontUtils.h" #include "FileItem.h" +#include "FileItemList.h" #include "StringUtils.h" #include "URIUtils.h" #include "filesystem/Directory.h" diff --git a/xbmc/utils/Geometry.h b/xbmc/utils/Geometry.h index 31557fc647..1bf4624d06 100644 --- a/xbmc/utils/Geometry.h +++ b/xbmc/utils/Geometry.h @@ -281,6 +281,11 @@ public: return (x1 <= point.x && point.x <= x2 && y1 <= point.y && point.y <= y2); }; + constexpr bool Intersects(const this_type& rect) const + { + return (x1 < rect.x2 && x2 > rect.x1 && y1 < rect.y2 && y2 > rect.y1); + }; + this_type& operator-=(const point_type &point) XBMC_FORCE_INLINE { x1 -= point.x; diff --git a/xbmc/utils/GroupUtils.cpp b/xbmc/utils/GroupUtils.cpp index b3c00efc18..348b574880 100644 --- a/xbmc/utils/GroupUtils.cpp +++ b/xbmc/utils/GroupUtils.cpp @@ -9,15 +9,19 @@ #include "GroupUtils.h" #include "FileItem.h" +#include "FileItemList.h" #include "filesystem/MultiPathDirectory.h" #include "utils/StringUtils.h" #include "utils/URIUtils.h" #include "video/VideoDbUrl.h" +#include "video/VideoFileItemClassify.h" #include "video/VideoInfoTag.h" #include <map> #include <set> +using namespace KODI; + using SetMap = std::map<int, std::set<CFileItemPtr> >; bool GroupUtils::Group(GroupBy groupBy, const std::string &baseDir, const CFileItemList &items, CFileItemList &groupedItems, GroupAttribute groupAttributes /* = GroupAttributeNone */) @@ -127,7 +131,7 @@ bool GroupUtils::Group(GroupBy groupBy, const std::string &baseDir, const CFileI //accumulate the path for a multipath construction CFileItem video(movieInfo->m_basePath, false); - if (video.IsVideo()) + if (VIDEO::IsVideo(video)) pathSet.insert(URIUtils::GetParentPath(movieInfo->m_basePath)); else pathSet.insert(movieInfo->m_basePath); diff --git a/xbmc/utils/RecentlyAddedJob.cpp b/xbmc/utils/RecentlyAddedJob.cpp index fca1f6d997..3a845ac2ac 100644 --- a/xbmc/utils/RecentlyAddedJob.cpp +++ b/xbmc/utils/RecentlyAddedJob.cpp @@ -9,6 +9,7 @@ #include "RecentlyAddedJob.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "guilib/GUIComponent.h" #include "guilib/GUIWindow.h" diff --git a/xbmc/utils/SaveFileStateJob.cpp b/xbmc/utils/SaveFileStateJob.cpp index aa23b11508..aeb479a4bb 100644 --- a/xbmc/utils/SaveFileStateJob.cpp +++ b/xbmc/utils/SaveFileStateJob.cpp @@ -28,6 +28,9 @@ #include "utils/Variant.h" #include "video/Bookmark.h" #include "video/VideoDatabase.h" +#include "video/VideoFileItemClassify.h" + +using namespace KODI::VIDEO; void CSaveFileState::DoWork(CFileItem& item, CBookmark& bookmark, @@ -37,7 +40,7 @@ void CSaveFileState::DoWork(CFileItem& item, if (item.HasVideoInfoTag() && StringUtils::StartsWith(item.GetVideoInfoTag()->m_strFileNameAndPath, "removable://")) progressTrackingFile = item.GetVideoInfoTag()->m_strFileNameAndPath; // this variable contains removable:// suffixed by disc label+uniqueid or is empty if label not uniquely identified - else if (item.HasVideoInfoTag() && item.IsVideoDb()) + else if (item.HasVideoInfoTag() && IsVideoDb(item)) progressTrackingFile = item.GetVideoInfoTag()->m_strFileNameAndPath; // we need the file url of the video db item to create the bookmark else if (item.HasProperty("original_listitem_url")) { @@ -57,7 +60,7 @@ void CSaveFileState::DoWork(CFileItem& item, return; } #endif - if (item.IsVideo()) + if (IsVideo(item)) { std::string redactPath = CURL::GetRedacted(progressTrackingFile); CLog::Log(LOGDEBUG, "{} - Saving file state for video item {}", __FUNCTION__, redactPath); diff --git a/xbmc/utils/URIUtils.cpp b/xbmc/utils/URIUtils.cpp index ca65b57b65..9b862a7f43 100644 --- a/xbmc/utils/URIUtils.cpp +++ b/xbmc/utils/URIUtils.cpp @@ -6,19 +6,21 @@ * See LICENSES/README.md for more information. */ -#include "network/Network.h" #include "URIUtils.h" + #include "FileItem.h" +#include "FileItemList.h" +#include "ServiceBroker.h" +#include "StringUtils.h" +#include "URL.h" #include "filesystem/MultiPathDirectory.h" #include "filesystem/SpecialProtocol.h" #include "filesystem/StackDirectory.h" #include "network/DNSNameCache.h" +#include "network/Network.h" #include "pvr/channels/PVRChannelsPath.h" #include "settings/AdvancedSettings.h" -#include "URL.h" #include "utils/FileExtensionProvider.h" -#include "ServiceBroker.h" -#include "StringUtils.h" #include "utils/log.h" #if defined(TARGET_WINDOWS) diff --git a/xbmc/utils/test/TestVariant.cpp b/xbmc/utils/test/TestVariant.cpp index f5bf687ea6..60eafddf04 100644 --- a/xbmc/utils/test/TestVariant.cpp +++ b/xbmc/utils/test/TestVariant.cpp @@ -294,7 +294,7 @@ TEST(TestVariant, empty) std::map<std::string, std::string> strmap; EXPECT_TRUE(CVariant(strmap).empty()); - strmap.emplace(std::string("key"), std::string("value")); + strmap.emplace("key", "value"); EXPECT_FALSE(CVariant(strmap).empty()); std::string str; diff --git a/xbmc/video/CMakeLists.txt b/xbmc/video/CMakeLists.txt index 8586c30626..d867cdbace 100644 --- a/xbmc/video/CMakeLists.txt +++ b/xbmc/video/CMakeLists.txt @@ -7,6 +7,7 @@ set(SOURCES Bookmark.cpp VideoDatabase.cpp VideoDbUrl.cpp VideoEmbeddedImageFileLoader.cpp + VideoFileItemClassify.cpp VideoGeneratedImageFileLoader.cpp VideoInfoDownloader.cpp VideoInfoScanner.cpp @@ -28,6 +29,7 @@ set(HEADERS Bookmark.h VideoDatabase.h VideoDbUrl.h VideoEmbeddedImageFileLoader.h + VideoFileItemClassify.h VideoGeneratedImageFileLoader.h VideoInfoDownloader.h VideoInfoScanner.h diff --git a/xbmc/video/ContextMenus.cpp b/xbmc/video/ContextMenus.cpp index a7a724e082..1ab69f504e 100644 --- a/xbmc/video/ContextMenus.cpp +++ b/xbmc/video/ContextMenus.cpp @@ -24,6 +24,7 @@ #include "utils/ExecString.h" #include "utils/StringUtils.h" #include "utils/URIUtils.h" +#include "video/VideoFileItemClassify.h" #include "video/VideoInfoTag.h" #include "video/VideoManagerTypes.h" #include "video/VideoUtils.h" @@ -35,6 +36,8 @@ #include <utility> +using namespace KODI::VIDEO; + namespace CONTEXTMENU { @@ -87,7 +90,7 @@ bool CVideoMarkWatched::IsVisible(const CFileItem& item) const if (item.m_bIsFolder) // Only allow video db content, video and recording folders to be updated recursively { if (item.HasVideoInfoTag()) - return item.IsVideoDb(); + return IsVideoDb(item); else if (item.GetProperty("IsVideoFolder").asBoolean()) return true; else @@ -116,7 +119,7 @@ bool CVideoMarkUnWatched::IsVisible(const CFileItem& item) const if (item.m_bIsFolder) // Only allow video db content, video and recording folders to be updated recursively { if (item.HasVideoInfoTag()) - return item.IsVideoDb(); + return IsVideoDb(item); else if (item.GetProperty("IsVideoFolder").asBoolean()) return true; else @@ -237,7 +240,7 @@ bool CVideoChooseVersion::IsVisible(const CFileItem& item) const return item.HasVideoVersions() && !CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool( CSettings::SETTING_VIDEOLIBRARY_SHOWVIDEOVERSIONSASFOLDER) && - !VIDEO::IsVideoAssetFile(item); + !IsVideoAssetFile(item); } bool CVideoChooseVersion::Execute(const std::shared_ptr<CFileItem>& item) const @@ -272,7 +275,7 @@ std::vector<std::string> GetPlayers(const CPlayerCoreFactory& playerCoreFactory, const CFileItem& item) { std::vector<std::string> players; - if (item.IsVideoDb()) + if (IsVideoDb(item)) { //! @todo CPlayerCoreFactory and classes called from there do not handle dyn path correctly. CFileItem item2{item}; @@ -351,7 +354,7 @@ void SetPathAndPlay(const std::shared_ptr<CFileItem>& item, PlayMode mode) else { const auto itemCopy{std::make_shared<CFileItem>(*item)}; - if (itemCopy->IsVideoDb()) + if (IsVideoDb(*itemCopy)) { if (!itemCopy->m_bIsFolder) { @@ -431,7 +434,7 @@ bool CVideoPlayUsing::IsVisible(const CFileItem& item) const if (item.HasVideoVersions() && !CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool( CSettings::SETTING_VIDEOLIBRARY_SHOWVIDEOVERSIONSASFOLDER) && - !VIDEO::IsVideoAssetFile(item)) + !IsVideoAssetFile(item)) return false; if (item.IsLiveTV()) @@ -453,7 +456,7 @@ bool CVideoPlayVersionUsing::IsVisible(const CFileItem& item) const return item.HasVideoVersions() && !CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool( CSettings::SETTING_VIDEOLIBRARY_SHOWVIDEOVERSIONSASFOLDER) && - !VIDEO::IsVideoAssetFile(item); + !IsVideoAssetFile(item); } bool CVideoPlayVersionUsing::Execute(const std::shared_ptr<CFileItem>& itemIn) const diff --git a/xbmc/video/GUIViewStateVideo.cpp b/xbmc/video/GUIViewStateVideo.cpp index 278bec56b4..1cf1a0115c 100644 --- a/xbmc/video/GUIViewStateVideo.cpp +++ b/xbmc/video/GUIViewStateVideo.cpp @@ -9,6 +9,7 @@ #include "GUIViewStateVideo.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "VideoDatabase.h" #include "filesystem/Directory.h" @@ -21,8 +22,10 @@ #include "settings/SettingsComponent.h" #include "utils/FileExtensionProvider.h" #include "utils/SortUtils.h" +#include "video/VideoFileItemClassify.h" #include "view/ViewStateSettings.h" +using namespace KODI::VIDEO; using namespace XFILE; using namespace VIDEODATABASEDIRECTORY; @@ -69,7 +72,7 @@ CGUIViewStateWindowVideoNav::CGUIViewStateWindowVideoNav(const CFileItemList& it SetSortOrder(SortOrderNone); } - else if (items.IsVideoDb()) + else if (IsVideoDb(items)) { NODE_TYPE NodeType=CVideoDatabaseDirectory::GetDirectoryChildType(items.GetPath()); CQueryParams params; @@ -337,7 +340,7 @@ CGUIViewStateWindowVideoNav::CGUIViewStateWindowVideoNav(const CFileItemList& it void CGUIViewStateWindowVideoNav::SaveViewState() { - if (m_items.IsVideoDb()) + if (IsVideoDb(m_items)) { NODE_TYPE NodeType = CVideoDatabaseDirectory::GetDirectoryChildType(m_items.GetPath()); CQueryParams params; diff --git a/xbmc/video/VideoDatabase.cpp b/xbmc/video/VideoDatabase.cpp index d175929bb6..a40b707a3f 100644 --- a/xbmc/video/VideoDatabase.cpp +++ b/xbmc/video/VideoDatabase.cpp @@ -9,6 +9,7 @@ #include "VideoDatabase.h" #include "FileItem.h" +#include "FileItemList.h" #include "GUIInfoManager.h" #include "GUIPassword.h" #include "ServiceBroker.h" @@ -52,6 +53,7 @@ #include "utils/XMLUtils.h" #include "utils/log.h" #include "video/VideoDbUrl.h" +#include "video/VideoFileItemClassify.h" #include "video/VideoInfoTag.h" #include "video/VideoLibraryQueue.h" #include "video/VideoManagerTypes.h" @@ -70,6 +72,7 @@ using namespace VIDEO; using namespace ADDON; using namespace KODI::MESSAGING; using namespace KODI::GUILIB; +using namespace KODI::VIDEO; //******************************************************************************************************************************** CVideoDatabase::CVideoDatabase(void) = default; @@ -1040,7 +1043,7 @@ int CVideoDatabase::AddFile(const std::string& strFileNameAndPath, int CVideoDatabase::AddFile(const CFileItem& item) { - if (item.IsVideoDb() && item.HasVideoInfoTag()) + if (IsVideoDb(item) && item.HasVideoInfoTag()) { const auto videoInfoTag = item.GetVideoInfoTag(); if (videoInfoTag->m_iFileId != -1) @@ -4973,22 +4976,19 @@ bool CVideoDatabase::GetArtForAsset(int assetId, if (nullptr == m_pDS2) return false; // using dataset 2 as we're likely called in loops on dataset 1 - const std::string sqlFallback{fallback == ArtFallbackOptions::PARENT - ? StringUtils::Format("UNION " - "SELECT idMedia, media_type " - "FROM videoversion " - "WHERE idFile = {} ", - assetId) - : ""}; - - const std::string sql{PrepareSQL("SELECT art.media_type, art.type, art.url " - "FROM art " - "WHERE (media_id, media_type) " - "IN (" - "SELECT %i, '%s'" - "%s" - ")", - assetId, MediaTypeVideoVersion, sqlFallback.c_str())}; + std::string sql{PrepareSQL("SELECT art.media_type, art.type, art.url " + "FROM art " + "WHERE media_id = %i AND media_type = '%s' ", + assetId, MediaTypeVideoVersion)}; + + if (fallback == ArtFallbackOptions::PARENT) + sql.append(PrepareSQL("UNION " + "SELECT art.media_type, art.type, art.url " + "FROM art " + " JOIN videoversion as vv " + " ON art.media_id = vv.idMedia AND art.media_type = vv.media_type " + "WHERE idFile = %i", + assetId)); m_pDS2->query(sql); while (!m_pDS2->eof()) diff --git a/xbmc/video/VideoFileItemClassify.cpp b/xbmc/video/VideoFileItemClassify.cpp new file mode 100644 index 0000000000..d57306013d --- /dev/null +++ b/xbmc/video/VideoFileItemClassify.cpp @@ -0,0 +1,147 @@ +/* + * 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 "video/VideoFileItemClassify.h" + +#include "FileItem.h" +#include "ServiceBroker.h" +#include "URL.h" +#include "utils/FileExtensionProvider.h" +#include "utils/FileUtils.h" +#include "utils/StringUtils.h" +#include "utils/URIUtils.h" +#include "video/VideoInfoTag.h" + +namespace KODI::VIDEO +{ + +bool IsBDFile(const CFileItem& item) +{ + const std::string strFileName = URIUtils::GetFileName(item.GetDynPath()); + return (StringUtils::EqualsNoCase(strFileName, "index.bdmv") || + StringUtils::EqualsNoCase(strFileName, "MovieObject.bdmv") || + StringUtils::EqualsNoCase(strFileName, "INDEX.BDM") || + StringUtils::EqualsNoCase(strFileName, "MOVIEOBJ.BDM")); +} + +bool IsDiscStub(const CFileItem& item) +{ + if (IsVideoDb(item) && item.HasVideoInfoTag()) + { + CFileItem dbItem(item.m_bIsFolder ? item.GetVideoInfoTag()->m_strPath + : item.GetVideoInfoTag()->m_strFileNameAndPath, + item.m_bIsFolder); + return IsDiscStub(dbItem); + } + + return URIUtils::HasExtension(item.GetPath(), + CServiceBroker::GetFileExtensionProvider().GetDiscStubExtensions()); +} + +bool IsDVDFile(const CFileItem& item, bool bVobs /*= true*/, bool bIfos /*= true*/) +{ + const std::string strFileName = URIUtils::GetFileName(item.GetDynPath()); + if (bIfos) + { + if (StringUtils::EqualsNoCase(strFileName, "video_ts.ifo")) + return true; + if (StringUtils::StartsWithNoCase(strFileName, "vts_") && + StringUtils::EndsWithNoCase(strFileName, "_0.ifo") && strFileName.length() == 12) + return true; + } + if (bVobs) + { + if (StringUtils::EqualsNoCase(strFileName, "video_ts.vob")) + return true; + if (StringUtils::StartsWithNoCase(strFileName, "vts_") && + StringUtils::EndsWithNoCase(strFileName, ".vob")) + return true; + } + + return false; +} + +bool IsProtectedBlurayDisc(const CFileItem& item) +{ + const std::string path = URIUtils::AddFileToFolder(item.GetPath(), "AACS", "Unit_Key_RO.inf"); + return CFileUtils::Exists(path); +} + +bool IsSubtitle(const CFileItem& item) +{ + return URIUtils::HasExtension(item.GetPath(), + CServiceBroker::GetFileExtensionProvider().GetSubtitleExtensions()); +} + +bool IsVideo(const CFileItem& item) +{ + /* check preset mime type */ + if (StringUtils::StartsWithNoCase(item.GetMimeType(), "video/")) + return true; + + if (item.HasVideoInfoTag()) + return true; + + if (item.HasGameInfoTag()) + return false; + + if (item.HasMusicInfoTag()) + return false; + + if (item.HasPictureInfoTag()) + return false; + + // TV recordings are videos... + if (!item.m_bIsFolder && URIUtils::IsPVRTVRecordingFileOrFolder(item.GetPath())) + return true; + + // ... all other PVR items are not. + if (item.IsPVR()) + return false; + + if (URIUtils::IsDVD(item.GetPath())) + return true; + + std::string extension; + if (StringUtils::StartsWithNoCase(item.GetMimeType(), "application/")) + { /* check for some standard types */ + extension = item.GetMimeType().substr(12); + if (StringUtils::EqualsNoCase(extension, "ogg") || + StringUtils::EqualsNoCase(extension, "mp4") || StringUtils::EqualsNoCase(extension, "mxf")) + return true; + } + + //! @todo If the file is a zip file, ask the game clients if any support this + // file before assuming it is video. + + return URIUtils::HasExtension(item.GetPath(), + CServiceBroker::GetFileExtensionProvider().GetVideoExtensions()); +} + +bool IsVideoAssetFile(const CFileItem& item) +{ + if (item.m_bIsFolder || !IsVideoDb(item)) + return false; + + // @todo maybe in the future look for prefix videodb://movies/videoversions in path instead + // @todo better encoding of video assets as path, they won't always be tied with movies. + return CURL(item.GetPath()).HasOption("videoversionid"); +} + +bool IsVideoDb(const CFileItem& item) +{ + return URIUtils::IsVideoDb(item.GetPath()); +} + +bool IsVideoExtrasFolder(const CFileItem& item) +{ + return item.m_bIsFolder && + StringUtils::EqualsNoCase(URIUtils::GetFileOrFolderName(item.GetPath()), "extras"); +} + +} // namespace KODI::VIDEO diff --git a/xbmc/video/VideoFileItemClassify.h b/xbmc/video/VideoFileItemClassify.h new file mode 100644 index 0000000000..55e5aeded7 --- /dev/null +++ b/xbmc/video/VideoFileItemClassify.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2005-2018 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 + +class CFileItem; + +namespace KODI::VIDEO +{ + +//! \brief Check whether an item is a blu-ray file. +bool IsBDFile(const CFileItem& item); + +//! \brief Check whether an item is a disc stub. +bool IsDiscStub(const CFileItem& item); + +//! \brief Check whether an item is a DVD file. +bool IsDVDFile(const CFileItem& item, bool bVobs = true, bool bIfos = true); + +//! \brief Checks whether item points to a protected blu-ray disc. +bool IsProtectedBlurayDisc(const CFileItem& item); + +//! \brief Check whether an item is a subtitle file. +bool IsSubtitle(const CFileItem& item); + +//! \brief Check whether an item is a video item. +//! \details Note that this returns true for anything with a video info tag, +//! so that may include eg. folders. +bool IsVideo(const CFileItem& item); + +//! \brief Is the item a video asset, excluding folders +//! \param[in] item the item +//! \return true if it is, false otherwise +bool IsVideoAssetFile(const CFileItem& item); + +//! \brief Check whether an item is a video database item. +bool IsVideoDb(const CFileItem& item); + +//! \brief Check whether an item is a video extras folder item. +bool IsVideoExtrasFolder(const CFileItem& item); + +} // namespace KODI::VIDEO diff --git a/xbmc/video/VideoGeneratedImageFileLoader.cpp b/xbmc/video/VideoGeneratedImageFileLoader.cpp index e39f5960cf..6ef1b93ef9 100644 --- a/xbmc/video/VideoGeneratedImageFileLoader.cpp +++ b/xbmc/video/VideoGeneratedImageFileLoader.cpp @@ -17,8 +17,11 @@ #include "settings/Settings.h" #include "settings/SettingsComponent.h" #include "utils/URIUtils.h" +#include "video/VideoFileItemClassify.h" #include "video/VideoInfoTag.h" +using namespace KODI::VIDEO; + bool VIDEO::CVideoGeneratedImageFileLoader::CanLoad(const std::string& specialType) const { return specialType == "video"; @@ -29,7 +32,7 @@ namespace void SetupRarOptions(CFileItem& item, const std::string& path) { std::string path2(path); - if (item.IsVideoDb() && item.HasVideoInfoTag()) + if (IsVideoDb(item) && item.HasVideoInfoTag()) path2 = item.GetVideoInfoTag()->m_strFileNameAndPath; CURL url(path2); std::string opts = url.GetOptions(); @@ -40,7 +43,7 @@ void SetupRarOptions(CFileItem& item, const std::string& path) else opts = "?flags=8"; url.SetOptions(opts); - if (item.IsVideoDb() && item.HasVideoInfoTag()) + if (IsVideoDb(item) && item.HasVideoInfoTag()) item.GetVideoInfoTag()->m_strFileNameAndPath = url.Get(); else item.SetPath(url.Get()); diff --git a/xbmc/video/VideoInfoScanner.cpp b/xbmc/video/VideoInfoScanner.cpp index aca4162fd5..b9062bf0b1 100644 --- a/xbmc/video/VideoInfoScanner.cpp +++ b/xbmc/video/VideoInfoScanner.cpp @@ -9,6 +9,7 @@ #include "VideoInfoScanner.h" #include "FileItem.h" +#include "FileItemList.h" #include "GUIInfoManager.h" #include "GUIUserMessages.h" #include "ServiceBroker.h" @@ -42,6 +43,7 @@ #include "utils/URIUtils.h" #include "utils/Variant.h" #include "utils/log.h" +#include "video/VideoFileItemClassify.h" #include "video/VideoManagerTypes.h" #include "video/VideoThumbLoader.h" #include "video/dialogs/GUIDialogVideoManagerExtras.h" @@ -54,6 +56,7 @@ using namespace XFILE; using namespace ADDON; using namespace KODI::MESSAGING; +using namespace KODI::VIDEO; using KODI::MESSAGING::HELPERS::DialogResponse; using KODI::UTILITY::CDigest; @@ -413,7 +416,7 @@ namespace VIDEO break; // add video extras to library - if (foundSomething && !m_ignoreVideoExtras && pItem->IsVideoExtras()) + if (foundSomething && !m_ignoreVideoExtras && IsVideoExtrasFolder(*pItem)) { if (AddVideoExtras(items, content, pItem->GetPath())) { @@ -721,8 +724,8 @@ namespace VIDEO CScraperUrl* pURL, CGUIDialogProgress* pDlgProgress) { - if (pItem->m_bIsFolder || !pItem->IsVideo() || pItem->IsNFO() || - (pItem->IsPlayList() && !URIUtils::HasExtension(pItem->GetPath(), ".strm"))) + if (pItem->m_bIsFolder || !IsVideo(*pItem) || pItem->IsNFO() || + (pItem->IsPlayList() && !URIUtils::HasExtension(pItem->GetPath(), ".strm"))) return INFO_NOT_NEEDED; if (ProgressCancelled(pDlgProgress, 198, pItem->GetLabel())) @@ -826,8 +829,8 @@ namespace VIDEO CScraperUrl* pURL, CGUIDialogProgress* pDlgProgress) { - if (pItem->m_bIsFolder || !pItem->IsVideo() || pItem->IsNFO() || - (pItem->IsPlayList() && !URIUtils::HasExtension(pItem->GetPath(), ".strm"))) + if (pItem->m_bIsFolder || !IsVideo(*pItem) || pItem->IsNFO() || + (pItem->IsPlayList() && !URIUtils::HasExtension(pItem->GetPath(), ".strm"))) return INFO_NOT_NEEDED; if (ProgressCancelled(pDlgProgress, 20394, pItem->GetLabel())) @@ -2204,7 +2207,7 @@ namespace VIDEO KODI::TIME::FileTime time = pItem->m_dateTime; digest.Update(&time, sizeof(KODI::TIME::FileTime)); } - if (pItem->IsVideo() && !pItem->IsPlayList() && !pItem->IsNFO()) + if (IsVideo(*pItem) && !pItem->IsPlayList() && !pItem->IsNFO()) count++; } hash = digest.Finalize(); diff --git a/xbmc/video/VideoItemArtworkHandler.cpp b/xbmc/video/VideoItemArtworkHandler.cpp index 0401c832b3..b845b52b4c 100644 --- a/xbmc/video/VideoItemArtworkHandler.cpp +++ b/xbmc/video/VideoItemArtworkHandler.cpp @@ -9,6 +9,7 @@ #include "VideoItemArtworkHandler.h" #include "FileItem.h" +#include "FileItemList.h" #include "MediaSource.h" #include "ServiceBroker.h" #include "TextureDatabase.h" @@ -23,11 +24,13 @@ #include "utils/Variant.h" #include "utils/log.h" #include "video/VideoDatabase.h" +#include "video/VideoFileItemClassify.h" #include "video/VideoInfoScanner.h" #include "video/VideoInfoTag.h" #include "video/VideoThumbLoader.h" #include "video/tags/VideoTagExtractionHelper.h" +using namespace KODI::VIDEO; using namespace VIDEO; using namespace XFILE; @@ -118,7 +121,7 @@ void CVideoItemArtworkHandler::AddItemPathToFileBrowserSources(std::vector<CMedi itemDir = m_item->GetVideoInfoTag()->GetPath(); const CFileItem itemTmp(itemDir, false); - if (itemTmp.IsVideo()) + if (IsVideo(itemTmp)) itemDir = URIUtils::GetParentPath(itemDir); AddItemPathStringToFileBrowserSources(sources, itemDir, diff --git a/xbmc/video/VideoThumbLoader.cpp b/xbmc/video/VideoThumbLoader.cpp index 1cb634ac2e..7119716136 100644 --- a/xbmc/video/VideoThumbLoader.cpp +++ b/xbmc/video/VideoThumbLoader.cpp @@ -9,6 +9,7 @@ #include "VideoThumbLoader.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "TextureCache.h" #include "URL.h" @@ -29,6 +30,7 @@ #include "utils/URIUtils.h" #include "utils/log.h" #include "video/VideoDatabase.h" +#include "video/VideoFileItemClassify.h" #include "video/VideoInfoTag.h" #include "video/VideoManagerTypes.h" #include "video/guilib/VideoVersionHelper.h" @@ -37,6 +39,7 @@ #include <cstdlib> #include <utility> +using namespace KODI::VIDEO; using namespace XFILE; using namespace VIDEO; @@ -180,8 +183,11 @@ bool CVideoThumbLoader::LoadItemCached(CFileItem* pItem) if (!pItem->HasVideoInfoTag() || !pItem->GetVideoInfoTag()->HasStreamDetails()) // no stream details { - if ((pItem->HasVideoInfoTag() && pItem->GetVideoInfoTag()->m_iFileId >= 0) // file (or maybe folder) is in the database - || (!pItem->m_bIsFolder && pItem->IsVideo())) // Some other video file for which we haven't yet got any database details + if ((pItem->HasVideoInfoTag() && + pItem->GetVideoInfoTag()->m_iFileId >= 0) // file (or maybe folder) is in the database + || (!pItem->m_bIsFolder && + IsVideo( + *pItem))) // Some other video file for which we haven't yet got any database details { if (m_videoDatabase->GetStreamDetails(*pItem)) pItem->SetInvalid(); @@ -286,7 +292,7 @@ bool CVideoThumbLoader::LoadItemLookup(CFileItem* pItem) } // We can only extract flags/thumbs for file-like items - if (!pItem->m_bIsFolder && pItem->IsVideo()) + if (!pItem->m_bIsFolder && IsVideo(*pItem)) { const std::shared_ptr<CSettings> settings = CServiceBroker::GetSettingsComponent()->GetSettings(); if (!pItem->HasArt("thumb")) @@ -408,7 +414,7 @@ bool CVideoThumbLoader::FillLibraryArt(CFileItem &item) m_videoDatabase->Open(); // @todo unify asset path for other items path - if (VIDEO::IsVideoAssetFile(item)) + if (IsVideoAssetFile(item)) { if (m_videoDatabase->GetArtForAsset( tag.m_iFileId, @@ -549,7 +555,7 @@ std::string CVideoThumbLoader::GetLocalArt(const CFileItem &item, const std::str std::string CVideoThumbLoader::GetEmbeddedThumbURL(const CFileItem &item) { std::string path(item.GetPath()); - if (item.IsVideoDb() && item.HasVideoInfoTag()) + if (IsVideoDb(item) && item.HasVideoInfoTag()) path = item.GetVideoInfoTag()->m_strFileNameAndPath; if (URIUtils::IsStack(path)) path = CStackDirectory::GetFirstStackedFile(path); @@ -595,7 +601,7 @@ void CVideoThumbLoader::DetectAndAddMissingItemData(CFileItem &item) if (stereoMode.empty()) { std::string path = item.GetPath(); - if (item.IsVideoDb() && item.HasVideoInfoTag()) + if (IsVideoDb(item) && item.HasVideoInfoTag()) path = item.GetVideoInfoTag()->GetPath(); // check for custom stereomode setting in video settings diff --git a/xbmc/video/VideoUtils.cpp b/xbmc/video/VideoUtils.cpp index 70a1aa0a25..cc74cb0a0f 100644 --- a/xbmc/video/VideoUtils.cpp +++ b/xbmc/video/VideoUtils.cpp @@ -9,6 +9,7 @@ #include "VideoUtils.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "Util.h" #include "filesystem/Directory.h" @@ -17,14 +18,20 @@ #include "settings/Settings.h" #include "settings/SettingsComponent.h" #include "settings/lib/Setting.h" +#include "utils/FileUtils.h" #include "utils/URIUtils.h" #include "utils/log.h" #include "video/VideoDatabase.h" +#include "video/VideoFileItemClassify.h" #include "video/VideoInfoTag.h" +#include <algorithm> +#include <array> #include <cstdint> #include <vector> +using namespace KODI::VIDEO; + namespace { VIDEO_UTILS::ResumeInformation GetFolderItemResumeInformation(const CFileItem& item) @@ -121,13 +128,13 @@ VIDEO_UTILS::ResumeInformation GetNonFolderItemResumeInformation(const CFileItem } std::string path = item.GetPath(); - if (item.IsVideoDb() || item.IsDVD()) + if (IsVideoDb(item) || item.IsDVD()) { if (item.HasVideoInfoTag()) { path = item.GetVideoInfoTag()->m_strFileNameAndPath; } - else if (item.IsVideoDb()) + else if (IsVideoDb(item)) { // Obtain path+filename from video db XFILE::VIDEODATABASEDIRECTORY::CQueryParams params; @@ -177,6 +184,27 @@ VIDEO_UTILS::ResumeInformation GetNonFolderItemResumeInformation(const CFileItem namespace VIDEO_UTILS { +std::string GetOpticalMediaPath(const CFileItem& item) +{ + auto exists = [&item](const std::string& file) + { + const std::string path = URIUtils::AddFileToFolder(item.GetPath(), file); + return CFileUtils::Exists(path); + }; + + using namespace std::string_literals; + const auto files = std::array{ + "VIDEO_TS.IFO"s, "VIDEO_TS/VIDEO_TS.IFO"s, +#ifdef HAVE_LIBBLURAY + "index.bdmv"s, "INDEX.BDM"s, + "BDMV/index.bdmv"s, "BDMV/INDEX.BDM"s, +#endif + }; + + const auto it = std::find_if(files.begin(), files.end(), exists); + return it != files.end() ? URIUtils::AddFileToFolder(item.GetPath(), *it) : std::string{}; +} + bool IsAutoPlayNextItem(const CFileItem& item) { if (!item.HasVideoInfoTag()) diff --git a/xbmc/video/VideoUtils.h b/xbmc/video/VideoUtils.h index f8903730ae..200f650318 100644 --- a/xbmc/video/VideoUtils.h +++ b/xbmc/video/VideoUtils.h @@ -14,6 +14,15 @@ class CFileItem; namespace VIDEO_UTILS { +/*! + \brief Check whether an item is an optical media folder or its parent. + This will return the non-empty path to the playable entry point of the media + one or two levels down (VIDEO_TS.IFO for DVDs or index.bdmv for BDs). + The returned path will be empty if folder does not meet this criterion. + \return non-empty string if item is optical media folder, empty otherwise. + */ +std::string GetOpticalMediaPath(const CFileItem& item); + /*! \brief Check whether auto play next item is set for the media type of the given item. \param item [in] the item to check \return True if auto play next item is active, false otherwise. diff --git a/xbmc/video/dialogs/GUIDialogCMSSettings.cpp b/xbmc/video/dialogs/GUIDialogCMSSettings.cpp index 6299cacbc6..c7945523ee 100644 --- a/xbmc/video/dialogs/GUIDialogCMSSettings.cpp +++ b/xbmc/video/dialogs/GUIDialogCMSSettings.cpp @@ -9,6 +9,7 @@ #include "GUIDialogCMSSettings.h" #include "FileItem.h" +#include "FileItemList.h" #include "GUIPassword.h" #include "ServiceBroker.h" #include "addons/Skin.h" diff --git a/xbmc/video/dialogs/GUIDialogSubtitles.cpp b/xbmc/video/dialogs/GUIDialogSubtitles.cpp index e178a0002e..c22eda9717 100644 --- a/xbmc/video/dialogs/GUIDialogSubtitles.cpp +++ b/xbmc/video/dialogs/GUIDialogSubtitles.cpp @@ -9,6 +9,7 @@ #include "GUIDialogSubtitles.h" #include "FileItem.h" +#include "FileItemList.h" #include "LangInfo.h" #include "ServiceBroker.h" #include "URL.h" diff --git a/xbmc/video/dialogs/GUIDialogVideoBookmarks.cpp b/xbmc/video/dialogs/GUIDialogVideoBookmarks.cpp index 10708a2f80..9c086dc109 100644 --- a/xbmc/video/dialogs/GUIDialogVideoBookmarks.cpp +++ b/xbmc/video/dialogs/GUIDialogVideoBookmarks.cpp @@ -9,6 +9,7 @@ #include "GUIDialogVideoBookmarks.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "TextureCache.h" #include "Util.h" @@ -35,6 +36,7 @@ #include "utils/Variant.h" #include "utils/log.h" #include "video/VideoDatabase.h" +#include "video/VideoFileItemClassify.h" #include "view/ViewState.h" #include <algorithm> @@ -48,6 +50,8 @@ #define CONTROL_THUMBS 11 +using namespace KODI::VIDEO; + CGUIDialogVideoBookmarks::CGUIDialogVideoBookmarks() : CGUIDialog(WINDOW_DIALOG_VIDEO_BOOKMARKS, "VideoOSDBookmarks.xml") { @@ -531,7 +535,7 @@ bool CGUIDialogVideoBookmarks::AddEpisodeBookmark() bool CGUIDialogVideoBookmarks::OnAddBookmark() { - if (!g_application.CurrentFileItem().IsVideo()) + if (!IsVideo(g_application.CurrentFileItem())) return false; if (CGUIDialogVideoBookmarks::AddBookmark()) diff --git a/xbmc/video/dialogs/GUIDialogVideoInfo.cpp b/xbmc/video/dialogs/GUIDialogVideoInfo.cpp index 59daa631de..2585679c6e 100644 --- a/xbmc/video/dialogs/GUIDialogVideoInfo.cpp +++ b/xbmc/video/dialogs/GUIDialogVideoInfo.cpp @@ -10,6 +10,7 @@ #include "ContextMenuManager.h" #include "FileItem.h" +#include "FileItemList.h" #include "GUIPassword.h" #include "GUIUserMessages.h" #include "ServiceBroker.h" @@ -51,6 +52,7 @@ #include "utils/URIUtils.h" #include "utils/Variant.h" #include "video/VideoDbUrl.h" +#include "video/VideoFileItemClassify.h" #include "video/VideoInfoScanner.h" #include "video/VideoInfoTag.h" #include "video/VideoItemArtworkHandler.h" @@ -71,6 +73,7 @@ using namespace XFILE::VIDEODATABASEDIRECTORY; using namespace XFILE; using namespace KODI::MESSAGING; +using namespace KODI::VIDEO; #define CONTROL_IMAGE 3 #define CONTROL_TEXTAREA 4 @@ -279,7 +282,7 @@ void CGUIDialogVideoInfo::OnInitWindow() CONTROL_DISABLE(CONTROL_BTN_REFRESH); // @todo add support to edit video asset art. Until then edit art through Versions Manager. - if (!VIDEO::IsVideoAssetFile(*m_movieItem)) + if (!IsVideoAssetFile(*m_movieItem)) CONTROL_ENABLE_ON_CONDITION( CONTROL_BTN_GET_THUMB, (profileManager->GetCurrentProfile().canWriteDatabases() || @@ -1067,7 +1070,8 @@ std::string CGUIDialogVideoInfo::GetThumbnail() const int CGUIDialogVideoInfo::ManageVideoItem(const std::shared_ptr<CFileItem>& item) { - if (item == nullptr || !item->IsVideoDb() || !item->HasVideoInfoTag() || item->GetVideoInfoTag()->m_iDbId < 0) + if (item == nullptr || !IsVideoDb(*item) || !item->HasVideoInfoTag() || + item->GetVideoInfoTag()->m_iDbId < 0) return -1; CVideoDatabase database; @@ -1078,18 +1082,18 @@ int CGUIDialogVideoInfo::ManageVideoItem(const std::shared_ptr<CFileItem>& item) int dbId = item->GetVideoInfoTag()->m_iDbId; CContextButtons buttons; - if ((type == MediaTypeMovie && !VIDEO::IsVideoAssetFile(*item)) || - type == MediaTypeVideoCollection || type == MediaTypeTvShow || type == MediaTypeEpisode || + if ((type == MediaTypeMovie && !IsVideoAssetFile(*item)) || type == MediaTypeVideoCollection || + type == MediaTypeTvShow || type == MediaTypeEpisode || (type == MediaTypeSeason && item->GetVideoInfoTag()->m_iSeason > 0) || // seasons without "all seasons" and "specials" type == MediaTypeMusicVideo) buttons.Add(CONTEXT_BUTTON_EDIT, 16105); - if ((type == MediaTypeMovie && !VIDEO::IsVideoAssetFile(*item)) || type == MediaTypeTvShow || + if ((type == MediaTypeMovie && !IsVideoAssetFile(*item)) || type == MediaTypeTvShow || type == MediaTypeSeason) buttons.Add(CONTEXT_BUTTON_EDIT_SORTTITLE, 16107); - if (type == MediaTypeMovie && !VIDEO::IsVideoAssetFile(*item)) + if (type == MediaTypeMovie && !IsVideoAssetFile(*item)) { // only show link/unlink if there are tvshows available if (database.HasContent(VideoDbContentType::TVSHOWS)) @@ -1113,9 +1117,8 @@ int CGUIDialogVideoInfo::ManageVideoItem(const std::shared_ptr<CFileItem>& item) item->GetVideoInfoTag()->m_iBookmarkId > 0) buttons.Add(CONTEXT_BUTTON_UNLINK_BOOKMARK, 20405); - if (type == MediaTypeVideoCollection || - (type == MediaTypeMovie && !VIDEO::IsVideoAssetFile(*item)) || type == MediaTypeTvShow || - type == MediaTypeSeason || type == MediaTypeEpisode) + if (type == MediaTypeVideoCollection || (type == MediaTypeMovie && !IsVideoAssetFile(*item)) || + type == MediaTypeTvShow || type == MediaTypeSeason || type == MediaTypeEpisode) buttons.Add(CONTEXT_BUTTON_SET_ART, 13511); // movie sets @@ -1139,7 +1142,7 @@ int CGUIDialogVideoInfo::ManageVideoItem(const std::shared_ptr<CFileItem>& item) } } - if (type != MediaTypeSeason && !VIDEO::IsVideoAssetFile(*item)) + if (type != MediaTypeSeason && !IsVideoAssetFile(*item)) { // Remove from library buttons.Add(CONTEXT_BUTTON_DELETE, 646); diff --git a/xbmc/video/dialogs/GUIDialogVideoManager.cpp b/xbmc/video/dialogs/GUIDialogVideoManager.cpp index d2d503c0fc..18c6d90562 100644 --- a/xbmc/video/dialogs/GUIDialogVideoManager.cpp +++ b/xbmc/video/dialogs/GUIDialogVideoManager.cpp @@ -9,6 +9,7 @@ #include "GUIDialogVideoManager.h" #include "FileItem.h" +#include "FileItemList.h" #include "GUIUserMessages.h" #include "MediaSource.h" #include "ServiceBroker.h" @@ -51,9 +52,6 @@ CGUIDialogVideoManager::CGUIDialogVideoManager(int windowId) m_selectedVideoAsset(std::make_shared<CFileItem>()) { m_loadType = KEEP_IN_MEMORY; - - if (!m_database.Open()) - CLog::LogF(LOGERROR, "Failed to open video database!"); } bool CGUIDialogVideoManager::OnMessage(CGUIMessage& message) @@ -115,6 +113,9 @@ bool CGUIDialogVideoManager::OnAction(const CAction& action) void CGUIDialogVideoManager::OnInitWindow() { + if (!m_database.IsOpen() && !m_database.Open()) + CLog::LogF(LOGERROR, "Failed to open video database!"); + CGUIDialog::OnInitWindow(); SET_CONTROL_LABEL(CONTROL_LABEL_TITLE, @@ -127,6 +128,12 @@ void CGUIDialogVideoManager::OnInitWindow() UpdateControls(); } +void CGUIDialogVideoManager::OnDeinitWindow(int nextWindowID) +{ + CGUIDialog::OnDeinitWindow(nextWindowID); + m_database.Close(); +} + void CGUIDialogVideoManager::Clear() { m_videoAssetsList->Clear(); @@ -198,6 +205,9 @@ void CGUIDialogVideoManager::UpdateControls() void CGUIDialogVideoManager::Refresh() { + if (!m_database.IsOpen() && !m_database.Open()) + CLog::LogF(LOGERROR, "Failed to open video database!"); + Clear(); const int dbId{m_videoAsset->GetVideoInfoTag()->m_iDbId}; diff --git a/xbmc/video/dialogs/GUIDialogVideoManager.h b/xbmc/video/dialogs/GUIDialogVideoManager.h index b4b043df0a..a76f724259 100644 --- a/xbmc/video/dialogs/GUIDialogVideoManager.h +++ b/xbmc/video/dialogs/GUIDialogVideoManager.h @@ -31,6 +31,7 @@ public: protected: void OnInitWindow() override; + void OnDeinitWindow(int nextWindowID) override; bool OnMessage(CGUIMessage& message) override; bool OnAction(const CAction& action) override; diff --git a/xbmc/video/dialogs/GUIDialogVideoManagerExtras.cpp b/xbmc/video/dialogs/GUIDialogVideoManagerExtras.cpp index 28bae13d04..9f8206d44e 100644 --- a/xbmc/video/dialogs/GUIDialogVideoManagerExtras.cpp +++ b/xbmc/video/dialogs/GUIDialogVideoManagerExtras.cpp @@ -9,6 +9,7 @@ #include "GUIDialogVideoManagerExtras.h" #include "FileItem.h" +#include "FileItemList.h" #include "GUIUserMessages.h" #include "ServiceBroker.h" #include "URL.h" diff --git a/xbmc/video/dialogs/GUIDialogVideoManagerVersions.cpp b/xbmc/video/dialogs/GUIDialogVideoManagerVersions.cpp index f2dada7087..f48c61ee67 100644 --- a/xbmc/video/dialogs/GUIDialogVideoManagerVersions.cpp +++ b/xbmc/video/dialogs/GUIDialogVideoManagerVersions.cpp @@ -9,6 +9,7 @@ #include "GUIDialogVideoManagerVersions.h" #include "FileItem.h" +#include "FileItemList.h" #include "GUIUserMessages.h" #include "ServiceBroker.h" #include "URL.h" diff --git a/xbmc/video/guilib/VideoGUIUtils.cpp b/xbmc/video/guilib/VideoGUIUtils.cpp index 176ec8edce..9cd5487828 100644 --- a/xbmc/video/guilib/VideoGUIUtils.cpp +++ b/xbmc/video/guilib/VideoGUIUtils.cpp @@ -9,6 +9,7 @@ #include "VideoGUIUtils.h" #include "FileItem.h" +#include "FileItemList.h" #include "GUIPassword.h" #include "PartyModeManager.h" #include "PlayListPlayer.h" @@ -35,10 +36,13 @@ #include "utils/URIUtils.h" #include "utils/log.h" #include "video/VideoDatabase.h" +#include "video/VideoFileItemClassify.h" #include "video/VideoInfoTag.h" #include "video/VideoUtils.h" #include "view/GUIViewState.h" +using namespace KODI::VIDEO; + namespace { class CAsyncGetItemsForPlaylist : public IRunnable @@ -134,7 +138,7 @@ void CAsyncGetItemsForPlaylist::GetItemsForPlaylist(const std::shared_ptr<CFileI if (item->m_bIsFolder) { // check if it's a folder with dvd or bluray files, then just add the relevant file - const std::string mediapath = item->GetOpticalMediaPath(); + const std::string mediapath = VIDEO_UTILS::GetOpticalMediaPath(*item); if (!mediapath.empty()) { m_queuedItems.Add(std::make_shared<CFileItem>(mediapath, false)); @@ -197,7 +201,7 @@ void CAsyncGetItemsForPlaylist::GetItemsForPlaylist(const std::shared_ptr<CFileI items.Sort(sortDesc); } - if (items.GetContent().empty() && !items.IsVideoDb() && !items.IsVirtualDirectoryRoot() && + if (items.GetContent().empty() && !IsVideoDb(items) && !items.IsVirtualDirectoryRoot() && !items.IsSourcesPath() && !items.IsLibraryFolder()) { CVideoDatabase db; @@ -299,7 +303,7 @@ void CAsyncGetItemsForPlaylist::GetItemsForPlaylist(const std::shared_ptr<CFileI // a playable python files m_queuedItems.Add(item); } - else if (item->IsVideoDb()) + else if (IsVideoDb(*item)) { // this case is needed unless we allow IsVideo() to return true for videodb items, // but then we have issues with playlists of videodb items @@ -307,7 +311,7 @@ void CAsyncGetItemsForPlaylist::GetItemsForPlaylist(const std::shared_ptr<CFileI itemCopy->SetStartOffset(item->GetStartOffset()); m_queuedItems.Add(itemCopy); } - else if (!item->IsNFO() && item->IsVideo()) + else if (!item->IsNFO() && IsVideo(*item)) { m_queuedItems.Add(item); } @@ -553,7 +557,7 @@ bool IsItemPlayable(const CFileItem& item) return false; if (item.m_bIsFolder && - (item.IsVideoDb() || StringUtils::StartsWithNoCase(item.GetPath(), "library://video/"))) + (IsVideoDb(item) || StringUtils::StartsWithNoCase(item.GetPath(), "library://video/"))) { // Exclude top level nodes - eg can't play 'genres' just a specific genre etc const XFILE::VIDEODATABASEDIRECTORY::NODE_TYPE node = @@ -571,7 +575,7 @@ bool IsItemPlayable(const CFileItem& item) { return true; } - else if ((!item.m_bIsFolder && item.IsVideo()) || item.IsDVD() || item.IsCDDA()) + else if ((!item.m_bIsFolder && IsVideo(item)) || item.IsDVD() || item.IsCDDA()) { return true; } diff --git a/xbmc/video/guilib/VideoSelectActionProcessor.cpp b/xbmc/video/guilib/VideoSelectActionProcessor.cpp index 665b55858d..b3a84b1fb8 100644 --- a/xbmc/video/guilib/VideoSelectActionProcessor.cpp +++ b/xbmc/video/guilib/VideoSelectActionProcessor.cpp @@ -9,6 +9,7 @@ #include "VideoSelectActionProcessor.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "dialogs/GUIDialogContextMenu.h" #include "dialogs/GUIDialogSelect.h" diff --git a/xbmc/video/guilib/VideoVersionHelper.cpp b/xbmc/video/guilib/VideoVersionHelper.cpp index 035ed2c45c..6a4923052b 100644 --- a/xbmc/video/guilib/VideoVersionHelper.cpp +++ b/xbmc/video/guilib/VideoVersionHelper.cpp @@ -9,6 +9,7 @@ #include "VideoVersionHelper.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "URL.h" #include "dialogs/GUIDialogSelect.h" @@ -21,9 +22,11 @@ #include "utils/StringUtils.h" #include "utils/log.h" #include "video/VideoDatabase.h" +#include "video/VideoFileItemClassify.h" #include "video/VideoManagerTypes.h" #include "video/VideoThumbLoader.h" +using namespace KODI::VIDEO; using namespace VIDEO::GUILIB; namespace @@ -46,7 +49,7 @@ private: std::shared_ptr<const CFileItem> ChooseVideo(CGUIDialogSelect& dialog, int headingId, int buttonId, - const CFileItemList& itemsToDisplay, + CFileItemList& itemsToDisplay, const CFileItemList& itemsToSwitchTo); const std::shared_ptr<const CFileItem> m_item; @@ -151,15 +154,13 @@ std::shared_ptr<const CFileItem> CVideoChooser::ChooseVideoExtra() std::shared_ptr<const CFileItem> CVideoChooser::ChooseVideo(CGUIDialogSelect& dialog, int headingId, int buttonId, - const CFileItemList& itemsToDisplay, + CFileItemList& itemsToDisplay, const CFileItemList& itemsToSwitchTo) { CVideoThumbLoader thumbLoader; + thumbLoader.Load(itemsToDisplay); for (auto& item : itemsToDisplay) - { - thumbLoader.LoadItem(item.get()); item->SetLabel2(item->GetVideoInfoTag()->m_strFileNameAndPath); - } dialog.Reset(); @@ -174,6 +175,9 @@ std::shared_ptr<const CFileItem> CVideoChooser::ChooseVideo(CGUIDialogSelect& di dialog.Open(); + if (thumbLoader.IsLoading()) + thumbLoader.StopThread(); + m_switchType = dialog.IsButtonPressed(); if (dialog.IsConfirmed()) return dialog.GetSelectedFileItem(); @@ -277,17 +281,3 @@ std::shared_ptr<CFileItem> CVideoVersionHelper::ChooseVideoFromAssets( return item; } - -bool VIDEO::IsVideoAssetFile(const CFileItem& item) -{ - if (item.m_bIsFolder || !item.IsVideoDb()) - return false; - - // @todo maybe in the future look for prefix videodb://movies/videoversions in path instead - // @todo better encoding of video assets as path, they won't always be tied with movies. - const CURL itemUrl{item.GetPath()}; - if (itemUrl.HasOption("videoversionid")) - return true; - - return false; -} diff --git a/xbmc/video/guilib/VideoVersionHelper.h b/xbmc/video/guilib/VideoVersionHelper.h index 8d81ec1b65..b3ab15e503 100644 --- a/xbmc/video/guilib/VideoVersionHelper.h +++ b/xbmc/video/guilib/VideoVersionHelper.h @@ -23,11 +23,4 @@ public: }; } // namespace GUILIB -/*! - * \brief Is the item a video asset, excluding folders - * \param[in] item the item - * \return true if it is, false otherwise - */ -bool IsVideoAssetFile(const CFileItem& item); - } // namespace VIDEO diff --git a/xbmc/video/jobs/VideoLibraryMarkWatchedJob.cpp b/xbmc/video/jobs/VideoLibraryMarkWatchedJob.cpp index 486bd7a727..ef2e9253ad 100644 --- a/xbmc/video/jobs/VideoLibraryMarkWatchedJob.cpp +++ b/xbmc/video/jobs/VideoLibraryMarkWatchedJob.cpp @@ -9,6 +9,7 @@ #include "VideoLibraryMarkWatchedJob.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "Util.h" #include "filesystem/Directory.h" diff --git a/xbmc/video/jobs/VideoLibraryRefreshingJob.cpp b/xbmc/video/jobs/VideoLibraryRefreshingJob.cpp index 832bdd6b7f..ff0f7426fa 100644 --- a/xbmc/video/jobs/VideoLibraryRefreshingJob.cpp +++ b/xbmc/video/jobs/VideoLibraryRefreshingJob.cpp @@ -9,6 +9,7 @@ #include "VideoLibraryRefreshingJob.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "TextureDatabase.h" #include "URL.h" diff --git a/xbmc/video/jobs/VideoLibraryResetResumePointJob.cpp b/xbmc/video/jobs/VideoLibraryResetResumePointJob.cpp index 15b71a2955..1c9d2c768d 100644 --- a/xbmc/video/jobs/VideoLibraryResetResumePointJob.cpp +++ b/xbmc/video/jobs/VideoLibraryResetResumePointJob.cpp @@ -8,12 +8,13 @@ #include "VideoLibraryResetResumePointJob.h" -#include <vector> - #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "Util.h" #include "filesystem/IDirectory.h" + +#include <vector> #ifdef HAS_UPNP #include "network/upnp/UPnP.h" #endif diff --git a/xbmc/video/tags/VideoTagLoaderNFO.cpp b/xbmc/video/tags/VideoTagLoaderNFO.cpp index f85ce39818..c5e3b84539 100644 --- a/xbmc/video/tags/VideoTagLoaderNFO.cpp +++ b/xbmc/video/tags/VideoTagLoaderNFO.cpp @@ -9,6 +9,7 @@ #include "VideoTagLoaderNFO.h" #include "FileItem.h" +#include "FileItemList.h" #include "NfoFile.h" #include "URL.h" #include "filesystem/Directory.h" diff --git a/xbmc/video/tags/VideoTagLoaderPlugin.cpp b/xbmc/video/tags/VideoTagLoaderPlugin.cpp index f3b97ee608..6e7e8e0fbc 100644 --- a/xbmc/video/tags/VideoTagLoaderPlugin.cpp +++ b/xbmc/video/tags/VideoTagLoaderPlugin.cpp @@ -9,6 +9,7 @@ #include "VideoTagLoaderPlugin.h" #include "FileItem.h" +#include "FileItemList.h" #include "URL.h" #include "filesystem/PluginDirectory.h" diff --git a/xbmc/video/test/CMakeLists.txt b/xbmc/video/test/CMakeLists.txt index e03acfbe4d..1cf8a5d878 100644 --- a/xbmc/video/test/CMakeLists.txt +++ b/xbmc/video/test/CMakeLists.txt @@ -1,4 +1,6 @@ set(SOURCES TestStacks.cpp - TestVideoInfoScanner.cpp) + TestVideoFileItemClassify.cpp + TestVideoInfoScanner.cpp + TestVideoUtils.cpp) core_add_test_library(video_test) diff --git a/xbmc/video/test/TestStacks.cpp b/xbmc/video/test/TestStacks.cpp index f5d92eabf8..12639a1a5f 100644 --- a/xbmc/video/test/TestStacks.cpp +++ b/xbmc/video/test/TestStacks.cpp @@ -7,6 +7,7 @@ */ #include "FileItem.h" +#include "FileItemList.h" #include "filesystem/Directory.h" #include "test/TestUtils.h" diff --git a/xbmc/video/test/TestVideoFileItemClassify.cpp b/xbmc/video/test/TestVideoFileItemClassify.cpp new file mode 100644 index 0000000000..3fae8d23a0 --- /dev/null +++ b/xbmc/video/test/TestVideoFileItemClassify.cpp @@ -0,0 +1,219 @@ +/* + * Copyright (C) 2005-2018 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 "FileItem.h" +#include "ServiceBroker.h" +#include "filesystem/Directory.h" +#include "filesystem/File.h" +#include "games/tags/GameInfoTag.h" +#include "music/tags/MusicInfoTag.h" +#include "pictures/PictureInfoTag.h" +#include "test/TestUtils.h" +#include "utils/FileExtensionProvider.h" +#include "utils/FileUtils.h" +#include "utils/URIUtils.h" +#include "video/VideoFileItemClassify.h" +#include "video/VideoInfoTag.h" + +#include <array> + +#include <gtest/gtest.h> + +using namespace KODI; + +struct StubDefinition +{ + StubDefinition(const std::string& path, + bool res = true, + const std::string& tagPath = "", + bool isFolder = false) + : item(path, isFolder), result(res) + { + if (!tagPath.empty()) + { + if (isFolder) + item.GetVideoInfoTag()->m_strPath = tagPath; + else + item.GetVideoInfoTag()->m_strFileNameAndPath = tagPath; + } + } + + CFileItem item; + bool result; +}; + +class DiscStubTest : public testing::WithParamInterface<StubDefinition>, public testing::Test +{ +}; + +TEST_P(DiscStubTest, IsDiscStub) +{ + EXPECT_EQ(VIDEO::IsDiscStub(GetParam().item), GetParam().result); +} + +const auto discstub_tests = std::array{ + StubDefinition{"/home/user/test.disc"}, + StubDefinition{"videodb://foo/bar", true, "/home/user/test.disc"}, + StubDefinition{"videodb://foo/bar", false, "/home/user/test.disc", true}, + StubDefinition{"/home/user/test.avi", false}, +}; + +INSTANTIATE_TEST_SUITE_P(TestVideoFileItemClassify, + DiscStubTest, + testing::ValuesIn(discstub_tests)); + +struct VideoClassifyTest +{ + VideoClassifyTest(const std::string& path, + bool res = true, + const std::string& mime = "", + int tag_type = 0) + : item(path, false), result(res) + { + if (!mime.empty()) + item.SetMimeType(mime); + switch (tag_type) + { + case 1: + item.GetVideoInfoTag()->m_strFileNameAndPath = path; + break; + case 2: + item.GetGameInfoTag()->SetGameClient("some_client"); + break; + case 3: + item.GetMusicInfoTag()->SetPlayCount(1); + break; + case 4: + item.GetPictureInfoTag()->SetInfo("foo", "bar"); + ; + break; + default: + break; + } + } + + CFileItem item; + bool result; +}; + +class VideoTest : public testing::WithParamInterface<VideoClassifyTest>, public testing::Test +{ +}; + +TEST_P(VideoTest, IsVideo) +{ + EXPECT_EQ(VIDEO::IsVideo(GetParam().item), GetParam().result); +} + +const auto video_tests = std::array{ + VideoClassifyTest{"/home/user/video.avi", true, "video/avi"}, + VideoClassifyTest{"/home/user/video.avi", true, "", 1}, + VideoClassifyTest{"/home/user/video.avi", false, "", 2}, + VideoClassifyTest{"/home/user/video.avi", false, "", 3}, + VideoClassifyTest{"/home/user/video.avi", false, "", 4}, + VideoClassifyTest{"pvr://recordings/tv/1", true}, + VideoClassifyTest{"pvr://123", false}, + VideoClassifyTest{"dvd://VIDEO_TS/video_ts.ifo", true}, + VideoClassifyTest{"dvd://1", true}, + VideoClassifyTest{"/home/user/video.not", true, "application/ogg"}, + VideoClassifyTest{"/home/user/video.not", true, "application/mp4"}, + VideoClassifyTest{"/home/user/video.not", true, "application/mxf"}, +}; + +INSTANTIATE_TEST_SUITE_P(TestVideoFileItemClassify, VideoTest, testing::ValuesIn(video_tests)); + +TEST(TestVideoFileItemClassify, VideoExtensions) +{ + const auto& exts = CServiceBroker::GetFileExtensionProvider().GetVideoExtensions(); + for (const auto& ext : StringUtils::Split(exts, "|")) + { + if (!ext.empty()) + EXPECT_TRUE(VIDEO::IsVideo(CFileItem(ext, false))); + } +} + +TEST(TestVideoFileItemClassify, IsBDFile) +{ + EXPECT_TRUE(VIDEO::IsBDFile(CFileItem("/home/foo/index.BDMV", false))); + EXPECT_TRUE(VIDEO::IsBDFile(CFileItem("smb://foo/bar/index.bdm", false))); + EXPECT_TRUE(VIDEO::IsBDFile(CFileItem("ftp://foo:bar@foobar.com/movieobject.BDMV", false))); + EXPECT_TRUE(VIDEO::IsBDFile(CFileItem("https://foobar.com/movieobj.bdm", false))); + EXPECT_FALSE(VIDEO::IsBDFile(CFileItem("https://foobar.com/movieobject.not", false))); +} + +TEST(TestVideoFileItemClassify, IsDVDFile) +{ + EXPECT_TRUE(VIDEO::IsDVDFile(CFileItem("/home/foo/video_ts.vob", false), true, false)); + EXPECT_TRUE(VIDEO::IsDVDFile(CFileItem("/home/foo/video_ts.VOB", false), true, true)); + EXPECT_FALSE(VIDEO::IsDVDFile(CFileItem("/home/foo/video_TS.vob", false), false, false)); + EXPECT_FALSE(VIDEO::IsDVDFile(CFileItem("/home/foo/video_ts.VOb", false), false, true)); + + EXPECT_TRUE(VIDEO::IsDVDFile(CFileItem("/home/foo/vts_yo_0.vob", false), true, false)); + EXPECT_TRUE(VIDEO::IsDVDFile(CFileItem("/home/foo/vts_0_ifo.vob", false), true, true)); + EXPECT_FALSE(VIDEO::IsDVDFile(CFileItem("/home/foo/VTS_123456_0.vob", false), false, false)); + EXPECT_FALSE(VIDEO::IsDVDFile(CFileItem("/home/foo/VTS_qwerty_0.VOB", false), false, true)); + + EXPECT_TRUE(VIDEO::IsDVDFile(CFileItem("/home/foo/video_ts.IFO", false), false, true)); + EXPECT_TRUE(VIDEO::IsDVDFile(CFileItem("/home/foo/video_ts.IFO", false), true, true)); + EXPECT_FALSE(VIDEO::IsDVDFile(CFileItem("/home/foo/video_ts.IFO", false), false, false)); + EXPECT_FALSE(VIDEO::IsDVDFile(CFileItem("/home/foo/video_ts.IFO", false), true, false)); + + EXPECT_TRUE(VIDEO::IsDVDFile(CFileItem("/home/foo/vts_ab_0.ifo", false), false, true)); + EXPECT_TRUE(VIDEO::IsDVDFile(CFileItem("/home/foo/vts_ab_0.ifo", false), false, true)); + EXPECT_FALSE(VIDEO::IsDVDFile(CFileItem("/home/foo/VTS_ab_0.ifo", false), false, false)); + EXPECT_FALSE(VIDEO::IsDVDFile(CFileItem("/home/foo/VTS_ab_0.ifo", false), false, false)); +} + +TEST(TestVideoFileItemClassify, IsProtectedBlurayDisc) +{ + const auto temp_file = CXBMCTestUtils::Instance().CreateTempFile("bluraytest"); + const std::string dir = CXBMCTestUtils::Instance().TempFileDirectory(temp_file); + CFileUtils::DeleteItem(URIUtils::AddFileToFolder(dir, "AACS", "Unit_Key_RO.inf")); + EXPECT_FALSE(VIDEO::IsProtectedBlurayDisc(CFileItem(dir, true))); + XFILE::CDirectory::Create(URIUtils::AddFileToFolder(dir, "AACS")); + XFILE::CFile inf_file; + inf_file.OpenForWrite(URIUtils::AddFileToFolder(dir, "AACS", "Unit_Key_RO.inf")); + inf_file.Close(); + EXPECT_TRUE(VIDEO::IsProtectedBlurayDisc(CFileItem(dir, true))); + CFileUtils::DeleteItem(URIUtils::AddFileToFolder(dir, "AACS", "Unit_Key_RO.inf")); + CXBMCTestUtils::Instance().DeleteTempFile(temp_file); +} + +TEST(TestVideoFileItemClassify, IsSubtitle) +{ + const auto& exts = CServiceBroker::GetFileExtensionProvider().GetSubtitleExtensions(); + for (const auto& ext : StringUtils::Split(exts, "|")) + { + if (!ext.empty()) + EXPECT_TRUE(VIDEO::IsSubtitle(CFileItem("random" + ext, false))); + } + + EXPECT_FALSE(VIDEO::IsSubtitle(CFileItem("random.notasub", false))); +} + +TEST(TestVideoFileItemClassify, IsVideoAssetsFile) +{ + EXPECT_TRUE(VIDEO::IsVideoAssetFile(CFileItem("videodb://foo/bar?videoversionid=1", false))); + EXPECT_FALSE(VIDEO::IsVideoAssetFile(CFileItem("videodb://foo/bar?videoversionid=1", true))); + EXPECT_FALSE(VIDEO::IsVideoAssetFile(CFileItem("videodb://foo/bar", false))); +} + +TEST(TestVideoFileItemClassify, IsVideoDb) +{ + EXPECT_TRUE(VIDEO::IsVideoDb(CFileItem("videodb://1/2/3", false))); + EXPECT_TRUE(VIDEO::IsVideoDb(CFileItem("videodb://1/2/", true))); + EXPECT_FALSE(VIDEO::IsVideoDb(CFileItem("/videodb/home/foo/Extraordinary/", true))); +} + +TEST(TestVideoFileItemClassify, IsVideoExtrasFolder) +{ + EXPECT_TRUE(VIDEO::IsVideoExtrasFolder(CFileItem("/home/foo/Extras/", true))); + EXPECT_TRUE(VIDEO::IsVideoExtrasFolder(CFileItem("/home/foo/extras/", true))); + EXPECT_FALSE(VIDEO::IsVideoExtrasFolder(CFileItem("/home/foo/Extraordinary/", true))); + EXPECT_FALSE(VIDEO::IsVideoExtrasFolder(CFileItem("/home/foo/Extras/abc.mkv", false))); +} diff --git a/xbmc/video/test/TestVideoUtils.cpp b/xbmc/video/test/TestVideoUtils.cpp new file mode 100644 index 0000000000..5c77d9bd50 --- /dev/null +++ b/xbmc/video/test/TestVideoUtils.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2005-2018 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 "FileItem.h" +#include "Util.h" +#include "filesystem/Directory.h" +#include "platform/Filesystem.h" +#include "utils/FileUtils.h" +#include "utils/URIUtils.h" +#include "video/VideoUtils.h" + +#include <array> +#include <fstream> + +#include <gtest/gtest.h> + +namespace fs = KODI::PLATFORM::FILESYSTEM; + +using OptDef = std::pair<std::string, bool>; + +class OpticalMediaPathTest : public testing::WithParamInterface<OptDef>, public testing::Test +{ +}; + +TEST_P(OpticalMediaPathTest, GetOpticalMediaPath) +{ + std::error_code ec; + const std::string temp_path = fs::create_temp_directory(ec); + EXPECT_FALSE(ec); + const std::string file_path = URIUtils::AddFileToFolder(temp_path, GetParam().first); + EXPECT_TRUE(CUtil::CreateDirectoryEx(URIUtils::GetDirectory(file_path))); + { + std::ofstream of(file_path); + } + CFileItem item(temp_path, true); + if (GetParam().second) + EXPECT_EQ(VIDEO_UTILS::GetOpticalMediaPath(item), file_path); + else + EXPECT_EQ(VIDEO_UTILS::GetOpticalMediaPath(item), ""); + + XFILE::CDirectory::RemoveRecursive(temp_path); +} + +const auto mediapath_tests = std::array{ + OptDef{"VIDEO_TS.IFO", true}, OptDef{"VIDEO_TS/VIDEO_TS.IFO", true}, + OptDef{"some.file", false}, +#ifdef HAVE_LIBBLURAY + OptDef{"index.bdmv", true}, OptDef{"INDEX.BDM", true}, + OptDef{"BDMV/index.bdmv", true}, OptDef{"BDMV/INDEX.BDM", true}, +#endif +}; + +INSTANTIATE_TEST_SUITE_P(TestVideoUtils, OpticalMediaPathTest, testing::ValuesIn(mediapath_tests)); diff --git a/xbmc/video/windows/GUIWindowVideoBase.cpp b/xbmc/video/windows/GUIWindowVideoBase.cpp index 4b31a1c22f..13c1bd25d2 100644 --- a/xbmc/video/windows/GUIWindowVideoBase.cpp +++ b/xbmc/video/windows/GUIWindowVideoBase.cpp @@ -10,6 +10,7 @@ #include "Autorun.h" #include "ContextMenuManager.h" +#include "FileItemList.h" #include "GUIPassword.h" #include "GUIUserMessages.h" #include "PartyModeManager.h" @@ -53,6 +54,7 @@ #include "utils/log.h" #include "video/VideoDatabase.h" #include "video/VideoDbUrl.h" +#include "video/VideoFileItemClassify.h" #include "video/VideoInfoScanner.h" #include "video/VideoLibraryQueue.h" #include "video/VideoManagerTypes.h" @@ -73,6 +75,7 @@ using namespace VIDEO::GUILIB; using namespace ADDON; using namespace PVR; using namespace KODI::MESSAGING; +using namespace KODI::VIDEO; #define CONTROL_BTNVIEWASICONS 2 #define CONTROL_BTNSORTBY 3 @@ -223,13 +226,13 @@ bool CGUIWindowVideoBase::OnItemInfo(const CFileItem& fileItem) return false; // Movie set - if (fileItem.m_bIsFolder && fileItem.IsVideoDb() && + if (fileItem.m_bIsFolder && IsVideoDb(fileItem) && fileItem.GetPath() != "videodb://movies/sets/" && StringUtils::StartsWith(fileItem.GetPath(), "videodb://movies/sets/")) return ShowInfoAndRefresh(std::make_shared<CFileItem>(fileItem), nullptr); // Music video. Match visibility test of CMusicInfo::IsVisible - if (fileItem.IsVideoDb() && fileItem.HasVideoInfoTag() && + if (IsVideoDb(fileItem) && fileItem.HasVideoInfoTag() && (fileItem.HasProperty("artist_musicid") || fileItem.HasProperty("album_musicid"))) { CGUIDialogMusicInfo::ShowFor(std::make_shared<CFileItem>(fileItem).get()); @@ -237,7 +240,7 @@ bool CGUIWindowVideoBase::OnItemInfo(const CFileItem& fileItem) } std::string strDir; - if (fileItem.IsVideoDb() && fileItem.HasVideoInfoTag() && + if (IsVideoDb(fileItem) && fileItem.HasVideoInfoTag() && !fileItem.GetVideoInfoTag()->m_strPath.empty()) strDir = fileItem.GetVideoInfoTag()->m_strPath; else @@ -268,7 +271,7 @@ bool CGUIWindowVideoBase::OnItemInfo(const CFileItem& fileItem) return true; CFileItem item(fileItem); - if ((item.IsVideoDb() && item.HasVideoInfoTag()) || + if ((IsVideoDb(item) && item.HasVideoInfoTag()) || (item.HasVideoInfoTag() && item.GetVideoInfoTag()->m_iDbId != -1)) { if (item.GetVideoInfoTag()->m_type == MediaTypeSeason) @@ -286,7 +289,8 @@ bool CGUIWindowVideoBase::OnItemInfo(const CFileItem& fileItem) CDirectory::GetDirectory(item.GetPath(), items, fileExts, DIR_FLAG_DEFAULTS); // Check for cases 1_dir/1_dir/.../file (e.g. by packages where have a extra folder) - while (items.Size() == 1 && items[0]->m_bIsFolder && items[0]->GetOpticalMediaPath().empty()) + while (items.Size() == 1 && items[0]->m_bIsFolder && + VIDEO_UTILS::GetOpticalMediaPath(*items[0]).empty()) { const std::string path = items[0]->GetPath(); items.Clear(); @@ -302,7 +306,7 @@ bool CGUIWindowVideoBase::OnItemInfo(const CFileItem& fileItem) ->m_moviesExcludeFromScanRegExps; for (const auto& i : items) { - if (i->IsVideo() && !i->IsPlayList() && + if (IsVideo(*i) && !i->IsPlayList() && !CUtil::ExcludeFileOrFolder(i->GetPath(), excludeFromScan)) { item.SetPath(i->GetPath()); @@ -424,7 +428,7 @@ bool CGUIWindowVideoBase::ShowInfo(const CFileItemPtr& item2, const ScraperPtr& if (bHasInfo) { // @todo add support to refresh movie version information - if (!info || info->Content() == CONTENT_NONE || VIDEO::IsVideoAssetFile(*item)) + if (!info || info->Content() == CONTENT_NONE || IsVideoAssetFile(*item)) item->SetProperty("xxuniqueid", "xx" + movieDetails.GetUniqueID()); // disable refresh button item->SetProperty("CheckAutoPlayNextItem", IsActive()); *item->GetVideoInfoTag() = movieDetails; @@ -440,8 +444,14 @@ bool CGUIWindowVideoBase::ShowInfo(const CFileItemPtr& item2, const ScraperPtr& { item = pDlgInfo->GetCurrentListItem(); - if (item->IsVideoDb() && item->HasVideoInfoTag()) + if (IsVideoDb(*item) && item->HasVideoInfoTag()) item->SetPath(item->GetVideoInfoTag()->GetPath()); + else if (!IsVideoDb(*item) && item->m_bIsFolder) + { + // Info on folder containing a movie needs dyn path as path for refresh with correct name + //! @todo get rid of "videos with versions as folder" hack to be able to fix in CFileItem::GetBaseMoviePath() + item->SetPath(item->GetVideoInfoTag()->GetPath()); + } } } @@ -485,7 +495,7 @@ bool CGUIWindowVideoBase::ShowInfo(const CFileItemPtr& item2, const ScraperPtr& { item = pDlgInfo->GetCurrentListItem(); - if (item->IsVideoDb() && item->HasVideoInfoTag()) + if (IsVideoDb(*item) && item->HasVideoInfoTag()) item->SetPath(item->GetVideoInfoTag()->GetPath()); } listNeedsUpdating = true; @@ -732,7 +742,7 @@ void CGUIWindowVideoBase::LoadVideoInfo(CFileItemList& items, } // set the watched overlay - if (pItem->IsVideo()) + if (IsVideo(*pItem)) pItem->SetOverlayImage(pItem->HasVideoInfoTag() && pItem->GetVideoInfoTag()->GetPlayCount() > 0 ? CGUIListItem::ICON_OVERLAY_WATCHED @@ -793,7 +803,7 @@ void CGUIWindowVideoBase::GetContextButtons(int itemNumber, CContextButtons &but if (!item->IsParentFolder()) { std::string path(item->GetPath()); - if (item->IsVideoDb() && item->HasVideoInfoTag()) + if (IsVideoDb(*item) && item->HasVideoInfoTag()) path = item->GetVideoInfoTag()->m_strFileNameAndPath; if (!item->IsPath("add") && !item->IsPlugin() && @@ -904,13 +914,13 @@ bool CGUIWindowVideoBase::OnContextButton(int itemNumber, CONTEXT_BUTTON button) if (!item) return false; - if (item->IsVideoDb() && (!item->m_bIsFolder || item->GetVideoInfoTag()->m_strPath.empty())) + if (IsVideoDb(*item) && (!item->m_bIsFolder || item->GetVideoInfoTag()->m_strPath.empty())) return false; if (item->m_bIsFolder) { const std::string strPath = - item->IsVideoDb() ? item->GetVideoInfoTag()->m_strPath : item->GetPath(); + IsVideoDb(*item) ? item->GetVideoInfoTag()->m_strPath : item->GetPath(); OnScan(strPath, true); } else @@ -960,7 +970,7 @@ bool CGUIWindowVideoBase::OnPlayMedia(const std::shared_ptr<CFileItem>& pItem, auto itemCopy = std::make_shared<CFileItem>(*pItem); - if (pItem->IsVideoDb()) + if (IsVideoDb(*pItem)) { itemCopy->SetPath(pItem->GetVideoInfoTag()->m_strFileNameAndPath); itemCopy->SetProperty("original_listitem_url", pItem->GetPath()); @@ -1073,7 +1083,7 @@ void CGUIWindowVideoBase::LoadPlayList(const std::string& strPlayList, bool CGUIWindowVideoBase::PlayItem(const std::shared_ptr<CFileItem>& pItem, const std::string& player) { - if (!pItem->m_bIsFolder && pItem->IsVideoDb() && !pItem->Exists()) + if (!pItem->m_bIsFolder && IsVideoDb(*pItem) && !pItem->Exists()) { CLog::LogF(LOGDEBUG, "File '{}' for library item '{}' doesn't exist.", pItem->GetDynPath(), pItem->GetPath()); @@ -1209,9 +1219,8 @@ bool CGUIWindowVideoBase::GetDirectory(const std::string &strDirectory, CFileIte bool CGUIWindowVideoBase::StackingAvailable(const CFileItemList &items) { CURL url(items.GetPath()); - return !(items.IsPlugin() || items.IsAddonsPath() || - items.IsRSS() || items.IsInternetStream() || - items.IsVideoDb() || url.IsProtocol("playlistvideo")); + return !(items.IsPlugin() || items.IsAddonsPath() || items.IsRSS() || items.IsInternetStream() || + IsVideoDb(items) || url.IsProtocol("playlistvideo")); } void CGUIWindowVideoBase::GetGroupedItems(CFileItemList &items) @@ -1258,9 +1267,9 @@ void CGUIWindowVideoBase::GetGroupedItems(CFileItemList &items) bool CGUIWindowVideoBase::CheckFilterAdvanced(CFileItemList &items) const { const std::string& content = items.GetContent(); - if ((items.IsVideoDb() || CanContainFilter(m_strFilterPath)) && - (StringUtils::EqualsNoCase(content, "movies") || - StringUtils::EqualsNoCase(content, "tvshows") || + if ((IsVideoDb(items) || CanContainFilter(m_strFilterPath)) && + (StringUtils::EqualsNoCase(content, "movies") || + StringUtils::EqualsNoCase(content, "tvshows") || StringUtils::EqualsNoCase(content, "episodes") || StringUtils::EqualsNoCase(content, "musicvideos"))) return true; @@ -1334,7 +1343,8 @@ void CGUIWindowVideoBase::OnSearchItemFound(const CFileItem* pSelItem) Update(strParentPath); - if (pSelItem->IsVideoDb() && CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_MYVIDEOS_FLATTEN)) + if (IsVideoDb(*pSelItem) && CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool( + CSettings::SETTING_MYVIDEOS_FLATTEN)) SetHistoryForPath(""); else SetHistoryForPath(strParentPath); @@ -1360,7 +1370,8 @@ void CGUIWindowVideoBase::OnSearchItemFound(const CFileItem* pSelItem) Update(strPath); - if (pSelItem->IsVideoDb() && CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_MYVIDEOS_FLATTEN)) + if (IsVideoDb(*pSelItem) && CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool( + CSettings::SETTING_MYVIDEOS_FLATTEN)) SetHistoryForPath(""); else SetHistoryForPath(strPath); @@ -1369,7 +1380,7 @@ void CGUIWindowVideoBase::OnSearchItemFound(const CFileItem* pSelItem) { CFileItemPtr pItem = m_vecItems->Get(i); CURL url(pItem->GetPath()); - if (pSelItem->IsVideoDb()) + if (IsVideoDb(*pSelItem)) url.SetOptions(""); if (url.Get() == pSelItem->GetPath()) { @@ -1511,7 +1522,7 @@ void CGUIWindowVideoBase::UpdateVideoVersionItems() //! not for example for home screen widgets! int videoVersionId{-1}; - if (item->IsVideoDb() && item->GetVideoInfoTag()->HasVideoVersions()) + if (IsVideoDb(*item) && item->GetVideoInfoTag()->HasVideoVersions()) { if (item->GetProperty("has_resolved_video_asset").asBoolean(false)) { diff --git a/xbmc/video/windows/GUIWindowVideoNav.cpp b/xbmc/video/windows/GUIWindowVideoNav.cpp index 86ab1d96eb..69b81a760a 100644 --- a/xbmc/video/windows/GUIWindowVideoNav.cpp +++ b/xbmc/video/windows/GUIWindowVideoNav.cpp @@ -9,6 +9,7 @@ #include "GUIWindowVideoNav.h" #include "FileItem.h" +#include "FileItemList.h" #include "GUIPassword.h" #include "PartyModeManager.h" #include "ServiceBroker.h" @@ -39,6 +40,7 @@ #include "utils/Variant.h" #include "utils/log.h" #include "video/VideoDbUrl.h" +#include "video/VideoFileItemClassify.h" #include "video/VideoInfoScanner.h" #include "video/VideoLibraryQueue.h" #include "video/dialogs/GUIDialogVideoInfo.h" @@ -49,6 +51,7 @@ using namespace XFILE; using namespace VIDEODATABASEDIRECTORY; using namespace KODI::MESSAGING; +using namespace KODI::VIDEO; #define CONTROL_BTNVIEWASICONS 2 #define CONTROL_BTNSORTBY 3 @@ -152,7 +155,7 @@ bool CGUIWindowVideoNav::OnMessage(CGUIMessage& message) // We are here if the item is filtered out in the nav window const std::string& path = message.GetStringParam(0); CFileItem item(path, URIUtils::HasSlashAtEnd(path)); - if (item.IsVideoDb()) + if (IsVideoDb(item)) { *(item.GetVideoInfoTag()) = XFILE::CVideoDatabaseFile::GetVideoTag(CURL(item.GetPath())); if (!item.GetVideoInfoTag()->IsEmpty()) @@ -242,7 +245,7 @@ bool CGUIWindowVideoNav::OnMessage(CGUIMessage& message) SelectFirstUnwatchedItem CGUIWindowVideoNav::GetSettingSelectFirstUnwatchedItem() { - if (m_vecItems->IsVideoDb()) + if (IsVideoDb(*m_vecItems)) { NODE_TYPE nodeType = CVideoDatabaseDirectory::GetDirectoryChildType(m_vecItems->GetPath()); @@ -358,7 +361,7 @@ bool CGUIWindowVideoNav::GetDirectory(const std::string &strDirectory, CFileItem bool bResult = CGUIWindowVideoBase::GetDirectory(strDirectory, items); if (bResult) { - if (items.IsVideoDb()) + if (IsVideoDb(items)) { XFILE::CVideoDatabaseDirectory dir; CQueryParams params; @@ -546,7 +549,7 @@ void CGUIWindowVideoNav::UpdateButtons() else if (m_vecItems->IsPath("sources://video/")) strLabel = g_localizeStrings.Get(744); // everything else is from a videodb:// path - else if (m_vecItems->IsVideoDb()) + else if (IsVideoDb(*m_vecItems)) { CVideoDatabaseDirectory dir; dir.GetLabel(m_vecItems->GetPath(), strLabel); @@ -671,7 +674,7 @@ void CGUIWindowVideoNav::OnDeleteItem(const CFileItemPtr& pItem) if (m_vecItems->IsParentFolder()) return; - if (!m_vecItems->IsVideoDb() && !pItem->IsVideoDb()) + if (!IsVideoDb(*m_vecItems) && !IsVideoDb(*pItem)) { if (!pItem->IsPath("newsmartplaylist://video") && !pItem->IsPath("special://videoplaylists/") && !pItem->IsPath("sources://video/") && !URIUtils::IsProtocol(pItem->GetPath(), "newtag")) @@ -798,7 +801,7 @@ void CGUIWindowVideoNav::GetContextButtons(int itemNumber, CContextButtons &butt // can we update the database? if (profileManager->GetCurrentProfile().canWriteDatabases() || g_passwordManager.bMasterUser) { - if (!CVideoLibraryQueue::GetInstance().IsScanningLibrary() && item->IsVideoDb() && + if (!CVideoLibraryQueue::GetInstance().IsScanningLibrary() && IsVideoDb(*item) && item->HasVideoInfoTag() && (item->GetVideoInfoTag()->m_type == MediaTypeMovie || // movies item->GetVideoInfoTag()->m_type == MediaTypeTvShow || // tvshows @@ -824,7 +827,7 @@ void CGUIWindowVideoNav::GetContextButtons(int itemNumber, CContextButtons &butt } } - if (!m_vecItems->IsVideoDb() && !m_vecItems->IsVirtualDirectoryRoot()) + if (!IsVideoDb(*m_vecItems) && !m_vecItems->IsVirtualDirectoryRoot()) { // non-video db items, file operations are allowed if ((CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_FILELISTS_ALLOWFILEDELETION) && CUtil::SupportsWriteFileOperations(item->GetPath())) || @@ -835,7 +838,9 @@ void CGUIWindowVideoNav::GetContextButtons(int itemNumber, CContextButtons &butt buttons.Add(CONTEXT_BUTTON_RENAME, 118); } // add "Set/Change content" to folders - if (item->m_bIsFolder && !item->IsVideoDb() && !item->IsPlayList() && !item->IsSmartPlayList() && !item->IsLibraryFolder() && !item->IsLiveTV() && !item->IsPlugin() && !item->IsAddonsPath() && !URIUtils::IsUPnP(item->GetPath())) + if (item->m_bIsFolder && !IsVideoDb(*item) && !item->IsPlayList() && + !item->IsSmartPlayList() && !item->IsLibraryFolder() && !item->IsLiveTV() && + !item->IsPlugin() && !item->IsAddonsPath() && !URIUtils::IsUPnP(item->GetPath())) { if (info && info->Content() != CONTENT_NONE) buttons.Add(CONTEXT_BUTTON_SET_CONTENT, 20442); @@ -1079,7 +1084,7 @@ bool CGUIWindowVideoNav::ApplyWatchedFilter(CFileItemList &items) || node == NODE_TYPE_RECENTLY_ADDED_MOVIES || node == NODE_TYPE_RECENTLY_ADDED_MUSICVIDEOS) filterWatched = true; - if (!items.IsVideoDb()) + if (!IsVideoDb(items)) filterWatched = true; if (items.GetContent() == "tvshows" && (items.IsSmartPlayList() || items.IsLibraryFolder())) diff --git a/xbmc/video/windows/GUIWindowVideoPlaylist.cpp b/xbmc/video/windows/GUIWindowVideoPlaylist.cpp index 3569a0c5ea..bb381a9dbc 100644 --- a/xbmc/video/windows/GUIWindowVideoPlaylist.cpp +++ b/xbmc/video/windows/GUIWindowVideoPlaylist.cpp @@ -8,6 +8,7 @@ #include "GUIWindowVideoPlaylist.h" +#include "FileItemList.h" #include "GUIUserMessages.h" #include "PartyModeManager.h" #include "PlayListPlayer.h" @@ -30,6 +31,7 @@ #include "utils/URIUtils.h" #include "utils/Variant.h" #include "utils/log.h" +#include "video/VideoFileItemClassify.h" #include "video/guilib/VideoPlayActionProcessor.h" #define CONTROL_BTNVIEWASICONS 2 @@ -46,6 +48,7 @@ #define CONTROL_BTNPREVIOUS 25 #define CONTROL_BTNREPEAT 26 +using namespace KODI::VIDEO; using namespace VIDEO::GUILIB; CGUIWindowVideoPlaylist::CGUIWindowVideoPlaylist() @@ -63,7 +66,7 @@ void CGUIWindowVideoPlaylist::OnPrepareFileItems(CFileItemList& items) if (items.IsEmpty()) return; - if (!items.IsVideoDb() && !items.IsVirtualDirectoryRoot()) + if (!IsVideoDb(items) && !items.IsVirtualDirectoryRoot()) { // load info from the database std::string label; if (items.GetLabel().empty() && diff --git a/xbmc/video/windows/VideoFileItemListModifier.cpp b/xbmc/video/windows/VideoFileItemListModifier.cpp index b17a71db87..2f5c222c62 100644 --- a/xbmc/video/windows/VideoFileItemListModifier.cpp +++ b/xbmc/video/windows/VideoFileItemListModifier.cpp @@ -9,6 +9,7 @@ #include "VideoFileItemListModifier.h" #include "FileItem.h" +#include "FileItemList.h" #include "ServiceBroker.h" #include "filesystem/VideoDatabaseDirectory/DirectoryNode.h" #include "guilib/LocalizeStrings.h" @@ -17,14 +18,16 @@ #include "settings/SettingsComponent.h" #include "video/VideoDatabase.h" #include "video/VideoDbUrl.h" +#include "video/VideoFileItemClassify.h" #include <memory> +using namespace KODI::VIDEO; using namespace XFILE::VIDEODATABASEDIRECTORY; bool CVideoFileItemListModifier::CanModify(const CFileItemList &items) const { - if (items.IsVideoDb()) + if (IsVideoDb(items)) return true; return false; @@ -40,7 +43,7 @@ bool CVideoFileItemListModifier::Modify(CFileItemList &items) const // depending on the child node void CVideoFileItemListModifier::AddQueuingFolder(CFileItemList& items) { - if (!items.IsVideoDb()) + if (!IsVideoDb(items)) return; auto directoryNode = CDirectoryNode::ParseURL(items.GetPath()); diff --git a/xbmc/view/GUIViewControl.cpp b/xbmc/view/GUIViewControl.cpp index 3d4801b693..6ce4516b52 100644 --- a/xbmc/view/GUIViewControl.cpp +++ b/xbmc/view/GUIViewControl.cpp @@ -9,6 +9,7 @@ #include "GUIViewControl.h" #include "FileItem.h" +#include "FileItemList.h" #include "GUIInfoManager.h" #include "ServiceBroker.h" #include "guilib/GUIComponent.h" diff --git a/xbmc/view/GUIViewState.cpp b/xbmc/view/GUIViewState.cpp index e0cf9d2aca..89c234a709 100644 --- a/xbmc/view/GUIViewState.cpp +++ b/xbmc/view/GUIViewState.cpp @@ -10,6 +10,7 @@ #include "AutoSwitch.h" #include "FileItem.h" +#include "FileItemList.h" #include "GUIPassword.h" #include "PlayListPlayer.h" #include "ServiceBroker.h" diff --git a/xbmc/windowing/android/AndroidUtils.cpp b/xbmc/windowing/android/AndroidUtils.cpp index 6b3cdf8568..1396e581a1 100644 --- a/xbmc/windowing/android/AndroidUtils.cpp +++ b/xbmc/windowing/android/AndroidUtils.cpp @@ -20,52 +20,14 @@ #include <androidjni/MediaCodecInfo.h> #include <androidjni/MediaCodecList.h> -#include <androidjni/System.h> -#include <androidjni/SystemProperties.h> #include <androidjni/View.h> #include <androidjni/Window.h> -#include <androidjni/WindowManager.h> -static bool s_hasModeApi = false; static std::vector<RESOLUTION_INFO> s_res_displayModes; static RESOLUTION_INFO s_res_cur_displayMode; -static float currentRefreshRate() -{ - if (s_hasModeApi) - return s_res_cur_displayMode.fRefreshRate; - - CJNIWindow window = CXBMCApp::getWindow(); - if (window) - { - float preferredRate = window.getAttributes().getpreferredRefreshRate(); - if (preferredRate > 20.0f) - { - CLog::Log(LOGINFO, "CAndroidUtils: Preferred refresh rate: {:f}", preferredRate); - return preferredRate; - } - CJNIView view(window.getDecorView()); - if (view) - { - CJNIDisplay display(view.getDisplay()); - if (display) - { - float reportedRate = display.getRefreshRate(); - if (reportedRate > 20.0f) - { - CLog::Log(LOGINFO, "CAndroidUtils: Current display refresh rate: {:f}", reportedRate); - return reportedRate; - } - } - } - } - CLog::Log(LOGDEBUG, "found no refresh rate"); - return 60.0; -} - static void fetchDisplayModes() { - s_hasModeApi = false; s_res_displayModes.clear(); CJNIDisplay display = CXBMCApp::getWindow().getDecorView().getDisplay(); @@ -77,8 +39,6 @@ static void fetchDisplayModes() { if (m.getPhysicalWidth() > m.getPhysicalHeight()) // Assume unusable if portrait is returned { - s_hasModeApi = true; - CLog::Log(LOGDEBUG, "CAndroidUtils: current mode: {}: {}x{}@{:f}", m.getModeId(), m.getPhysicalWidth(), m.getPhysicalHeight(), m.getRefreshRate()); s_res_cur_displayMode.strId = std::to_string(m.getModeId()); @@ -142,35 +102,15 @@ const std::string CAndroidUtils::SETTING_LIMITGUI = "videoscreen.limitgui"; CAndroidUtils::CAndroidUtils() { - std::string displaySize; m_width = m_height = 0; - if (CJNIBase::GetSDKVersion() >= 23) - { - fetchDisplayModes(); - for (const RESOLUTION_INFO& res : s_res_displayModes) - { - if (res.iWidth > m_width || res.iHeight > m_height) - { - m_width = res.iWidth; - m_height = res.iHeight; - } - } - } - - if (!m_width || !m_height) + fetchDisplayModes(); + for (const RESOLUTION_INFO& res : s_res_displayModes) { - // Property available on some devices - displaySize = CJNISystemProperties::get("sys.display-size", ""); - if (!displaySize.empty()) + if (res.iWidth > m_width || res.iHeight > m_height) { - std::vector<std::string> aSize = StringUtils::Split(displaySize, "x"); - if (aSize.size() == 2) - { - m_width = StringUtils::IsInteger(aSize[0]) ? atoi(aSize[0].c_str()) : 0; - m_height = StringUtils::IsInteger(aSize[1]) ? atoi(aSize[1].c_str()) : 0; - } - CLog::Log(LOGDEBUG, "CAndroidUtils: display-size: {}({}x{})", displaySize, m_width, m_height); + m_width = res.iWidth; + m_height = res.iHeight; } } @@ -224,24 +164,9 @@ bool CAndroidUtils::GetNativeResolution(RESOLUTION_INFO* res) const CLog::Log(LOGINFO, "CAndroidUtils: window resolution: {}x{}", m_width, m_height); } - if (s_hasModeApi) - { - *res = s_res_cur_displayMode; - res->iWidth = m_width; - res->iHeight = m_height; - } - else - { - res->strId = "-1"; - res->fRefreshRate = currentRefreshRate(); - res->dwFlags = D3DPRESENTFLAG_PROGRESSIVE; - res->bFullScreen = true; - res->iWidth = m_width; - res->iHeight = m_height; - res->fPixelRatio = 1.0f; - res->iScreenWidth = res->iWidth; - res->iScreenHeight = res->iHeight; - } + *res = s_res_cur_displayMode; + res->iWidth = m_width; + res->iHeight = m_height; res->iSubtitles = res->iHeight; res->strMode = StringUtils::Format("{}x{} @ {:.6f}{} - Full Screen", res->iScreenWidth, res->iScreenHeight, @@ -256,14 +181,8 @@ bool CAndroidUtils::SetNativeResolution(const RESOLUTION_INFO& res) CLog::Log(LOGINFO, "CAndroidUtils: SetNativeResolution: {}: {}x{} {}x{}@{:f}", res.strId, res.iWidth, res.iHeight, res.iScreenWidth, res.iScreenHeight, res.fRefreshRate); - if (s_hasModeApi) - { - CXBMCApp::Get().SetDisplayMode(std::atoi(res.strId.c_str()), res.fRefreshRate); - s_res_cur_displayMode = res; - } - else - CXBMCApp::Get().SetRefreshRate(res.fRefreshRate); - + CXBMCApp::Get().SetDisplayMode(std::atoi(res.strId.c_str()), res.fRefreshRate); + s_res_cur_displayMode = res; CXBMCApp::Get().SetBuffersGeometry(res.iWidth, res.iHeight, 0); return true; @@ -272,69 +191,26 @@ bool CAndroidUtils::SetNativeResolution(const RESOLUTION_INFO& res) bool CAndroidUtils::ProbeResolutions(std::vector<RESOLUTION_INFO>& resolutions) { RESOLUTION_INFO cur_res; - bool ret = GetNativeResolution(&cur_res); + GetNativeResolution(&cur_res); CLog::Log(LOGDEBUG, "CAndroidUtils: ProbeResolutions: {}x{}", m_width, m_height); - if (s_hasModeApi) - { - for (RESOLUTION_INFO res : s_res_displayModes) - { - if (m_width && m_height) - { - res.iWidth = std::min(res.iWidth, m_width); - res.iHeight = std::min(res.iHeight, m_height); - res.iSubtitles = res.iHeight; - } - resolutions.push_back(res); - } - return true; - } - - if (ret && cur_res.iWidth > 1 && cur_res.iHeight > 1) + for (RESOLUTION_INFO res : s_res_displayModes) { - std::vector<float> refreshRates; - CJNIWindow window = CXBMCApp::getWindow(); - if (window) - { - CJNIView view = window.getDecorView(); - if (view) - { - CJNIDisplay display = view.getDisplay(); - if (display) - { - refreshRates = display.getSupportedRefreshRates(); - } - } - - if (!refreshRates.empty()) - { - for (unsigned int i = 0; i < refreshRates.size(); i++) - { - if (refreshRates[i] < 20.0f) - continue; - cur_res.fRefreshRate = refreshRates[i]; - cur_res.strMode = StringUtils::Format( - "{}x{} @ {:.6f}{} - Full Screen", cur_res.iScreenWidth, cur_res.iScreenHeight, - cur_res.fRefreshRate, cur_res.dwFlags & D3DPRESENTFLAG_INTERLACED ? "i" : ""); - resolutions.push_back(cur_res); - } - } - } - if (resolutions.empty()) + if (m_width && m_height) { - /* No valid refresh rates available, just provide the current one */ - resolutions.push_back(cur_res); + res.iWidth = std::min(res.iWidth, m_width); + res.iHeight = std::min(res.iHeight, m_height); + res.iSubtitles = res.iHeight; } - return true; + resolutions.push_back(res); } - return false; + return true; } bool CAndroidUtils::UpdateDisplayModes() { - if (CJNIBase::GetSDKVersion() >= 23) - fetchDisplayModes(); + fetchDisplayModes(); return true; } diff --git a/xbmc/windowing/gbm/WinSystemGbm.cpp b/xbmc/windowing/gbm/WinSystemGbm.cpp index 6569718b3d..72497a2156 100644 --- a/xbmc/windowing/gbm/WinSystemGbm.cpp +++ b/xbmc/windowing/gbm/WinSystemGbm.cpp @@ -401,7 +401,7 @@ bool CWinSystemGbm::SetHDR(const VideoPicture* videoPicture) m_hdr_blob_id = 0; } - return true; + return false; } KODI::UTILS::Colorimetry colorimetry = DRMPRIME::GetColorimetry(*videoPicture); @@ -501,7 +501,7 @@ bool CWinSystemGbm::SetHDR(const VideoPicture* videoPicture) drm->SetActive(true); } - return true; + return m_hdr_blob_id != 0; } bool CWinSystemGbm::IsHDRDisplay() diff --git a/xbmc/windowing/osx/OpenGL/OSXGLView.h b/xbmc/windowing/osx/OpenGL/OSXGLView.h index 54a85a232f..016e102e78 100644 --- a/xbmc/windowing/osx/OpenGL/OSXGLView.h +++ b/xbmc/windowing/osx/OpenGL/OSXGLView.h @@ -16,12 +16,6 @@ - (CGLContextObj)getGLContextObj; /** - * @brief Application renders out of the NSOpenGLView drawRect (on a different thread). Hence the current - * NSOpenGLContext needs to be make current so that the view on the context is valid for rendering. - * This should be done whenever gl calls are about to be done. - */ -- (void)NotifyContext; -/** * @brief Update the current OpenGL context (view is set before updating) */ - (void)Update; @@ -30,9 +24,4 @@ */ - (void)FlushBuffer; -/** - * @brief Specifies if the glContext is currently owned by the view - */ -@property(atomic, assign) BOOL glContextOwned; - @end diff --git a/xbmc/windowing/osx/OpenGL/OSXGLView.mm b/xbmc/windowing/osx/OpenGL/OSXGLView.mm index 195ea0d889..857174838a 100644 --- a/xbmc/windowing/osx/OpenGL/OSXGLView.mm +++ b/xbmc/windowing/osx/OpenGL/OSXGLView.mm @@ -20,8 +20,6 @@ NSTrackingArea* m_trackingArea; } -@synthesize glContextOwned; - - (void)SendInputEvent:(NSEvent*)nsEvent { CWinSystemOSX* winSystem = dynamic_cast<CWinSystemOSX*>(CServiceBroker::GetWinSystem()); @@ -88,14 +86,6 @@ - (void)drawRect:(NSRect)rect { - // whenever the view/window is resized the glContext is made current to the main (rendering) thread. - // Since kodi does its rendering on the application main thread (not the macOS rendering thread), we - // need to store this so that on a subsquent frame render we get the ownership of the gl context again. - // doing this blindly without any sort of control may stall the main thread and lead to low GUI fps - // since the glContext ownership needs to be obtained from the rendering thread (diverged from the actual - // thread doing the rendering calls). - [self setGlContextOwned:TRUE]; - static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ [self setOpenGLContext:m_glcontext]; @@ -215,17 +205,8 @@ - (void)Update { assert(m_glcontext); - [self NotifyContext]; - [m_glcontext update]; -} - -- (void)NotifyContext -{ - assert(m_glcontext); - // signals/notifies the context that this view is current (required if we render out of DrawRect) - // ownership of the context is transferred to the callee thread [m_glcontext makeCurrentContext]; - [self setGlContextOwned:FALSE]; + [m_glcontext update]; } - (void)FlushBuffer diff --git a/xbmc/windowing/osx/OpenGL/WindowControllerMacOS.mm b/xbmc/windowing/osx/OpenGL/WindowControllerMacOS.mm index 5bfb6b0d22..4f50a49dbc 100644 --- a/xbmc/windowing/osx/OpenGL/WindowControllerMacOS.mm +++ b/xbmc/windowing/osx/OpenGL/WindowControllerMacOS.mm @@ -22,6 +22,8 @@ @implementation XBMCWindowControllerMacOS +bool m_inFullscreenTransition = false; + - (nullable instancetype)initWithTitle:(NSString*)title defaultSize:(NSSize)size { auto frame = NSMakeRect(0, 0, size.width, size.height); @@ -77,6 +79,30 @@ } } +- (void)windowWillStartLiveResize:(NSNotification*)notification +{ + if (m_inFullscreenTransition) + return; + + std::shared_ptr<CAppInboundProtocol> appPort = CServiceBroker::GetAppPort(); + if (appPort) + { + appPort->SetRenderGUI(false); + } +} + +- (void)windowDidEndLiveResize:(NSNotification*)notification +{ + if (m_inFullscreenTransition) + return; + + std::shared_ptr<CAppInboundProtocol> appPort = CServiceBroker::GetAppPort(); + if (appPort) + { + appPort->SetRenderGUI(true); + } +} + - (void)windowDidMiniaturize:(NSNotification*)aNotification { g_application.m_AppFocused = false; @@ -170,8 +196,14 @@ return frameSize; } +- (void)windowWillExitFullScreen:(NSNotification*)notification +{ + m_inFullscreenTransition = true; +} + - (void)windowWillEnterFullScreen:(NSNotification*)pNotification { + m_inFullscreenTransition = true; CWinSystemOSX* winSystem = dynamic_cast<CWinSystemOSX*>(CServiceBroker::GetWinSystem()); if (!winSystem) return; @@ -209,6 +241,7 @@ - (void)windowDidExitFullScreen:(NSNotification*)pNotification { + m_inFullscreenTransition = false; auto winSystem = dynamic_cast<CWinSystemOSX*>(CServiceBroker::GetWinSystem()); if (!winSystem) return; @@ -235,6 +268,7 @@ - (void)windowDidEnterFullScreen:(NSNotification*)notification { + m_inFullscreenTransition = false; auto winSystem = dynamic_cast<CWinSystemOSX*>(CServiceBroker::GetWinSystem()); if (!winSystem) return; diff --git a/xbmc/windowing/osx/WinSystemOSX.h b/xbmc/windowing/osx/WinSystemOSX.h index c431d70cd9..899e52486b 100644 --- a/xbmc/windowing/osx/WinSystemOSX.h +++ b/xbmc/windowing/osx/WinSystemOSX.h @@ -71,7 +71,6 @@ public: void MoveToScreen(unsigned int screenIdx) override; void OnMove(int x, int y) override; void OnChangeScreen(unsigned int screenIdx) override; - CGraphicContext& GetGfxContext() const override; bool HasValidResolution() const; std::string GetClipboardText() override; diff --git a/xbmc/windowing/osx/WinSystemOSX.mm b/xbmc/windowing/osx/WinSystemOSX.mm index 04a0670a17..007fc14be3 100644 --- a/xbmc/windowing/osx/WinSystemOSX.mm +++ b/xbmc/windowing/osx/WinSystemOSX.mm @@ -1304,18 +1304,6 @@ CGLContextObj CWinSystemOSX::GetCGLContextObj() return cglcontex; } -CGraphicContext& CWinSystemOSX::GetGfxContext() const -{ - if (m_glView && [m_glView glContextOwned]) - { - dispatch_sync(dispatch_get_main_queue(), ^{ - [m_glView NotifyContext]; - }); - } - - return CWinSystemBase::GetGfxContext(); -} - bool CWinSystemOSX::FlushBuffer() { if (m_appWindow) diff --git a/xbmc/windowing/wayland/CMakeLists.txt b/xbmc/windowing/wayland/CMakeLists.txt index d29b97c685..c406de112f 100644 --- a/xbmc/windowing/wayland/CMakeLists.txt +++ b/xbmc/windowing/wayland/CMakeLists.txt @@ -68,10 +68,12 @@ if(TARGET_WEBOS) PROPERTIES GENERATED TRUE) list(APPEND SOURCES OSScreenSaverWebOS.cpp + SeatWebOS.cpp ShellSurfaceWebOSShell.cpp WinSystemWaylandWebOS.cpp ${WAYLAND_EXTRA_PROTOCOL_GENERATED_DIR}/wayland-webos-protocols.cpp) list(APPEND HEADERS OSScreenSaverWebOS.h + SeatWebOS.h ShellSurfaceWebOSShell.h WinSystemWaylandWebOS.h ${WAYLAND_EXTRA_PROTOCOL_GENERATED_DIR}/wayland-webos-protocols.hpp) diff --git a/xbmc/windowing/wayland/Seat.cpp b/xbmc/windowing/wayland/Seat.cpp index de22f1e218..770c274ed6 100644 --- a/xbmc/windowing/wayland/Seat.cpp +++ b/xbmc/windowing/wayland/Seat.cpp @@ -136,10 +136,7 @@ void CSeat::SetCursor(std::uint32_t serial, wayland::surface_t const &surface, s { if (m_pointer) { - // set_cursor on webOS completely breaks pointer input -#ifndef TARGET_WEBOS m_pointer.set_cursor(serial, surface, hotspotX, hotspotY); -#endif } } @@ -182,6 +179,11 @@ void CSeat::HandleKeyboardCapability() handler->OnKeyboardModifiers(this, serial, modsDepressed, modsLatched, modsLocked, group); } }; + InstallKeyboardRepeatInfo(); +} + +void CSeat::InstallKeyboardRepeatInfo() +{ m_keyboard.on_repeat_info() = [this](std::int32_t rate, std::int32_t delay) { for (auto handler : m_rawKeyboardHandlers) @@ -191,7 +193,6 @@ void CSeat::HandleKeyboardCapability() }; } - void CSeat::HandlePointerCapability() { m_pointer.on_enter() = [this](std::uint32_t serial, const wayland::surface_t& surface, diff --git a/xbmc/windowing/wayland/Seat.h b/xbmc/windowing/wayland/Seat.h index 095f18dd89..edaf8e4df4 100644 --- a/xbmc/windowing/wayland/Seat.h +++ b/xbmc/windowing/wayland/Seat.h @@ -121,7 +121,7 @@ public: * \param connection connection for retrieving additional globals */ CSeat(std::uint32_t globalName, wayland::seat_t const& seat, CConnection& connection); - ~CSeat() noexcept; + virtual ~CSeat() noexcept; void AddRawInputHandlerKeyboard(IRawInputHandlerKeyboard* rawKeyboardHandler); void RemoveRawInputHandlerKeyboard(IRawInputHandlerKeyboard* rawKeyboardHandler); @@ -172,7 +172,13 @@ public: * Parameters are identical wo wl_pointer.set_cursor(). * If the seat does not currently have the pointer capability, this is a no-op. */ - void SetCursor(std::uint32_t serial, wayland::surface_t const& surface, std::int32_t hotspotX, std::int32_t hotspotY); + virtual void SetCursor(std::uint32_t serial, + wayland::surface_t const& surface, + std::int32_t hotspotX, + std::int32_t hotspotY); + +protected: + virtual void InstallKeyboardRepeatInfo(); private: CSeat(CSeat const& other) = delete; diff --git a/xbmc/windowing/wayland/SeatWebOS.cpp b/xbmc/windowing/wayland/SeatWebOS.cpp new file mode 100644 index 0000000000..29eb0117ad --- /dev/null +++ b/xbmc/windowing/wayland/SeatWebOS.cpp @@ -0,0 +1,29 @@ +/* +* Copyright (C) 2024 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 "SeatWebOS.h" + +namespace KODI::WINDOWING::WAYLAND +{ + +void CSeatWebOS::SetCursor(std::uint32_t serial, + wayland::surface_t const& surface, + std::int32_t hotspotX, + std::int32_t hotspotY) +{ + // set_cursor on webOS completely breaks pointer input +} + +void CSeatWebOS::InstallKeyboardRepeatInfo() +{ + // Since webOS 7 the compositor sends the following key repeat info: + // Key repeat rate: 40 cps, delay 400 ms + // Which is too fast for the long press detection +} + +} // namespace KODI::WINDOWING::WAYLAND diff --git a/xbmc/windowing/wayland/SeatWebOS.h b/xbmc/windowing/wayland/SeatWebOS.h new file mode 100644 index 0000000000..45bf155f6c --- /dev/null +++ b/xbmc/windowing/wayland/SeatWebOS.h @@ -0,0 +1,33 @@ +/* +* Copyright (C) 2024 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 + +#include "Seat.h" + +namespace KODI::WINDOWING::WAYLAND +{ + +class CSeatWebOS final : public CSeat +{ +public: + CSeatWebOS(std::uint32_t globalName, wayland::seat_t const& seat, CConnection& connection) + : CSeat(globalName, seat, connection) + { + } + + void SetCursor(std::uint32_t serial, + wayland::surface_t const& surface, + std::int32_t hotspotX, + std::int32_t hotspotY) override; + +protected: + void InstallKeyboardRepeatInfo() override; +}; + +} // namespace KODI::WINDOWING::WAYLAND diff --git a/xbmc/windowing/wayland/WinSystemWayland.cpp b/xbmc/windowing/wayland/WinSystemWayland.cpp index e226563a35..01d7c8b7ea 100644 --- a/xbmc/windowing/wayland/WinSystemWayland.cpp +++ b/xbmc/windowing/wayland/WinSystemWayland.cpp @@ -1088,9 +1088,7 @@ bool CWinSystemWayland::HasCursor() std::unique_lock<CCriticalSection> lock(m_seatsMutex); return std::any_of(m_seats.cbegin(), m_seats.cend(), [](decltype(m_seats)::value_type const& entry) - { - return entry.second.HasPointerCapability(); - }); + { return entry.second->HasPointerCapability(); }); } void CWinSystemWayland::ShowOSMouse(bool show) @@ -1144,13 +1142,17 @@ void CWinSystemWayland::OnSeatAdded(std::uint32_t name, wayland::proxy_t&& proxy std::unique_lock<CCriticalSection> lock(m_seatsMutex); wayland::seat_t seat(proxy); - auto newSeatEmplace = m_seats.emplace(std::piecewise_construct, - std::forward_as_tuple(name), - std::forward_as_tuple(name, seat, *m_connection)); + auto newSeatEmplace = m_seats.emplace(std::piecewise_construct, std::forward_as_tuple(name), + std::forward_as_tuple(CreateSeat(name, seat))); auto& seatInst = newSeatEmplace.first->second; - m_seatInputProcessing->AddSeat(&seatInst); - m_windowDecorator->AddSeat(&seatInst); + m_seatInputProcessing->AddSeat(seatInst.get()); + m_windowDecorator->AddSeat(seatInst.get()); +} + +std::unique_ptr<CSeat> CWinSystemWayland::CreateSeat(std::uint32_t name, wayland::seat_t& seat) +{ + return std::make_unique<CSeat>(name, seat, *m_connection); } void CWinSystemWayland::OnSeatRemoved(std::uint32_t name) @@ -1160,8 +1162,8 @@ void CWinSystemWayland::OnSeatRemoved(std::uint32_t name) auto seatI = m_seats.find(name); if (seatI != m_seats.end()) { - m_seatInputProcessing->RemoveSeat(&seatI->second); - m_windowDecorator->RemoveSeat(&seatI->second); + m_seatInputProcessing->RemoveSeat(seatI->second.get()); + m_windowDecorator->RemoveSeat(seatI->second.get()); m_seats.erase(name); } } @@ -1262,12 +1264,13 @@ void CWinSystemWayland::OnSetCursor(std::uint32_t seatGlobalName, std::uint32_t LoadDefaultCursor(); if (m_cursorSurface) // Cursor loading could have failed { - seatI->second.SetCursor(serial, m_cursorSurface, m_cursorImage.hotspot_x(), m_cursorImage.hotspot_y()); + seatI->second->SetCursor(serial, m_cursorSurface, m_cursorImage.hotspot_x(), + m_cursorImage.hotspot_y()); } } else { - seatI->second.SetCursor(serial, wayland::surface_t{}, 0, 0); + seatI->second->SetCursor(serial, wayland::surface_t{}, 0, 0); } } @@ -1517,7 +1520,7 @@ std::string CWinSystemWayland::GetClipboardText() // probably just not that relevant in practice for (auto const& seat : m_seats) { - auto text = seat.second.GetSelectionText(); + auto text = seat.second->GetSelectionText(); if (text != "") { return text; diff --git a/xbmc/windowing/wayland/WinSystemWayland.h b/xbmc/windowing/wayland/WinSystemWayland.h index 95f2a9cfea..62e96d2183 100644 --- a/xbmc/windowing/wayland/WinSystemWayland.h +++ b/xbmc/windowing/wayland/WinSystemWayland.h @@ -122,6 +122,8 @@ protected: void OnConfigure(std::uint32_t serial, CSizeInt size, IShellSurface::StateBitset state) override; void OnClose() override; + virtual std::unique_ptr<CSeat> CreateSeat(std::uint32_t name, wayland::seat_t& seat); + private: // IInputHandler void OnEnter(InputType type) override; @@ -208,7 +210,7 @@ private: // Seat handling // ------------- - std::map<std::uint32_t, CSeat> m_seats; + std::map<std::uint32_t, std::unique_ptr<CSeat>> m_seats; CCriticalSection m_seatsMutex; std::unique_ptr<CSeatInputProcessing> m_seatInputProcessing; std::map<std::uint32_t, std::shared_ptr<COutput>> m_outputs; diff --git a/xbmc/windowing/wayland/WinSystemWaylandWebOS.cpp b/xbmc/windowing/wayland/WinSystemWaylandWebOS.cpp index bfbb2fa286..2ca132026c 100644 --- a/xbmc/windowing/wayland/WinSystemWaylandWebOS.cpp +++ b/xbmc/windowing/wayland/WinSystemWaylandWebOS.cpp @@ -11,6 +11,7 @@ #include "Connection.h" #include "OSScreenSaverWebOS.h" #include "Registry.h" +#include "SeatWebOS.h" #include "ShellSurfaceWebOSShell.h" #include "application/ApplicationComponents.h" #include "application/ApplicationPlayer.h" @@ -148,6 +149,11 @@ std::unique_ptr<KODI::WINDOWING::IOSScreenSaver> CWinSystemWaylandWebOS::GetOSSc return std::make_unique<COSScreenSaverWebOS>(); } +std::unique_ptr<CSeat> CWinSystemWaylandWebOS::CreateSeat(std::uint32_t name, wayland::seat_t& seat) +{ + return std::make_unique<CSeatWebOS>(name, seat, *GetConnection()); +} + bool CWinSystemWaylandWebOS::OnAppLifecycleEventWrapper(LSHandle* sh, LSMessage* reply, void* ctx) { HContext* context = static_cast<HContext*>(ctx); diff --git a/xbmc/windowing/wayland/WinSystemWaylandWebOS.h b/xbmc/windowing/wayland/WinSystemWaylandWebOS.h index 3f3c9821b4..375b0c3f94 100644 --- a/xbmc/windowing/wayland/WinSystemWaylandWebOS.h +++ b/xbmc/windowing/wayland/WinSystemWaylandWebOS.h @@ -50,6 +50,7 @@ public: protected: std::unique_ptr<KODI::WINDOWING::IOSScreenSaver> GetOSScreenSaverImpl() override; + std::unique_ptr<CSeat> CreateSeat(std::uint32_t name, wayland::seat_t& seat) override; private: static bool OnAppLifecycleEventWrapper(LSHandle* sh, LSMessage* reply, void* ctx); diff --git a/xbmc/windowing/win10/WinSystemWin10.cpp b/xbmc/windowing/win10/WinSystemWin10.cpp index ccdbc395f3..1461d797b0 100644 --- a/xbmc/windowing/win10/WinSystemWin10.cpp +++ b/xbmc/windowing/win10/WinSystemWin10.cpp @@ -692,7 +692,14 @@ float CWinSystemWin10::GetGuiSdrPeakLuminance() const */ bool CWinSystemWin10::HasSystemSdrPeakLuminance() { - return CWIN32Util::GetSystemSdrWhiteLevel(std::wstring(), nullptr); + if (m_uiThreadId == GetCurrentThreadId()) + { + const bool hasSystemSdrPeakLum = CWIN32Util::GetSystemSdrWhiteLevel(std::wstring(), nullptr); + m_cachedHasSystemSdrPeakLum = hasSystemSdrPeakLum; + return hasSystemSdrPeakLum; + } + + return m_cachedHasSystemSdrPeakLum; } /*! diff --git a/xbmc/windowing/win10/WinSystemWin10.h b/xbmc/windowing/win10/WinSystemWin10.h index c53fd01872..6b5be4bb4e 100644 --- a/xbmc/windowing/win10/WinSystemWin10.h +++ b/xbmc/windowing/win10/WinSystemWin10.h @@ -156,6 +156,10 @@ protected: bool m_validSystemSdrPeakLuminance{false}; float m_systemSdrPeakLuminance{.0f}; + + DWORD m_uiThreadId{0}; + HDR_STATUS m_cachedHdrStatus{HDR_STATUS::HDR_UNSUPPORTED}; + bool m_cachedHasSystemSdrPeakLum{false}; }; #pragma pack(pop) diff --git a/xbmc/windowing/win10/WinSystemWin10DX.cpp b/xbmc/windowing/win10/WinSystemWin10DX.cpp index 1101b1a7ef..55167ff386 100644 --- a/xbmc/windowing/win10/WinSystemWin10DX.cpp +++ b/xbmc/windowing/win10/WinSystemWin10DX.cpp @@ -61,6 +61,14 @@ bool CWinSystemWin10DX::CreateNewWindow(const std::string& name, bool fullScreen m_deviceResources = DX::DeviceResources::Get(); m_deviceResources->SetWindow(m_coreWindow); + // saves threadId of current thread (UI thread) + m_uiThreadId = GetCurrentThreadId(); + + // calls these methods to make sure cached values are properly initialized + // and can be used later when called from other thread + IsHDRDisplay(); + HasSystemSdrPeakLuminance(); + if (CWinSystemWin10::CreateNewWindow(name, fullScreen, res) && m_deviceResources->HasValidDevice()) { CGenericTouchInputHandler::GetInstance().RegisterHandler(&CGenericTouchActionHandler::GetInstance()); @@ -166,7 +174,14 @@ void CWinSystemWin10DX::InitHooks(IDXGIOutput* pOutput) bool CWinSystemWin10DX::IsHDRDisplay() { - return (CWIN32Util::GetWindowsHDRStatus() != HDR_STATUS::HDR_UNSUPPORTED); + if (m_uiThreadId == GetCurrentThreadId()) + { + const HDR_STATUS hdrStatus = CWIN32Util::GetWindowsHDRStatus(); + m_cachedHdrStatus = hdrStatus; + return (hdrStatus != HDR_STATUS::HDR_UNSUPPORTED); + } + + return (m_cachedHdrStatus != HDR_STATUS::HDR_UNSUPPORTED); } HDR_STATUS CWinSystemWin10DX::GetOSHDRStatus() diff --git a/xbmc/windows/GUIMediaWindow.cpp b/xbmc/windows/GUIMediaWindow.cpp index 5dacf417a1..aab1d37e0c 100644 --- a/xbmc/windows/GUIMediaWindow.cpp +++ b/xbmc/windows/GUIMediaWindow.cpp @@ -10,6 +10,7 @@ #include "ContextMenuManager.h" #include "FileItem.h" +#include "FileItemList.h" #include "FileItemListModification.h" #include "GUIPassword.h" #include "GUIUserMessages.h" @@ -59,6 +60,7 @@ #include "utils/URIUtils.h" #include "utils/Variant.h" #include "utils/log.h" +#include "video/VideoFileItemClassify.h" #include "view/GUIViewState.h" #include <inttypes.h> @@ -78,6 +80,7 @@ using namespace ADDON; using namespace KODI::MESSAGING; +using namespace KODI::VIDEO; using namespace std::chrono_literals; namespace @@ -1550,7 +1553,8 @@ bool CGUIMediaWindow::OnPlayAndQueueMedia(const CFileItemPtr& item, const std::s if (nItem->m_bIsFolder) continue; - if (!nItem->IsZIP() && !nItem->IsRAR() && (!nItem->IsDVDFile() || (URIUtils::GetFileName(nItem->GetDynPath()) == mainDVD))) + if (!nItem->IsZIP() && !nItem->IsRAR() && + (!IsDVDFile(*nItem) || (URIUtils::GetFileName(nItem->GetDynPath()) == mainDVD))) CServiceBroker::GetPlaylistPlayer().Add(playlistId, nItem); if (item->IsSamePath(nItem.get())) diff --git a/xbmc/windows/GUIWindowFileManager.cpp b/xbmc/windows/GUIWindowFileManager.cpp index 2093101d08..bf11d13dfe 100644 --- a/xbmc/windows/GUIWindowFileManager.cpp +++ b/xbmc/windows/GUIWindowFileManager.cpp @@ -56,9 +56,11 @@ #include "utils/URIUtils.h" #include "utils/Variant.h" #include "utils/log.h" +#include "video/VideoFileItemClassify.h" using namespace XFILE; using namespace KODI::MESSAGING; +using namespace KODI::VIDEO; #define CONTROL_BTNSELECTALL 1 #define CONTROL_BTNFAVOURITES 2 @@ -655,7 +657,7 @@ void CGUIWindowFileManager::OnStart(CFileItem *pItem, const std::string &player) g_application.ProcessAndStartPlaylist(strPlayList, *pPlayList, PLAYLIST::TYPE_MUSIC); return; } - if (pItem->IsAudio() || pItem->IsVideo()) + if (pItem->IsAudio() || IsVideo(*pItem)) { CServiceBroker::GetPlaylistPlayer().Play(std::make_shared<CFileItem>(*pItem), player); return; diff --git a/xbmc/windows/GUIWindowLoginScreen.cpp b/xbmc/windows/GUIWindowLoginScreen.cpp index 04eb5f9041..c95f6e4b61 100644 --- a/xbmc/windows/GUIWindowLoginScreen.cpp +++ b/xbmc/windows/GUIWindowLoginScreen.cpp @@ -9,6 +9,7 @@ #include "GUIWindowLoginScreen.h" #include "FileItem.h" +#include "FileItemList.h" #include "GUIPassword.h" #include "ServiceBroker.h" #include "addons/Skin.h" |