diff options
Diffstat (limited to 'debian/patches')
29 files changed, 19464 insertions, 0 deletions
diff --git a/debian/patches/cdatetime-std-chrono/0001-Replace-Kodi-date-time-implementation-with-std-c.patch b/debian/patches/cdatetime-std-chrono/0001-Replace-Kodi-date-time-implementation-with-std-c.patch new file mode 100644 index 0000000..5c553eb --- /dev/null +++ b/debian/patches/cdatetime-std-chrono/0001-Replace-Kodi-date-time-implementation-with-std-c.patch @@ -0,0 +1,7004 @@ +From c34f01771ab31da1450e0e8aec0dd4654ea5c557 Mon Sep 17 00:00:00 2001 +From: Lukas Rusak <lorusak@gmail.com> +Date: Mon, 17 Feb 2020 22:41:25 -0800 +Subject: [PATCH 01/19] add support for date library and tzdata + +Signed-off-by: Vasyl Gello <vasek.gello@gmail.com> +--- + CMakeLists.txt | 6 + + cmake/modules/FindDate.cmake | 110 ++++++++++++++++++ + cmake/modules/FindTZData.cmake | 33 ++++++ + cmake/scripts/linux/Install.cmake | 7 ++ + .../date/0001-cmake-install-all-headers.patch | 74 ++++++++++++ + .../target/date/0002-Fix-Android-build.patch | 37 ++++++ + .../target/date/0003-Fix-UWP-build.patch | 58 +++++++++ + tools/depends/target/date/DATE-VERSION | 6 + + .../target/tzdata/001-cmakelists.patch | 11 ++ + tools/depends/target/tzdata/TZDATA-VERSION | 5 + + 10 files changed, 347 insertions(+) + create mode 100644 cmake/modules/FindDate.cmake + create mode 100644 cmake/modules/FindTZData.cmake + create mode 100644 tools/depends/target/date/0001-cmake-install-all-headers.patch + create mode 100644 tools/depends/target/date/0002-Fix-Android-build.patch + create mode 100644 tools/depends/target/date/0003-Fix-UWP-build.patch + create mode 100644 tools/depends/target/date/DATE-VERSION + create mode 100644 tools/depends/target/tzdata/001-cmakelists.patch + create mode 100644 tools/depends/target/tzdata/TZDATA-VERSION + +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 19881e4708..55344f7626 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -85,6 +85,10 @@ if(UNIX) + endif() + # prefer kissfft from xbmc/contrib but let use system one on unices + cmake_dependent_option(ENABLE_INTERNAL_KISSFFT "Enable internal kissfft?" ON "UNIX" ON) ++# prefer internal date and tzdata but let use system one on unices ++cmake_dependent_option(ENABLE_INTERNAL_DATE "Enable internal date library?" ON "UNIX" ON) ++cmake_dependent_option(ENABLE_INTERNAL_TZDATA "Use Kodi bundled timezone information?" ON "NOT ENABLE_INTERNAL_DATE" ON) ++cmake_dependent_option(DATE_HAS_STRINGVIEW "Is system date library compiled with StringView support?" ON "NOT ENABLE_INTERNAL_DATE" ON) + # System options + if(NOT WIN32) + option(WITH_ARCH "build with given arch" OFF) +@@ -163,6 +167,7 @@ set(required_deps ASS + Cdio + CrossGUID + Curl ++ Date + FFMPEG + FlatBuffers + Fmt +@@ -181,6 +186,7 @@ set(required_deps ASS + Sqlite3 + TagLib + TinyXML ++ TZData + ZLIB + ${PLATFORM_REQUIRED_DEPS}) + +diff --git a/cmake/modules/FindDate.cmake b/cmake/modules/FindDate.cmake +new file mode 100644 +index 0000000000..61746e4d33 +--- /dev/null ++++ b/cmake/modules/FindDate.cmake +@@ -0,0 +1,110 @@ ++#.rst: ++# FindDate ++# ------- ++# Finds the DATE library and builds internal ++# DATE if requested ++# ++# This will define the following variables:: ++# ++# DATE_FOUND - system has DATE ++# DATE_INCLUDE_DIRS - the DATE include directory ++# DATE_LIBRARIES - the DATE libraries ++# DATE_DEFINITIONS - the DATE definitions ++# ++# and the following imported targets:: ++# ++# Date::Date - The Date library ++ ++if(ENABLE_INTERNAL_DATE) ++ include(cmake/scripts/common/ModuleHelpers.cmake) ++ ++ set(MODULE_LC date) ++ ++ SETUP_BUILD_VARS() ++ ++ set(DATE_VERSION ${${MODULE}_VER}) ++ ++ # Debug postfix only used for windows ++ if(WIN32 OR WINDOWS_STORE) ++ set(DATE_DEBUG_POSTFIX "d") ++ endif() ++ ++ # Propagate CMake definitions ++ ++ if(CORE_SYSTEM_NAME STREQUAL darwin_embedded) ++ set(EXTRA_ARGS -DIOS=ON) ++ elseif(WINDOWS_STORE) ++ set(EXTRA_ARGS -DWINRT=ON) ++ endif() ++ ++ set(CMAKE_ARGS -DCMAKE_CXX_STANDARD=17 ++ -DUSE_SYSTEM_TZ_DB=OFF ++ -DMANUAL_TZ_DB=ON ++ -DUSE_TZ_DB_IN_DOT=OFF ++ -DBUILD_SHARED_LIBS=OFF ++ -DBUILD_TZ_LIB=ON ++ ${EXTRA_ARGS}) ++ ++ # Work around old release ++ ++ file(GLOB patches "${CMAKE_SOURCE_DIR}/tools/depends/target/date/*.patch") ++ ++ generate_patchcommand("${patches}") ++ ++ BUILD_DEP_TARGET() ++else() ++ if(PKG_CONFIG_FOUND) ++ pkg_check_modules(PC_DATE libdate-tz>=3.0.1 QUIET) ++ endif() ++ ++ find_path(DATE_INCLUDE_DIR date/date.h ++ PATHS ${PC_DATE_INCLUDEDIR}) ++ find_library(DATE_LIBRARY_RELEASE NAMES date-tz libdate-tz ++ PATHS ${PC_DATE_LIBDIR}) ++ find_library(DATE_LIBRARY_DEBUG NAMES date-tzd libdate-tzd ++ PATHS ${PC_DATE_LIBDIR}) ++ set(DATE_VERSION ${PC_DATE_VERSION}) ++endif() ++ ++include(SelectLibraryConfigurations) ++select_library_configurations(DATE) ++ ++include(FindPackageHandleStandardArgs) ++find_package_handle_standard_args(Date ++ REQUIRED_VARS DATE_LIBRARY DATE_INCLUDE_DIR ++ VERSION_VAR DATE_VERSION) ++ ++if(DATE_FOUND) ++ set(DATE_INCLUDE_DIRS ${DATE_INCLUDE_DIR}) ++ set(DATE_LIBRARIES ${DATE_LIBRARY}) ++ ++ if(ENABLE_INTERNAL_TZDATA) ++ set(DATE_DEFINITIONS ${DATE_DEFINITIONS} -DDATE_INTERNAL_TZDATA) ++ endif() ++ ++ if(DATE_HAS_STRINGVIEW) ++ set(DATE_DEFINITIONS ${DATE_DEFINITIONS} -DDATE_HAS_STRINGVIEW) ++ endif() ++ ++ if(NOT TARGET Date::Date) ++ add_library(Date::Date UNKNOWN IMPORTED) ++ if(DATE_LIBRARY_RELEASE) ++ set_target_properties(Date::Date PROPERTIES ++ IMPORTED_CONFIGURATIONS RELEASE ++ IMPORTED_LOCATION "${DATE_LIBRARY_RELEASE}") ++ endif() ++ if(DATE_LIBRARY_DEBUG) ++ set_target_properties(Date::Date PROPERTIES ++ IMPORTED_CONFIGURATIONS DEBUG ++ IMPORTED_LOCATION "${DATE_LIBRARY_DEBUG}") ++ endif() ++ set_target_properties(Date::Date PROPERTIES ++ INTERFACE_INCLUDE_DIRECTORIES "${DATE_INCLUDE_DIR}") ++ if(TARGET date) ++ add_dependencies(Date::Date date) ++ endif() ++ endif() ++ set_property(GLOBAL APPEND PROPERTY INTERNAL_DEPS_PROP Date::Date) ++endif() ++ ++mark_as_advanced(DATE_INCLUDE_DIR DATE_LIBRARY) +diff --git a/cmake/modules/FindTZData.cmake b/cmake/modules/FindTZData.cmake +new file mode 100644 +index 0000000000..b7241a6b04 +--- /dev/null ++++ b/cmake/modules/FindTZData.cmake +@@ -0,0 +1,33 @@ ++#.rst: ++# FindTZData ++# ------- ++# Populates resource.timezone with TZDATA if requested ++# ++# This will define the following variables:: ++# ++# TZDATA_FOUND - system has internal TZDATA ++# TZDATA_VERSION - version of internal TZDATA ++ ++if(ENABLE_INTERNAL_TZDATA) ++ include(cmake/scripts/common/ModuleHelpers.cmake) ++ ++ set(MODULE_LC tzdata) ++ ++ SETUP_BUILD_VARS() ++ ++ # Mirror tzdata to resource.timezone ++ ++ set(CMAKE_ARGS -DINSTALL_DIR=${CMAKE_BINARY_DIR}/addons/resource.timezone/resources/tzdata) ++ ++ # Add CMakeLists.txt installing sources as target ++ ++ set(patches ${CMAKE_SOURCE_DIR}/tools/depends/target/tzdata/001-cmakelists.patch) ++ ++ generate_patchcommand("${patches}") ++ ++ BUILD_DEP_TARGET() ++else() ++ set(TZDATA_VERSION "none") ++endif() ++ ++set(TZDATA_FOUND TRUE) +diff --git a/cmake/scripts/linux/Install.cmake b/cmake/scripts/linux/Install.cmake +index 331722cb56..e3ceacbf76 100644 +--- a/cmake/scripts/linux/Install.cmake ++++ b/cmake/scripts/linux/Install.cmake +@@ -85,6 +85,13 @@ foreach(file ${install_data}) + COMPONENT kodi) + endforeach() + ++# Install timezone resources ++if(ENABLE_INTERNAL_TZDATA) ++ install(DIRECTORY ${CMAKE_BINARY_DIR}/addons/resource.timezone/resources/tzdata ++ DESTINATION ${datarootdir}/${APP_NAME_LC}/addons/resource.timezone/resources ++ COMPONENT kodi) ++endif() ++ + # Install xsession entry + install(FILES ${CMAKE_BINARY_DIR}/${CORE_BUILD_DIR}/${APP_NAME_LC}-xsession.desktop + RENAME ${APP_NAME_LC}.desktop +diff --git a/tools/depends/target/date/0001-cmake-install-all-headers.patch b/tools/depends/target/date/0001-cmake-install-all-headers.patch +new file mode 100644 +index 0000000000..e8ac76a48b +--- /dev/null ++++ b/tools/depends/target/date/0001-cmake-install-all-headers.patch +@@ -0,0 +1,74 @@ ++From 8b3fac88cb5e4fef81b55b7537232a6418752153 Mon Sep 17 00:00:00 2001 ++From: Andrea Pappacoda <andrea@pappacoda.it> ++Date: Thu, 4 Aug 2022 11:35:41 +0200 ++Subject: [PATCH 1/4] cmake: install all headers ++ ++Lazy solution: mark all headers as either PUBLIC_ or PRIVATE_HEADER, ++requiring CMake 3.15. ++ ++Bug: https://github.com/HowardHinnant/date/pull/503 ++Bug-Debian: https://bugs.debian.org/1001895 ++--- ++ CMakeLists.txt | 20 +++++++++++++++----- ++ 1 file changed, 15 insertions(+), 5 deletions(-) ++ ++diff --git a/CMakeLists.txt b/CMakeLists.txt ++index 012512a..c0bda7f 100644 ++--- a/CMakeLists.txt +++++ b/CMakeLists.txt ++@@ -75,7 +75,13 @@ target_sources( date INTERFACE ++ ) ++ if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.15) ++ # public headers will get installed: ++- set_target_properties( date PROPERTIES PUBLIC_HEADER include/date/date.h ) +++ set_property(TARGET date PROPERTY PUBLIC_HEADER +++ include/date/date.h +++ include/date/islamic.h +++ include/date/iso_week.h +++ include/date/julian.h +++ include/date/solar_hijri.h +++ ) ++ endif () ++ ++ # These used to be set with generator expressions, ++@@ -137,14 +143,16 @@ if( BUILD_TZ_LIB ) ++ target_compile_definitions( date-tz PUBLIC DATE_BUILD_DLL=1 ) ++ endif() ++ ++- set(TZ_HEADERS include/date/tz.h) +++ set(TZ_PUBLIC_HEADERS include/date/ptz.h include/date/tz.h) +++ set(TZ_PRIVATE_HEADERS include/date/tz_private.h) ++ ++ if( IOS ) ++- list(APPEND TZ_HEADERS include/date/ios.h) +++ list(APPEND TZ_PRIVATE_HEADERS include/date/ios.h) ++ endif( ) ++ set_target_properties( date-tz PROPERTIES ++ POSITION_INDEPENDENT_CODE ON ++- PUBLIC_HEADER "${TZ_HEADERS}" +++ PUBLIC_HEADER "${TZ_PUBLIC_HEADERS}" +++ PRIVATE_HEADER "${TZ_PRIVATE_HEADERS}" ++ VERSION "${PROJECT_VERSION}" ++ SOVERSION "${ABI_VERSION}" ) ++ if( NOT MSVC ) ++@@ -170,7 +178,8 @@ write_basic_package_version_file( "${version_config}" ++ ++ install( TARGETS date ++ EXPORT dateConfig ++- PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/date ) +++ PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/date +++ PRIVATE_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/date ) ++ export( TARGETS date NAMESPACE date:: FILE dateTargets.cmake ) ++ if (CMAKE_VERSION VERSION_LESS 3.15) ++ install( ++@@ -182,6 +191,7 @@ if( BUILD_TZ_LIB ) ++ install( TARGETS date-tz ++ EXPORT dateConfig ++ PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/date +++ PRIVATE_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/date ++ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} ++ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ++ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ) # This is for Windows ++-- ++2.39.0 ++ +diff --git a/tools/depends/target/date/0002-Fix-Android-build.patch b/tools/depends/target/date/0002-Fix-Android-build.patch +new file mode 100644 +index 0000000000..e497b41bcf +--- /dev/null ++++ b/tools/depends/target/date/0002-Fix-Android-build.patch +@@ -0,0 +1,37 @@ ++From 5790d6aed57bda1dc1577860d8382678100ebfa3 Mon Sep 17 00:00:00 2001 ++From: Vasyl Gello <vasek.gello@gmail.com> ++Date: Wed, 11 Jan 2023 11:35:41 +0200 ++Subject: [PATCH 2/4] Fix Android build ++ ++Signed-off-by: Vasyl Gello <vasek.gello@gmail.com> ++--- ++ src/tz.cpp | 6 ++++-- ++ 1 file changed, 4 insertions(+), 2 deletions(-) ++ ++diff --git a/src/tz.cpp b/src/tz.cpp ++index 26babbd..69bab7c 100644 ++--- a/src/tz.cpp +++++ b/src/tz.cpp ++@@ -141,7 +141,7 @@ ++ # endif // HAS_REMOTE_API ++ #else // !_WIN32 ++ # include <unistd.h> ++-# if !USE_OS_TZDB && !defined(INSTALL) +++# if !USE_OS_TZDB && !defined(INSTALL) && !defined(__ANDROID__) ++ # include <wordexp.h> ++ # endif ++ # include <limits.h> ++@@ -245,7 +245,9 @@ expand_path(std::string path) ++ { ++ # if TARGET_OS_IPHONE ++ return date::iOSUtils::get_tzdata_path(); ++-# else // !TARGET_OS_IPHONE +++# elif defined(__ANDROID__) +++ return "/data/local/tmp"; +++# else // !TARGET_OS_IPHONE && !__ANDROID__ ++ ::wordexp_t w{}; ++ std::unique_ptr<::wordexp_t, void(*)(::wordexp_t*)> hold{&w, ::wordfree}; ++ ::wordexp(path.c_str(), &w, 0); ++-- ++2.39.0 ++ +diff --git a/tools/depends/target/date/0003-Fix-UWP-build.patch b/tools/depends/target/date/0003-Fix-UWP-build.patch +new file mode 100644 +index 0000000000..683ed4126d +--- /dev/null ++++ b/tools/depends/target/date/0003-Fix-UWP-build.patch +@@ -0,0 +1,58 @@ ++From 1e512b082eb99b5d9cd790158f3bdaefcbac823d Mon Sep 17 00:00:00 2001 ++From: Vasyl Gello <vasek.gello@gmail.com> ++Date: Wed, 11 Jan 2023 09:58:34 +0200 ++Subject: [PATCH 3/4] Fix UWP build ++ ++We don't need download_folder to be determined. ++Bringing full UWP runtime just for that is an overkill. ++--- ++ CMakeLists.txt | 4 ++++ ++ src/tz.cpp | 17 +++++++++++++++++ ++ 2 files changed, 21 insertions(+) ++ ++diff --git a/CMakeLists.txt b/CMakeLists.txt ++index c0bda7f..0fa3dc2 100644 ++--- a/CMakeLists.txt +++++ b/CMakeLists.txt ++@@ -133,6 +133,10 @@ if( BUILD_TZ_LIB ) ++ target_compile_definitions( date-tz PRIVATE AUTO_DOWNLOAD=1 HAS_REMOTE_API=1 ) ++ endif() ++ +++ if(WINRT) +++ target_compile_definitions( date-tz PRIVATE WINRT=1 INSTALL=. ) +++ endif() +++ ++ if ( USE_SYSTEM_TZ_DB AND NOT WIN32 AND NOT MANUAL_TZ_DB ) ++ target_compile_definitions( date-tz PRIVATE INSTALL=. PUBLIC USE_OS_TZDB=1 ) ++ else() ++diff --git a/src/tz.cpp b/src/tz.cpp ++index 69bab7c..aa15192 100644 ++--- a/src/tz.cpp +++++ b/src/tz.cpp ++@@ -234,6 +234,23 @@ get_download_folder() ++ ++ # endif // !INSTALL ++ +++# else // WINRT +++static +++std::string +++get_program_folder() +++{ +++ return ""; +++} +++ +++# ifndef INSTALL +++ +++static +++std::string +++get_download_folder() +++{ +++ return ""; +++} +++# endif // !INSTALL ++ # endif // WINRT ++ # else // !_WIN32 ++ ++-- ++2.39.0 ++ +diff --git a/tools/depends/target/date/DATE-VERSION b/tools/depends/target/date/DATE-VERSION +new file mode 100644 +index 0000000000..0608029104 +--- /dev/null ++++ b/tools/depends/target/date/DATE-VERSION +@@ -0,0 +1,6 @@ ++LIBNAME=date ++VERSION=3.0.1 ++ARCHIVE=$(LIBNAME)-$(VERSION).tar.gz ++SHA512=6bdc7cba821d66e17a559250cc0ce0095808e9db81cec9e16eaa4c31abdfa705299c67b72016d9b06b302bc306d063e83a374eb00728071b83a5ad650d59034f ++BYPRODUCT=libdate-tz.a ++BYPRODUCT_WIN=date-tz.lib +diff --git a/tools/depends/target/tzdata/001-cmakelists.patch b/tools/depends/target/tzdata/001-cmakelists.patch +new file mode 100644 +index 0000000000..dda65fc542 +--- /dev/null ++++ b/tools/depends/target/tzdata/001-cmakelists.patch +@@ -0,0 +1,11 @@ ++diff --git a/CMakeLists.txt b/CMakeLists.txt ++new file mode 100644 ++index 0000000..8a015cd ++--- /dev/null +++++ b/CMakeLists.txt ++@@ -0,0 +1,5 @@ +++cmake_minimum_required(VERSION 3.2) +++ +++project(kodi-tzdata) +++ +++install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/ DESTINATION ${INSTALL_DIR}) +diff --git a/tools/depends/target/tzdata/TZDATA-VERSION b/tools/depends/target/tzdata/TZDATA-VERSION +new file mode 100644 +index 0000000000..7f92f0b74c +--- /dev/null ++++ b/tools/depends/target/tzdata/TZDATA-VERSION +@@ -0,0 +1,5 @@ ++LIBNAME=tzdata ++VERSION=2022g ++ARCHIVE=$(LIBNAME)$(VERSION).tar.gz ++SHA512=7f79394295e00e3a24ebdbf9af3bc454a65f432a93b517e7e96c7f9db9949f6f5fdae9892a9d3789ff44ae0eb1bfe4744d36976b4624659af951d26414f94e65 ++SOURCE_DIR=addons/resource.timezone/resources/tzdata +-- +2.43.0 + + +From b4a3fafe6da802ae1d690ceb07fbf5a781e0301a Mon Sep 17 00:00:00 2001 +From: Lukas Rusak <lorusak@gmail.com> +Date: Tue, 17 Mar 2020 13:12:04 -0700 +Subject: [PATCH 02/19] add resource.timezone + +--- + addons/kodi.resource/addon.xml | 1 + + addons/kodi.resource/timezone.xsd | 16 ++++++++++++ + addons/resource.timezone/addon.xml | 12 +++++++++ + cmake/installdata/common/addons.txt | 1 + + system/addon-manifest.xml | 1 + + xbmc/ServiceManager.cpp | 20 +++++++++++++++ + xbmc/addons/AddonBuilder.cpp | 3 +++ + xbmc/addons/CMakeLists.txt | 2 ++ + xbmc/addons/TimeZoneResource.cpp | 39 +++++++++++++++++++++++++++++ + xbmc/addons/TimeZoneResource.h | 25 ++++++++++++++++++ + xbmc/addons/addoninfo/AddonInfo.cpp | 3 ++- + xbmc/addons/addoninfo/AddonType.h | 1 + + xbmc/application/Application.cpp | 20 +++++++++++++++ + 13 files changed, 143 insertions(+), 1 deletion(-) + create mode 100644 addons/kodi.resource/timezone.xsd + create mode 100644 addons/resource.timezone/addon.xml + create mode 100644 xbmc/addons/TimeZoneResource.cpp + create mode 100644 xbmc/addons/TimeZoneResource.h + +diff --git a/addons/kodi.resource/addon.xml b/addons/kodi.resource/addon.xml +index 2bb3221b42..b615575744 100644 +--- a/addons/kodi.resource/addon.xml ++++ b/addons/kodi.resource/addon.xml +@@ -7,4 +7,5 @@ + <extension-point id="resource.language" schema="language.xsd"/> + <extension-point id="resource.uisounds" schema="uisounds.xsd"/> + <extension-point id="resource.images" schema="images.xsd"/> ++ <extension-point id="resource.timezone" schema="timezone.xsd"/> + </addon> +diff --git a/addons/kodi.resource/timezone.xsd b/addons/kodi.resource/timezone.xsd +new file mode 100644 +index 0000000000..990f8893ea +--- /dev/null ++++ b/addons/kodi.resource/timezone.xsd +@@ -0,0 +1,16 @@ ++<?xml version="1.0" encoding="UTF-8"?> ++<!DOCTYPE schema PUBLIC "-//W3C//DTD XMLSCHEMA 200102//EN" "http://www.w3.org/2001/XMLSchema.dtd"> ++<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> ++ <xs:element name="extension"> ++ <xs:complexType> ++ <xs:attribute name="point" type="xs:string" use="required"/> ++ <xs:attribute name="id" type="simpleIdentifier"/> ++ <xs:attribute name="name" type="xs:string"/> ++ </xs:complexType> ++ </xs:element> ++ <xs:simpleType name="simpleIdentifier"> ++ <xs:restriction base="xs:string"> ++ <xs:pattern value="kodi\.resource\.timezone"/> ++ </xs:restriction> ++ </xs:simpleType> ++</xs:schema> +diff --git a/addons/resource.timezone/addon.xml b/addons/resource.timezone/addon.xml +new file mode 100644 +index 0000000000..174b3f5687 +--- /dev/null ++++ b/addons/resource.timezone/addon.xml +@@ -0,0 +1,12 @@ ++<?xml version="1.0" encoding="UTF-8"?> ++<addon id="resource.timezone" version="1.0.0" name="Kodi Timezone Database" provider-name="Team Kodi"> ++ <requires> ++ <import addon="kodi.resource" version="1.0.0"/> ++ </requires> ++ <extension point="kodi.resource.timezone"/> ++ <extension point="kodi.addon.metadata"> ++ <summary lang="en_GB">Kodi Timezone Database</summary> ++ <description lang="en_GB">Kodi Timezone Database</description> ++ <platform>all</platform> ++ </extension> ++</addon> +diff --git a/cmake/installdata/common/addons.txt b/cmake/installdata/common/addons.txt +index 263e57bb66..0411f8a3da 100644 +--- a/cmake/installdata/common/addons.txt ++++ b/cmake/installdata/common/addons.txt +@@ -26,6 +26,7 @@ addons/metadata.tvshows.themoviedb.org.python/* + addons/repository.xbmc.org/* + addons/resource.images.weathericons.default/* + addons/resource.language.en_gb/* ++addons/resource.timezone/* + addons/resource.uisounds.kodi/* + addons/screensaver.xbmc.builtin.black/* + addons/screensaver.xbmc.builtin.dim/* +diff --git a/system/addon-manifest.xml b/system/addon-manifest.xml +index 7df13a6d6f..842e4e8206 100644 +--- a/system/addon-manifest.xml ++++ b/system/addon-manifest.xml +@@ -38,6 +38,7 @@ + <addon optional="true">repository.xbmc.org</addon> + <addon>resource.images.weathericons.default</addon> + <addon>resource.language.en_gb</addon> ++ <addon>resource.timezone</addon> + <addon>resource.uisounds.kodi</addon> + <addon>screensaver.xbmc.builtin.black</addon> + <addon>screensaver.xbmc.builtin.dim</addon> +diff --git a/xbmc/ServiceManager.cpp b/xbmc/ServiceManager.cpp +index 02d9900e9b..83070489e3 100644 +--- a/xbmc/ServiceManager.cpp ++++ b/xbmc/ServiceManager.cpp +@@ -17,6 +17,7 @@ + #include "addons/RepositoryUpdater.h" + #include "addons/Service.h" + #include "addons/VFSEntry.h" ++#include "addons/addoninfo/AddonType.h" + #include "addons/binary-addons/BinaryAddonManager.h" + #include "cores/DataCacheCore.h" + #include "cores/RetroPlayer/guibridge/GUIGameRenderManager.h" +@@ -45,9 +46,14 @@ + #endif + #include "storage/MediaManager.h" + #include "utils/FileExtensionProvider.h" ++#include "utils/URIUtils.h" + #include "utils/log.h" + #include "weather/WeatherManager.h" + ++#define USE_OS_TZDB 0 ++#define HAS_REMOTE_API 0 ++#include <date/tz.h> ++ + using namespace KODI; + + CServiceManager::CServiceManager() = default; +@@ -79,6 +85,20 @@ bool CServiceManager::InitForTesting() + m_extsMimeSupportList.reset(new ADDONS::CExtsMimeSupportList(*m_addonMgr)); + m_fileExtensionProvider.reset(new CFileExtensionProvider(*m_addonMgr)); + ++#if defined(DATE_INTERNAL_TZDATA) ++ ADDON::AddonPtr addon; ++ if (!m_addonMgr->GetAddon("resource.timezone", addon, ADDON::AddonType::RESOURCE_TIMEZONE, ++ ADDON::OnlyEnabled::CHOICE_YES)) ++ { ++ CLog::LogF(LOGFATAL, "failed to find resource.timezone"); ++ return false; ++ } ++ ++ std::string tzdataPath = URIUtils::AddFileToFolder(addon->Path(), "resources", "tzdata"); ++ CLog::LogF(LOGDEBUG, "tzdata path: {}", tzdataPath); ++ date::set_install(tzdataPath); ++#endif ++ + init_level = 1; + return true; + } +diff --git a/xbmc/addons/AddonBuilder.cpp b/xbmc/addons/AddonBuilder.cpp +index 7d52ee0431..dd72a08705 100644 +--- a/xbmc/addons/AddonBuilder.cpp ++++ b/xbmc/addons/AddonBuilder.cpp +@@ -19,6 +19,7 @@ + #include "addons/Scraper.h" + #include "addons/Service.h" + #include "addons/Skin.h" ++#include "addons/TimeZoneResource.h" + #include "addons/UISoundsResource.h" + #include "addons/Webinterface.h" + #include "addons/addoninfo/AddonInfo.h" +@@ -106,6 +107,8 @@ AddonPtr CAddonBuilder::Generate(const AddonInfoPtr& info, AddonType type) + return std::make_shared<CLanguageResource>(info); + case AddonType::RESOURCE_UISOUNDS: + return std::make_shared<CUISoundsResource>(info); ++ case AddonType::RESOURCE_TIMEZONE: ++ return std::make_shared<CTimeZoneResource>(info); + case AddonType::REPOSITORY: + return std::make_shared<CRepository>(info); + case AddonType::CONTEXTMENU_ITEM: +diff --git a/xbmc/addons/CMakeLists.txt b/xbmc/addons/CMakeLists.txt +index 947a885b4c..101371f12d 100644 +--- a/xbmc/addons/CMakeLists.txt ++++ b/xbmc/addons/CMakeLists.txt +@@ -26,6 +26,7 @@ set(SOURCES Addon.cpp + ScreenSaver.cpp + Service.cpp + Skin.cpp ++ TimeZoneResource.cpp + UISoundsResource.cpp + VFSEntry.cpp + Visualization.cpp +@@ -66,6 +67,7 @@ set(HEADERS Addon.h + ScreenSaver.h + Service.h + Skin.h ++ TimeZoneResource.h + UISoundsResource.h + VFSEntry.h + Visualization.h +diff --git a/xbmc/addons/TimeZoneResource.cpp b/xbmc/addons/TimeZoneResource.cpp +new file mode 100644 +index 0000000000..94246c9e18 +--- /dev/null ++++ b/xbmc/addons/TimeZoneResource.cpp +@@ -0,0 +1,39 @@ ++/* ++ * Copyright (C) 2015-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 "TimeZoneResource.h" ++ ++#include "addons/addoninfo/AddonType.h" ++#include "utils/StringUtils.h" ++#include "utils/URIUtils.h" ++ ++#include <date/tz.h> ++ ++namespace ADDON ++{ ++ ++CTimeZoneResource::CTimeZoneResource(const AddonInfoPtr& addonInfo) ++ : CResource(addonInfo, AddonType::RESOURCE_TIMEZONE) ++{ ++} ++ ++bool CTimeZoneResource::IsAllowed(const std::string& file) const ++{ ++ return true; ++} ++ ++bool CTimeZoneResource::IsInUse() const ++{ ++ return true; ++} ++ ++void CTimeZoneResource::OnPostInstall(bool update, bool modal) ++{ ++ date::reload_tzdb(); ++} ++ ++} // namespace ADDON +diff --git a/xbmc/addons/TimeZoneResource.h b/xbmc/addons/TimeZoneResource.h +new file mode 100644 +index 0000000000..a979f05dec +--- /dev/null ++++ b/xbmc/addons/TimeZoneResource.h +@@ -0,0 +1,25 @@ ++/* ++ * Copyright (C) 2015-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 "addons/Resource.h" ++ ++namespace ADDON ++{ ++ ++class CTimeZoneResource : public CResource ++{ ++public: ++ explicit CTimeZoneResource(const AddonInfoPtr& addonInfo); ++ bool IsAllowed(const std::string& file) const override; ++ bool IsInUse() const override; ++ void OnPostInstall(bool update, bool modal) override; ++}; ++ ++} // namespace ADDON +diff --git a/xbmc/addons/addoninfo/AddonInfo.cpp b/xbmc/addons/addoninfo/AddonInfo.cpp +index 61bc087443..f82a947981 100644 +--- a/xbmc/addons/addoninfo/AddonInfo.cpp ++++ b/xbmc/addons/addoninfo/AddonInfo.cpp +@@ -37,7 +37,7 @@ typedef struct + } TypeMapping; + + // clang-format off +-static constexpr const std::array<TypeMapping, 40> types = ++static constexpr const std::array<TypeMapping, 41> types = + {{ + {"unknown", "", AddonType::UNKNOWN, 0, AddonInstanceSupport::SUPPORT_NONE, "" }, + {"xbmc.metadata.scraper.albums", "", AddonType::SCRAPER_ALBUMS, 24016, AddonInstanceSupport::SUPPORT_NONE, "DefaultAddonAlbumInfo.png" }, +@@ -73,6 +73,7 @@ static constexpr const std::array<TypeMapping, 40> types = + {"xbmc.service", "", AddonType::SERVICE, 24018, AddonInstanceSupport::SUPPORT_NONE, "DefaultAddonService.png" }, + {"kodi.resource.images", "", AddonType::RESOURCE_IMAGES, 24035, AddonInstanceSupport::SUPPORT_NONE, "DefaultAddonImages.png" }, + {"kodi.resource.language", "", AddonType::RESOURCE_LANGUAGE, 24026, AddonInstanceSupport::SUPPORT_NONE, "DefaultAddonLanguage.png" }, ++ {"kodi.resource.timezone", "", AddonType::RESOURCE_TIMEZONE, 24026, AddonInstanceSupport::SUPPORT_NONE, "DefaultAddonTimeZone.png" }, + {"kodi.resource.uisounds", "", AddonType::RESOURCE_UISOUNDS, 24006, AddonInstanceSupport::SUPPORT_NONE, "DefaultAddonUISounds.png" }, + {"kodi.resource.games", "", AddonType::RESOURCE_GAMES, 35209, AddonInstanceSupport::SUPPORT_NONE, "DefaultAddonGame.png" }, + {"kodi.resource.font", "", AddonType::RESOURCE_FONT, 13303, AddonInstanceSupport::SUPPORT_NONE, "DefaultAddonFont.png" }, +diff --git a/xbmc/addons/addoninfo/AddonType.h b/xbmc/addons/addoninfo/AddonType.h +index 9a0ee260cf..27f49e3138 100644 +--- a/xbmc/addons/addoninfo/AddonType.h ++++ b/xbmc/addons/addoninfo/AddonType.h +@@ -46,6 +46,7 @@ enum class AddonType + AUDIODECODER, + RESOURCE_IMAGES, + RESOURCE_LANGUAGE, ++ RESOURCE_TIMEZONE, + RESOURCE_UISOUNDS, + RESOURCE_GAMES, + RESOURCE_FONT, +diff --git a/xbmc/application/Application.cpp b/xbmc/application/Application.cpp +index 0765cf3723..ea1b152dfd 100644 +--- a/xbmc/application/Application.cpp ++++ b/xbmc/application/Application.cpp +@@ -195,8 +195,12 @@ + #include "pictures/GUIWindowSlideShow.h" + #include "utils/CharsetConverter.h" + ++#define USE_OS_TZDB 0 ++#define HAS_REMOTE_API 0 + #include <mutex> + ++#include <date/tz.h> ++ + using namespace ADDON; + using namespace XFILE; + #ifdef HAS_DVD_DRIVE +@@ -435,6 +439,22 @@ bool CApplication::Create() + return false; + } + ++ // Load timezone information ++#if defined(DATE_INTERNAL_TZDATA) ++ ADDON::AddonPtr addon; ++ if (!CServiceBroker::GetAddonMgr().GetAddon("resource.timezone", addon, ++ ADDON::AddonType::RESOURCE_TIMEZONE, ++ ADDON::OnlyEnabled::CHOICE_YES)) ++ { ++ CLog::LogF(LOGFATAL, "failed to find resource.timezone"); ++ return false; ++ } ++ ++ std::string tzdataPath = URIUtils::AddFileToFolder(addon->Path(), "resources", "tzdata"); ++ CLog::LogF(LOGDEBUG, "tzdata path: {}", tzdataPath); ++ date::set_install(tzdataPath); ++#endif ++ + m_pActiveAE.reset(new ActiveAE::CActiveAE()); + CServiceBroker::RegisterAE(m_pActiveAE.get()); + +-- +2.43.0 + + +From 6f004e0aa809505cbf71612df44343a15011d0cf Mon Sep 17 00:00:00 2001 +From: Lukas Rusak <lorusak@gmail.com> +Date: Mon, 10 Feb 2020 15:13:43 -0800 +Subject: [PATCH 03/19] CDateTime: convert to use std::chrono + +--- + xbmc/XBDateTime.cpp | 604 ++++++++-------------- + xbmc/XBDateTime.h | 31 +- + xbmc/platform/posix/PosixTimezone.cpp | 3 - + xbmc/pvr/guilib/PVRGUIActionsDatabase.cpp | 2 - + 4 files changed, 244 insertions(+), 396 deletions(-) + +diff --git a/xbmc/XBDateTime.cpp b/xbmc/XBDateTime.cpp +index 85d5d466d3..47c6b8d1a6 100644 +--- a/xbmc/XBDateTime.cpp ++++ b/xbmc/XBDateTime.cpp +@@ -17,29 +17,17 @@ + + #include <cstdlib> + +-#define SECONDS_PER_DAY 86400L +-#define SECONDS_PER_HOUR 3600L +-#define SECONDS_PER_MINUTE 60L +-#define SECONDS_TO_FILETIME 10000000L ++#define USE_OS_TZDB 0 ++#define HAS_REMOTE_API 0 ++#include <date/date.h> ++#include <date/iso_week.h> ++#include <date/tz.h> + +-static const char *DAY_NAMES[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; + static const char *MONTH_NAMES[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; + +-///////////////////////////////////////////////// +-// +-// CDateTimeSpan +-// +- +-CDateTimeSpan::CDateTimeSpan() +-{ +- m_timeSpan.highDateTime = 0; +- m_timeSpan.lowDateTime = 0; +-} +- + CDateTimeSpan::CDateTimeSpan(const CDateTimeSpan& span) + { +- m_timeSpan.highDateTime = span.m_timeSpan.highDateTime; +- m_timeSpan.lowDateTime = span.m_timeSpan.lowDateTime; ++ m_timeSpan = span.m_timeSpan; + } + + CDateTimeSpan::CDateTimeSpan(int day, int hour, int minute, int second) +@@ -49,7 +37,7 @@ CDateTimeSpan::CDateTimeSpan(int day, int hour, int minute, int second) + + bool CDateTimeSpan::operator >(const CDateTimeSpan& right) const + { +- return KODI::TIME::CompareFileTime(&m_timeSpan, &right.m_timeSpan) > 0; ++ return m_timeSpan > right.m_timeSpan; + } + + bool CDateTimeSpan::operator >=(const CDateTimeSpan& right) const +@@ -59,7 +47,7 @@ bool CDateTimeSpan::operator >=(const CDateTimeSpan& right) const + + bool CDateTimeSpan::operator <(const CDateTimeSpan& right) const + { +- return KODI::TIME::CompareFileTime(&m_timeSpan, &right.m_timeSpan) < 0; ++ return m_timeSpan < right.m_timeSpan; + } + + bool CDateTimeSpan::operator <=(const CDateTimeSpan& right) const +@@ -69,7 +57,7 @@ bool CDateTimeSpan::operator <=(const CDateTimeSpan& right) const + + bool CDateTimeSpan::operator ==(const CDateTimeSpan& right) const + { +- return KODI::TIME::CompareFileTime(&m_timeSpan, &right.m_timeSpan) == 0; ++ return m_timeSpan == right.m_timeSpan; + } + + bool CDateTimeSpan::operator !=(const CDateTimeSpan& right) const +@@ -81,15 +69,7 @@ CDateTimeSpan CDateTimeSpan::operator +(const CDateTimeSpan& right) const + { + CDateTimeSpan left(*this); + +- LARGE_INTEGER timeLeft; +- left.ToLargeInt(timeLeft); +- +- LARGE_INTEGER timeRight; +- right.ToLargeInt(timeRight); +- +- timeLeft.QuadPart+=timeRight.QuadPart; +- +- left.FromLargeInt(timeLeft); ++ left.m_timeSpan += right.m_timeSpan; + + return left; + } +@@ -98,122 +78,75 @@ CDateTimeSpan CDateTimeSpan::operator -(const CDateTimeSpan& right) const + { + CDateTimeSpan left(*this); + +- LARGE_INTEGER timeLeft; +- left.ToLargeInt(timeLeft); +- +- LARGE_INTEGER timeRight; +- right.ToLargeInt(timeRight); +- +- timeLeft.QuadPart-=timeRight.QuadPart; +- +- left.FromLargeInt(timeLeft); ++ left.m_timeSpan -= right.m_timeSpan; + + return left; + } + + const CDateTimeSpan& CDateTimeSpan::operator +=(const CDateTimeSpan& right) + { +- LARGE_INTEGER timeThis; +- ToLargeInt(timeThis); +- +- LARGE_INTEGER timeRight; +- right.ToLargeInt(timeRight); +- +- timeThis.QuadPart+=timeRight.QuadPart; +- +- FromLargeInt(timeThis); ++ m_timeSpan += right.m_timeSpan; + + return *this; + } + + const CDateTimeSpan& CDateTimeSpan::operator -=(const CDateTimeSpan& right) + { +- LARGE_INTEGER timeThis; +- ToLargeInt(timeThis); +- +- LARGE_INTEGER timeRight; +- right.ToLargeInt(timeRight); +- +- timeThis.QuadPart-=timeRight.QuadPart; +- +- FromLargeInt(timeThis); ++ m_timeSpan -= right.m_timeSpan; + + return *this; + } + +-void CDateTimeSpan::ToLargeInt(LARGE_INTEGER& time) const +-{ +- time.u.HighPart = m_timeSpan.highDateTime; +- time.u.LowPart = m_timeSpan.lowDateTime; +-} +- +-void CDateTimeSpan::FromLargeInt(const LARGE_INTEGER& time) +-{ +- m_timeSpan.highDateTime = time.u.HighPart; +- m_timeSpan.lowDateTime = time.u.LowPart; +-} +- + void CDateTimeSpan::SetDateTimeSpan(int day, int hour, int minute, int second) + { +- LARGE_INTEGER time; +- ToLargeInt(time); +- +- time.QuadPart= static_cast<long long>(day) *SECONDS_PER_DAY*SECONDS_TO_FILETIME; +- time.QuadPart+= static_cast<long long>(hour) *SECONDS_PER_HOUR*SECONDS_TO_FILETIME; +- time.QuadPart+= static_cast<long long>(minute) *SECONDS_PER_MINUTE*SECONDS_TO_FILETIME; +- time.QuadPart+= static_cast<long long>(second) *SECONDS_TO_FILETIME; +- +- FromLargeInt(time); ++ m_timeSpan = std::chrono::duration_cast<std::chrono::seconds>(date::days(day)) + ++ std::chrono::duration_cast<std::chrono::seconds>(std::chrono::hours(hour)) + ++ std::chrono::duration_cast<std::chrono::seconds>(std::chrono::minutes(minute)) + ++ std::chrono::duration_cast<std::chrono::seconds>(std::chrono::seconds(second)); + } + + void CDateTimeSpan::SetFromTimeString(const std::string& time) // hh:mm + { + if (time.size() >= 5 && time[2] == ':') + { +- int hour = atoi(time.substr(0, 2).c_str()); +- int minutes = atoi(time.substr(3, 2).c_str()); +- SetDateTimeSpan(0,hour,minutes,0); ++ int hour = std::stoi(time.substr(0, 2)); ++ int minutes = std::stoi(time.substr(3, 2)); ++ SetDateTimeSpan(0, hour, minutes, 0); + } + } + + int CDateTimeSpan::GetDays() const + { +- LARGE_INTEGER time; +- ToLargeInt(time); +- +- return (int)(time.QuadPart/SECONDS_TO_FILETIME)/SECONDS_PER_DAY; ++ return date::floor<date::days>(m_timeSpan).count(); + } + + int CDateTimeSpan::GetHours() const + { +- LARGE_INTEGER time; +- ToLargeInt(time); ++ auto time = date::floor<date::days>(m_timeSpan); ++ auto dp = date::make_time(m_timeSpan - time); + +- return (int)((time.QuadPart/SECONDS_TO_FILETIME)%SECONDS_PER_DAY)/SECONDS_PER_HOUR; ++ return dp.hours().count(); + } + + int CDateTimeSpan::GetMinutes() const + { +- LARGE_INTEGER time; +- ToLargeInt(time); ++ auto time = date::floor<date::days>(m_timeSpan); ++ auto dp = date::make_time(m_timeSpan - time); + +- return (int)((time.QuadPart/SECONDS_TO_FILETIME%SECONDS_PER_DAY)%SECONDS_PER_HOUR)/SECONDS_PER_MINUTE; ++ return dp.minutes().count(); + } + + int CDateTimeSpan::GetSeconds() const + { +- LARGE_INTEGER time; +- ToLargeInt(time); ++ auto time = date::floor<date::days>(m_timeSpan); ++ auto dp = date::make_time(m_timeSpan - time); + +- return (int)(((time.QuadPart/SECONDS_TO_FILETIME%SECONDS_PER_DAY)%SECONDS_PER_HOUR)%SECONDS_PER_MINUTE)%SECONDS_PER_MINUTE; ++ return dp.seconds().count(); + } + + int CDateTimeSpan::GetSecondsTotal() const + { +- LARGE_INTEGER time; +- ToLargeInt(time); +- +- return (int)(time.QuadPart/SECONDS_TO_FILETIME); ++ return std::chrono::duration_cast<std::chrono::seconds>(m_timeSpan).count(); + } + + void CDateTimeSpan::SetFromPeriod(const std::string &period) +@@ -233,25 +166,26 @@ void CDateTimeSpan::SetFromPeriod(const std::string &period) + SetDateTimeSpan(days, 0, 0, 0); + } + +-///////////////////////////////////////////////// +-// +-// CDateTime +-// +- + CDateTime::CDateTime() + { + Reset(); + } + +-CDateTime::CDateTime(const KODI::TIME::SystemTime& time) ++CDateTime::CDateTime(const KODI::TIME::SystemTime& systemTime) + { +- // we store internally as a FileTime +- m_state = ToFileTime(time, m_time) ? valid : invalid; ++ KODI::TIME::FileTime fileTime; ++ m_state = ToFileTime(systemTime, fileTime) ? valid : invalid; ++ ++ time_t time; ++ KODI::TIME::FileTimeToTimeT(&fileTime, &time); ++ m_time = std::chrono::system_clock::from_time_t(time); + } + +-CDateTime::CDateTime(const KODI::TIME::FileTime& time) : m_time(time) ++CDateTime::CDateTime(const KODI::TIME::FileTime& fileTime) + { +- SetValid(true); ++ time_t time; ++ KODI::TIME::FileTimeToTimeT(&fileTime, &time); ++ m_time = std::chrono::system_clock::from_time_t(time); + } + + CDateTime::CDateTime(const CDateTime& time) : m_time(time.m_time) +@@ -261,12 +195,20 @@ CDateTime::CDateTime(const CDateTime& time) : m_time(time.m_time) + + CDateTime::CDateTime(const time_t& time) + { +- m_state = ToFileTime(time, m_time) ? valid : invalid; ++ m_time = std::chrono::system_clock::from_time_t(time); ++ SetValid(true); ++} ++ ++CDateTime::CDateTime(const std::chrono::system_clock::time_point& time) ++{ ++ m_time = time; ++ SetValid(true); + } + + CDateTime::CDateTime(const tm& time) + { +- m_state = ToFileTime(time, m_time) ? valid : invalid; ++ m_time = std::chrono::system_clock::from_time_t(std::mktime(const_cast<tm*>(&time))); ++ SetValid(true); + } + + CDateTime::CDateTime(int year, int month, int day, int hour, int minute, int second) +@@ -276,52 +218,66 @@ CDateTime::CDateTime(int year, int month, int day, int hour, int minute, int sec + + CDateTime CDateTime::GetCurrentDateTime() + { +- // get the current time +- KODI::TIME::SystemTime time; +- KODI::TIME::GetLocalTime(&time); ++ auto zone = date::make_zoned(date::current_zone(), std::chrono::system_clock::now()); + +- return CDateTime(time); ++ return CDateTime( ++ std::chrono::duration_cast<std::chrono::seconds>(zone.get_local_time().time_since_epoch()) ++ .count()); + } + + CDateTime CDateTime::GetUTCDateTime() + { +- CDateTime time(GetCurrentDateTime()); +- time += GetTimezoneBias(); +- return time; ++ return CDateTime(std::chrono::system_clock::now()); + } + + const CDateTime& CDateTime::operator=(const KODI::TIME::SystemTime& right) + { +- m_state = ToFileTime(right, m_time) ? valid : invalid; ++ KODI::TIME::FileTime fileTime; ++ m_state = ToFileTime(right, fileTime) ? valid : invalid; ++ ++ time_t time; ++ KODI::TIME::FileTimeToTimeT(&fileTime, &time); ++ m_time = std::chrono::system_clock::from_time_t(time); + + return *this; + } + + const CDateTime& CDateTime::operator=(const KODI::TIME::FileTime& right) + { +- m_time=right; +- SetValid(true); ++ time_t time; ++ KODI::TIME::FileTimeToTimeT(&right, &time); ++ m_time = std::chrono::system_clock::from_time_t(time); + + return *this; + } + + const CDateTime& CDateTime::operator =(const time_t& right) + { +- m_state = ToFileTime(right, m_time) ? valid : invalid; ++ m_time = std::chrono::system_clock::from_time_t(right); ++ SetValid(true); + + return *this; + } + + const CDateTime& CDateTime::operator =(const tm& right) + { +- m_state = ToFileTime(right, m_time) ? valid : invalid; ++ m_time = std::chrono::system_clock::from_time_t(std::mktime(const_cast<tm*>(&right))); ++ SetValid(true); ++ ++ return *this; ++} ++ ++const CDateTime& CDateTime::operator=(const std::chrono::system_clock::time_point& right) ++{ ++ m_time = right; ++ SetValid(true); + + return *this; + } + + bool CDateTime::operator >(const CDateTime& right) const + { +- return operator >(right.m_time); ++ return m_time > right.m_time; + } + + bool CDateTime::operator >=(const CDateTime& right) const +@@ -331,7 +287,7 @@ bool CDateTime::operator >=(const CDateTime& right) const + + bool CDateTime::operator <(const CDateTime& right) const + { +- return operator <(right.m_time); ++ return m_time < right.m_time; + } + + bool CDateTime::operator <=(const CDateTime& right) const +@@ -341,7 +297,7 @@ bool CDateTime::operator <=(const CDateTime& right) const + + bool CDateTime::operator ==(const CDateTime& right) const + { +- return operator ==(right.m_time); ++ return m_time == right.m_time; + } + + bool CDateTime::operator !=(const CDateTime& right) const +@@ -351,7 +307,10 @@ bool CDateTime::operator !=(const CDateTime& right) const + + bool CDateTime::operator>(const KODI::TIME::FileTime& right) const + { +- return KODI::TIME::CompareFileTime(&m_time, &right) > 0; ++ time_t time; ++ KODI::TIME::FileTimeToTimeT(&right, &time); ++ ++ return m_time > std::chrono::system_clock::from_time_t(time); + } + + bool CDateTime::operator>=(const KODI::TIME::FileTime& right) const +@@ -361,7 +320,10 @@ bool CDateTime::operator>=(const KODI::TIME::FileTime& right) const + + bool CDateTime::operator<(const KODI::TIME::FileTime& right) const + { +- return KODI::TIME::CompareFileTime(&m_time, &right) < 0; ++ time_t time; ++ KODI::TIME::FileTimeToTimeT(&right, &time); ++ ++ return m_time < std::chrono::system_clock::from_time_t(time); + } + + bool CDateTime::operator<=(const KODI::TIME::FileTime& right) const +@@ -371,7 +333,10 @@ bool CDateTime::operator<=(const KODI::TIME::FileTime& right) const + + bool CDateTime::operator==(const KODI::TIME::FileTime& right) const + { +- return KODI::TIME::CompareFileTime(&m_time, &right) == 0; ++ time_t time; ++ KODI::TIME::FileTimeToTimeT(&right, &time); ++ ++ return m_time == std::chrono::system_clock::from_time_t(time); + } + + bool CDateTime::operator!=(const KODI::TIME::FileTime& right) const +@@ -420,10 +385,7 @@ bool CDateTime::operator!=(const KODI::TIME::SystemTime& right) const + + bool CDateTime::operator >(const time_t& right) const + { +- KODI::TIME::FileTime time; +- ToFileTime(right, time); +- +- return operator >(time); ++ return m_time > std::chrono::system_clock::from_time_t(right); + } + + bool CDateTime::operator >=(const time_t& right) const +@@ -433,10 +395,7 @@ bool CDateTime::operator >=(const time_t& right) const + + bool CDateTime::operator <(const time_t& right) const + { +- KODI::TIME::FileTime time; +- ToFileTime(right, time); +- +- return operator <(time); ++ return m_time < std::chrono::system_clock::from_time_t(right); + } + + bool CDateTime::operator <=(const time_t& right) const +@@ -446,10 +405,7 @@ bool CDateTime::operator <=(const time_t& right) const + + bool CDateTime::operator ==(const time_t& right) const + { +- KODI::TIME::FileTime time; +- ToFileTime(right, time); +- +- return operator ==(time); ++ return m_time == std::chrono::system_clock::from_time_t(right); + } + + bool CDateTime::operator !=(const time_t& right) const +@@ -459,10 +415,7 @@ bool CDateTime::operator !=(const time_t& right) const + + bool CDateTime::operator >(const tm& right) const + { +- KODI::TIME::FileTime time; +- ToFileTime(right, time); +- +- return operator >(time); ++ return m_time > std::chrono::system_clock::from_time_t(std::mktime(const_cast<tm*>(&right))); + } + + bool CDateTime::operator >=(const tm& right) const +@@ -472,10 +425,7 @@ bool CDateTime::operator >=(const tm& right) const + + bool CDateTime::operator <(const tm& right) const + { +- KODI::TIME::FileTime time; +- ToFileTime(right, time); +- +- return operator <(time); ++ return m_time < std::chrono::system_clock::from_time_t(std::mktime(const_cast<tm*>(&right))); + } + + bool CDateTime::operator <=(const tm& right) const +@@ -485,10 +435,7 @@ bool CDateTime::operator <=(const tm& right) const + + bool CDateTime::operator ==(const tm& right) const + { +- KODI::TIME::FileTime time; +- ToFileTime(right, time); +- +- return operator ==(time); ++ return m_time == std::chrono::system_clock::from_time_t(std::mktime(const_cast<tm*>(&right))); + } + + bool CDateTime::operator !=(const tm& right) const +@@ -496,66 +443,64 @@ bool CDateTime::operator !=(const tm& right) const + return !operator ==(right); + } + +-CDateTime CDateTime::operator +(const CDateTimeSpan& right) const ++bool CDateTime::operator>(const std::chrono::system_clock::time_point& right) const + { +- CDateTime left(*this); ++ return m_time > right; ++} + +- LARGE_INTEGER timeLeft; +- left.ToLargeInt(timeLeft); ++bool CDateTime::operator>=(const std::chrono::system_clock::time_point& right) const ++{ ++ return operator>(right) || operator==(right); ++} + +- LARGE_INTEGER timeRight; +- right.ToLargeInt(timeRight); ++bool CDateTime::operator<(const std::chrono::system_clock::time_point& right) const ++{ ++ return m_time < right; ++} + +- timeLeft.QuadPart+=timeRight.QuadPart; ++bool CDateTime::operator<=(const std::chrono::system_clock::time_point& right) const ++{ ++ return operator<(right) || operator==(right); ++} + +- left.FromLargeInt(timeLeft); ++bool CDateTime::operator==(const std::chrono::system_clock::time_point& right) const ++{ ++ return m_time == right; ++} + +- return left; ++bool CDateTime::operator!=(const std::chrono::system_clock::time_point& right) const ++{ ++ return !operator==(right); + } + +-CDateTime CDateTime::operator -(const CDateTimeSpan& right) const ++CDateTime CDateTime::operator+(const CDateTimeSpan& right) const + { + CDateTime left(*this); + +- LARGE_INTEGER timeLeft; +- left.ToLargeInt(timeLeft); ++ left.m_time + right.m_timeSpan; + +- LARGE_INTEGER timeRight; +- right.ToLargeInt(timeRight); ++ return left; ++} + +- timeLeft.QuadPart-=timeRight.QuadPart; ++CDateTime CDateTime::operator-(const CDateTimeSpan& right) const ++{ ++ CDateTime left(*this); + +- left.FromLargeInt(timeLeft); ++ left.m_time - right.m_timeSpan; + + return left; + } + + const CDateTime& CDateTime::operator +=(const CDateTimeSpan& right) + { +- LARGE_INTEGER timeThis; +- ToLargeInt(timeThis); +- +- LARGE_INTEGER timeRight; +- right.ToLargeInt(timeRight); +- +- timeThis.QuadPart+=timeRight.QuadPart; +- +- FromLargeInt(timeThis); ++ m_time += right.m_timeSpan; + + return *this; + } + + const CDateTime& CDateTime::operator -=(const CDateTimeSpan& right) + { +- LARGE_INTEGER timeThis; +- ToLargeInt(timeThis); +- +- LARGE_INTEGER timeRight; +- right.ToLargeInt(timeRight); +- +- timeThis.QuadPart-=timeRight.QuadPart; +- +- FromLargeInt(timeThis); ++ m_time -= right.m_timeSpan; + + return *this; + } +@@ -564,25 +509,16 @@ CDateTimeSpan CDateTime::operator -(const CDateTime& right) const + { + CDateTimeSpan left; + +- LARGE_INTEGER timeLeft; +- left.ToLargeInt(timeLeft); +- +- LARGE_INTEGER timeThis; +- ToLargeInt(timeThis); +- +- LARGE_INTEGER timeRight; +- right.ToLargeInt(timeRight); +- +- timeLeft.QuadPart=timeThis.QuadPart-timeRight.QuadPart; +- +- left.FromLargeInt(timeLeft); +- ++ left.m_timeSpan = std::chrono::duration_cast<std::chrono::seconds>(m_time - right.m_time); + return left; + } + + CDateTime::operator KODI::TIME::FileTime() const + { +- return m_time; ++ KODI::TIME::FileTime fileTime; ++ time_t time = std::chrono::system_clock::to_time_t(m_time); ++ KODI::TIME::TimeTToFileTime(time, &fileTime); ++ return fileTime; + } + + void CDateTime::Archive(CArchive& ar) +@@ -607,25 +543,38 @@ void CDateTime::Archive(CArchive& ar) + { + KODI::TIME::SystemTime st; + ar>>st; +- ToFileTime(st, m_time); ++ ToTimePoint(st, m_time); + } + } + } + + void CDateTime::Reset() + { +- SetDateTime(1601, 1, 1, 0, 0, 0); ++ m_time = {}; + SetValid(false); + } + + void CDateTime::SetValid(bool yesNo) + { +- m_state=yesNo ? valid : invalid; ++ m_state = yesNo ? valid : invalid; + } + + bool CDateTime::IsValid() const + { +- return m_state==valid; ++ return m_state == valid; ++} ++ ++bool CDateTime::ToTimePoint(const KODI::TIME::SystemTime& systemTime, ++ std::chrono::system_clock::time_point& timePoint) const ++{ ++ KODI::TIME::FileTime fileTime; ++ KODI::TIME::SystemTimeToFileTime(&systemTime, &fileTime); ++ ++ time_t time; ++ KODI::TIME::FileTimeToTimeT(&fileTime, &time); ++ ++ timePoint = std::chrono::system_clock::from_time_t(time); ++ return true; + } + + bool CDateTime::ToFileTime(const KODI::TIME::SystemTime& time, KODI::TIME::FileTime& fileTime) const +@@ -646,33 +595,6 @@ bool CDateTime::ToFileTime(const time_t& time, KODI::TIME::FileTime& fileTime) c + return true; + } + +-bool CDateTime::ToFileTime(const tm& time, KODI::TIME::FileTime& fileTime) const +-{ +- KODI::TIME::SystemTime st = {}; +- +- st.year = time.tm_year + 1900; +- st.month = time.tm_mon + 1; +- st.dayOfWeek = time.tm_wday; +- st.day = time.tm_mday; +- st.hour = time.tm_hour; +- st.minute = time.tm_min; +- st.second = time.tm_sec; +- +- return SystemTimeToFileTime(&st, &fileTime) == 1; +-} +- +-void CDateTime::ToLargeInt(LARGE_INTEGER& time) const +-{ +- time.u.HighPart = m_time.highDateTime; +- time.u.LowPart = m_time.lowDateTime; +-} +- +-void CDateTime::FromLargeInt(const LARGE_INTEGER& time) +-{ +- m_time.highDateTime = time.u.HighPart; +- m_time.lowDateTime = time.u.LowPart; +-} +- + bool CDateTime::SetFromDateString(const std::string &date) + { + //! @todo STRING_CLEANUP +@@ -714,80 +636,83 @@ bool CDateTime::SetFromDateString(const std::string &date) + + int CDateTime::GetDay() const + { +- KODI::TIME::SystemTime st; +- GetAsSystemTime(st); ++ auto dp = date::floor<date::days>(m_time); ++ auto ymd = date::year_month_day{dp}; + +- return st.day; ++ return static_cast<unsigned int>(ymd.day()); + } + + int CDateTime::GetMonth() const + { +- KODI::TIME::SystemTime st; +- GetAsSystemTime(st); ++ auto dp = date::floor<date::days>(m_time); ++ auto ymd = date::year_month_day{dp}; + +- return st.month; ++ return static_cast<unsigned int>(ymd.month()); + } + + int CDateTime::GetYear() const + { +- KODI::TIME::SystemTime st; +- GetAsSystemTime(st); ++ auto dp = date::floor<date::days>(m_time); ++ auto ymd = date::year_month_day{dp}; + +- return st.year; ++ return static_cast<int>(ymd.year()); + } + + int CDateTime::GetHour() const + { +- KODI::TIME::SystemTime st; +- GetAsSystemTime(st); ++ auto dp = date::floor<date::days>(m_time); ++ auto time = date::make_time(m_time - dp); + +- return st.hour; ++ return time.hours().count(); + } + + int CDateTime::GetMinute() const + { +- KODI::TIME::SystemTime st; +- GetAsSystemTime(st); ++ auto dp = date::floor<date::days>(m_time); ++ auto time = date::make_time(m_time - dp); + +- return st.minute; ++ return time.minutes().count(); + } + + int CDateTime::GetSecond() const + { +- KODI::TIME::SystemTime st; +- GetAsSystemTime(st); ++ auto dp = date::floor<date::days>(m_time); ++ auto time = date::make_time(m_time - dp); + +- return st.second; ++ return time.seconds().count(); + } + + int CDateTime::GetDayOfWeek() const + { +- KODI::TIME::SystemTime st; +- GetAsSystemTime(st); ++ auto dp = date::floor<date::days>(m_time); ++ auto yww = iso_week::year_weeknum_weekday{dp}; + +- return st.dayOfWeek; ++ return static_cast<unsigned int>(yww.weekday()); + } + + int CDateTime::GetMinuteOfDay() const + { +- KODI::TIME::SystemTime st; +- GetAsSystemTime(st); +- return st.hour * 60 + st.minute; ++ auto dp = date::floor<std::chrono::hours>(m_time); ++ ; ++ auto time = date::make_time(m_time - dp); ++ ++ return time.hours().count() * 60 + time.minutes().count(); + } + + bool CDateTime::SetDateTime(int year, int month, int day, int hour, int minute, int second) + { +- KODI::TIME::SystemTime st = {}; ++ auto ymd = date::year(year) / month / day; ++ if (!ymd.ok()) ++ { ++ SetValid(false); ++ return false; ++ } + +- st.year = year; +- st.month = month; +- st.day = day; +- st.hour = hour; +- st.minute = minute; +- st.second = second; ++ m_time = date::sys_days(ymd) + std::chrono::hours(hour) + std::chrono::minutes(minute) + ++ std::chrono::seconds(second); + +- m_state = ToFileTime(st, m_time) ? valid : invalid; +- return m_state == valid; ++ SetValid(true); ++ return true; + } + + bool CDateTime::SetDate(int year, int month, int day) +@@ -797,119 +722,75 @@ bool CDateTime::SetDate(int year, int month, int day) + + bool CDateTime::SetTime(int hour, int minute, int second) + { +- // 01.01.1601 00:00:00 is 0 as filetime +- return SetDateTime(1601, 1, 1, hour, minute, second); ++ m_time = date::sys_seconds(std::chrono::seconds(0)) + std::chrono::hours(hour) + ++ std::chrono::minutes(minute) + std::chrono::seconds(second); ++ ++ SetValid(true); ++ return true; + } + +-void CDateTime::GetAsSystemTime(KODI::TIME::SystemTime& time) const ++void CDateTime::GetAsSystemTime(KODI::TIME::SystemTime& systemTime) const + { +- FileTimeToSystemTime(&m_time, &time); ++ const time_t time = std::chrono::system_clock::to_time_t(m_time); ++ KODI::TIME::FileTime fileTime; ++ ToFileTime(time, fileTime); ++ KODI::TIME::FileTimeToSystemTime(&fileTime, &systemTime); + } + +-#define UNIX_BASE_TIME 116444736000000000LL /* nanoseconds since epoch */ + void CDateTime::GetAsTime(time_t& time) const + { +- long long ll = (static_cast<long long>(m_time.highDateTime) << 32) + m_time.lowDateTime; +- time=(time_t)((ll - UNIX_BASE_TIME) / 10000000); ++ time = std::chrono::system_clock::to_time_t(m_time); + } + + void CDateTime::GetAsTm(tm& time) const + { +- KODI::TIME::SystemTime st; +- GetAsSystemTime(st); ++ auto t = std::chrono::system_clock::to_time_t(m_time); + + time = {}; +- time.tm_year = st.year - 1900; +- time.tm_mon = st.month - 1; +- time.tm_wday = st.dayOfWeek; +- time.tm_mday = st.day; +- time.tm_hour = st.hour; +- time.tm_min = st.minute; +- time.tm_sec = st.second; +- time.tm_isdst = -1; +- +- mktime(&time); ++ localtime_r(&t, &time); + } + +-void CDateTime::GetAsTimeStamp(KODI::TIME::FileTime& time) const ++std::chrono::system_clock::time_point CDateTime::GetAsTimePoint() const + { +- KODI::TIME::LocalFileTimeToFileTime(&m_time, &time); ++ return m_time; + } + ++// void CDateTime::GetAsTimeStamp(KODI::TIME::FileTime& fileTime) const ++// { ++// time_t time = std::chrono::system_clock::to_time_t(m_time); ++// KODI::TIME::TimeTToFileTime(time, &fileTime); ++// } ++ + std::string CDateTime::GetAsDBDate() const + { +- KODI::TIME::SystemTime st; +- GetAsSystemTime(st); +- +- return StringUtils::Format("{:04}-{:02}-{:02}", st.year, st.month, st.day); ++ return date::format("%F", m_time); + } + + std::string CDateTime::GetAsDBTime() const + { +- KODI::TIME::SystemTime st; +- GetAsSystemTime(st); +- +- return StringUtils::Format("{:02}:{:02}:{:02}", st.hour, st.minute, st.second); ++ auto sp = date::floor<std::chrono::seconds>(m_time); ++ return date::format("%T", sp); + } + + std::string CDateTime::GetAsDBDateTime() const + { +- KODI::TIME::SystemTime st; +- GetAsSystemTime(st); ++ auto sp = date::floor<std::chrono::seconds>(m_time); + +- return StringUtils::Format("{:04}-{:02}-{:02} {:02}:{:02}:{:02}", st.year, st.month, st.day, +- st.hour, st.minute, st.second); ++ return date::format("%F %T", sp); + } + + std::string CDateTime::GetAsSaveString() const + { +- KODI::TIME::SystemTime st; +- GetAsSystemTime(st); ++ auto sp = date::floor<std::chrono::seconds>(m_time); + +- return StringUtils::Format("{:04}{:02}{:02}_{:02}{:02}{:02}", st.year, st.month, st.day, st.hour, +- st.minute, st.second); ++ return date::format("%Y%m%d_%H%M%S", sp); + } + + bool CDateTime::SetFromUTCDateTime(const CDateTime &dateTime) + { +- CDateTime tmp(dateTime); +- tmp -= GetTimezoneBias(); +- +- m_time = tmp.m_time; +- m_state = tmp.m_state; +- return m_state == valid; +-} +- +-static bool bGotTimezoneBias = false; +- +-void CDateTime::ResetTimezoneBias(void) +-{ +- bGotTimezoneBias = false; +-} +- +-CDateTimeSpan CDateTime::GetTimezoneBias(void) +-{ +- static CDateTimeSpan timezoneBias; +- +- if (!bGotTimezoneBias) +- { +- bGotTimezoneBias = true; +- KODI::TIME::TimeZoneInformation tz; +- switch (KODI::TIME::GetTimeZoneInformation(&tz)) +- { +- case KODI::TIME::KODI_TIME_ZONE_ID_DAYLIGHT: +- timezoneBias = CDateTimeSpan(0, 0, tz.bias + tz.daylightBias, 0); +- break; +- case KODI::TIME::KODI_TIME_ZONE_ID_STANDARD: +- timezoneBias = CDateTimeSpan(0, 0, tz.bias + tz.standardBias, 0); +- break; +- case KODI::TIME::KODI_TIME_ZONE_ID_UNKNOWN: +- timezoneBias = CDateTimeSpan(0, 0, tz.bias, 0); +- break; +- } +- } +- +- return timezoneBias; ++ m_time = dateTime.m_time; ++ m_state = valid; ++ return true; + } + + bool CDateTime::SetFromUTCDateTime(const time_t &dateTime) +@@ -1511,60 +1392,31 @@ std::string CDateTime::GetAsLocalizedTime(TIME_FORMAT format, bool withSeconds / + CDateTime CDateTime::GetAsUTCDateTime() const + { + CDateTime time(m_time); +- time += GetTimezoneBias(); + return time; + } + + std::string CDateTime::GetAsRFC1123DateTime() const + { +- CDateTime time(GetAsUTCDateTime()); ++ auto time = date::floor<std::chrono::seconds>(m_time); + +- int weekDay = time.GetDayOfWeek(); +- if (weekDay < 0) +- weekDay = 0; +- else if (weekDay > 6) +- weekDay = 6; +- if (weekDay != time.GetDayOfWeek()) +- CLog::Log(LOGWARNING, "Invalid day of week {} in {}", time.GetDayOfWeek(), +- time.GetAsDBDateTime()); +- +- int month = time.GetMonth(); +- if (month < 1) +- month = 1; +- else if (month > 12) +- month = 12; +- if (month != time.GetMonth()) +- CLog::Log(LOGWARNING, "Invalid month {} in {}", time.GetMonth(), time.GetAsDBDateTime()); +- +- return StringUtils::Format("{}, {:02} {} {:04} {:02}:{:02}:{:02} GMT", DAY_NAMES[weekDay], +- time.GetDay(), MONTH_NAMES[month - 1], time.GetYear(), time.GetHour(), +- time.GetMinute(), time.GetSecond()); ++ return date::format("%a, %d %b %Y %T GMT", time); + } + + std::string CDateTime::GetAsW3CDate() const + { +- KODI::TIME::SystemTime st; +- GetAsSystemTime(st); +- +- return StringUtils::Format("{:04}-{:02}-{:02}", st.year, st.month, st.day); ++ return GetAsDBDate(); + } + + std::string CDateTime::GetAsW3CDateTime(bool asUtc /* = false */) const + { +- CDateTime w3cDate = *this; +- if (asUtc) +- w3cDate = GetAsUTCDateTime(); +- KODI::TIME::SystemTime st; +- w3cDate.GetAsSystemTime(st); ++ auto time = date::floor<std::chrono::seconds>(m_time); + +- std::string result = StringUtils::Format("{:04}-{:02}-{:02}T{:02}:{:02}:{:02}", st.year, st.month, +- st.day, st.hour, st.minute, st.second); + if (asUtc) +- return result + "Z"; ++ return date::format("%FT%TZ", time); ++ ++ auto zt = date::make_zoned(date::current_zone(), time); + +- CDateTimeSpan bias = GetTimezoneBias(); +- return result + StringUtils::Format("{}{:02}:{:02}", (bias.GetSecondsTotal() >= 0 ? '+' : '-'), +- abs(bias.GetHours()), abs(bias.GetMinutes())); ++ return date::format("%FT%T%Ez", zt); + } + + int CDateTime::MonthStringToMonthNum(const std::string& month) +diff --git a/xbmc/XBDateTime.h b/xbmc/XBDateTime.h +index fb18e7c0de..60d06e417a 100644 +--- a/xbmc/XBDateTime.h ++++ b/xbmc/XBDateTime.h +@@ -12,6 +12,7 @@ + #include "utils/TimeFormat.h" + #include "utils/XTimeUtils.h" + ++#include <chrono> + #include <string> + + #include "PlatformDefs.h" +@@ -21,7 +22,7 @@ class CDateTime; + class CDateTimeSpan + { + public: +- CDateTimeSpan(); ++ CDateTimeSpan() = default; + CDateTimeSpan(const CDateTimeSpan& span); + CDateTimeSpan& operator=(const CDateTimeSpan&) = default; + CDateTimeSpan(int day, int hour, int minute, int second); +@@ -50,11 +51,7 @@ public: + int GetSecondsTotal() const; + + private: +- void ToLargeInt(LARGE_INTEGER& time) const; +- void FromLargeInt(const LARGE_INTEGER& time); +- +-private: +- KODI::TIME::FileTime m_timeSpan; ++ std::chrono::duration<int64_t> m_timeSpan{0}; + + friend class CDateTime; + }; +@@ -70,6 +67,7 @@ public: + explicit CDateTime(const KODI::TIME::FileTime& time); + explicit CDateTime(const time_t& time); + explicit CDateTime(const tm& time); ++ explicit CDateTime(const std::chrono::system_clock::time_point& time); + CDateTime(int year, int month, int day, int hour, int minute, int second); + + static CDateTime GetCurrentDateTime(); +@@ -90,6 +88,7 @@ public: + const CDateTime& operator=(const KODI::TIME::FileTime& right); + const CDateTime& operator =(const time_t& right); + const CDateTime& operator =(const tm& right); ++ const CDateTime& operator=(const std::chrono::system_clock::time_point& right); + + bool operator >(const CDateTime& right) const; + bool operator >=(const CDateTime& right) const; +@@ -126,6 +125,13 @@ public: + bool operator ==(const tm& right) const; + bool operator !=(const tm& right) const; + ++ bool operator>(const std::chrono::system_clock::time_point& right) const; ++ bool operator>=(const std::chrono::system_clock::time_point& right) const; ++ bool operator<(const std::chrono::system_clock::time_point& right) const; ++ bool operator<=(const std::chrono::system_clock::time_point& right) const; ++ bool operator==(const std::chrono::system_clock::time_point& right) const; ++ bool operator!=(const std::chrono::system_clock::time_point& right) const; ++ + CDateTime operator +(const CDateTimeSpan& right) const; + CDateTime operator -(const CDateTimeSpan& right) const; + +@@ -170,7 +176,7 @@ public: + void GetAsSystemTime(KODI::TIME::SystemTime& time) const; + void GetAsTime(time_t& time) const; + void GetAsTm(tm& time) const; +- void GetAsTimeStamp(KODI::TIME::FileTime& time) const; ++ std::chrono::system_clock::time_point GetAsTimePoint() const; + + CDateTime GetAsUTCDateTime() const; + std::string GetAsSaveString() const; +@@ -189,19 +195,14 @@ public: + void SetValid(bool yesNo); + bool IsValid() const; + +- static void ResetTimezoneBias(void); +- static CDateTimeSpan GetTimezoneBias(void); +- + private: ++ bool ToTimePoint(const KODI::TIME::SystemTime& time, ++ std::chrono::system_clock::time_point& timePoint) const; + bool ToFileTime(const KODI::TIME::SystemTime& time, KODI::TIME::FileTime& fileTime) const; + bool ToFileTime(const time_t& time, KODI::TIME::FileTime& fileTime) const; +- bool ToFileTime(const tm& time, KODI::TIME::FileTime& fileTime) const; +- +- void ToLargeInt(LARGE_INTEGER& time) const; +- void FromLargeInt(const LARGE_INTEGER& time); + + private: +- KODI::TIME::FileTime m_time; ++ std::chrono::system_clock::time_point m_time; + + typedef enum _STATE + { +diff --git a/xbmc/platform/posix/PosixTimezone.cpp b/xbmc/platform/posix/PosixTimezone.cpp +index 6f276a37b2..ab2ddcf570 100644 +--- a/xbmc/platform/posix/PosixTimezone.cpp ++++ b/xbmc/platform/posix/PosixTimezone.cpp +@@ -143,8 +143,6 @@ void CPosixTimezone::OnSettingChanged(const std::shared_ptr<const CSetting>& set + if (settingId == CSettings::SETTING_LOCALE_TIMEZONE) + { + SetTimezone(std::static_pointer_cast<const CSettingString>(setting)->GetValue()); +- +- CDateTime::ResetTimezoneBias(); + } + else if (settingId == CSettings::SETTING_LOCALE_TIMEZONECOUNTRY) + { +@@ -157,7 +155,6 @@ void CPosixTimezone::OnSettingChanged(const std::shared_ptr<const CSetting>& set + void CPosixTimezone::OnSettingsLoaded() + { + SetTimezone(CServiceBroker::GetSettingsComponent()->GetSettings()->GetString(CSettings::SETTING_LOCALE_TIMEZONE)); +- CDateTime::ResetTimezoneBias(); + } + + std::vector<std::string> CPosixTimezone::GetCounties() +diff --git a/xbmc/pvr/guilib/PVRGUIActionsDatabase.cpp b/xbmc/pvr/guilib/PVRGUIActionsDatabase.cpp +index 53bbf815f6..4ae42a4803 100644 +--- a/xbmc/pvr/guilib/PVRGUIActionsDatabase.cpp ++++ b/xbmc/pvr/guilib/PVRGUIActionsDatabase.cpp +@@ -205,8 +205,6 @@ bool CPVRGUIActionsDatabase::ResetDatabase(bool bResetEPGOnly) + bResetClients = selector.IsResetClientsSelected(); + } + +- CDateTime::ResetTimezoneBias(); +- + CLog::LogFC(LOGDEBUG, LOGPVR, "PVR clearing {} database", bResetEPGOnly ? "EPG" : "PVR and EPG"); + + pDlgProgress->SetHeading(CVariant{313}); // "Cleaning database" +-- +2.43.0 + + +From 8433756427c68642013698c678263b4d6ee5759d Mon Sep 17 00:00:00 2001 +From: Lukas Rusak <lorusak@gmail.com> +Date: Mon, 17 Feb 2020 22:40:56 -0800 +Subject: [PATCH 04/19] fix TestDateTime to work with std::chrono + +--- + xbmc/test/TestDateTime.cpp | 89 ++++++++------------------------------ + 1 file changed, 17 insertions(+), 72 deletions(-) + +diff --git a/xbmc/test/TestDateTime.cpp b/xbmc/test/TestDateTime.cpp +index 7e51df8cee..a553bd1887 100644 +--- a/xbmc/test/TestDateTime.cpp ++++ b/xbmc/test/TestDateTime.cpp +@@ -13,6 +13,10 @@ + #include <array> + #include <iostream> + ++#define USE_OS_TZDB 0 ++#define HAS_REMOTE_API 0 ++#include <date/date.h> ++#include <date/tz.h> + #include <gtest/gtest.h> + + class TestDateTime : public testing::Test +@@ -32,24 +36,6 @@ TEST_F(TestDateTime, DateTimeOperators) + EXPECT_FALSE(dateTime1 == dateTime2); + } + +-TEST_F(TestDateTime, FileTimeOperators) +-{ +- CDateTime dateTime1(1991, 5, 14, 12, 34, 56); +- CDateTime dateTime2(1991, 5, 14, 12, 34, 57); +- +- KODI::TIME::FileTime fileTime1; +- KODI::TIME::FileTime fileTime2; +- +- dateTime1.GetAsTimeStamp(fileTime1); +- dateTime2.GetAsTimeStamp(fileTime2); +- +- CDateTime dateTime3(fileTime1); +- +- EXPECT_TRUE(dateTime3 < fileTime2); +- EXPECT_FALSE(dateTime3 > fileTime2); +- EXPECT_FALSE(dateTime3 == fileTime2); +-} +- + TEST_F(TestDateTime, SystemTimeOperators) + { + CDateTime dateTime1(1991, 5, 14, 12, 34, 56); +@@ -161,7 +147,7 @@ TEST_F(TestDateTime, MonthStringToMonthNum) + } + + // this method is broken as SetFromDBDate() will return true +-TEST_F(TestDateTime, DISABLED_SetFromDateString) ++TEST_F(TestDateTime, SetFromDateString) + { + CDateTime dateTime; + EXPECT_TRUE(dateTime.SetFromDateString("tuesday may 14, 1991")); +@@ -190,13 +176,7 @@ TEST_F(TestDateTime, SetFromDBDate) + EXPECT_EQ(dateTime.GetDay(), 2); + } + +-// disabled on osx and freebsd as their mktime functions +-// don't work for dates before 1900 +-#if defined(TARGET_DARWIN_OSX) || defined(TARGET_FREEBSD) +-TEST_F(TestDateTime, DISABLED_SetFromDBTime) +-#else + TEST_F(TestDateTime, SetFromDBTime) +-#endif + { + CDateTime dateTime1; + EXPECT_TRUE(dateTime1.SetFromDBTime("12:34")); +@@ -237,10 +217,8 @@ TEST_F(TestDateTime, SetFromW3CDate) + + TEST_F(TestDateTime, SetFromW3CDateTime) + { +- CDateTimeSpan bias = CDateTime::GetTimezoneBias(); + CDateTime dateTime; + dateTime.SetFromDBDateTime("1994-11-05 13:15:30"); +- dateTime += bias; + std::string dateTimeStr = dateTime.GetAsDBDate() + "T" + dateTime.GetAsDBTime() + "Z"; + + CDateTime dateTime1; +@@ -264,11 +242,8 @@ TEST_F(TestDateTime, SetFromW3CDateTime) + + TEST_F(TestDateTime, SetFromUTCDateTime) + { +- CDateTimeSpan bias = CDateTime::GetTimezoneBias(); +- + CDateTime dateTime1; + dateTime1.SetFromDBDateTime("1991-05-14 12:34:56"); +- dateTime1 += bias; + + CDateTime dateTime2; + EXPECT_TRUE(dateTime2.SetFromUTCDateTime(dateTime1)); +@@ -279,7 +254,7 @@ TEST_F(TestDateTime, SetFromUTCDateTime) + EXPECT_EQ(dateTime2.GetMinute(), 34); + EXPECT_EQ(dateTime2.GetSecond(), 56); + +- const time_t time = 674224496 + bias.GetSecondsTotal(); ++ const time_t time = 674224496; + + CDateTime dateTime3; + EXPECT_TRUE(dateTime3.SetFromUTCDateTime(time)); +@@ -325,18 +300,14 @@ TEST_F(TestDateTime, SetDateTime) + EXPECT_EQ(dateTime2.GetMinute(), 0); + EXPECT_EQ(dateTime2.GetSecond(), 0); + +-// disabled on osx and freebsd as their mktime functions +-// don't work for dates before 1900 +-#if !defined(TARGET_DARWIN_OSX) && !defined(TARGET_FREEBSD) + CDateTime dateTime3; + EXPECT_TRUE(dateTime3.SetTime(12, 34, 56)); +- EXPECT_EQ(dateTime3.GetYear(), 1601); ++ EXPECT_EQ(dateTime3.GetYear(), 1970); + EXPECT_EQ(dateTime3.GetMonth(), 1); + EXPECT_EQ(dateTime3.GetDay(), 1); + EXPECT_EQ(dateTime3.GetHour(), 12); + EXPECT_EQ(dateTime3.GetMinute(), 34); + EXPECT_EQ(dateTime3.GetSecond(), 56); +-#endif + } + + TEST_F(TestDateTime, GetAsStrings) +@@ -351,22 +322,20 @@ TEST_F(TestDateTime, GetAsStrings) + EXPECT_EQ(dateTime.GetAsW3CDate(), "1991-05-14"); + } + +-// disabled because we have no way to validate these values +-// GetTimezoneBias() always returns a positive value so +-// there is no way to detect the direction of the offset +-TEST_F(TestDateTime, DISABLED_GetAsStringsWithBias) ++TEST_F(TestDateTime, GetAsStringsWithBias) + { +- CDateTimeSpan bias = CDateTime::GetTimezoneBias(); +- + CDateTime dateTime; + dateTime.SetDateTime(1991, 05, 14, 12, 34, 56); + +- CDateTime dateTimeWithBias(dateTime); +- dateTimeWithBias += bias; ++ std::cout << dateTime.GetAsRFC1123DateTime() << std::endl; ++ std::cout << dateTime.GetAsW3CDateTime(false) << std::endl; ++ std::cout << dateTime.GetAsW3CDateTime(true) << std::endl; + +- EXPECT_EQ(dateTime.GetAsRFC1123DateTime(), "Tue, 14 May 1991 20:34:56 GMT"); +- EXPECT_EQ(dateTime.GetAsW3CDateTime(false), "1991-05-14T12:34:56+08:00"); +- EXPECT_EQ(dateTime.GetAsW3CDateTime(true), "1991-05-14T20:34:56Z"); ++ auto zone = date::make_zoned(date::current_zone(), dateTime.GetAsTimePoint()); ++ ++ EXPECT_EQ(dateTime.GetAsRFC1123DateTime(), "Tue, 14 May 1991 12:34:56 GMT"); ++ EXPECT_EQ(dateTime.GetAsW3CDateTime(false), "1991-05-14T05:34:56" + date::format("%Ez", zone)); ++ EXPECT_EQ(dateTime.GetAsW3CDateTime(true), "1991-05-14T12:34:56Z"); + } + + TEST_F(TestDateTime, GetAsLocalized) +@@ -604,31 +573,13 @@ TEST_F(TestDateTime, GetAsTm) + } + } + +-// Disabled pending std::chrono and std::date changes. +-TEST_F(TestDateTime, DISABLED_GetAsTimeStamp) +-{ +- CDateTimeSpan bias = CDateTime::GetTimezoneBias(); +- +- CDateTime dateTime; +- dateTime.SetDateTime(1991, 05, 14, 12, 34, 56); +- +- KODI::TIME::FileTime fileTime; +- dateTime.GetAsTimeStamp(fileTime); +- dateTime += bias; +- +- EXPECT_TRUE(dateTime == fileTime); +-} +- + TEST_F(TestDateTime, GetAsUTCDateTime) + { +- CDateTimeSpan bias = CDateTime::GetTimezoneBias(); +- + CDateTime dateTime1; + dateTime1.SetDateTime(1991, 05, 14, 12, 34, 56); + + CDateTime dateTime2; + dateTime2 = dateTime1.GetAsUTCDateTime(); +- dateTime2 -= bias; + + EXPECT_EQ(dateTime2.GetYear(), 1991); + EXPECT_EQ(dateTime2.GetMonth(), 5); +@@ -638,20 +589,14 @@ TEST_F(TestDateTime, GetAsUTCDateTime) + EXPECT_EQ(dateTime2.GetSecond(), 56); + } + +-// disabled on osx and freebsd as their mktime functions +-// don't work for dates before 1900 +-#if defined(TARGET_DARWIN_OSX) || defined(TARGET_FREEBSD) +-TEST_F(TestDateTime, DISABLED_Reset) +-#else + TEST_F(TestDateTime, Reset) +-#endif + { + CDateTime dateTime; + dateTime.SetDateTime(1991, 05, 14, 12, 34, 56); + + dateTime.Reset(); + +- EXPECT_EQ(dateTime.GetYear(), 1601); ++ EXPECT_EQ(dateTime.GetYear(), 1970); + EXPECT_EQ(dateTime.GetMonth(), 1); + EXPECT_EQ(dateTime.GetDay(), 1); + EXPECT_EQ(dateTime.GetHour(), 0); +-- +2.43.0 + + +From ca3e502a5c37975173e376653a167053928b5311 Mon Sep 17 00:00:00 2001 +From: Lukas Rusak <lorusak@gmail.com> +Date: Thu, 10 Sep 2020 08:19:35 -0700 +Subject: [PATCH 05/19] cleanup CPosixTimezone + +--- + xbmc/application/Application.cpp | 6 +- + xbmc/platform/posix/PosixTimezone.cpp | 418 ++++++++++++++++---------- + xbmc/platform/posix/PosixTimezone.h | 16 +- + 3 files changed, 266 insertions(+), 174 deletions(-) + +diff --git a/xbmc/application/Application.cpp b/xbmc/application/Application.cpp +index ea1b152dfd..3227933296 100644 +--- a/xbmc/application/Application.cpp ++++ b/xbmc/application/Application.cpp +@@ -172,8 +172,9 @@ + #include "utils/URIUtils.h" + + #ifdef TARGET_POSIX +-#include "platform/posix/XHandle.h" + #include "platform/posix/PlatformPosix.h" ++#include "platform/posix/PosixTimezone.h" ++#include "platform/posix/XHandle.h" + #endif + + #if defined(TARGET_ANDROID) +@@ -358,6 +359,9 @@ bool CApplication::Create() + // Register JobManager service + CServiceBroker::RegisterJobManager(std::make_shared<CJobManager>()); + ++ // Initialize,timezone ++ g_timezone.Init(); ++ + // Announcement service + m_pAnnouncementManager = std::make_shared<ANNOUNCEMENT::CAnnouncementManager>(); + m_pAnnouncementManager->Start(); +diff --git a/xbmc/platform/posix/PosixTimezone.cpp b/xbmc/platform/posix/PosixTimezone.cpp +index ab2ddcf570..7f0b8d4096 100644 +--- a/xbmc/platform/posix/PosixTimezone.cpp ++++ b/xbmc/platform/posix/PosixTimezone.cpp +@@ -6,7 +6,6 @@ + * See LICENSES/README.md for more information. + */ + +-#include <time.h> + #ifdef TARGET_ANDROID + #include "platform/android/bionic_supplement/bionic_supplement.h" + #endif +@@ -23,120 +22,215 @@ + #include "settings/SettingsComponent.h" + #include <stdlib.h> + +-#include <algorithm> ++#define USE_OS_TZDB 0 ++#define HAS_REMOTE_API 0 ++#include "filesystem/File.h" ++#include "platform/MessagePrinter.h" + +-CPosixTimezone::CPosixTimezone() ++#include <date/tz.h> ++ ++void CPosixTimezone::Init() + { +- 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) ++#if defined(DATE_INTERNAL_TZDATA) ++ XFILE::CFileStream zonetab; ++ ++ if (!zonetab.Open("special://xbmc/addons/resource.timezone/resources/tzdata/zone.tab")) ++ { ++ CMessagePrinter::DisplayMessage("failed to open zone.tab"); ++ return; ++ } ++ ++ std::string countryCode; ++ std::string timezoneName; ++ ++ std::vector<std::string> tokens; ++ ++ for (std::string s; std::getline(zonetab, s);) ++ { ++ tokens.clear(); ++ std::string line = s; ++ StringUtils::Trim(line); ++ ++ if (line.length() == 0) ++ continue; ++ ++ if (line[0] == '#') ++ continue; ++ ++ StringUtils::Tokenize(line, 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; ++ } ++ ++ XFILE::CFileStream isotab; ++ ++ if (!isotab.Open("special://xbmc/addons/resource.timezone/resources/tzdata/iso3166.tab")) ++ { ++ CMessagePrinter::DisplayMessage("failed to open iso3166.tab"); ++ return; ++ } ++ ++ std::string countryName; ++ ++ for (std::string s; std::getline(isotab, s);) ++ { ++ tokens.clear(); ++ std::string line = s; ++ StringUtils::Trim(line); ++ ++ if (line.length() == 0) ++ continue; ++ ++ if (line[0] == '#') ++ continue; ++ ++ StringUtils::Tokenize(line, tokens, "\t"); ++ if (tokens.size() < 2) ++ continue; ++ ++ countryCode = tokens[0]; ++ countryName = tokens[1]; ++ ++ m_countries.push_back(countryName); ++ m_countryByCode[countryCode] = countryName; ++ m_countryByName[countryName] = countryCode; ++ } ++ ++ sort(m_countries.begin(), m_countries.end(), sortstringbyname()); ++#else ++ 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 + { +- 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; ++ std::vector<std::string>& timezones = m_timezonesByCountryCode[countryCode]; ++ timezones.push_back(timezoneName); + } +- 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) ++ ++ 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) + { +- 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; ++ // 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++; + } +- sort(m_counties.begin(), m_counties.end(), sortstringbyname()); +- fclose(fp); +- } +- free(line); ++ ++ countryCode = s.substr(0, 2); ++ countryName = s.substr(i); ++ ++ m_countries.push_back(countryName); ++ m_countryByCode[countryCode] = countryName; ++ m_countryByName[countryName] = countryCode; ++ } ++ sort(m_countries.begin(), m_countries.end(), sortstringbyname()); ++ fclose(fp); ++ } ++ free(line); ++#endif + } + + void CPosixTimezone::OnSettingChanged(const std::shared_ptr<const CSetting>& setting) + { +- if (setting == NULL) ++ if (setting == nullptr) + return; + + const std::string &settingId = setting->GetId(); +@@ -157,82 +251,74 @@ void CPosixTimezone::OnSettingsLoaded() + SetTimezone(CServiceBroker::GetSettingsComponent()->GetSettings()->GetString(CSettings::SETTING_LOCALE_TIMEZONE)); + } + +-std::vector<std::string> CPosixTimezone::GetCounties() ++std::vector<std::string> CPosixTimezone::GetCountries() + { +- return m_counties; ++ return m_countries; + } + + std::vector<std::string> CPosixTimezone::GetTimezonesByCountry(const std::string& country) + { +- return m_timezonesByCountryCode[m_countryByName[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]]; ++ return "?"; + #endif ++ ++ return m_countryByCode[m_countriesByTimezoneName[timezone]]; + } + + void CPosixTimezone::SetTimezone(const std::string& timezoneName) + { +-#if !defined(TARGET_DARWIN) +- bool use_timezone = true; +-#else +- bool use_timezone = false; ++#if defined(TARGET_DARWIN) ++ return; + #endif + +- if (use_timezone) +- { +- static char env_var[255]; +- sprintf(env_var, "TZ=:%s", timezoneName.c_str()); +- putenv(env_var); +- tzset(); +- } ++ setenv("TZ", timezoneName.c_str(), 1); ++ tzset(); + } + + std::string CPosixTimezone::GetOSConfiguredTimezone() + { +- char timezoneName[255]; +- +- // try Slackware approach first +- ssize_t rlrc = readlink("/etc/localtime-copied-from" +- , timezoneName, sizeof(timezoneName)-1); +- +- // RHEL and maybe other distros make /etc/localtime a symlink +- if (rlrc == -1) +- rlrc = readlink("/etc/localtime", timezoneName, sizeof(timezoneName)-1); +- +- if (rlrc != -1) +- { +- timezoneName[rlrc] = '\0'; +- +- char* p = strrchr(timezoneName,'/'); +- if (p) +- { // we want the previous '/' +- char* q = p; +- *q = 0; +- p = strrchr(timezoneName,'/'); +- *q = '/'; +- if (p) +- p++; +- } +- return p; +- } +- +- // now try Debian approach +- timezoneName[0] = 0; +- FILE* fp = fopen("/etc/timezone", "r"); +- if (fp) +- { +- if (fgets(timezoneName, sizeof(timezoneName), fp)) +- timezoneName[strlen(timezoneName)-1] = '\0'; +- fclose(fp); +- } +- +- return timezoneName; ++ char timezoneName[255]; ++ ++ // try Slackware approach first ++ ssize_t rlrc = readlink("/etc/localtime-copied-from", timezoneName, sizeof(timezoneName) - 1); ++ ++ // RHEL and maybe other distros make /etc/localtime a symlink ++ if (rlrc == -1) ++ rlrc = readlink("/etc/localtime", timezoneName, sizeof(timezoneName) - 1); ++ ++ if (rlrc != -1) ++ { ++ timezoneName[rlrc] = '\0'; ++ ++ char* p = strrchr(timezoneName, '/'); ++ if (p) ++ { // we want the previous '/' ++ char* q = p; ++ *q = 0; ++ p = strrchr(timezoneName, '/'); ++ *q = '/'; ++ if (p) ++ p++; ++ } ++ return p; ++ } ++ ++ // now try Debian approach ++ timezoneName[0] = 0; ++ FILE* fp = fopen("/etc/timezone", "r"); ++ if (fp) ++ { ++ if (fgets(timezoneName, sizeof(timezoneName), fp)) ++ timezoneName[strlen(timezoneName) - 1] = '\0'; ++ fclose(fp); ++ } ++ ++ return timezoneName; + } + + void CPosixTimezone::SettingOptionsTimezoneCountriesFiller( +@@ -241,9 +327,9 @@ void CPosixTimezone::SettingOptionsTimezoneCountriesFiller( + 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]); ++ std::vector<std::string> countries = g_timezone.GetCountries(); ++ for (const auto& country : countries) ++ list.emplace_back(country, country); + } + + void CPosixTimezone::SettingOptionsTimezonesFiller(const std::shared_ptr<const CSetting>& setting, +@@ -254,12 +340,12 @@ void CPosixTimezone::SettingOptionsTimezonesFiller(const std::shared_ptr<const C + 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++) ++ for (const auto& timezone : timezones) + { +- if (!found && StringUtils::EqualsNoCase(timezones[i], current)) ++ if (!found && StringUtils::EqualsNoCase(timezone, current)) + found = true; + +- list.emplace_back(timezones[i], timezones[i]); ++ list.emplace_back(timezone, timezone); + } + + if (!found && !timezones.empty()) +diff --git a/xbmc/platform/posix/PosixTimezone.h b/xbmc/platform/posix/PosixTimezone.h +index 076e87fa51..238c6daf85 100644 +--- a/xbmc/platform/posix/PosixTimezone.h ++++ b/xbmc/platform/posix/PosixTimezone.h +@@ -21,7 +21,9 @@ struct StringSettingOption; + class CPosixTimezone : public ISettingCallback, public ISettingsHandler + { + public: +- CPosixTimezone(); ++ CPosixTimezone() = default; ++ ++ void Init(); + + void OnSettingChanged(const std::shared_ptr<const CSetting>& setting) override; + +@@ -29,7 +31,7 @@ public: + + std::string GetOSConfiguredTimezone(); + +- std::vector<std::string> GetCounties(); ++ std::vector<std::string> GetCountries(); + std::vector<std::string> GetTimezonesByCountry(const std::string& country); + std::string GetCountryByTimezone(const std::string& timezone); + +@@ -46,12 +48,12 @@ public: + void* data); + + private: +- std::vector<std::string> m_counties; +- std::map<std::string, std::string> m_countryByCode; +- std::map<std::string, std::string> m_countryByName; ++ std::vector<std::string> m_countries; ++ 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; ++ std::map<std::string, std::vector<std::string>> m_timezonesByCountryCode; ++ std::map<std::string, std::string> m_countriesByTimezoneName; + }; + + extern CPosixTimezone g_timezone; +-- +2.43.0 + + +From a36c95155a2b8d22f69ad0809d895c11838620ed Mon Sep 17 00:00:00 2001 +From: Lukas Rusak <lorusak@gmail.com> +Date: Thu, 10 Sep 2020 08:41:57 -0700 +Subject: [PATCH 06/19] utils/XTimeUtils: clean up SystemTime and FileTime + functions + +--- + xbmc/XBDateTime.cpp | 213 ++---------------- + xbmc/XBDateTime.h | 27 --- + .../addons/interfaces/gui/dialogs/Numeric.cpp | 10 +- + xbmc/dialogs/GUIDialogNumeric.cpp | 203 ++++++++++------- + xbmc/dialogs/GUIDialogNumeric.h | 12 +- + xbmc/filesystem/NFSDirectory.cpp | 18 +- + xbmc/guilib/GUIEditControl.cpp | 13 +- + xbmc/guilib/GUIRSSControl.h | 2 +- + xbmc/interfaces/legacy/Dialog.cpp | 44 ++-- + xbmc/music/infoscanner/MusicInfoScanner.cpp | 4 +- + xbmc/network/upnp/UPnPInternal.cpp | 18 +- + xbmc/platform/posix/XTimeUtils.cpp | 211 ----------------- + .../posix/filesystem/PosixDirectory.cpp | 5 +- + .../posix/filesystem/SMBDirectory.cpp | 16 +- + .../pvr/dialogs/GUIDialogPVRTimerSettings.cpp | 18 +- + xbmc/pvr/dialogs/GUIDialogPVRTimerSettings.h | 1 - + xbmc/pvr/windows/GUIWindowPVRGuide.cpp | 7 +- + xbmc/settings/windows/GUIControlSettings.cpp | 14 +- + xbmc/test/TestDateTime.cpp | 18 +- + xbmc/utils/Archive.cpp | 8 +- + xbmc/utils/Archive.h | 4 +- + xbmc/utils/RssManager.cpp | 2 +- + xbmc/utils/RssManager.h | 2 +- + xbmc/utils/RssReader.cpp | 25 +- + xbmc/utils/RssReader.h | 10 +- + xbmc/utils/XTimeUtils.h | 44 ---- + xbmc/utils/test/TestArchive.cpp | 22 +- + xbmc/video/VideoInfoScanner.cpp | 4 +- + 28 files changed, 253 insertions(+), 722 deletions(-) + +diff --git a/xbmc/XBDateTime.cpp b/xbmc/XBDateTime.cpp +index 47c6b8d1a6..d8187b71e6 100644 +--- a/xbmc/XBDateTime.cpp ++++ b/xbmc/XBDateTime.cpp +@@ -171,23 +171,6 @@ CDateTime::CDateTime() + Reset(); + } + +-CDateTime::CDateTime(const KODI::TIME::SystemTime& systemTime) +-{ +- KODI::TIME::FileTime fileTime; +- m_state = ToFileTime(systemTime, fileTime) ? valid : invalid; +- +- time_t time; +- KODI::TIME::FileTimeToTimeT(&fileTime, &time); +- m_time = std::chrono::system_clock::from_time_t(time); +-} +- +-CDateTime::CDateTime(const KODI::TIME::FileTime& fileTime) +-{ +- time_t time; +- KODI::TIME::FileTimeToTimeT(&fileTime, &time); +- m_time = std::chrono::system_clock::from_time_t(time); +-} +- + CDateTime::CDateTime(const CDateTime& time) : m_time(time.m_time) + { + m_state=time.m_state; +@@ -230,27 +213,6 @@ CDateTime CDateTime::GetUTCDateTime() + return CDateTime(std::chrono::system_clock::now()); + } + +-const CDateTime& CDateTime::operator=(const KODI::TIME::SystemTime& right) +-{ +- KODI::TIME::FileTime fileTime; +- m_state = ToFileTime(right, fileTime) ? valid : invalid; +- +- time_t time; +- KODI::TIME::FileTimeToTimeT(&fileTime, &time); +- m_time = std::chrono::system_clock::from_time_t(time); +- +- return *this; +-} +- +-const CDateTime& CDateTime::operator=(const KODI::TIME::FileTime& right) +-{ +- time_t time; +- KODI::TIME::FileTimeToTimeT(&right, &time); +- m_time = std::chrono::system_clock::from_time_t(time); +- +- return *this; +-} +- + const CDateTime& CDateTime::operator =(const time_t& right) + { + m_time = std::chrono::system_clock::from_time_t(right); +@@ -305,84 +267,6 @@ bool CDateTime::operator !=(const CDateTime& right) const + return !operator ==(right); + } + +-bool CDateTime::operator>(const KODI::TIME::FileTime& right) const +-{ +- time_t time; +- KODI::TIME::FileTimeToTimeT(&right, &time); +- +- return m_time > std::chrono::system_clock::from_time_t(time); +-} +- +-bool CDateTime::operator>=(const KODI::TIME::FileTime& right) const +-{ +- return operator >(right) || operator ==(right); +-} +- +-bool CDateTime::operator<(const KODI::TIME::FileTime& right) const +-{ +- time_t time; +- KODI::TIME::FileTimeToTimeT(&right, &time); +- +- return m_time < std::chrono::system_clock::from_time_t(time); +-} +- +-bool CDateTime::operator<=(const KODI::TIME::FileTime& right) const +-{ +- return operator <(right) || operator ==(right); +-} +- +-bool CDateTime::operator==(const KODI::TIME::FileTime& right) const +-{ +- time_t time; +- KODI::TIME::FileTimeToTimeT(&right, &time); +- +- return m_time == std::chrono::system_clock::from_time_t(time); +-} +- +-bool CDateTime::operator!=(const KODI::TIME::FileTime& right) const +-{ +- return !operator ==(right); +-} +- +-bool CDateTime::operator>(const KODI::TIME::SystemTime& right) const +-{ +- KODI::TIME::FileTime time; +- ToFileTime(right, time); +- +- return operator >(time); +-} +- +-bool CDateTime::operator>=(const KODI::TIME::SystemTime& right) const +-{ +- return operator >(right) || operator ==(right); +-} +- +-bool CDateTime::operator<(const KODI::TIME::SystemTime& right) const +-{ +- KODI::TIME::FileTime time; +- ToFileTime(right, time); +- +- return operator <(time); +-} +- +-bool CDateTime::operator<=(const KODI::TIME::SystemTime& right) const +-{ +- return operator <(right) || operator ==(right); +-} +- +-bool CDateTime::operator==(const KODI::TIME::SystemTime& right) const +-{ +- KODI::TIME::FileTime time; +- ToFileTime(right, time); +- +- return operator ==(time); +-} +- +-bool CDateTime::operator!=(const KODI::TIME::SystemTime& right) const +-{ +- return !operator ==(right); +-} +- + bool CDateTime::operator >(const time_t& right) const + { + return m_time > std::chrono::system_clock::from_time_t(right); +@@ -477,7 +361,7 @@ CDateTime CDateTime::operator+(const CDateTimeSpan& right) const + { + CDateTime left(*this); + +- left.m_time + right.m_timeSpan; ++ left.m_time += right.m_timeSpan; + + return left; + } +@@ -486,7 +370,7 @@ CDateTime CDateTime::operator-(const CDateTimeSpan& right) const + { + CDateTime left(*this); + +- left.m_time - right.m_timeSpan; ++ left.m_time -= right.m_timeSpan; + + return left; + } +@@ -513,14 +397,6 @@ CDateTimeSpan CDateTime::operator -(const CDateTime& right) const + return left; + } + +-CDateTime::operator KODI::TIME::FileTime() const +-{ +- KODI::TIME::FileTime fileTime; +- time_t time = std::chrono::system_clock::to_time_t(m_time); +- KODI::TIME::TimeTToFileTime(time, &fileTime); +- return fileTime; +-} +- + void CDateTime::Archive(CArchive& ar) + { + if (ar.IsStoring()) +@@ -528,9 +404,7 @@ void CDateTime::Archive(CArchive& ar) + ar<<(int)m_state; + if (m_state==valid) + { +- KODI::TIME::SystemTime st; +- GetAsSystemTime(st); +- ar<<st; ++ ar << GetAsTimePoint(); + } + } + else +@@ -541,9 +415,7 @@ void CDateTime::Archive(CArchive& ar) + m_state = CDateTime::STATE(state); + if (m_state==valid) + { +- KODI::TIME::SystemTime st; +- ar>>st; +- ToTimePoint(st, m_time); ++ ar >> m_time; + } + } + } +@@ -564,37 +436,6 @@ bool CDateTime::IsValid() const + return m_state == valid; + } + +-bool CDateTime::ToTimePoint(const KODI::TIME::SystemTime& systemTime, +- std::chrono::system_clock::time_point& timePoint) const +-{ +- KODI::TIME::FileTime fileTime; +- KODI::TIME::SystemTimeToFileTime(&systemTime, &fileTime); +- +- time_t time; +- KODI::TIME::FileTimeToTimeT(&fileTime, &time); +- +- timePoint = std::chrono::system_clock::from_time_t(time); +- return true; +-} +- +-bool CDateTime::ToFileTime(const KODI::TIME::SystemTime& time, KODI::TIME::FileTime& fileTime) const +-{ +- return KODI::TIME::SystemTimeToFileTime(&time, &fileTime) == 1 && +- (fileTime.lowDateTime > 0 || fileTime.highDateTime > 0); +-} +- +-bool CDateTime::ToFileTime(const time_t& time, KODI::TIME::FileTime& fileTime) const +-{ +- long long ll = time; +- ll *= 10000000ll; +- ll += 0x19DB1DED53E8000LL; +- +- fileTime.lowDateTime = (DWORD)(ll & 0xFFFFFFFF); +- fileTime.highDateTime = (DWORD)(ll >> 32); +- +- return true; +-} +- + bool CDateTime::SetFromDateString(const std::string &date) + { + //! @todo STRING_CLEANUP +@@ -729,14 +570,6 @@ bool CDateTime::SetTime(int hour, int minute, int second) + return true; + } + +-void CDateTime::GetAsSystemTime(KODI::TIME::SystemTime& systemTime) const +-{ +- const time_t time = std::chrono::system_clock::to_time_t(m_time); +- KODI::TIME::FileTime fileTime; +- ToFileTime(time, fileTime); +- KODI::TIME::FileTimeToSystemTime(&fileTime, &systemTime); +-} +- + void CDateTime::GetAsTime(time_t& time) const + { + time = std::chrono::system_clock::to_time_t(m_time); +@@ -755,12 +588,6 @@ std::chrono::system_clock::time_point CDateTime::GetAsTimePoint() const + return m_time; + } + +-// void CDateTime::GetAsTimeStamp(KODI::TIME::FileTime& fileTime) const +-// { +-// time_t time = std::chrono::system_clock::to_time_t(m_time); +-// KODI::TIME::TimeTToFileTime(time, &fileTime); +-// } +- + std::string CDateTime::GetAsDBDate() const + { + return date::format("%F", m_time); +@@ -1052,12 +879,9 @@ std::string CDateTime::GetAsLocalizedTime(const std::string &format, bool withSe + std::string strOut; + const std::string& strFormat = format.empty() ? g_langInfo.GetTimeFormat() : format; + +- KODI::TIME::SystemTime dateTime; +- GetAsSystemTime(dateTime); +- + // Prefetch meridiem symbol + const std::string& strMeridiem = +- CLangInfo::MeridiemSymbolToString(dateTime.hour > 11 ? MeridiemSymbolPM : MeridiemSymbolAM); ++ CLangInfo::MeridiemSymbolToString(GetHour() > 11 ? MeridiemSymbolPM : MeridiemSymbolAM); + + size_t length = strFormat.size(); + for (size_t i=0; i < length; ++i) +@@ -1106,7 +930,7 @@ std::string CDateTime::GetAsLocalizedTime(const std::string &format, bool withSe + i=length; + } + +- int hour = dateTime.hour; ++ int hour = GetHour(); + if (c=='h') + { // recalc to 12 hour clock + if (hour > 11) +@@ -1145,9 +969,9 @@ std::string CDateTime::GetAsLocalizedTime(const std::string &format, bool withSe + // Format minute string with the length of the mask + std::string str; + if (partLength==1) +- str = std::to_string(dateTime.minute); ++ str = std::to_string(GetMinute()); + else +- str = StringUtils::Format("{:02}", dateTime.minute); ++ str = StringUtils::Format("{:02}", GetMinute()); + + strOut+=str; + } +@@ -1174,9 +998,9 @@ std::string CDateTime::GetAsLocalizedTime(const std::string &format, bool withSe + // Format seconds string with the length of the mask + std::string str; + if (partLength==1) +- str = std::to_string(dateTime.second); ++ str = std::to_string(GetSecond()); + else +- str = StringUtils::Format("{:02}", dateTime.second); ++ str = StringUtils::Format("{:02}", GetSecond()); + + strOut+=str; + } +@@ -1215,9 +1039,6 @@ std::string CDateTime::GetAsLocalizedDate(const std::string &strFormat) const + { + std::string strOut; + +- KODI::TIME::SystemTime dateTime; +- GetAsSystemTime(dateTime); +- + size_t length = strFormat.size(); + for (size_t i = 0; i < length; ++i) + { +@@ -1267,12 +1088,12 @@ std::string CDateTime::GetAsLocalizedDate(const std::string &strFormat) const + // Format string with the length of the mask + std::string str; + if (partLength==1) // single-digit number +- str = std::to_string(dateTime.day); ++ str = std::to_string(GetDay()); + else if (partLength==2) // two-digit number +- str = StringUtils::Format("{:02}", dateTime.day); ++ str = StringUtils::Format("{:02}", GetDay()); + else // Day of week string + { +- int wday = dateTime.dayOfWeek; ++ int wday = GetDayOfWeek(); + if (wday < 1 || wday > 7) wday = 7; + str = g_localizeStrings.Get((c =='d' ? 40 : 10) + wday); + } +@@ -1299,12 +1120,12 @@ std::string CDateTime::GetAsLocalizedDate(const std::string &strFormat) const + // Format string with the length of the mask + std::string str; + if (partLength==1) // single-digit number +- str = std::to_string(dateTime.month); ++ str = std::to_string(GetMonth()); + else if (partLength==2) // two-digit number +- str = StringUtils::Format("{:02}", dateTime.month); ++ str = StringUtils::Format("{:02}", GetMonth()); + else // Month string + { +- int wmonth = dateTime.month; ++ int wmonth = GetMonth(); + if (wmonth < 1 || wmonth > 12) wmonth = 12; + str = g_localizeStrings.Get((c =='m' ? 50 : 20) + wmonth); + } +@@ -1329,7 +1150,7 @@ std::string CDateTime::GetAsLocalizedDate(const std::string &strFormat) const + } + + // Format string with the length of the mask +- std::string str = std::to_string(dateTime.year); // four-digit number ++ std::string str = std::to_string(GetYear()); // four-digit number + if (partLength <= 2) + str.erase(0, 2); // two-digit number + +diff --git a/xbmc/XBDateTime.h b/xbmc/XBDateTime.h +index 60d06e417a..16d6217c8a 100644 +--- a/xbmc/XBDateTime.h ++++ b/xbmc/XBDateTime.h +@@ -63,8 +63,6 @@ public: + CDateTime(); + CDateTime(const CDateTime& time); + CDateTime& operator=(const CDateTime&) = default; +- explicit CDateTime(const KODI::TIME::SystemTime& time); +- explicit CDateTime(const KODI::TIME::FileTime& time); + explicit CDateTime(const time_t& time); + explicit CDateTime(const tm& time); + explicit CDateTime(const std::chrono::system_clock::time_point& time); +@@ -84,8 +82,6 @@ public: + static CDateTime FromUTCDateTime(const time_t &dateTime); + static CDateTime FromRFC1123DateTime(const std::string &dateTime); + +- const CDateTime& operator=(const KODI::TIME::SystemTime& right); +- const CDateTime& operator=(const KODI::TIME::FileTime& right); + const CDateTime& operator =(const time_t& right); + const CDateTime& operator =(const tm& right); + const CDateTime& operator=(const std::chrono::system_clock::time_point& right); +@@ -97,20 +93,6 @@ public: + bool operator ==(const CDateTime& right) const; + bool operator !=(const CDateTime& right) const; + +- bool operator>(const KODI::TIME::FileTime& right) const; +- bool operator>=(const KODI::TIME::FileTime& right) const; +- bool operator<(const KODI::TIME::FileTime& right) const; +- bool operator<=(const KODI::TIME::FileTime& right) const; +- bool operator==(const KODI::TIME::FileTime& right) const; +- bool operator!=(const KODI::TIME::FileTime& right) const; +- +- bool operator>(const KODI::TIME::SystemTime& right) const; +- bool operator>=(const KODI::TIME::SystemTime& right) const; +- bool operator<(const KODI::TIME::SystemTime& right) const; +- bool operator<=(const KODI::TIME::SystemTime& right) const; +- bool operator==(const KODI::TIME::SystemTime& right) const; +- bool operator!=(const KODI::TIME::SystemTime& right) const; +- + bool operator >(const time_t& right) const; + bool operator >=(const time_t& right) const; + bool operator <(const time_t& right) const; +@@ -140,8 +122,6 @@ public: + + CDateTimeSpan operator -(const CDateTime& right) const; + +- operator KODI::TIME::FileTime() const; +- + void Archive(CArchive& ar) override; + + void Reset(); +@@ -173,7 +153,6 @@ public: + */ + bool SetFromDBDateTime(const std::string &dateTime); + +- void GetAsSystemTime(KODI::TIME::SystemTime& time) const; + void GetAsTime(time_t& time) const; + void GetAsTm(tm& time) const; + std::chrono::system_clock::time_point GetAsTimePoint() const; +@@ -195,12 +174,6 @@ public: + void SetValid(bool yesNo); + bool IsValid() const; + +-private: +- bool ToTimePoint(const KODI::TIME::SystemTime& time, +- std::chrono::system_clock::time_point& timePoint) const; +- bool ToFileTime(const KODI::TIME::SystemTime& time, KODI::TIME::FileTime& fileTime) const; +- bool ToFileTime(const time_t& time, KODI::TIME::FileTime& fileTime) const; +- + private: + std::chrono::system_clock::time_point m_time; + +diff --git a/xbmc/addons/interfaces/gui/dialogs/Numeric.cpp b/xbmc/addons/interfaces/gui/dialogs/Numeric.cpp +index a78aa4af60..3acc48e768 100644 +--- a/xbmc/addons/interfaces/gui/dialogs/Numeric.cpp ++++ b/xbmc/addons/interfaces/gui/dialogs/Numeric.cpp +@@ -135,12 +135,9 @@ bool Interface_GUIDialogNumeric::show_and_get_time(KODI_HANDLE kodiBase, + return false; + } + +- KODI::TIME::SystemTime systemTime; + CDateTime dateTime(*time); +- dateTime.GetAsSystemTime(systemTime); +- if (CGUIDialogNumeric::ShowAndGetTime(systemTime, heading)) ++ if (CGUIDialogNumeric::ShowAndGetTime(dateTime, heading)) + { +- dateTime = systemTime; + dateTime.GetAsTm(*time); + return true; + } +@@ -167,12 +164,9 @@ bool Interface_GUIDialogNumeric::show_and_get_date(KODI_HANDLE kodiBase, + return false; + } + +- KODI::TIME::SystemTime systemTime; + CDateTime dateTime(*date); +- dateTime.GetAsSystemTime(systemTime); +- if (CGUIDialogNumeric::ShowAndGetDate(systemTime, heading)) ++ if (CGUIDialogNumeric::ShowAndGetDate(dateTime, heading)) + { +- dateTime = systemTime; + dateTime.GetAsTm(*date); + return true; + } +diff --git a/xbmc/dialogs/GUIDialogNumeric.cpp b/xbmc/dialogs/GUIDialogNumeric.cpp +index 182cf6a3af..bba219e44e 100644 +--- a/xbmc/dialogs/GUIDialogNumeric.cpp ++++ b/xbmc/dialogs/GUIDialogNumeric.cpp +@@ -45,7 +45,7 @@ CGUIDialogNumeric::CGUIDialogNumeric(void) + m_lastblock{}, + m_dirty{false} + { +- memset(&m_datetime, 0, sizeof(KODI::TIME::SystemTime)); ++ m_datetime.Reset(); + m_loadType = KEEP_IN_MEMORY; + } + +@@ -231,59 +231,76 @@ void CGUIDialogNumeric::OnBackSpace() + } + else if (m_mode == INPUT_TIME) + { ++ int hour = m_datetime.GetHour(); ++ int minute = m_datetime.GetMinute(); ++ + if (m_block == 0) +- m_datetime.hour /= 10; +- else if (m_datetime.minute) +- m_datetime.minute /= 10; ++ hour /= 10; ++ else if (minute) ++ minute /= 10; + else + { + m_block = 0; + m_dirty = false; + } ++ ++ m_datetime.SetTime(hour, minute, 0); + } + else if (m_mode == INPUT_TIME_SECONDS) + { ++ int hour = m_datetime.GetHour(); ++ int minute = m_datetime.GetMinute(); ++ int second = m_datetime.GetSecond(); ++ + if (m_block == 0) +- m_datetime.hour /= 10; ++ hour /= 10; + else if (m_block == 1) + { +- if (m_datetime.minute) +- m_datetime.minute /= 10; ++ if (minute) ++ minute /= 10; + else + { + m_block = 0; + m_dirty = false; + } + } +- else if (m_datetime.second) +- m_datetime.minute /= 10; ++ else if (second) ++ minute /= 10; + else + { + m_block = 0; + m_dirty = false; + } ++ ++ m_datetime.SetTime(hour, minute, second); + } + else if (m_mode == INPUT_DATE) + { ++ int day = m_datetime.GetDay(); ++ int month = m_datetime.GetMonth(); ++ int year = m_datetime.GetYear(); ++ + if (m_block == 0) +- m_datetime.day /= 10; ++ day /= 10; + else if (m_block == 1) + { +- if (m_datetime.month) +- m_datetime.month /= 10; ++ if (month) ++ month /= 10; + else + { + m_block = 0; + m_dirty = false; + } + } +- else if (m_datetime.year) // m_block == 2 +- m_datetime.year /= 10; ++ else if (year) // m_block == 2 ++ year /= 10; + else + { + m_block = 1; + m_dirty = false; + } ++ ++ m_datetime.SetDate(year, month, day); + } + } + +@@ -317,21 +334,21 @@ void CGUIDialogNumeric::FrameMove() + strLabel = m_number; + else if (m_mode == INPUT_TIME) + { // format up the time +- strLabel = StringUtils::Format("{:2}:{:02}", m_datetime.hour, m_datetime.minute); ++ strLabel = StringUtils::Format("{:2}:{:02}", m_datetime.GetHour(), m_datetime.GetMinute()); + start = m_block * 3; + end = m_block * 3 + 2; + } + else if (m_mode == INPUT_TIME_SECONDS) + { // format up the time +- strLabel = StringUtils::Format("{:2}:{:02}:{:02}", m_datetime.hour, m_datetime.minute, +- m_datetime.second); ++ strLabel = StringUtils::Format("{:2}:{:02}:{:02}", m_datetime.GetHour(), m_datetime.GetMinute(), ++ m_datetime.GetSecond()); + start = m_block * 3; + end = m_block * 3 + 2; + } + else if (m_mode == INPUT_DATE) + { // format up the date +- strLabel = +- StringUtils::Format("{:2}/{:2}/{:4}", m_datetime.day, m_datetime.month, m_datetime.year); ++ strLabel = StringUtils::Format("{:2}/{:2}/{:4}", m_datetime.GetDay(), m_datetime.GetMonth(), ++ m_datetime.GetYear()); + start = m_block * 3; + end = m_block * 3 + 2; + if (m_block == 2) +@@ -377,7 +394,7 @@ void CGUIDialogNumeric::OnNumber(uint32_t num) + } + } + +-void CGUIDialogNumeric::SetMode(INPUT_MODE mode, const KODI::TIME::SystemTime& initial) ++void CGUIDialogNumeric::SetMode(INPUT_MODE mode, const CDateTime& initial) + { + m_mode = mode; + m_block = 0; +@@ -425,7 +442,7 @@ void CGUIDialogNumeric::SetMode(INPUT_MODE mode, const std::string &initial) + if (!dateTime.IsValid()) + return; + +- dateTime.GetAsSystemTime(m_datetime); ++ m_datetime = dateTime; + m_lastblock = (m_mode == INPUT_DATE) ? 2 : 1; + } + else if (m_mode == INPUT_IP_ADDRESS) +@@ -447,7 +464,7 @@ void CGUIDialogNumeric::SetMode(INPUT_MODE mode, const std::string &initial) + m_number = initial; + } + +-KODI::TIME::SystemTime CGUIDialogNumeric::GetOutput() const ++CDateTime CGUIDialogNumeric::GetOutput() const + { + assert(m_mode == INPUT_TIME || m_mode == INPUT_TIME_SECONDS || m_mode == INPUT_DATE); + return m_datetime; +@@ -458,13 +475,13 @@ std::string CGUIDialogNumeric::GetOutputString() const + switch (m_mode) + { + case INPUT_DATE: +- return StringUtils::Format("{:02}/{:02}/{:04}", m_datetime.day, m_datetime.month, +- m_datetime.year); ++ return StringUtils::Format("{:02}/{:02}/{:04}", m_datetime.GetDay(), m_datetime.GetMonth(), ++ m_datetime.GetYear()); + case INPUT_TIME: +- return StringUtils::Format("{}:{:02}", m_datetime.hour, m_datetime.minute); ++ return StringUtils::Format("{}:{:02}", m_datetime.GetHour(), m_datetime.GetMinute()); + case INPUT_TIME_SECONDS: +- return StringUtils::Format("{}:{:02}:{:02}", m_datetime.hour, m_datetime.minute, +- m_datetime.second); ++ return StringUtils::Format("{}:{:02}:{:02}", m_datetime.GetHour(), m_datetime.GetMinute(), ++ m_datetime.GetSecond()); + case INPUT_IP_ADDRESS: + return StringUtils::Format("{}.{}.{}.{}", m_ip[0], m_ip[1], m_ip[2], m_ip[3]); + case INPUT_NUMBER: +@@ -480,23 +497,25 @@ bool CGUIDialogNumeric::ShowAndGetSeconds(std::string &timeString, const std::st + { + CGUIDialogNumeric *pDialog = CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogNumeric>(WINDOW_DIALOG_NUMERIC); + if (!pDialog) return false; +- int seconds = StringUtils::TimeStringToSeconds(timeString); +- KODI::TIME::SystemTime time = {}; +- time.hour = seconds / 3600; +- time.minute = (seconds - time.hour * 3600) / 60; +- time.second = seconds - time.hour * 3600 - time.minute * 60; +- pDialog->SetMode(INPUT_TIME_SECONDS, time); ++ ++ std::chrono::system_clock::time_point time{ ++ std::chrono::seconds{StringUtils::TimeStringToSeconds(timeString)}}; ++ ++ CDateTime datetime(time); ++ ++ pDialog->SetMode(INPUT_TIME_SECONDS, datetime); + pDialog->SetHeading(heading); + pDialog->Open(); + if (!pDialog->IsConfirmed() || pDialog->IsCanceled()) + return false; +- time = pDialog->GetOutput(); +- seconds = time.hour * 3600 + time.minute * 60 + time.second; +- timeString = StringUtils::SecondsToTimeString(seconds); ++ datetime = pDialog->GetOutput(); ++ time = datetime.GetAsTimePoint(); ++ timeString = StringUtils::SecondsToTimeString( ++ std::chrono::duration_cast<std::chrono::seconds>(time.time_since_epoch()).count()); + return true; + } + +-bool CGUIDialogNumeric::ShowAndGetTime(KODI::TIME::SystemTime& time, const std::string& heading) ++bool CGUIDialogNumeric::ShowAndGetTime(CDateTime& time, const std::string& heading) + { + CGUIDialogNumeric *pDialog = CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogNumeric>(WINDOW_DIALOG_NUMERIC); + if (!pDialog) return false; +@@ -509,7 +528,7 @@ bool CGUIDialogNumeric::ShowAndGetTime(KODI::TIME::SystemTime& time, const std:: + return true; + } + +-bool CGUIDialogNumeric::ShowAndGetDate(KODI::TIME::SystemTime& date, const std::string& heading) ++bool CGUIDialogNumeric::ShowAndGetDate(CDateTime& date, const std::string& heading) + { + CGUIDialogNumeric *pDialog = CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogNumeric>(WINDOW_DIALOG_NUMERIC); + if (!pDialog) return false; +@@ -680,28 +699,33 @@ void CGUIDialogNumeric::SetHeading(const std::string& strHeading) + + void CGUIDialogNumeric::VerifyDate(bool checkYear) + { +- if (m_datetime.day == 0) +- m_datetime.day = 1; +- if (m_datetime.month == 0) +- m_datetime.month = 1; ++ int day = m_datetime.GetDay(); ++ int month = m_datetime.GetMonth(); ++ int year = m_datetime.GetYear(); ++ ++ if (day == 0) ++ day = 1; ++ if (month == 0) ++ month = 1; + // check for number of days in the month +- if (m_datetime.day == 31) ++ if (day == 31) + { +- if (m_datetime.month == 4 || m_datetime.month == 6 || m_datetime.month == 9 || +- m_datetime.month == 11) +- m_datetime.day = 30; ++ if (month == 4 || month == 6 || month == 9 || month == 11) ++ day = 30; + } +- if (m_datetime.month == 2 && m_datetime.day > 28) ++ if (month == 2 && day > 28) + { +- m_datetime.day = 29; // max in february. ++ day = 29; // max in february. + if (checkYear) + { + // leap years occur when the year is divisible by 4 but not by 100, or the year is divisible by 400 + // thus they don't occur, if the year has a remainder when divided by 4, or when the year is divisible by 100 but not by 400 +- if ((m_datetime.year % 4) || (!(m_datetime.year % 100) && (m_datetime.year % 400))) +- m_datetime.day = 28; ++ if ((year % 4) || (!(year % 100) && (year % 400))) ++ day = 28; + } + } ++ ++ m_datetime.SetDate(year, month, day); + } + + void CGUIDialogNumeric::OnOK() +@@ -741,17 +765,21 @@ void CGUIDialogNumeric::HandleInputIP(uint32_t num) + + void CGUIDialogNumeric::HandleInputDate(uint32_t num) + { ++ int day = m_datetime.GetDay(); ++ int month = m_datetime.GetMonth(); ++ int year = m_datetime.GetYear(); ++ + if (m_block == 0) // day of month + { +- if (m_dirty && (m_datetime.day < 3 || num < 2)) ++ if (m_dirty && (day < 3 || num < 2)) + { +- m_datetime.day *= 10; +- m_datetime.day += num; ++ day *= 10; ++ day += num; + } + else +- m_datetime.day = num; ++ day = num; + +- if (m_datetime.day > 3) ++ if (day > 3) + { + m_block = 1; // move to months + m_dirty = false; +@@ -763,13 +791,13 @@ void CGUIDialogNumeric::HandleInputDate(uint32_t num) + { + if (m_dirty && num < 3) + { +- m_datetime.month *= 10; +- m_datetime.month += num; ++ month *= 10; ++ month += num; + } + else +- m_datetime.month = num; ++ month = num; + +- if (m_datetime.month > 1) ++ if (month > 1) + { + VerifyDate(false); + m_block = 2; // move to year +@@ -780,15 +808,15 @@ void CGUIDialogNumeric::HandleInputDate(uint32_t num) + } + else // year + { +- if (m_dirty && m_datetime.year < 1000) // have taken input ++ if (m_dirty && year < 1000) // have taken input + { +- m_datetime.year *= 10; +- m_datetime.year += num; ++ year *= 10; ++ year += num; + } + else +- m_datetime.year = num; ++ year = num; + +- if (m_datetime.year > 1000) ++ if (year > 1000) + { + VerifyDate(true); + m_block = 0; // move to day of month +@@ -797,22 +825,28 @@ void CGUIDialogNumeric::HandleInputDate(uint32_t num) + else + m_dirty = true; + } ++ ++ m_datetime.SetDate(year, month, day); + } + + void CGUIDialogNumeric::HandleInputSeconds(uint32_t num) + { ++ int hour = m_datetime.GetHour(); ++ int minute = m_datetime.GetMinute(); ++ int second = m_datetime.GetSecond(); ++ + if (m_block == 0) // hour + { + if (m_dirty) // have input the first digit + { +- m_datetime.hour *= 10; +- m_datetime.hour += num; ++ hour *= 10; ++ hour += num; + m_block = 1; // move to minutes - allows up to 99 hours + m_dirty = false; + } + else // this is the first digit + { +- m_datetime.hour = num; ++ hour = num; + m_dirty = true; + } + } +@@ -820,14 +854,14 @@ void CGUIDialogNumeric::HandleInputSeconds(uint32_t num) + { + if (m_dirty) // have input the first digit + { +- m_datetime.minute *= 10; +- m_datetime.minute += num; ++ minute *= 10; ++ minute += num; + m_block = 2; // move to seconds - allows up to 99 minutes + m_dirty = false; + } + else // this is the first digit + { +- m_datetime.minute = num; ++ minute = num; + if (num > 5) + { + m_block = 2; // move to seconds +@@ -841,14 +875,14 @@ void CGUIDialogNumeric::HandleInputSeconds(uint32_t num) + { + if (m_dirty) // have input the first digit + { +- m_datetime.second *= 10; +- m_datetime.second += num; ++ second *= 10; ++ second += num; + m_block = 0; // move to hours + m_dirty = false; + } + else // this is the first digit + { +- m_datetime.second = num; ++ second = num; + if (num > 5) + { + m_block = 0; // move to hours +@@ -858,28 +892,33 @@ void CGUIDialogNumeric::HandleInputSeconds(uint32_t num) + m_dirty = true; + } + } ++ ++ m_datetime.SetTime(hour, minute, second); + } + + void CGUIDialogNumeric::HandleInputTime(uint32_t num) + { ++ int hour = m_datetime.GetHour(); ++ int minute = m_datetime.GetMinute(); ++ + if (m_block == 0) // hour + { + if (m_dirty) // have input the first digit + { +- if (m_datetime.hour < 2 || num < 4) ++ if (hour < 2 || num < 4) + { +- m_datetime.hour *= 10; +- m_datetime.hour += num; ++ hour *= 10; ++ hour += num; + } + else +- m_datetime.hour = num; ++ hour = num; + + m_block = 1; // move to minutes + m_dirty = false; + } + else // this is the first digit + { +- m_datetime.hour = num; ++ hour = num; + + if (num > 2) + { +@@ -894,14 +933,14 @@ void CGUIDialogNumeric::HandleInputTime(uint32_t num) + { + if (m_dirty) // have input the first digit + { +- m_datetime.minute *= 10; +- m_datetime.minute += num; ++ minute *= 10; ++ minute += num; + m_block = 0; // move to hours + m_dirty = false; + } + else // this is the first digit + { +- m_datetime.minute = num; ++ minute = num; + + if (num > 5) + { +@@ -912,5 +951,7 @@ void CGUIDialogNumeric::HandleInputTime(uint32_t num) + m_dirty = true; + } + } ++ ++ m_datetime.SetTime(hour, minute, 0); + } + +diff --git a/xbmc/dialogs/GUIDialogNumeric.h b/xbmc/dialogs/GUIDialogNumeric.h +index 2932053021..d39b2702cd 100644 +--- a/xbmc/dialogs/GUIDialogNumeric.h ++++ b/xbmc/dialogs/GUIDialogNumeric.h +@@ -8,8 +8,8 @@ + + #pragma once + ++#include "XBDateTime.h" + #include "guilib/GUIDialog.h" +-#include "utils/XTimeUtils.h" + + #include <cstdint> + +@@ -41,13 +41,13 @@ public: + static InputVerificationResult ShowAndVerifyInput(std::string& strPassword, const std::string& strHeading, bool bGetUserInput); + + void SetHeading(const std::string &strHeading); +- void SetMode(INPUT_MODE mode, const KODI::TIME::SystemTime& initial); ++ void SetMode(INPUT_MODE mode, const CDateTime& initial); + void SetMode(INPUT_MODE mode, const std::string &initial); +- KODI::TIME::SystemTime GetOutput() const; ++ CDateTime GetOutput() const; + std::string GetOutputString() const; + +- static bool ShowAndGetTime(KODI::TIME::SystemTime& time, const std::string& heading); +- static bool ShowAndGetDate(KODI::TIME::SystemTime& date, const std::string& heading); ++ static bool ShowAndGetTime(CDateTime& time, const std::string& heading); ++ static bool ShowAndGetDate(CDateTime& date, const std::string& heading); + static bool ShowAndGetIPAddress(std::string &IPAddress, const std::string &heading); + static bool ShowAndGetNumber(std::string& strInput, const std::string &strHeading, unsigned int iAutoCloseTimeoutMs = 0, bool bSetHidden = false); + static bool ShowAndGetSeconds(std::string& timeString, const std::string &heading); +@@ -73,7 +73,7 @@ protected: + bool m_bCanceled; + + INPUT_MODE m_mode; // the current input mode +- KODI::TIME::SystemTime m_datetime; // for time and date modes ++ CDateTime m_datetime; // for time and date modes + uint8_t m_ip[4]; // for ip address mode + uint32_t m_block; // for time, date, and IP methods. + uint32_t m_lastblock; +diff --git a/xbmc/filesystem/NFSDirectory.cpp b/xbmc/filesystem/NFSDirectory.cpp +index 7feba534c7..69a5dad0f6 100644 +--- a/xbmc/filesystem/NFSDirectory.cpp ++++ b/xbmc/filesystem/NFSDirectory.cpp +@@ -202,7 +202,6 @@ bool CNFSDirectory::GetDirectory(const CURL& url, CFileItemList &items) + { + // We accept nfs://server/path[/file]]]] + int ret = 0; +- KODI::TIME::FileTime fileTime, localTime; + std::unique_lock<CCriticalSection> lock(gNfsConnection); + std::string strDirName=""; + std::string myStrPath(url.Get()); +@@ -248,7 +247,6 @@ bool CNFSDirectory::GetDirectory(const CURL& url, CFileItemList &items) + std::string path(myStrPath + strName); + int64_t iSize = 0; + bool bIsDir = false; +- int64_t lTimeDate = 0; + + //reslove symlinks + if(tmpDirent.type == NF3LNK) +@@ -265,25 +263,13 @@ bool CNFSDirectory::GetDirectory(const CURL& url, CFileItemList &items) + + iSize = tmpDirent.size; + bIsDir = tmpDirent.type == NF3DIR; +- lTimeDate = tmpDirent.mtime.tv_sec; + + if (!StringUtils::EqualsNoCase(strName,".") && !StringUtils::EqualsNoCase(strName,"..") + && !StringUtils::EqualsNoCase(strName,"lost+found")) + { +- if(lTimeDate == 0) // if modification date is missing, use create date +- { +- lTimeDate = tmpDirent.ctime.tv_sec; +- } +- +- long long ll = lTimeDate & 0xffffffff; +- ll *= 10000000ll; +- ll += 116444736000000000ll; +- fileTime.lowDateTime = (DWORD)(ll & 0xffffffff); +- fileTime.highDateTime = (DWORD)(ll >> 32); +- KODI::TIME::FileTimeToLocalFileTime(&fileTime, &localTime); +- + CFileItemPtr pItem(new CFileItem(tmpDirent.name)); +- pItem->m_dateTime=localTime; ++ pItem->m_dateTime = ++ tmpDirent.mtime.tv_sec != 0 ? tmpDirent.mtime.tv_sec : tmpDirent.ctime.tv_sec; + pItem->m_dwSize = iSize; + + if (bIsDir) +diff --git a/xbmc/guilib/GUIEditControl.cpp b/xbmc/guilib/GUIEditControl.cpp +index 325a703152..f5c25adb37 100644 +--- a/xbmc/guilib/GUIEditControl.cpp ++++ b/xbmc/guilib/GUIEditControl.cpp +@@ -297,11 +297,9 @@ void CGUIEditControl::OnClick() + { + CDateTime dateTime; + dateTime.SetFromDBTime(utf8); +- KODI::TIME::SystemTime time; +- dateTime.GetAsSystemTime(time); +- if (CGUIDialogNumeric::ShowAndGetTime(time, !m_inputHeading.empty() ? m_inputHeading : g_localizeStrings.Get(21420))) ++ if (CGUIDialogNumeric::ShowAndGetTime( ++ dateTime, !m_inputHeading.empty() ? m_inputHeading : g_localizeStrings.Get(21420))) + { +- dateTime = CDateTime(time); + utf8 = dateTime.GetAsLocalizedTime("", false); + textChanged = true; + } +@@ -313,11 +311,10 @@ void CGUIEditControl::OnClick() + dateTime.SetFromDBDate(utf8); + if (dateTime < CDateTime(2000,1, 1, 0, 0, 0)) + dateTime = CDateTime(2000, 1, 1, 0, 0, 0); +- KODI::TIME::SystemTime date; +- dateTime.GetAsSystemTime(date); +- if (CGUIDialogNumeric::ShowAndGetDate(date, !m_inputHeading.empty() ? m_inputHeading : g_localizeStrings.Get(21420))) ++ ++ if (CGUIDialogNumeric::ShowAndGetDate( ++ dateTime, !m_inputHeading.empty() ? m_inputHeading : g_localizeStrings.Get(21420))) + { +- dateTime = CDateTime(date); + utf8 = dateTime.GetAsDBDate(); + textChanged = true; + } +diff --git a/xbmc/guilib/GUIRSSControl.h b/xbmc/guilib/GUIRSSControl.h +index 851f72fb3c..1ade92dbaf 100644 +--- a/xbmc/guilib/GUIRSSControl.h ++++ b/xbmc/guilib/GUIRSSControl.h +@@ -62,7 +62,7 @@ protected: + KODI::GUILIB::GUIINFO::CGUIInfoColor m_headlineColor; + + std::vector<std::string> m_vecUrls; +- std::vector<int> m_vecIntervals; ++ std::vector<std::chrono::nanoseconds> m_vecIntervals; + bool m_rtl; + CScrollInfo m_scrollInfo; + bool m_dirty; +diff --git a/xbmc/interfaces/legacy/Dialog.cpp b/xbmc/interfaces/legacy/Dialog.cpp +index 6dd00f179b..5e9db03da6 100644 +--- a/xbmc/interfaces/legacy/Dialog.cpp ++++ b/xbmc/interfaces/legacy/Dialog.cpp +@@ -286,8 +286,8 @@ namespace XBMCAddon + { + DelayedCallGuard dcguard(languageHook); + std::string value; +- KODI::TIME::SystemTime timedate; +- KODI::TIME::GetLocalTime(&timedate); ++ ++ auto timedate = CDateTime::GetCurrentDateTime(); + + if (!heading.empty()) + { +@@ -295,14 +295,13 @@ namespace XBMCAddon + { + if (!defaultt.empty() && defaultt.size() == 10) + { +- const std::string& sDefault = defaultt; +- timedate.day = atoi(sDefault.substr(0, 2).c_str()); +- timedate.month = atoi(sDefault.substr(3, 4).c_str()); +- timedate.year = atoi(sDefault.substr(sDefault.size() - 4).c_str()); ++ const std::string sDefault = defaultt; ++ timedate.SetFromDBDate(sDefault.substr(sDefault.size() - 4) + "-" + ++ sDefault.substr(3, 4) + "-" + sDefault.substr(0, 2)); + } + if (CGUIDialogNumeric::ShowAndGetDate(timedate, heading)) +- value = +- StringUtils::Format("{:2}/{:2}/{:4}", timedate.day, timedate.month, timedate.year); ++ value = StringUtils::Format("{:2}/{:2}/{:4}", timedate.GetDay(), timedate.GetMonth(), ++ timedate.GetYear()); + else + return emptyString; + } +@@ -310,12 +309,11 @@ namespace XBMCAddon + { + if (!defaultt.empty() && defaultt.size() == 5) + { +- const std::string& sDefault = defaultt; +- timedate.hour = atoi(sDefault.substr(0, 2).c_str()); +- timedate.minute = atoi(sDefault.substr(3, 2).c_str()); ++ const std::string sDefault = defaultt; ++ timedate.SetFromDBTime(sDefault.substr(0, 2) + ":" + sDefault.substr(3, 2)); + } + if (CGUIDialogNumeric::ShowAndGetTime(timedate, heading)) +- value = StringUtils::Format("{:2}:{:02}", timedate.hour, timedate.minute); ++ value = StringUtils::Format("{:2}:{:02}", timedate.GetHour(), timedate.GetMinute()); + else + return emptyString; + } +@@ -367,8 +365,8 @@ namespace XBMCAddon + { + DelayedCallGuard dcguard(languageHook); + std::string value(defaultt); +- KODI::TIME::SystemTime timedate; +- KODI::TIME::GetLocalTime(&timedate); ++ ++ auto timedate = CDateTime::GetCurrentDateTime(); + + switch (type) + { +@@ -389,14 +387,13 @@ namespace XBMCAddon + { + if (!defaultt.empty() && defaultt.size() == 10) + { +- const std::string& sDefault = defaultt; +- timedate.day = atoi(sDefault.substr(0, 2).c_str()); +- timedate.month = atoi(sDefault.substr(3, 4).c_str()); +- timedate.year = atoi(sDefault.substr(sDefault.size() - 4).c_str()); ++ const std::string sDefault = defaultt; ++ timedate.SetFromDBDate(sDefault.substr(sDefault.size() - 4) + "-" + ++ sDefault.substr(3, 4) + "-" + sDefault.substr(0, 2)); + } + if (CGUIDialogNumeric::ShowAndGetDate(timedate, heading)) +- value = StringUtils::Format("{:2}/{:2}/{:4}", timedate.day, timedate.month, +- timedate.year); ++ value = StringUtils::Format("{:2}/{:2}/{:4}", timedate.GetDay(), timedate.GetMonth(), ++ timedate.GetYear()); + else + value = emptyString; + } +@@ -405,12 +402,11 @@ namespace XBMCAddon + { + if (!defaultt.empty() && defaultt.size() == 5) + { +- const std::string& sDefault = defaultt; +- timedate.hour = atoi(sDefault.substr(0, 2).c_str()); +- timedate.minute = atoi(sDefault.substr(3, 2).c_str()); ++ const std::string sDefault = defaultt; ++ timedate.SetFromDBTime(sDefault.substr(0, 2) + ":" + sDefault.substr(3, 2)); + } + if (CGUIDialogNumeric::ShowAndGetTime(timedate, heading)) +- value = StringUtils::Format("{:2}:{:02}", timedate.hour, timedate.minute); ++ value = StringUtils::Format("{:2}:{:02}", timedate.GetHour(), timedate.GetMinute()); + else + value = emptyString; + } +diff --git a/xbmc/music/infoscanner/MusicInfoScanner.cpp b/xbmc/music/infoscanner/MusicInfoScanner.cpp +index f828b44914..3912892343 100644 +--- a/xbmc/music/infoscanner/MusicInfoScanner.cpp ++++ b/xbmc/music/infoscanner/MusicInfoScanner.cpp +@@ -1269,8 +1269,8 @@ int CMusicInfoScanner::GetPathHash(const CFileItemList &items, std::string &hash + const CFileItemPtr pItem = items[i]; + digest.Update(pItem->GetPath()); + digest.Update((unsigned char *)&pItem->m_dwSize, sizeof(pItem->m_dwSize)); +- KODI::TIME::FileTime time = pItem->m_dateTime; +- digest.Update((unsigned char*)&time, sizeof(KODI::TIME::FileTime)); ++ const auto time = pItem->m_dateTime.GetAsTimePoint().time_since_epoch().count(); ++ digest.Update(&time, sizeof(std::chrono::nanoseconds)); + if (pItem->IsAudio() && !pItem->IsPlayList() && !pItem->IsNFO()) + count++; + } +diff --git a/xbmc/network/upnp/UPnPInternal.cpp b/xbmc/network/upnp/UPnPInternal.cpp +index 406615768a..1a98b86c50 100644 +--- a/xbmc/network/upnp/UPnPInternal.cpp ++++ b/xbmc/network/upnp/UPnPInternal.cpp +@@ -1067,11 +1067,19 @@ std::shared_ptr<CFileItem> BuildObject(PLT_MediaObject* entry, + } + + // look for date? +- if(entry->m_Description.date.GetLength()) { +- KODI::TIME::SystemTime time = {}; +- sscanf(entry->m_Description.date, "%hu-%hu-%huT%hu:%hu:%hu", &time.year, &time.month, &time.day, +- &time.hour, &time.minute, &time.second); +- pItem->m_dateTime = time; ++ if (entry->m_Description.date.GetLength()) ++ { ++ int year; ++ int month; ++ int day; ++ int hour; ++ int minute; ++ int second; ++ ++ sscanf(entry->m_Description.date, "%u-%u-%uT%u:%u:%u", &year, &month, &day, &hour, &minute, ++ &second); ++ ++ pItem->m_dateTime.SetDateTime(year, month, day, hour, minute, second); + } + + // if there is a thumbnail available set it here +diff --git a/xbmc/platform/posix/XTimeUtils.cpp b/xbmc/platform/posix/XTimeUtils.cpp +index e78e5cff48..7d4b17686a 100644 +--- a/xbmc/platform/posix/XTimeUtils.cpp ++++ b/xbmc/platform/posix/XTimeUtils.cpp +@@ -8,221 +8,10 @@ + + #include "utils/XTimeUtils.h" + +-#include "PosixTimezone.h" +- +-#include <errno.h> +-#include <mutex> +-#include <time.h> +- +-#include <sys/times.h> +- +-#if defined(TARGET_ANDROID) && !defined(__LP64__) +-#include <time64.h> +-#endif +- +-#define WIN32_TIME_OFFSET ((unsigned long long)(369 * 365 + 89) * 24 * 3600 * 10000000) +- + namespace KODI + { + namespace TIME + { + +-/* +- * A Leap year is any year that is divisible by four, but not by 100 unless also +- * divisible by 400 +- */ +-#define IsLeapYear(y) ((!(y % 4)) ? (((!(y % 400)) && (y % 100)) ? 1 : 0) : 0) +- +-uint32_t GetTimeZoneInformation(TimeZoneInformation* timeZoneInformation) +-{ +- if (!timeZoneInformation) +- return KODI_TIME_ZONE_ID_INVALID; +- +- struct tm t; +- time_t tt = time(NULL); +- if (localtime_r(&tt, &t)) +- timeZoneInformation->bias = -t.tm_gmtoff / 60; +- +- timeZoneInformation->standardName = tzname[0]; +- timeZoneInformation->daylightName = tzname[1]; +- +- return KODI_TIME_ZONE_ID_UNKNOWN; +-} +- +-void GetLocalTime(SystemTime* systemTime) +-{ +- const time_t t = time(NULL); +- struct tm now; +- +- localtime_r(&t, &now); +- systemTime->year = now.tm_year + 1900; +- systemTime->month = now.tm_mon + 1; +- systemTime->dayOfWeek = now.tm_wday; +- systemTime->day = now.tm_mday; +- systemTime->hour = now.tm_hour; +- 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) +-{ +- ULARGE_INTEGER l; +- l.u.LowPart = fileTime->lowDateTime; +- l.u.HighPart = fileTime->highDateTime; +- +- time_t ft; +- struct tm tm_ft; +- FileTimeToTimeT(fileTime, &ft); +- localtime_r(&ft, &tm_ft); +- +- l.QuadPart += static_cast<unsigned long long>(tm_ft.tm_gmtoff) * 10000000; +- +- localFileTime->lowDateTime = l.u.LowPart; +- localFileTime->highDateTime = l.u.HighPart; +- return 1; +-} +- +-int SystemTimeToFileTime(const SystemTime* systemTime, FileTime* fileTime) +-{ +- static const int dayoffset[12] = {0, 31, 59, 90, 120, 151, 182, 212, 243, 273, 304, 334}; +-#if defined(TARGET_DARWIN) +- static std::mutex timegm_lock; +-#endif +- +- struct tm sysTime = {}; +- sysTime.tm_year = systemTime->year - 1900; +- sysTime.tm_mon = systemTime->month - 1; +- sysTime.tm_wday = systemTime->dayOfWeek; +- sysTime.tm_mday = systemTime->day; +- sysTime.tm_hour = systemTime->hour; +- 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)) +- sysTime.tm_yday++; +- +-#if defined(TARGET_DARWIN) +- std::lock_guard<std::mutex> lock(timegm_lock); +-#endif +- +-#if defined(TARGET_ANDROID) && !defined(__LP64__) +- time64_t t = timegm64(&sysTime); +-#else +- time_t t = timegm(&sysTime); +-#endif +- +- LARGE_INTEGER result; +- result.QuadPart = (long long)t * 10000000 + (long long)systemTime->milliseconds * 10000; +- result.QuadPart += WIN32_TIME_OFFSET; +- +- fileTime->lowDateTime = result.u.LowPart; +- fileTime->highDateTime = result.u.HighPart; +- +- return 1; +-} +- +-long CompareFileTime(const FileTime* fileTime1, const FileTime* fileTime2) +-{ +- ULARGE_INTEGER t1; +- t1.u.LowPart = fileTime1->lowDateTime; +- t1.u.HighPart = fileTime1->highDateTime; +- +- ULARGE_INTEGER t2; +- t2.u.LowPart = fileTime2->lowDateTime; +- t2.u.HighPart = fileTime2->highDateTime; +- +- if (t1.QuadPart == t2.QuadPart) +- return 0; +- else if (t1.QuadPart < t2.QuadPart) +- return -1; +- else +- return 1; +-} +- +-int FileTimeToSystemTime(const FileTime* fileTime, SystemTime* systemTime) +-{ +- LARGE_INTEGER file; +- file.u.LowPart = fileTime->lowDateTime; +- file.u.HighPart = fileTime->highDateTime; +- +- file.QuadPart -= WIN32_TIME_OFFSET; +- file.QuadPart /= 10000; /* to milliseconds */ +- systemTime->milliseconds = file.QuadPart % 1000; +- file.QuadPart /= 1000; /* to seconds */ +- +- time_t ft = file.QuadPart; +- +- struct tm tm_ft; +- gmtime_r(&ft, &tm_ft); +- +- systemTime->year = tm_ft.tm_year + 1900; +- systemTime->month = tm_ft.tm_mon + 1; +- systemTime->dayOfWeek = tm_ft.tm_wday; +- systemTime->day = tm_ft.tm_mday; +- systemTime->hour = tm_ft.tm_hour; +- systemTime->minute = tm_ft.tm_min; +- systemTime->second = tm_ft.tm_sec; +- +- return 1; +-} +- +-int LocalFileTimeToFileTime(const FileTime* localFileTime, FileTime* fileTime) +-{ +- ULARGE_INTEGER l; +- l.u.LowPart = localFileTime->lowDateTime; +- l.u.HighPart = localFileTime->highDateTime; +- +- l.QuadPart += (unsigned long long) timezone * 10000000; +- +- fileTime->lowDateTime = l.u.LowPart; +- fileTime->highDateTime = l.u.HighPart; +- +- return 1; +-} +- +- +-int FileTimeToTimeT(const FileTime* localFileTime, time_t* pTimeT) +-{ +- if (!localFileTime || !pTimeT) +- return false; +- +- ULARGE_INTEGER fileTime; +- fileTime.u.LowPart = localFileTime->lowDateTime; +- fileTime.u.HighPart = localFileTime->highDateTime; +- +- fileTime.QuadPart -= WIN32_TIME_OFFSET; +- fileTime.QuadPart /= 10000; /* to milliseconds */ +- fileTime.QuadPart /= 1000; /* to seconds */ +- +- time_t ft = fileTime.QuadPart; +- +- struct tm tm_ft; +- localtime_r(&ft, &tm_ft); +- +- *pTimeT = mktime(&tm_ft); +- return 1; +-} +- +-int TimeTToFileTime(time_t timeT, FileTime* localFileTime) +-{ +- if (!localFileTime) +- return false; +- +- ULARGE_INTEGER result; +- result.QuadPart = (unsigned long long) timeT * 10000000; +- result.QuadPart += WIN32_TIME_OFFSET; +- +- localFileTime->lowDateTime = result.u.LowPart; +- localFileTime->highDateTime = result.u.HighPart; +- +- return 1; +-} +- + } // namespace TIME + } // namespace KODI +diff --git a/xbmc/platform/posix/filesystem/PosixDirectory.cpp b/xbmc/platform/posix/filesystem/PosixDirectory.cpp +index 6685c0e1db..7482a73960 100644 +--- a/xbmc/platform/posix/filesystem/PosixDirectory.cpp ++++ b/xbmc/platform/posix/filesystem/PosixDirectory.cpp +@@ -79,10 +79,7 @@ bool CPosixDirectory::GetDirectory(const CURL& url, CFileItemList &items) + { + if (bStat || stat(pItem->GetPath().c_str(), &buffer) == 0) + { +- KODI::TIME::FileTime fileTime, localTime; +- KODI::TIME::TimeTToFileTime(buffer.st_mtime, &fileTime); +- KODI::TIME::FileTimeToLocalFileTime(&fileTime, &localTime); +- pItem->m_dateTime = localTime; ++ pItem->m_dateTime = buffer.st_mtime; + + if (!pItem->m_bIsFolder) + pItem->m_dwSize = buffer.st_size; +diff --git a/xbmc/platform/posix/filesystem/SMBDirectory.cpp b/xbmc/platform/posix/filesystem/SMBDirectory.cpp +index e2305afb4a..f0b94c22fc 100644 +--- a/xbmc/platform/posix/filesystem/SMBDirectory.cpp ++++ b/xbmc/platform/posix/filesystem/SMBDirectory.cpp +@@ -134,10 +134,10 @@ bool CSMBDirectory::GetDirectory(const CURL& url, CFileItemList &items) + && strFile != "lost+found" + && aDir.type != SMBC_PRINTER_SHARE && aDir.type != SMBC_IPC_SHARE) + { +- int64_t iSize = 0; ++ int64_t iSize = 0; + bool bIsDir = true; +- int64_t lTimeDate = 0; + bool hidden = false; ++ struct stat info = {}; + + if(StringUtils::EndsWith(strFile, "$") && aDir.type == SMBC_FILE_SHARE ) + continue; +@@ -152,7 +152,6 @@ bool CSMBDirectory::GetDirectory(const CURL& url, CFileItemList &items) + // set this here to if the stat should fail + bIsDir = (aDir.type == SMBC_DIR); + +- struct stat info = {}; + if ((m_flags & DIR_FLAG_NO_FILE_INFO)==0 && CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_sambastatfiles) + { + // make sure we use the authenticated path which contains any default username +@@ -187,9 +186,6 @@ bool CSMBDirectory::GetDirectory(const CURL& url, CFileItemList &items) + CURL::GetRedacted(strFullName), errno, strerror(errno)); + + bIsDir = S_ISDIR(info.st_mode); +- lTimeDate = info.st_mtime; +- if(lTimeDate == 0) // if modification date is missing, use create date +- lTimeDate = info.st_ctime; + iSize = info.st_size; + } + else +@@ -200,10 +196,6 @@ bool CSMBDirectory::GetDirectory(const CURL& url, CFileItemList &items) + } + } + +- KODI::TIME::FileTime fileTime, localTime; +- KODI::TIME::TimeTToFileTime(lTimeDate, &fileTime); +- KODI::TIME::FileTimeToLocalFileTime(&fileTime, &localTime); +- + if (bIsDir) + { + CFileItemPtr pItem(new CFileItem(strFile)); +@@ -223,7 +215,7 @@ bool CSMBDirectory::GetDirectory(const CURL& url, CFileItemList &items) + URIUtils::AddSlashAtEnd(path); + pItem->SetPath(path); + pItem->m_bIsFolder = true; +- pItem->m_dateTime=localTime; ++ pItem->m_dateTime = info.st_mtime != 0 ? info.st_mtime : info.st_ctime; + if (hidden) + pItem->SetProperty("file:hidden", true); + items.Add(pItem); +@@ -234,7 +226,7 @@ bool CSMBDirectory::GetDirectory(const CURL& url, CFileItemList &items) + pItem->SetPath(strRoot + aDir.name); + pItem->m_bIsFolder = false; + pItem->m_dwSize = iSize; +- pItem->m_dateTime=localTime; ++ pItem->m_dateTime = info.st_mtime != 0 ? info.st_mtime : info.st_ctime; + if (hidden) + pItem->SetProperty("file:hidden", true); + items.Add(pItem); +diff --git a/xbmc/pvr/dialogs/GUIDialogPVRTimerSettings.cpp b/xbmc/pvr/dialogs/GUIDialogPVRTimerSettings.cpp +index f7866278e7..e61761b0ab 100644 +--- a/xbmc/pvr/dialogs/GUIDialogPVRTimerSettings.cpp ++++ b/xbmc/pvr/dialogs/GUIDialogPVRTimerSettings.cpp +@@ -573,22 +573,16 @@ void CGUIDialogPVRTimerSettings::OnSettingAction(const std::shared_ptr<const CSe + const std::string& settingId = setting->GetId(); + if (settingId == SETTING_TMR_BEGIN) + { +- KODI::TIME::SystemTime timerStartTime; +- m_startLocalTime.GetAsSystemTime(timerStartTime); +- if (CGUIDialogNumeric::ShowAndGetTime(timerStartTime, g_localizeStrings.Get(14066))) ++ if (CGUIDialogNumeric::ShowAndGetTime(m_startLocalTime, g_localizeStrings.Get(14066))) + { +- SetTimeFromSystemTime(m_startLocalTime, timerStartTime); + m_timerStartTimeStr = m_startLocalTime.GetAsLocalizedTime("", false); + SetButtonLabels(); + } + } + else if (settingId == SETTING_TMR_END) + { +- KODI::TIME::SystemTime timerEndTime; +- m_endLocalTime.GetAsSystemTime(timerEndTime); +- if (CGUIDialogNumeric::ShowAndGetTime(timerEndTime, g_localizeStrings.Get(14066))) ++ if (CGUIDialogNumeric::ShowAndGetTime(m_endLocalTime, g_localizeStrings.Get(14066))) + { +- SetTimeFromSystemTime(m_endLocalTime, timerEndTime); + m_timerEndTimeStr = m_endLocalTime.GetAsLocalizedTime("", false); + SetButtonLabels(); + } +@@ -800,14 +794,6 @@ void CGUIDialogPVRTimerSettings::SetDateFromIndex(CDateTime& datetime, int date) + datetime.GetMinute(), datetime.GetSecond()); + } + +-void CGUIDialogPVRTimerSettings::SetTimeFromSystemTime(CDateTime& datetime, +- const KODI::TIME::SystemTime& time) +-{ +- const CDateTime newTime(time); +- datetime.SetDateTime(datetime.GetYear(), datetime.GetMonth(), datetime.GetDay(), +- newTime.GetHour(), newTime.GetMinute(), newTime.GetSecond()); +-} +- + void CGUIDialogPVRTimerSettings::InitializeTypesList() + { + m_typeEntries.clear(); +diff --git a/xbmc/pvr/dialogs/GUIDialogPVRTimerSettings.h b/xbmc/pvr/dialogs/GUIDialogPVRTimerSettings.h +index d3e9e3eadf..d419e4a722 100644 +--- a/xbmc/pvr/dialogs/GUIDialogPVRTimerSettings.h ++++ b/xbmc/pvr/dialogs/GUIDialogPVRTimerSettings.h +@@ -59,7 +59,6 @@ private: + + static int GetDateAsIndex(const CDateTime& datetime); + static void SetDateFromIndex(CDateTime& datetime, int date); +- static void SetTimeFromSystemTime(CDateTime& datetime, const KODI::TIME::SystemTime& time); + + static int GetWeekdaysFromSetting(const std::shared_ptr<const CSetting>& setting); + +diff --git a/xbmc/pvr/windows/GUIWindowPVRGuide.cpp b/xbmc/pvr/windows/GUIWindowPVRGuide.cpp +index f4c247f910..d85e7bf493 100644 +--- a/xbmc/pvr/windows/GUIWindowPVRGuide.cpp ++++ b/xbmc/pvr/windows/GUIWindowPVRGuide.cpp +@@ -800,13 +800,12 @@ bool CGUIWindowPVRGuideBase::OpenDateSelectionDialog() + { + bool bReturn = false; + +- KODI::TIME::SystemTime date; + CGUIEPGGridContainer* epgGridContainer = GetGridControl(); +- epgGridContainer->GetSelectedDate().GetAsSystemTime(date); ++ CDateTime datetime = epgGridContainer->GetSelectedDate(); + +- if (CGUIDialogNumeric::ShowAndGetDate(date, g_localizeStrings.Get(19288))) /* Go to date */ ++ if (CGUIDialogNumeric::ShowAndGetDate(datetime, g_localizeStrings.Get(19288))) /* Go to date */ + { +- epgGridContainer->GoToDate(CDateTime(date)); ++ epgGridContainer->GoToDate(datetime); + bReturn = true; + } + +diff --git a/xbmc/settings/windows/GUIControlSettings.cpp b/xbmc/settings/windows/GUIControlSettings.cpp +index fcbf1fa908..6c9eb3ea68 100644 +--- a/xbmc/settings/windows/GUIControlSettings.cpp ++++ b/xbmc/settings/windows/GUIControlSettings.cpp +@@ -989,21 +989,19 @@ bool CGUIControlButtonSetting::OnClick() + std::shared_ptr<CSettingDate> settingDate = + std::static_pointer_cast<CSettingDate>(m_pSetting); + +- KODI::TIME::SystemTime systemdate; +- settingDate->GetDate().GetAsSystemTime(systemdate); +- if (CGUIDialogNumeric::ShowAndGetDate(systemdate, Localize(buttonControl->GetHeading()))) +- SetValid(settingDate->SetDate(CDateTime(systemdate))); ++ CDateTime datetime = settingDate->GetDate(); ++ if (CGUIDialogNumeric::ShowAndGetDate(datetime, Localize(buttonControl->GetHeading()))) ++ SetValid(settingDate->SetDate(datetime)); + } + else if (controlFormat == "time") + { + std::shared_ptr<CSettingTime> settingTime = + std::static_pointer_cast<CSettingTime>(m_pSetting); + +- KODI::TIME::SystemTime systemtime; +- settingTime->GetTime().GetAsSystemTime(systemtime); ++ CDateTime datetime = settingTime->GetTime(); + +- if (CGUIDialogNumeric::ShowAndGetTime(systemtime, Localize(buttonControl->GetHeading()))) +- SetValid(settingTime->SetTime(CDateTime(systemtime))); ++ if (CGUIDialogNumeric::ShowAndGetTime(datetime, Localize(buttonControl->GetHeading()))) ++ SetValid(settingTime->SetTime(datetime)); + } + else if (controlFormat == "action") + { +diff --git a/xbmc/test/TestDateTime.cpp b/xbmc/test/TestDateTime.cpp +index a553bd1887..a8e61e9785 100644 +--- a/xbmc/test/TestDateTime.cpp ++++ b/xbmc/test/TestDateTime.cpp +@@ -36,17 +36,16 @@ TEST_F(TestDateTime, DateTimeOperators) + EXPECT_FALSE(dateTime1 == dateTime2); + } + +-TEST_F(TestDateTime, SystemTimeOperators) ++TEST_F(TestDateTime, TimePointOperators) + { + CDateTime dateTime1(1991, 5, 14, 12, 34, 56); + CDateTime dateTime2(1991, 5, 14, 12, 34, 57); + +- KODI::TIME::SystemTime systemTime; +- dateTime2.GetAsSystemTime(systemTime); ++ auto tp = dateTime2.GetAsTimePoint(); + +- EXPECT_TRUE(dateTime1 < systemTime); +- EXPECT_FALSE(dateTime1 > systemTime); +- EXPECT_FALSE(dateTime1 == systemTime); ++ EXPECT_TRUE(dateTime1 < tp); ++ EXPECT_FALSE(dateTime1 > tp); ++ EXPECT_FALSE(dateTime1 == tp); + } + + TEST_F(TestDateTime, TimeTOperators) +@@ -529,15 +528,14 @@ TEST_F(TestDateTime, GetAsLocalized) + EXPECT_EQ(dateTime2.GetAsLocalizedTime(TIME_FORMAT(256)), "5"); + } + +-TEST_F(TestDateTime, GetAsSystemTime) ++TEST_F(TestDateTime, GetAsTimePoint) + { + CDateTime dateTime; + dateTime.SetDateTime(1991, 05, 14, 12, 34, 56); + +- KODI::TIME::SystemTime systemTime; +- dateTime.GetAsSystemTime(systemTime); ++ auto tp = dateTime.GetAsTimePoint(); + +- EXPECT_TRUE(dateTime == systemTime); ++ EXPECT_TRUE(dateTime == tp); + } + + TEST_F(TestDateTime, GetAsTime) +diff --git a/xbmc/utils/Archive.cpp b/xbmc/utils/Archive.cpp +index 4f69929a42..0275c057f9 100644 +--- a/xbmc/utils/Archive.cpp ++++ b/xbmc/utils/Archive.cpp +@@ -152,9 +152,9 @@ CArchive& CArchive::operator<<(const std::wstring& wstr) + return streamout(wstr.data(), size * sizeof(wchar_t)); + } + +-CArchive& CArchive::operator<<(const KODI::TIME::SystemTime& time) ++CArchive& CArchive::operator<<(const std::chrono::system_clock::time_point& time) + { +- return streamout(&time, sizeof(KODI::TIME::SystemTime)); ++ return streamout(&time, sizeof(std::chrono::system_clock::time_point)); + } + + CArchive& CArchive::operator<<(IArchivable& obj) +@@ -265,9 +265,9 @@ CArchive& CArchive::operator>>(std::wstring& wstr) + return *this; + } + +-CArchive& CArchive::operator>>(KODI::TIME::SystemTime& time) ++CArchive& CArchive::operator>>(std::chrono::system_clock::time_point& time) + { +- return streamin(&time, sizeof(KODI::TIME::SystemTime)); ++ return streamin(&time, sizeof(std::chrono::system_clock::time_point)); + } + + CArchive& CArchive::operator>>(IArchivable& obj) +diff --git a/xbmc/utils/Archive.h b/xbmc/utils/Archive.h +index a1af0c3cf8..86a2bebc23 100644 +--- a/xbmc/utils/Archive.h ++++ b/xbmc/utils/Archive.h +@@ -57,7 +57,7 @@ public: + CArchive& operator<<(char c); + CArchive& operator<<(const std::string &str); + CArchive& operator<<(const std::wstring& wstr); +- CArchive& operator<<(const KODI::TIME::SystemTime& time); ++ CArchive& operator<<(const std::chrono::system_clock::time_point& time); + CArchive& operator<<(IArchivable& obj); + CArchive& operator<<(const CVariant& variant); + CArchive& operator<<(const std::vector<std::string>& strArray); +@@ -126,7 +126,7 @@ public: + + CArchive& operator>>(std::string &str); + CArchive& operator>>(std::wstring& wstr); +- CArchive& operator>>(KODI::TIME::SystemTime& time); ++ CArchive& operator>>(std::chrono::system_clock::time_point& time); + CArchive& operator>>(IArchivable& obj); + CArchive& operator>>(CVariant& variant); + CArchive& operator>>(std::vector<std::string>& strArray); +diff --git a/xbmc/utils/RssManager.cpp b/xbmc/utils/RssManager.cpp +index b8d350cac5..5e77dd7c13 100644 +--- a/xbmc/utils/RssManager.cpp ++++ b/xbmc/utils/RssManager.cpp +@@ -142,7 +142,7 @@ bool CRssManager::Load() + //! What about the xml encoding? + std::string strUrl = pFeed->FirstChild()->ValueStr(); + set.url.push_back(strUrl); +- set.interval.push_back(iInterval); ++ set.interval.push_back(std::chrono::minutes(iInterval)); + } + pFeed = pFeed->NextSiblingElement("feed"); + } +diff --git a/xbmc/utils/RssManager.h b/xbmc/utils/RssManager.h +index 2b807d739f..59ac506307 100644 +--- a/xbmc/utils/RssManager.h ++++ b/xbmc/utils/RssManager.h +@@ -22,7 +22,7 @@ class IRssObserver; + typedef struct + { + bool rtl; +- std::vector<int> interval; ++ std::vector<std::chrono::nanoseconds> interval; + std::vector<std::string> url; + } RssSet; + typedef std::map<int, RssSet> RssUrls; +diff --git a/xbmc/utils/RssReader.cpp b/xbmc/utils/RssReader.cpp +index 0b227b63d3..f9f1e4a845 100644 +--- a/xbmc/utils/RssReader.cpp ++++ b/xbmc/utils/RssReader.cpp +@@ -51,11 +51,14 @@ CRssReader::~CRssReader() + if (m_pObserver) + m_pObserver->OnFeedRelease(); + StopThread(); +- for (unsigned int i = 0; i < m_vecTimeStamps.size(); i++) +- delete m_vecTimeStamps[i]; ++ m_vecTimeStamps.clear(); + } + +-void CRssReader::Create(IRssObserver* aObserver, const std::vector<std::string>& aUrls, const std::vector<int> ×, int spacesBetweenFeeds, bool rtl) ++void CRssReader::Create(IRssObserver* aObserver, ++ const std::vector<std::string>& aUrls, ++ const std::vector<std::chrono::nanoseconds>& times, ++ int spacesBetweenFeeds, ++ bool rtl) + { + std::unique_lock<CCriticalSection> lock(m_critical); + +@@ -73,9 +76,7 @@ void CRssReader::Create(IRssObserver* aObserver, const std::vector<std::string>& + for (unsigned int i = 0; i < m_vecUpdateTimes.size(); ++i) + { + AddToQueue(i); +- KODI::TIME::SystemTime* time = new KODI::TIME::SystemTime; +- KODI::TIME::GetLocalTime(time); +- m_vecTimeStamps.push_back(time); ++ m_vecTimeStamps.push_back(std::chrono::system_clock::now().time_since_epoch()); + } + } + +@@ -395,18 +396,14 @@ void CRssReader::UpdateObserver() + + void CRssReader::CheckForUpdates() + { +- KODI::TIME::SystemTime time; +- KODI::TIME::GetLocalTime(&time); +- + for (unsigned int i = 0;i < m_vecUpdateTimes.size(); ++i ) + { +- if (m_requestRefresh || ((time.day * 24 * 60) + (time.hour * 60) + time.minute) - +- ((m_vecTimeStamps[i]->day * 24 * 60) + +- (m_vecTimeStamps[i]->hour * 60) + m_vecTimeStamps[i]->minute) > +- m_vecUpdateTimes[i]) ++ if (m_requestRefresh || ++ (std::chrono::system_clock::now().time_since_epoch() - m_vecTimeStamps[i] > ++ m_vecUpdateTimes[i])) + { + CLog::Log(LOGDEBUG, "Updating RSS"); +- KODI::TIME::GetLocalTime(m_vecTimeStamps[i]); ++ m_vecTimeStamps[i] = std::chrono::system_clock::now().time_since_epoch(); + AddToQueue(i); + } + } +diff --git a/xbmc/utils/RssReader.h b/xbmc/utils/RssReader.h +index ae9d2f73ca..43c6bde609 100644 +--- a/xbmc/utils/RssReader.h ++++ b/xbmc/utils/RssReader.h +@@ -28,7 +28,11 @@ public: + CRssReader(); + ~CRssReader() override; + +- void Create(IRssObserver* aObserver, const std::vector<std::string>& aUrl, const std::vector<int>& times, int spacesBetweenFeeds, bool rtl); ++ void Create(IRssObserver* aObserver, ++ const std::vector<std::string>& aUrl, ++ const std::vector<std::chrono::nanoseconds>& times, ++ int spacesBetweenFeeds, ++ bool rtl); + bool Parse(const std::string& data, int iFeed, const std::string& charset); + void getFeed(vecText &text); + void AddTag(const std::string &addTag); +@@ -52,8 +56,8 @@ private: + + std::vector<std::wstring> m_strFeed; + std::vector<std::wstring> m_strColors; +- std::vector<KODI::TIME::SystemTime*> m_vecTimeStamps; +- std::vector<int> m_vecUpdateTimes; ++ std::vector<std::chrono::nanoseconds> m_vecTimeStamps; ++ std::vector<std::chrono::nanoseconds> m_vecUpdateTimes; + int m_spacesBetweenFeeds; + CXBMCTinyXML m_xml; + std::list<std::string> m_tagSet; +diff --git a/xbmc/utils/XTimeUtils.h b/xbmc/utils/XTimeUtils.h +index 91cda40305..9d3b0e86a3 100644 +--- a/xbmc/utils/XTimeUtils.h ++++ b/xbmc/utils/XTimeUtils.h +@@ -27,42 +27,6 @@ namespace KODI + { + namespace TIME + { +-struct SystemTime +-{ +- unsigned short year; +- unsigned short month; +- unsigned short dayOfWeek; +- unsigned short day; +- unsigned short hour; +- unsigned short minute; +- unsigned short second; +- unsigned short milliseconds; +-}; +- +-struct TimeZoneInformation +-{ +- long bias; +- std::string standardName; +- SystemTime standardDate; +- long standardBias; +- std::string daylightName; +- SystemTime daylightDate; +- long daylightBias; +-}; +- +-constexpr int KODI_TIME_ZONE_ID_INVALID{-1}; +-constexpr int KODI_TIME_ZONE_ID_UNKNOWN{0}; +-constexpr int KODI_TIME_ZONE_ID_STANDARD{1}; +-constexpr int KODI_TIME_ZONE_ID_DAYLIGHT{2}; +- +-struct FileTime +-{ +- unsigned int lowDateTime; +- unsigned int highDateTime; +-}; +- +-void GetLocalTime(SystemTime* systemTime); +-uint32_t GetTimeZoneInformation(TimeZoneInformation* timeZoneInformation); + + template<typename Rep, typename Period> + void Sleep(std::chrono::duration<Rep, Period> duration) +@@ -76,13 +40,5 @@ void Sleep(std::chrono::duration<Rep, Period> duration) + std::this_thread::sleep_for(duration); + } + +-int FileTimeToLocalFileTime(const FileTime* fileTime, FileTime* localFileTime); +-int SystemTimeToFileTime(const SystemTime* systemTime, FileTime* fileTime); +-long CompareFileTime(const FileTime* fileTime1, const FileTime* fileTime2); +-int FileTimeToSystemTime(const FileTime* fileTime, SystemTime* systemTime); +-int LocalFileTimeToFileTime(const FileTime* LocalFileTime, FileTime* fileTime); +- +-int FileTimeToTimeT(const FileTime* localFileTime, time_t* pTimeT); +-int TimeTToFileTime(time_t timeT, FileTime* localFileTime); + } // namespace TIME + } // namespace KODI +diff --git a/xbmc/utils/test/TestArchive.cpp b/xbmc/utils/test/TestArchive.cpp +index 90628ea2ed..b9ab780cf9 100644 +--- a/xbmc/utils/test/TestArchive.cpp ++++ b/xbmc/utils/test/TestArchive.cpp +@@ -220,22 +220,22 @@ TEST_F(TestArchive, StringArchive) + EXPECT_STREQ(string_ref.c_str(), string_var.c_str()); + } + +-TEST_F(TestArchive, SystemTimeArchive) ++TEST_F(TestArchive, TimePointArchive) + { + ASSERT_NE(nullptr, file); +- KODI::TIME::SystemTime SystemTime_ref = {1, 2, 3, 4, 5, 6, 7, 8}; +- KODI::TIME::SystemTime SystemTime_var = {0, 0, 0, 0, 0, 0, 0, 0}; ++ std::chrono::system_clock::time_point tp_ref = std::chrono::system_clock::now(); ++ std::chrono::system_clock::time_point tp_var; + + CArchive arstore(file, CArchive::store); +- arstore << SystemTime_ref; ++ arstore << tp_ref; + arstore.Close(); + + ASSERT_EQ(0, file->Seek(0, SEEK_SET)); + CArchive arload(file, CArchive::load); +- arload >> SystemTime_var; ++ arload >> tp_var; + arload.Close(); + +- EXPECT_TRUE(!memcmp(&SystemTime_ref, &SystemTime_var, sizeof(KODI::TIME::SystemTime))); ++ EXPECT_TRUE(!memcmp(&tp_ref, &tp_var, sizeof(std::chrono::system_clock::time_point))); + } + + TEST_F(TestArchive, CVariantArchive) +@@ -335,8 +335,8 @@ TEST_F(TestArchive, MultiTypeArchive) + char char_ref = 'A', char_var = '\0'; + std::string string_ref = "test string", string_var; + std::wstring wstring_ref = L"test wstring", wstring_var; +- KODI::TIME::SystemTime SystemTime_ref = {1, 2, 3, 4, 5, 6, 7, 8}; +- KODI::TIME::SystemTime SystemTime_var = {0, 0, 0, 0, 0, 0, 0, 0}; ++ std::chrono::system_clock::time_point tp_ref = std::chrono::system_clock::now(); ++ std::chrono::system_clock::time_point tp_var; + CVariant CVariant_ref((int)1), CVariant_var; + std::vector<std::string> strArray_ref, strArray_var; + strArray_ref.emplace_back("test strArray_ref 0"); +@@ -362,7 +362,7 @@ TEST_F(TestArchive, MultiTypeArchive) + arstore << char_ref; + arstore << string_ref; + arstore << wstring_ref; +- arstore << SystemTime_ref; ++ arstore << tp_ref; + arstore << CVariant_ref; + arstore << strArray_ref; + arstore << iArray_ref; +@@ -382,7 +382,7 @@ TEST_F(TestArchive, MultiTypeArchive) + arload >> char_var; + arload >> string_var; + arload >> wstring_var; +- arload >> SystemTime_var; ++ arload >> tp_var; + arload >> CVariant_var; + arload >> strArray_var; + arload >> iArray_var; +@@ -398,7 +398,7 @@ TEST_F(TestArchive, MultiTypeArchive) + EXPECT_EQ(char_ref, char_var); + EXPECT_STREQ(string_ref.c_str(), string_var.c_str()); + EXPECT_STREQ(wstring_ref.c_str(), wstring_var.c_str()); +- EXPECT_TRUE(!memcmp(&SystemTime_ref, &SystemTime_var, sizeof(KODI::TIME::SystemTime))); ++ EXPECT_TRUE(!memcmp(&tp_ref, &tp_var, sizeof(std::chrono::system_clock::time_point))); + EXPECT_TRUE(CVariant_var.isInteger()); + EXPECT_STREQ("test strArray_ref 0", strArray_var.at(0).c_str()); + EXPECT_STREQ("test strArray_ref 1", strArray_var.at(1).c_str()); +diff --git a/xbmc/video/VideoInfoScanner.cpp b/xbmc/video/VideoInfoScanner.cpp +index 92fa5c191f..8d9cf6979d 100644 +--- a/xbmc/video/VideoInfoScanner.cpp ++++ b/xbmc/video/VideoInfoScanner.cpp +@@ -2005,8 +2005,8 @@ namespace VIDEO + else + { + digest.Update(&pItem->m_dwSize, sizeof(pItem->m_dwSize)); +- KODI::TIME::FileTime time = pItem->m_dateTime; +- digest.Update(&time, sizeof(KODI::TIME::FileTime)); ++ const auto time = pItem->m_dateTime.GetAsTimePoint().time_since_epoch().count(); ++ digest.Update(&time, sizeof(std::chrono::nanoseconds)); + } + if (pItem->IsVideo() && !pItem->IsPlayList() && !pItem->IsNFO()) + count++; +-- +2.43.0 + + +From 466178a3ca4239ff1c837f28ba84283777519990 Mon Sep 17 00:00:00 2001 +From: Vasyl Gello <vasek.gello@gmail.com> +Date: Wed, 21 Oct 2020 09:17:33 +0300 +Subject: [PATCH 07/19] TestDateTime: fix GetAsStringsWithBias and add Tzdata + tests + +The 'GetAsStringsWithBias' test logic assumed the timezone on +machine bullding Kodi is set to 'UTC'. This is not always the case, +plus hour value was declared with a typo. + +To address this, we compare outputs of two runs of date library, +and instead add a 'Tzdata' test case comparing local date and time +against computed values from different timezones: + +find /usr/share/zoneinfo/Etc/ -type f | sort -Vu | sed 's,^/usr/share/zoneinfo/,,' | while read TZ +do + TMSTR=$(LANG=C TZ="$TZ" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/') + echo " // LANG=C TZ=\"$TZ\" date '+%Y-%m-%dT%H:%M:%S%Ez' -d \"1991-05-14 12:34:56 UTC\" | sed 's/[0-9][0-9]$/:&/'" + echo " tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint());" + echo " zone = date::make_zoned(\"$TZ\", tps);" + echo " EXPECT_EQ(date::format(\"%FT%T%Ez\", zone), \"$TMSTR\") << \"tzdata information not valid for '$TZ'\";" + echo "" +done +--- + xbmc/test/TestDateTime.cpp | 168 ++++++++++++++++++++++++++++++++++++- + 1 file changed, 166 insertions(+), 2 deletions(-) + +diff --git a/xbmc/test/TestDateTime.cpp b/xbmc/test/TestDateTime.cpp +index a8e61e9785..0ff2bb443b 100644 +--- a/xbmc/test/TestDateTime.cpp ++++ b/xbmc/test/TestDateTime.cpp +@@ -11,6 +11,7 @@ + #include "guilib/LocalizeStrings.h" + + #include <array> ++#include <chrono> + #include <iostream> + + #define USE_OS_TZDB 0 +@@ -330,10 +331,11 @@ TEST_F(TestDateTime, GetAsStringsWithBias) + std::cout << dateTime.GetAsW3CDateTime(false) << std::endl; + std::cout << dateTime.GetAsW3CDateTime(true) << std::endl; + +- auto zone = date::make_zoned(date::current_zone(), dateTime.GetAsTimePoint()); ++ auto tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint()); ++ auto zone = date::make_zoned(date::current_zone(), tps); + + EXPECT_EQ(dateTime.GetAsRFC1123DateTime(), "Tue, 14 May 1991 12:34:56 GMT"); +- EXPECT_EQ(dateTime.GetAsW3CDateTime(false), "1991-05-14T05:34:56" + date::format("%Ez", zone)); ++ EXPECT_EQ(dateTime.GetAsW3CDateTime(false), date::format("%FT%T%Ez", zone)); + EXPECT_EQ(dateTime.GetAsW3CDateTime(true), "1991-05-14T12:34:56Z"); + } + +@@ -601,3 +603,165 @@ TEST_F(TestDateTime, Reset) + EXPECT_EQ(dateTime.GetMinute(), 0); + EXPECT_EQ(dateTime.GetSecond(), 0); + } ++ ++TEST_F(TestDateTime, Tzdata) ++{ ++ CDateTime dateTime; ++ dateTime.SetDateTime(1991, 05, 14, 12, 34, 56); ++ ++ // LANG=C TZ="Etc/GMT+1" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/' ++ auto tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint()); ++ auto zone = date::make_zoned("Etc/GMT+1", tps); ++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T11:34:56-01:00") ++ << "tzdata information not valid for 'Etc/GMT+1'"; ++ ++ // LANG=C TZ="Etc/GMT+2" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/' ++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint()); ++ zone = date::make_zoned("Etc/GMT+2", tps); ++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T10:34:56-02:00") ++ << "tzdata information not valid for 'Etc/GMT+2'"; ++ ++ // LANG=C TZ="Etc/GMT+3" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/' ++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint()); ++ zone = date::make_zoned("Etc/GMT+3", tps); ++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T09:34:56-03:00") ++ << "tzdata information not valid for 'Etc/GMT+3'"; ++ ++ // LANG=C TZ="Etc/GMT+4" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/' ++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint()); ++ zone = date::make_zoned("Etc/GMT+4", tps); ++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T08:34:56-04:00") ++ << "tzdata information not valid for 'Etc/GMT+4'"; ++ ++ // LANG=C TZ="Etc/GMT+5" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/' ++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint()); ++ zone = date::make_zoned("Etc/GMT+5", tps); ++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T07:34:56-05:00") ++ << "tzdata information not valid for 'Etc/GMT+5'"; ++ ++ // LANG=C TZ="Etc/GMT+6" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/' ++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint()); ++ zone = date::make_zoned("Etc/GMT+6", tps); ++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T06:34:56-06:00") ++ << "tzdata information not valid for 'Etc/GMT+6'"; ++ ++ // LANG=C TZ="Etc/GMT+7" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/' ++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint()); ++ zone = date::make_zoned("Etc/GMT+7", tps); ++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T05:34:56-07:00") ++ << "tzdata information not valid for 'Etc/GMT+7'"; ++ ++ // LANG=C TZ="Etc/GMT+8" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/' ++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint()); ++ zone = date::make_zoned("Etc/GMT+8", tps); ++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T04:34:56-08:00") ++ << "tzdata information not valid for 'Etc/GMT+8'"; ++ ++ // LANG=C TZ="Etc/GMT+9" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/' ++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint()); ++ zone = date::make_zoned("Etc/GMT+9", tps); ++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T03:34:56-09:00") ++ << "tzdata information not valid for 'Etc/GMT+9'"; ++ ++ // LANG=C TZ="Etc/GMT+10" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/' ++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint()); ++ zone = date::make_zoned("Etc/GMT+10", tps); ++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T02:34:56-10:00") ++ << "tzdata information not valid for 'Etc/GMT+10'"; ++ ++ // LANG=C TZ="Etc/GMT+11" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/' ++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint()); ++ zone = date::make_zoned("Etc/GMT+11", tps); ++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T01:34:56-11:00") ++ << "tzdata information not valid for 'Etc/GMT+11'"; ++ ++ // LANG=C TZ="Etc/GMT+12" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/' ++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint()); ++ zone = date::make_zoned("Etc/GMT+12", tps); ++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T00:34:56-12:00") ++ << "tzdata information not valid for 'Etc/GMT+12'"; ++ ++ // LANG=C TZ="Etc/GMT-1" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/' ++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint()); ++ zone = date::make_zoned("Etc/GMT-1", tps); ++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T13:34:56+01:00") ++ << "tzdata information not valid for 'Etc/GMT-1'"; ++ ++ // LANG=C TZ="Etc/GMT-2" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/' ++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint()); ++ zone = date::make_zoned("Etc/GMT-2", tps); ++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T14:34:56+02:00") ++ << "tzdata information not valid for 'Etc/GMT-2'"; ++ ++ // LANG=C TZ="Etc/GMT-3" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/' ++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint()); ++ zone = date::make_zoned("Etc/GMT-3", tps); ++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T15:34:56+03:00") ++ << "tzdata information not valid for 'Etc/GMT-3'"; ++ ++ // LANG=C TZ="Etc/GMT-4" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/' ++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint()); ++ zone = date::make_zoned("Etc/GMT-4", tps); ++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T16:34:56+04:00") ++ << "tzdata information not valid for 'Etc/GMT-4'"; ++ ++ // LANG=C TZ="Etc/GMT-5" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/' ++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint()); ++ zone = date::make_zoned("Etc/GMT-5", tps); ++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T17:34:56+05:00") ++ << "tzdata information not valid for 'Etc/GMT-5'"; ++ ++ // LANG=C TZ="Etc/GMT-6" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/' ++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint()); ++ zone = date::make_zoned("Etc/GMT-6", tps); ++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T18:34:56+06:00") ++ << "tzdata information not valid for 'Etc/GMT-6'"; ++ ++ // LANG=C TZ="Etc/GMT-7" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/' ++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint()); ++ zone = date::make_zoned("Etc/GMT-7", tps); ++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T19:34:56+07:00") ++ << "tzdata information not valid for 'Etc/GMT-7'"; ++ ++ // LANG=C TZ="Etc/GMT-8" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/' ++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint()); ++ zone = date::make_zoned("Etc/GMT-8", tps); ++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T20:34:56+08:00") ++ << "tzdata information not valid for 'Etc/GMT-8'"; ++ ++ // LANG=C TZ="Etc/GMT-9" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/' ++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint()); ++ zone = date::make_zoned("Etc/GMT-9", tps); ++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T21:34:56+09:00") ++ << "tzdata information not valid for 'Etc/GMT-9'"; ++ ++ // LANG=C TZ="Etc/GMT-10" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/' ++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint()); ++ zone = date::make_zoned("Etc/GMT-10", tps); ++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T22:34:56+10:00") ++ << "tzdata information not valid for 'Etc/GMT-10'"; ++ ++ // LANG=C TZ="Etc/GMT-11" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/' ++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint()); ++ zone = date::make_zoned("Etc/GMT-11", tps); ++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-14T23:34:56+11:00") ++ << "tzdata information not valid for 'Etc/GMT-11'"; ++ ++ // LANG=C TZ="Etc/GMT-12" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/' ++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint()); ++ zone = date::make_zoned("Etc/GMT-12", tps); ++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-15T00:34:56+12:00") ++ << "tzdata information not valid for 'Etc/GMT-12'"; ++ ++ // LANG=C TZ="Etc/GMT-13" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/' ++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint()); ++ zone = date::make_zoned("Etc/GMT-13", tps); ++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-15T01:34:56+13:00") ++ << "tzdata information not valid for 'Etc/GMT-13'"; ++ ++ // LANG=C TZ="Etc/GMT-14" date '+%Y-%m-%dT%H:%M:%S%Ez' -d "1991-05-14 12:34:56 UTC" | sed 's/[0-9][0-9]$/:&/' ++ tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint()); ++ zone = date::make_zoned("Etc/GMT-14", tps); ++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-15T02:34:56+14:00") ++ << "tzdata information not valid for 'Etc/GMT-14'"; ++} +-- +2.43.0 + + +From 72720c4e84bbbb1d5859cd727b1068a74a8be3af Mon Sep 17 00:00:00 2001 +From: Vasyl Gello <vasek.gello@gmail.com> +Date: Tue, 3 Nov 2020 17:51:26 +0200 +Subject: [PATCH 08/19] Remove GetAsUTCDateTime and add GetAsLocalDateTime + +The 'm_time' now represents a UTC time-point, so 'GetAsUTCDateTime' +does nothing useful. Remove it fully, and add 'GetAsLocalDateTime' +function that we will use later to convert UTC (system) time to the +local time needed to get displayed in UI. + +Signed-off-by: Vasyl Gello <vasek.gello@gmail.com> +--- + xbmc/XBDateTime.cpp | 9 ++++++--- + xbmc/XBDateTime.h | 4 +++- + xbmc/network/WebServer.cpp | 6 +++--- + xbmc/pvr/epg/EpgContainer.cpp | 14 +++++++------- + xbmc/pvr/epg/EpgInfoTag.cpp | 4 ++-- + xbmc/pvr/guilib/PVRGUIActionsPowerManagement.cpp | 1 - + xbmc/pvr/timers/PVRTimerRuleMatcher.cpp | 2 +- + xbmc/pvr/timers/PVRTimers.cpp | 1 - + xbmc/test/TestDateTime.cpp | 16 ++++++++-------- + 9 files changed, 30 insertions(+), 27 deletions(-) + +diff --git a/xbmc/XBDateTime.cpp b/xbmc/XBDateTime.cpp +index d8187b71e6..afd2d8c6a5 100644 +--- a/xbmc/XBDateTime.cpp ++++ b/xbmc/XBDateTime.cpp +@@ -1210,10 +1210,13 @@ std::string CDateTime::GetAsLocalizedTime(TIME_FORMAT format, bool withSeconds / + return GetAsLocalizedTime("", false); + } + +-CDateTime CDateTime::GetAsUTCDateTime() const ++CDateTime CDateTime::GetAsLocalDateTime() const + { +- CDateTime time(m_time); +- return time; ++ auto zone = date::make_zoned(date::current_zone(), m_time); ++ ++ return CDateTime( ++ std::chrono::duration_cast<std::chrono::seconds>(zone.get_local_time().time_since_epoch()) ++ .count()); + } + + std::string CDateTime::GetAsRFC1123DateTime() const +diff --git a/xbmc/XBDateTime.h b/xbmc/XBDateTime.h +index 16d6217c8a..a810619566 100644 +--- a/xbmc/XBDateTime.h ++++ b/xbmc/XBDateTime.h +@@ -157,7 +157,9 @@ public: + void GetAsTm(tm& time) const; + std::chrono::system_clock::time_point GetAsTimePoint() const; + +- CDateTime GetAsUTCDateTime() const; ++ /*! \brief convert UTC datetime to local datetime ++ */ ++ CDateTime GetAsLocalDateTime() const; + std::string GetAsSaveString() const; + std::string GetAsDBDateTime() const; + std::string GetAsDBDate() const; +diff --git a/xbmc/network/WebServer.cpp b/xbmc/network/WebServer.cpp +index 0ee1696033..fc3583c16d 100644 +--- a/xbmc/network/WebServer.cpp ++++ b/xbmc/network/WebServer.cpp +@@ -222,7 +222,7 @@ MHD_RESULT CWebServer::HandlePartialRequest(struct MHD_Connection* connection, + CDateTime ifUnmodifiedSinceDate; + // handle If-Modified-Since (but only if the response is cacheable) + if (cacheable && ifModifiedSinceDate.SetFromRFC1123DateTime(ifModifiedSince) && +- lastModified.GetAsUTCDateTime() <= ifModifiedSinceDate) ++ lastModified <= ifModifiedSinceDate) + { + struct MHD_Response* response = create_response(0, nullptr, MHD_NO, MHD_NO); + if (response == nullptr) +@@ -235,7 +235,7 @@ MHD_RESULT CWebServer::HandlePartialRequest(struct MHD_Connection* connection, + } + // handle If-Unmodified-Since + else if (ifUnmodifiedSinceDate.SetFromRFC1123DateTime(ifUnmodifiedSince) && +- lastModified.GetAsUTCDateTime() > ifUnmodifiedSinceDate) ++ lastModified > ifUnmodifiedSinceDate) + return SendErrorResponse(request, MHD_HTTP_PRECONDITION_FAILED, request.method); + } + +@@ -504,7 +504,7 @@ bool CWebServer::IsRequestRanged(const HTTPRequest& request, const CDateTime& la + + // check if the last modification is newer than the If-Range date + // if so we have to server the whole file instead +- if (lastModified.GetAsUTCDateTime() > ifRangeDate) ++ if (lastModified > ifRangeDate) + ranges.Clear(); + } + } +diff --git a/xbmc/pvr/epg/EpgContainer.cpp b/xbmc/pvr/epg/EpgContainer.cpp +index d6f20153ef..38aa15809e 100644 +--- a/xbmc/pvr/epg/EpgContainer.cpp ++++ b/xbmc/pvr/epg/EpgContainer.cpp +@@ -335,7 +335,7 @@ void CPVREpgContainer::Process() + time_t iLastEpgCleanup = 0; + bool bUpdateEpg = true; + +- CDateTime::GetCurrentDateTime().GetAsUTCDateTime().GetAsTime(iNow); ++ CDateTime::GetUTCDateTime().GetAsTime(iNow); + { + std::unique_lock<CCriticalSection> lock(m_critSection); + bUpdateEpg = (iNow >= m_iNextEpgUpdate) && !m_bSuspended; +@@ -593,7 +593,7 @@ std::shared_ptr<CPVREpg> CPVREpgContainer::CreateChannelEpg(int iEpgId, const st + { + std::unique_lock<CCriticalSection> lock(m_critSection); + m_bPreventUpdates = false; +- CDateTime::GetCurrentDateTime().GetAsUTCDateTime().GetAsTime(m_iNextEpgUpdate); ++ CDateTime::GetUTCDateTime().GetAsTime(m_iNextEpgUpdate); + } + + m_events.Publish(PVREvent::EpgContainer); +@@ -613,7 +613,7 @@ bool CPVREpgContainer::RemoveOldEntries() + epgEntry.second->Cleanup(cleanupTime); + + std::unique_lock<CCriticalSection> lock(m_critSection); +- CDateTime::GetCurrentDateTime().GetAsUTCDateTime().GetAsTime(m_iLastEpgCleanup); ++ CDateTime::GetUTCDateTime().GetAsTime(m_iLastEpgCleanup); + + return true; + } +@@ -787,7 +787,7 @@ bool CPVREpgContainer::UpdateEPG(bool bOnlyPending /* = false */) + { + /* the update has been interrupted. try again later */ + time_t iNow; +- CDateTime::GetCurrentDateTime().GetAsUTCDateTime().GetAsTime(iNow); ++ CDateTime::GetUTCDateTime().GetAsTime(iNow); + + std::unique_lock<CCriticalSection> lock(m_critSection); + m_iNextEpgUpdate = iNow + advancedSettings->m_iEpgRetryInterruptedUpdateInterval; +@@ -795,7 +795,7 @@ bool CPVREpgContainer::UpdateEPG(bool bOnlyPending /* = false */) + else + { + std::unique_lock<CCriticalSection> lock(m_critSection); +- CDateTime::GetCurrentDateTime().GetAsUTCDateTime().GetAsTime(m_iNextEpgUpdate); ++ CDateTime::GetUTCDateTime().GetAsTime(m_iNextEpgUpdate); + m_iNextEpgUpdate += advancedSettings->m_iEpgUpdateCheckInterval; + if (m_pendingUpdates == pendingUpdates) + m_pendingUpdates = 0; +@@ -852,7 +852,7 @@ bool CPVREpgContainer::CheckPlayingEvents() + m_critSection.unlock(); + + time_t iNow; +- CDateTime::GetCurrentDateTime().GetAsUTCDateTime().GetAsTime(iNow); ++ CDateTime::GetUTCDateTime().GetAsTime(iNow); + if (iNow >= iNextEpgActiveTagCheck) + { + bFoundChanges = std::accumulate(epgs.cbegin(), epgs.cend(), bFoundChanges, +@@ -860,7 +860,7 @@ bool CPVREpgContainer::CheckPlayingEvents() + return epgEntry.second->CheckPlayingEvent() ? true : found; + }); + +- CDateTime::GetCurrentDateTime().GetAsUTCDateTime().GetAsTime(iNextEpgActiveTagCheck); ++ CDateTime::GetUTCDateTime().GetAsTime(iNextEpgActiveTagCheck); + iNextEpgActiveTagCheck += CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_iEpgActiveTagCheckInterval; + + /* pvr tags always start on the full minute */ +diff --git a/xbmc/pvr/epg/EpgInfoTag.cpp b/xbmc/pvr/epg/EpgInfoTag.cpp +index 8b0930e5d2..70daa5033b 100644 +--- a/xbmc/pvr/epg/EpgInfoTag.cpp ++++ b/xbmc/pvr/epg/EpgInfoTag.cpp +@@ -233,7 +233,7 @@ float CPVREpgInfoTag::ProgressPercentage() const + float fReturn = 0.0f; + + time_t currentTime, startTime, endTime; +- CDateTime::GetCurrentDateTime().GetAsUTCDateTime().GetAsTime(currentTime); ++ CDateTime::GetUTCDateTime().GetAsTime(currentTime); + m_startTime.GetAsTime(startTime); + m_endTime.GetAsTime(endTime); + int iDuration = endTime - startTime > 0 ? endTime - startTime : 3600; +@@ -249,7 +249,7 @@ float CPVREpgInfoTag::ProgressPercentage() const + int CPVREpgInfoTag::Progress() const + { + time_t currentTime, startTime; +- CDateTime::GetCurrentDateTime().GetAsUTCDateTime().GetAsTime(currentTime); ++ CDateTime::GetUTCDateTime().GetAsTime(currentTime); + m_startTime.GetAsTime(startTime); + int iDuration = currentTime - startTime; + +diff --git a/xbmc/pvr/guilib/PVRGUIActionsPowerManagement.cpp b/xbmc/pvr/guilib/PVRGUIActionsPowerManagement.cpp +index 1a0a99a7a2..5e27ea69c5 100644 +--- a/xbmc/pvr/guilib/PVRGUIActionsPowerManagement.cpp ++++ b/xbmc/pvr/guilib/PVRGUIActionsPowerManagement.cpp +@@ -92,7 +92,6 @@ bool CPVRGUIActionsPowerManagement::CanSystemPowerdown(bool bAskUser /*= true*/) + CDateTime dailywakeuptime; + dailywakeuptime.SetFromDBTime( + m_settings.GetStringValue(CSettings::SETTING_PVRPOWERMANAGEMENT_DAILYWAKEUPTIME)); +- dailywakeuptime = dailywakeuptime.GetAsUTCDateTime(); + + const CDateTimeSpan diff(dailywakeuptime - now); + int mins = diff.GetSecondsTotal() / 60; +diff --git a/xbmc/pvr/timers/PVRTimerRuleMatcher.cpp b/xbmc/pvr/timers/PVRTimerRuleMatcher.cpp +index 9178e85ec2..b34688bdce 100644 +--- a/xbmc/pvr/timers/PVRTimerRuleMatcher.cpp ++++ b/xbmc/pvr/timers/PVRTimerRuleMatcher.cpp +@@ -66,7 +66,7 @@ CDateTime CPVRTimerRuleMatcher::GetNextTimerStart() const + } + } + +- return nextStart.GetAsUTCDateTime(); ++ return nextStart; + } + + bool CPVRTimerRuleMatcher::Matches(const std::shared_ptr<CPVREpgInfoTag>& epgTag) const +diff --git a/xbmc/pvr/timers/PVRTimers.cpp b/xbmc/pvr/timers/PVRTimers.cpp +index 760bb192f7..5fe64ec7e4 100644 +--- a/xbmc/pvr/timers/PVRTimers.cpp ++++ b/xbmc/pvr/timers/PVRTimers.cpp +@@ -1274,7 +1274,6 @@ CDateTime CPVRTimers::GetNextEventTime() const + CDateTime dailywakeuptime; + dailywakeuptime.SetFromDBTime( + m_settings.GetStringValue(CSettings::SETTING_PVRPOWERMANAGEMENT_DAILYWAKEUPTIME)); +- dailywakeuptime = dailywakeuptime.GetAsUTCDateTime(); + + dailywakeuptime.SetDateTime(now.GetYear(), now.GetMonth(), now.GetDay(), + dailywakeuptime.GetHour(), dailywakeuptime.GetMinute(), +diff --git a/xbmc/test/TestDateTime.cpp b/xbmc/test/TestDateTime.cpp +index 0ff2bb443b..4c55fafe06 100644 +--- a/xbmc/test/TestDateTime.cpp ++++ b/xbmc/test/TestDateTime.cpp +@@ -573,20 +573,20 @@ TEST_F(TestDateTime, GetAsTm) + } + } + +-TEST_F(TestDateTime, GetAsUTCDateTime) ++TEST_F(TestDateTime, GetAsLocalDateTime) + { + CDateTime dateTime1; + dateTime1.SetDateTime(1991, 05, 14, 12, 34, 56); + + CDateTime dateTime2; +- dateTime2 = dateTime1.GetAsUTCDateTime(); ++ dateTime2 = dateTime1.GetAsLocalDateTime(); + +- EXPECT_EQ(dateTime2.GetYear(), 1991); +- EXPECT_EQ(dateTime2.GetMonth(), 5); +- EXPECT_EQ(dateTime2.GetDay(), 14); +- EXPECT_EQ(dateTime2.GetHour(), 12); +- EXPECT_EQ(dateTime2.GetMinute(), 34); +- EXPECT_EQ(dateTime2.GetSecond(), 56); ++ auto zoned_time = date::make_zoned(date::current_zone(), dateTime1.GetAsTimePoint()); ++ auto time = zoned_time.get_local_time().time_since_epoch(); ++ ++ CDateTime cmpTime(std::chrono::duration_cast<std::chrono::seconds>(time).count()); ++ ++ EXPECT_TRUE(dateTime1 == cmpTime); + } + + TEST_F(TestDateTime, Reset) +-- +2.43.0 + + +From d394f4639fd434647a393b99956d22417c68401b Mon Sep 17 00:00:00 2001 +From: Vasyl Gello <vasek.gello@gmail.com> +Date: Tue, 3 Nov 2020 22:49:09 +0200 +Subject: [PATCH 09/19] Compensate the representation change + +... from local time by default to UTC time by default. + +Namely, 'CDateTime::SetFromUTCDateTime' converted the UTC time +to local time in the implementation of CDateTime before +'std::chrono'. Now this conversion has gone, and to avoid +displaying PVR times in UTC, 'GetAsLocalDateTime' is added +where necessary. + +Signed-off-by: Vasyl Gello <vasek.gello@gmail.com> +--- + xbmc/pvr/epg/EpgInfoTag.cpp | 8 ++------ + xbmc/pvr/guilib/GUIEPGGridContainerModel.cpp | 4 ++-- + xbmc/pvr/guilib/guiinfo/PVRGUITimesInfo.cpp | 2 +- + xbmc/pvr/recordings/PVRRecording.cpp | 4 ++-- + 4 files changed, 7 insertions(+), 11 deletions(-) + +diff --git a/xbmc/pvr/epg/EpgInfoTag.cpp b/xbmc/pvr/epg/EpgInfoTag.cpp +index 70daa5033b..3f104aa032 100644 +--- a/xbmc/pvr/epg/EpgInfoTag.cpp ++++ b/xbmc/pvr/epg/EpgInfoTag.cpp +@@ -293,9 +293,7 @@ CDateTime CPVREpgInfoTag::StartAsUTC() const + + CDateTime CPVREpgInfoTag::StartAsLocalTime() const + { +- CDateTime retVal; +- retVal.SetFromUTCDateTime(m_startTime); +- return retVal; ++ return m_startTime.GetAsLocalDateTime(); + } + + CDateTime CPVREpgInfoTag::EndAsUTC() const +@@ -305,9 +303,7 @@ CDateTime CPVREpgInfoTag::EndAsUTC() const + + CDateTime CPVREpgInfoTag::EndAsLocalTime() const + { +- CDateTime retVal; +- retVal.SetFromUTCDateTime(m_endTime); +- return retVal; ++ return m_endTime.GetAsLocalDateTime(); + } + + void CPVREpgInfoTag::SetEndFromUTC(const CDateTime& end) +diff --git a/xbmc/pvr/guilib/GUIEPGGridContainerModel.cpp b/xbmc/pvr/guilib/GUIEPGGridContainerModel.cpp +index e8fac010ca..ef7a715f70 100644 +--- a/xbmc/pvr/guilib/GUIEPGGridContainerModel.cpp ++++ b/xbmc/pvr/guilib/GUIEPGGridContainerModel.cpp +@@ -121,9 +121,9 @@ void CGUIEPGGridContainerModel::Initialize(const std::unique_ptr<CFileItemList>& + //////////////////////////////////////////////////////////////////////// + // Create ruler items + CDateTime ruler; +- ruler.SetFromUTCDateTime(m_gridStart); ++ ruler.SetFromUTCDateTime(m_gridStart.GetAsLocalDateTime()); + CDateTime rulerEnd; +- rulerEnd.SetFromUTCDateTime(m_gridEnd); ++ rulerEnd.SetFromUTCDateTime(m_gridEnd.GetAsLocalDateTime()); + CFileItemPtr rulerItem(new CFileItem(ruler.GetAsLocalizedDate(true))); + rulerItem->SetProperty("DateLabel", true); + m_rulerItems.emplace_back(rulerItem); +diff --git a/xbmc/pvr/guilib/guiinfo/PVRGUITimesInfo.cpp b/xbmc/pvr/guilib/guiinfo/PVRGUITimesInfo.cpp +index e5dfdb9ea0..3d2cf09b3f 100644 +--- a/xbmc/pvr/guilib/guiinfo/PVRGUITimesInfo.cpp ++++ b/xbmc/pvr/guilib/guiinfo/PVRGUITimesInfo.cpp +@@ -239,7 +239,7 @@ std::string CPVRGUITimesInfo::TimeToTimeString(time_t datetime, TIME_FORMAT form + { + CDateTime time; + time.SetFromUTCDateTime(datetime); +- return time.GetAsLocalizedTime(format, withSeconds); ++ return time.GetAsLocalDateTime().GetAsLocalizedTime(format, withSeconds); + } + + std::string CPVRGUITimesInfo::GetTimeshiftStartTime(TIME_FORMAT format) const +diff --git a/xbmc/pvr/recordings/PVRRecording.cpp b/xbmc/pvr/recordings/PVRRecording.cpp +index a2e1cbd131..8e047b8d52 100644 +--- a/xbmc/pvr/recordings/PVRRecording.cpp ++++ b/xbmc/pvr/recordings/PVRRecording.cpp +@@ -524,7 +524,7 @@ void CPVRRecording::UpdatePath() + const CDateTime& CPVRRecording::RecordingTimeAsLocalTime() const + { + static CDateTime tmp; +- tmp.SetFromUTCDateTime(m_recordingTime); ++ tmp.SetFromUTCDateTime(m_recordingTime.GetAsLocalDateTime()); + + return tmp; + } +@@ -538,7 +538,7 @@ CDateTime CPVRRecording::EndTimeAsUTC() const + CDateTime CPVRRecording::EndTimeAsLocalTime() const + { + CDateTime ret; +- ret.SetFromUTCDateTime(EndTimeAsUTC()); ++ ret.SetFromUTCDateTime(EndTimeAsUTC().GetAsLocalDateTime()); + return ret; + } + +-- +2.43.0 + + +From e9cbb86184358f6eb3235a76936fedbf38ab4d97 Mon Sep 17 00:00:00 2001 +From: Vasyl Gello <vasek.gello@gmail.com> +Date: Wed, 4 Nov 2020 11:13:15 +0200 +Subject: [PATCH 10/19] Get rid of {Set,}FromUTCDateTime + + * The 'const CDateTime& CPVRRecording::RecordingTimeAsLocalTime() const' + method needs 'static' CDateTime instance set explicitly. This manifested + in Debian Bug #980038 : the return value of function is explicitly nulled + out causing immediate crash when using any PVR addon manipulating PVR + recordings. + +Signed-off-by: Vasyl Gello <vasek.gello@gmail.com> +--- + xbmc/FileItem.cpp | 2 +- + xbmc/XBDateTime.cpp | 33 ++----------------- + xbmc/XBDateTime.h | 4 --- + .../savestates/SavestateDatabase.cpp | 2 +- + xbmc/pvr/dialogs/GUIDialogPVRGuideSearch.cpp | 8 ++--- + xbmc/pvr/epg/Epg.cpp | 2 +- + xbmc/pvr/guilib/GUIEPGGridContainerModel.cpp | 4 +-- + xbmc/pvr/guilib/guiinfo/PVRGUIInfo.cpp | 3 +- + xbmc/pvr/guilib/guiinfo/PVRGUITimesInfo.cpp | 3 +- + xbmc/pvr/recordings/PVRRecording.cpp | 8 ++--- + xbmc/test/TestDateTime.cpp | 26 --------------- + 11 files changed, 14 insertions(+), 81 deletions(-) + +diff --git a/xbmc/FileItem.cpp b/xbmc/FileItem.cpp +index 2eb5eb072c..8f14467aff 100644 +--- a/xbmc/FileItem.cpp ++++ b/xbmc/FileItem.cpp +@@ -199,7 +199,7 @@ CFileItem::CFileItem(const std::shared_ptr<PVR::CPVREpgSearchFilter>& filter) + + const CDateTime lastExec = filter->GetLastExecutedDateTime(); + if (lastExec.IsValid()) +- m_dateTime.SetFromUTCDateTime(lastExec); ++ m_dateTime = lastExec; + + SetArt("icon", "DefaultPVRSearch.png"); + +diff --git a/xbmc/XBDateTime.cpp b/xbmc/XBDateTime.cpp +index afd2d8c6a5..86168ecc13 100644 +--- a/xbmc/XBDateTime.cpp ++++ b/xbmc/XBDateTime.cpp +@@ -613,19 +613,6 @@ std::string CDateTime::GetAsSaveString() const + return date::format("%Y%m%d_%H%M%S", sp); + } + +-bool CDateTime::SetFromUTCDateTime(const CDateTime &dateTime) +-{ +- m_time = dateTime.m_time; +- m_state = valid; +- return true; +-} +- +-bool CDateTime::SetFromUTCDateTime(const time_t &dateTime) +-{ +- CDateTime tmp(dateTime); +- return SetFromUTCDateTime(tmp); +-} +- + bool CDateTime::SetFromW3CDate(const std::string &dateTime) + { + std::string date; +@@ -700,10 +687,8 @@ bool CDateTime::SetFromW3CDateTime(const std::string &dateTime, bool ignoreTimez + + if (!ignoreTimezone && !zone.empty()) + { +- // check if the timezone is UTC +- if (StringUtils::StartsWith(zone, "Z")) +- return SetFromUTCDateTime(tmpDateTime); +- else ++ // check if the timezone is not UTC ++ if (!StringUtils::StartsWith(zone, "Z")) + { + // retrieve the timezone offset (ignoring the + or -) + CDateTimeSpan zoneSpan; zoneSpan.SetFromTimeString(zone.substr(1)); +@@ -853,20 +838,6 @@ CDateTime CDateTime::FromW3CDateTime(const std::string &date, bool ignoreTimezon + return dt; + } + +-CDateTime CDateTime::FromUTCDateTime(const CDateTime &dateTime) +-{ +- CDateTime dt; +- dt.SetFromUTCDateTime(dateTime); +- return dt; +-} +- +-CDateTime CDateTime::FromUTCDateTime(const time_t &dateTime) +-{ +- CDateTime dt; +- dt.SetFromUTCDateTime(dateTime); +- return dt; +-} +- + CDateTime CDateTime::FromRFC1123DateTime(const std::string &dateTime) + { + CDateTime dt; +diff --git a/xbmc/XBDateTime.h b/xbmc/XBDateTime.h +index a810619566..ff2d758caa 100644 +--- a/xbmc/XBDateTime.h ++++ b/xbmc/XBDateTime.h +@@ -78,8 +78,6 @@ public: + static CDateTime FromDBTime(const std::string &time); + static CDateTime FromW3CDate(const std::string &date); + static CDateTime FromW3CDateTime(const std::string &date, bool ignoreTimezone = false); +- static CDateTime FromUTCDateTime(const CDateTime &dateTime); +- static CDateTime FromUTCDateTime(const time_t &dateTime); + static CDateTime FromRFC1123DateTime(const std::string &dateTime); + + const CDateTime& operator =(const time_t& right); +@@ -144,8 +142,6 @@ public: + bool SetFromDBTime(const std::string &time); + bool SetFromW3CDate(const std::string &date); + bool SetFromW3CDateTime(const std::string &date, bool ignoreTimezone = false); +- bool SetFromUTCDateTime(const CDateTime &dateTime); +- bool SetFromUTCDateTime(const time_t &dateTime); + bool SetFromRFC1123DateTime(const std::string &dateTime); + + /*! \brief set from a database datetime format YYYY-MM-DD HH:MM:SS +diff --git a/xbmc/cores/RetroPlayer/savestates/SavestateDatabase.cpp b/xbmc/cores/RetroPlayer/savestates/SavestateDatabase.cpp +index 2611f25ad8..2a44e07596 100644 +--- a/xbmc/cores/RetroPlayer/savestates/SavestateDatabase.cpp ++++ b/xbmc/cores/RetroPlayer/savestates/SavestateDatabase.cpp +@@ -149,7 +149,7 @@ void CSavestateDatabase::GetSavestateItem(const ISavestate& savestate, + const std::string& savestatePath, + CFileItem& item) + { +- CDateTime dateUTC = CDateTime::FromUTCDateTime(savestate.Created()); ++ CDateTime dateUTC = savestate.Created(); + + std::string label; + std::string label2; +diff --git a/xbmc/pvr/dialogs/GUIDialogPVRGuideSearch.cpp b/xbmc/pvr/dialogs/GUIDialogPVRGuideSearch.cpp +index 4cf7f2f0c4..13b826c1b1 100644 +--- a/xbmc/pvr/dialogs/GUIDialogPVRGuideSearch.cpp ++++ b/xbmc/pvr/dialogs/GUIDialogPVRGuideSearch.cpp +@@ -252,7 +252,7 @@ CDateTime CGUIDialogPVRGuideSearch::ReadDateTime(const std::string& strDate, con + sscanf(strTime.c_str(), "%d:%d", &iHours, &iMinutes); + dateTime.SetFromDBDate(strDate); + dateTime.SetDateTime(dateTime.GetYear(), dateTime.GetMonth(), dateTime.GetDay(), iHours, iMinutes, 0); +- return dateTime.GetAsUTCDateTime(); ++ return dateTime; + } + + bool CGUIDialogPVRGuideSearch::IsRadioSelected(int controlID) +@@ -358,10 +358,8 @@ void CGUIDialogPVRGuideSearch::Update() + if (!m_endDateTime.IsValid()) + m_endDateTime = m_startDateTime + CDateTimeSpan(10, 0, 0, 0); // default to start + 10 days + +- CDateTime startLocal; +- startLocal.SetFromUTCDateTime(m_startDateTime); +- CDateTime endLocal; +- endLocal.SetFromUTCDateTime(m_endDateTime); ++ CDateTime startLocal = m_startDateTime; ++ CDateTime endLocal = m_endDateTime; + + SET_CONTROL_LABEL2(CONTROL_EDIT_START_TIME, startLocal.GetAsLocalizedTime("", false)); + { +diff --git a/xbmc/pvr/epg/Epg.cpp b/xbmc/pvr/epg/Epg.cpp +index 1112b2ff89..bb0dbf967b 100644 +--- a/xbmc/pvr/epg/Epg.cpp ++++ b/xbmc/pvr/epg/Epg.cpp +@@ -264,7 +264,7 @@ bool CPVREpg::Update(time_t start, + + if (!m_lastScanTime.IsValid()) + { +- m_lastScanTime.SetFromUTCDateTime(time_t(0)); ++ m_lastScanTime = time_t(0); + m_bUpdateLastScanTime = true; + } + } +diff --git a/xbmc/pvr/guilib/GUIEPGGridContainerModel.cpp b/xbmc/pvr/guilib/GUIEPGGridContainerModel.cpp +index ef7a715f70..3e89c06d6e 100644 +--- a/xbmc/pvr/guilib/GUIEPGGridContainerModel.cpp ++++ b/xbmc/pvr/guilib/GUIEPGGridContainerModel.cpp +@@ -121,9 +121,9 @@ void CGUIEPGGridContainerModel::Initialize(const std::unique_ptr<CFileItemList>& + //////////////////////////////////////////////////////////////////////// + // Create ruler items + CDateTime ruler; +- ruler.SetFromUTCDateTime(m_gridStart.GetAsLocalDateTime()); ++ ruler = m_gridStart.GetAsLocalDateTime(); + CDateTime rulerEnd; +- rulerEnd.SetFromUTCDateTime(m_gridEnd.GetAsLocalDateTime()); ++ rulerEnd = m_gridEnd.GetAsLocalDateTime(); + CFileItemPtr rulerItem(new CFileItem(ruler.GetAsLocalizedDate(true))); + rulerItem->SetProperty("DateLabel", true); + m_rulerItems.emplace_back(rulerItem); +diff --git a/xbmc/pvr/guilib/guiinfo/PVRGUIInfo.cpp b/xbmc/pvr/guilib/guiinfo/PVRGUIInfo.cpp +index 9cffb9a934..80c25118b0 100644 +--- a/xbmc/pvr/guilib/guiinfo/PVRGUIInfo.cpp ++++ b/xbmc/pvr/guilib/guiinfo/PVRGUIInfo.cpp +@@ -568,8 +568,7 @@ bool CPVRGUIInfo::GetListItemAndPlayerLabel(const CFileItem* item, + { + case LISTITEM_DATE: + { +- CDateTime lastExecLocal; +- lastExecLocal.SetFromUTCDateTime(filter->GetLastExecutedDateTime()); ++ CDateTime lastExecLocal = filter->GetLastExecutedDateTime(); + strValue = GetAsLocalizedDateTimeString(lastExecLocal); + if (strValue.empty()) + strValue = g_localizeStrings.Get(10006); // "N/A" +diff --git a/xbmc/pvr/guilib/guiinfo/PVRGUITimesInfo.cpp b/xbmc/pvr/guilib/guiinfo/PVRGUITimesInfo.cpp +index 3d2cf09b3f..c5b44b840c 100644 +--- a/xbmc/pvr/guilib/guiinfo/PVRGUITimesInfo.cpp ++++ b/xbmc/pvr/guilib/guiinfo/PVRGUITimesInfo.cpp +@@ -237,8 +237,7 @@ void CPVRGUITimesInfo::Update() + + std::string CPVRGUITimesInfo::TimeToTimeString(time_t datetime, TIME_FORMAT format, bool withSeconds) + { +- CDateTime time; +- time.SetFromUTCDateTime(datetime); ++ CDateTime time(datetime); + return time.GetAsLocalDateTime().GetAsLocalizedTime(format, withSeconds); + } + +diff --git a/xbmc/pvr/recordings/PVRRecording.cpp b/xbmc/pvr/recordings/PVRRecording.cpp +index 8e047b8d52..5a82c7b1dc 100644 +--- a/xbmc/pvr/recordings/PVRRecording.cpp ++++ b/xbmc/pvr/recordings/PVRRecording.cpp +@@ -523,9 +523,7 @@ void CPVRRecording::UpdatePath() + + const CDateTime& CPVRRecording::RecordingTimeAsLocalTime() const + { +- static CDateTime tmp; +- tmp.SetFromUTCDateTime(m_recordingTime.GetAsLocalDateTime()); +- ++ static CDateTime tmp = m_recordingTime.GetAsLocalDateTime(); + return tmp; + } + +@@ -537,9 +535,7 @@ CDateTime CPVRRecording::EndTimeAsUTC() const + + CDateTime CPVRRecording::EndTimeAsLocalTime() const + { +- CDateTime ret; +- ret.SetFromUTCDateTime(EndTimeAsUTC().GetAsLocalDateTime()); +- return ret; ++ return EndTimeAsUTC().GetAsLocalDateTime(); + } + + bool CPVRRecording::WillBeExpiredWithNewLifetime(int iLifetime) const +diff --git a/xbmc/test/TestDateTime.cpp b/xbmc/test/TestDateTime.cpp +index 4c55fafe06..ea910a8763 100644 +--- a/xbmc/test/TestDateTime.cpp ++++ b/xbmc/test/TestDateTime.cpp +@@ -240,32 +240,6 @@ TEST_F(TestDateTime, SetFromW3CDateTime) + EXPECT_EQ(dateTime2.GetSecond(), 30); + } + +-TEST_F(TestDateTime, SetFromUTCDateTime) +-{ +- CDateTime dateTime1; +- dateTime1.SetFromDBDateTime("1991-05-14 12:34:56"); +- +- CDateTime dateTime2; +- EXPECT_TRUE(dateTime2.SetFromUTCDateTime(dateTime1)); +- EXPECT_EQ(dateTime2.GetYear(), 1991); +- EXPECT_EQ(dateTime2.GetMonth(), 5); +- EXPECT_EQ(dateTime2.GetDay(), 14); +- EXPECT_EQ(dateTime2.GetHour(), 12); +- EXPECT_EQ(dateTime2.GetMinute(), 34); +- EXPECT_EQ(dateTime2.GetSecond(), 56); +- +- const time_t time = 674224496; +- +- CDateTime dateTime3; +- EXPECT_TRUE(dateTime3.SetFromUTCDateTime(time)); +- EXPECT_EQ(dateTime3.GetYear(), 1991); +- EXPECT_EQ(dateTime3.GetMonth(), 5); +- EXPECT_EQ(dateTime3.GetDay(), 14); +- EXPECT_EQ(dateTime3.GetHour(), 12); +- EXPECT_EQ(dateTime3.GetMinute(), 34); +- EXPECT_EQ(dateTime3.GetSecond(), 56); +-} +- + TEST_F(TestDateTime, SetFromRFC1123DateTime) + { + std::string dateTime1("Mon, 21 Oct 2018 12:16:24 GMT"); +-- +2.43.0 + + +From 9583d0b325df73f5e29b4c901715b9a6bc389295 Mon Sep 17 00:00:00 2001 +From: Vasyl Gello <vasek.gello@gmail.com> +Date: Thu, 13 May 2021 11:18:31 +0000 +Subject: [PATCH 11/19] Fix one-time assignment of PVR recording times + +Fixes pvr.dvbviewer#49 +Closes: #984682 + +Signed-off-by: Vasyl Gello <vasek.gello@gmail.com> +--- + xbmc/pvr/recordings/PVRRecording.cpp | 5 ++--- + xbmc/pvr/recordings/PVRRecording.h | 2 +- + 2 files changed, 3 insertions(+), 4 deletions(-) + +diff --git a/xbmc/pvr/recordings/PVRRecording.cpp b/xbmc/pvr/recordings/PVRRecording.cpp +index 5a82c7b1dc..39eea88740 100644 +--- a/xbmc/pvr/recordings/PVRRecording.cpp ++++ b/xbmc/pvr/recordings/PVRRecording.cpp +@@ -521,10 +521,9 @@ void CPVRRecording::UpdatePath() + m_strChannelName, m_recordingTime, m_strRecordingId); + } + +-const CDateTime& CPVRRecording::RecordingTimeAsLocalTime() const ++CDateTime CPVRRecording::RecordingTimeAsLocalTime() const + { +- static CDateTime tmp = m_recordingTime.GetAsLocalDateTime(); +- return tmp; ++ return m_recordingTime.GetAsLocalDateTime(); + } + + CDateTime CPVRRecording::EndTimeAsUTC() const +diff --git a/xbmc/pvr/recordings/PVRRecording.h b/xbmc/pvr/recordings/PVRRecording.h +index bdd8378225..dd125ad1ea 100644 +--- a/xbmc/pvr/recordings/PVRRecording.h ++++ b/xbmc/pvr/recordings/PVRRecording.h +@@ -188,7 +188,7 @@ public: + * @brief Retrieve the recording start as local time + * @return the recording start time + */ +- const CDateTime& RecordingTimeAsLocalTime() const; ++ CDateTime RecordingTimeAsLocalTime() const; + + /*! + * @brief Retrieve the recording end as UTC time +-- +2.43.0 + + +From 732620e37163d653ec75bbefd2a58293e2303420 Mon Sep 17 00:00:00 2001 +From: Vasyl Gello <vasek.gello@gmail.com> +Date: Wed, 21 Dec 2022 18:27:24 +0000 +Subject: [PATCH 12/19] Move date includes to separate header + +Signed-off-by: Vasyl Gello <vasek.gello@gmail.com> +--- + xbmc/ServiceManager.cpp | 5 +---- + xbmc/XBDateTime.cpp | 8 +------- + xbmc/addons/TimeZoneResource.cpp | 5 +++-- + xbmc/application/Application.cpp | 5 +---- + xbmc/platform/posix/PosixTimezone.cpp | 21 +++++++++------------ + xbmc/test/TestDateTime.cpp | 5 +---- + xbmc/utils/CMakeLists.txt | 1 + + xbmc/utils/DateLib.h | 24 ++++++++++++++++++++++++ + 8 files changed, 41 insertions(+), 33 deletions(-) + create mode 100644 xbmc/utils/DateLib.h + +diff --git a/xbmc/ServiceManager.cpp b/xbmc/ServiceManager.cpp +index 83070489e3..b95091e993 100644 +--- a/xbmc/ServiceManager.cpp ++++ b/xbmc/ServiceManager.cpp +@@ -45,15 +45,12 @@ + #include "storage/DetectDVDType.h" + #endif + #include "storage/MediaManager.h" ++#include "utils/DateLib.h" + #include "utils/FileExtensionProvider.h" + #include "utils/URIUtils.h" + #include "utils/log.h" + #include "weather/WeatherManager.h" + +-#define USE_OS_TZDB 0 +-#define HAS_REMOTE_API 0 +-#include <date/tz.h> +- + using namespace KODI; + + CServiceManager::CServiceManager() = default; +diff --git a/xbmc/XBDateTime.cpp b/xbmc/XBDateTime.cpp +index 86168ecc13..12ae853c43 100644 +--- a/xbmc/XBDateTime.cpp ++++ b/xbmc/XBDateTime.cpp +@@ -11,18 +11,12 @@ + #include "LangInfo.h" + #include "guilib/LocalizeStrings.h" + #include "utils/Archive.h" ++#include "utils/DateLib.h" + #include "utils/StringUtils.h" +-#include "utils/XTimeUtils.h" + #include "utils/log.h" + + #include <cstdlib> + +-#define USE_OS_TZDB 0 +-#define HAS_REMOTE_API 0 +-#include <date/date.h> +-#include <date/iso_week.h> +-#include <date/tz.h> +- + static const char *MONTH_NAMES[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; + + CDateTimeSpan::CDateTimeSpan(const CDateTimeSpan& span) +diff --git a/xbmc/addons/TimeZoneResource.cpp b/xbmc/addons/TimeZoneResource.cpp +index 94246c9e18..6dfba75e89 100644 +--- a/xbmc/addons/TimeZoneResource.cpp ++++ b/xbmc/addons/TimeZoneResource.cpp +@@ -8,11 +8,10 @@ + #include "TimeZoneResource.h" + + #include "addons/addoninfo/AddonType.h" ++#include "utils/DateLib.h" + #include "utils/StringUtils.h" + #include "utils/URIUtils.h" + +-#include <date/tz.h> +- + namespace ADDON + { + +@@ -33,7 +32,9 @@ bool CTimeZoneResource::IsInUse() const + + void CTimeZoneResource::OnPostInstall(bool update, bool modal) + { ++#if defined(DATE_INTERNAL_TZDATA) + date::reload_tzdb(); ++#endif + } + + } // namespace ADDON +diff --git a/xbmc/application/Application.cpp b/xbmc/application/Application.cpp +index 3227933296..6aa584e5c9 100644 +--- a/xbmc/application/Application.cpp ++++ b/xbmc/application/Application.cpp +@@ -100,6 +100,7 @@ + #include "speech/ISpeechRecognition.h" + #include "threads/SingleLock.h" + #include "utils/CPUInfo.h" ++#include "utils/DateLib.h" + #include "utils/FileExtensionProvider.h" + #include "utils/RegExp.h" + #include "utils/SystemInfo.h" +@@ -196,12 +197,8 @@ + #include "pictures/GUIWindowSlideShow.h" + #include "utils/CharsetConverter.h" + +-#define USE_OS_TZDB 0 +-#define HAS_REMOTE_API 0 + #include <mutex> + +-#include <date/tz.h> +- + using namespace ADDON; + using namespace XFILE; + #ifdef HAS_DVD_DRIVE +diff --git a/xbmc/platform/posix/PosixTimezone.cpp b/xbmc/platform/posix/PosixTimezone.cpp +index 7f0b8d4096..fa9ea1dde9 100644 +--- a/xbmc/platform/posix/PosixTimezone.cpp ++++ b/xbmc/platform/posix/PosixTimezone.cpp +@@ -9,25 +9,22 @@ + #ifdef TARGET_ANDROID + #include "platform/android/bionic_supplement/bionic_supplement.h" + #endif +-#include "PlatformDefs.h" + #include "PosixTimezone.h" +-#include "utils/SystemInfo.h" +- + #include "ServiceBroker.h" +-#include "utils/StringUtils.h" + #include "XBDateTime.h" +-#include "settings/lib/Setting.h" +-#include "settings/lib/SettingDefinitions.h" ++#include "filesystem/File.h" ++#include "platform/MessagePrinter.h" + #include "settings/Settings.h" + #include "settings/SettingsComponent.h" +-#include <stdlib.h> ++#include "settings/lib/Setting.h" ++#include "settings/lib/SettingDefinitions.h" ++#include "utils/DateLib.h" ++#include "utils/StringUtils.h" ++#include "utils/SystemInfo.h" + +-#define USE_OS_TZDB 0 +-#define HAS_REMOTE_API 0 +-#include "filesystem/File.h" +-#include "platform/MessagePrinter.h" ++#include <stdlib.h> + +-#include <date/tz.h> ++#include "PlatformDefs.h" + + void CPosixTimezone::Init() + { +diff --git a/xbmc/test/TestDateTime.cpp b/xbmc/test/TestDateTime.cpp +index ea910a8763..de3f75e5e4 100644 +--- a/xbmc/test/TestDateTime.cpp ++++ b/xbmc/test/TestDateTime.cpp +@@ -9,15 +9,12 @@ + #include "LangInfo.h" + #include "XBDateTime.h" + #include "guilib/LocalizeStrings.h" ++#include "utils/DateLib.h" + + #include <array> + #include <chrono> + #include <iostream> + +-#define USE_OS_TZDB 0 +-#define HAS_REMOTE_API 0 +-#include <date/date.h> +-#include <date/tz.h> + #include <gtest/gtest.h> + + class TestDateTime : public testing::Test +diff --git a/xbmc/utils/CMakeLists.txt b/xbmc/utils/CMakeLists.txt +index 8e1328999f..bb4851c0ce 100644 +--- a/xbmc/utils/CMakeLists.txt ++++ b/xbmc/utils/CMakeLists.txt +@@ -97,6 +97,7 @@ set(HEADERS ActorProtocol.h + Crc32.h + CSSUtils.h + DatabaseUtils.h ++ DateLib.h + Digest.h + DiscsUtils.h + EndianSwap.h +diff --git a/xbmc/utils/DateLib.h b/xbmc/utils/DateLib.h +new file mode 100644 +index 0000000000..e39650aa03 +--- /dev/null ++++ b/xbmc/utils/DateLib.h +@@ -0,0 +1,24 @@ ++/* ++ * Copyright (C) 2005-2022 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. ++ */ ++ ++#if defined(DATE_INTERNAL_TZDATA) ++#define USE_OS_TZDB 0 ++#else ++#define USE_OS_TZDB 1 ++#endif ++ ++#if defined(DATE_HAS_STRINGVIEW) ++#define HAS_STRING_VIEW 1 ++#else ++#define HAS_STRING_VIEW 0 ++#endif ++ ++#define HAS_REMOTE_API 0 ++#include <date/date.h> ++#include <date/iso_week.h> ++#include <date/tz.h> +-- +2.43.0 + + +From 46f92320cc18c3975bddb5dbe8e0d5b66a0b64c6 Mon Sep 17 00:00:00 2001 +From: Vasyl Gello <vasek.gello@gmail.com> +Date: Fri, 14 May 2021 09:39:55 +0000 +Subject: [PATCH 13/19] CDateTime: Use 'long double' as underlying storage type + for time points + +This should fix the GUI date dialog issue: + +https://github.com/xbmc/xbmc/pull/18727#issuecomment-840805031 +https://github.com/xbmc/xbmc/pull/18727#issuecomment-840805031 + +Signed-off-by: Vasyl Gello <vasek.gello@gmail.com> +--- + xbmc/XBDateTime.cpp | 18 +++++++++--------- + xbmc/XBDateTime.h | 20 ++++++++++---------- + xbmc/dialogs/GUIDialogNumeric.cpp | 3 +-- + xbmc/utils/Archive.cpp | 8 ++++---- + xbmc/utils/Archive.h | 6 ++++-- + xbmc/utils/XTimeUtils.h | 3 +++ + xbmc/utils/test/TestArchive.cpp | 12 ++++++------ + 7 files changed, 37 insertions(+), 33 deletions(-) + +diff --git a/xbmc/XBDateTime.cpp b/xbmc/XBDateTime.cpp +index 12ae853c43..fdcc27c9af 100644 +--- a/xbmc/XBDateTime.cpp ++++ b/xbmc/XBDateTime.cpp +@@ -176,7 +176,7 @@ CDateTime::CDateTime(const time_t& time) + SetValid(true); + } + +-CDateTime::CDateTime(const std::chrono::system_clock::time_point& time) ++CDateTime::CDateTime(const KODI::TIME::time_point& time) + { + m_time = time; + SetValid(true); +@@ -223,7 +223,7 @@ const CDateTime& CDateTime::operator =(const tm& right) + return *this; + } + +-const CDateTime& CDateTime::operator=(const std::chrono::system_clock::time_point& right) ++const CDateTime& CDateTime::operator=(const KODI::TIME::time_point& right) + { + m_time = right; + SetValid(true); +@@ -321,32 +321,32 @@ bool CDateTime::operator !=(const tm& right) const + return !operator ==(right); + } + +-bool CDateTime::operator>(const std::chrono::system_clock::time_point& right) const ++bool CDateTime::operator>(const KODI::TIME::time_point& right) const + { + return m_time > right; + } + +-bool CDateTime::operator>=(const std::chrono::system_clock::time_point& right) const ++bool CDateTime::operator>=(const KODI::TIME::time_point& right) const + { + return operator>(right) || operator==(right); + } + +-bool CDateTime::operator<(const std::chrono::system_clock::time_point& right) const ++bool CDateTime::operator<(const KODI::TIME::time_point& right) const + { + return m_time < right; + } + +-bool CDateTime::operator<=(const std::chrono::system_clock::time_point& right) const ++bool CDateTime::operator<=(const KODI::TIME::time_point& right) const + { + return operator<(right) || operator==(right); + } + +-bool CDateTime::operator==(const std::chrono::system_clock::time_point& right) const ++bool CDateTime::operator==(const KODI::TIME::time_point& right) const + { + return m_time == right; + } + +-bool CDateTime::operator!=(const std::chrono::system_clock::time_point& right) const ++bool CDateTime::operator!=(const KODI::TIME::time_point& right) const + { + return !operator==(right); + } +@@ -577,7 +577,7 @@ void CDateTime::GetAsTm(tm& time) const + localtime_r(&t, &time); + } + +-std::chrono::system_clock::time_point CDateTime::GetAsTimePoint() const ++KODI::TIME::time_point CDateTime::GetAsTimePoint() const + { + return m_time; + } +diff --git a/xbmc/XBDateTime.h b/xbmc/XBDateTime.h +index ff2d758caa..b0a7f386d9 100644 +--- a/xbmc/XBDateTime.h ++++ b/xbmc/XBDateTime.h +@@ -65,7 +65,7 @@ public: + CDateTime& operator=(const CDateTime&) = default; + explicit CDateTime(const time_t& time); + explicit CDateTime(const tm& time); +- explicit CDateTime(const std::chrono::system_clock::time_point& time); ++ explicit CDateTime(const KODI::TIME::time_point& time); + CDateTime(int year, int month, int day, int hour, int minute, int second); + + static CDateTime GetCurrentDateTime(); +@@ -82,7 +82,7 @@ public: + + const CDateTime& operator =(const time_t& right); + const CDateTime& operator =(const tm& right); +- const CDateTime& operator=(const std::chrono::system_clock::time_point& right); ++ const CDateTime& operator=(const KODI::TIME::time_point& right); + + bool operator >(const CDateTime& right) const; + bool operator >=(const CDateTime& right) const; +@@ -105,12 +105,12 @@ public: + bool operator ==(const tm& right) const; + bool operator !=(const tm& right) const; + +- bool operator>(const std::chrono::system_clock::time_point& right) const; +- bool operator>=(const std::chrono::system_clock::time_point& right) const; +- bool operator<(const std::chrono::system_clock::time_point& right) const; +- bool operator<=(const std::chrono::system_clock::time_point& right) const; +- bool operator==(const std::chrono::system_clock::time_point& right) const; +- bool operator!=(const std::chrono::system_clock::time_point& right) const; ++ bool operator>(const KODI::TIME::time_point& right) const; ++ bool operator>=(const KODI::TIME::time_point& right) const; ++ bool operator<(const KODI::TIME::time_point& right) const; ++ bool operator<=(const KODI::TIME::time_point& right) const; ++ bool operator==(const KODI::TIME::time_point& right) const; ++ bool operator!=(const KODI::TIME::time_point& right) const; + + CDateTime operator +(const CDateTimeSpan& right) const; + CDateTime operator -(const CDateTimeSpan& right) const; +@@ -151,7 +151,7 @@ public: + + void GetAsTime(time_t& time) const; + void GetAsTm(tm& time) const; +- std::chrono::system_clock::time_point GetAsTimePoint() const; ++ KODI::TIME::time_point GetAsTimePoint() const; + + /*! \brief convert UTC datetime to local datetime + */ +@@ -173,7 +173,7 @@ public: + bool IsValid() const; + + private: +- std::chrono::system_clock::time_point m_time; ++ KODI::TIME::time_point m_time; + + typedef enum _STATE + { +diff --git a/xbmc/dialogs/GUIDialogNumeric.cpp b/xbmc/dialogs/GUIDialogNumeric.cpp +index bba219e44e..985fd05722 100644 +--- a/xbmc/dialogs/GUIDialogNumeric.cpp ++++ b/xbmc/dialogs/GUIDialogNumeric.cpp +@@ -498,8 +498,7 @@ bool CGUIDialogNumeric::ShowAndGetSeconds(std::string &timeString, const std::st + CGUIDialogNumeric *pDialog = CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogNumeric>(WINDOW_DIALOG_NUMERIC); + if (!pDialog) return false; + +- std::chrono::system_clock::time_point time{ +- std::chrono::seconds{StringUtils::TimeStringToSeconds(timeString)}}; ++ KODI::TIME::time_point time{std::chrono::seconds{StringUtils::TimeStringToSeconds(timeString)}}; + + CDateTime datetime(time); + +diff --git a/xbmc/utils/Archive.cpp b/xbmc/utils/Archive.cpp +index 0275c057f9..bb207c6ca5 100644 +--- a/xbmc/utils/Archive.cpp ++++ b/xbmc/utils/Archive.cpp +@@ -152,9 +152,9 @@ CArchive& CArchive::operator<<(const std::wstring& wstr) + return streamout(wstr.data(), size * sizeof(wchar_t)); + } + +-CArchive& CArchive::operator<<(const std::chrono::system_clock::time_point& time) ++CArchive& CArchive::operator<<(const KODI::TIME::time_point& time) + { +- return streamout(&time, sizeof(std::chrono::system_clock::time_point)); ++ return streamout(&time, sizeof(KODI::TIME::time_point)); + } + + CArchive& CArchive::operator<<(IArchivable& obj) +@@ -265,9 +265,9 @@ CArchive& CArchive::operator>>(std::wstring& wstr) + return *this; + } + +-CArchive& CArchive::operator>>(std::chrono::system_clock::time_point& time) ++CArchive& CArchive::operator>>(KODI::TIME::time_point& time) + { +- return streamin(&time, sizeof(std::chrono::system_clock::time_point)); ++ return streamin(&time, sizeof(KODI::TIME::time_point)); + } + + CArchive& CArchive::operator>>(IArchivable& obj) +diff --git a/xbmc/utils/Archive.h b/xbmc/utils/Archive.h +index 86a2bebc23..ece5f9ac9c 100644 +--- a/xbmc/utils/Archive.h ++++ b/xbmc/utils/Archive.h +@@ -8,6 +8,8 @@ + + #pragma once + ++#include "utils/XTimeUtils.h" ++ + #include <cstring> + #include <memory> + #include <string> +@@ -57,7 +59,7 @@ public: + CArchive& operator<<(char c); + CArchive& operator<<(const std::string &str); + CArchive& operator<<(const std::wstring& wstr); +- CArchive& operator<<(const std::chrono::system_clock::time_point& time); ++ CArchive& operator<<(const KODI::TIME::time_point& time); + CArchive& operator<<(IArchivable& obj); + CArchive& operator<<(const CVariant& variant); + CArchive& operator<<(const std::vector<std::string>& strArray); +@@ -126,7 +128,7 @@ public: + + CArchive& operator>>(std::string &str); + CArchive& operator>>(std::wstring& wstr); +- CArchive& operator>>(std::chrono::system_clock::time_point& time); ++ CArchive& operator>>(KODI::TIME::time_point& time); + CArchive& operator>>(IArchivable& obj); + CArchive& operator>>(CVariant& variant); + CArchive& operator>>(std::vector<std::string>& strArray); +diff --git a/xbmc/utils/XTimeUtils.h b/xbmc/utils/XTimeUtils.h +index 9d3b0e86a3..ed1b25fb74 100644 +--- a/xbmc/utils/XTimeUtils.h ++++ b/xbmc/utils/XTimeUtils.h +@@ -28,6 +28,9 @@ namespace KODI + namespace TIME + { + ++using time_point = std::chrono::time_point<std::chrono::system_clock, ++ std::chrono::duration<long double, std::nano>>; ++ + template<typename Rep, typename Period> + void Sleep(std::chrono::duration<Rep, Period> duration) + { +diff --git a/xbmc/utils/test/TestArchive.cpp b/xbmc/utils/test/TestArchive.cpp +index b9ab780cf9..de912eba21 100644 +--- a/xbmc/utils/test/TestArchive.cpp ++++ b/xbmc/utils/test/TestArchive.cpp +@@ -223,8 +223,8 @@ TEST_F(TestArchive, StringArchive) + TEST_F(TestArchive, TimePointArchive) + { + ASSERT_NE(nullptr, file); +- std::chrono::system_clock::time_point tp_ref = std::chrono::system_clock::now(); +- std::chrono::system_clock::time_point tp_var; ++ KODI::TIME::time_point tp_ref = std::chrono::system_clock::now(); ++ KODI::TIME::time_point tp_var; + + CArchive arstore(file, CArchive::store); + arstore << tp_ref; +@@ -235,7 +235,7 @@ TEST_F(TestArchive, TimePointArchive) + arload >> tp_var; + arload.Close(); + +- EXPECT_TRUE(!memcmp(&tp_ref, &tp_var, sizeof(std::chrono::system_clock::time_point))); ++ EXPECT_TRUE(!memcmp(&tp_ref, &tp_var, sizeof(KODI::TIME::time_point))); + } + + TEST_F(TestArchive, CVariantArchive) +@@ -335,8 +335,8 @@ TEST_F(TestArchive, MultiTypeArchive) + char char_ref = 'A', char_var = '\0'; + std::string string_ref = "test string", string_var; + std::wstring wstring_ref = L"test wstring", wstring_var; +- std::chrono::system_clock::time_point tp_ref = std::chrono::system_clock::now(); +- std::chrono::system_clock::time_point tp_var; ++ KODI::TIME::time_point tp_ref = std::chrono::system_clock::now(); ++ KODI::TIME::time_point tp_var; + CVariant CVariant_ref((int)1), CVariant_var; + std::vector<std::string> strArray_ref, strArray_var; + strArray_ref.emplace_back("test strArray_ref 0"); +@@ -398,7 +398,7 @@ TEST_F(TestArchive, MultiTypeArchive) + EXPECT_EQ(char_ref, char_var); + EXPECT_STREQ(string_ref.c_str(), string_var.c_str()); + EXPECT_STREQ(wstring_ref.c_str(), wstring_var.c_str()); +- EXPECT_TRUE(!memcmp(&tp_ref, &tp_var, sizeof(std::chrono::system_clock::time_point))); ++ EXPECT_TRUE(!memcmp(&tp_ref, &tp_var, sizeof(KODI::TIME::time_point))); + EXPECT_TRUE(CVariant_var.isInteger()); + EXPECT_STREQ("test strArray_ref 0", strArray_var.at(0).c_str()); + EXPECT_STREQ("test strArray_ref 1", strArray_var.at(1).c_str()); +-- +2.43.0 + + +From c2f4add32ebf1c3a965f1a88af0d49afcdf9e847 Mon Sep 17 00:00:00 2001 +From: Vasyl Gello <vasek.gello@gmail.com> +Date: Fri, 14 May 2021 12:35:54 +0000 +Subject: [PATCH 14/19] Use "long double" type in time_t / tm conversions + +Signed-off-by: Vasyl Gello <vasek.gello@gmail.com> +--- + xbmc/XBDateTime.cpp | 60 +++++++++++++++++++++++++-------------------- + 1 file changed, 34 insertions(+), 26 deletions(-) + +diff --git a/xbmc/XBDateTime.cpp b/xbmc/XBDateTime.cpp +index fdcc27c9af..c71478085b 100644 +--- a/xbmc/XBDateTime.cpp ++++ b/xbmc/XBDateTime.cpp +@@ -93,10 +93,10 @@ const CDateTimeSpan& CDateTimeSpan::operator -=(const CDateTimeSpan& right) + + void CDateTimeSpan::SetDateTimeSpan(int day, int hour, int minute, int second) + { +- m_timeSpan = std::chrono::duration_cast<std::chrono::seconds>(date::days(day)) + +- std::chrono::duration_cast<std::chrono::seconds>(std::chrono::hours(hour)) + +- std::chrono::duration_cast<std::chrono::seconds>(std::chrono::minutes(minute)) + +- std::chrono::duration_cast<std::chrono::seconds>(std::chrono::seconds(second)); ++ m_timeSpan = date::floor<std::chrono::seconds>(date::days(day)) + ++ date::floor<std::chrono::seconds>(std::chrono::hours(hour)) + ++ date::floor<std::chrono::seconds>(std::chrono::minutes(minute)) + ++ date::floor<std::chrono::seconds>(std::chrono::seconds(second)); + } + + void CDateTimeSpan::SetFromTimeString(const std::string& time) // hh:mm +@@ -140,7 +140,7 @@ int CDateTimeSpan::GetSeconds() const + + int CDateTimeSpan::GetSecondsTotal() const + { +- return std::chrono::duration_cast<std::chrono::seconds>(m_timeSpan).count(); ++ return date::floor<std::chrono::seconds>(m_timeSpan).count(); + } + + void CDateTimeSpan::SetFromPeriod(const std::string &period) +@@ -172,7 +172,8 @@ CDateTime::CDateTime(const CDateTime& time) : m_time(time.m_time) + + CDateTime::CDateTime(const time_t& time) + { +- m_time = std::chrono::system_clock::from_time_t(time); ++ Reset(); ++ m_time += std::chrono::duration<long double>(time); + SetValid(true); + } + +@@ -184,7 +185,8 @@ CDateTime::CDateTime(const KODI::TIME::time_point& time) + + CDateTime::CDateTime(const tm& time) + { +- m_time = std::chrono::system_clock::from_time_t(std::mktime(const_cast<tm*>(&time))); ++ Reset(); ++ m_time += std::chrono::duration<long double>(std::mktime(const_cast<tm*>(&time))); + SetValid(true); + } + +@@ -198,8 +200,7 @@ CDateTime CDateTime::GetCurrentDateTime() + auto zone = date::make_zoned(date::current_zone(), std::chrono::system_clock::now()); + + return CDateTime( +- std::chrono::duration_cast<std::chrono::seconds>(zone.get_local_time().time_since_epoch()) +- .count()); ++ date::floor<std::chrono::seconds>(zone.get_local_time().time_since_epoch()).count()); + } + + CDateTime CDateTime::GetUTCDateTime() +@@ -209,7 +210,8 @@ CDateTime CDateTime::GetUTCDateTime() + + const CDateTime& CDateTime::operator =(const time_t& right) + { +- m_time = std::chrono::system_clock::from_time_t(right); ++ Reset(); ++ m_time += std::chrono::duration<long double>(right); + SetValid(true); + + return *this; +@@ -217,7 +219,8 @@ const CDateTime& CDateTime::operator =(const time_t& right) + + const CDateTime& CDateTime::operator =(const tm& right) + { +- m_time = std::chrono::system_clock::from_time_t(std::mktime(const_cast<tm*>(&right))); ++ Reset(); ++ m_time += std::chrono::duration<long double>(std::mktime(const_cast<tm*>(&right))); + SetValid(true); + + return *this; +@@ -263,7 +266,8 @@ bool CDateTime::operator !=(const CDateTime& right) const + + bool CDateTime::operator >(const time_t& right) const + { +- return m_time > std::chrono::system_clock::from_time_t(right); ++ return m_time > ++ std::chrono::system_clock::from_time_t(0) + std::chrono::duration<long double>(right); + } + + bool CDateTime::operator >=(const time_t& right) const +@@ -273,7 +277,8 @@ bool CDateTime::operator >=(const time_t& right) const + + bool CDateTime::operator <(const time_t& right) const + { +- return m_time < std::chrono::system_clock::from_time_t(right); ++ return m_time < ++ std::chrono::system_clock::from_time_t(0) + std::chrono::duration<long double>(right); + } + + bool CDateTime::operator <=(const time_t& right) const +@@ -283,7 +288,8 @@ bool CDateTime::operator <=(const time_t& right) const + + bool CDateTime::operator ==(const time_t& right) const + { +- return m_time == std::chrono::system_clock::from_time_t(right); ++ return m_time == ++ std::chrono::system_clock::from_time_t(0) + std::chrono::duration<long double>(right); + } + + bool CDateTime::operator !=(const time_t& right) const +@@ -293,7 +299,8 @@ bool CDateTime::operator !=(const time_t& right) const + + bool CDateTime::operator >(const tm& right) const + { +- return m_time > std::chrono::system_clock::from_time_t(std::mktime(const_cast<tm*>(&right))); ++ return m_time > std::chrono::system_clock::from_time_t(0) + ++ std::chrono::duration<long double>(std::mktime(const_cast<tm*>(&right))); + } + + bool CDateTime::operator >=(const tm& right) const +@@ -303,7 +310,8 @@ bool CDateTime::operator >=(const tm& right) const + + bool CDateTime::operator <(const tm& right) const + { +- return m_time < std::chrono::system_clock::from_time_t(std::mktime(const_cast<tm*>(&right))); ++ return m_time < std::chrono::system_clock::from_time_t(0) + ++ std::chrono::duration<long double>(std::mktime(const_cast<tm*>(&right))); + } + + bool CDateTime::operator <=(const tm& right) const +@@ -313,7 +321,8 @@ bool CDateTime::operator <=(const tm& right) const + + bool CDateTime::operator ==(const tm& right) const + { +- return m_time == std::chrono::system_clock::from_time_t(std::mktime(const_cast<tm*>(&right))); ++ return m_time == std::chrono::system_clock::from_time_t(0) + ++ std::chrono::duration<long double>(std::mktime(const_cast<tm*>(&right))); + } + + bool CDateTime::operator !=(const tm& right) const +@@ -387,7 +396,7 @@ CDateTimeSpan CDateTime::operator -(const CDateTime& right) const + { + CDateTimeSpan left; + +- left.m_timeSpan = std::chrono::duration_cast<std::chrono::seconds>(m_time - right.m_time); ++ left.m_timeSpan = date::floor<std::chrono::seconds>(m_time - right.m_time); + return left; + } + +@@ -496,7 +505,7 @@ int CDateTime::GetYear() const + int CDateTime::GetHour() const + { + auto dp = date::floor<date::days>(m_time); +- auto time = date::make_time(m_time - dp); ++ auto time = date::make_time(date::floor<std::chrono::seconds>(m_time - dp)); + + return time.hours().count(); + } +@@ -504,7 +513,7 @@ int CDateTime::GetHour() const + int CDateTime::GetMinute() const + { + auto dp = date::floor<date::days>(m_time); +- auto time = date::make_time(m_time - dp); ++ auto time = date::make_time(date::floor<std::chrono::seconds>(m_time - dp)); + + return time.minutes().count(); + } +@@ -512,7 +521,7 @@ int CDateTime::GetMinute() const + int CDateTime::GetSecond() const + { + auto dp = date::floor<date::days>(m_time); +- auto time = date::make_time(m_time - dp); ++ auto time = date::make_time(date::floor<std::chrono::seconds>(m_time - dp)); + + return time.seconds().count(); + } +@@ -529,7 +538,7 @@ int CDateTime::GetMinuteOfDay() const + { + auto dp = date::floor<std::chrono::hours>(m_time); + ; +- auto time = date::make_time(m_time - dp); ++ auto time = date::make_time(date::floor<std::chrono::seconds>(m_time - dp)); + + return time.hours().count() * 60 + time.minutes().count(); + } +@@ -566,12 +575,12 @@ bool CDateTime::SetTime(int hour, int minute, int second) + + void CDateTime::GetAsTime(time_t& time) const + { +- time = std::chrono::system_clock::to_time_t(m_time); ++ time = date::floor<std::chrono::seconds>(m_time.time_since_epoch()).count(); + } + + void CDateTime::GetAsTm(tm& time) const + { +- auto t = std::chrono::system_clock::to_time_t(m_time); ++ auto t = date::floor<std::chrono::seconds>(m_time.time_since_epoch()).count(); + + time = {}; + localtime_r(&t, &time); +@@ -1180,8 +1189,7 @@ CDateTime CDateTime::GetAsLocalDateTime() const + auto zone = date::make_zoned(date::current_zone(), m_time); + + return CDateTime( +- std::chrono::duration_cast<std::chrono::seconds>(zone.get_local_time().time_since_epoch()) +- .count()); ++ date::floor<std::chrono::seconds>(zone.get_local_time().time_since_epoch()).count()); + } + + std::string CDateTime::GetAsRFC1123DateTime() const +-- +2.43.0 + + +From 0a476801a4d337a1e3e9c7115a03c58d302cdd75 Mon Sep 17 00:00:00 2001 +From: Vasyl Gello <vasek.gello@gmail.com> +Date: Mon, 17 May 2021 09:41:32 +0000 +Subject: [PATCH 15/19] Avoid time_t in tm conversions + +This should leave the possibility of time_t truncation on 32-bit +architectures only in GetAsTime(), what we can do nothing with. + +Signed-off-by: Vasyl Gello <vasek.gello@gmail.com> +--- + xbmc/XBDateTime.cpp | 56 +++++++++++++++++++++++++++++++++++++-------- + 1 file changed, 46 insertions(+), 10 deletions(-) + +diff --git a/xbmc/XBDateTime.cpp b/xbmc/XBDateTime.cpp +index c71478085b..ce5c242128 100644 +--- a/xbmc/XBDateTime.cpp ++++ b/xbmc/XBDateTime.cpp +@@ -186,7 +186,16 @@ CDateTime::CDateTime(const KODI::TIME::time_point& time) + CDateTime::CDateTime(const tm& time) + { + Reset(); +- m_time += std::chrono::duration<long double>(std::mktime(const_cast<tm*>(&time))); ++ ++ auto ymd = date::local_days(date::year(time.tm_year + 1900) / date::month(time.tm_mon + 1) / ++ time.tm_mday); ++ auto dur = ymd + std::chrono::hours(time.tm_hour) + std::chrono::minutes(time.tm_min) + ++ std::chrono::seconds(time.tm_sec); ++ ++ auto timeT = date::floor<std::chrono::seconds>(dur.time_since_epoch()).count(); ++ ++ m_time += std::chrono::duration<long double>(timeT); ++ + SetValid(true); + } + +@@ -220,7 +229,16 @@ const CDateTime& CDateTime::operator =(const time_t& right) + const CDateTime& CDateTime::operator =(const tm& right) + { + Reset(); +- m_time += std::chrono::duration<long double>(std::mktime(const_cast<tm*>(&right))); ++ ++ auto ymd = date::local_days(date::year(right.tm_year + 1900) / date::month(right.tm_mon + 1) / ++ right.tm_mday); ++ auto dur = ymd + std::chrono::hours(right.tm_hour) + std::chrono::minutes(right.tm_min) + ++ std::chrono::seconds(right.tm_sec); ++ ++ auto timeT = date::floor<std::chrono::seconds>(dur.time_since_epoch()).count(); ++ ++ m_time += std::chrono::duration<long double>(timeT); ++ + SetValid(true); + + return *this; +@@ -299,8 +317,8 @@ bool CDateTime::operator !=(const time_t& right) const + + bool CDateTime::operator >(const tm& right) const + { +- return m_time > std::chrono::system_clock::from_time_t(0) + +- std::chrono::duration<long double>(std::mktime(const_cast<tm*>(&right))); ++ CDateTime temp(right); ++ return m_time > temp.m_time; + } + + bool CDateTime::operator >=(const tm& right) const +@@ -310,8 +328,8 @@ bool CDateTime::operator >=(const tm& right) const + + bool CDateTime::operator <(const tm& right) const + { +- return m_time < std::chrono::system_clock::from_time_t(0) + +- std::chrono::duration<long double>(std::mktime(const_cast<tm*>(&right))); ++ CDateTime temp(right); ++ return m_time < temp.m_time; + } + + bool CDateTime::operator <=(const tm& right) const +@@ -321,8 +339,8 @@ bool CDateTime::operator <=(const tm& right) const + + bool CDateTime::operator ==(const tm& right) const + { +- return m_time == std::chrono::system_clock::from_time_t(0) + +- std::chrono::duration<long double>(std::mktime(const_cast<tm*>(&right))); ++ CDateTime temp(right); ++ return m_time == temp.m_time; + } + + bool CDateTime::operator !=(const tm& right) const +@@ -580,10 +598,28 @@ void CDateTime::GetAsTime(time_t& time) const + + void CDateTime::GetAsTm(tm& time) const + { +- auto t = date::floor<std::chrono::seconds>(m_time.time_since_epoch()).count(); ++ auto dp = date::floor<date::days>(m_time); + + time = {}; +- localtime_r(&t, &time); ++ ++ auto ymd = date::year_month_day{dp}; ++ time.tm_year = int(ymd.year()) - 1900; ++ time.tm_mon = unsigned(ymd.month()) - 1; ++ time.tm_mday = unsigned(ymd.day()); ++ ++ auto hms = date::make_time(date::floor<std::chrono::seconds>(m_time - dp)); ++ time.tm_hour = hms.hours().count(); ++ time.tm_min = hms.minutes().count(); ++ time.tm_sec = hms.seconds().count(); ++ ++ date::weekday wd{dp}; ++ time.tm_wday = wd.c_encoding(); ++ ++ auto newyear = date::sys_days(date::year(time.tm_year + 1900) / 1 / 1); ++ auto seconds_to_newyear = date::floor<std::chrono::seconds>(m_time - newyear); ++ time.tm_yday = seconds_to_newyear.count() / 86400; ++ ++ time.tm_isdst = date::current_zone()->get_info(m_time).save.count() != 0; + } + + KODI::TIME::time_point CDateTime::GetAsTimePoint() const +-- +2.43.0 + + +From 431a3cdbdc388bb8661d4d35fe5a42b579e3fc86 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?P=C3=A4r=20Bj=C3=B6rklund?= <per.bjorklund@gmail.com> +Date: Sun, 31 Oct 2021 10:33:30 +0100 +Subject: [PATCH 16/19] Windows patches + +--- + xbmc/application/Application.cpp | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/xbmc/application/Application.cpp b/xbmc/application/Application.cpp +index 6aa584e5c9..df55665b5e 100644 +--- a/xbmc/application/Application.cpp ++++ b/xbmc/application/Application.cpp +@@ -357,7 +357,9 @@ bool CApplication::Create() + CServiceBroker::RegisterJobManager(std::make_shared<CJobManager>()); + + // Initialize,timezone ++#if defined(TARGET_POSIX) + g_timezone.Init(); ++#endif + + // Announcement service + m_pAnnouncementManager = std::make_shared<ANNOUNCEMENT::CAnnouncementManager>(); +-- +2.43.0 + + +From 257a56972008869e448fd81b15c67bb46c17f338 Mon Sep 17 00:00:00 2001 +From: Vasyl Gello <vasek.gello@gmail.com> +Date: Mon, 11 Jul 2022 09:24:01 +0000 +Subject: [PATCH 17/19] XBDateTime: Use timezone info specified via timezone + picker. + +Fixes broken timezone picker as reported in Debian Bug#1011294. + +Also fixes TZ-related issue spotted on reproducibility build +where TZ envvar specifying timezone as absolute pathname on Linux +and FreeBSD screwed date lib up. + +Signed-off-by: Vasyl Gello <vasek.gello@gmail.com> +--- + xbmc/XBDateTime.cpp | 8 +++--- + xbmc/test/TestDateTime.cpp | 20 ++++++++++++--- + xbmc/utils/CMakeLists.txt | 1 + + xbmc/utils/DateLib.cpp | 51 ++++++++++++++++++++++++++++++++++++++ + xbmc/utils/DateLib.h | 13 ++++++++++ + 5 files changed, 86 insertions(+), 7 deletions(-) + create mode 100644 xbmc/utils/DateLib.cpp + +diff --git a/xbmc/XBDateTime.cpp b/xbmc/XBDateTime.cpp +index ce5c242128..29118e7570 100644 +--- a/xbmc/XBDateTime.cpp ++++ b/xbmc/XBDateTime.cpp +@@ -206,7 +206,7 @@ CDateTime::CDateTime(int year, int month, int day, int hour, int minute, int sec + + CDateTime CDateTime::GetCurrentDateTime() + { +- auto zone = date::make_zoned(date::current_zone(), std::chrono::system_clock::now()); ++ auto zone = date::make_zoned(KODI::TIME::GetTimeZone(), std::chrono::system_clock::now()); + + return CDateTime( + date::floor<std::chrono::seconds>(zone.get_local_time().time_since_epoch()).count()); +@@ -619,7 +619,7 @@ void CDateTime::GetAsTm(tm& time) const + auto seconds_to_newyear = date::floor<std::chrono::seconds>(m_time - newyear); + time.tm_yday = seconds_to_newyear.count() / 86400; + +- time.tm_isdst = date::current_zone()->get_info(m_time).save.count() != 0; ++ time.tm_isdst = KODI::TIME::GetTimeZone()->get_info(m_time).save.count() != 0; + } + + KODI::TIME::time_point CDateTime::GetAsTimePoint() const +@@ -1222,7 +1222,7 @@ std::string CDateTime::GetAsLocalizedTime(TIME_FORMAT format, bool withSeconds / + + CDateTime CDateTime::GetAsLocalDateTime() const + { +- auto zone = date::make_zoned(date::current_zone(), m_time); ++ auto zone = date::make_zoned(KODI::TIME::GetTimeZone(), m_time); + + return CDateTime( + date::floor<std::chrono::seconds>(zone.get_local_time().time_since_epoch()).count()); +@@ -1247,7 +1247,7 @@ std::string CDateTime::GetAsW3CDateTime(bool asUtc /* = false */) const + if (asUtc) + return date::format("%FT%TZ", time); + +- auto zt = date::make_zoned(date::current_zone(), time); ++ auto zt = date::make_zoned(KODI::TIME::GetTimeZone(), time); + + return date::format("%FT%T%Ez", zt); + } +diff --git a/xbmc/test/TestDateTime.cpp b/xbmc/test/TestDateTime.cpp +index de3f75e5e4..6604146a61 100644 +--- a/xbmc/test/TestDateTime.cpp ++++ b/xbmc/test/TestDateTime.cpp +@@ -303,7 +303,7 @@ TEST_F(TestDateTime, GetAsStringsWithBias) + std::cout << dateTime.GetAsW3CDateTime(true) << std::endl; + + auto tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint()); +- auto zone = date::make_zoned(date::current_zone(), tps); ++ auto zone = date::make_zoned(KODI::TIME::GetTimeZone(), tps); + + EXPECT_EQ(dateTime.GetAsRFC1123DateTime(), "Tue, 14 May 1991 12:34:56 GMT"); + EXPECT_EQ(dateTime.GetAsW3CDateTime(false), date::format("%FT%T%Ez", zone)); +@@ -552,12 +552,12 @@ TEST_F(TestDateTime, GetAsLocalDateTime) + CDateTime dateTime2; + dateTime2 = dateTime1.GetAsLocalDateTime(); + +- auto zoned_time = date::make_zoned(date::current_zone(), dateTime1.GetAsTimePoint()); ++ auto zoned_time = date::make_zoned(KODI::TIME::GetTimeZone(), dateTime1.GetAsTimePoint()); + auto time = zoned_time.get_local_time().time_since_epoch(); + + CDateTime cmpTime(std::chrono::duration_cast<std::chrono::seconds>(time).count()); + +- EXPECT_TRUE(dateTime1 == cmpTime); ++ EXPECT_TRUE(dateTime2 == cmpTime); + } + + TEST_F(TestDateTime, Reset) +@@ -736,3 +736,17 @@ TEST_F(TestDateTime, Tzdata) + EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-15T02:34:56+14:00") + << "tzdata information not valid for 'Etc/GMT-14'"; + } ++ ++TEST_F(TestDateTime, ExtractTzName) ++{ ++ CDateTime dateTime; ++ dateTime.SetDateTime(1991, 05, 14, 12, 34, 56); ++ ++ auto tps = date::floor<std::chrono::seconds>(dateTime.GetAsTimePoint()); ++ auto zone = date::make_zoned(KODI::TIME::ExtractTzName("/usr/share/zoneinfo/Etc/GMT-14"), tps); ++ EXPECT_EQ(date::format("%FT%T%Ez", zone), "1991-05-15T02:34:56+14:00") ++ << "extractTzName failed for '/usr/share/zoneinfo/Etc/GMT-14'"; ++ ++ EXPECT_EQ(KODI::TIME::ExtractTzName("/usr/share/z0neinfo/Etc/GMT+12"), "") ++ << "extractTzName failed for '/usr/share/z0neinfo/Etc/GMT+12'"; ++} +diff --git a/xbmc/utils/CMakeLists.txt b/xbmc/utils/CMakeLists.txt +index bb4851c0ce..8f3a199a65 100644 +--- a/xbmc/utils/CMakeLists.txt ++++ b/xbmc/utils/CMakeLists.txt +@@ -17,6 +17,7 @@ set(SOURCES ActorProtocol.cpp + Crc32.cpp + CSSUtils.cpp + DatabaseUtils.cpp ++ DateLib.cpp + Digest.cpp + DiscsUtils.cpp + EndianSwap.cpp +diff --git a/xbmc/utils/DateLib.cpp b/xbmc/utils/DateLib.cpp +new file mode 100644 +index 0000000000..bd86dd5791 +--- /dev/null ++++ b/xbmc/utils/DateLib.cpp +@@ -0,0 +1,51 @@ ++/* ++ * Copyright (C) 2005-2022 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 "DateLib.h" ++ ++#include "utils/XTimeUtils.h" ++ ++#include <cstdlib> ++ ++const std::string KODI::TIME::ExtractTzName(const char* tzname) ++{ ++ if (tzname[0] != '/') ++ return tzname; ++ ++ std::string result = tzname; ++ const char zoneinfo[] = "zoneinfo"; ++ size_t pos = result.rfind(zoneinfo); ++ if (pos == result.npos) ++ { ++ return ""; ++ } ++ ++ pos = result.find('/', pos); ++ result.erase(0, pos + 1); ++ return result; ++} ++ ++const date::time_zone* KODI::TIME::GetTimeZone() ++{ ++#if defined(TARGET_POSIX) && !defined(TARGET_DARWIN) ++ const date::time_zone* tz = nullptr; ++ const char* tzname = std::getenv("TZ"); ++ ++ if (tzname && tzname[0] != '\0') ++ { ++ const std::string tzn = ExtractTzName(tzname); ++ if (!tzn.empty()) ++ tz = date::locate_zone(tzn); ++ } ++ ++ if (tz) ++ return tz; ++ else ++#endif ++ return date::current_zone(); ++} +diff --git a/xbmc/utils/DateLib.h b/xbmc/utils/DateLib.h +index e39650aa03..9838dd94fe 100644 +--- a/xbmc/utils/DateLib.h ++++ b/xbmc/utils/DateLib.h +@@ -19,6 +19,19 @@ + #endif + + #define HAS_REMOTE_API 0 ++#include <cstring> ++ + #include <date/date.h> + #include <date/iso_week.h> + #include <date/tz.h> ++ ++namespace KODI ++{ ++namespace TIME ++{ ++ ++const std::string ExtractTzName(const char* tzname); ++const date::time_zone* GetTimeZone(); ++ ++} // namespace TIME ++} // namespace KODI +-- +2.43.0 + + +From b67dabf8a304565713b413d4efb30c567a0a639b Mon Sep 17 00:00:00 2001 +From: Vasyl Gello <vasek.gello@gmail.com> +Date: Mon, 9 Jan 2023 23:00:17 +0200 +Subject: [PATCH 18/19] Apply formatting fixes + +Signed-off-by: Vasyl Gello <vasek.gello@gmail.com> +--- + xbmc/XBDateTime.cpp | 30 +++++++++++++++--------------- + 1 file changed, 15 insertions(+), 15 deletions(-) + +diff --git a/xbmc/XBDateTime.cpp b/xbmc/XBDateTime.cpp +index 29118e7570..402aecfa9c 100644 +--- a/xbmc/XBDateTime.cpp ++++ b/xbmc/XBDateTime.cpp +@@ -167,7 +167,7 @@ CDateTime::CDateTime() + + CDateTime::CDateTime(const CDateTime& time) : m_time(time.m_time) + { +- m_state=time.m_state; ++ m_state = time.m_state; + } + + CDateTime::CDateTime(const time_t& time) +@@ -217,7 +217,7 @@ CDateTime CDateTime::GetUTCDateTime() + return CDateTime(std::chrono::system_clock::now()); + } + +-const CDateTime& CDateTime::operator =(const time_t& right) ++const CDateTime& CDateTime::operator=(const time_t& right) + { + Reset(); + m_time += std::chrono::duration<long double>(right); +@@ -226,7 +226,7 @@ const CDateTime& CDateTime::operator =(const time_t& right) + return *this; + } + +-const CDateTime& CDateTime::operator =(const tm& right) ++const CDateTime& CDateTime::operator=(const tm& right) + { + Reset(); + +@@ -282,68 +282,68 @@ bool CDateTime::operator !=(const CDateTime& right) const + return !operator ==(right); + } + +-bool CDateTime::operator >(const time_t& right) const ++bool CDateTime::operator>(const time_t& right) const + { + return m_time > + std::chrono::system_clock::from_time_t(0) + std::chrono::duration<long double>(right); + } + +-bool CDateTime::operator >=(const time_t& right) const ++bool CDateTime::operator>=(const time_t& right) const + { + return operator >(right) || operator ==(right); + } + +-bool CDateTime::operator <(const time_t& right) const ++bool CDateTime::operator<(const time_t& right) const + { + return m_time < + std::chrono::system_clock::from_time_t(0) + std::chrono::duration<long double>(right); + } + +-bool CDateTime::operator <=(const time_t& right) const ++bool CDateTime::operator<=(const time_t& right) const + { + return operator <(right) || operator ==(right); + } + +-bool CDateTime::operator ==(const time_t& right) const ++bool CDateTime::operator==(const time_t& right) const + { + return m_time == + std::chrono::system_clock::from_time_t(0) + std::chrono::duration<long double>(right); + } + +-bool CDateTime::operator !=(const time_t& right) const ++bool CDateTime::operator!=(const time_t& right) const + { + return !operator ==(right); + } + +-bool CDateTime::operator >(const tm& right) const ++bool CDateTime::operator>(const tm& right) const + { + CDateTime temp(right); + return m_time > temp.m_time; + } + +-bool CDateTime::operator >=(const tm& right) const ++bool CDateTime::operator>=(const tm& right) const + { + return operator >(right) || operator ==(right); + } + +-bool CDateTime::operator <(const tm& right) const ++bool CDateTime::operator<(const tm& right) const + { + CDateTime temp(right); + return m_time < temp.m_time; + } + +-bool CDateTime::operator <=(const tm& right) const ++bool CDateTime::operator<=(const tm& right) const + { + return operator <(right) || operator ==(right); + } + +-bool CDateTime::operator ==(const tm& right) const ++bool CDateTime::operator==(const tm& right) const + { + CDateTime temp(right); + return m_time == temp.m_time; + } + +-bool CDateTime::operator !=(const tm& right) const ++bool CDateTime::operator!=(const tm& right) const + { + return !operator ==(right); + } +-- +2.43.0 + + +From ae3e34c85b2c8fe476d22b7adbe9e2457a025edd Mon Sep 17 00:00:00 2001 +From: Vasyl Gello <vasek.gello@gmail.com> +Date: Thu, 13 Apr 2023 20:18:28 +0300 +Subject: [PATCH 19/19] Move LoadTimeZoneDatabase to xbmc/utils/DateLib.cpp + +Signed-off-by: Vasyl Gello <vasek.gello@gmail.com> +--- + xbmc/addons/TimeZoneResource.cpp | 4 +--- + xbmc/settings/SettingsComponent.cpp | 5 +++++ + xbmc/utils/DateLib.cpp | 23 +++++++++++++++++++++++ + xbmc/utils/DateLib.h | 1 + + 4 files changed, 30 insertions(+), 3 deletions(-) + +diff --git a/xbmc/addons/TimeZoneResource.cpp b/xbmc/addons/TimeZoneResource.cpp +index 6dfba75e89..12c4371e19 100644 +--- a/xbmc/addons/TimeZoneResource.cpp ++++ b/xbmc/addons/TimeZoneResource.cpp +@@ -32,9 +32,7 @@ bool CTimeZoneResource::IsInUse() const + + void CTimeZoneResource::OnPostInstall(bool update, bool modal) + { +-#if defined(DATE_INTERNAL_TZDATA) +- date::reload_tzdb(); +-#endif ++ KODI::TIME::LoadTimeZoneDatabase(); + } + + } // namespace ADDON +diff --git a/xbmc/settings/SettingsComponent.cpp b/xbmc/settings/SettingsComponent.cpp +index 0f5f7ae8da..8ce2730d3b 100644 +--- a/xbmc/settings/SettingsComponent.cpp ++++ b/xbmc/settings/SettingsComponent.cpp +@@ -24,6 +24,7 @@ + #include "settings/AdvancedSettings.h" + #include "settings/Settings.h" + #include "settings/SubtitlesSettings.h" ++#include "utils/DateLib.h" + #include "utils/StringUtils.h" + #include "utils/URIUtils.h" + #include "utils/log.h" +@@ -56,6 +57,10 @@ void CSettingsComponent::Initialize() + if (!inited) + inited = InitDirectoriesWin32(params->HasPlatformDirectories()); + ++ // Try loading timezone information after directories were provisioned ++ //!@todo check if the whole dirs logic should be moved to AppEnvironment ++ KODI::TIME::LoadTimeZoneDatabase(); ++ + m_settings->Initialize(); + + m_advancedSettings->Initialize(*m_settings->GetSettingsManager()); +diff --git a/xbmc/utils/DateLib.cpp b/xbmc/utils/DateLib.cpp +index bd86dd5791..d8a6d67764 100644 +--- a/xbmc/utils/DateLib.cpp ++++ b/xbmc/utils/DateLib.cpp +@@ -49,3 +49,26 @@ const date::time_zone* KODI::TIME::GetTimeZone() + #endif + return date::current_zone(); + } ++ ++void KODI::TIME::LoadTimeZoneDatabase() ++{ ++#if defined(DATE_INTERNAL_TZDATA) ++ // First check the timezone resource from userprofile ++ auto tzdataPath = ++ CSpecialProtocol::TranslatePath("special://home/addons/resource.timezone/resources/tzdata"); ++ if (!XFILE::CDirectory::Exists(tzdataPath)) ++ { ++ // Then check system-wide Kodi profile and bail out if not found ++ tzdataPath = ++ CSpecialProtocol::TranslatePath("special://xbmc/addons/resource.timezone/resources/tzdata"); ++ if (!XFILE::CDirectory::Exists(tzdataPath)) ++ { ++ CLog::LogF(LOGFATAL, "failed to find resource.timezone"); ++ return; ++ } ++ } ++ ++ CLog::LogF(LOGDEBUG, "Loading tzdata from path: {}", tzdataPath); ++ date::set_install(tzdataPath); ++#endif ++} +diff --git a/xbmc/utils/DateLib.h b/xbmc/utils/DateLib.h +index 9838dd94fe..09c4ba0b17 100644 +--- a/xbmc/utils/DateLib.h ++++ b/xbmc/utils/DateLib.h +@@ -32,6 +32,7 @@ namespace TIME + + const std::string ExtractTzName(const char* tzname); + const date::time_zone* GetTimeZone(); ++void LoadTimeZoneDatabase(); + + } // namespace TIME + } // namespace KODI +-- +2.43.0 + diff --git a/debian/patches/kodi/0001-Implement-hashes-using-Libgcrypt.patch b/debian/patches/kodi/0001-Implement-hashes-using-Libgcrypt.patch new file mode 100644 index 0000000..10c46de --- /dev/null +++ b/debian/patches/kodi/0001-Implement-hashes-using-Libgcrypt.patch @@ -0,0 +1,145 @@ +From 418ce26d409cadc089c5e2e624578432727d7de5 Mon Sep 17 00:00:00 2001 +From: Balint Reczey <balint.reczey@canonical.com> +Date: Fri, 22 Feb 2019 23:03:21 +0100 +Subject: [PATCH] Implement hashes using Libgcrypt +Forwarded: not-needed + +--- + xbmc/utils/Digest.cpp | 36 ++++++++++++++++-------------------- + xbmc/utils/Digest.h | 10 +++++----- + 2 files changed, 21 insertions(+), 25 deletions(-) + +diff --git a/xbmc/utils/Digest.cpp b/xbmc/utils/Digest.cpp +index 445a755..63ce81e 100644 +--- a/xbmc/utils/Digest.cpp ++++ b/xbmc/utils/Digest.cpp +@@ -13,7 +13,7 @@ + #include <array> + #include <stdexcept> + +-#include <openssl/evp.h> ++#include <gcrypt.h> + + namespace KODI + { +@@ -23,18 +23,18 @@ namespace UTILITY + namespace + { + +-EVP_MD const * TypeToEVPMD(CDigest::Type type) ++int const TypeToInt(CDigest::Type type) + { + switch (type) + { + case CDigest::Type::MD5: +- return EVP_md5(); ++ return GCRY_MD_MD5; + case CDigest::Type::SHA1: +- return EVP_sha1(); ++ return GCRY_MD_SHA1; + case CDigest::Type::SHA256: +- return EVP_sha256(); ++ return GCRY_MD_SHA256; + case CDigest::Type::SHA512: +- return EVP_sha512(); ++ return GCRY_MD_SHA512; + default: + throw std::invalid_argument("Unknown digest type"); + } +@@ -92,18 +92,20 @@ CDigest::Type CDigest::TypeFromString(std::string const& type) + } + } + +-void CDigest::MdCtxDeleter::operator()(EVP_MD_CTX* context) ++void CDigest::MdCtxDeleter::operator()(gcry_md_hd_t context) + { +- EVP_MD_CTX_destroy(context); ++ gcry_md_close(context); + } + + CDigest::CDigest(Type type) +-: m_context{EVP_MD_CTX_create()}, m_md(TypeToEVPMD(type)) ++ : m_context(), m_md(TypeToInt(type)) + { +- if (1 != EVP_DigestInit_ex(m_context.get(), m_md, nullptr)) ++ gcry_md_hd_t hd = NULL; ++ if (GPG_ERR_NO_ERROR != gcry_md_open(&hd, m_md, 0)) + { +- throw std::runtime_error("EVP_DigestInit_ex failed"); ++ throw std::runtime_error("gcry_md_open failed"); + } ++ m_context.reset(hd); + } + + void CDigest::Update(std::string const& data) +@@ -118,10 +120,7 @@ void CDigest::Update(void const* data, std::size_t size) + throw std::logic_error("Finalized digest cannot be updated any more"); + } + +- if (1 != EVP_DigestUpdate(m_context.get(), data, size)) +- { +- throw std::runtime_error("EVP_DigestUpdate failed"); +- } ++ gcry_md_write(m_context.get(), data, size); + } + + std::string CDigest::FinalizeRaw() +@@ -134,15 +133,12 @@ std::string CDigest::FinalizeRaw() + m_finalized = true; + + std::array<unsigned char, 64> digest; +- std::size_t size = EVP_MD_size(m_md); ++ std::size_t size = gcry_md_get_algo_dlen(m_md); + if (size > digest.size()) + { + throw std::runtime_error("Digest unexpectedly long"); + } +- if (1 != EVP_DigestFinal_ex(m_context.get(), digest.data(), nullptr)) +- { +- throw std::runtime_error("EVP_DigestFinal_ex failed"); +- } ++ memcpy(digest.data(), gcry_md_read(m_context.get(), m_md), size); + return {reinterpret_cast<char*> (digest.data()), size}; + } + +diff --git a/xbmc/utils/Digest.h b/xbmc/utils/Digest.h +index 6452857..6dfed47 100644 +--- a/xbmc/utils/Digest.h ++++ b/xbmc/utils/Digest.h +@@ -15,7 +15,7 @@ + #include <stdexcept> + #include <string> + +-#include <openssl/evp.h> ++#include <gcrypt.h> + + namespace KODI + { +@@ -23,7 +23,7 @@ namespace UTILITY + { + + /** +- * Utility class for calculating message digests/hashes, currently using OpenSSL ++ * Utility class for calculating message digests/hashes + */ + class CDigest + { +@@ -93,12 +93,12 @@ public: + private: + struct MdCtxDeleter + { +- void operator()(EVP_MD_CTX* context); ++ void operator()(gcry_md_hd_t context); + }; + + bool m_finalized{false}; +- std::unique_ptr<EVP_MD_CTX, MdCtxDeleter> m_context; +- EVP_MD const* m_md; ++ std::unique_ptr<struct gcry_md_handle, MdCtxDeleter> m_context; ++ int const m_md; + }; + + struct TypedDigest +-- +2.20.1 + diff --git a/debian/patches/kodi/0002-Find-and-link-with-Libgcrypt.patch b/debian/patches/kodi/0002-Find-and-link-with-Libgcrypt.patch new file mode 100644 index 0000000..30be79a --- /dev/null +++ b/debian/patches/kodi/0002-Find-and-link-with-Libgcrypt.patch @@ -0,0 +1,58 @@ +From 9f0f2742dee33c33303b6158751a0baab17543f2 Mon Sep 17 00:00:00 2001 +From: Balint Reczey <balint.reczey@canonical.com> +Date: Sat, 23 Feb 2019 11:06:43 +0100 +Subject: [PATCH] Find and link with Libgcrypt +Forwarded: not-needed + +--- + CMakeLists.txt | 1 + + cmake/modules/FindLibgcrypt.cmake | 25 +++++++++++++++++++++++++ + 2 files changed, 26 insertions(+) + create mode 100644 cmake/modules/FindLibgcrypt.cmake + +diff --git a/CMakeLists.txt b/CMakeLists.txt +index f902211..f20909a 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -139,6 +139,7 @@ + Iconv + KissFFT + LibDvd ++ Libgcrypt + Lzo2 + OpenSSL>=1.1.0 + PCRE +diff --git a/cmake/modules/FindLibgcrypt.cmake b/cmake/modules/FindLibgcrypt.cmake +new file mode 100644 +index 0000000..9de789a +--- /dev/null ++++ b/cmake/modules/FindLibgcrypt.cmake +@@ -0,0 +1,25 @@ ++#.rst: ++# FindLibgcrypt ++# ------- ++# Finds the Libgcrypt library ++# ++# This will define the following variables:: ++# ++# LIBGCRYPT_FOUND - system has Libgcrypt ++# LIBGCRYPT_INCLUDE_DIRS - the Libgcrypt include directory ++# LIBGCRYPT_LIBRARIES - the Libgcrypt libraries ++# LIBGCRYPT_DEFINITIONS - the Libgcrypt compile definitions ++ ++find_path(LIBGCRYPT_INCLUDE_DIR gcrypt.h) ++find_library(LIBGCRYPT_LIBRARY NAMES gcrypt) ++ ++include(FindPackageHandleStandardArgs) ++find_package_handle_standard_args(Libgcrypt REQUIRED_VARS LIBGCRYPT_LIBRARY LIBGCRYPT_INCLUDE_DIR) ++ ++if(LIBGCRYPT_FOUND) ++ set(LIBGCRYPT_LIBRARIES ${LIBGCRYPT_LIBRARY}) ++ set(LIBGCRYPT_INCLUDE_DIRS ${LIBGCRYPT_INCLUDE_DIR}) ++ set(LIBGCRYPT_DEFINITIONS -DHAVE_GCRYPT=1) ++endif() ++ ++mark_as_advanced(LIBGCRYPT_LIBRARY LIBGCRYPT_INCLUDE_DIR) +-- +2.20.1 + diff --git a/debian/patches/kodi/0003-differentiate-from-vanilla-Kodi.patch b/debian/patches/kodi/0003-differentiate-from-vanilla-Kodi.patch new file mode 100644 index 0000000..f909400 --- /dev/null +++ b/debian/patches/kodi/0003-differentiate-from-vanilla-Kodi.patch @@ -0,0 +1,90 @@ +From d7ce565e1de5515afab869f8d1de35840567af7a Mon Sep 17 00:00:00 2001 +From: Debian Multimedia Maintainers <debian-multimedia@lists.debian.org> +Date: Wed, 26 Feb 2020 13:48:55 +0100 +Subject: [PATCH] differentiate-from-vanilla-Kodi +Forwarded: not-needed + +--- + addons/skin.estuary/xml/Home.xml | 8 ++++++++ + xbmc/utils/SystemInfo.cpp | 12 ++++++++---- + xbmc/utils/test/TestSystemInfo.cpp | 2 +- + 3 files changed, 17 insertions(+), 5 deletions(-) + +diff --git a/addons/skin.estuary/xml/Home.xml b/addons/skin.estuary/xml/Home.xml +index b5e1290..f441b04 100644 +--- a/addons/skin.estuary/xml/Home.xml ++++ b/addons/skin.estuary/xml/Home.xml +@@ -1046,6 +1046,14 @@ + <param name="visible" value="Player.HasMedia" /> + </include> + </control> ++ <control type="image"> ++ <left>140</left> ++ <top>71</top> ++ <width>250</width> ++ <height>56</height> ++ <aspectratio>keep</aspectratio> ++ <texture>from-debian-logo.png</texture> ++ </control> + </control> + <include>BottomBar</include> + <control type="group"> +diff --git a/xbmc/utils/SystemInfo.cpp b/xbmc/utils/SystemInfo.cpp +index f14d1e8a..c64821e9 100644 +--- a/xbmc/utils/SystemInfo.cpp ++++ b/xbmc/utils/SystemInfo.cpp +@@ -75,6 +75,9 @@ using namespace winrt::Windows::System::Profile; + + #include <system_error> + ++#include <algorithm> ++#include <cctype> ++ + /* Expand macro before stringify */ + #define STR_MACRO(x) #x + #define XSTR_MACRO(x) STR_MACRO(x) +@@ -422,7 +425,7 @@ bool CSysInfo::Save(TiXmlNode *settings) const + const std::string& CSysInfo::GetAppName(void) + { + assert(CCompileInfo::GetAppName() != NULL); +- static const std::string appName(CCompileInfo::GetAppName()); ++ static const std::string appName(StringUtils::Format("{} from Debian", CCompileInfo::GetAppName())); + + return appName; + } +@@ -1017,7 +1020,9 @@ std::string CSysInfo::GetUserAgent() + if (!result.empty()) + return result; + +- result = GetAppName() + "/" + CSysInfo::GetVersionShort() + " ("; ++ std::string appName = GetAppName(); ++ appName.erase(std::remove_if(appName.begin(), appName.end(), ::isspace), appName.end()); ++ result = appName + "/" + CSysInfo::GetVersionShort() + " ("; + #if defined(TARGET_WINDOWS) + result += GetKernelName() + " " + GetKernelVersion(); + #ifndef TARGET_WINDOWS_STORE +@@ -1185,8 +1190,7 @@ std::string CSysInfo::GetVersionShort() + + std::string CSysInfo::GetVersion() + { +- return GetVersionShort() + " (" + CCompileInfo::GetVersionCode() + ")" + +- " Git:" + CCompileInfo::GetSCMID(); ++ return GetVersionShort() + StringUtils::Format(" Debian package version: {}", DEB_VERSION); + } + + std::string CSysInfo::GetVersionCode() +diff --git a/xbmc/utils/test/TestSystemInfo.cpp b/xbmc/utils/test/TestSystemInfo.cpp +index 1f2b0a1..1145aa4 100644 +--- a/xbmc/utils/test/TestSystemInfo.cpp ++++ b/xbmc/utils/test/TestSystemInfo.cpp +@@ -208,7 +208,7 @@ TEST_F(TestSystemInfo, GetXbmcBitness) + + TEST_F(TestSystemInfo, GetUserAgent) + { +- EXPECT_STREQ(g_sysinfo.GetAppName().c_str(), g_sysinfo.GetUserAgent().substr(0, g_sysinfo.GetAppName().size()).c_str()) << "'GetUserAgent()' string must start with app name'"; ++ // EXPECT_STREQ(g_sysinfo.GetAppName().c_str(), g_sysinfo.GetUserAgent().substr(0, g_sysinfo.GetAppName().size()).c_str()) << "'GetUserAgent()' string must start with app name'"; + EXPECT_NE(std::string::npos, g_sysinfo.GetUserAgent().find('(')) << "'GetUserAgent()' must contain brackets around second parameter"; + EXPECT_NE(std::string::npos, g_sysinfo.GetUserAgent().find(')')) << "'GetUserAgent()' must contain brackets around second parameter"; + EXPECT_EQ(g_sysinfo.GetUserAgent().find(' '), g_sysinfo.GetUserAgent().find(" (")) << "Second parameter in 'GetUserAgent()' string must be in brackets"; +-- +2.27.0.rc2 diff --git a/debian/patches/kodi/0004-use-system-groovy.patch b/debian/patches/kodi/0004-use-system-groovy.patch new file mode 100644 index 0000000..e2df3c2 --- /dev/null +++ b/debian/patches/kodi/0004-use-system-groovy.patch @@ -0,0 +1,128 @@ +From 9c5f184cee41bb65c6dbe49b0c0b8cf049785d51 Mon Sep 17 00:00:00 2001 +From: Balint Reczey <balint@balintreczey.hu> +Date: Tue, 3 Mar 2020 23:56:06 +0100 +Subject: [PATCH] Use system's groovy instead of the embedded one +Forwarded: not-needed + +--- + xbmc/interfaces/swig/CMakeLists.txt | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/xbmc/interfaces/swig/CMakeLists.txt b/xbmc/interfaces/swig/CMakeLists.txt +index fc73821..0b5895b 100644 +--- a/xbmc/interfaces/swig/CMakeLists.txt ++++ b/xbmc/interfaces/swig/CMakeLists.txt +@@ -1,8 +1,6 @@ + function(generate_file file) +- set(classpath ${GROOVY_DIR}/groovy-${GROOVY_VER}.jar +- ${GROOVY_DIR}/groovy-xml-${GROOVY_VER}.jar +- ${GROOVY_DIR}/groovy-templates-${GROOVY_VER}.jar +- ${GROOVY_DIR}/commons-lang-${COMMONS_VER}.jar ++ set(classpath /usr/share/java/groovy.jar ++ /usr/share/java/commons-lang-2.6.jar + ${CMAKE_SOURCE_DIR}/tools/codegenerator + ${CMAKE_CURRENT_SOURCE_DIR}/../python) + if(NOT CORE_SYSTEM_NAME STREQUAL windows AND NOT CORE_SYSTEM_NAME STREQUAL windowsstore) +@@ -24,8 +24,8 @@ + add_custom_command(OUTPUT ${CPP_FILE} + COMMAND ${SWIG_EXECUTABLE} + ARGS -w401 -c++ -o ${file}.xml -xml -I${CMAKE_SOURCE_DIR}/xbmc -xmllang python ${CMAKE_CURRENT_SOURCE_DIR}/../swig/${file} +- COMMAND ${Java_JAVA_EXECUTABLE} +- ARGS ${JAVA_OPEN_OPTS} -cp "${classpath}" groovy.ui.GroovyMain ${CMAKE_SOURCE_DIR}/tools/codegenerator/Generator.groovy ${file}.xml ${CMAKE_CURRENT_SOURCE_DIR}/../python/PythonSwig.cpp.template ${file}.cpp > ${devnull} ++ COMMAND groovy ++ ARGS -cp "${classpath}" ${CMAKE_SOURCE_DIR}/tools/codegenerator/Generator.groovy ${file}.xml ${CMAKE_CURRENT_SOURCE_DIR}/../python/PythonSwig.cpp.template ${file}.cpp > ${devnull} + ${CLANG_FORMAT_COMMAND} + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/../swig/${file} ${CMAKE_CURRENT_SOURCE_DIR}/../python/PythonSwig.cpp.template) + set(SOURCES ${SOURCES} "${CPP_FILE}" PARENT_SCOPE) +-- +2.20.1 + + +From 8178f46f2f692bd57d5fe851e16b1b377bb4867b Mon Sep 17 00:00:00 2001 +From: Jose Luis Marti <joseluis.marti@gmail.com> +Date: Sun, 23 Oct 2022 23:54:58 +0200 +Subject: [PATCH 2/2] add imports needed for the bump + +--- + tools/codegenerator/Generator.groovy | 1 - + tools/codegenerator/Helper.groovy | 1 - + tools/codegenerator/SwigTypeParser.groovy | 2 -- + 3 files changed, 4 deletions(-) + +diff --git b/tools/codegenerator/Generator.groovy a/tools/codegenerator/Generator.groovy +index 79cfe4f5fb..53cf7864f9 100644 +--- b/tools/codegenerator/Generator.groovy ++++ a/tools/codegenerator/Generator.groovy +@@ -19,7 +19,6 @@ + */ + + import groovy.text.SimpleTemplateEngine +-import groovy.xml.XmlParser + import groovy.xml.XmlUtil + + import Helper +diff --git b/tools/codegenerator/Helper.groovy a/tools/codegenerator/Helper.groovy +index 4308ffd3f3..6324e537e1 100644 +--- b/tools/codegenerator/Helper.groovy ++++ a/tools/codegenerator/Helper.groovy +@@ -18,7 +18,6 @@ + * + */ + +-import groovy.xml.XmlParser + import groovy.xml.XmlUtil + import org.apache.commons.lang.StringEscapeUtils + +diff --git b/tools/codegenerator/SwigTypeParser.groovy a/tools/codegenerator/SwigTypeParser.groovy +index 24dfa8f8ab..ab4e5292f9 100644 +--- b/tools/codegenerator/SwigTypeParser.groovy ++++ a/tools/codegenerator/SwigTypeParser.groovy +@@ -18,8 +18,6 @@ + * + */ + +-import groovy.xml.XmlParser +- + /** + * These methods are somewhat ugly because they have been copied out of + * the Swig source code and simply made compilable with groovy. They could +-- +2.35.1 + + +From b99c39bee1c12d4471959c4854927a60f5dc4393 Mon Sep 17 00:00:00 2001 +From: Jose Luis Marti <joseluis.marti@gmail.com> +Date: Sun, 23 Oct 2022 23:46:38 +0200 +Subject: [PATCH 1/2] delete imports that were unnecessary + +--- + tools/codegenerator/Generator.groovy | 1 + + tools/codegenerator/Helper.groovy | 1 + + 2 files changed, 2 insertions(+) + +diff --git b/tools/codegenerator/Generator.groovy a/tools/codegenerator/Generator.groovy +index 53cf7864f9..305fb0a94b 100644 +--- b/tools/codegenerator/Generator.groovy ++++ a/tools/codegenerator/Generator.groovy +@@ -18,6 +18,7 @@ + * + */ + ++import groovy.util.Node + import groovy.text.SimpleTemplateEngine + import groovy.xml.XmlUtil + +diff --git b/tools/codegenerator/Helper.groovy a/tools/codegenerator/Helper.groovy +index 6324e537e1..764e6c83a9 100644 +--- b/tools/codegenerator/Helper.groovy ++++ a/tools/codegenerator/Helper.groovy +@@ -21,6 +21,7 @@ + import groovy.xml.XmlUtil + import org.apache.commons.lang.StringEscapeUtils + ++import groovy.text.SimpleTemplateEngine + import groovy.text.SimpleTemplateEngine + import java.util.regex.Pattern + +-- +2.35.1 diff --git a/debian/patches/kodi/0005-fix-tests.patch b/debian/patches/kodi/0005-fix-tests.patch new file mode 100644 index 0000000..4099ced --- /dev/null +++ b/debian/patches/kodi/0005-fix-tests.patch @@ -0,0 +1,28 @@ +From 239e1d72ebe9c2a8c3cd890b443317877f04d42b Mon Sep 17 00:00:00 2001 +From: Debian Multimedia Maintainers <debian-multimedia@lists.debian.org> +Date: Tue, 3 Mar 2020 23:56:07 +0100 +Subject: [PATCH] fix-tests +Forwarded: not-needed + +--- + xbmc/utils/test/TestSystemInfo.cpp | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/xbmc/utils/test/TestSystemInfo.cpp b/xbmc/utils/test/TestSystemInfo.cpp +index 1145aa4..7b5f00d 100644 +--- a/xbmc/utils/test/TestSystemInfo.cpp ++++ b/xbmc/utils/test/TestSystemInfo.cpp +@@ -73,8 +73,8 @@ TEST_F(TestSystemInfo, GetKernelName) + TEST_F(TestSystemInfo, GetKernelVersionFull) + { + EXPECT_FALSE(g_sysinfo.GetKernelVersionFull().empty()) << "'GetKernelVersionFull()' must not return empty string"; +- EXPECT_STRNE("0.0.0", g_sysinfo.GetKernelVersionFull().c_str()) << "'GetKernelVersionFull()' must not return '0.0.0'"; +- EXPECT_STRNE("0.0", g_sysinfo.GetKernelVersionFull().c_str()) << "'GetKernelVersionFull()' must not return '0.0'"; ++ // EXPECT_STRNE("0.0.0", g_sysinfo.GetKernelVersionFull().c_str()) << "'GetKernelVersionFull()' must not return '0.0.0'"; ++ // EXPECT_STRNE("0.0", g_sysinfo.GetKernelVersionFull().c_str()) << "'GetKernelVersionFull()' must not return '0.0'"; + EXPECT_EQ(0U, g_sysinfo.GetKernelVersionFull().find_first_of("0123456789")) << "'GetKernelVersionFull()' must not return version not starting from digit"; + } + +-- +2.20.1 + diff --git a/debian/patches/kodi/0006-dont-use-openssl.patch b/debian/patches/kodi/0006-dont-use-openssl.patch new file mode 100644 index 0000000..012f187 --- /dev/null +++ b/debian/patches/kodi/0006-dont-use-openssl.patch @@ -0,0 +1,29 @@ +From 7eda44dad7fc5964d934c73612bb3c2a7001c26f Mon Sep 17 00:00:00 2001 +From: Debian Multimedia Maintainers <debian-multimedia@lists.debian.org> +Date: Tue, 3 Mar 2020 23:56:07 +0100 +Subject: [PATCH] dont-use-openssl +Forwarded: not-needed + +--- + CMakeLists.txt | 2 +- + xbmc/utils/CryptThreading.cpp | 2 +- + xbmc/utils/CryptThreading.h | 4 +--- + xbmc/utils/test/TestCryptThreading.cpp | 2 +- + 4 files changed, 4 insertions(+), 6 deletions(-) + +diff --git a/CMakeLists.txt b/CMakeLists.txt +index f20909a..400707d 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -141,7 +141,7 @@ + LibDvd + Libgcrypt + Lzo2 +- OpenSSL>=1.1.0 ++# OpenSSL>=1.1.0 + PCRE + RapidJSON + Spdlog +-- +2.20.1 + diff --git a/debian/patches/kodi/0007-support-omitting-addons-service.patch b/debian/patches/kodi/0007-support-omitting-addons-service.patch new file mode 100644 index 0000000..c63e58f --- /dev/null +++ b/debian/patches/kodi/0007-support-omitting-addons-service.patch @@ -0,0 +1,27 @@ +From: Jonas Smedegaard <dr@jones.dk> +Date: Tue, 3 Mar 2020 23:56:07 +0100 +Subject: Support omitting addons repository feed +Forwarded: not-needed +Last-Update: 2017-10-03 + +Upstream official addon repository feed contain non-free addons. + +Extending the system at runtime is arguably an anti-feature - +either for political reasons or due to security risks. + +This patch makes it possible to omit the addons repository feed. +--- + system/addon-manifest.xml | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/system/addon-manifest.xml ++++ b/system/addon-manifest.xml +@@ -37,7 +37,7 @@ + <addon>metadata.local</addon> + <addon>metadata.themoviedb.org.python</addon> + <addon>metadata.tvshows.themoviedb.org.python</addon> +- <addon>repository.xbmc.org</addon> ++ <addon optional="true">repository.xbmc.org</addon> + <addon>resource.images.weathericons.default</addon> + <addon>resource.language.en_gb</addon> + <addon>resource.uisounds.kodi</addon> diff --git a/debian/patches/kodi/0008-Find-test-fixtures-in-source-directory.patch b/debian/patches/kodi/0008-Find-test-fixtures-in-source-directory.patch new file mode 100644 index 0000000..9c22ab0 --- /dev/null +++ b/debian/patches/kodi/0008-Find-test-fixtures-in-source-directory.patch @@ -0,0 +1,22 @@ +From: Balint Reczey <balint.reczey@canonical.com> +Date: Thu, 5 Mar 2020 16:14:33 +0100 +Subject: Find test fixtures in source directory +Forwarded: not-needed + +--- + xbmc/test/TestUtils.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/xbmc/test/TestUtils.h b/xbmc/test/TestUtils.h +index b0dbcf6..0e46579 100644 +--- a/xbmc/test/TestUtils.h ++++ b/xbmc/test/TestUtils.h +@@ -94,7 +94,7 @@ private: + double probability; + }; + +-#define XBMC_REF_FILE_PATH(s) CXBMCTestUtils::Instance().ReferenceFilePath(s) ++#define XBMC_REF_FILE_PATH(s) std::string("../" s) + #define XBMC_CREATETEMPFILE(a) CXBMCTestUtils::Instance().CreateTempFile(a) + #define XBMC_DELETETEMPFILE(a) CXBMCTestUtils::Instance().DeleteTempFile(a) + #define XBMC_TEMPFILEPATH(a) CXBMCTestUtils::Instance().TempFilePath(a) diff --git a/debian/patches/kodi/0009-Skip-long-time-broken-test.patch b/debian/patches/kodi/0009-Skip-long-time-broken-test.patch new file mode 100644 index 0000000..eadf33f --- /dev/null +++ b/debian/patches/kodi/0009-Skip-long-time-broken-test.patch @@ -0,0 +1,23 @@ +From: Balint Reczey <balint.reczey@canonical.com> +Date: Thu, 5 Mar 2020 19:27:51 +0100 +Subject: Skip long time broken test +Forwarded: not-needed + +--- + xbmc/network/test/TestWebServer.cpp | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/xbmc/network/test/TestWebServer.cpp b/xbmc/network/test/TestWebServer.cpp +index a87d9f4..3a4e9e2 100644 +--- a/xbmc/network/test/TestWebServer.cpp ++++ b/xbmc/network/test/TestWebServer.cpp +@@ -155,7 +155,8 @@ + // Must be only one "Content-Length" header + ASSERT_EQ(1U, httpHeader.GetValues(MHD_HTTP_HEADER_CONTENT_LENGTH).size()); + // Content-Length must be "4" +- EXPECT_STREQ("4", httpHeader.GetValue(MHD_HTTP_HEADER_CONTENT_LENGTH).c_str()); ++ // FIXME it is "0" actually ++ // EXPECT_STREQ("4", httpHeader.GetValue(MHD_HTTP_HEADER_CONTENT_LENGTH).c_str()); + // Accept-Ranges must be "bytes" + EXPECT_STREQ("bytes", httpHeader.GetValue(MHD_HTTP_HEADER_ACCEPT_RANGES).c_str()); + diff --git a/debian/patches/kodi/0010-Disable-flaky-TestMassEvent.General-and-TestMassEven.patch b/debian/patches/kodi/0010-Disable-flaky-TestMassEvent.General-and-TestMassEven.patch new file mode 100644 index 0000000..7572210 --- /dev/null +++ b/debian/patches/kodi/0010-Disable-flaky-TestMassEvent.General-and-TestMassEven.patch @@ -0,0 +1,31 @@ +From: Balint Reczey <balint.reczey@canonical.com> +Date: Sat, 7 Mar 2020 20:31:55 +0100 +Subject: Disable flaky TestMassEvent.General and TestMassEvent.Polling tests +Forwarded: not-needed + +--- + xbmc/threads/test/TestEvent.cpp | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/xbmc/threads/test/TestEvent.cpp b/xbmc/threads/test/TestEvent.cpp +index 1e3bb93..3293ca8 100644 +--- a/xbmc/threads/test/TestEvent.cpp ++++ b/xbmc/threads/test/TestEvent.cpp +@@ -593,7 +593,7 @@ template <class W> void RunMassEventTest(std::vector<std::shared_ptr<W>>& m, boo + } + + +-TEST(TestMassEvent, General) ++TEST(DISABLED_TestMassEvent, General) + { + g_event = new CEvent(); + +@@ -605,7 +605,7 @@ TEST(TestMassEvent, General) + delete g_event; + } + +-TEST(TestMassEvent, Polling) ++TEST(DISABLED_TestMassEvent, Polling) + { + g_event = new CEvent(true); // polling needs to avoid the auto-reset + diff --git a/debian/patches/kodi/0011-Skip-checking-errno-against-ENOENT-because-this-test.patch b/debian/patches/kodi/0011-Skip-checking-errno-against-ENOENT-because-this-test.patch new file mode 100644 index 0000000..8f6d155 --- /dev/null +++ b/debian/patches/kodi/0011-Skip-checking-errno-against-ENOENT-because-this-test.patch @@ -0,0 +1,22 @@ +From: Balint Reczey <balint.reczey@canonical.com> +Date: Tue, 17 Mar 2020 08:19:53 +0100 +Subject: Skip checking errno against ENOENT because this test fails on armhf +Forwarded: not-needed + +--- + xbmc/filesystem/test/TestFile.cpp | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/xbmc/filesystem/test/TestFile.cpp b/xbmc/filesystem/test/TestFile.cpp +index 898bdf9..d5f7a17 100644 +--- a/xbmc/filesystem/test/TestFile.cpp ++++ b/xbmc/filesystem/test/TestFile.cpp +@@ -133,7 +133,7 @@ TEST(TestFile, Stat) + file->Close(); + EXPECT_NE(0U, buffer.st_mode | _S_IFREG); + EXPECT_EQ(-1, XFILE::CFile::Stat("", &buffer)); +- EXPECT_EQ(ENOENT, errno); ++ // EXPECT_EQ(ENOENT, errno); + EXPECT_TRUE(XBMC_DELETETEMPFILE(file)); + } + diff --git a/debian/patches/kodi/0012-The-baseline-of-the-i386-port-does-not-include-SSE.patch b/debian/patches/kodi/0012-The-baseline-of-the-i386-port-does-not-include-SSE.patch new file mode 100644 index 0000000..fc0d6f9 --- /dev/null +++ b/debian/patches/kodi/0012-The-baseline-of-the-i386-port-does-not-include-SSE.patch @@ -0,0 +1,96 @@ +From 93dd546db947f872f337d25038de60e6bc939440 Mon Sep 17 00:00:00 2001 +From: Adrian Bunk <bunk@debian.org> +Date: Sat, 30 May 2020 21:50:37 +0200 +Subject: [PATCH] The baseline of the i386 port does not include SSE + +SSE2 is always enabled on amd64. +--- + cmake/scripts/linux/ArchSetup.cmake | 2 +- + xbmc/cores/AudioEngine/CMakeLists.txt | 16 ++++++++-------- + xbmc/rendering/CMakeLists.txt | 16 ++++++++-------- + xbmc/utils/CMakeLists.txt | 10 +++++----- + 4 files changed, 22 insertions(+), 22 deletions(-) + +diff --git a/cmake/scripts/linux/ArchSetup.cmake b/cmake/scripts/linux/ArchSetup.cmake +index d3ad51a7..c02ac4a1 100644 +--- a/cmake/scripts/linux/ArchSetup.cmake ++++ b/cmake/scripts/linux/ArchSetup.cmake +@@ -18,7 +18,7 @@ else() + elseif(CPU MATCHES "i.86") + set(ARCH i486-linux) + set(NEON False) +- add_options(CXX ALL_BUILDS "-msse") ++ #add_options(CXX ALL_BUILDS "-msse") + elseif(CPU STREQUAL arm1176jzf-s) + set(ARCH arm) + set(NEON False) +diff --git a/xbmc/cores/AudioEngine/CMakeLists.txt b/xbmc/cores/AudioEngine/CMakeLists.txt +index c5d4d978..f5ad9a47 100644 +--- a/xbmc/cores/AudioEngine/CMakeLists.txt ++++ b/xbmc/cores/AudioEngine/CMakeLists.txt +@@ -156,11 +156,11 @@ endif() + + core_add_library(audioengine) + target_include_directories(${CORE_LIBRARY} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) +-if(NOT CORE_SYSTEM_NAME STREQUAL windows AND NOT CORE_SYSTEM_NAME STREQUAL windowsstore) +- if(HAVE_SSE) +- target_compile_options(${CORE_LIBRARY} PRIVATE -msse) +- endif() +- if(HAVE_SSE2) +- target_compile_options(${CORE_LIBRARY} PRIVATE -msse2) +- endif() +-endif() ++#if(NOT CORE_SYSTEM_NAME STREQUAL windows AND NOT CORE_SYSTEM_NAME STREQUAL windowsstore) ++# if(HAVE_SSE) ++# target_compile_options(${CORE_LIBRARY} PRIVATE -msse) ++# endif() ++# if(HAVE_SSE2) ++# target_compile_options(${CORE_LIBRARY} PRIVATE -msse2) ++# endif() ++#endif() +diff --git a/xbmc/rendering/CMakeLists.txt b/xbmc/rendering/CMakeLists.txt +index c212a962..aa999703 100644 +--- a/xbmc/rendering/CMakeLists.txt ++++ b/xbmc/rendering/CMakeLists.txt +@@ -16,12 +16,12 @@ if(OPENGL_FOUND OR OPENGLES_FOUND) + endif() + + core_add_library(rendering) +-if(NOT CORE_SYSTEM_NAME STREQUAL windows AND NOT CORE_SYSTEM_NAME STREQUAL windowsstore) +- if(HAVE_SSE) +- target_compile_options(${CORE_LIBRARY} PRIVATE -msse) +- endif() +- if(HAVE_SSE2) +- target_compile_options(${CORE_LIBRARY} PRIVATE -msse2) +- endif() +-endif() ++#if(NOT CORE_SYSTEM_NAME STREQUAL windows AND NOT CORE_SYSTEM_NAME STREQUAL windowsstore) ++# if(HAVE_SSE) ++# target_compile_options(${CORE_LIBRARY} PRIVATE -msse) ++# endif() ++# if(HAVE_SSE2) ++# target_compile_options(${CORE_LIBRARY} PRIVATE -msse2) ++# endif() ++#endif() + +diff --git a/xbmc/utils/CMakeLists.txt b/xbmc/utils/CMakeLists.txt +index 904b5cc9..48406633 100644 +--- a/xbmc/utils/CMakeLists.txt ++++ b/xbmc/utils/CMakeLists.txt +@@ -232,8 +232,8 @@ endif() + + core_add_library(utils) + +-if(NOT CORE_SYSTEM_NAME STREQUAL windows AND NOT CORE_SYSTEM_NAME STREQUAL windowsstore) +- if(HAVE_SSE2) +- target_compile_options(${CORE_LIBRARY} PRIVATE -msse2) +- endif() +-endif() ++#if(NOT CORE_SYSTEM_NAME STREQUAL windows AND NOT CORE_SYSTEM_NAME STREQUAL windowsstore) ++# if(HAVE_SSE2) ++# target_compile_options(${CORE_LIBRARY} PRIVATE -msse2) ++# endif() ++#endif() +-- +2.35.1 + diff --git a/debian/patches/kodi/0013-Disable-GetCPUFrequency-test.patch b/debian/patches/kodi/0013-Disable-GetCPUFrequency-test.patch new file mode 100644 index 0000000..fe06a92 --- /dev/null +++ b/debian/patches/kodi/0013-Disable-GetCPUFrequency-test.patch @@ -0,0 +1,22 @@ +From: Vasyl Gello <vasek.gello@gmail.com> +Date: Mon, 02 Nov 2020 08:05:00 +0200 +Subject: Disable TestCPUInfo.GetCPUFrequency test +Origin: vendor +Forwarded: not-needed + +Fixes test failure on many architectures, like s390x. +See #970236 for example. + +--- + +--- a/xbmc/utils/test/TestCPUInfo.cpp ++++ b/xbmc/utils/test/TestCPUInfo.cpp +@@ -36,7 +36,7 @@ + EXPECT_GT(CServiceBroker::GetCPUInfo()->GetCPUCount(), 0); + } + +-TEST_F(TestCPUInfo, GetCPUFrequency) ++TEST_F(TestCPUInfo, DISABLED_GetCPUFrequency) + { + EXPECT_GE(CServiceBroker::GetCPUInfo()->GetCPUFrequency(), 0.f); + } diff --git a/debian/patches/kodi/0014-Fix-C++-example-includes.patch b/debian/patches/kodi/0014-Fix-C++-example-includes.patch new file mode 100644 index 0000000..a37339c --- /dev/null +++ b/debian/patches/kodi/0014-Fix-C++-example-includes.patch @@ -0,0 +1,52 @@ +From: Vasyl Gello <vaek.gello@gmail.com> +Date: Mon, 16 Nov 2020 20:20:00 +0200 +Subject: Fix C++ example includes +Forwarded: not-needed + +--- + +--- a/tools/EventClients/examples/c++/example_button1.cpp ++++ b/tools/EventClients/examples/c++/example_button1.cpp +@@ -1,4 +1,5 @@ +-#include "../../lib/c++/xbmcclient.h" ++#include <kodi/xbmcclient.h> ++ + #include <stdio.h> + #include <string.h> + #include <sys/socket.h> +--- a/tools/EventClients/examples/c++/example_button2.cpp ++++ b/tools/EventClients/examples/c++/example_button2.cpp +@@ -1,4 +1,5 @@ +-#include "../../lib/c++/xbmcclient.h" ++#include <kodi/xbmcclient.h> ++ + #include <stdio.h> + #include <string.h> + #include <sys/socket.h> +--- a/tools/EventClients/examples/c++/example_log.cpp ++++ b/tools/EventClients/examples/c++/example_log.cpp +@@ -1,4 +1,5 @@ +-#include "../../lib/c++/xbmcclient.h" ++#include <kodi/xbmcclient.h> ++ + #include <stdio.h> + #include <string.h> + #include <sys/socket.h> +--- a/tools/EventClients/examples/c++/example_mouse.cpp ++++ b/tools/EventClients/examples/c++/example_mouse.cpp +@@ -1,4 +1,5 @@ +-#include "../../lib/c++/xbmcclient.h" ++#include <kodi/xbmcclient.h> ++ + #include <stdio.h> + #include <string.h> + #include <sys/socket.h> +--- a/tools/EventClients/examples/c++/example_notification.cpp ++++ b/tools/EventClients/examples/c++/example_notification.cpp +@@ -1,4 +1,5 @@ +-#include "../../lib/c++/xbmcclient.h" ++#include <kodi/xbmcclient.h> ++ + #include <stdio.h> + #include <string.h> + #include <sys/socket.h> diff --git a/debian/patches/kodi/0015-debian-cross-compile.patch b/debian/patches/kodi/0015-debian-cross-compile.patch new file mode 100644 index 0000000..6d315bc --- /dev/null +++ b/debian/patches/kodi/0015-debian-cross-compile.patch @@ -0,0 +1,33 @@ +Author: Vasyl Gello <vasek.gello@gmail.com> +Last-Updated: 2021-10-30 +Forwarded: not-needed +Subject: Patch native dependencies for cross-compiling + + * Don't build TexturePacker statically - it breaks fakeroot + +--- + +diff --git a/tools/depends/native/TexturePacker/Makefile b/tools/depends/native/TexturePacker/Makefile +index f50dc879..9ba9da48 100644 +--- a/tools/depends/native/TexturePacker/Makefile ++++ b/tools/depends/native/TexturePacker/Makefile +@@ -10,15 +10,15 @@ endif + + ifeq ($(NATIVEPLATFORM),) + PLATFORM = native +- EXTRA_CONFIGURE = --enable-static ++# EXTRA_CONFIGURE = --enable-static + else + PLATFORM = $(NATIVEPLATFORM) + DEPS += ../../Makefile.include + endif + +-ifeq ($(NATIVE_OS), linux) +- EXTRA_CONFIGURE = --enable-static +-endif ++#ifeq ($(NATIVE_OS), linux) ++# EXTRA_CONFIGURE = --enable-static ++#endif + ifeq ($(NATIVE_OS), android) + EXTRA_CONFIGURE = --enable-static + endif diff --git a/debian/patches/kodi/0016-ports-architectures.patch b/debian/patches/kodi/0016-ports-architectures.patch new file mode 100644 index 0000000..6595d31 --- /dev/null +++ b/debian/patches/kodi/0016-ports-architectures.patch @@ -0,0 +1,132 @@ +From 5627432b717cf7df565c30490400ef11efa016e0 Mon Sep 17 00:00:00 2001 +From: Vasyl Gello <vasek.gello@gmail.com> +Date: Fri, 30 Dec 2022 14:39:36 +0200 +Subject: [PATCH] Introduce buildable Debian ports architectures + +Tested by building against sid/ppc64 and running via +xvfb + x11vnc. + +Signed-off-by: Vasyl Gello <vasek.gello@gmail.com> +--- + cmake/scripts/linux/ArchSetup.cmake | 18 ++++++++++++++++++ + xbmc/cores/DllLoader/DllLoader.h | 1 + + xbmc/cores/DllLoader/ldt_keeper.c | 1 + + xbmc/utils/MathUtils.h | 1 + + xbmc/utils/SystemInfo.cpp | 19 ++++++++++++++++++- + 5 files changed, 39 insertions(+), 1 deletion(-) + +diff --git a/cmake/scripts/linux/ArchSetup.cmake b/cmake/scripts/linux/ArchSetup.cmake +index 4083483173..917d8f06a4 100644 +--- a/cmake/scripts/linux/ArchSetup.cmake ++++ b/cmake/scripts/linux/ArchSetup.cmake +@@ -40,9 +40,27 @@ else() + elseif(CPU MATCHES riscv64) + set(ARCH riscv64) + set(NEON False) ++ elseif(CPU MATCHES ppc) ++ set(ARCH ppc) ++ set(NEON False) ++ elseif(CPU MATCHES ppc64) ++ set(ARCH ppc64) ++ set(NEON False) + elseif(CPU MATCHES ppc64le) + set(ARCH ppc64le) + set(NEON False) ++ elseif(CPU MATCHES m68k) ++ set(ARCH m68k) ++ set(NEON False) ++ elseif(CPU MATCHES sh4) ++ set(ARCH sh4) ++ set(NEON False) ++ elseif(CPU MATCHES sparc64) ++ set(ARCH sparc64) ++ set(NEON False) ++ elseif(CPU MATCHES alpha) ++ set(ARCH alpha) ++ set(NEON False) + elseif(CPU MATCHES loongarch64) + set(ARCH loongarch64) + set(NEON False) +diff --git a/xbmc/cores/DllLoader/DllLoader.h b/xbmc/cores/DllLoader/DllLoader.h +index 79e019d0e3..216c2dd067 100644 +--- a/xbmc/cores/DllLoader/DllLoader.h ++++ b/xbmc/cores/DllLoader/DllLoader.h +@@ -18,6 +18,7 @@ + !defined(__arc__) && \ + !defined(__arm__) && \ + !defined(__loongarch__) && \ ++ !defined(__m68k__) && \ + !defined(__mips__) && \ + !defined(__powerpc__) && \ + !defined(__or1k__) && \ +diff --git a/xbmc/cores/DllLoader/ldt_keeper.c b/xbmc/cores/DllLoader/ldt_keeper.c +index 325d50cb70..01e2e9ad61 100644 +--- a/xbmc/cores/DllLoader/ldt_keeper.c ++++ b/xbmc/cores/DllLoader/ldt_keeper.c +@@ -24,6 +24,7 @@ + !defined(__arc__) &&\ + !defined(__arm__) && \ + !defined(__loongarch__) && \ ++ !defined(__m68k__) && \ + !defined(__mips__) && \ + !defined(__or1k__) && \ + !defined(__powerpc__) && \ +diff --git a/xbmc/utils/MathUtils.h b/xbmc/utils/MathUtils.h +index 2b1dbcc51f..62301deef9 100644 +--- a/xbmc/utils/MathUtils.h ++++ b/xbmc/utils/MathUtils.h +@@ -29,6 +29,7 @@ + defined(__arm__) || \ + defined(__loongarch__) || \ + defined(_M_ARM) || \ ++ defined(__m68k__) || \ + defined(__mips__) || \ + defined(__or1k__) || \ + defined(__powerpc__) || \ +diff --git a/xbmc/utils/SystemInfo.cpp b/xbmc/utils/SystemInfo.cpp +index 6e4c1ff2a9..e3da06d70e 100644 +--- a/xbmc/utils/SystemInfo.cpp ++++ b/xbmc/utils/SystemInfo.cpp +@@ -933,7 +933,8 @@ int CSysInfo::GetKernelBitness(void) + std::string machine(un.machine); + if (machine == "x86_64" || machine == "amd64" || machine == "arm64" || machine == "aarch64" || + machine == "ppc64" || machine == "ppc64el" || machine == "ppc64le" || machine == "ia64" || +- machine == "mips64" || machine == "s390x" || machine == "riscv64") ++ machine == "mips64" || machine == "s390x" || machine == "riscv64" || ++ machine == "sparc64" || machine == "alpha") + kernelBitness = 64; + else + kernelBitness = 32; +@@ -990,6 +991,14 @@ const std::string& CSysInfo::GetKernelCpuFamily(void) + kernelCpuFamily = "PowerPC"; + else if (machine.compare(0, 5, "riscv", 5) == 0) + kernelCpuFamily = "RISC-V"; ++ else if (machine.compare(0, 4, "m68k", 4) == 0) ++ kernelCpuFamily = "m68k"; ++ else if (machine.compare(0, 3, "sh4", 3) == 0) ++ kernelCpuFamily = "sh4"; ++ else if (machine.compare(0, 7, "sparc64", 7) == 0) ++ kernelCpuFamily = "SPARC"; ++ else if (machine.compare(0, 5, "alpha", 5) == 0) ++ kernelCpuFamily = "alpha"; + } + #endif + if (kernelCpuFamily.empty()) +@@ -1373,6 +1382,14 @@ std::string CSysInfo::GetBuildTargetCpuFamily(void) + return "PowerPC"; + #elif defined(__riscv) + return "RISC-V"; ++#elif defined(__m68k__) ++ return "m68k"; ++#elif defined(__SH4__) ++ return "sh4"; ++#elif defined(__sparc__) ++ return "SPARC"; ++#elif defined(__alpha__) ++ return "alpha"; + #else + return "unknown CPU family"; + #endif +-- +2.39.0 + diff --git a/debian/patches/libdvdnav/0001-libdvdnav-PR48-enen92.patch b/debian/patches/libdvdnav/0001-libdvdnav-PR48-enen92.patch new file mode 100644 index 0000000..17ae1fa --- /dev/null +++ b/debian/patches/libdvdnav/0001-libdvdnav-PR48-enen92.patch @@ -0,0 +1,184 @@ +From 3984a232ae432fc9aca028a980139d12b087b32e Mon Sep 17 00:00:00 2001 +From: Miguel Borges de Freitas <enen92@kodi.tv> +Date: Tue, 26 Jul 2022 18:20:50 +0100 +Subject: [PATCH] dvdnav_open_files implementation + +Attempts to open files given that the calling application provides the dvd_reader_filesystem implementation +and the path to the file. Supports logging callbacks similarly to other dvdnav_open methods. +Useful for opening files located on a virtual file system (vfs) such as smb, nfs, etc +--- + libdvdnav-embedded/src/dvdnav.c | 21 ++++++++++++++------- + libdvdnav-embedded/src/dvdnav/dvdnav.h | 12 ++++++++++++ + libdvdnav-embedded/src/vm/vm.c | 9 ++++++--- + libdvdnav-embedded/src/vm/vm.h | 3 ++- + 4 files changed, 34 insertions(+), 11 deletions(-) + +diff --git a/libdvdnav-embedded/src/dvdnav.c b/libdvdnav-embedded/src/dvdnav.c +index 4ef7d1a..b180b18 100644 +--- a/libdvdnav-embedded/src/dvdnav.c ++++ b/libdvdnav-embedded/src/dvdnav.c +@@ -151,7 +151,8 @@ dvdnav_status_t dvdnav_free_dup(dvdnav_t *this) { + static dvdnav_status_t dvdnav_open_common(dvdnav_t** dest, + void *priv, const dvdnav_logger_cb *logcb, + const char *path, +- dvdnav_stream_cb *stream_cb) { ++ dvdnav_stream_cb *stream_cb, ++ dvdnav_filesystem_h *fs) { + dvdnav_t *this; + struct timeval time; + +@@ -174,7 +175,7 @@ static dvdnav_status_t dvdnav_open_common(dvdnav_t** dest, + if(!this->vm) { + goto fail; + } +- if(!vm_reset(this->vm, path, priv, stream_cb)) { ++ if(!vm_reset(this->vm, path, priv, stream_cb, fs)) { + goto fail; + } + +@@ -213,24 +214,30 @@ fail: + } + + dvdnav_status_t dvdnav_open(dvdnav_t** dest, const char *path) { +- return dvdnav_open_common(dest, NULL, NULL, path, NULL); ++ return dvdnav_open_common(dest, NULL, NULL, path, NULL, NULL); + } + + dvdnav_status_t dvdnav_open2(dvdnav_t** dest, + void *priv,const dvdnav_logger_cb *logcb, + const char *path) { +- return dvdnav_open_common(dest, priv, logcb, path, NULL); ++ return dvdnav_open_common(dest, priv, logcb, path, NULL, NULL); + } + + dvdnav_status_t dvdnav_open_stream(dvdnav_t** dest, + void *priv, dvdnav_stream_cb *stream_cb) { +- return dvdnav_open_common(dest, priv, NULL, NULL, stream_cb); ++ return dvdnav_open_common(dest, priv, NULL, NULL, stream_cb, NULL); + } + + dvdnav_status_t dvdnav_open_stream2(dvdnav_t** dest, + void *priv,const dvdnav_logger_cb *logcb, + dvdnav_stream_cb *stream_cb) { +- return dvdnav_open_common(dest, priv, logcb, NULL, stream_cb); ++ return dvdnav_open_common(dest, priv, logcb, NULL, stream_cb, NULL); ++} ++ ++dvdnav_status_t dvdnav_open_files(dvdnav_t** dest, ++ void *priv, const dvdnav_logger_cb *logcb, ++ const char *path, dvdnav_filesystem_h *fs) { ++ return dvdnav_open_common(dest, priv, logcb, path, NULL, fs); + } + + dvdnav_status_t dvdnav_close(dvdnav_t *this) { +@@ -280,7 +287,7 @@ dvdnav_status_t dvdnav_reset(dvdnav_t *this) { + #ifdef LOG_DEBUG + Log3(this, "resetting vm"); + #endif +- if(!vm_reset(this->vm, NULL, NULL, NULL)) { ++ if(!vm_reset(this->vm, NULL, NULL, NULL, NULL)) { + printerr("Error restarting the VM."); + pthread_mutex_unlock(&this->vm_lock); + return DVDNAV_STATUS_ERR; +diff --git a/libdvdnav-embedded/src/dvdnav/dvdnav.h b/libdvdnav-embedded/src/dvdnav/dvdnav.h +index 85136a4..ebb3751 100644 +--- a/libdvdnav-embedded/src/dvdnav/dvdnav.h ++++ b/libdvdnav-embedded/src/dvdnav/dvdnav.h +@@ -32,6 +32,7 @@ extern "C" { + + #include "version.h" + #include <dvdnav/dvd_types.h> ++#include <dvdread/dvd_filesystem.h> + #include <dvdread/dvd_reader.h> + #include <dvdread/nav_types.h> + #include <dvdnav/dvdnav_events.h> +@@ -55,6 +56,8 @@ typedef int32_t dvdnav_status_t; + + typedef dvd_reader_stream_cb dvdnav_stream_cb; + ++typedef dvd_reader_filesystem_h dvdnav_filesystem_h; ++ + /* + * Unless otherwise stated, all functions return DVDNAV_STATUS_OK if + * they succeeded, otherwise DVDNAV_STATUS_ERR is returned and the error may +@@ -110,6 +113,15 @@ dvdnav_status_t dvdnav_open_stream2(dvdnav_t **dest, + void *priv, const dvdnav_logger_cb *, + dvdnav_stream_cb *stream_cb); + ++/* ++ * Attempts to open files given that the calling application provides the dvd_reader_filesystem implementation ++ * and the path to the file. Supports logging callbacks similarly to other dvdnav_open methods. ++ * Useful for opening files located on a virtual file system (vfs) such as smb, nfs, etc ++ */ ++dvdnav_status_t dvdnav_open_files(dvdnav_t **dest, ++ void *priv, const dvdnav_logger_cb *, ++ const char *path, dvdnav_filesystem_h *fs); ++ + dvdnav_status_t dvdnav_dup(dvdnav_t **dest, dvdnav_t *src); + dvdnav_status_t dvdnav_free_dup(dvdnav_t * _this); + +diff --git a/libdvdnav-embedded/src/vm/vm.c b/libdvdnav-embedded/src/vm/vm.c +index 9276c91..23c187b 100644 +--- a/libdvdnav-embedded/src/vm/vm.c ++++ b/libdvdnav-embedded/src/vm/vm.c +@@ -334,7 +334,7 @@ dvd_reader_t *vm_get_dvd_reader(vm_t *vm) { + + int vm_start(vm_t *vm) { + if (vm->stopped) { +- if (!vm_reset(vm, NULL, NULL, NULL)) ++ if (!vm_reset(vm, NULL, NULL, NULL, NULL)) + return 0; + + vm->stopped = 0; +@@ -368,7 +368,7 @@ static void vm_close(vm_t *vm) { + } + + int vm_reset(vm_t *vm, const char *dvdroot, +- void *priv, dvdnav_stream_cb *stream_cb) { ++ void *priv, dvdnav_stream_cb *stream_cb, dvdnav_filesystem_h *fs) { + /* Setup State */ + memset(vm->state.registers.SPRM, 0, sizeof(vm->state.registers.SPRM)); + memset(vm->state.registers.GPRM, 0, sizeof(vm->state.registers.GPRM)); +@@ -410,6 +410,7 @@ int vm_reset(vm_t *vm, const char *dvdroot, + vm->streamcb = *stream_cb; + else + vm->streamcb = (dvdnav_stream_cb) { NULL, NULL, NULL }; ++ vm->dvdreaderfs = fs; + + /* bind local callbacks */ + vm->dvdstreamcb.pf_seek = vm->streamcb.pf_seek ? dvd_reader_seek_handler : NULL; +@@ -426,7 +427,9 @@ int vm_reset(vm_t *vm, const char *dvdroot, + dvd_logger_cb dvdread_logcb = { .pf_log = dvd_reader_logger_handler }; + /* Only install log handler if we have one ourself */ + dvd_logger_cb *p_dvdread_logcb = vm->logcb.pf_log ? &dvdread_logcb : NULL; +- if(dvdroot) ++ if(dvdroot && fs) ++ vm->dvd = DVDOpenFiles(vm, p_dvdread_logcb, dvdroot, vm->dvdreaderfs); ++ else if(dvdroot) + vm->dvd = DVDOpen2(vm, p_dvdread_logcb, dvdroot); + else if(vm->priv && vm->dvdstreamcb.pf_read) + vm->dvd = DVDOpenStream2(vm, p_dvdread_logcb, &vm->dvdstreamcb); +diff --git a/libdvdnav-embedded/src/vm/vm.h b/libdvdnav-embedded/src/vm/vm.h +index bada9f0..e97c6c0 100644 +--- a/libdvdnav-embedded/src/vm/vm.h ++++ b/libdvdnav-embedded/src/vm/vm.h +@@ -72,6 +72,7 @@ typedef struct { + dvdnav_stream_cb streamcb; + dvd_reader_t *dvd; + dvd_reader_stream_cb dvdstreamcb; ++ dvdnav_filesystem_h *dvdreaderfs; + ifo_handle_t *vmgi; + ifo_handle_t *vtsi; + dvd_state_t state; +@@ -119,7 +120,7 @@ dvd_reader_t *vm_get_dvd_reader(vm_t *vm); + int vm_start(vm_t *vm); + void vm_stop(vm_t *vm); + int vm_reset(vm_t *vm, const char *dvdroot, void *priv, +- dvdnav_stream_cb *stream_cb); ++ dvdnav_stream_cb *stream_cb, dvdnav_filesystem_h *fs); + + /* copying and merging - useful for try-running an operation */ + vm_t *vm_new_copy(vm_t *vm); +-- +2.35.1 + diff --git a/debian/patches/libdvdread/0001-libdvdread-PR40-enen92.patch b/debian/patches/libdvdread/0001-libdvdread-PR40-enen92.patch new file mode 100644 index 0000000..f512696 --- /dev/null +++ b/debian/patches/libdvdread/0001-libdvdread-PR40-enen92.patch @@ -0,0 +1,1694 @@ +From 4510e2ab7f85f87f781b59cafb0ad278c9edeb61 Mon Sep 17 00:00:00 2001 +From: Miguel Borges de Freitas <enen92@kodi.tv> +Date: Fri, 17 Jun 2022 09:43:49 +0100 +Subject: [PATCH 1/3] Split filesystem implementation into platform based code + +--- + libdvdread-embedded/Makefile.am | 17 ++- + libdvdread-embedded/configure.ac | 4 + + libdvdread-embedded/src/dvd_input.c | 58 +++------- + libdvdread-embedded/src/dvd_input.h | 23 +--- + libdvdread-embedded/src/dvd_reader.c | 216 ++++++++++------------------------- + libdvdread-embedded/src/dvdread/dvd_filesystem.h | 124 ++++++++++++++++++++ + libdvdread-embedded/src/dvdread/dvd_reader.h | 13 +-- + libdvdread-embedded/src/dvdread_internal.h | 1 + + libdvdread-embedded/src/file/dir_posix.c | 98 ++++++++++++++++ + libdvdread-embedded/src/file/dir_win32.c | 108 ++++++++++++++++++ + libdvdread-embedded/src/file/file_posix.c | 113 ++++++++++++++++++ + libdvdread-embedded/src/file/file_win32.c | 98 ++++++++++++++++ + libdvdread-embedded/src/file/filesystem.c | 37 ++++++ + libdvdread-embedded/src/file/filesystem.h | 46 ++++++++ + libdvdread-embedded/src/file/stat_posix.c | 36 ++++++ + libdvdread-embedded/src/file/stat_win32.c | 53 +++++++++ + 16 files changed, 821 insertions(+), 224 deletions(-) + create mode 100644 libdvdread-embedded/src/dvdread/dvd_filesystem.h + create mode 100644 libdvdread-embedded/src/file/dir_posix.c + create mode 100644 libdvdread-embedded/src/file/dir_win32.c + create mode 100644 libdvdread-embedded/src/file/file_posix.c + create mode 100644 libdvdread-embedded/src/file/file_win32.c + create mode 100644 libdvdread-embedded/src/file/filesystem.c + create mode 100644 libdvdread-embedded/src/file/filesystem.h + create mode 100644 libdvdread-embedded/src/file/stat_posix.c + create mode 100644 libdvdread-embedded/src/file/stat_win32.c + +diff --git a/libdvdread-embedded/Makefile.am b/libdvdread-embedded/Makefile.am +index f2849b8..29dca92 100644 +--- a/libdvdread-embedded/Makefile.am ++++ b/libdvdread-embedded/Makefile.am +@@ -32,7 +32,21 @@ libdvdread_la_SOURCES = \ + src/md5.h \ + src/nav_print.c \ + src/nav_read.c \ +- msvc/contrib/win32_cs.h ++ msvc/contrib/win32_cs.h \ ++ src/file/filesystem.c \ ++ src/file/filesystem.h ++ ++if HAVE_WIN32 ++libdvdread_la_SOURCES+= \ ++ src/file/dir_win32.c \ ++ src/file/file_win32.c \ ++ src/file/stat_win32.c ++else ++libdvdread_la_SOURCES+= \ ++ src/file/dir_posix.c \ ++ src/file/file_posix.c \ ++ src/file/stat_posix.c ++endif + + libdvdread_la_LIBADD = $(CSS_LIBS) + +@@ -42,6 +56,7 @@ libdvdread_la_LDFLAGS = -version-info $(DVDREAD_LTVERSION) \ + pkgincludedir = $(includedir)/dvdread + pkginclude_HEADERS = \ + src/dvdread/bitreader.h \ ++ src/dvdread/dvd_filesystem.h \ + src/dvdread/dvd_reader.h \ + src/dvdread/dvd_udf.h \ + src/dvdread/ifo_print.h \ +diff --git a/libdvdread-embedded/configure.ac b/libdvdread-embedded/configure.ac +index a60ef0c..e3cb5ac 100644 +--- a/libdvdread-embedded/configure.ac ++++ b/libdvdread-embedded/configure.ac +@@ -77,6 +77,9 @@ AC_ARG_ENABLE([dlfcn], + [use_builtin_dlfcn=$enableval], + [use_builtin_dlfcn=no]) + ++# for filesystem/dir access ++AC_CHECK_HEADERS([dirent.h]) ++ + AS_IF([test x"$with_libdvdcss" = "xyes"], [ + CSS_REQUIRES="libdvdcss >= 1.2" + PKG_CHECK_MODULES([CSS], [$CSS_REQUIRES]) +@@ -108,6 +111,7 @@ AS_IF([test "x$DOXYGEN" = "x"], [ + ]) + ]) + AM_CONDITIONAL([APIDOC], [test "x$DOXYGEN" != "x" && test "x$enable_apidoc" = "xyes"]) ++AM_CONDITIONAL(HAVE_WIN32, expr $host : '.*-mingw' >/dev/null 2>&1) + + AS_IF([test "x$ac_cv_c_compiler_gnu" = "xyes"], [ + AC_DEFINE([UNUSED], [__attribute__((unused))], [Unused parameter annotation]) +diff --git a/libdvdread-embedded/src/dvd_input.c b/libdvdread-embedded/src/dvd_input.c +index 17f0d36..1baf8f7 100644 +--- a/libdvdread-embedded/src/dvd_input.c ++++ b/libdvdread-embedded/src/dvd_input.c +@@ -22,16 +22,9 @@ + #include "config.h" /* Required for HAVE_DVDCSS_DVDCSS_H */ + #include <stdio.h> /* fprintf */ + #include <stdlib.h> /* free */ +-#include <fcntl.h> /* open */ +-#include <unistd.h> /* lseek */ + #include <string.h> /* strerror */ + #include <errno.h> + +-#ifdef _WIN32 +-#include <windows.h> +-#include "../msvc/contrib/win32_cs.h" +-#endif +- + #include "dvdread/dvd_reader.h" /* DVD_VIDEO_LB_LEN */ + #include "dvdread_internal.h" + #include "dvd_input.h" +@@ -40,7 +33,8 @@ + + /* The function pointers that is the exported interface of this file. */ + dvd_input_t (*dvdinput_open) (void *, dvd_logger_cb *, +- const char *,dvd_reader_stream_cb *); ++ const char *, dvd_reader_stream_cb *, ++ dvd_reader_filesystem_h *); + int (*dvdinput_close) (dvd_input_t); + int (*dvdinput_seek) (dvd_input_t, int); + int (*dvdinput_title) (dvd_input_t, int); +@@ -77,22 +71,6 @@ static int (*DVDcss_read) (dvdcss_t, void *, int, int); + #define DVDCSS_SEEK_KEY (1 << 1) + #endif + +-#ifdef _WIN32 +-static int open_win32(const char *path, int flags) +-{ +- wchar_t *wpath; +- int fd; +- +- wpath = _utf8_to_wchar(path); +- if (!wpath) { +- return -1; +- } +- fd = _wopen(wpath, flags); +- free(wpath); +- return fd; +-} +-#endif +- + /* The DVDinput handle, add stuff here for new input methods. + * NOTE: All members of this structure must be initialized in dvd_input_New + */ +@@ -104,8 +82,8 @@ struct dvd_input_s { + dvd_logger_cb *logcb; + off_t ipos; + +- /* dummy file input */ +- int fd; ++ /* file input */ ++ dvd_file_h* file; + /* stream input */ + dvd_reader_stream_cb *stream_cb; + }; +@@ -121,7 +99,7 @@ static dvd_input_t dvd_input_New(void *priv, dvd_logger_cb *logcb) + + /* Initialize all inputs to safe defaults */ + dev->dvdcss = NULL; +- dev->fd = -1; ++ dev->file = NULL; + dev->stream_cb = NULL; + } + return dev; +@@ -132,7 +110,8 @@ static dvd_input_t dvd_input_New(void *priv, dvd_logger_cb *logcb) + */ + static dvd_input_t css_open(void *priv, dvd_logger_cb *logcb, + const char *target, +- dvd_reader_stream_cb *stream_cb) ++ dvd_reader_stream_cb *stream_cb, ++ dvd_reader_filesystem_h *fs UNUSED) + { + dvd_input_t dev; + +@@ -210,7 +189,8 @@ static int css_close(dvd_input_t dev) + */ + static dvd_input_t file_open(void *priv, dvd_logger_cb *logcb, + const char *target, +- dvd_reader_stream_cb *stream_cb) ++ dvd_reader_stream_cb *stream_cb, ++ dvd_reader_filesystem_h *fs) + { + dvd_input_t dev; + +@@ -239,14 +219,8 @@ static dvd_input_t file_open(void *priv, dvd_logger_cb *logcb, + free(dev); + return NULL; + } +-#if defined(_WIN32) +- dev->fd = open_win32(target, O_RDONLY | O_BINARY); +-#elif defined(__OS2__) +- dev->fd = open(target, O_RDONLY | O_BINARY); +-#else +- dev->fd = open(target, O_RDONLY); +-#endif +- if(dev->fd < 0) { ++ dev->file = fs->file_open(fs, target); ++ if(!dev->file) { + char buf[256]; + #if defined(HAVE_STRERROR_R) && defined(HAVE_DECL_STRERROR_R) + #ifdef STRERROR_R_CHAR_P +@@ -279,7 +253,7 @@ static dvd_input_t file_open(void *priv, dvd_logger_cb *logcb, + */ + static int file_seek(dvd_input_t dev, int blocks) + { +- off_t pos = -1; ++ int64_t pos = -1; + + if(dev->ipos == blocks) + { +@@ -298,7 +272,7 @@ static int file_seek(dvd_input_t dev, int blocks) + /* Returns position as the number of bytes from beginning of file + * or -1 on error + */ +- pos = lseek(dev->fd, (off_t)blocks * (off_t)DVD_VIDEO_LB_LEN, SEEK_SET); ++ pos = dev->file->seek(dev->file, (int64_t)blocks * (int64_t)DVD_VIDEO_LB_LEN, SEEK_SET); + + if (pos >= 0) { + dev->ipos = pos / DVD_VIDEO_LB_LEN; +@@ -342,7 +316,7 @@ static int file_read(dvd_input_t dev, void *buffer, int blocks, + ret = dev->stream_cb->pf_read(dev->priv, ((char*)buffer) + bytes, len); + } else { + /* Returns the number of bytes read or -1 on error */ +- ret = read(dev->fd, ((char*)buffer) + bytes, len); ++ ret = dev->file->read(dev->file, ((char*)buffer) + bytes, len); + } + + if(ret < 0) { +@@ -381,8 +355,8 @@ static int file_close(dvd_input_t dev) + + /* close file if it was open */ + +- if (dev->fd >= 0) { +- ret = close(dev->fd); ++ if (dev->file) { ++ ret = dev->file->close(dev->file); + } + + free(dev); +diff --git a/libdvdread-embedded/src/dvd_input.h b/libdvdread-embedded/src/dvd_input.h +index 470cfa4..56fe170 100644 +--- a/libdvdread-embedded/src/dvd_input.h ++++ b/libdvdread-embedded/src/dvd_input.h +@@ -31,33 +31,14 @@ + + typedef struct dvd_input_s *dvd_input_t; + +-#if defined( __MINGW32__ ) +-# undef lseek +-# define lseek _lseeki64 +-# undef off_t +-# define off_t off64_t +-# undef stat +-# define stat _stati64 +-# undef fstat +-# define fstat _fstati64 +-# undef wstat +-# define wstat _wstati64 +-#endif +- +-#ifdef __ANDROID__ +-# undef lseek +-# define lseek lseek64 +-# undef off_t +-# define off_t off64_t +-#endif +- + /** + * Function pointers that will be filled in by the input implementation. + * These functions provide the main API. + */ + extern dvd_input_t (*dvdinput_open) (void *, dvd_logger_cb *, + const char *, +- dvd_reader_stream_cb *); ++ dvd_reader_stream_cb *, ++ dvd_reader_filesystem_h *); + extern int (*dvdinput_close) (dvd_input_t); + extern int (*dvdinput_seek) (dvd_input_t, int); + extern int (*dvdinput_title) (dvd_input_t, int); +diff --git a/libdvdread-embedded/src/dvd_reader.c b/libdvdread-embedded/src/dvd_reader.c +index c4d9641..5a21056 100644 +--- a/libdvdread-embedded/src/dvd_reader.c ++++ b/libdvdread-embedded/src/dvd_reader.c +@@ -21,17 +21,13 @@ + */ + + #include "config.h" +-#include <sys/types.h> /* off_t */ +-#include <sys/stat.h> /* stat */ + #include <sys/time.h> /* For the timing of dvdcss_title crack. */ +-#include <fcntl.h> /* open */ + #include <stdlib.h> /* free */ + #include <stdio.h> /* fprintf */ + #include <errno.h> /* errno, EIN* */ + #include <string.h> /* memcpy, strlen */ + #include <unistd.h> /* pclose */ + #include <limits.h> /* PATH_MAX */ +-#include <dirent.h> /* opendir, readdir */ + #include <ctype.h> /* isalpha */ + + #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__bsdi__) || defined(__APPLE__) +@@ -57,11 +53,8 @@ + #include "dvdread_internal.h" + #include "md5.h" + #include "dvdread/ifo_read.h" ++#include "file/filesystem.h" + +-#if defined(_WIN32) +-# include <windows.h> +-# include "msvc/contrib/win32_cs.h" +-#endif + + /* misc win32 helpers */ + +@@ -81,107 +74,6 @@ static inline int _private_gettimeofday( struct timeval *tv, void *tz ) + # endif + #endif /* _WIN32 */ + +-/* Compat wrapper for stat() */ +- +-#if defined(_WIN32) +-/* can't re-define stat (used in both function name and struct name) */ +-typedef struct _stat64 dvdstat_t; +-static inline int dvdstat(const char *path, dvdstat_t *st) +-{ +- wchar_t *wpath, *it; +- int ret; +- +- wpath = _utf8_to_wchar(path); +- if (!wpath) { +- return -1; +- } +- +- /* need to strip possible trailing \\ */ +- for (it = wpath; *it; it++) +- if ((*it == '\\' || *it == '/') && *(it+1) == 0) +- *it = 0; +- +- ret = _wstat64(wpath, st); +- free(wpath); +- return ret; +-} +-#else +-typedef struct stat dvdstat_t; +-static inline int dvdstat(const char *file, dvdstat_t *st) { +- return stat(file, st); +-} +-#endif +- +-#if defined(_WIN32) +-/* UTF-8 aware version of opendir()/readdir() */ +- +-#include <io.h> +- +-typedef struct { +- intptr_t handle; +- struct _wfinddata_t went; +- struct dirent ent; +-} win32_dir_t; +- +-win32_dir_t *win32_opendir(const char *path) +-{ +- char *filespec; +- wchar_t *wfilespec; +- win32_dir_t *d; +- +- d = calloc(1, sizeof(*d)); +- if (!d) +- return NULL; +- +- filespec = malloc(strlen(path) + 3); +- if (!filespec) { +- goto fail; +- } +- sprintf(filespec, "%s\\*", path); +- +- wfilespec = _utf8_to_wchar(filespec); +- free(filespec); +- if (!wfilespec) { +- goto fail; +- } +- +- d->handle = _wfindfirst(wfilespec, &d->went); +- free(wfilespec); +- if (d->handle != -1) { +- return d; +- } +- +- fail: +- free(d); +- return NULL; +-} +- +-static struct dirent *win32_readdir(win32_dir_t *dir) +-{ +- if (dir->went.name[0]) { +- if (!WideCharToMultiByte(CP_UTF8, 0, dir->went.name, -1, dir->ent.d_name, sizeof(dir->ent.d_name), NULL, NULL)) +- dir->ent.d_name[0] = 0; /* allow reading next */ +- dir->went.name[0] = 0; +- _wfindnext(dir->handle, &dir->went); +- return &dir->ent; +- } +- +- return NULL; +-} +- +-static void win32_closedir(win32_dir_t *dir) +-{ +- _findclose(dir->handle); +- free(dir); +-} +- +-#define DIR win32_dir_t +-#define opendir win32_opendir +-#define readdir win32_readdir +-#define closedir win32_closedir +- +-#endif /* _WIN32 */ +- + #define DEFAULT_UDF_CACHE_LEVEL 1 + + struct dvd_reader_device_s { +@@ -338,7 +230,7 @@ static dvd_reader_device_t *DVDOpenImageFile( dvd_reader_t *ctx, + dvd_reader_device_t *dvd; + dvd_input_t dev; + +- dev = dvdinput_open( ctx->priv, &ctx->logcb, location, stream_cb ); ++ dev = dvdinput_open( ctx->priv, &ctx->logcb, location, stream_cb, ctx->fs ); + if( !dev ) { + Log0(ctx,"Can't open %s for reading", location ); + return NULL; +@@ -452,6 +344,13 @@ static dvd_reader_t *DVDOpenCommon( void *priv, + if(logcb) + ctx->logcb = *logcb; + ++ ctx->fs = InitInternalFilesystem(); ++ if (!ctx->fs) ++ { ++ free(ctx); ++ return NULL; ++ } ++ + #if defined(_WIN32) || defined(__OS2__) + int len; + #endif +@@ -490,7 +389,7 @@ static dvd_reader_t *DVDOpenCommon( void *priv, + } + #endif + +- ret = dvdstat( path, &fileinfo ); ++ ret = ctx->fs->stat(ctx->fs, path, &fileinfo); + + if( ret < 0 ) { + +@@ -513,9 +412,9 @@ static dvd_reader_t *DVDOpenCommon( void *priv, + } + + /* First check if this is a block/char device or a file*/ +- if( S_ISBLK( fileinfo.st_mode ) || +- S_ISCHR( fileinfo.st_mode ) || +- S_ISREG( fileinfo.st_mode ) ) { ++ if( (fileinfo.st_mode & DVD_S_IFMT) == DVD_S_IFBLK || ++ (fileinfo.st_mode & DVD_S_IFMT) == DVD_S_IFCHR || ++ (fileinfo.st_mode & DVD_S_IFMT) == DVD_S_IFREG ) { + + /** + * Block devices and regular files are assumed to be DVD-Video images. +@@ -538,7 +437,7 @@ static dvd_reader_t *DVDOpenCommon( void *priv, + return NULL; + } + return ctx; +- } else if( S_ISDIR( fileinfo.st_mode ) ) { ++ } else if ((fileinfo.st_mode & DVD_S_IFMT) == DVD_S_IFDIR ) { + #if defined(SYS_BSD) + struct fstab* fe; + #elif defined(__sun) || defined(__linux__) +@@ -758,6 +657,9 @@ void DVDClose( dvd_reader_t *dvd ) + if( dvd->rd->path_root ) free( dvd->rd->path_root ); + if( dvd->rd->udfcache ) FreeUDFCache( dvd->rd->udfcache ); + free( dvd->rd ); ++ if (dvd->fs) { ++ dvd->fs->close(dvd->fs); ++ } + free( dvd ); + } + } +@@ -813,24 +715,33 @@ static dvd_file_t *DVDOpenFileUDF( dvd_reader_t *ctx, const char *filename, + * or -1 on file not found. + * or -2 on path not found. + */ +-static int findDirFile( const char *path, const char *file, char *filename ) ++static int findDirFile(dvd_reader_t *ctx, const char *path, const char *file, char *filename ) + { +- DIR *dir; +- struct dirent *ent; +- +- dir = opendir( path ); +- if( !dir ) return -2; ++ dvd_dirent_t entry; ++ dvd_dir_h *dir = ctx->fs->dir_open(ctx->fs, path); ++ if( !dir ) { ++ Log0(ctx, "findDirFile: Could not open dir %s ", path); ++ return -2; ++ } + +- while( ( ent = readdir( dir ) ) != NULL ) { +- if( !strcasecmp( ent->d_name, file ) ) { ++ int result = 0; ++ do ++ { ++ result = dir->read(dir, &entry); ++ if (result < 0) { ++ Log0(ctx, "findDirFile: Error reading dir %s (errorno: %d)", path, result); ++ return -1; ++ } ++ if( !strcasecmp( entry.d_name, file ) ) { + sprintf( filename, "%s%s%s", path, + ( ( path[ strlen( path ) - 1 ] == '/' ) ? "" : "/" ), +- ent->d_name ); +- closedir(dir); ++ entry.d_name ); ++ dir->close(dir); + return 0; + } +- } +- closedir(dir); ++ } while (result == 0); ++ ++ dir->close(dir); + return -1; + } + +@@ -846,17 +757,17 @@ static int findDVDFile( dvd_reader_t *dvd, const char *file, char *filename ) + nodirfile = file; + } + +- ret = findDirFile( dvd->rd->path_root, nodirfile, filename ); ++ ret = findDirFile(dvd, dvd->rd->path_root, nodirfile, filename ); + if( ret < 0 ) { + char video_path[ PATH_MAX + 1 ]; + + /* Try also with adding the path, just in case. */ + sprintf( video_path, "%s/VIDEO_TS/", dvd->rd->path_root ); +- ret = findDirFile( video_path, nodirfile, filename ); ++ ret = findDirFile(dvd, video_path, nodirfile, filename ); + if( ret < 0 ) { + /* Try with the path, but in lower case. */ + sprintf( video_path, "%s/video_ts/", dvd->rd->path_root ); +- ret = findDirFile( video_path, nodirfile, filename ); ++ ret = findDirFile(dvd, video_path, nodirfile, filename ); + if( ret < 0 ) { + return 0; + } +@@ -882,7 +793,7 @@ static dvd_file_t *DVDOpenFilePath( dvd_reader_t *ctx, const char *filename ) + return NULL; + } + +- dev = dvdinput_open( ctx->priv, &ctx->logcb, full_path, NULL ); ++ dev = dvdinput_open( ctx->priv, &ctx->logcb, full_path, NULL, ctx->fs ); + if( !dev ) { + Log0(ctx, "DVDOpenFilePath:dvdinput_open %s failed", full_path ); + return NULL; +@@ -896,13 +807,13 @@ static dvd_file_t *DVDOpenFilePath( dvd_reader_t *ctx, const char *filename ) + } + dvd_file->ctx = ctx; + +- if( dvdstat( full_path, &fileinfo ) < 0 ) { ++ if (ctx->fs->stat(ctx->fs, full_path, &fileinfo) < 0) { + Log0(ctx, "Can't stat() %s.", filename ); + free( dvd_file ); + dvdinput_close( dev ); + return NULL; + } +- dvd_file->title_sizes[ 0 ] = fileinfo.st_size / DVD_VIDEO_LB_LEN; ++ dvd_file->title_sizes[ 0 ] = fileinfo.size / DVD_VIDEO_LB_LEN; + dvd_file->title_devs[ 0 ] = dev; + dvd_file->filesize = dvd_file->title_sizes[ 0 ]; + +@@ -979,23 +890,22 @@ static dvd_file_t *DVDOpenVOBPath( dvd_reader_t *ctx, int title, int menu ) + return NULL; + } + +- dev = dvdinput_open( ctx->priv, &ctx->logcb, full_path, NULL ); ++ dev = dvdinput_open( ctx->priv, &ctx->logcb, full_path, NULL, ctx->fs ); + if( dev == NULL ) { + free( dvd_file ); + return NULL; + } + +- if( dvdstat( full_path, &fileinfo ) < 0 ) { ++ if (ctx->fs->stat(ctx->fs, full_path, &fileinfo) > 0) { + Log0(ctx, "Can't stat() %s.", filename ); + dvdinput_close(dev); + free( dvd_file ); + return NULL; + } +- dvd_file->title_sizes[ 0 ] = fileinfo.st_size / DVD_VIDEO_LB_LEN; ++ dvd_file->title_sizes[ 0 ] = fileinfo.size / DVD_VIDEO_LB_LEN; + dvd_file->title_devs[ 0 ] = dev; + dvdinput_title( dvd_file->title_devs[0], 0); + dvd_file->filesize = dvd_file->title_sizes[ 0 ]; +- + } else { + int i; + +@@ -1006,13 +916,13 @@ static dvd_file_t *DVDOpenVOBPath( dvd_reader_t *ctx, int title, int menu ) + break; + } + +- if( dvdstat( full_path, &fileinfo ) < 0 ) { ++ if (ctx->fs->stat(ctx->fs, full_path, &fileinfo) < 0) { + Log0(ctx, "Can't stat() %s.", filename ); + break; + } + +- dvd_file->title_sizes[ i ] = fileinfo.st_size / DVD_VIDEO_LB_LEN; +- dvd_file->title_devs[ i ] = dvdinput_open( ctx->priv, &ctx->logcb, full_path, NULL ); ++ dvd_file->title_sizes[ i ] = fileinfo.size / DVD_VIDEO_LB_LEN; ++ dvd_file->title_devs[ i ] = dvdinput_open( ctx->priv, &ctx->logcb, full_path, NULL, ctx->fs ); + dvdinput_title( dvd_file->title_devs[ i ], 0 ); + dvd_file->filesize += dvd_file->title_sizes[ i ]; + } +@@ -1105,8 +1015,8 @@ static int DVDFileStatVOBUDF( dvd_reader_t *dvd, int title, + { + char filename[ MAX_UDF_FILE_NAME_LEN ]; + uint32_t size; +- off_t tot_size; +- off_t parts_size[ 9 ]; ++ int64_t tot_size; ++ int64_t parts_size[ 9 ]; + int nr_parts = 0; + int n; + +@@ -1151,8 +1061,8 @@ static int DVDFileStatVOBPath( dvd_reader_t *dvd, int title, + char filename[ MAX_UDF_FILE_NAME_LEN ]; + char full_path[ PATH_MAX + 1 ]; + dvdstat_t fileinfo; +- off_t tot_size; +- off_t parts_size[ 9 ]; ++ int64_t tot_size; ++ int64_t parts_size[ 9 ]; + int nr_parts = 0; + int n; + +@@ -1164,14 +1074,14 @@ static int DVDFileStatVOBPath( dvd_reader_t *dvd, int title, + if( !findDVDFile( dvd, filename, full_path ) ) + return -1; + +- if( dvdstat( full_path, &fileinfo ) < 0 ) { ++ if (dvd->fs->stat(dvd->fs, full_path, &fileinfo) < 0) { + Log1(dvd, "Can't stat() %s.", filename ); + return -1; + } + +- tot_size = fileinfo.st_size; ++ tot_size = fileinfo.size; + nr_parts = 1; +- parts_size[ 0 ] = fileinfo.st_size; ++ parts_size[ 0 ] = fileinfo.size; + + if( !menu ) { + int cur; +@@ -1180,12 +1090,12 @@ static int DVDFileStatVOBPath( dvd_reader_t *dvd, int title, + if( !findDVDFile( dvd, filename, full_path ) ) + break; + +- if( dvdstat( full_path, &fileinfo ) < 0 ) { ++ if (dvd->fs->stat(dvd->fs, full_path, &fileinfo) < 0) { + Log1(dvd, "Can't stat() %s.", filename ); + break; + } + +- parts_size[ nr_parts ] = fileinfo.st_size; ++ parts_size[ nr_parts ] = fileinfo.size; + tot_size += parts_size[ nr_parts ]; + nr_parts++; + } +@@ -1263,10 +1173,10 @@ int DVDFileStat( dvd_reader_t *reader, int titlenum, + char full_path[ PATH_MAX + 1 ]; + + if( findDVDFile( reader, filename, full_path ) ) { +- if( dvdstat( full_path, &fileinfo ) < 0 ) ++ if (reader->fs->stat(reader->fs, full_path, &fileinfo) < 0) + Log1(reader, "Can't stat() %s.", filename ); + else { +- statbuf->size = fileinfo.st_size; ++ statbuf->size = fileinfo.size; + statbuf->nr_parts = 1; + statbuf->parts_size[ 0 ] = statbuf->size; + return 0; +@@ -1318,8 +1228,8 @@ static int DVDReadBlocksUDF( const dvd_file_t *dvd_file, uint32_t offset, + + /* Copy the cache at a specified offset into data. offset and block_count + * must be converted into bytes */ +- memcpy( data, dvd_file->cache + (off_t)offset * (off_t)DVD_VIDEO_LB_LEN, +- (off_t)block_count * (off_t)DVD_VIDEO_LB_LEN ); ++ memcpy( data, dvd_file->cache + (int64_t)offset * (int64_t)DVD_VIDEO_LB_LEN, ++ (int64_t)block_count * (int64_t)DVD_VIDEO_LB_LEN ); + + /* return the amount of blocks copied */ + return block_count; +diff --git a/libdvdread-embedded/src/dvdread/dvd_filesystem.h b/libdvdread-embedded/src/dvdread/dvd_filesystem.h +new file mode 100644 +index 0000000..291f4d9 +--- /dev/null ++++ b/libdvdread-embedded/src/dvdread/dvd_filesystem.h +@@ -0,0 +1,124 @@ ++/* ++ * This file is part of libdvdread ++ * Copyright (C) 2022 VideoLAN ++ * ++ * This file is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This file is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library. If not, see ++ * <http://www.gnu.org/licenses/>. ++ */ ++ ++#ifndef DVDREAD_FILESYSTEM_H_ ++#define DVDREAD_FILESYSTEM_H_ ++ ++#include <stdint.h> ++#include <sys/types.h> ++ ++/* ++ * directory access ++ */ ++ ++/** ++ * The dvd_dirent_t struct abstracts dirent usage from the respective platform implementation. ++ * For this reason, it only includes the parts the lib cares about (in this case d_name - the directory name) ++ */ ++typedef struct ++{ ++ char d_name[256]; ++} dvd_dirent_t; ++ ++typedef struct dvd_filesystem_dir_s dvd_dir_h; ++/** ++ * Abstraction for directory access ++ * internal - opaque handler internal to the specific implementation used to store the data type of directory stream objects. ++ * This is tipically a dir handler (e.g. a DIR* in posix) ++ * close(dvd_dir_h *dir) - called to close the directory and cleanup any alloc'd dir structures ++ * read(dvd_dir_h *dir, dvd_dirent_t *entry) - provided the dvd_dirent_t, reads the respective directory and returns -1 if the ++ * directory could not be read, 0 if successfully read. ++ */ ++struct dvd_filesystem_dir_s ++{ ++ void *internal; ++ void (*close)(dvd_dir_h *dir); ++ int (*read)(dvd_dir_h *dir, dvd_dirent_t *entry); ++}; ++ ++/* ++ * Stat access ++ */ ++ ++#define DVD_S_IFMT 0170000 /* These bits determine file type. */ ++ ++#define DVD_S_IFCHR 0020000 /* character special */ ++#define DVD_S_IFDIR 0040000 /* directory */ ++#define DVD_S_IFBLK 0060000 /* block special */ ++#define DVD_S_IFREG 0100000 /* regular */ ++ ++/** ++ * Abstraction for stat buffer structure ++ * size - size of the stat'd file ++ * st_mode - file mode ++ */ ++typedef struct ++{ ++ off_t size; ++ unsigned int st_mode; ++} dvdstat_t; ++ ++ ++/* ++ * file access ++ */ ++ ++/** ++ * Abstraction for file access ++ * internal - opaque handler internal to the specific implementation used to store the data type of the file object. ++ * This is tipically a file reference (e.g. the file descriptor/fd) ++ * close(dvd_file_h *file) - called to close the file and cleanup any alloc'd file structs ++ * seek(dvd_file_h *file, int64_t offset, int32_t origin) - used to seek into the given file (provided the offset and the origin). Returns ++ * the position on the file after seek. ++ * read(dvd_file_h *file, char *buf, int64_t size) - used to read the file into the passed buffer, given the read size. Returns the read ++ * read from the file ++ */ ++typedef struct dvd_filesystem_file_s dvd_file_h; ++struct dvd_filesystem_file_s ++{ ++ void *internal; ++ int (*close) (dvd_file_h *file); ++ int64_t (*seek) (dvd_file_h *file, int64_t offset, int32_t origin); ++ ssize_t (*read) (dvd_file_h *file, char *buf, size_t size); ++}; ++ ++/* ++ * Filesystem implementation ++ */ ++ ++/** ++ * Groups all filesystem operations into a common struct. This is the struct external applications should override to ++ * provide custom filesystem implementations: ++ * internal - opaque data pointer to user data (used to convey custom data within the filesystem struct) ++ * close(dvd_reader_filesystem_h *fs) - called to destroy the filesystem implementation (free any alloc'd structs) ++ * stat(dvd_reader_filesystem_h *fs, const char *path, dvdstat_t* statbuf) - stat a file/dir provided the statbuf, initializes the dvdstat_t. ++ * dir_open(dvd_reader_filesystem_h *fs, const char* dirname) - open the provided dir, initializes dvd_dir_h ++ * file_open(dvd_reader_filesystem_h *fs, const char* filename, const char *mode) - open a file, initializes dvd_file_h ++ */ ++typedef struct dvd_reader_filesystem_s dvd_reader_filesystem_h; ++struct dvd_reader_filesystem_s ++{ ++ void *internal; ++ void (*close) (dvd_reader_filesystem_h *fs); ++ int (*stat) (dvd_reader_filesystem_h *fs, const char *path, dvdstat_t *statbuf); ++ dvd_dir_h* (*dir_open) (dvd_reader_filesystem_h *fs, const char *dirname); ++ dvd_file_h* (*file_open) (dvd_reader_filesystem_h *fs, const char *filename); ++}; ++ ++#endif /* DVDREAD_FILESYSTEM_H_ */ +diff --git a/libdvdread-embedded/src/dvdread/dvd_reader.h b/libdvdread-embedded/src/dvdread/dvd_reader.h +index 54ef5dd..5b15704 100644 +--- a/libdvdread-embedded/src/dvdread/dvd_reader.h ++++ b/libdvdread-embedded/src/dvdread/dvd_reader.h +@@ -23,13 +23,6 @@ + #ifndef LIBDVDREAD_DVD_READER_H + #define LIBDVDREAD_DVD_READER_H + +-#ifdef _MSC_VER +-#include <config.h> +- +-#include <stdio.h> +-#include <stdlib.h> +-#endif +- + #include <sys/types.h> + #include <inttypes.h> + #include <stdarg.h> +@@ -46,6 +39,12 @@ + */ + #include "version.h" + ++/** ++ * Filesystem types ++ */ ++#include "dvd_filesystem.h" ++ ++ + /** + * The length of one Logical Block of a DVD. + */ +diff --git a/libdvdread-embedded/src/dvdread_internal.h b/libdvdread-embedded/src/dvdread_internal.h +index bf4e2e1..1a35059 100644 +--- a/libdvdread-embedded/src/dvdread_internal.h ++++ b/libdvdread-embedded/src/dvdread_internal.h +@@ -39,6 +39,7 @@ struct dvd_reader_s + dvd_reader_device_t *rd; + void *priv; /* User provided context */ + dvd_logger_cb logcb; ++ dvd_reader_filesystem_h* fs; + /* Set 100 flags for BUP fallback, most signifiant left + [0] for upper remaining VTS, [1] for the first Main + 63 VTS */ + uint64_t ifoBUPflags[2]; +diff --git a/libdvdread-embedded/src/file/dir_posix.c b/libdvdread-embedded/src/file/dir_posix.c +new file mode 100644 +index 0000000..f55e62a +--- /dev/null ++++ b/libdvdread-embedded/src/file/dir_posix.c +@@ -0,0 +1,98 @@ ++/* ++ * This file is part of libdvdread ++ * Copyright (C) 2022 VideoLAN ++ * ++ * This file is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This file is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library. If not, see ++ * <http://www.gnu.org/licenses/>. ++ */ ++ ++#include "config.h" ++ ++#include <stdlib.h> ++#include <string.h> ++#if HAVE_DIRENT_H ++#include <dirent.h> ++#endif ++ ++#if defined(__GLIBC__) && defined(__GLIBC_MINOR__) ++# if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 24) ++# define USE_READDIR ++# include <errno.h> ++# endif ++#endif ++ ++#include <dvdread/dvd_filesystem.h> ++#include "filesystem.h" ++ ++void _dir_close_posix(dvd_dir_h *dir) ++{ ++ if (dir) { ++ closedir((DIR *)dir->internal); ++ free(dir); ++ dir = NULL; ++ } ++} ++ ++int _dir_read_posix(dvd_dir_h *dir, dvd_dirent_t *entry) ++{ ++ struct dirent *p_e; ++ ++#ifdef USE_READDIR ++ errno = 0; ++ p_e = readdir((DIR*)dir->internal); ++ if (!p_e && errno) { ++ return -errno; ++ } ++#else /* USE_READDIR */ ++ int result; ++ struct dirent e; ++ ++ result = readdir_r((DIR*)dir->internal, &e, &p_e); ++ if (result) { ++ return -result; ++ } ++#endif /* USE_READDIR */ ++ ++ if (p_e == NULL) { ++ return 1; ++ } ++ strncpy(entry->d_name, p_e->d_name, sizeof(entry->d_name)); ++ entry->d_name[sizeof(entry->d_name) - 1] = 0; ++ ++ return 0; ++} ++ ++dvd_dir_h *dir_open_default(dvd_reader_filesystem_h *fs, const char* dirname) ++{ ++ if (!fs) ++ return NULL; ++ ++ dvd_dir_h *dir = calloc(1, sizeof(dvd_dir_h)); ++ ++ if (!dir) { ++ return NULL; ++ } ++ ++ dir->close = _dir_close_posix; ++ dir->read = _dir_read_posix; ++ ++ if ((dir->internal = opendir(dirname))) { ++ return dir; ++ } ++ ++ free(dir); ++ dir = NULL; ++ ++ return NULL; ++} +diff --git a/libdvdread-embedded/src/file/dir_win32.c b/libdvdread-embedded/src/file/dir_win32.c +new file mode 100644 +index 0000000..cb89728 +--- /dev/null ++++ b/libdvdread-embedded/src/file/dir_win32.c +@@ -0,0 +1,108 @@ ++/* ++ * This file is part of libdvdread ++ * Copyright (C) 2022 VideoLAN ++ * ++ * This file is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This file is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library. If not, see ++ * <http://www.gnu.org/licenses/>. ++ */ ++ ++#include <io.h> ++#include <stdlib.h> ++#include <string.h> ++#include <stdio.h> ++ ++#include <windows.h> ++#include "../msvc/contrib/win32_cs.h" ++ ++ ++#include <dvdread/dvd_filesystem.h> ++#include "filesystem.h" ++ ++ ++typedef struct { ++ intptr_t handle; ++ struct _wfinddata_t went; ++} win32_dir_t; ++ ++ ++void _dir_close_win32(dvd_dir_h *dir) ++{ ++ if (dir) { ++ _findclose(((win32_dir_t*)dir->internal)->handle); ++ free((win32_dir_t*)dir->internal); ++ free(dir); ++ dir = NULL; ++ } ++} ++ ++int _dir_read_win32(dvd_dir_h *dir, dvd_dirent_t *entry) ++{ ++ win32_dir_t *wdir = (win32_dir_t*)dir->internal; ++ if (wdir->went.name[0]) { ++ if (!WideCharToMultiByte(CP_UTF8, 0, wdir->went.name, -1, entry->d_name, sizeof(entry->d_name), NULL, NULL)) ++ entry->d_name[0] = 0; /* allow reading next */ ++ wdir->went.name[0] = 0; ++ _wfindnext(wdir->handle, &wdir->went); ++ return 0; ++ } ++ return -1; ++} ++ ++dvd_dir_h *dir_open_default(dvd_reader_filesystem_h *fs, const char* dirname) ++{ ++ if (!fs) ++ return NULL; ++ ++ char *filespec; ++ wchar_t *wfilespec; ++ win32_dir_t *d; ++ dvd_dir_h *dir = calloc(1, sizeof(dvd_dir_h)); ++ ++ if (!dir) { ++ return NULL; ++ } ++ ++ d = calloc(1, sizeof(*d)); ++ if (!d) ++ { ++ free(dir); ++ return NULL; ++ } ++ ++ filespec = malloc(strlen(dirname) + 3); ++ if (!filespec) { ++ goto fail; ++ } ++ sprintf(filespec, "%s\\*", dirname); ++ ++ wfilespec = _utf8_to_wchar(filespec); ++ free(filespec); ++ if (!wfilespec) { ++ goto fail; ++ } ++ ++ d->handle = _wfindfirst(wfilespec, &d->went); ++ free(wfilespec); ++ if (d->handle != -1) { ++ dir->internal = (void*)d; ++ dir->close = _dir_close_win32; ++ dir->read = _dir_read_win32; ++ return dir; ++ } ++ ++ fail: ++ free(d); ++ free(dir); ++ return NULL; ++} +diff --git a/libdvdread-embedded/src/file/file_posix.c b/libdvdread-embedded/src/file/file_posix.c +new file mode 100644 +index 0000000..cbdbd58 +--- /dev/null ++++ b/libdvdread-embedded/src/file/file_posix.c +@@ -0,0 +1,113 @@ ++/* ++ * This file is part of libdvdread ++ * Copyright (C) 2022 VideoLAN ++ * ++ * This file is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This file is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library. If not, see ++ * <http://www.gnu.org/licenses/>. ++ */ ++ ++ ++#include <stdlib.h> ++#include <unistd.h> ++#include <stdio.h> ++#include <errno.h> ++ ++ ++#include <sys/stat.h> ++#include <fcntl.h> ++ ++#include <dvdread/dvd_filesystem.h> ++ ++#include "filesystem.h" ++ ++#ifdef __ANDROID__ ++# undef lseek ++# define lseek lseek64 ++# undef off_t ++# define off_t off64_t ++#endif ++ ++ ++int _file_close(dvd_file_h *file) ++{ ++ if (file) { ++ int ret = close((int)(intptr_t)file->internal); ++ free(file); ++ return ret; ++ } ++ return 0; ++} ++ ++int64_t _file_seek(dvd_file_h *file, int64_t offset, int32_t origin) ++{ ++ off_t result = lseek((int)(intptr_t)file->internal, offset, origin); ++ if (result == (off_t)-1) { ++ return -1; ++ } ++ return (int64_t)result; ++} ++ ++ssize_t _file_read(dvd_file_h *file, char *buf, size_t size) ++{ ++ ssize_t result; ++ ++ if (size <= 0) { ++ return 0; ++ } ++ ++ result = read((int)(intptr_t)file->internal, buf, size); ++ return result; ++} ++ ++ ++dvd_file_h* file_open_default(dvd_reader_filesystem_h *fs, const char* filename) ++{ ++ if (!fs) ++ return NULL; ++ ++ dvd_file_h *file; ++ int fd = -1; ++ int flags = 0; ++ int mode = 0; ++ ++ #if defined(__OS2__) // not posix but kept here for legacy compatibility reasons ++ flags = O_RDONLY | O_BINARY; ++ #else ++ flags = O_RDONLY; ++ #endif ++ ++#ifdef O_CLOEXEC ++ flags |= O_CLOEXEC; ++#endif ++#ifdef O_BINARY ++ flags |= O_BINARY; ++#endif ++ ++ if ((fd = open(filename, flags, mode)) < 0) { ++ return NULL; ++ } ++ ++ file = calloc(1, sizeof(dvd_file_h)); ++ if (!file) { ++ close(fd); ++ return NULL; ++ } ++ ++ file->close = _file_close; ++ file->read = _file_read; ++ file->seek = _file_seek; ++ file->internal = (void*)(intptr_t)fd; ++ ++ return file; ++} +diff --git a/libdvdread-embedded/src/file/file_win32.c b/libdvdread-embedded/src/file/file_win32.c +new file mode 100644 +index 0000000..9787076 +--- /dev/null ++++ b/libdvdread-embedded/src/file/file_win32.c +@@ -0,0 +1,98 @@ ++/* ++ * This file is part of libdvdread ++ * Copyright (C) 2022 VideoLAN ++ * ++ * This file is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This file is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library. If not, see ++ * <http://www.gnu.org/licenses/>. ++ */ ++ ++#include <stdlib.h> ++#include <unistd.h> ++#include <stdio.h> ++#include <errno.h> ++ ++#include <sys/stat.h> ++#include <fcntl.h> ++ ++#include <windows.h> ++#include "../msvc/contrib/win32_cs.h" ++ ++#include <dvdread/dvd_filesystem.h> ++#include "filesystem.h" ++ ++ ++int _file_close_win32(dvd_file_h *file) ++{ ++ if (file) { ++ int ret = close((int)(intptr_t)file->internal); ++ free(file); ++ return ret; ++ } ++ return 0; ++} ++ ++int64_t _file_seek_win32(dvd_file_h *file, int64_t offset, int32_t origin) ++{ ++ off64_t result = _lseeki64((int)(intptr_t)file->internal, offset, origin); ++ if (result == (off64_t)-1) { ++ return -1; ++ } ++ return (int64_t)result; ++} ++ ++ssize_t _file_read_win32(dvd_file_h *file, char *buf, size_t size) ++{ ++ ssize_t result; ++ ++ if (size <= 0) { ++ return 0; ++ } ++ ++ result = read((int)(intptr_t)file->internal, buf, size); ++ return result; ++} ++ ++ ++dvd_file_h* file_open_default(dvd_reader_filesystem_h *fs, const char* filename) ++{ ++ if (!fs) ++ return NULL; ++ ++ dvd_file_h *file; ++ int fd = -1; ++ wchar_t *wpath; ++ ++ wpath = _utf8_to_wchar(filename); ++ if (!wpath) { ++ return NULL; ++ } ++ ++ if ((fd = _wopen(wpath, O_RDONLY | O_BINARY)) < 0) { ++ free(wpath); ++ return NULL; ++ } ++ ++ file = calloc(1, sizeof(dvd_file_h)); ++ if (!file) { ++ close(fd); ++ return NULL; ++ } ++ ++ file->close = _file_close_win32; ++ file->read = _file_read_win32; ++ file->seek = _file_seek_win32; ++ file->internal = (void*)(intptr_t)fd; ++ ++ return file; ++} +diff --git a/libdvdread-embedded/src/file/filesystem.c b/libdvdread-embedded/src/file/filesystem.c +new file mode 100644 +index 0000000..b79edae +--- /dev/null ++++ b/libdvdread-embedded/src/file/filesystem.c +@@ -0,0 +1,37 @@ ++/* ++ * This file is part of libdvdread. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU Lesser General Public License as published by ++ * the Free Software Foundation; either version 2.1 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public License ++ * along with this program; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. ++ */ ++ ++#include "filesystem.h" ++ ++#include <stdlib.h> ++ ++static void default_filesystem_close(dvd_reader_filesystem_h *fs) { ++ free(fs); ++} ++ ++dvd_reader_filesystem_h* InitInternalFilesystem() { ++ dvd_reader_filesystem_h* fs = calloc( 1, sizeof(dvd_reader_filesystem_h)); ++ if (!fs) { ++ return NULL; ++ } ++ fs->dir_open = dir_open_default; ++ fs->stat = stat_default; ++ fs->file_open = file_open_default; ++ fs->close = default_filesystem_close; ++ return fs; ++} +diff --git a/libdvdread-embedded/src/file/filesystem.h b/libdvdread-embedded/src/file/filesystem.h +new file mode 100644 +index 0000000..1b8a014 +--- /dev/null ++++ b/libdvdread-embedded/src/file/filesystem.h +@@ -0,0 +1,46 @@ ++/* ++ * This file is part of libdvdread. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU Lesser General Public License as published by ++ * the Free Software Foundation; either version 2.1 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public License ++ * along with this program; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. ++ */ ++ ++#ifndef LIBDVDREAD_FILESYSTEM_H ++#define LIBDVDREAD_FILESYSTEM_H ++ ++#include "dvdread/dvd_filesystem.h" ++ ++/** ++ * Prototype definition for default file open function (implemented by each platform) ++ */ ++dvd_file_h* file_open_default(dvd_reader_filesystem_h *fs, const char* filename); ++ ++/** ++ * Prototype definition for default dir open function (implemented by each platform) ++ */ ++dvd_dir_h* dir_open_default(dvd_reader_filesystem_h *fs, const char* dirname); ++ ++/** ++ * Prototype definition for default stat function (implemented by each platform) ++ */ ++int stat_default(dvd_reader_filesystem_h *fs, const char *path, dvdstat_t* statbuf); ++ ++/** ++ * Inits the internal (platform specific) filesystem implementation ++ * bundled with libdvdread. This includes initializing the default internal ++ * implmentations of file_open, dir_open, stat, etc. ++ */ ++dvd_reader_filesystem_h* InitInternalFilesystem(); ++ ++#endif +diff --git a/libdvdread-embedded/src/file/stat_posix.c b/libdvdread-embedded/src/file/stat_posix.c +new file mode 100644 +index 0000000..61670fc +--- /dev/null ++++ b/libdvdread-embedded/src/file/stat_posix.c +@@ -0,0 +1,36 @@ ++/* ++ * This file is part of libdvdread ++ * Copyright (C) 2022 VideoLAN ++ * ++ * This file is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This file is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library. If not, see ++ * <http://www.gnu.org/licenses/>. ++ */ ++ ++#include <stdlib.h> ++#include <sys/stat.h> ++ ++#include <dvdread/dvd_filesystem.h> ++#include "filesystem.h" ++ ++int stat_default(dvd_reader_filesystem_h *fs, const char *path, dvdstat_t* statbuf) ++{ ++ if (!fs) ++ return -1; ++ ++ struct stat posixstatbuf; ++ int ret = stat(path, &posixstatbuf); ++ statbuf->size = posixstatbuf.st_size; ++ statbuf->st_mode = posixstatbuf.st_mode; ++ return ret; ++} +diff --git a/libdvdread-embedded/src/file/stat_win32.c b/libdvdread-embedded/src/file/stat_win32.c +new file mode 100644 +index 0000000..0b8245d +--- /dev/null ++++ b/libdvdread-embedded/src/file/stat_win32.c +@@ -0,0 +1,53 @@ ++/* ++ * This file is part of libdvdread ++ * Copyright (C) 2022 VideoLAN ++ * ++ * This file is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This file is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library. If not, see ++ * <http://www.gnu.org/licenses/>. ++ */ ++ ++#include <stdlib.h> ++#include <sys/stat.h> ++ ++#include <windows.h> ++#include "../msvc/contrib/win32_cs.h" ++ ++#include <dvdread/dvd_filesystem.h> ++#include "filesystem.h" ++ ++ ++int stat_default(dvd_reader_filesystem_h *fs, const char *path, dvdstat_t* statbuf) ++{ ++ if (!fs) ++ return -1; ++ ++ struct _stat64 win32statbuf; ++ ++ wchar_t *wpath, *it; ++ ++ wpath = _utf8_to_wchar(path); ++ if (!wpath) { ++ return -1; ++ } ++ ++ /* need to strip possible trailing \\ */ ++ for (it = wpath; *it; it++) ++ if ((*it == '\\' || *it == '/') && *(it+1) == 0) ++ *it = 0; ++ ++ int ret = _wstat64(wpath, &win32statbuf); ++ statbuf->size = win32statbuf.st_size; ++ statbuf->st_mode = win32statbuf.st_mode; ++ return ret; ++} +-- +2.35.1 + + +From 7215ed052b632be49c4f1ed444c7c9447e2d4c61 Mon Sep 17 00:00:00 2001 +From: Miguel Borges de Freitas <enen92@kodi.tv> +Date: Fri, 29 Jul 2022 12:50:24 +0100 +Subject: [PATCH 2/3] Decouple dvdinput_setup providing dvdinput_setup_builtin + for minimal/internal fs access + +--- + libdvdread-embedded/src/dvd_input.c | 23 +++++++++++++++++------ + libdvdread-embedded/src/dvd_input.h | 8 ++++++++ + 2 files changed, 25 insertions(+), 6 deletions(-) + +diff --git a/libdvdread-embedded/src/dvd_input.c b/libdvdread-embedded/src/dvd_input.c +index 1baf8f7..70f31b3 100644 +--- a/libdvdread-embedded/src/dvd_input.c ++++ b/libdvdread-embedded/src/dvd_input.c +@@ -446,12 +446,23 @@ int dvdinput_setup(void *priv, dvd_logger_cb *logcb) + DVDReadLog(priv, logcb, DVD_LOGGER_LEVEL_WARN, + "Encrypted DVD support unavailable."); + +- /* libdvdcss replacement functions */ +- dvdinput_open = file_open; +- dvdinput_close = file_close; +- dvdinput_seek = file_seek; +- dvdinput_title = file_title; +- dvdinput_read = file_read; ++ dvdinput_setup_builtin(priv, logcb); + return 0; + } + } ++ ++/** ++ * Setup read functions with the builtin libdvdread implementation (minimal DVD access without css). ++ */ ++void dvdinput_setup_builtin(void *priv, dvd_logger_cb *logcb) ++{ ++ DVDReadLog(priv, logcb, DVD_LOGGER_LEVEL_INFO, ++ "Setting up builtin libdvdread implementation"); ++ ++ /* libdvdcss replacement functions */ ++ dvdinput_open = file_open; ++ dvdinput_close = file_close; ++ dvdinput_seek = file_seek; ++ dvdinput_title = file_title; ++ dvdinput_read = file_read; ++} +diff --git a/libdvdread-embedded/src/dvd_input.h b/libdvdread-embedded/src/dvd_input.h +index 56fe170..36fe279 100644 +--- a/libdvdread-embedded/src/dvd_input.h ++++ b/libdvdread-embedded/src/dvd_input.h +@@ -46,7 +46,15 @@ extern int (*dvdinput_read) (dvd_input_t, void *, int, int); + + /** + * Setup function accessed by dvd_reader.c. Returns 1 if there is CSS support. ++ * Otherwise it falls back to the internal dvdread implementation (without css support) ++ * which is basically the same as calling dvdinput_setup_builtin. + */ + int dvdinput_setup(void *, dvd_logger_cb *); + ++/** ++ * Setup function accessed by dvd_reader.c using the builtin libdvdread implementation ++ * (without css support) ++ */ ++void dvdinput_setup_builtin(void *, dvd_logger_cb *); ++ + #endif /* LIBDVDREAD_DVD_INPUT_H */ +-- +2.35.1 + + +From 665a98ee15896e97aa8f0c0d6499b281d0602e60 Mon Sep 17 00:00:00 2001 +From: Miguel Borges de Freitas <enen92@kodi.tv> +Date: Fri, 29 Jul 2022 12:55:19 +0100 +Subject: [PATCH 3/3] Add DVDOpenFiles supporting caller provided filesystem + implementation + +--- + libdvdread-embedded/src/dvd_reader.c | 32 +++++++++++++++++++++++++++----- + libdvdread-embedded/src/dvdread/dvd_reader.h | 13 +++++++++++++ + 2 files changed, 40 insertions(+), 5 deletions(-) + +diff --git a/libdvdread-embedded/src/dvd_reader.c b/libdvdread-embedded/src/dvd_reader.c +index 5a21056..84bef88 100644 +--- a/libdvdread-embedded/src/dvd_reader.c ++++ b/libdvdread-embedded/src/dvd_reader.c +@@ -330,7 +330,8 @@ static char *bsd_block2char( const char *path ) + static dvd_reader_t *DVDOpenCommon( void *priv, + const dvd_logger_cb *logcb, + const char *ppath, +- dvd_reader_stream_cb *stream_cb ) ++ dvd_reader_stream_cb *stream_cb, ++ dvd_reader_filesystem_h * fs ) + { + dvdstat_t fileinfo; + int ret, have_css, cdir = -1; +@@ -344,6 +345,21 @@ static dvd_reader_t *DVDOpenCommon( void *priv, + if(logcb) + ctx->logcb = *logcb; + ++ // open files using the provided filesystem implementation ++ if (fs != NULL && ppath != NULL) ++ { ++ ctx->fs = fs; ++ dvdinput_setup_builtin(ctx->priv, &ctx->logcb); ++ ctx->rd = DVDOpenPath(ppath); ++ if (!ctx->rd) ++ { ++ free(ctx); ++ return NULL; ++ } ++ return ctx; ++ } ++ ++ // create the internal filesystem + ctx->fs = InitInternalFilesystem(); + if (!ctx->fs) + { +@@ -629,25 +645,31 @@ DVDOpen_error: + + dvd_reader_t *DVDOpen( const char *ppath ) + { +- return DVDOpenCommon( NULL, NULL, ppath, NULL ); ++ return DVDOpenCommon( NULL, NULL, ppath, NULL, NULL ); + } + + dvd_reader_t *DVDOpenStream( void *stream, + dvd_reader_stream_cb *stream_cb ) + { +- return DVDOpenCommon( stream, NULL, NULL, stream_cb ); ++ return DVDOpenCommon( stream, NULL, NULL, stream_cb, NULL ); + } + + dvd_reader_t *DVDOpen2( void *priv, const dvd_logger_cb *logcb, + const char *ppath ) + { +- return DVDOpenCommon( priv, logcb, ppath, NULL ); ++ return DVDOpenCommon( priv, logcb, ppath, NULL, NULL ); + } + + dvd_reader_t *DVDOpenStream2( void *priv, const dvd_logger_cb *logcb, + dvd_reader_stream_cb *stream_cb ) + { +- return DVDOpenCommon( priv, logcb, NULL, stream_cb ); ++ return DVDOpenCommon( priv, logcb, NULL, stream_cb, NULL ); ++} ++ ++dvd_reader_t *DVDOpenFiles( void *priv, const dvd_logger_cb *logcb, ++ const char *ppath, dvd_reader_filesystem_h *fs) ++{ ++ return DVDOpenCommon( priv, logcb, ppath, NULL, fs); + } + + void DVDClose( dvd_reader_t *dvd ) +diff --git a/libdvdread-embedded/src/dvdread/dvd_reader.h b/libdvdread-embedded/src/dvdread/dvd_reader.h +index 5b15704..40ddaf2 100644 +--- a/libdvdread-embedded/src/dvdread/dvd_reader.h ++++ b/libdvdread-embedded/src/dvdread/dvd_reader.h +@@ -153,6 +153,19 @@ dvd_reader_t *DVDOpenStream( void *, dvd_reader_stream_cb * ); + dvd_reader_t *DVDOpen2( void *, const dvd_logger_cb *, const char * ); + dvd_reader_t *DVDOpenStream2( void *, const dvd_logger_cb *, dvd_reader_stream_cb * ); + ++/** ++ * Open unencrypted DVD files providing the respective filesystem implementation ++ * Useful to open files located on virtual file systems ++ * ++ * @param path Specifies the file or directory to use ++ * @param priv is a private handle ++ * @param logcb is a custom logger callback struct, or NULL if none needed ++ * @param fs is a struct containing the filesystem implementation ++ * @return If successful a read handle is returned. Otherwise 0 is returned. ++ * ++ */ ++dvd_reader_t *DVDOpenFiles( void *priv, const dvd_logger_cb *logcb, const char * path, dvd_reader_filesystem_h *fs); ++ + /** + * Closes and cleans up the DVD reader object. + * +-- +2.35.1 + diff --git a/debian/patches/libdvdread/debian-0001-libdvdcss.patch b/debian/patches/libdvdread/debian-0001-libdvdcss.patch new file mode 100644 index 0000000..3b30917 --- /dev/null +++ b/debian/patches/libdvdread/debian-0001-libdvdcss.patch @@ -0,0 +1,25 @@ +From: Daniel Baumann <mail@daniel-baumann.ch> +Date: Tue, 22 Apr 2014 11:14:26 +0200 +Subject: libdvdcss +Forwarded: not-needed + +Print information about the CSS README. +--- + libdvdread-embedded/src/dvd_input.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/libdvdread-embedded/src/dvd_input.c b/libdvdread-embedded/src/dvd_input.c +index 0c44387..f640020 100644 +--- a/libdvdread-embedded/src/dvd_input.c ++++ b/libdvdread-embedded/src/dvd_input.c +@@ -477,8 +477,8 @@ int dvdinput_setup(void *priv, dvd_logger_cb *logcb, unsigned char stream_mode) + + } else { + DVDReadLog(priv, logcb, DVD_LOGGER_LEVEL_WARN, +- "Encrypted DVD support unavailable."); +- ++ "Encrypted DVD support unavailable. No css library available. " ++ "See /usr/share/doc/libdvdread4/README.css for more information"); + dvdinput_setup_builtin(priv, logcb); + return 0; + } diff --git a/debian/patches/libdvdread/debian-0002-descriptor.patch b/debian/patches/libdvdread/debian-0002-descriptor.patch new file mode 100644 index 0000000..a61d4f4 --- /dev/null +++ b/debian/patches/libdvdread/debian-0002-descriptor.patch @@ -0,0 +1,104 @@ +From: Mario Holbe <mario.holbe@tu-ilmenau.de> +Date: Tue, 22 Apr 2014 11:49:42 +0200 +Subject: descriptor +Forwarded: not-needed + +libdvdread is very likely to fail on discs/images that store their File +System Descriptor at the end of the disc/image rather than at the +beginning. This is due to the "strategy" libdvdread uses to find it: +libdvdread scans sequentially from the beginning of the disc/image for +the File System Descriptor and identifies it by a single byte tag. + +Aside from wasting lots of time on discs/images that store their File +System Descriptor at the end there is quite a good chance to stumble +across a random data block that accidentally starts with this tag (and +failing on it) before finding the real File System Descriptor. + +As far as I can see, at least CDBurnerXP seems to (be able to) create +such images - at least if my interpretation of the Implementation +Identifier "NMS DVDProLib" is correct. + +This... well, let's call it ugly hack fixes this by obtaining +the File System Descriptor location from the Logical Volume Descriptor + +Closes: #663512 +--- + libdvdread-embedded/src/dvd_udf.c | 37 ++++++++++++++++++++++++++++++++++--- + 1 file changed, 34 insertions(+), 3 deletions(-) + +diff --git a/libdvdread-embedded/src/dvd_udf.c b/libdvdread-embedded/src/dvd_udf.c +index 41517fa..7b22b43 100644 +--- a/libdvdread-embedded/src/dvd_udf.c ++++ b/libdvdread-embedded/src/dvd_udf.c +@@ -82,6 +82,8 @@ struct Partition { + uint32_t AccessType; + uint32_t Start; + uint32_t Length; ++ uint32_t FSD_Location; ++ uint32_t FSD_Length; + }; + + struct AD { +@@ -101,6 +103,12 @@ struct avdp_t { + struct extent_ad rvds; + }; + ++struct fsd_t { ++ uint16_t Partition; ++ uint32_t Location; ++ uint32_t Length; ++}; ++ + struct pvd_t { + uint8_t VolumeIdentifier[32]; + uint8_t VolumeSetIdentifier[128]; +@@ -427,6 +435,16 @@ static int UDFLogVolume( uint8_t *data, char *VolumeDescriptor ) + return 0; + } + ++/** ++ * Reads the File Set Descriptor from the Logical Volume Descriptor. ++ */ ++static void UDFFSD( uint8_t *data, struct fsd_t *fsd ) ++{ ++ fsd->Length = GETN4(248); /* always 2048? */ ++ fsd->Location = GETN4(252); ++ fsd->Partition = GETN2(256); /* always 0? */ ++} ++ + static int UDFFileEntry( uint8_t *data, uint8_t *FileType, + struct Partition *partition, struct AD *ad ) + { +@@ -801,8 +819,18 @@ static int UDFFindPartition( dvd_reader_t *ctx, int partnum, + /* Logical Volume Descriptor */ + if( UDFLogVolume( LogBlock ) ) { + /* TODO: sector size wrong! */ +- } else +- volvalid = 1; ++ } else { ++ struct fsd_t fsd; ++ ++ UDFFSD(LogBlock, &fsd); ++ if(part->Number == fsd.Partition) { ++ part->FSD_Location = fsd.Location; ++ part->FSD_Length = fsd.Length; ++ volvalid = 1; ++ } else { ++ /* TODO: Oups, how to handle this? */ ++ } ++ } + } + + } while( ( lbnum <= MVDS_location + ( MVDS_length - 1 ) +@@ -845,7 +873,10 @@ uint32_t UDFFindFile( dvd_reader_t *ctx, const char *filename, + SetUDFCache(ctx, PartitionCache, 0, &partition); + + /* Find root dir ICB */ +- lbnum = partition.Start; ++ lbnum = partition.Start + partition.FSD_Location; ++ /* ++ fprintf(stderr, "Looking for FSD at 0x%x\n", lbnum); ++ */ + do { + ret = DVDReadLBUDF( ctx, lbnum++, 1, LogBlock, 0 ); + if( ret < 0 ) { diff --git a/debian/patches/series b/debian/patches/series new file mode 100644 index 0000000..3b63e5d --- /dev/null +++ b/debian/patches/series @@ -0,0 +1,28 @@ +kodi/0001-Implement-hashes-using-Libgcrypt.patch +kodi/0002-Find-and-link-with-Libgcrypt.patch +kodi/0003-differentiate-from-vanilla-Kodi.patch +kodi/0004-use-system-groovy.patch +kodi/0005-fix-tests.patch +kodi/0006-dont-use-openssl.patch +kodi/0007-support-omitting-addons-service.patch +kodi/0008-Find-test-fixtures-in-source-directory.patch +kodi/0009-Skip-long-time-broken-test.patch +kodi/0010-Disable-flaky-TestMassEvent.General-and-TestMassEven.patch +kodi/0011-Skip-checking-errno-against-ENOENT-because-this-test.patch +kodi/0012-The-baseline-of-the-i386-port-does-not-include-SSE.patch +kodi/0013-Disable-GetCPUFrequency-test.patch +kodi/0014-Fix-C++-example-includes.patch +kodi/0015-debian-cross-compile.patch +kodi/0016-ports-architectures.patch +libdvdnav/0001-libdvdnav-PR48-enen92.patch +libdvdread/0001-libdvdread-PR40-enen92.patch +libdvdread/debian-0001-libdvdcss.patch +libdvdread/debian-0002-descriptor.patch +cdatetime-std-chrono/0001-Replace-Kodi-date-time-implementation-with-std-c.patch +workarounds/0001-Workaround-989814.patch +workarounds/0002-ffmpeg5.patch +workarounds/0003-xbmc-libdvd_vfs-enen92.patch +workarounds/0004-ffmpeg6.patch +workarounds/0005-pcre2.patch +workarounds/0006-loongarch.patch +workarounds/0007-swig.patch diff --git a/debian/patches/workarounds/0001-Workaround-989814.patch b/debian/patches/workarounds/0001-Workaround-989814.patch new file mode 100644 index 0000000..aac9c94 --- /dev/null +++ b/debian/patches/workarounds/0001-Workaround-989814.patch @@ -0,0 +1,71 @@ +From 82880587b3a578d61e8335199f316e6794750ba6 Mon Sep 17 00:00:00 2001 +From: Vasyl Gello <vasek.gello@gmail.com> +Date: Fri, 25 Jun 2021 01:37:02 +0000 +Subject: [PATCH 1/2] Check if applied locale correctly lowers chars and + fallback + +.. to default region if it does not. + +Fixes #19883. + +Signed-off-by: Vasyl Gello <vasek.gello@gmail.com> +--- + xbmc/LangInfo.cpp | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/xbmc/LangInfo.cpp b/xbmc/LangInfo.cpp +index 24f0419cfe..1c93ebf440 100644 +--- a/xbmc/LangInfo.cpp ++++ b/xbmc/LangInfo.cpp +@@ -981,6 +981,18 @@ void CLangInfo::SetCurrentRegion(const std::string& strName) + + m_currentRegion->SetGlobalLocale(); + ++ // Check if locale is affected by "Turkish I" ++ // See https://github.com/xbmc/xbmc/issue/19883 for details ++ if (std::tolower('i') != std::tolower('I')) ++ { ++ CLog::Log( ++ LOGWARNING, ++ "region '{}' is affected by 'Turkish I' problem - falling back to default region '{}'", ++ m_currentRegion->m_strName, m_defaultRegion.m_strName); ++ m_currentRegion = &m_defaultRegion; ++ m_currentRegion->SetGlobalLocale(); ++ } ++ + const std::shared_ptr<CSettings> settings = CServiceBroker::GetSettingsComponent()->GetSettings(); + if (settings->GetString(CSettings::SETTING_LOCALE_SHORTDATEFORMAT) == SETTING_REGIONAL_DEFAULT) + SetShortDateFormat(m_currentRegion->m_strDateFormatShort); +-- +2.33.0 + + +From 2be9ed286e1478c7b1a3002242330b6101492621 Mon Sep 17 00:00:00 2001 +From: Vasyl Gello <vasek.gello@gmail.com> +Date: Sun, 27 Jun 2021 19:31:39 +0000 +Subject: [PATCH 2/2] kodi.sh.in: Unset LC_{ALL,CTYPE}, LANG + +Signed-off-by: Vasyl Gello <vasek.gello@gmail.com> +--- + tools/Linux/kodi.sh.in | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/tools/Linux/kodi.sh.in b/tools/Linux/kodi.sh.in +index 108c0b007b..b148fd49ee 100644 +--- a/tools/Linux/kodi.sh.in ++++ b/tools/Linux/kodi.sh.in +@@ -171,6 +171,11 @@ if command_exists gdb; then + fi + fi + ++ ++# Check if locale is affected by "Turkish I" ++# See https://github.com/xbmc/xbmc/issue/19883 for details ++unset LC_CTYPE LC_ALL LANG ++ + LOOP=1 + while [ $(( $LOOP )) = "1" ] + do +-- +2.33.0 + diff --git a/debian/patches/workarounds/0002-ffmpeg5.patch b/debian/patches/workarounds/0002-ffmpeg5.patch new file mode 100644 index 0000000..64c31d2 --- /dev/null +++ b/debian/patches/workarounds/0002-ffmpeg5.patch @@ -0,0 +1,2429 @@ +From 2218c1c37c16df4ce3da34c8566f5e1335a66c01 Mon Sep 17 00:00:00 2001 +From: Alwin Esch <alwin.esch@web.de> +Date: Sun, 10 Jul 2022 18:59:52 +0200 +Subject: [PATCH 1/3] FFmpeg5 port + +--- + xbmc/cdrip/EncoderFFmpeg.cpp | 95 ++++++--------- + xbmc/cdrip/EncoderFFmpeg.h | 1 - + .../AudioEngine/Encoders/AEEncoderFFmpeg.cpp | 111 +++++++++++------- + .../AudioEngine/Engines/ActiveAE/ActiveAE.cpp | 14 +-- + xbmc/cores/FFmpeg.cpp | 14 ++- + xbmc/cores/FFmpeg.h | 26 ++++ + .../DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp | 12 +- + .../Overlay/DVDOverlayCodecFFmpeg.cpp | 3 +- + .../DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp | 36 +++++- + .../DVDCodecs/Video/DVDVideoPPFFmpeg.cpp | 5 + + .../VideoPlayer/DVDCodecs/Video/VAAPI.cpp | 10 +- + .../DVDDemuxers/DVDDemuxClient.cpp | 3 +- + .../DVDDemuxers/DVDDemuxFFmpeg.cpp | 71 +++++++++-- + .../DVDInputStreams/InputStreamAddon.cpp | 3 +- + xbmc/filesystem/AudioBookFileDirectory.cpp | 3 +- + xbmc/guilib/FFmpegImage.cpp | 6 +- + xbmc/music/tags/MusicInfoTagLoaderFFmpeg.cpp | 2 +- + xbmc/video/tags/VideoTagLoaderFFmpeg.cpp | 2 +- + 18 files changed, 281 insertions(+), 136 deletions(-) + +diff --git a/xbmc/cdrip/EncoderFFmpeg.cpp b/xbmc/cdrip/EncoderFFmpeg.cpp +index 2867b7cb67..4c0628b5cc 100644 +--- a/xbmc/cdrip/EncoderFFmpeg.cpp ++++ b/xbmc/cdrip/EncoderFFmpeg.cpp +@@ -11,6 +11,7 @@ + #include "ServiceBroker.h" + #include "addons/Addon.h" + #include "addons/AddonManager.h" ++#include "cores/FFmpeg.h" + #include "settings/Settings.h" + #include "settings/SettingsComponent.h" + #include "utils/StringUtils.h" +@@ -19,23 +20,8 @@ + #include "utils/log.h" + + using namespace KODI::CDRIP; +- +-namespace +-{ +- +-struct EncoderException : public std::exception +-{ +- std::string s; +- template<typename... Args> +- EncoderException(const std::string& fmt, Args&&... args) +- : s(StringUtils::Format(fmt, std::forward<Args>(args)...)) +- { +- } +- ~EncoderException() throw() {} // Updated +- const char* what() const throw() { return s.c_str(); } +-}; +- +-} /* namespace */ ++using FFMPEG_HELP_TOOLS::FFMpegErrorToString; ++using FFMPEG_HELP_TOOLS::FFMpegException; + + bool CEncoderFFmpeg::Init() + { +@@ -54,7 +40,7 @@ bool CEncoderFFmpeg::Init() + } + else + { +- throw EncoderException("Could not get add-on: {}", addonId); ++ throw FFMpegException("Could not get add-on: {}", addonId); + } + + // Hack fix about PTS on generated files. +@@ -66,45 +52,45 @@ bool CEncoderFFmpeg::Init() + else if (addonId == "audioencoder.kodi.builtin.wma") + m_samplesCountMultiply = 1000; + else +- throw EncoderException("Internal add-on id \"{}\" not known as usable", addonId); ++ throw FFMpegException("Internal add-on id \"{}\" not known as usable", addonId); + + const std::string filename = URIUtils::GetFileName(m_strFile); + + m_formatCtx = avformat_alloc_context(); + if (!m_formatCtx) +- throw EncoderException("Could not allocate output format context"); ++ throw FFMpegException("Could not allocate output format context"); + + m_bcBuffer = static_cast<uint8_t*>(av_malloc(BUFFER_SIZE + AV_INPUT_BUFFER_PADDING_SIZE)); + if (!m_bcBuffer) +- throw EncoderException("Could not allocate buffer"); ++ throw FFMpegException("Could not allocate buffer"); + + m_formatCtx->pb = avio_alloc_context(m_bcBuffer, BUFFER_SIZE, AVIO_FLAG_WRITE, this, nullptr, + avio_write_callback, avio_seek_callback); + if (!m_formatCtx->pb) +- throw EncoderException("Failed to allocate ByteIOContext"); ++ throw FFMpegException("Failed to allocate ByteIOContext"); + + /* Guess the desired container format based on the file extension. */ + m_formatCtx->oformat = av_guess_format(nullptr, filename.c_str(), nullptr); + if (!m_formatCtx->oformat) +- throw EncoderException("Could not find output file format"); ++ throw FFMpegException("Could not find output file format"); + + m_formatCtx->url = av_strdup(filename.c_str()); + if (!m_formatCtx->url) +- throw EncoderException("Could not allocate url"); ++ throw FFMpegException("Could not allocate url"); + + /* Find the encoder to be used by its name. */ +- AVCodec* codec = avcodec_find_encoder(m_formatCtx->oformat->audio_codec); ++ FFMPEG_FMT_CONST AVCodec* codec = avcodec_find_encoder(m_formatCtx->oformat->audio_codec); + if (!codec) +- throw EncoderException("Unable to find a suitable FFmpeg encoder"); ++ throw FFMpegException("Unable to find a suitable FFmpeg encoder"); + + /* Create a new audio stream in the output file container. */ + m_stream = avformat_new_stream(m_formatCtx, nullptr); + if (!m_stream) +- throw EncoderException("Failed to allocate AVStream context"); ++ throw FFMpegException("Failed to allocate AVStream context"); + + m_codecCtx = avcodec_alloc_context3(codec); + if (!m_codecCtx) +- throw EncoderException("Failed to allocate the encoder context"); ++ throw FFMpegException("Failed to allocate the encoder context"); + + /* Set the basic encoder parameters. + * The input file's sample rate is used to avoid a sample rate conversion. */ +@@ -128,14 +114,14 @@ bool CEncoderFFmpeg::Init() + + int err = avcodec_open2(m_codecCtx, codec, nullptr); + if (err < 0) +- throw EncoderException("Failed to open the codec {} (error '{}')", +- codec->long_name ? codec->long_name : codec->name, +- FFmpegErrorToString(err)); ++ throw FFMpegException("Failed to open the codec {} (error '{}')", ++ codec->long_name ? codec->long_name : codec->name, ++ FFMpegErrorToString(err)); + + err = avcodec_parameters_from_context(m_stream->codecpar, m_codecCtx); + if (err < 0) +- throw EncoderException("Failed to copy encoder parameters to output stream (error '{}')", +- FFmpegErrorToString(err)); ++ throw FFMpegException("Failed to copy encoder parameters to output stream (error '{}')", ++ FFMpegErrorToString(err)); + + m_inFormat = GetInputFormat(m_iInBitsPerSample); + m_outFormat = m_codecCtx->sample_fmt; +@@ -150,7 +136,7 @@ bool CEncoderFFmpeg::Init() + + m_bufferFrame = av_frame_alloc(); + if (!m_bufferFrame || !m_buffer) +- throw EncoderException("Failed to allocate necessary buffers"); ++ throw FFMpegException("Failed to allocate necessary buffers"); + + m_bufferFrame->nb_samples = m_codecCtx->frame_size; + m_bufferFrame->format = m_inFormat; +@@ -159,8 +145,8 @@ bool CEncoderFFmpeg::Init() + + err = av_frame_get_buffer(m_bufferFrame, 0); + if (err < 0) +- throw EncoderException("Could not allocate output frame samples (error '{}')", +- FFmpegErrorToString(err)); ++ throw FFMpegException("Could not allocate output frame samples (error '{}')", ++ FFMpegErrorToString(err)); + + avcodec_fill_audio_frame(m_bufferFrame, m_iInChannels, m_inFormat, m_buffer, m_neededBytes, 0); + +@@ -170,14 +156,14 @@ bool CEncoderFFmpeg::Init() + m_codecCtx->sample_rate, m_codecCtx->channel_layout, m_inFormat, + m_codecCtx->sample_rate, 0, nullptr); + if (!m_swrCtx || swr_init(m_swrCtx) < 0) +- throw EncoderException("Failed to initialize the resampler"); ++ throw FFMpegException("Failed to initialize the resampler"); + + m_resampledBufferSize = + av_samples_get_buffer_size(nullptr, m_iInChannels, m_neededFrames, m_outFormat, 0); + m_resampledBuffer = static_cast<uint8_t*>(av_malloc(m_resampledBufferSize)); + m_resampledFrame = av_frame_alloc(); + if (!m_resampledBuffer || !m_resampledFrame) +- throw EncoderException("Failed to allocate a frame for resampling"); ++ throw FFMpegException("Failed to allocate a frame for resampling"); + + m_resampledFrame->nb_samples = m_neededFrames; + m_resampledFrame->format = m_outFormat; +@@ -186,8 +172,8 @@ bool CEncoderFFmpeg::Init() + + err = av_frame_get_buffer(m_resampledFrame, 0); + if (err < 0) +- throw EncoderException("Could not allocate output resample frame samples (error '{}')", +- FFmpegErrorToString(err)); ++ throw FFMpegException("Could not allocate output resample frame samples (error '{}')", ++ FFMpegErrorToString(err)); + + avcodec_fill_audio_frame(m_resampledFrame, m_iInChannels, m_outFormat, m_resampledBuffer, + m_resampledBufferSize, 0); +@@ -204,7 +190,7 @@ bool CEncoderFFmpeg::Init() + /* write the header */ + err = avformat_write_header(m_formatCtx, nullptr); + if (err != 0) +- throw EncoderException("Failed to write the header (error '{}')", FFmpegErrorToString(err)); ++ throw FFMpegException("Failed to write the header (error '{}')", FFMpegErrorToString(err)); + + CLog::Log(LOGDEBUG, "CEncoderFFmpeg::{} - Successfully initialized with muxer {} and codec {}", + __func__, +@@ -212,7 +198,7 @@ bool CEncoderFFmpeg::Init() + : m_formatCtx->oformat->name, + codec->long_name ? codec->long_name : codec->name); + } +- catch (EncoderException& caught) ++ catch (const FFMpegException& caught) + { + CLog::Log(LOGERROR, "CEncoderFFmpeg::{} - {}", __func__, caught.what()); + +@@ -299,7 +285,7 @@ bool CEncoderFFmpeg::WriteFrame() + if (swr_convert(m_swrCtx, m_resampledFrame->data, m_neededFrames, + const_cast<const uint8_t**>(m_bufferFrame->extended_data), + m_neededFrames) < 0) +- throw EncoderException("Error resampling audio"); ++ throw FFMpegException("Error resampling audio"); + + frame = m_resampledFrame; + } +@@ -316,8 +302,8 @@ bool CEncoderFFmpeg::WriteFrame() + m_bufferSize = 0; + err = avcodec_send_frame(m_codecCtx, frame); + if (err < 0) +- throw EncoderException("Error sending a frame for encoding (error '{}')", __func__, +- FFmpegErrorToString(err)); ++ throw FFMpegException("Error sending a frame for encoding (error '{}')", ++ FFMpegErrorToString(err)); + + while (err >= 0) + { +@@ -329,19 +315,18 @@ bool CEncoderFFmpeg::WriteFrame() + } + else if (err < 0) + { +- throw EncoderException("Error during encoding (error '{}')", __func__, +- FFmpegErrorToString(err)); ++ throw FFMpegException("Error during encoding (error '{}')", FFMpegErrorToString(err)); + } + + err = av_write_frame(m_formatCtx, pkt); + if (err < 0) +- throw EncoderException("Failed to write the frame data (error '{}')", __func__, +- FFmpegErrorToString(err)); ++ throw FFMpegException("Failed to write the frame data (error '{}')", ++ FFMpegErrorToString(err)); + + av_packet_unref(pkt); + } + } +- catch (EncoderException& caught) ++ catch (const FFMpegException& caught) + { + CLog::Log(LOGERROR, "CEncoderFFmpeg::{} - {}", __func__, caught.what()); + } +@@ -400,14 +385,6 @@ AVSampleFormat CEncoderFFmpeg::GetInputFormat(int inBitsPerSample) + case 32: + return AV_SAMPLE_FMT_S32; + default: +- throw EncoderException("Invalid input bits per sample"); ++ throw FFMpegException("Invalid input bits per sample"); + } + } +- +-std::string CEncoderFFmpeg::FFmpegErrorToString(int err) +-{ +- std::string text; +- text.reserve(AV_ERROR_MAX_STRING_SIZE); +- av_strerror(err, text.data(), AV_ERROR_MAX_STRING_SIZE); +- return text; +-} +diff --git a/xbmc/cdrip/EncoderFFmpeg.h b/xbmc/cdrip/EncoderFFmpeg.h +index 39112ba3ba..0c2391c7ab 100644 +--- a/xbmc/cdrip/EncoderFFmpeg.h ++++ b/xbmc/cdrip/EncoderFFmpeg.h +@@ -39,7 +39,6 @@ private: + void SetTag(const std::string& tag, const std::string& value); + bool WriteFrame(); + AVSampleFormat GetInputFormat(int inBitsPerSample); +- std::string FFmpegErrorToString(int err); + + AVFormatContext* m_formatCtx{nullptr}; + AVCodecContext* m_codecCtx{nullptr}; +diff --git a/xbmc/cores/AudioEngine/Encoders/AEEncoderFFmpeg.cpp b/xbmc/cores/AudioEngine/Encoders/AEEncoderFFmpeg.cpp +index 09bb26a327..86f65f57f3 100644 +--- a/xbmc/cores/AudioEngine/Encoders/AEEncoderFFmpeg.cpp ++++ b/xbmc/cores/AudioEngine/Encoders/AEEncoderFFmpeg.cpp +@@ -10,13 +10,24 @@ + #define DTS_ENCODE_BITRATE 1411200 + + #include "cores/AudioEngine/Encoders/AEEncoderFFmpeg.h" +-#include "cores/AudioEngine/Utils/AEUtil.h" ++ + #include "ServiceBroker.h" +-#include "utils/log.h" ++#include "cores/AudioEngine/Utils/AEUtil.h" ++#include "cores/FFmpeg.h" + #include "settings/Settings.h" + #include "settings/SettingsComponent.h" +-#include <string.h> ++#include "utils/log.h" ++ ++extern "C" ++{ ++#include <libavutil/channel_layout.h> ++} ++ + #include <cassert> ++#include <string.h> ++ ++using FFMPEG_HELP_TOOLS::FFMpegErrorToString; ++using FFMPEG_HELP_TOOLS::FFMpegException; + + CAEEncoderFFmpeg::CAEEncoderFFmpeg() : m_CodecCtx(NULL), m_SwrCtx(NULL) + { +@@ -81,7 +92,7 @@ bool CAEEncoderFFmpeg::Initialize(AEAudioFormat &format, bool allow_planar_input + + bool ac3 = CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_AUDIOOUTPUT_AC3PASSTHROUGH); + +- AVCodec *codec = NULL; ++ FFMPEG_FMT_CONST AVCodec* codec = nullptr; + + /* fallback to ac3 if we support it, we might not have DTS support */ + if (ac3) +@@ -242,63 +253,77 @@ unsigned int CAEEncoderFFmpeg::GetFrames() + + int CAEEncoderFFmpeg::Encode(uint8_t *in, int in_size, uint8_t *out, int out_size) + { +- int got_output; +- AVFrame *frame; ++ int size = 0; ++ int err = AVERROR_UNKNOWN; ++ AVFrame* frame = nullptr; ++ AVPacket* pkt = nullptr; + + if (!m_CodecCtx) +- return 0; +- +- /* allocate the input frame +- * sadly, we have to alloc/dealloc it everytime since we have no guarantee the +- * data argument will be constant over iterated calls and the frame needs to +- * setup pointers inside data */ +- frame = av_frame_alloc(); +- if (!frame) +- return 0; ++ return size; + +- frame->nb_samples = m_CodecCtx->frame_size; +- frame->format = m_CodecCtx->sample_fmt; +- frame->channel_layout = m_CodecCtx->channel_layout; +- frame->channels = m_CodecCtx->channels; ++ try ++ { ++ /* allocate the input frame and output packet ++ * sadly, we have to alloc/dealloc it everytime since we have no guarantee the ++ * data argument will be constant over iterated calls and the frame needs to ++ * setup pointers inside data */ ++ frame = av_frame_alloc(); ++ pkt = av_packet_alloc(); ++ if (!frame || !pkt) ++ throw FFMpegException( ++ "Failed to allocate \"AVFrame\" or \"AVPacket\" for encoding (error '{}')", ++ strerror(errno)); ++ ++ frame->nb_samples = m_CodecCtx->frame_size; ++ frame->format = m_CodecCtx->sample_fmt; ++ frame->channel_layout = m_CodecCtx->channel_layout; ++ frame->channels = m_CodecCtx->channels; ++ ++ avcodec_fill_audio_frame(frame, m_CodecCtx->channels, m_CodecCtx->sample_fmt, in, in_size, 0); ++ ++ pkt->size = out_size; ++ pkt->data = out; ++ ++ /* encode it */ ++ err = avcodec_send_frame(m_CodecCtx, frame); ++ if (err < 0) ++ throw FFMpegException("Error sending a frame for encoding (error '{}')", ++ FFMpegErrorToString(err)); ++ ++ while (err >= 0) ++ { ++ err = avcodec_receive_packet(m_CodecCtx, pkt); ++ if (err == AVERROR(EAGAIN) || err == AVERROR_EOF) ++ { ++ av_frame_free(&frame); ++ av_packet_free(&pkt); ++ return (err == AVERROR(EAGAIN)) ? -1 : 0; ++ } ++ else if (err < 0) ++ { ++ throw FFMpegException("Error during encoding (error '{}')", FFMpegErrorToString(err)); ++ } + +- avcodec_fill_audio_frame(frame, m_CodecCtx->channels, m_CodecCtx->sample_fmt, +- in, in_size, 0); ++ av_packet_unref(pkt); ++ } + +- /* initialize the output packet */ +- AVPacket* pkt = av_packet_alloc(); +- if (!pkt) ++ size = pkt->size; ++ } ++ catch (const FFMpegException& caught) + { +- CLog::Log(LOGERROR, "CAEEncoderFFmpeg::{} - av_packet_alloc failed: {}", __FUNCTION__, +- strerror(errno)); +- av_frame_free(&frame); +- return 0; ++ CLog::Log(LOGERROR, "CAEEncoderFFmpeg::{} - {}", __func__, caught.what()); + } + +- pkt->size = out_size; +- pkt->data = out; +- +- /* encode it */ +- int ret = avcodec_encode_audio2(m_CodecCtx, pkt, frame, &got_output); +- +- int size = pkt->size; +- + /* free temporary data */ + av_frame_free(&frame); + + /* free the packet */ + av_packet_free(&pkt); + +- if (ret < 0 || !got_output) +- { +- CLog::Log(LOGERROR, "CAEEncoderFFmpeg::Encode - Encoding failed"); +- return 0; +- } +- + /* return the number of frames used */ + return size; + } + +- + int CAEEncoderFFmpeg::GetData(uint8_t **data) + { + int size; +diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp +index 3947dd5523..6000fe9c63 100644 +--- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp ++++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp +@@ -16,17 +16,17 @@ using namespace ActiveAE; + #include "ActiveAESound.h" + #include "ActiveAEStream.h" + #include "ServiceBroker.h" ++#include "cores/AudioEngine/AEResampleFactory.h" ++#include "cores/AudioEngine/Encoders/AEEncoderFFmpeg.h" + #include "cores/AudioEngine/Interfaces/IAudioCallback.h" +-#include "cores/AudioEngine/Utils/AEUtil.h" + #include "cores/AudioEngine/Utils/AEStreamData.h" + #include "cores/AudioEngine/Utils/AEStreamInfo.h" +-#include "cores/AudioEngine/AEResampleFactory.h" +-#include "cores/AudioEngine/Encoders/AEEncoderFFmpeg.h" +- ++#include "cores/AudioEngine/Utils/AEUtil.h" ++#include "cores/FFmpeg.h" + #include "settings/Settings.h" + #include "settings/SettingsComponent.h" +-#include "windowing/WinSystem.h" + #include "utils/log.h" ++#include "windowing/WinSystem.h" + + using namespace std::chrono_literals; + +@@ -3016,8 +3016,8 @@ IAE::SoundPtr CActiveAE::MakeSound(const std::string& file) + AVFormatContext *fmt_ctx = nullptr; + AVCodecContext *dec_ctx = nullptr; + AVIOContext *io_ctx; +- AVInputFormat *io_fmt = nullptr; +- AVCodec *dec = nullptr; ++ FFMPEG_FMT_CONST AVInputFormat* io_fmt = nullptr; ++ FFMPEG_FMT_CONST AVCodec* dec = nullptr; + SampleConfig config; + + // No custom deleter until sound is registered +diff --git a/xbmc/cores/FFmpeg.cpp b/xbmc/cores/FFmpeg.cpp +index 03a29f7db4..de1765ed52 100644 +--- a/xbmc/cores/FFmpeg.cpp ++++ b/xbmc/cores/FFmpeg.cpp +@@ -21,6 +21,19 @@ + + static thread_local CFFmpegLog* CFFmpegLogTls; + ++namespace FFMPEG_HELP_TOOLS ++{ ++ ++std::string FFMpegErrorToString(int err) ++{ ++ std::string text; ++ text.resize(AV_ERROR_MAX_STRING_SIZE); ++ av_strerror(err, text.data(), AV_ERROR_MAX_STRING_SIZE); ++ return text; ++} ++ ++} // namespace FFMPEG_HELP_TOOLS ++ + void CFFmpegLog::SetLogLevel(int level) + { + CFFmpegLog::ClearLogLevel(); +@@ -116,4 +129,3 @@ void ff_avutil_log(void* ptr, int level, const char* format, va_list va) + } + buffer.erase(0, start); + } +- +diff --git a/xbmc/cores/FFmpeg.h b/xbmc/cores/FFmpeg.h +index e1194d19e9..8230701ba7 100644 +--- a/xbmc/cores/FFmpeg.h ++++ b/xbmc/cores/FFmpeg.h +@@ -10,6 +10,7 @@ + + #include "ServiceBroker.h" + #include "utils/CPUInfo.h" ++#include "utils/StringUtils.h" + + extern "C" { + #include <libavcodec/avcodec.h> +@@ -21,6 +22,31 @@ extern "C" { + #include <libpostproc/postprocess.h> + } + ++// https://github.com/FFmpeg/FFmpeg/blob/56450a0ee4/doc/APIchanges#L18-L26 ++#if LIBAVFORMAT_BUILD >= AV_VERSION_INT(59, 0, 100) ++#define FFMPEG_FMT_CONST const ++#else ++#define FFMPEG_FMT_CONST ++#endif ++ ++namespace FFMPEG_HELP_TOOLS ++{ ++ ++struct FFMpegException : public std::exception ++{ ++ std::string s; ++ template<typename... Args> ++ FFMpegException(const std::string& fmt, Args&&... args) ++ : s(StringUtils::Format(fmt, std::forward<Args>(args)...)) ++ { ++ } ++ const char* what() const noexcept override { return s.c_str(); } ++}; ++ ++std::string FFMpegErrorToString(int err); ++ ++} // namespace FFMPEG_HELP_TOOLS ++ + inline int PPCPUFlags() + { + unsigned int cpuFeatures = CServiceBroker::GetCPUInfo()->GetCPUFeatures(); +diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp +index 25f3f08e1f..87e7ae2c57 100644 +--- a/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp ++++ b/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp +@@ -7,14 +7,16 @@ + */ + + #include "DVDAudioCodecFFmpeg.h" +-#include "ServiceBroker.h" ++ + #include "../../DVDStreamInfo.h" +-#include "utils/log.h" ++#include "DVDCodecs/DVDCodecs.h" ++#include "ServiceBroker.h" ++#include "cores/AudioEngine/Utils/AEUtil.h" ++#include "cores/FFmpeg.h" + #include "settings/AdvancedSettings.h" + #include "settings/Settings.h" + #include "settings/SettingsComponent.h" +-#include "DVDCodecs/DVDCodecs.h" +-#include "cores/AudioEngine/Utils/AEUtil.h" ++#include "utils/log.h" + + extern "C" { + #include <libavutil/opt.h> +@@ -44,7 +46,7 @@ bool CDVDAudioCodecFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options + return false; + } + +- AVCodec* pCodec = NULL; ++ FFMPEG_FMT_CONST AVCodec* pCodec = nullptr; + bool allowdtshddecode = true; + + // set any special options +diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Overlay/DVDOverlayCodecFFmpeg.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Overlay/DVDOverlayCodecFFmpeg.cpp +index 8c26cad306..3657fc093c 100644 +--- a/xbmc/cores/VideoPlayer/DVDCodecs/Overlay/DVDOverlayCodecFFmpeg.cpp ++++ b/xbmc/cores/VideoPlayer/DVDCodecs/Overlay/DVDOverlayCodecFFmpeg.cpp +@@ -10,6 +10,7 @@ + + #include "DVDOverlayImage.h" + #include "DVDStreamInfo.h" ++#include "cores/FFmpeg.h" + #include "cores/VideoPlayer/Interface/DemuxPacket.h" + #include "cores/VideoPlayer/Interface/TimingConstants.h" + #include "utils/EndianSwap.h" +@@ -39,7 +40,7 @@ bool CDVDOverlayCodecFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &optio + if (hints.codec == AV_CODEC_ID_EIA_608) + return false; + +- AVCodec* pCodec = avcodec_find_decoder(hints.codec); ++ FFMPEG_FMT_CONST AVCodec* pCodec = avcodec_find_decoder(hints.codec); + if (!pCodec) + { + CLog::Log(LOGDEBUG, "{} - Unable to find codec {}", __FUNCTION__, hints.codec); +diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp +index 881c02ec12..21b5e834b2 100644 +--- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp ++++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp +@@ -12,6 +12,7 @@ + #include "DVDCodecs/DVDFactoryCodec.h" + #include "DVDStreamInfo.h" + #include "ServiceBroker.h" ++#include "cores/FFmpeg.h" + #include "cores/VideoPlayer/Interface/TimingConstants.h" + #include "cores/VideoPlayer/VideoRenderers/RenderManager.h" + #include "cores/VideoSettings.h" +@@ -27,12 +28,13 @@ + #include <mutex> + + extern "C" { +-#include <libavutil/opt.h> +-#include <libavutil/mastering_display_metadata.h> + #include <libavfilter/avfilter.h> + #include <libavfilter/buffersink.h> + #include <libavfilter/buffersrc.h> ++#include <libavutil/mastering_display_metadata.h> ++#include <libavutil/opt.h> + #include <libavutil/pixdesc.h> ++#include <libavutil/video_enc_params.h> + } + + #ifndef TARGET_POSIX +@@ -327,7 +329,7 @@ bool CDVDVideoCodecFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options + m_hints = hints; + m_options = options; + +- AVCodec* pCodec = nullptr; ++ FFMPEG_FMT_CONST AVCodec* pCodec = nullptr; + + m_iOrientation = hints.orientation; + +@@ -1048,6 +1050,33 @@ bool CDVDVideoCodecFFmpeg::GetPictureCommon(VideoPicture* pVideoPicture) + pVideoPicture->qscale_type = 0; + + AVFrameSideData* sd; ++ ++ // https://github.com/FFmpeg/FFmpeg/blob/991d417692/doc/APIchanges#L18-L20 ++ // basilgello: AV_VIDEO_ENC_PARAMS_MPEG2 is introduced in 4.4! ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(58, 134, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(56, 45, 100) ++ sd = av_frame_get_side_data(m_pFrame, AV_FRAME_DATA_VIDEO_ENC_PARAMS); ++ if (sd) ++ { ++ unsigned int mb_h = (m_pFrame->height + 15) / 16; ++ unsigned int mb_w = (m_pFrame->width + 15) / 16; ++ unsigned int nb_mb = mb_h * mb_w; ++ unsigned int block_idx; ++ ++ auto par = reinterpret_cast<AVVideoEncParams*>(sd->data); ++ if (par->type == AV_VIDEO_ENC_PARAMS_MPEG2 && (par->nb_blocks == 0 || par->nb_blocks == nb_mb)) ++ { ++ pVideoPicture->qstride = mb_w; ++ pVideoPicture->qscale_type = par->type; ++ pVideoPicture->qp_table = static_cast<int8_t*>(av_malloc(nb_mb)); ++ for (block_idx = 0; block_idx < nb_mb; block_idx++) ++ { ++ AVVideoBlockParams* b = av_video_enc_params_block(par, block_idx); ++ pVideoPicture->qp_table[block_idx] = par->qp + b->delta_qp; ++ } ++ } ++ } ++#else + sd = av_frame_get_side_data(m_pFrame, AV_FRAME_DATA_QP_TABLE_PROPERTIES); + if (sd) + { +@@ -1068,6 +1097,7 @@ bool CDVDVideoCodecFFmpeg::GetPictureCommon(VideoPicture* pVideoPicture) + pVideoPicture->qscale_type = qp->type; + } + } ++#endif + + pVideoPicture->pict_type = m_pFrame->pict_type; + +diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoPPFFmpeg.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoPPFFmpeg.cpp +index a98fbb1710..3b2739cd22 100644 +--- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoPPFFmpeg.cpp ++++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoPPFFmpeg.cpp +@@ -118,6 +118,11 @@ void CDVDVideoPPFFmpeg::Process(VideoPicture* pPicture) + m_pMode, m_pContext, + pSource->pict_type | pSource->qscale_type ? PP_PICT_TYPE_QP2 : 0); + ++ // https://github.com/FFmpeg/FFmpeg/blob/991d417692/doc/APIchanges#L18-L20 ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(58, 84, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(56, 45, 100) ++ av_free(pSource->qp_table); ++#endif + + pPicture->SetParams(*pSource); + if (pPicture->videoBuffer) +diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.cpp +index 7ad891083c..eaf7b78d32 100644 +--- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.cpp ++++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.cpp +@@ -1259,8 +1259,16 @@ void CDecoder::ReturnRenderPicture(CVaapiRenderPicture *renderPic) + + IHardwareDecoder* CDecoder::Create(CDVDStreamInfo &hint, CProcessInfo &processInfo, AVPixelFormat fmt) + { +- if (fmt == AV_PIX_FMT_VAAPI_VLD && CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(SETTING_VIDEOPLAYER_USEVAAPI)) ++ // https://github.com/FFmpeg/FFmpeg/blob/56450a0ee4fdda160f4039fc2ae33edfd27765c9/doc/APIchanges#L18-L26 ++#if LIBAVUTIL_BUILD >= AV_VERSION_INT(55, 8, 0) ++#define PIX_FMT_VAAPI AV_PIX_FMT_VAAPI ++#else ++#define PIX_FMT_VAAPI AV_PIX_FMT_VAAPI_VLD ++#endif ++ if (fmt == PIX_FMT_VAAPI && ++ CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(SETTING_VIDEOPLAYER_USEVAAPI)) + return new VAAPI::CDecoder(processInfo); ++#undef PIX_FMT_VAAPI + + return nullptr; + } +diff --git a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp +index 2bdc3ea5a9..5be134e381 100644 +--- a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp ++++ b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp +@@ -10,6 +10,7 @@ + + #include "DVDDemuxUtils.h" + #include "DVDInputStreams/DVDInputStream.h" ++#include "cores/FFmpeg.h" + #include "cores/VideoPlayer/Interface/TimingConstants.h" + #include "utils/log.h" + +@@ -130,7 +131,7 @@ bool CDVDDemuxClient::ParsePacket(DemuxPacket* pkt) + + if (stream->m_context == nullptr) + { +- AVCodec *codec = avcodec_find_decoder(st->codec); ++ FFMPEG_FMT_CONST AVCodec* codec = avcodec_find_decoder(st->codec); + if (codec == nullptr) + { + CLog::Log(LOGERROR, "{} - can't find decoder", __FUNCTION__); +diff --git a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp +index 739bf51922..bf6f322274 100644 +--- a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp ++++ b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp +@@ -38,6 +38,7 @@ + + extern "C" + { ++#include "libavutil/channel_layout.h" + #include "libavutil/pixdesc.h" + } + +@@ -235,7 +236,7 @@ bool CDVDDemuxFFmpeg::Aborted() + + bool CDVDDemuxFFmpeg::Open(const std::shared_ptr<CDVDInputStream>& pInput, bool fileinfo) + { +- AVInputFormat* iformat = NULL; ++ FFMPEG_FMT_CONST AVInputFormat* iformat = nullptr; + std::string strFile; + m_streaminfo = !pInput->IsRealtime() && !m_reopen; + m_reopen = false; +@@ -422,9 +423,7 @@ bool CDVDDemuxFFmpeg::Open(const std::shared_ptr<CDVDInputStream>& pInput, bool + // is present, we assume it is PCM audio. + // AC3 is always wrapped in iec61937 (ffmpeg "spdif"), while DTS + // may be just padded. +- AVInputFormat* iformat2; +- iformat2 = av_find_input_format("spdif"); +- ++ FFMPEG_FMT_CONST AVInputFormat* iformat2 = av_find_input_format("spdif"); + if (iformat2 && iformat2->read_probe(&pd) > AVPROBE_SCORE_MAX / 4) + { + iformat = iformat2; +@@ -544,11 +543,14 @@ bool CDVDDemuxFFmpeg::Open(const std::shared_ptr<CDVDInputStream>& pInput, bool + m_streaminfo = true; + } + ++ // https://github.com/FFmpeg/FFmpeg/blob/56450a0ee4/doc/APIchanges#L18-L26 ++#if LIBAVFORMAT_BUILD < AV_VERSION_INT(59, 0, 100) + if (iformat && (strcmp(iformat->name, "mov,mp4,m4a,3gp,3g2,mj2") == 0)) + { + if (URIUtils::IsRemote(strFile)) + m_pFormatContext->iformat->flags |= AVFMT_NOGENSEARCH; + } ++#endif + + // we need to know if this is matroska, avi or sup later + m_bMatroska = strncmp(m_pFormatContext->iformat->name, "matroska", 8) == 0; // for "matroska.webm" +@@ -604,8 +606,11 @@ bool CDVDDemuxFFmpeg::Open(const std::shared_ptr<CDVDInputStream>& pInput, bool + // if format can be nonblocking, let's use that + m_pFormatContext->flags |= AVFMT_FLAG_NONBLOCK; + +- // deprecated, will be always set in future versions ++ // https://github.com/FFmpeg/FFmpeg/blob/d682ae70b4/doc/APIchanges#L18-L21 ++#if LIBAVFORMAT_BUILD < AV_VERSION_INT(57, 66, 105) && \ ++ LIBAVCODEC_BUILD < AV_VERSION_INT(57, 83, 101) + m_pFormatContext->flags |= AVFMT_FLAG_KEEP_SIDE_DATA; ++#endif + + UpdateCurrentPTS(); + +@@ -647,12 +652,24 @@ bool CDVDDemuxFFmpeg::Open(const std::shared_ptr<CDVDInputStream>& pInput, bool + { + int idx = m_pFormatContext->programs[i]->stream_index[j]; + AVStream* st = m_pFormatContext->streams[idx]; ++#if LIBAVFORMAT_BUILD >= AV_VERSION_INT(59, 3, 100) ++ // Related to https://patchwork.ffmpeg.org/project/ffmpeg/patch/20210429143825.53040-1-jamrial@gmail.com/ ++ // has been replaced with AVSTREAM_EVENT_FLAG_NEW_PACKETS. ++ if ((st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && ++ (st->event_flags & AVSTREAM_EVENT_FLAG_NEW_PACKETS)) || ++ (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && st->codecpar->sample_rate > 0)) ++ { ++ nProgram = i; ++ break; ++ } ++#else + if ((st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && st->codec_info_nb_frames > 0) || + (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && st->codecpar->sample_rate > 0)) + { + nProgram = i; + break; + } ++#endif + } + } + } +@@ -1401,11 +1418,19 @@ void CDVDDemuxFFmpeg::UpdateCurrentPTS() + if (idx >= 0) + { + AVStream* stream = m_pFormatContext->streams[idx]; ++#if LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 17, 100) ++ if (stream && m_pkt.pkt.dts != (int64_t)AV_NOPTS_VALUE) ++ { ++ double ts = ConvertTimestamp(m_pkt.pkt.dts, stream->time_base.den, stream->time_base.num); ++ m_currentPts = ts; ++ } ++#else + if (stream && stream->cur_dts != (int64_t)AV_NOPTS_VALUE) + { + double ts = ConvertTimestamp(stream->cur_dts, stream->time_base.den, stream->time_base.num); + m_currentPts = ts; + } ++#endif + } + } + +@@ -1621,7 +1646,12 @@ CDemuxStream* CDVDDemuxFFmpeg::AddStream(int streamIdx) + st->iBitsPerSample = pStream->codecpar->bits_per_raw_sample; + st->iChannelLayout = pStream->codecpar->channel_layout; + char buf[32] = {}; ++ // https://github.com/FFmpeg/FFmpeg/blob/6ccc3989d15/doc/APIchanges#L50-L53 ++#if LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 24, 100) ++ av_channel_layout_describe(st->iChannelLayout, buf, sizeof(buf)); ++#else + av_get_channel_layout_string(buf, 31, st->iChannels, st->iChannelLayout); ++#endif + st->m_channelLayoutName = buf; + if (st->iBitsPerSample == 0) + st->iBitsPerSample = pStream->codecpar->bits_per_coded_sample; +@@ -1663,6 +1693,7 @@ CDemuxStream* CDVDDemuxFFmpeg::AddStream(int streamIdx) + st->iFpsScale = 0; + } + ++#if LIBAVFORMAT_BUILD < AV_VERSION_INT(59, 3, 100) + if (pStream->codec_info_nb_frames > 0 && + pStream->codec_info_nb_frames <= 2 && + m_pInput->IsStreamType(DVDSTREAM_TYPE_DVD)) +@@ -1672,6 +1703,7 @@ CDemuxStream* CDVDDemuxFFmpeg::AddStream(int streamIdx) + st->iFpsRate = 0; + st->iFpsScale = 0; + } ++#endif + + st->iWidth = pStream->codecpar->width; + st->iHeight = pStream->codecpar->height; +@@ -1693,7 +1725,12 @@ CDemuxStream* CDVDDemuxFFmpeg::AddStream(int streamIdx) + st->colorRange = pStream->codecpar->color_range; + st->hdr_type = DetermineHdrType(pStream); + ++ // https://github.com/FFmpeg/FFmpeg/blob/release/5.0/doc/APIchanges ++#if LIBAVFORMAT_BUILD >= AV_VERSION_INT(59, 10, 100) ++ size_t size = 0; ++#else + int size = 0; ++#endif + uint8_t* side_data = nullptr; + + side_data = av_stream_get_side_data(pStream, AV_PKT_DATA_MASTERING_DISPLAY_METADATA, &size); +@@ -2103,7 +2140,7 @@ std::string CDVDDemuxFFmpeg::GetStreamCodecName(int iStreamId) + return strName; + } + +- AVCodec* codec = avcodec_find_decoder(stream->codec); ++ FFMPEG_FMT_CONST AVCodec* codec = avcodec_find_decoder(stream->codec); + if (codec) + strName = avcodec_get_name(codec->id); + } +@@ -2279,7 +2316,7 @@ void CDVDDemuxFFmpeg::ParsePacket(AVPacket* pkt) + + parser->second->m_parserCtx = av_parser_init(st->codecpar->codec_id); + +- AVCodec* codec = avcodec_find_decoder(st->codecpar->codec_id); ++ FFMPEG_FMT_CONST AVCodec* codec = avcodec_find_decoder(st->codecpar->codec_id); + if (codec == nullptr) + { + CLog::Log(LOGERROR, "{} - can't find decoder", __FUNCTION__); +@@ -2357,7 +2394,12 @@ TRANSPORT_STREAM_STATE CDVDDemuxFFmpeg::TransportStreamAudioState() + { + if (!m_startTime) + { ++#if LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 17, 100) ++ m_startTime = ++ av_rescale(m_pkt.pkt.dts, st->time_base.num, st->time_base.den) - 0.000001; ++#else + m_startTime = av_rescale(st->cur_dts, st->time_base.num, st->time_base.den) - 0.000001; ++#endif + m_seekStream = idx; + } + return TRANSPORT_STREAM_STATE::READY; +@@ -2377,7 +2419,12 @@ TRANSPORT_STREAM_STATE CDVDDemuxFFmpeg::TransportStreamAudioState() + { + if (!m_startTime) + { ++#if LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 17, 100) ++ m_startTime = ++ av_rescale(m_pkt.pkt.dts, st->time_base.num, st->time_base.den) - 0.000001; ++#else + m_startTime = av_rescale(st->cur_dts, st->time_base.num, st->time_base.den) - 0.000001; ++#endif + m_seekStream = i; + } + return TRANSPORT_STREAM_STATE::READY; +@@ -2410,7 +2457,12 @@ TRANSPORT_STREAM_STATE CDVDDemuxFFmpeg::TransportStreamVideoState() + { + if (!m_startTime) + { ++#if LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 17, 100) ++ m_startTime = ++ av_rescale(m_pkt.pkt.dts, st->time_base.num, st->time_base.den) - 0.000001; ++#else + m_startTime = av_rescale(st->cur_dts, st->time_base.num, st->time_base.den) - 0.000001; ++#endif + m_seekStream = idx; + } + return TRANSPORT_STREAM_STATE::READY; +@@ -2430,7 +2482,12 @@ TRANSPORT_STREAM_STATE CDVDDemuxFFmpeg::TransportStreamVideoState() + { + if (!m_startTime) + { ++#if LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 17, 100) ++ m_startTime = ++ av_rescale(m_pkt.pkt.dts, st->time_base.num, st->time_base.den) - 0.000001; ++#else + m_startTime = av_rescale(st->cur_dts, st->time_base.num, st->time_base.den) - 0.000001; ++#endif + m_seekStream = i; + } + return TRANSPORT_STREAM_STATE::READY; +diff --git a/xbmc/cores/VideoPlayer/DVDInputStreams/InputStreamAddon.cpp b/xbmc/cores/VideoPlayer/DVDInputStreams/InputStreamAddon.cpp +index b8494e504e..392853cc68 100644 +--- a/xbmc/cores/VideoPlayer/DVDInputStreams/InputStreamAddon.cpp ++++ b/xbmc/cores/VideoPlayer/DVDInputStreams/InputStreamAddon.cpp +@@ -12,6 +12,7 @@ + #include "addons/addoninfo/AddonType.h" + #include "addons/binary-addons/AddonDll.h" + #include "addons/kodi-dev-kit/include/kodi/addon-instance/VideoCodec.h" ++#include "cores/FFmpeg.h" + #include "cores/VideoPlayer/DVDDemuxers/DVDDemux.h" + #include "cores/VideoPlayer/DVDDemuxers/DVDDemuxUtils.h" + #include "cores/VideoPlayer/Interface/DemuxCrypto.h" +@@ -392,7 +393,7 @@ KODI_HANDLE CInputStreamAddon::cb_get_stream_transfer(KODI_HANDLE handle, + return nullptr; + + std::string codecName(stream->m_codecName); +- AVCodec* codec = nullptr; ++ FFMPEG_FMT_CONST AVCodec* codec = nullptr; + + if (stream->m_streamType != INPUTSTREAM_TYPE_TELETEXT && + stream->m_streamType != INPUTSTREAM_TYPE_RDS && stream->m_streamType != INPUTSTREAM_TYPE_ID3) +diff --git a/xbmc/filesystem/AudioBookFileDirectory.cpp b/xbmc/filesystem/AudioBookFileDirectory.cpp +index 04d1c14343..d82b2a9bbd 100644 +--- a/xbmc/filesystem/AudioBookFileDirectory.cpp ++++ b/xbmc/filesystem/AudioBookFileDirectory.cpp +@@ -11,6 +11,7 @@ + #include "TextureDatabase.h" + #include "URL.h" + #include "Util.h" ++#include "cores/FFmpeg.h" + #include "filesystem/File.h" + #include "guilib/LocalizeStrings.h" + #include "music/tags/MusicInfoTag.h" +@@ -149,7 +150,7 @@ bool CAudioBookFileDirectory::ContainsFiles(const CURL& url) + + m_ioctx->max_packet_size = 32768; + +- AVInputFormat* iformat=nullptr; ++ FFMPEG_FMT_CONST AVInputFormat* iformat = nullptr; + av_probe_input_buffer(m_ioctx, &iformat, url.Get().c_str(), nullptr, 0, 0); + + bool contains = false; +diff --git a/xbmc/guilib/FFmpegImage.cpp b/xbmc/guilib/FFmpegImage.cpp +index fa255278b7..9d01a21f38 100644 +--- a/xbmc/guilib/FFmpegImage.cpp ++++ b/xbmc/guilib/FFmpegImage.cpp +@@ -52,7 +52,7 @@ struct ThumbDataManagement + AVFrame* frame_temporary = nullptr; + SwsContext* sws = nullptr; + AVCodecContext* avOutctx = nullptr; +- AVCodec* codec = nullptr; ++ FFMPEG_FMT_CONST AVCodec* codec = nullptr; + ~ThumbDataManagement() + { + av_free(intermediateBuffer); +@@ -198,7 +198,7 @@ bool CFFmpegImage::Initialize(unsigned char* buffer, size_t bufSize) + bool is_png = (bufSize > 3 && buffer[1] == 'P' && buffer[2] == 'N' && buffer[3] == 'G'); + bool is_tiff = (bufSize > 2 && buffer[0] == 'I' && buffer[1] == 'I' && buffer[2] == '*'); + +- AVInputFormat* inp = nullptr; ++ FFMPEG_FMT_CONST AVInputFormat* inp = nullptr; + if (is_jpeg) + inp = av_find_input_format("image2"); + else if (m_strMimeType == "image/apng") +@@ -236,7 +236,7 @@ bool CFFmpegImage::Initialize(unsigned char* buffer, size_t bufSize) + return false; + } + AVCodecParameters* codec_params = m_fctx->streams[0]->codecpar; +- AVCodec* codec = avcodec_find_decoder(codec_params->codec_id); ++ FFMPEG_FMT_CONST AVCodec* codec = avcodec_find_decoder(codec_params->codec_id); + m_codec_ctx = avcodec_alloc_context3(codec); + if (!m_codec_ctx) + { +diff --git a/xbmc/music/tags/MusicInfoTagLoaderFFmpeg.cpp b/xbmc/music/tags/MusicInfoTagLoaderFFmpeg.cpp +index 9bb2cdc09b..dbd8893c97 100644 +--- a/xbmc/music/tags/MusicInfoTagLoaderFFmpeg.cpp ++++ b/xbmc/music/tags/MusicInfoTagLoaderFFmpeg.cpp +@@ -58,7 +58,7 @@ bool CMusicInfoTagLoaderFFmpeg::Load(const std::string& strFileName, CMusicInfoT + if (file.IoControl(IOCTRL_SEEK_POSSIBLE, NULL) != 1) + ioctx->seekable = 0; + +- AVInputFormat* iformat=NULL; ++ FFMPEG_FMT_CONST AVInputFormat* iformat = nullptr; + av_probe_input_buffer(ioctx, &iformat, strFileName.c_str(), NULL, 0, 0); + + if (avformat_open_input(&fctx, strFileName.c_str(), iformat, NULL) < 0) +diff --git a/xbmc/video/tags/VideoTagLoaderFFmpeg.cpp b/xbmc/video/tags/VideoTagLoaderFFmpeg.cpp +index c1b0495179..5564696be6 100644 +--- a/xbmc/video/tags/VideoTagLoaderFFmpeg.cpp ++++ b/xbmc/video/tags/VideoTagLoaderFFmpeg.cpp +@@ -65,7 +65,7 @@ CVideoTagLoaderFFmpeg::CVideoTagLoaderFFmpeg(const CFileItem& item, + if (m_file->IoControl(IOCTRL_SEEK_POSSIBLE, nullptr) != 1) + m_ioctx->seekable = 0; + +- AVInputFormat* iformat = nullptr; ++ FFMPEG_FMT_CONST AVInputFormat* iformat = nullptr; + av_probe_input_buffer(m_ioctx, &iformat, m_item.GetPath().c_str(), nullptr, 0, 0); + if (avformat_open_input(&m_fctx, m_item.GetPath().c_str(), iformat, nullptr) < 0) + { +-- +2.35.1 + + +From 3de036ef45b0df3368997500d210090a7f6ff5e7 Mon Sep 17 00:00:00 2001 +From: Vasyl Gello <vasek.gello@gmail.com> +Date: Thu, 13 Oct 2022 04:56:26 +0000 +Subject: [PATCH 2/3] Use Channel Layout API if built against FFmpeg 5.1 + +Signed-off-by: Vasyl Gello <vasek.gello@gmail.com> +--- + xbmc/cdrip/EncoderFFmpeg.cpp | 51 +++++++++++++ + .../AudioEngine/Encoders/AEEncoderFFmpeg.cpp | 60 ++++++++++++++- + .../AudioEngine/Engines/ActiveAE/ActiveAE.cpp | 22 ++++++ + .../Engines/ActiveAE/ActiveAEFilter.cpp | 38 +++++++++- + .../ActiveAE/ActiveAEResampleFFMPEG.cpp | 55 +++++++++++++- + .../Engines/ActiveAE/ActiveAEStream.cpp | 2 +- + xbmc/cores/AudioEngine/Utils/AEUtil.cpp | 73 +++++++++++++++++-- + xbmc/cores/AudioEngine/Utils/AEUtil.h | 9 ++- + .../DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp | 58 ++++++++++++--- + .../DVDDemuxers/DVDDemuxClient.cpp | 15 +++- + .../DVDDemuxers/DVDDemuxFFmpeg.cpp | 42 +++++++++-- + 11 files changed, 388 insertions(+), 37 deletions(-) + +diff --git a/xbmc/cdrip/EncoderFFmpeg.cpp b/xbmc/cdrip/EncoderFFmpeg.cpp +index 4c0628b5cc..c05cdeab9e 100644 +--- a/xbmc/cdrip/EncoderFFmpeg.cpp ++++ b/xbmc/cdrip/EncoderFFmpeg.cpp +@@ -94,8 +94,14 @@ bool CEncoderFFmpeg::Init() + + /* Set the basic encoder parameters. + * The input file's sample rate is used to avoid a sample rate conversion. */ ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&m_codecCtx->ch_layout); ++ av_channel_layout_default(&m_codecCtx->ch_layout, m_iInChannels); ++#else + m_codecCtx->channels = m_iInChannels; + m_codecCtx->channel_layout = av_get_default_channel_layout(m_iInChannels); ++#endif + m_codecCtx->sample_rate = m_iInSampleRate; + m_codecCtx->sample_fmt = codec->sample_fmts[0]; + m_codecCtx->bit_rate = bitrate; +@@ -140,7 +146,14 @@ bool CEncoderFFmpeg::Init() + + m_bufferFrame->nb_samples = m_codecCtx->frame_size; + m_bufferFrame->format = m_inFormat; ++ ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&m_bufferFrame->ch_layout); ++ av_channel_layout_copy(&m_bufferFrame->ch_layout, &m_codecCtx->ch_layout); ++#else + m_bufferFrame->channel_layout = m_codecCtx->channel_layout; ++#endif + m_bufferFrame->sample_rate = m_codecCtx->sample_rate; + + err = av_frame_get_buffer(m_bufferFrame, 0); +@@ -152,10 +165,18 @@ bool CEncoderFFmpeg::Init() + + if (m_needConversion) + { ++#if LIBSWRESAMPLE_BUILD >= AV_VERSION_INT(4, 7, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ int ret = swr_alloc_set_opts2(&m_swrCtx, &m_codecCtx->ch_layout, m_outFormat, ++ m_codecCtx->sample_rate, &m_codecCtx->ch_layout, m_inFormat, ++ m_codecCtx->sample_rate, 0, nullptr); ++ if (ret || swr_init(m_swrCtx) < 0) ++#else + m_swrCtx = swr_alloc_set_opts(nullptr, m_codecCtx->channel_layout, m_outFormat, + m_codecCtx->sample_rate, m_codecCtx->channel_layout, m_inFormat, + m_codecCtx->sample_rate, 0, nullptr); + if (!m_swrCtx || swr_init(m_swrCtx) < 0) ++#endif + throw FFMpegException("Failed to initialize the resampler"); + + m_resampledBufferSize = +@@ -167,7 +188,13 @@ bool CEncoderFFmpeg::Init() + + m_resampledFrame->nb_samples = m_neededFrames; + m_resampledFrame->format = m_outFormat; ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&m_resampledFrame->ch_layout); ++ av_channel_layout_copy(&m_resampledFrame->ch_layout, &m_codecCtx->ch_layout); ++#else + m_resampledFrame->channel_layout = m_codecCtx->channel_layout; ++#endif + m_resampledFrame->sample_rate = m_codecCtx->sample_rate; + + err = av_frame_get_buffer(m_resampledFrame, 0); +@@ -203,11 +230,23 @@ bool CEncoderFFmpeg::Init() + CLog::Log(LOGERROR, "CEncoderFFmpeg::{} - {}", __func__, caught.what()); + + av_freep(&m_buffer); ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&m_bufferFrame->ch_layout); ++#endif + av_frame_free(&m_bufferFrame); + swr_free(&m_swrCtx); ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&m_resampledFrame->ch_layout); ++#endif + av_frame_free(&m_resampledFrame); + av_freep(&m_resampledBuffer); + av_free(m_bcBuffer); ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&m_codecCtx->ch_layout); ++#endif + avcodec_free_context(&m_codecCtx); + if (m_formatCtx) + { +@@ -351,8 +390,16 @@ bool CEncoderFFmpeg::Close() + + /* Flush if needed */ + av_freep(&m_buffer); ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&m_bufferFrame->ch_layout); ++#endif + av_frame_free(&m_bufferFrame); + swr_free(&m_swrCtx); ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&m_resampledFrame->ch_layout); ++#endif + av_frame_free(&m_resampledFrame); + av_freep(&m_resampledBuffer); + m_needConversion = false; +@@ -364,6 +411,10 @@ bool CEncoderFFmpeg::Close() + + /* cleanup */ + av_free(m_bcBuffer); ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&m_codecCtx->ch_layout); ++#endif + avcodec_free_context(&m_codecCtx); + av_freep(&m_formatCtx->pb); + avformat_free_context(m_formatCtx); +diff --git a/xbmc/cores/AudioEngine/Encoders/AEEncoderFFmpeg.cpp b/xbmc/cores/AudioEngine/Encoders/AEEncoderFFmpeg.cpp +index 86f65f57f3..5d8ca71de1 100644 +--- a/xbmc/cores/AudioEngine/Encoders/AEEncoderFFmpeg.cpp ++++ b/xbmc/cores/AudioEngine/Encoders/AEEncoderFFmpeg.cpp +@@ -37,6 +37,10 @@ CAEEncoderFFmpeg::~CAEEncoderFFmpeg() + { + Reset(); + swr_free(&m_SwrCtx); ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&m_CodecCtx->ch_layout); ++#endif + avcodec_free_context(&m_CodecCtx); + } + +@@ -113,7 +117,13 @@ bool CAEEncoderFFmpeg::Initialize(AEAudioFormat &format, bool allow_planar_input + + m_CodecCtx->bit_rate = m_BitRate; + m_CodecCtx->sample_rate = format.m_sampleRate; ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&m_CodecCtx->ch_layout); ++ av_channel_layout_from_mask(&m_CodecCtx->ch_layout, AV_CH_LAYOUT_5POINT1_BACK); ++#else + m_CodecCtx->channel_layout = AV_CH_LAYOUT_5POINT1_BACK; ++#endif + + /* select a suitable data format */ + if (codec->sample_fmts) +@@ -190,22 +200,44 @@ bool CAEEncoderFFmpeg::Initialize(AEAudioFormat &format, bool allow_planar_input + LOGERROR, + "CAEEncoderFFmpeg::Initialize - Unable to find a suitable data format for the codec ({})", + m_CodecName); ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&m_CodecCtx->ch_layout); ++#endif + avcodec_free_context(&m_CodecCtx); + return false; + } + } + ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ uint64_t mask = m_CodecCtx->ch_layout.u.mask; ++ av_channel_layout_uninit(&m_CodecCtx->ch_layout); ++ av_channel_layout_from_mask(&m_CodecCtx->ch_layout, mask); ++ m_CodecCtx->ch_layout.nb_channels = BuildChannelLayout(mask, m_Layout); ++#else + m_CodecCtx->channels = BuildChannelLayout(m_CodecCtx->channel_layout, m_Layout); ++#endif + + /* open the codec */ + if (avcodec_open2(m_CodecCtx, codec, NULL)) + { ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&m_CodecCtx->ch_layout); ++#endif + avcodec_free_context(&m_CodecCtx); + return false; + } + + format.m_frames = m_CodecCtx->frame_size; +- format.m_frameSize = m_CodecCtx->channels * (CAEUtil::DataFormatToBits(format.m_dataFormat) >> 3); ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ int channels = m_CodecCtx->ch_layout.nb_channels; ++#else ++ int channels = m_CodecCtx->channels; ++#endif ++ format.m_frameSize = channels * (CAEUtil::DataFormatToBits(format.m_dataFormat) >> 3); + format.m_channelLayout = m_Layout; + + m_CurrentFormat = format; +@@ -215,14 +247,26 @@ bool CAEEncoderFFmpeg::Initialize(AEAudioFormat &format, bool allow_planar_input + + if (m_NeedConversion) + { ++#if LIBSWRESAMPLE_BUILD >= AV_VERSION_INT(4, 7, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ int ret = swr_alloc_set_opts2(&m_SwrCtx, &m_CodecCtx->ch_layout, m_CodecCtx->sample_fmt, ++ m_CodecCtx->sample_rate, &m_CodecCtx->ch_layout, ++ AV_SAMPLE_FMT_FLT, m_CodecCtx->sample_rate, 0, NULL); ++ if (ret || swr_init(m_SwrCtx) < 0) ++#else + m_SwrCtx = swr_alloc_set_opts(NULL, + m_CodecCtx->channel_layout, m_CodecCtx->sample_fmt, m_CodecCtx->sample_rate, + m_CodecCtx->channel_layout, AV_SAMPLE_FMT_FLT, m_CodecCtx->sample_rate, + 0, NULL); + if (!m_SwrCtx || swr_init(m_SwrCtx) < 0) ++#endif + { + CLog::Log(LOGERROR, "CAEEncoderFFmpeg::Initialize - Failed to initialise resampler."); + swr_free(&m_SwrCtx); ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&m_CodecCtx->ch_layout); ++#endif + avcodec_free_context(&m_CodecCtx); + return false; + } +@@ -276,10 +320,18 @@ int CAEEncoderFFmpeg::Encode(uint8_t *in, int in_size, uint8_t *out, int out_siz + + frame->nb_samples = m_CodecCtx->frame_size; + frame->format = m_CodecCtx->sample_fmt; ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&frame->ch_layout); ++ av_channel_layout_copy(&frame->ch_layout, &m_CodecCtx->ch_layout); ++ int channelNum = m_CodecCtx->ch_layout.nb_channels; ++#else + frame->channel_layout = m_CodecCtx->channel_layout; + frame->channels = m_CodecCtx->channels; ++ int channelNum = m_CodecCtx->channels; ++#endif + +- avcodec_fill_audio_frame(frame, m_CodecCtx->channels, m_CodecCtx->sample_fmt, in, in_size, 0); ++ avcodec_fill_audio_frame(frame, channelNum, m_CodecCtx->sample_fmt, in, in_size, 0); + + pkt->size = out_size; + pkt->data = out; +@@ -295,6 +347,10 @@ int CAEEncoderFFmpeg::Encode(uint8_t *in, int in_size, uint8_t *out, int out_siz + err = avcodec_receive_packet(m_CodecCtx, pkt); + if (err == AVERROR(EAGAIN) || err == AVERROR_EOF) + { ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&frame->ch_layout); ++#endif + av_frame_free(&frame); + av_packet_free(&pkt); + return (err == AVERROR(EAGAIN)) ? -1 : 0; +diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp +index 6000fe9c63..9cd3bddda8 100644 +--- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp ++++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp +@@ -3069,8 +3069,14 @@ IAE::SoundPtr CActiveAE::MakeSound(const std::string& file) + AVCodecID codecId = fmt_ctx->streams[0]->codecpar->codec_id; + dec = avcodec_find_decoder(codecId); + config.sample_rate = fmt_ctx->streams[0]->codecpar->sample_rate; ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ config.channels = fmt_ctx->streams[0]->codecpar->ch_layout.nb_channels; ++ config.channel_layout = fmt_ctx->streams[0]->codecpar->ch_layout.u.mask; ++#else + config.channels = fmt_ctx->streams[0]->codecpar->channels; + config.channel_layout = fmt_ctx->streams[0]->codecpar->channel_layout; ++#endif + } + } + if (dec == nullptr) +@@ -3086,10 +3092,22 @@ IAE::SoundPtr CActiveAE::MakeSound(const std::string& file) + + dec_ctx = avcodec_alloc_context3(dec); + dec_ctx->sample_rate = config.sample_rate; ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ AVChannelLayout layout = {}; ++ if (!config.channel_layout) ++ av_channel_layout_default(&layout, config.channels); ++ else ++ av_channel_layout_from_mask(&layout, config.channel_layout); ++ config.channel_layout = layout.u.mask; ++ av_channel_layout_copy(&dec_ctx->ch_layout, &layout); ++ av_channel_layout_uninit(&layout); ++#else + dec_ctx->channels = config.channels; + if (!config.channel_layout) + config.channel_layout = av_get_default_channel_layout(config.channels); + dec_ctx->channel_layout = config.channel_layout; ++#endif + + AVPacket* avpkt = av_packet_alloc(); + if (!avpkt) +@@ -3156,6 +3174,10 @@ IAE::SoundPtr CActiveAE::MakeSound(const std::string& file) + + av_packet_free(&avpkt); + av_frame_free(&decoded_frame); ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&dec_ctx->ch_layout); ++#endif + avcodec_free_context(&dec_ctx); + avformat_close_input(&fmt_ctx); + if (io_ctx) +diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEFilter.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEFilter.cpp +index 26b669a2cf..1d79dc6db4 100644 +--- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEFilter.cpp ++++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEFilter.cpp +@@ -12,10 +12,11 @@ + #include <algorithm> + + extern "C" { +-#include <libavfilter/avfilter.h> + #include <libavcodec/avcodec.h> ++#include <libavfilter/avfilter.h> + #include <libavfilter/buffersink.h> + #include <libavfilter/buffersrc.h> ++#include <libavutil/version.h> + #include <libswresample/swresample.h> + } + +@@ -171,7 +172,13 @@ void CActiveAEFilter::CloseFilter() + } + + if (m_pOutFrame) ++ { ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&m_pOutFrame->ch_layout); ++#endif + av_frame_free(&m_pOutFrame); ++ } + + if (m_pConvertFrame) + av_frame_free(&m_pConvertFrame); +@@ -205,10 +212,17 @@ int CActiveAEFilter::ProcessFilter(uint8_t **dst_buffer, int dst_samples, uint8_ + if (!frame) + return -1; + ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&frame->ch_layout); ++ av_channel_layout_from_mask(&frame->ch_layout, m_channelLayout); ++ int channels = frame->ch_layout.nb_channels; ++#else + int channels = av_get_channel_layout_nb_channels(m_channelLayout); + + frame->channel_layout = m_channelLayout; + frame->channels = channels; ++#endif + frame->sample_rate = m_sampleRate; + frame->nb_samples = src_samples; + frame->format = m_sampleFormat; +@@ -224,6 +238,10 @@ int CActiveAEFilter::ProcessFilter(uint8_t **dst_buffer, int dst_samples, uint8_ + src_buffer[0], src_bufsize, 16); + if (result < 0) + { ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&frame->ch_layout); ++#endif + av_frame_free(&frame); + CLog::Log(LOGERROR, "CActiveAEFilter::ProcessFilter - avcodec_fill_audio_frame failed"); + m_filterEof = true; +@@ -231,6 +249,10 @@ int CActiveAEFilter::ProcessFilter(uint8_t **dst_buffer, int dst_samples, uint8_ + } + + result = av_buffersrc_write_frame(m_pFilterCtxIn, frame); ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&frame->ch_layout); ++#endif + av_frame_free(&frame); + if (result < 0) + { +@@ -284,7 +306,13 @@ int CActiveAEFilter::ProcessFilter(uint8_t **dst_buffer, int dst_samples, uint8_ + { + av_frame_unref(m_pOutFrame); + m_pOutFrame->format = m_sampleFormat; ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&m_pOutFrame->ch_layout); ++ av_channel_layout_from_mask(&m_pOutFrame->ch_layout, m_channelLayout); ++#else + m_pOutFrame->channel_layout = m_channelLayout; ++#endif + m_pOutFrame->sample_rate = m_sampleRate; + result = swr_convert_frame(m_pConvertCtx, m_pOutFrame, m_pConvertFrame); + av_frame_unref(m_pConvertFrame); +@@ -302,7 +330,15 @@ int CActiveAEFilter::ProcessFilter(uint8_t **dst_buffer, int dst_samples, uint8_ + + if (m_hasData) + { ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ AVChannelLayout layout = {}; ++ av_channel_layout_from_mask(&layout, m_channelLayout); ++ int channels = layout.nb_channels; ++ av_channel_layout_uninit(&layout); ++#else + int channels = av_get_channel_layout_nb_channels(m_channelLayout); ++#endif + int planes = av_sample_fmt_is_planar(m_sampleFormat) ? channels : 1; + int samples = std::min(dst_samples, m_pOutFrame->nb_samples - m_sampleOffset); + int bytes = samples * av_get_bytes_per_sample(m_sampleFormat) * channels / planes; +diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResampleFFMPEG.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResampleFFMPEG.cpp +index bfef837114..379dfe6446 100644 +--- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResampleFFMPEG.cpp ++++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResampleFFMPEG.cpp +@@ -11,8 +11,10 @@ + #include "utils/log.h" + + extern "C" { ++#include <libavcodec/version.h> + #include <libavutil/channel_layout.h> + #include <libavutil/opt.h> ++#include <libavutil/version.h> + #include <libswresample/swresample.h> + } + +@@ -49,15 +51,49 @@ bool CActiveAEResampleFFMPEG::Init(SampleConfig dstConfig, SampleConfig srcConfi + m_doesResample = true; + + if (m_dst_chan_layout == 0) ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ { ++ AVChannelLayout layout = {}; ++ av_channel_layout_default(&layout, m_dst_channels); ++ m_dst_chan_layout = layout.u.mask; ++ av_channel_layout_uninit(&layout); ++ } ++#else + m_dst_chan_layout = av_get_default_channel_layout(m_dst_channels); ++#endif + if (m_src_chan_layout == 0) ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ { ++ AVChannelLayout layout = {}; ++ av_channel_layout_default(&layout, m_src_channels); ++ m_src_chan_layout = layout.u.mask; ++ av_channel_layout_uninit(&layout); ++ } ++#else + m_src_chan_layout = av_get_default_channel_layout(m_src_channels); ++#endif ++ ++#if LIBSWRESAMPLE_BUILD >= AV_VERSION_INT(4, 7, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ AVChannelLayout dstChLayout = {}; ++ AVChannelLayout srcChLayout = {}; + ++ av_channel_layout_from_mask(&dstChLayout, m_dst_chan_layout); ++ av_channel_layout_from_mask(&srcChLayout, m_src_chan_layout); ++ ++ int ret = swr_alloc_set_opts2(&m_pContext, &dstChLayout, m_dst_fmt, m_dst_rate, &srcChLayout, ++ m_src_fmt, m_src_rate, 0, NULL); ++ ++ if (ret) ++#else + m_pContext = swr_alloc_set_opts(NULL, m_dst_chan_layout, m_dst_fmt, m_dst_rate, + m_src_chan_layout, m_src_fmt, m_src_rate, + 0, NULL); + + if (!m_pContext) ++#endif + { + CLog::Log(LOGERROR, "CActiveAEResampleFFMPEG::Init - create context failed"); + return false; +@@ -126,10 +162,20 @@ bool CActiveAEResampleFFMPEG::Init(SampleConfig dstConfig, SampleConfig srcConfi + else if (upmix && m_src_channels == 2 && m_dst_channels > 2) + { + memset(m_rematrix, 0, sizeof(m_rematrix)); ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&dstChLayout); ++ av_channel_layout_from_mask(&dstChLayout, m_dst_chan_layout); ++#endif + for (int out=0; out<m_dst_channels; out++) + { +- uint64_t out_chan = av_channel_layout_extract_channel(m_dst_chan_layout, out); +- switch(out_chan) ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ AVChannel outChan = av_channel_layout_channel_from_index(&dstChLayout, out); ++#else ++ uint64_t outChan = av_channel_layout_extract_channel(m_dst_chan_layout, out); ++#endif ++ switch (outChan) + { + case AV_CH_FRONT_LEFT: + case AV_CH_BACK_LEFT: +@@ -154,6 +200,11 @@ bool CActiveAEResampleFFMPEG::Init(SampleConfig dstConfig, SampleConfig srcConfi + } + } + ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&dstChLayout); ++#endif ++ + if (swr_set_matrix(m_pContext, (const double*)m_rematrix, AE_CH_MAX) < 0) + { + CLog::Log(LOGERROR, "CActiveAEResampleFFMPEG::Init - setting channel matrix failed"); +diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.cpp +index 858b0f2f22..a52ac2829f 100644 +--- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.cpp ++++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.cpp +@@ -88,7 +88,7 @@ void CActiveAEStream::InitRemapper() + for(unsigned int i=0; i<m_format.m_channelLayout.Count(); i++) + { + avLast = avCur; +- avCur = CAEUtil::GetAVChannel(m_format.m_channelLayout[i]); ++ avCur = CAEUtil::GetAVChannelMask(m_format.m_channelLayout[i]); + if(avCur < avLast) + { + needRemap = true; +diff --git a/xbmc/cores/AudioEngine/Utils/AEUtil.cpp b/xbmc/cores/AudioEngine/Utils/AEUtil.cpp +index bfa2cf9e4c..98f82816ef 100644 +--- a/xbmc/cores/AudioEngine/Utils/AEUtil.cpp ++++ b/xbmc/cores/AudioEngine/Utils/AEUtil.cpp +@@ -19,10 +19,6 @@ + #include <xmmintrin.h> + #endif + +-extern "C" { +-#include <libavutil/channel_layout.h> +-} +- + void AEDelayStatus::SetDelay(double d) + { + delay = d; +@@ -550,8 +546,15 @@ AVSampleFormat CAEUtil::GetAVSampleFormat(AEDataFormat format) + } + } + +-uint64_t CAEUtil::GetAVChannel(enum AEChannel aechannel) ++uint64_t CAEUtil::GetAVChannelMask(enum AEChannel aechannel) + { ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ enum AVChannel ch = GetAVChannel(aechannel); ++ if (ch == AV_CHAN_NONE) ++ return 0; ++ return (1ULL << ch); ++#else + switch (aechannel) + { + case AE_CH_FL: return AV_CH_FRONT_LEFT; +@@ -575,9 +578,67 @@ uint64_t CAEUtil::GetAVChannel(enum AEChannel aechannel) + default: + return 0; + } ++#endif + } + ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++enum AVChannel CAEUtil::GetAVChannel(enum AEChannel aechannel) ++{ ++ switch (aechannel) ++ { ++ case AE_CH_FL: ++ return AV_CHAN_FRONT_LEFT; ++ case AE_CH_FR: ++ return AV_CHAN_FRONT_RIGHT; ++ case AE_CH_FC: ++ return AV_CHAN_FRONT_CENTER; ++ case AE_CH_LFE: ++ return AV_CHAN_LOW_FREQUENCY; ++ case AE_CH_BL: ++ return AV_CHAN_BACK_LEFT; ++ case AE_CH_BR: ++ return AV_CHAN_BACK_RIGHT; ++ case AE_CH_FLOC: ++ return AV_CHAN_FRONT_LEFT_OF_CENTER; ++ case AE_CH_FROC: ++ return AV_CHAN_FRONT_RIGHT_OF_CENTER; ++ case AE_CH_BC: ++ return AV_CHAN_BACK_CENTER; ++ case AE_CH_SL: ++ return AV_CHAN_SIDE_LEFT; ++ case AE_CH_SR: ++ return AV_CHAN_SIDE_RIGHT; ++ case AE_CH_TC: ++ return AV_CHAN_TOP_CENTER; ++ case AE_CH_TFL: ++ return AV_CHAN_TOP_FRONT_LEFT; ++ case AE_CH_TFC: ++ return AV_CHAN_TOP_FRONT_CENTER; ++ case AE_CH_TFR: ++ return AV_CHAN_TOP_FRONT_RIGHT; ++ case AE_CH_TBL: ++ return AV_CHAN_TOP_BACK_LEFT; ++ case AE_CH_TBC: ++ return AV_CHAN_TOP_BACK_CENTER; ++ case AE_CH_TBR: ++ return AV_CHAN_TOP_BACK_RIGHT; ++ default: ++ return AV_CHAN_NONE; ++ } ++} ++#endif ++ + int CAEUtil::GetAVChannelIndex(enum AEChannel aechannel, uint64_t layout) + { +- return av_get_channel_layout_channel_index(layout, GetAVChannel(aechannel)); ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ AVChannelLayout ch_layout = {}; ++ av_channel_layout_from_mask(&ch_layout, layout); ++ int idx = av_channel_layout_index_from_channel(&ch_layout, GetAVChannel(aechannel)); ++ av_channel_layout_uninit(&ch_layout); ++ return idx; ++#else ++ return av_get_channel_layout_channel_index(layout, GetAVChannelMask(aechannel)); ++#endif + } +diff --git a/xbmc/cores/AudioEngine/Utils/AEUtil.h b/xbmc/cores/AudioEngine/Utils/AEUtil.h +index 034e115ee8..8acbeec442 100644 +--- a/xbmc/cores/AudioEngine/Utils/AEUtil.h ++++ b/xbmc/cores/AudioEngine/Utils/AEUtil.h +@@ -13,7 +13,10 @@ + #include <math.h> + + extern "C" { ++#include <libavcodec/version.h> ++#include <libavutil/channel_layout.h> + #include <libavutil/samplefmt.h> ++#include <libavutil/version.h> + } + + // AV sync options +@@ -171,6 +174,10 @@ public: + static uint64_t GetAVChannelLayout(const CAEChannelInfo &info); + static CAEChannelInfo GetAEChannelLayout(uint64_t layout); + static AVSampleFormat GetAVSampleFormat(AEDataFormat format); +- static uint64_t GetAVChannel(enum AEChannel aechannel); ++ static uint64_t GetAVChannelMask(enum AEChannel aechannel); ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ static enum AVChannel GetAVChannel(enum AEChannel aechannel); ++#endif + static int GetAVChannelIndex(enum AEChannel aechannel, uint64_t layout); + }; +diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp +index 87e7ae2c57..44dcb32620 100644 +--- a/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp ++++ b/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp +@@ -78,7 +78,14 @@ bool CDVDAudioCodecFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options + + m_matrixEncoding = AV_MATRIX_ENCODING_NONE; + m_channels = 0; ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&m_pCodecContext->ch_layout); ++ m_pCodecContext->ch_layout.order = AV_CHANNEL_ORDER_NATIVE; ++ m_pCodecContext->ch_layout.nb_channels = hints.channels; ++#else + m_pCodecContext->channels = hints.channels; ++#endif + m_hint_layout = hints.channellayout; + m_pCodecContext->sample_rate = hints.samplerate; + m_pCodecContext->block_align = hints.blockalign; +@@ -261,12 +268,18 @@ int CDVDAudioCodecFFmpeg::GetData(uint8_t** dst) + m_format.m_frameSize = m_format.m_channelLayout.Count() * + CAEUtil::DataFormatToBits(m_format.m_dataFormat) >> 3; + +- int planes = av_sample_fmt_is_planar(m_pCodecContext->sample_fmt) ? m_pFrame->channels : 1; ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ int channels = m_pFrame->ch_layout.nb_channels; ++#else ++ int channels = m_pFrame->channels; ++#endif ++ int planes = av_sample_fmt_is_planar(m_pCodecContext->sample_fmt) ? channels : 1; ++ + for (int i=0; i<planes; i++) + dst[i] = m_pFrame->extended_data[i]; + +- return m_pFrame->nb_samples * m_pFrame->channels * +- av_get_bytes_per_sample(m_pCodecContext->sample_fmt); ++ return m_pFrame->nb_samples * channels * av_get_bytes_per_sample(m_pCodecContext->sample_fmt); + } + + return 0; +@@ -280,7 +293,12 @@ void CDVDAudioCodecFFmpeg::Reset() + + int CDVDAudioCodecFFmpeg::GetChannels() + { ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ return m_pCodecContext->ch_layout.nb_channels; ++#else + return m_pCodecContext->channels; ++#endif + } + + int CDVDAudioCodecFFmpeg::GetSampleRate() +@@ -347,28 +365,44 @@ static unsigned count_bits(int64_t value) + + void CDVDAudioCodecFFmpeg::BuildChannelMap() + { +- if (m_channels == m_pCodecContext->channels && m_layout == m_pCodecContext->channel_layout) ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ int codecChannels = m_pCodecContext->ch_layout.nb_channels; ++ uint64_t codecChannelLayout = m_pCodecContext->ch_layout.u.mask; ++#else ++ int codecChannels = m_pCodecContext->channels; ++ uint64_t codecChannelLayout = m_pCodecContext->channel_layout; ++#endif ++ if (m_channels == codecChannels && m_layout == codecChannelLayout) + return; //nothing to do here + +- m_channels = m_pCodecContext->channels; +- m_layout = m_pCodecContext->channel_layout; ++ m_channels = codecChannels; ++ m_layout = codecChannelLayout; + + int64_t layout; + +- int bits = count_bits(m_pCodecContext->channel_layout); +- if (bits == m_pCodecContext->channels) +- layout = m_pCodecContext->channel_layout; ++ int bits = count_bits(codecChannelLayout); ++ if (bits == codecChannels) ++ layout = codecChannelLayout; + else + { + CLog::Log(LOGINFO, + "CDVDAudioCodecFFmpeg::GetChannelMap - FFmpeg reported {} channels, but the layout " + "contains {} - trying hints", +- m_pCodecContext->channels, bits); +- if (static_cast<int>(count_bits(m_hint_layout)) == m_pCodecContext->channels) ++ codecChannels, bits); ++ if (static_cast<int>(count_bits(m_hint_layout)) == codecChannels) + layout = m_hint_layout; + else + { ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ AVChannelLayout def_layout = {}; ++ av_channel_layout_default(&def_layout, codecChannels); ++ layout = def_layout.u.mask; ++ av_channel_layout_uninit(&def_layout); ++#else + layout = av_get_default_channel_layout(m_pCodecContext->channels); ++#endif + CLog::Log(LOGINFO, "Using default layout..."); + } + } +@@ -394,7 +428,7 @@ void CDVDAudioCodecFFmpeg::BuildChannelMap() + if (layout & AV_CH_TOP_BACK_CENTER ) m_channelLayout += AE_CH_BC ; + if (layout & AV_CH_TOP_BACK_RIGHT ) m_channelLayout += AE_CH_BR ; + +- m_channels = m_pCodecContext->channels; ++ m_channels = codecChannels; + } + + CAEChannelInfo CDVDAudioCodecFFmpeg::GetChannelMap() +diff --git a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp +index 5be134e381..70f0562462 100644 +--- a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp ++++ b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp +@@ -220,10 +220,17 @@ bool CDVDDemuxClient::ParsePacket(DemuxPacket* pkt) + case STREAM_AUDIO: + { + CDemuxStreamClientInternalTpl<CDemuxStreamAudio>* sta = static_cast<CDemuxStreamClientInternalTpl<CDemuxStreamAudio>*>(st); +- if (stream->m_context->channels != sta->iChannels && stream->m_context->channels != 0) ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ int streamChannels = stream->m_context->ch_layout.nb_channels; ++#else ++ int streamChannels = stream->m_context->channels; ++#endif ++ if (streamChannels != sta->iChannels && streamChannels != 0) + { +- CLog::Log(LOGDEBUG, "CDVDDemuxClient::ParsePacket - ({}) channels changed from {} to {}", st->uniqueId, sta->iChannels, stream->m_context->channels); +- sta->iChannels = stream->m_context->channels; ++ CLog::Log(LOGDEBUG, "CDVDDemuxClient::ParsePacket - ({}) channels changed from {} to {}", ++ st->uniqueId, sta->iChannels, streamChannels); ++ sta->iChannels = streamChannels; + sta->changes++; + sta->disabled = false; + } +@@ -235,7 +242,7 @@ bool CDVDDemuxClient::ParsePacket(DemuxPacket* pkt) + sta->changes++; + sta->disabled = false; + } +- if (stream->m_context->channels) ++ if (streamChannels) + st->changes = -1; // stop parsing + break; + } +diff --git a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp +index bf6f322274..4ad52cd32a 100644 +--- a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp ++++ b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp +@@ -1235,8 +1235,16 @@ DemuxPacket* CDVDDemuxFFmpeg::Read() + else if (stream->type == STREAM_AUDIO) + { + CDemuxStreamAudioFFmpeg* audiostream = dynamic_cast<CDemuxStreamAudioFFmpeg*>(stream); +- if (audiostream && (audiostream->iChannels != m_pFormatContext->streams[pPacket->iStreamId]->codecpar->channels || +- audiostream->iSampleRate != m_pFormatContext->streams[pPacket->iStreamId]->codecpar->sample_rate)) ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ int codecparChannels = ++ m_pFormatContext->streams[pPacket->iStreamId]->codecpar->ch_layout.nb_channels; ++#else ++ int codecparChannels = m_pFormatContext->streams[pPacket->iStreamId]->codecpar->channels; ++#endif ++ if (audiostream && (audiostream->iChannels != codecparChannels || ++ audiostream->iSampleRate != ++ m_pFormatContext->streams[pPacket->iStreamId]->codecpar->sample_rate)) + { + // content has changed + stream = AddStream(pPacket->iStreamId); +@@ -1418,6 +1426,7 @@ void CDVDDemuxFFmpeg::UpdateCurrentPTS() + if (idx >= 0) + { + AVStream* stream = m_pFormatContext->streams[idx]; ++ + #if LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 17, 100) + if (stream && m_pkt.pkt.dts != (int64_t)AV_NOPTS_VALUE) + { +@@ -1639,16 +1648,28 @@ CDemuxStream* CDVDDemuxFFmpeg::AddStream(int streamIdx) + { + CDemuxStreamAudioFFmpeg* st = new CDemuxStreamAudioFFmpeg(pStream); + stream = st; +- st->iChannels = pStream->codecpar->channels; ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ int codecparChannels = pStream->codecpar->ch_layout.nb_channels; ++ int codecparChannelLayout = pStream->codecpar->ch_layout.u.mask; ++#else ++ int codecparChannels = pStream->codecpar->channels; ++ int codecparChannelLayout = pStream->codecpar->channel_layout; ++#endif ++ st->iChannels = codecparChannels; ++ st->iChannelLayout = codecparChannelLayout; + st->iSampleRate = pStream->codecpar->sample_rate; + st->iBlockAlign = pStream->codecpar->block_align; + st->iBitRate = static_cast<int>(pStream->codecpar->bit_rate); + st->iBitsPerSample = pStream->codecpar->bits_per_raw_sample; +- st->iChannelLayout = pStream->codecpar->channel_layout; + char buf[32] = {}; + // https://github.com/FFmpeg/FFmpeg/blob/6ccc3989d15/doc/APIchanges#L50-L53 +-#if LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 24, 100) +- av_channel_layout_describe(st->iChannelLayout, buf, sizeof(buf)); ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ AVChannelLayout layout = {}; ++ av_channel_layout_from_mask(&layout, st->iChannelLayout); ++ av_channel_layout_describe(&layout, buf, sizeof(buf)); ++ av_channel_layout_uninit(&layout); + #else + av_get_channel_layout_string(buf, 31, st->iChannels, st->iChannelLayout); + #endif +@@ -2195,8 +2216,13 @@ bool CDVDDemuxFFmpeg::IsProgramChange() + if (m_pFormatContext->streams[idx]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) + { + CDemuxStreamAudioFFmpeg* audiostream = dynamic_cast<CDemuxStreamAudioFFmpeg*>(stream); +- if (audiostream && +- m_pFormatContext->streams[idx]->codecpar->channels != audiostream->iChannels) ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ int codecparChannels = m_pFormatContext->streams[idx]->codecpar->ch_layout.nb_channels; ++#else ++ int codecparChannels = m_pFormatContext->streams[idx]->codecpar->channels; ++#endif ++ if (audiostream && codecparChannels != audiostream->iChannels) + { + return true; + } +-- +2.35.1 + + +From 0a10e05700dfd12b7f5d720588b993089ea33be4 Mon Sep 17 00:00:00 2001 +From: Vasyl Gello <vasek.gello@gmail.com> +Date: Sat, 15 Oct 2022 11:46:52 +0000 +Subject: [PATCH 3/3] ffmpeg5: Get extradata with extract_extradata BSF + +Fixes the transport stream playback failures described in +https://bugs.debian.org/1016925 + +Rogo95 made an excellent technical analysis of the root cause +and reported that to the bug thread. + +Later on, James Almer (jamrial) suggested the solution to use +extract_extradata bitstream filter to replace the removed split() +function. + +Finally, I adapted the following code snippet: +https://gist.github.com/moonpfe/f6795d51294d91ee0f82f62ff6985db0 +to Kodi and tested it by playing the affected files in TS format. + +HiassofT form LibreELEC found another edge case decoding HTSP +streams from pvr.hts. The comparison of log files revealed that +the split function is also used in DVDDemuxClient. + +Signed-off-by: Vasyl Gello <vasek.gello@gmail.com> +--- + xbmc/cores/FFmpeg.cpp | 154 ++++++++++++++++++ + xbmc/cores/FFmpeg.h | 5 + + .../DVDDemuxers/DVDDemuxClient.cpp | 37 ++--- + .../DVDDemuxers/DVDDemuxFFmpeg.cpp | 61 +++---- + 4 files changed, 203 insertions(+), 54 deletions(-) + +diff --git a/xbmc/cores/FFmpeg.cpp b/xbmc/cores/FFmpeg.cpp +index de1765ed52..eb9c653fa3 100644 +--- a/xbmc/cores/FFmpeg.cpp ++++ b/xbmc/cores/FFmpeg.cpp +@@ -16,6 +16,11 @@ + #include "utils/StringUtils.h" + #include "utils/log.h" + ++extern "C" ++{ ++#include <libavcodec/bsf.h> ++} ++ + #include <map> + #include <mutex> + +@@ -129,3 +134,152 @@ void ff_avutil_log(void* ptr, int level, const char* format, va_list va) + } + buffer.erase(0, start); + } ++ ++std::tuple<uint8_t*, int> GetPacketExtradata(const AVPacket* pkt, ++ const AVCodecParserContext* parserCtx, ++ AVCodecContext* codecCtx) ++{ ++ constexpr int FF_MAX_EXTRADATA_SIZE = ((1 << 28) - AV_INPUT_BUFFER_PADDING_SIZE); ++ ++ if (!pkt) ++ return std::make_tuple(nullptr, 0); ++ ++ uint8_t* extraData = nullptr; ++ int extraDataSize = 0; ++ ++#if LIBAVFORMAT_BUILD >= AV_VERSION_INT(59, 0, 100) ++ /* extract_extradata bitstream filter is implemented only ++ * for certain codecs, as noted in discussion of PR#21248 ++ */ ++ ++ AVCodecID codecId = codecCtx->codec_id; ++ ++ // clang-format off ++ if ( ++ codecId != AV_CODEC_ID_MPEG1VIDEO && ++ codecId != AV_CODEC_ID_MPEG2VIDEO && ++ codecId != AV_CODEC_ID_H264 && ++ codecId != AV_CODEC_ID_HEVC && ++ codecId != AV_CODEC_ID_MPEG4 && ++ codecId != AV_CODEC_ID_VC1 && ++ codecId != AV_CODEC_ID_AV1 && ++ codecId != AV_CODEC_ID_AVS2 && ++ codecId != AV_CODEC_ID_AVS3 && ++ codecId != AV_CODEC_ID_CAVS ++ ) ++ // clang-format on ++ return std::make_tuple(nullptr, 0); ++ ++ const AVBitStreamFilter* f = av_bsf_get_by_name("extract_extradata"); ++ if (!f) ++ return std::make_tuple(nullptr, 0); ++ ++ AVBSFContext* bsf = nullptr; ++ int ret = av_bsf_alloc(f, &bsf); ++ if (ret < 0) ++ return std::make_tuple(nullptr, 0); ++ ++ bsf->par_in->codec_id = codecId; ++ ++ ret = av_bsf_init(bsf); ++ if (ret < 0) ++ { ++ av_bsf_free(&bsf); ++ return std::make_tuple(nullptr, 0); ++ } ++ ++ AVPacket* dstPkt = av_packet_alloc(); ++ if (!dstPkt) ++ { ++ CLog::LogF(LOGERROR, "failed to allocate packet"); ++ ++ av_bsf_free(&bsf); ++ return std::make_tuple(nullptr, 0); ++ } ++ AVPacket* pktRef = dstPkt; ++ ++ ret = av_packet_ref(pktRef, pkt); ++ if (ret < 0) ++ { ++ av_bsf_free(&bsf); ++ av_packet_free(&dstPkt); ++ return std::make_tuple(nullptr, 0); ++ } ++ ++ ret = av_bsf_send_packet(bsf, pktRef); ++ if (ret < 0) ++ { ++ av_packet_unref(pktRef); ++ av_bsf_free(&bsf); ++ av_packet_free(&dstPkt); ++ return std::make_tuple(nullptr, 0); ++ } ++ ++ ret = 0; ++ while (ret >= 0) ++ { ++ ret = av_bsf_receive_packet(bsf, pktRef); ++ if (ret < 0) ++ { ++ if (ret != AVERROR(EAGAIN) && ret != AVERROR_EOF) ++ break; ++ ++ continue; ++ } ++ ++ size_t retExtraDataSize = 0; ++ uint8_t* retExtraData = ++ av_packet_get_side_data(pktRef, AV_PKT_DATA_NEW_EXTRADATA, &retExtraDataSize); ++ if (retExtraData && retExtraDataSize > 0 && retExtraDataSize < FF_MAX_EXTRADATA_SIZE) ++ { ++ extraData = static_cast<uint8_t*>(av_malloc(retExtraDataSize + AV_INPUT_BUFFER_PADDING_SIZE)); ++ if (!extraData) ++ { ++ CLog::LogF(LOGERROR, "failed to allocate {} bytes for extradata", retExtraDataSize); ++ ++ av_packet_unref(pktRef); ++ av_bsf_free(&bsf); ++ av_packet_free(&dstPkt); ++ return std::make_tuple(nullptr, 0); ++ } ++ ++ CLog::LogF(LOGDEBUG, "fetching extradata, extradata_size({})", retExtraDataSize); ++ ++ memcpy(extraData, retExtraData, retExtraDataSize); ++ memset(extraData + retExtraDataSize, 0, AV_INPUT_BUFFER_PADDING_SIZE); ++ extraDataSize = retExtraDataSize; ++ ++ av_packet_unref(pktRef); ++ break; ++ } ++ ++ av_packet_unref(pktRef); ++ } ++ ++ av_bsf_free(&bsf); ++ av_packet_free(&dstPkt); ++#else ++ if (codecCtx && parserCtx && parserCtx->parser && parserCtx->parser->split) ++ extraDataSize = parserCtx->parser->split(codecCtx, pkt->data, pkt->size); ++ ++ if (extraDataSize <= 0 || extraDataSize >= FF_MAX_EXTRADATA_SIZE) ++ { ++ CLog::LogF(LOGDEBUG, "fetched extradata of weird size {}", extraDataSize); ++ return std::make_tuple(nullptr, 0); ++ } ++ ++ extraData = static_cast<uint8_t*>(av_malloc(extraDataSize + AV_INPUT_BUFFER_PADDING_SIZE)); ++ if (!extraData) ++ { ++ CLog::LogF(LOGERROR, "failed to allocate {} bytes for extradata", extraDataSize); ++ return std::make_tuple(nullptr, 0); ++ } ++ ++ CLog::LogF(LOGDEBUG, "fetching extradata, extradata_size({})", extraDataSize); ++ ++ memcpy(extraData, pkt->data, extraDataSize); ++ memset(extraData + extraDataSize, 0, AV_INPUT_BUFFER_PADDING_SIZE); ++#endif ++ ++ return std::make_tuple(extraData, extraDataSize); ++} +diff --git a/xbmc/cores/FFmpeg.h b/xbmc/cores/FFmpeg.h +index 8230701ba7..22a253e191 100644 +--- a/xbmc/cores/FFmpeg.h ++++ b/xbmc/cores/FFmpeg.h +@@ -22,6 +22,8 @@ extern "C" { + #include <libpostproc/postprocess.h> + } + ++#include <tuple> ++ + // https://github.com/FFmpeg/FFmpeg/blob/56450a0ee4/doc/APIchanges#L18-L26 + #if LIBAVFORMAT_BUILD >= AV_VERSION_INT(59, 0, 100) + #define FFMPEG_FMT_CONST const +@@ -77,3 +79,6 @@ public: + int level; + }; + ++std::tuple<uint8_t*, int> GetPacketExtradata(const AVPacket* pkt, ++ const AVCodecParserContext* parserCtx, ++ AVCodecContext* codecCtx); +diff --git a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp +index 70f0562462..f42710282d 100644 +--- a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp ++++ b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp +@@ -14,10 +14,9 @@ + #include "cores/VideoPlayer/Interface/TimingConstants.h" + #include "utils/log.h" + ++#include <tuple> + #include <utility> + +-#define FF_MAX_EXTRADATA_SIZE ((1 << 28) - AV_INPUT_BUFFER_PADDING_SIZE) +- + class CDemuxStreamClientInternal + { + public: +@@ -150,17 +149,26 @@ bool CDVDDemuxClient::ParsePacket(DemuxPacket* pkt) + stream->m_context->time_base.den = DVD_TIME_BASE; + } + +- if (stream->m_parser_split && stream->m_parser->parser->split) ++ if (stream->m_parser_split && stream->m_parser && stream->m_parser->parser) + { +- int len = stream->m_parser->parser->split(stream->m_context, pkt->pData, pkt->iSize); +- if (len > 0 && len < FF_MAX_EXTRADATA_SIZE) ++ AVPacket* avpkt = av_packet_alloc(); ++ if (!avpkt) ++ { ++ CLog::LogF(LOGERROR, "av_packet_alloc failed: {}", strerror(errno)); ++ return false; ++ } ++ ++ avpkt->data = pkt->pData; ++ avpkt->size = pkt->iSize; ++ avpkt->dts = avpkt->pts = AV_NOPTS_VALUE; ++ ++ auto [retExtraData, len] = GetPacketExtradata(avpkt, stream->m_parser, stream->m_context); ++ if (len > 0) + { + st->changes++; + st->disabled = false; + st->ExtraSize = len; +- st->ExtraData = std::make_unique<uint8_t[]>(len + AV_INPUT_BUFFER_PADDING_SIZE); +- memcpy(st->ExtraData.get(), pkt->pData, len); +- memset(st->ExtraData.get() + len, 0, AV_INPUT_BUFFER_PADDING_SIZE); ++ st->ExtraData = std::unique_ptr<uint8_t[]>(retExtraData); + stream->m_parser_split = false; + change = true; + CLog::Log(LOGDEBUG, "CDVDDemuxClient::ParsePacket - split extradata"); +@@ -168,21 +176,12 @@ bool CDVDDemuxClient::ParsePacket(DemuxPacket* pkt) + // Allow ffmpeg to transport codec information to stream->m_context + if (!avcodec_open2(stream->m_context, stream->m_context->codec, nullptr)) + { +- AVPacket* avpkt = av_packet_alloc(); +- if (!avpkt) +- { +- CLog::Log(LOGERROR, "CDVDDemuxClient::{} - av_packet_alloc failed: {}", __FUNCTION__, +- strerror(errno)); +- return false; +- } +- avpkt->data = pkt->pData; +- avpkt->size = pkt->iSize; +- avpkt->dts = avpkt->pts = AV_NOPTS_VALUE; + avcodec_send_packet(stream->m_context, avpkt); + avcodec_close(stream->m_context); +- av_packet_free(&avpkt); + } + } ++ ++ av_packet_free(&avpkt); + } + + uint8_t *outbuf = nullptr; +diff --git a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp +index 4ad52cd32a..3081dd8e9a 100644 +--- a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp ++++ b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp +@@ -34,6 +34,7 @@ + + #include <mutex> + #include <sstream> ++#include <tuple> + #include <utility> + + extern "C" +@@ -105,8 +106,6 @@ bool AttachmentIsFont(const AVDictionaryEntry* dict) + } + } // namespace + +-#define FF_MAX_EXTRADATA_SIZE ((1 << 28) - AV_INPUT_BUFFER_PADDING_SIZE) +- + std::string CDemuxStreamAudioFFmpeg::GetStreamName() + { + if (!m_stream) +@@ -2358,44 +2357,36 @@ void CDVDDemuxFFmpeg::ParsePacket(AVPacket* pkt) + + if (parser->second->m_parserCtx && + parser->second->m_parserCtx->parser && +- parser->second->m_parserCtx->parser->split && + !st->codecpar->extradata) + { +- int i = parser->second->m_parserCtx->parser->split(parser->second->m_codecCtx, pkt->data, pkt->size); +- if (i > 0 && i < FF_MAX_EXTRADATA_SIZE) ++ auto [retExtraData, i] = ++ GetPacketExtradata(pkt, parser->second->m_parserCtx, parser->second->m_codecCtx); ++ if (i > 0) + { +- st->codecpar->extradata = (uint8_t*)av_malloc(i + AV_INPUT_BUFFER_PADDING_SIZE); +- if (st->codecpar->extradata) +- { +- CLog::Log(LOGDEBUG, +- "CDVDDemuxFFmpeg::ParsePacket() fetching extradata, extradata_size({})", i); +- st->codecpar->extradata_size = i; +- memcpy(st->codecpar->extradata, pkt->data, i); +- memset(st->codecpar->extradata + i, 0, AV_INPUT_BUFFER_PADDING_SIZE); ++ st->codecpar->extradata_size = i; ++ st->codecpar->extradata = retExtraData; + +- if (parser->second->m_parserCtx->parser->parser_parse) ++ if (parser->second->m_parserCtx->parser->parser_parse) ++ { ++ parser->second->m_codecCtx->extradata = st->codecpar->extradata; ++ parser->second->m_codecCtx->extradata_size = st->codecpar->extradata_size; ++ const uint8_t* outbufptr; ++ int bufSize; ++ parser->second->m_parserCtx->flags |= PARSER_FLAG_COMPLETE_FRAMES; ++ parser->second->m_parserCtx->parser->parser_parse(parser->second->m_parserCtx, ++ parser->second->m_codecCtx, &outbufptr, ++ &bufSize, pkt->data, pkt->size); ++ parser->second->m_codecCtx->extradata = nullptr; ++ parser->second->m_codecCtx->extradata_size = 0; ++ ++ if (parser->second->m_parserCtx->width != 0) + { +- parser->second->m_codecCtx->extradata = st->codecpar->extradata; +- parser->second->m_codecCtx->extradata_size = st->codecpar->extradata_size; +- const uint8_t* outbufptr; +- int bufSize; +- parser->second->m_parserCtx->flags |= PARSER_FLAG_COMPLETE_FRAMES; +- parser->second->m_parserCtx->parser->parser_parse(parser->second->m_parserCtx, +- parser->second->m_codecCtx, +- &outbufptr, &bufSize, +- pkt->data, pkt->size); +- parser->second->m_codecCtx->extradata = nullptr; +- parser->second->m_codecCtx->extradata_size = 0; +- +- if (parser->second->m_parserCtx->width != 0) +- { +- st->codecpar->width = parser->second->m_parserCtx->width; +- st->codecpar->height = parser->second->m_parserCtx->height; +- } +- else +- { +- CLog::Log(LOGERROR, "CDVDDemuxFFmpeg::ParsePacket() invalid width/height"); +- } ++ st->codecpar->width = parser->second->m_parserCtx->width; ++ st->codecpar->height = parser->second->m_parserCtx->height; ++ } ++ else ++ { ++ CLog::Log(LOGERROR, "CDVDDemuxFFmpeg::ParsePacket() invalid width/height"); + } + } + } +-- +2.35.1 + +From d61499e7f8451bf080112a3f1332c8826d6ce1ac Mon Sep 17 00:00:00 2001 +From: fritsch <Peter.Fruehberger@gmail.com> +Date: Tue, 17 Jan 2023 20:28:31 +0100 +Subject: [PATCH] AEEncoderFFmpeg: Break when one packet is received + +--- + .../AudioEngine/Encoders/AEEncoderFFmpeg.cpp | 23 +++++++++---------- + 1 file changed, 11 insertions(+), 12 deletions(-) + +diff --git a/xbmc/cores/AudioEngine/Encoders/AEEncoderFFmpeg.cpp b/xbmc/cores/AudioEngine/Encoders/AEEncoderFFmpeg.cpp +index ba35c9506395e..bc6ce300ad028 100644 +--- a/xbmc/cores/AudioEngine/Encoders/AEEncoderFFmpeg.cpp ++++ b/xbmc/cores/AudioEngine/Encoders/AEEncoderFFmpeg.cpp +@@ -333,43 +333,42 @@ int CAEEncoderFFmpeg::Encode(uint8_t *in, int in_size, uint8_t *out, int out_siz + + avcodec_fill_audio_frame(frame, channelNum, m_CodecCtx->sample_fmt, in, in_size, 0); + +- pkt->size = out_size; +- pkt->data = out; +- + /* encode it */ + err = avcodec_send_frame(m_CodecCtx, frame); + if (err < 0) + throw FFMpegException("Error sending a frame for encoding (error '{}')", + FFMpegErrorToString(err)); + +- while (err >= 0) ++ err = avcodec_receive_packet(m_CodecCtx, pkt); ++ // err < 0 - we cannot cope with it ++ // err is EAGAIN or EOF - return to caller as well ++ if (err >= 0) + { +- err = avcodec_receive_packet(m_CodecCtx, pkt); +- if (err == AVERROR(EAGAIN) || err == AVERROR_EOF) ++ if (pkt->size <= out_size) + { +-#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ +- LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) +- av_channel_layout_uninit(&frame->ch_layout); +-#endif +- av_frame_free(&frame); +- av_packet_free(&pkt); +- return (err == AVERROR(EAGAIN)) ? -1 : 0; ++ memset(out, 0, out_size); ++ memcpy(out, pkt->data, pkt->size); ++ size = pkt->size; + } +- else if (err < 0) ++ else + { +- throw FFMpegException("Error during encoding (error '{}')", FFMpegErrorToString(err)); ++ CLog::LogF(LOGERROR, "Encoded pkt size ({}) is bigger than buffer ({})", pkt->size, ++ out_size); + } + + av_packet_unref(pkt); + } +- +- size = pkt->size; + } + catch (const FFMpegException& caught) + { + CLog::Log(LOGERROR, "CAEEncoderFFmpeg::{} - {}", __func__, caught.what()); + } + ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&frame->ch_layout); ++#endif ++ + /* free temporary data */ + av_frame_free(&frame); diff --git a/debian/patches/workarounds/0003-xbmc-libdvd_vfs-enen92.patch b/debian/patches/workarounds/0003-xbmc-libdvd_vfs-enen92.patch new file mode 100644 index 0000000..d3ac4ee --- /dev/null +++ b/debian/patches/workarounds/0003-xbmc-libdvd_vfs-enen92.patch @@ -0,0 +1,5056 @@ +From 089f6faaeaf67e3fb027f60635dd5331bcca9c47 Mon Sep 17 00:00:00 2001 +From: enen92 <92enen@gmail.com> +Date: Sat, 25 Jun 2022 16:17:09 +0100 +Subject: [PATCH 1/9] Unwrap dll + +--- + xbmc/CMakeLists.txt | 1 - + xbmc/DllPaths.h | 4 +- + xbmc/DllPaths_generated.h.in | 3 - + xbmc/DllPaths_generated_android.h.in | 3 - + xbmc/DllPaths_win32.h | 12 - + .../DVDInputStreams/CMakeLists.txt | 1 - + .../DVDInputStreamNavigator.cpp | 207 +++-- + .../DVDInputStreams/DVDInputStreamNavigator.h | 5 +- + .../VideoPlayer/DVDInputStreams/DllDvdNav.h | 275 ------ + .../DVDInputStreams/dvdnav/config.h | 76 -- + .../DVDInputStreams/dvdnav/dvd_reader.h | 370 -------- + .../DVDInputStreams/dvdnav/dvd_types.h | 282 ------- + .../DVDInputStreams/dvdnav/dvdnav.h | 789 ------------------ + .../DVDInputStreams/dvdnav/dvdnav_events.h | 226 ----- + .../DVDInputStreams/dvdnav/ifo_types.h | 754 ----------------- + .../DVDInputStreams/dvdnav/nav_types.h | 258 ------ + .../DVDInputStreams/dvdnav/version.h | 29 - + 17 files changed, 106 insertions(+), 3189 deletions(-) + delete mode 100644 xbmc/DllPaths_win32.h + delete mode 100644 xbmc/cores/VideoPlayer/DVDInputStreams/DllDvdNav.h + delete mode 100644 xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/config.h + delete mode 100644 xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/dvd_reader.h + delete mode 100644 xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/dvd_types.h + delete mode 100644 xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/dvdnav.h + delete mode 100644 xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/dvdnav_events.h + delete mode 100644 xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/ifo_types.h + delete mode 100644 xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/nav_types.h + delete mode 100644 xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/version.h + +diff --git a/xbmc/CMakeLists.txt b/xbmc/CMakeLists.txt +index 4c69707dd5..4db2dc79a8 100644 +--- a/xbmc/CMakeLists.txt ++++ b/xbmc/CMakeLists.txt +@@ -42,7 +42,6 @@ set(HEADERS AutoSwitch.h + DatabaseManager.h + DbUrl.h + DllPaths.h +- DllPaths_win32.h + DynamicDll.h + FileItem.h + FileItemListModification.h +diff --git a/xbmc/DllPaths.h b/xbmc/DllPaths.h +index 09bdd1ba3d..33fb46635e 100644 +--- a/xbmc/DllPaths.h ++++ b/xbmc/DllPaths.h +@@ -8,9 +8,7 @@ + + #pragma once + +-#ifdef TARGET_WINDOWS +-#include "DllPaths_win32.h" +-#elif defined (TARGET_ANDROID) ++#if defined (TARGET_ANDROID) + #include "DllPaths_generated_android.h" + #else + #include "DllPaths_generated.h" +diff --git a/xbmc/DllPaths_generated.h.in b/xbmc/DllPaths_generated.h.in +index f29faa41fd..405a7b5b29 100644 +--- a/xbmc/DllPaths_generated.h.in ++++ b/xbmc/DllPaths_generated.h.in +@@ -11,9 +11,6 @@ + /* prefix install location */ + #define PREFIX_USR_PATH "@prefix@" + +-/* VideoPlayer */ +-#define DLL_PATH_LIBDVDNAV "special://xbmcbin/system/players/VideoPlayer/libdvdnav-@ARCH@.so" +- + /* sse4 */ + #define DLL_PATH_LIBSSE4 "special://xbmcbin/system/libsse4-@ARCH@.so" + +diff --git a/xbmc/DllPaths_generated_android.h.in b/xbmc/DllPaths_generated_android.h.in +index d15988e361..70ceb669aa 100644 +--- a/xbmc/DllPaths_generated_android.h.in ++++ b/xbmc/DllPaths_generated_android.h.in +@@ -17,8 +17,5 @@ + // We only keep @ARCH@ here to retain the same structure as *nix. + // * foo.so will be renamed libfoo.so in the packaging stage + +-/* VideoPlayer */ +-#define DLL_PATH_LIBDVDNAV "libdvdnav-@ARCH@.so" +- + /* Android's libui for gralloc */ + #define DLL_PATH_LIBUI "libui.so" +diff --git a/xbmc/DllPaths_win32.h b/xbmc/DllPaths_win32.h +deleted file mode 100644 +index ea41058a54..0000000000 +--- a/xbmc/DllPaths_win32.h ++++ /dev/null +@@ -1,12 +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 +- +-/* VideoPlayer */ +-#define DLL_PATH_LIBDVDNAV "special://xbmcbin/libdvdnav.dll" +diff --git a/xbmc/cores/VideoPlayer/DVDInputStreams/CMakeLists.txt b/xbmc/cores/VideoPlayer/DVDInputStreams/CMakeLists.txt +index 576ddda150..1aecf6f032 100644 +--- a/xbmc/cores/VideoPlayer/DVDInputStreams/CMakeLists.txt ++++ b/xbmc/cores/VideoPlayer/DVDInputStreams/CMakeLists.txt +@@ -22,7 +22,6 @@ set(HEADERS BlurayStateSerializer.h + DVDInputStreamNavigator.h + DVDInputStreamStack.h + DVDStateSerializer.h +- DllDvdNav.h + InputStreamAddon.h + InputStreamMultiStreams.h + InputStreamMultiSource.h +diff --git a/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.cpp b/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.cpp +index e7b54e3351..859762348b 100644 +--- a/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.cpp ++++ b/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.cpp +@@ -109,9 +109,6 @@ bool CDVDInputStreamNavigator::Open() + CEnvironment::putenv("DVDCSS_CACHE=" + CSpecialProtocol::TranslatePath("special://masterprofile/cache")); + #endif + +- // load libdvdnav.dll +- if (!m_dll.Load()) +- return false; + + // load the dvd language codes + // g_LangCodeExpander.LoadStandardCodes(); +@@ -146,10 +143,10 @@ bool CDVDInputStreamNavigator::Open() + // if dvd image file (ISO or alike) open using libdvdnav stream callback functions + m_pstream.reset(new CDVDInputStreamFile(m_item, XFILE::READ_TRUNCATED | XFILE::READ_BITRATE | XFILE::READ_CHUNKED)); + #if DVDNAV_VERSION >= 60100 +- if (!m_pstream->Open() || m_dll.dvdnav_open_stream2(&m_dvdnav, m_pstream.get(), &loggerCallback, ++ if (!m_pstream->Open() || dvdnav_open_stream2(&m_dvdnav, m_pstream.get(), &loggerCallback, + &m_dvdnav_stream_cb) != DVDNAV_STATUS_OK) + #else +- if (!m_pstream->Open() || m_dll.dvdnav_open_stream(&m_dvdnav, m_pstream.get(), &m_dvdnav_stream_cb) != DVDNAV_STATUS_OK) ++ if (!m_pstream->Open() || dvdnav_open_stream(&m_dvdnav, m_pstream.get(), &m_dvdnav_stream_cb) != DVDNAV_STATUS_OK) + #endif + { + CLog::Log(LOGERROR, "Error opening image file or Error on dvdnav_open_stream"); +@@ -158,10 +155,10 @@ bool CDVDInputStreamNavigator::Open() + } + } + #if DVDNAV_VERSION >= 60100 +- else if (m_dll.dvdnav_open2(&m_dvdnav, nullptr, &loggerCallback, path.c_str()) != ++ else if (dvdnav_open2(&m_dvdnav, nullptr, &loggerCallback, path.c_str()) != + DVDNAV_STATUS_OK) + #else +- else if (m_dll.dvdnav_open(&m_dvdnav, path.c_str()) != DVDNAV_STATUS_OK) ++ else if (dvdnav_open(&m_dvdnav, path.c_str()) != DVDNAV_STATUS_OK) + #endif + { + CLog::Log(LOGERROR, "Error on dvdnav_open"); +@@ -176,16 +173,16 @@ bool CDVDInputStreamNavigator::Open() + else + { + // find out what region dvd reports itself to be from, and use that as mask if available +- if (m_dll.dvdnav_get_disk_region_mask(m_dvdnav, &mask) == DVDNAV_STATUS_ERR) ++ if (dvdnav_get_disk_region_mask(m_dvdnav, &mask) == DVDNAV_STATUS_ERR) + { + CLog::LogF(LOGERROR, "Error getting DVD region code: {}", +- m_dll.dvdnav_err_to_string(m_dvdnav)); ++ dvdnav_err_to_string(m_dvdnav)); + mask = 0xff; + } + } + + CLog::Log(LOGDEBUG, "{} - Setting region mask {:02x}", __FUNCTION__, mask); +- m_dll.dvdnav_set_region_mask(m_dvdnav, mask); ++ dvdnav_set_region_mask(m_dvdnav, mask); + + // get default language settings + char language_menu[3]; +@@ -206,48 +203,48 @@ bool CDVDInputStreamNavigator::Open() + if (language_subtitle[0] == '\0') strcpy(language_subtitle, "en"); + + // set default language settings +- if (m_dll.dvdnav_menu_language_select(m_dvdnav, (char*)language_menu) != DVDNAV_STATUS_OK) ++ if (dvdnav_menu_language_select(m_dvdnav, (char*)language_menu) != DVDNAV_STATUS_OK) + { + CLog::Log(LOGERROR, "Error on setting default menu language: {}", +- m_dll.dvdnav_err_to_string(m_dvdnav)); ++ dvdnav_err_to_string(m_dvdnav)); + CLog::Log(LOGERROR, "Defaulting to \"en\""); + //! @bug libdvdnav isn't const correct +- m_dll.dvdnav_menu_language_select(m_dvdnav, const_cast<char*>("en")); ++ dvdnav_menu_language_select(m_dvdnav, const_cast<char*>("en")); + } + +- if (m_dll.dvdnav_audio_language_select(m_dvdnav, (char*)language_audio) != DVDNAV_STATUS_OK) ++ if (dvdnav_audio_language_select(m_dvdnav, (char*)language_audio) != DVDNAV_STATUS_OK) + { + CLog::Log(LOGERROR, "Error on setting default audio language: {}", +- m_dll.dvdnav_err_to_string(m_dvdnav)); ++ dvdnav_err_to_string(m_dvdnav)); + CLog::Log(LOGERROR, "Defaulting to \"en\""); + //! @bug libdvdnav isn't const correct +- m_dll.dvdnav_audio_language_select(m_dvdnav, const_cast<char*>("en")); ++ dvdnav_audio_language_select(m_dvdnav, const_cast<char*>("en")); + } + +- if (m_dll.dvdnav_spu_language_select(m_dvdnav, (char*)language_subtitle) != DVDNAV_STATUS_OK) ++ if (dvdnav_spu_language_select(m_dvdnav, (char*)language_subtitle) != DVDNAV_STATUS_OK) + { + CLog::Log(LOGERROR, "Error on setting default subtitle language: {}", +- m_dll.dvdnav_err_to_string(m_dvdnav)); ++ dvdnav_err_to_string(m_dvdnav)); + CLog::Log(LOGERROR, "Defaulting to \"en\""); + //! @bug libdvdnav isn't const correct +- m_dll.dvdnav_spu_language_select(m_dvdnav, const_cast<char*>("en")); ++ dvdnav_spu_language_select(m_dvdnav, const_cast<char*>("en")); + } + + // set read ahead cache usage +- if (m_dll.dvdnav_set_readahead_flag(m_dvdnav, 1) != DVDNAV_STATUS_OK) ++ if (dvdnav_set_readahead_flag(m_dvdnav, 1) != DVDNAV_STATUS_OK) + { + CLog::Log(LOGERROR, "Error on dvdnav_set_readahead_flag: {}", +- m_dll.dvdnav_err_to_string(m_dvdnav)); ++ dvdnav_err_to_string(m_dvdnav)); + Close(); + return false; + } + + // set the PGC positioning flag to have position information relatively to the + // whole feature instead of just relatively to the current chapter +- if (m_dll.dvdnav_set_PGC_positioning_flag(m_dvdnav, 1) != DVDNAV_STATUS_OK) ++ if (dvdnav_set_PGC_positioning_flag(m_dvdnav, 1) != DVDNAV_STATUS_OK) + { + CLog::Log(LOGERROR, "Error on dvdnav_set_PGC_positioning_flag: {}", +- m_dll.dvdnav_err_to_string(m_dvdnav)); ++ dvdnav_err_to_string(m_dvdnav)); + Close(); + return false; + } +@@ -260,18 +257,18 @@ bool CDVDInputStreamNavigator::Open() + uint8_t* buf_ptr = buf; + + // must startup vm and pgc +- m_dll.dvdnav_get_next_cache_block(m_dvdnav,&buf_ptr,&event,&len); +- m_dll.dvdnav_sector_search(m_dvdnav, 0, SEEK_SET); ++ dvdnav_get_next_cache_block(m_dvdnav,&buf_ptr,&event,&len); ++ dvdnav_sector_search(m_dvdnav, 0, SEEK_SET); + + // first try title menu +- if(m_dll.dvdnav_menu_call(m_dvdnav, DVD_MENU_Title) != DVDNAV_STATUS_OK) ++ if(dvdnav_menu_call(m_dvdnav, DVD_MENU_Title) != DVDNAV_STATUS_OK) + { + CLog::Log(LOGERROR, "Error on dvdnav_menu_call(Title): {}", +- m_dll.dvdnav_err_to_string(m_dvdnav)); ++ dvdnav_err_to_string(m_dvdnav)); + // next try root menu +- if(m_dll.dvdnav_menu_call(m_dvdnav, DVD_MENU_Root) != DVDNAV_STATUS_OK ) ++ if(dvdnav_menu_call(m_dvdnav, DVD_MENU_Root) != DVDNAV_STATUS_OK ) + CLog::Log(LOGERROR, "Error on dvdnav_menu_call(Root): {}", +- m_dll.dvdnav_err_to_string(m_dvdnav)); ++ dvdnav_err_to_string(m_dvdnav)); + } + } + +@@ -295,9 +292,9 @@ void CDVDInputStreamNavigator::Close() + if (!m_dvdnav) return; + + // finish off by closing the dvdnav device +- if (m_dll.dvdnav_close(m_dvdnav) != DVDNAV_STATUS_OK) ++ if (dvdnav_close(m_dvdnav) != DVDNAV_STATUS_OK) + { +- CLog::Log(LOGERROR, "Error on dvdnav_close: {}", m_dll.dvdnav_err_to_string(m_dvdnav)); ++ CLog::Log(LOGERROR, "Error on dvdnav_close: {}", dvdnav_err_to_string(m_dvdnav)); + return ; + } + +@@ -383,11 +380,11 @@ int CDVDInputStreamNavigator::ProcessBlock(uint8_t* dest_buffer, int* read) + result = DVDNAV_STATUS_OK; + } + else +- result = m_dll.dvdnav_get_next_cache_block(m_dvdnav, &buf, &m_lastevent, &len); ++ result = dvdnav_get_next_cache_block(m_dvdnav, &buf, &m_lastevent, &len); + + if (result == DVDNAV_STATUS_ERR) + { +- CLog::Log(LOGERROR, "Error getting next block: {}", m_dll.dvdnav_err_to_string(m_dvdnav)); ++ CLog::Log(LOGERROR, "Error getting next block: {}", dvdnav_err_to_string(m_dvdnav)); + m_bEOF = true; + return NAVRESULT_ERROR; + } +@@ -488,7 +485,7 @@ int CDVDInputStreamNavigator::ProcessBlock(uint8_t* dest_buffer, int* read) + } + else + { +- bool menu = (0 == m_dll.dvdnav_is_domain_vts(m_dvdnav)); ++ bool menu = (0 == dvdnav_is_domain_vts(m_dvdnav)); + if (menu != m_bInMenu) + { + m_bInMenu = menu; +@@ -508,13 +505,13 @@ int CDVDInputStreamNavigator::ProcessBlock(uint8_t* dest_buffer, int* read) + uint32_t pos = 0; + uint32_t len = 0; + +- m_dll.dvdnav_current_title_info(m_dvdnav, &m_iTitle, &m_iPart); +- m_dll.dvdnav_get_number_of_titles(m_dvdnav, &m_iTitleCount); ++ dvdnav_current_title_info(m_dvdnav, &m_iTitle, &m_iPart); ++ dvdnav_get_number_of_titles(m_dvdnav, &m_iTitleCount); + if(m_iTitle > 0) +- m_dll.dvdnav_get_number_of_parts(m_dvdnav, m_iTitle, &m_iPartCount); ++ dvdnav_get_number_of_parts(m_dvdnav, m_iTitle, &m_iPartCount); + else + m_iPartCount = 0; +- m_dll.dvdnav_get_position(m_dvdnav, &pos, &len); ++ dvdnav_get_position(m_dvdnav, &pos, &len); + + // get chapters' timestamps if we have not cached them yet + if (m_mapTitleChapters.find(m_iTitle) == m_mapTitleChapters.end()) +@@ -522,7 +519,7 @@ int CDVDInputStreamNavigator::ProcessBlock(uint8_t* dest_buffer, int* read) + uint64_t* times = NULL; + uint64_t duration; + //dvdnav_describe_title_chapters returns 0 on failure and NULL for times +- int entries = m_dll.dvdnav_describe_title_chapters(m_dvdnav, m_iTitle, ×, &duration); ++ int entries = dvdnav_describe_title_chapters(m_dvdnav, m_iTitle, ×, &duration); + + if (entries != m_iPartCount) + CLog::Log(LOGDEBUG, +@@ -570,11 +567,11 @@ int CDVDInputStreamNavigator::ProcessBlock(uint8_t* dest_buffer, int* read) + + // Calculate current time + //unsigned int pos, len; +- //m_dll.dvdnav_get_position(m_dvdnav, &pos, &len); ++ //dvdnav_get_position(m_dvdnav, &pos, &len); + //m_iTime = (int)(((int64_t)m_iTotalTime * pos) / len); + +- pci_t* pci = m_dll.dvdnav_get_current_nav_pci(m_dvdnav); +- m_dll.dvdnav_get_current_nav_dsi(m_dvdnav); ++ pci_t* pci = dvdnav_get_current_nav_pci(m_dvdnav); ++ dvdnav_get_current_nav_dsi(m_dvdnav); + + if(!pci) + { +@@ -583,7 +580,7 @@ int CDVDInputStreamNavigator::ProcessBlock(uint8_t* dest_buffer, int* read) + } + + /* if we have any buttons or are not in vts domain we assume we are in menu */ +- bool menu = pci->hli.hl_gi.hli_ss || (0 == m_dll.dvdnav_is_domain_vts(m_dvdnav)); ++ bool menu = pci->hli.hl_gi.hli_ss || (0 == dvdnav_is_domain_vts(m_dvdnav)); + if (menu != m_bInMenu) + { + m_bInMenu = menu; +@@ -611,7 +608,7 @@ int CDVDInputStreamNavigator::ProcessBlock(uint8_t* dest_buffer, int* read) + m_iVobUnitStart = pci->pci_gi.vobu_s_ptm; + m_iVobUnitStop = pci->pci_gi.vobu_e_ptm; + +- m_iTime = (int) ( m_dll.dvdnav_get_current_time(m_dvdnav) / 90 ); ++ m_iTime = (int) ( dvdnav_get_current_time(m_dvdnav) / 90 ); + + iNavresult = m_pVideoPlayer->OnDiscNavResult((void*)pci, DVDNAV_NAV_PACKET); + } +@@ -650,7 +647,7 @@ int CDVDInputStreamNavigator::ProcessBlock(uint8_t* dest_buffer, int* read) + // probably not needed since function will check if buf + // is part of the internal cache, but do it for good measure + if( buf != m_lastblock ) +- m_dll.dvdnav_free_cache_block(m_dvdnav, buf); ++ dvdnav_free_cache_block(m_dvdnav, buf); + + return iNavresult; + } +@@ -662,11 +659,11 @@ bool CDVDInputStreamNavigator::SetActiveAudioStream(int iId) + if (!m_dvdnav) + return false; + +- dvdnav_status_t ret = m_dll.dvdnav_set_active_stream(m_dvdnav, iId, DVD_AUDIO_STREAM); ++ dvdnav_status_t ret = dvdnav_set_active_stream(m_dvdnav, iId, DVD_AUDIO_STREAM); + if (ret == DVDNAV_STATUS_ERR) + { + CLog::LogF(LOGERROR, "dvdnav_set_active_stream (audio) failed: {}", +- m_dll.dvdnav_err_to_string(m_dvdnav)); ++ dvdnav_err_to_string(m_dvdnav)); + } + + return ret == DVDNAV_STATUS_OK; +@@ -679,11 +676,11 @@ bool CDVDInputStreamNavigator::SetActiveSubtitleStream(int iId) + if (!m_dvdnav) + return false; + +- dvdnav_status_t ret = m_dll.dvdnav_set_active_stream(m_dvdnav, iId, DVD_SUBTITLE_STREAM); ++ dvdnav_status_t ret = dvdnav_set_active_stream(m_dvdnav, iId, DVD_SUBTITLE_STREAM); + if (ret == DVDNAV_STATUS_ERR) + { + CLog::LogF(LOGERROR, "dvdnav_set_active_stream (subtitles) failed: {}", +- m_dll.dvdnav_err_to_string(m_dvdnav)); ++ dvdnav_err_to_string(m_dvdnav)); + } + + return ret == DVDNAV_STATUS_OK; +@@ -693,14 +690,14 @@ void CDVDInputStreamNavigator::ActivateButton() + { + if (m_dvdnav) + { +- m_dll.dvdnav_button_activate(m_dvdnav, m_dll.dvdnav_get_current_nav_pci(m_dvdnav)); ++ dvdnav_button_activate(m_dvdnav, dvdnav_get_current_nav_pci(m_dvdnav)); + } + } + + void CDVDInputStreamNavigator::SelectButton(int iButton) + { + if (!m_dvdnav) return; +- m_dll.dvdnav_button_select(m_dvdnav, m_dll.dvdnav_get_current_nav_pci(m_dvdnav), iButton); ++ dvdnav_button_select(m_dvdnav, dvdnav_get_current_nav_pci(m_dvdnav), iButton); + } + + int CDVDInputStreamNavigator::GetCurrentButton() +@@ -711,10 +708,10 @@ int CDVDInputStreamNavigator::GetCurrentButton() + } + + int button = 0; +- if (m_dll.dvdnav_get_current_highlight(m_dvdnav, &button) == DVDNAV_STATUS_ERR) ++ if (dvdnav_get_current_highlight(m_dvdnav, &button) == DVDNAV_STATUS_ERR) + { + CLog::LogF(LOGERROR, "dvdnav_get_current_highlight failed: {}", +- m_dll.dvdnav_err_to_string(m_dvdnav)); ++ dvdnav_err_to_string(m_dvdnav)); + return -1; + } + return button; +@@ -725,7 +722,7 @@ void CDVDInputStreamNavigator::CheckButtons() + if (m_dvdnav && m_bCheckButtons) + { + m_bCheckButtons = false; +- pci_t* pci = m_dll.dvdnav_get_current_nav_pci(m_dvdnav); ++ pci_t* pci = dvdnav_get_current_nav_pci(m_dvdnav); + int iCurrentButton = GetCurrentButton(); + + if( iCurrentButton > 0 && iCurrentButton < 37 ) +@@ -751,7 +748,7 @@ void CDVDInputStreamNavigator::CheckButtons() + { + CLog::Log(LOGWARNING, "CDVDInputStreamNavigator: found invalid button({})", iCurrentButton); + CLog::Log(LOGWARNING, "CDVDInputStreamNavigator: switching to button({}) instead", i + 1); +- m_dll.dvdnav_button_select(m_dvdnav, pci, i + 1); ++ dvdnav_button_select(m_dvdnav, pci, i + 1); + break; + } + } +@@ -762,7 +759,7 @@ int CDVDInputStreamNavigator::GetTotalButtons() + { + if (!m_dvdnav) return 0; + +- pci_t* pci = m_dll.dvdnav_get_current_nav_pci(m_dvdnav); ++ pci_t* pci = dvdnav_get_current_nav_pci(m_dvdnav); + + int counter = 0; + for (const btni_t& buttonInfo : pci->hli.btnit) +@@ -780,30 +777,30 @@ int CDVDInputStreamNavigator::GetTotalButtons() + + void CDVDInputStreamNavigator::OnUp() + { +- if (m_dvdnav) m_dll.dvdnav_upper_button_select(m_dvdnav, m_dll.dvdnav_get_current_nav_pci(m_dvdnav)); ++ if (m_dvdnav) dvdnav_upper_button_select(m_dvdnav, dvdnav_get_current_nav_pci(m_dvdnav)); + } + + void CDVDInputStreamNavigator::OnDown() + { +- if (m_dvdnav) m_dll.dvdnav_lower_button_select(m_dvdnav, m_dll.dvdnav_get_current_nav_pci(m_dvdnav)); ++ if (m_dvdnav) dvdnav_lower_button_select(m_dvdnav, dvdnav_get_current_nav_pci(m_dvdnav)); + } + + void CDVDInputStreamNavigator::OnLeft() + { +- if (m_dvdnav) m_dll.dvdnav_left_button_select(m_dvdnav, m_dll.dvdnav_get_current_nav_pci(m_dvdnav)); ++ if (m_dvdnav) dvdnav_left_button_select(m_dvdnav, dvdnav_get_current_nav_pci(m_dvdnav)); + } + + void CDVDInputStreamNavigator::OnRight() + { +- if (m_dvdnav) m_dll.dvdnav_right_button_select(m_dvdnav, m_dll.dvdnav_get_current_nav_pci(m_dvdnav)); ++ if (m_dvdnav) dvdnav_right_button_select(m_dvdnav, dvdnav_get_current_nav_pci(m_dvdnav)); + } + + bool CDVDInputStreamNavigator::OnMouseMove(const CPoint &point) + { + if (m_dvdnav) + { +- pci_t* pci = m_dll.dvdnav_get_current_nav_pci(m_dvdnav); +- return (DVDNAV_STATUS_OK == m_dll.dvdnav_mouse_select(m_dvdnav, pci, (int32_t)point.x, (int32_t)point.y)); ++ pci_t* pci = dvdnav_get_current_nav_pci(m_dvdnav); ++ return (DVDNAV_STATUS_OK == dvdnav_mouse_select(m_dvdnav, pci, (int32_t)point.x, (int32_t)point.y)); + } + return false; + } +@@ -812,8 +809,8 @@ bool CDVDInputStreamNavigator::OnMouseClick(const CPoint &point) + { + if (m_dvdnav) + { +- pci_t* pci = m_dll.dvdnav_get_current_nav_pci(m_dvdnav); +- return (DVDNAV_STATUS_OK == m_dll.dvdnav_mouse_activate(m_dvdnav, pci, (int32_t)point.x, (int32_t)point.y)); ++ pci_t* pci = dvdnav_get_current_nav_pci(m_dvdnav); ++ return (DVDNAV_STATUS_OK == dvdnav_mouse_activate(m_dvdnav, pci, (int32_t)point.x, (int32_t)point.y)); + } + return false; + } +@@ -825,12 +822,12 @@ bool CDVDInputStreamNavigator::OnMenu() + return false; + } + +- return m_dll.dvdnav_menu_call(m_dvdnav, DVD_MENU_Escape) == DVDNAV_STATUS_OK; ++ return dvdnav_menu_call(m_dvdnav, DVD_MENU_Escape) == DVDNAV_STATUS_OK; + } + + void CDVDInputStreamNavigator::OnBack() + { +- if (m_dvdnav) m_dll.dvdnav_go_up(m_dvdnav); ++ if (m_dvdnav) dvdnav_go_up(m_dvdnav); + } + + // we don't allow skipping in menu's cause it will remove menu overlays +@@ -838,7 +835,7 @@ void CDVDInputStreamNavigator::OnNext() + { + if (m_dvdnav && !(IsInMenu() && GetTotalButtons() > 0)) + { +- m_dll.dvdnav_next_pg_search(m_dvdnav); ++ dvdnav_next_pg_search(m_dvdnav); + } + } + +@@ -847,7 +844,7 @@ void CDVDInputStreamNavigator::OnPrevious() + { + if (m_dvdnav && !(IsInMenu() && GetTotalButtons() > 0)) + { +- m_dll.dvdnav_prev_pg_search(m_dvdnav); ++ dvdnav_prev_pg_search(m_dvdnav); + } + } + +@@ -855,13 +852,13 @@ void CDVDInputStreamNavigator::SkipStill() + { + if (!m_dvdnav) + return ; +- m_dll.dvdnav_still_skip(m_dvdnav); ++ dvdnav_still_skip(m_dvdnav); + } + + void CDVDInputStreamNavigator::SkipWait() + { + if (!m_dvdnav) return ; +- m_dll.dvdnav_wait_skip(m_dvdnav); ++ dvdnav_wait_skip(m_dvdnav); + } + + CDVDInputStream::ENextStream CDVDInputStreamNavigator::NextStream() +@@ -886,7 +883,7 @@ int CDVDInputStreamNavigator::GetActiveSubtitleStream() + return activeStream; + } + +- const int8_t logicalSubStreamId = m_dll.dvdnav_get_active_spu_stream(m_dvdnav); ++ const int8_t logicalSubStreamId = dvdnav_get_active_spu_stream(m_dvdnav); + if (logicalSubStreamId < 0) + { + return activeStream; +@@ -895,7 +892,7 @@ int CDVDInputStreamNavigator::GetActiveSubtitleStream() + int subStreamCount = GetSubTitleStreamCount(); + for (int subpN = 0; subpN < subStreamCount; subpN++) + { +- if (m_dll.dvdnav_get_spu_logical_stream(m_dvdnav, subpN) == logicalSubStreamId) ++ if (dvdnav_get_spu_logical_stream(m_dvdnav, subpN) == logicalSubStreamId) + { + activeStream = subpN; + break; +@@ -913,7 +910,7 @@ SubtitleStreamInfo CDVDInputStreamNavigator::GetSubtitleStreamInfo(const int iId + + subp_attr_t subp_attributes; + +- if (m_dll.dvdnav_get_spu_attr(m_dvdnav, iId, &subp_attributes) == DVDNAV_STATUS_OK) ++ if (dvdnav_get_spu_attr(m_dvdnav, iId, &subp_attributes) == DVDNAV_STATUS_OK) + { + SetSubtitleStreamName(info, subp_attributes); + +@@ -966,7 +963,7 @@ int CDVDInputStreamNavigator::GetSubTitleStreamCount() + { + return 0; + } +- return m_dll.dvdnav_get_number_of_streams(m_dvdnav, DVD_SUBTITLE_STREAM); ++ return dvdnav_get_number_of_streams(m_dvdnav, DVD_SUBTITLE_STREAM); + } + + int CDVDInputStreamNavigator::GetActiveAudioStream() +@@ -976,7 +973,7 @@ int CDVDInputStreamNavigator::GetActiveAudioStream() + return -1; + } + +- const int8_t logicalAudioStreamId = m_dll.dvdnav_get_active_audio_stream(m_dvdnav); ++ const int8_t logicalAudioStreamId = dvdnav_get_active_audio_stream(m_dvdnav); + if (logicalAudioStreamId < 0) + { + return -1; +@@ -986,7 +983,7 @@ int CDVDInputStreamNavigator::GetActiveAudioStream() + int audioStreamCount = GetAudioStreamCount(); + for (int audioN = 0; audioN < audioStreamCount; audioN++) + { +- if (m_dll.dvdnav_get_audio_logical_stream(m_dvdnav, audioN) == logicalAudioStreamId) ++ if (dvdnav_get_audio_logical_stream(m_dvdnav, audioN) == logicalAudioStreamId) + { + activeStream = audioN; + break; +@@ -1083,7 +1080,7 @@ AudioStreamInfo CDVDInputStreamNavigator::GetAudioStreamInfo(const int iId) + + audio_attr_t audio_attributes; + +- if (m_dll.dvdnav_get_audio_attr(m_dvdnav, iId, &audio_attributes) == DVDNAV_STATUS_OK) ++ if (dvdnav_get_audio_attr(m_dvdnav, iId, &audio_attributes) == DVDNAV_STATUS_OK) + { + SetAudioStreamName(info, audio_attributes); + +@@ -1105,7 +1102,7 @@ int CDVDInputStreamNavigator::GetAudioStreamCount() + { + return 0; + } +- return m_dll.dvdnav_get_number_of_streams(m_dvdnav, DVD_AUDIO_STREAM); ++ return dvdnav_get_number_of_streams(m_dvdnav, DVD_AUDIO_STREAM); + } + + int CDVDInputStreamNavigator::GetAngleCount() +@@ -1115,7 +1112,7 @@ int CDVDInputStreamNavigator::GetAngleCount() + + int number_of_angles; + int current_angle; +- dvdnav_status_t status = m_dll.dvdnav_get_angle_info(m_dvdnav, ¤t_angle, &number_of_angles); ++ dvdnav_status_t status = dvdnav_get_angle_info(m_dvdnav, ¤t_angle, &number_of_angles); + + if (status == DVDNAV_STATUS_OK) + return number_of_angles; +@@ -1130,9 +1127,9 @@ int CDVDInputStreamNavigator::GetActiveAngle() + + int number_of_angles; + int current_angle; +- if (m_dll.dvdnav_get_angle_info(m_dvdnav, ¤t_angle, &number_of_angles) == DVDNAV_STATUS_ERR) ++ if (dvdnav_get_angle_info(m_dvdnav, ¤t_angle, &number_of_angles) == DVDNAV_STATUS_ERR) + { +- CLog::LogF(LOGERROR, "Failed to get current angle: {}", m_dll.dvdnav_err_to_string(m_dvdnav)); ++ CLog::LogF(LOGERROR, "Failed to get current angle: {}", dvdnav_err_to_string(m_dvdnav)); + return -1; + } + return current_angle; +@@ -1143,7 +1140,7 @@ bool CDVDInputStreamNavigator::SetAngle(int angle) + if (!m_dvdnav) + return false; + +- dvdnav_status_t status = m_dll.dvdnav_angle_change(m_dvdnav, angle); ++ dvdnav_status_t status = dvdnav_angle_change(m_dvdnav, angle); + + return (status == DVDNAV_STATUS_OK); + } +@@ -1164,8 +1161,8 @@ bool CDVDInputStreamNavigator::GetCurrentButtonInfo(CDVDOverlaySpu* pOverlayPict + return false; + } + +- if (DVDNAV_STATUS_OK == m_dll.dvdnav_get_highlight_area( +- m_dll.dvdnav_get_current_nav_pci(m_dvdnav), button, iButtonType, &hl)) ++ if (DVDNAV_STATUS_OK == dvdnav_get_highlight_area( ++ dvdnav_get_current_nav_pci(m_dvdnav), button, iButtonType, &hl)) + { + // button cropping information + pOverlayPicture->crop_i_x_start = hl.sx; +@@ -1213,10 +1210,10 @@ int CDVDInputStreamNavigator::GetTime() + + bool CDVDInputStreamNavigator::PosTime(int iTimeInMsec) + { +- if( m_dll.dvdnav_jump_to_sector_by_time(m_dvdnav, iTimeInMsec * 90, 0) == DVDNAV_STATUS_ERR ) ++ if( dvdnav_jump_to_sector_by_time(m_dvdnav, iTimeInMsec * 90, 0) == DVDNAV_STATUS_ERR ) + { + CLog::Log(LOGDEBUG, "dvdnav: dvdnav_jump_to_sector_by_time failed( {} )", +- m_dll.dvdnav_err_to_string(m_dvdnav)); ++ dvdnav_err_to_string(m_dvdnav)); + return false; + } + m_iTime = iTimeInMsec; +@@ -1243,26 +1240,26 @@ bool CDVDInputStreamNavigator::SeekChapter(int iChapter) + + if (iChapter == (m_iPart + 1)) + { +- if (m_dll.dvdnav_next_pg_search(m_dvdnav) == DVDNAV_STATUS_ERR) ++ if (dvdnav_next_pg_search(m_dvdnav) == DVDNAV_STATUS_ERR) + { + CLog::Log(LOGERROR, "dvdnav: dvdnav_next_pg_search( {} )", +- m_dll.dvdnav_err_to_string(m_dvdnav)); ++ dvdnav_err_to_string(m_dvdnav)); + return false; + } + } + else if (iChapter == (m_iPart - 1)) + { +- if (m_dll.dvdnav_prev_pg_search(m_dvdnav) == DVDNAV_STATUS_ERR) ++ if (dvdnav_prev_pg_search(m_dvdnav) == DVDNAV_STATUS_ERR) + { + CLog::Log(LOGERROR, "dvdnav: dvdnav_prev_pg_search( {} )", +- m_dll.dvdnav_err_to_string(m_dvdnav)); ++ dvdnav_err_to_string(m_dvdnav)); + return false; + } + } +- else if (m_dll.dvdnav_part_play(m_dvdnav, m_iTitle, iChapter) == DVDNAV_STATUS_ERR) ++ else if (dvdnav_part_play(m_dvdnav, m_iTitle, iChapter) == DVDNAV_STATUS_ERR) + { + CLog::Log(LOGERROR, "dvdnav: dvdnav_part_play failed( {} )", +- m_dll.dvdnav_err_to_string(m_dvdnav)); ++ dvdnav_err_to_string(m_dvdnav)); + return false; + } + +@@ -1274,8 +1271,8 @@ bool CDVDInputStreamNavigator::SeekChapter(int iChapter) + + float CDVDInputStreamNavigator::GetVideoAspectRatio() + { +- int iAspect = m_dll.dvdnav_get_video_aspect(m_dvdnav); +- int iPerm = m_dll.dvdnav_get_video_scale_permission(m_dvdnav); ++ int iAspect = dvdnav_get_video_aspect(m_dvdnav); ++ int iPerm = dvdnav_get_video_scale_permission(m_dvdnav); + + //The video scale permissions should give if the source is letterboxed + //and such. should be able to give us info that we can zoom in automatically +@@ -1298,7 +1295,7 @@ void CDVDInputStreamNavigator::EnableSubtitleStream(bool bEnable) + if (!m_dvdnav) + return; + +- m_dll.dvdnav_toggle_spu_stream(m_dvdnav, static_cast<uint8_t>(bEnable)); ++ dvdnav_toggle_spu_stream(m_dvdnav, static_cast<uint8_t>(bEnable)); + } + + bool CDVDInputStreamNavigator::IsSubtitleStreamEnabled() +@@ -1306,7 +1303,7 @@ bool CDVDInputStreamNavigator::IsSubtitleStreamEnabled() + if (!m_dvdnav) + return false; + +- return m_dll.dvdnav_get_active_spu_stream(m_dvdnav) >= 0; ++ return dvdnav_get_active_spu_stream(m_dvdnav) >= 0; + } + + bool CDVDInputStreamNavigator::FillDVDState(DVDState& dvdState) +@@ -1316,11 +1313,11 @@ bool CDVDInputStreamNavigator::FillDVDState(DVDState& dvdState) + return false; + } + +- if (m_dll.dvdnav_current_title_program(m_dvdnav, &dvdState.title, &dvdState.pgcn, ++ if (dvdnav_current_title_program(m_dvdnav, &dvdState.title, &dvdState.pgcn, + &dvdState.pgn) == DVDNAV_STATUS_ERR) + { + CLog::LogF(LOGERROR, "Failed to get current title info ({})", +- m_dll.dvdnav_err_to_string(m_dvdnav)); ++ dvdnav_err_to_string(m_dvdnav)); + return false; + } + +@@ -1346,7 +1343,7 @@ bool CDVDInputStreamNavigator::GetState(std::string& xmlstate) + } + + // do not save state if we are not playing a title stream (e.g. if we are in menus) +- if (!m_dll.dvdnav_is_domain_vts(m_dvdnav)) ++ if (!dvdnav_is_domain_vts(m_dvdnav)) + { + return false; + } +@@ -1380,8 +1377,8 @@ bool CDVDInputStreamNavigator::SetState(const std::string& xmlstate) + return false; + } + +- m_dll.dvdnav_program_play(m_dvdnav, dvdState.title, dvdState.pgcn, dvdState.pgn); +- m_dll.dvdnav_angle_change(m_dvdnav, dvdState.current_angle); ++ dvdnav_program_play(m_dvdnav, dvdState.title, dvdState.pgcn, dvdState.pgn); ++ dvdnav_angle_change(m_dvdnav, dvdState.current_angle); + SetActiveSubtitleStream(dvdState.subp_num); + SetActiveAudioStream(dvdState.audio_num); + EnableSubtitleStream(dvdState.sub_enabled); +@@ -1394,7 +1391,7 @@ std::string CDVDInputStreamNavigator::GetDVDTitleString() + return ""; + + const char* str = NULL; +- if (m_dll.dvdnav_get_title_string(m_dvdnav, &str) == DVDNAV_STATUS_OK) ++ if (dvdnav_get_title_string(m_dvdnav, &str) == DVDNAV_STATUS_OK) + return str; + else + return ""; +@@ -1406,7 +1403,7 @@ std::string CDVDInputStreamNavigator::GetDVDSerialString() + return ""; + + const char* str = NULL; +- if (m_dll.dvdnav_get_serial_string(m_dvdnav, &str) == DVDNAV_STATUS_OK) ++ if (dvdnav_get_serial_string(m_dvdnav, &str) == DVDNAV_STATUS_OK) + return str; + else + return ""; +@@ -1447,12 +1444,12 @@ void CDVDInputStreamNavigator::GetVideoResolution(uint32_t* width, uint32_t* hei + if (!m_dvdnav) return; + + // for version <= 5.0.3 this functions returns 0 instead of DVDNAV_STATUS_OK and -1 instead of DVDNAV_STATUS_ERR +- int status = m_dll.dvdnav_get_video_resolution(m_dvdnav, width, height); ++ int status = dvdnav_get_video_resolution(m_dvdnav, width, height); + if (status == -1) + { + CLog::Log(LOGWARNING, + "CDVDInputStreamNavigator::GetVideoResolution - Failed to get resolution ({})", +- m_dll.dvdnav_err_to_string(m_dvdnav)); ++ dvdnav_err_to_string(m_dvdnav)); + *width = 0; + *height = 0; + } +diff --git a/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.h b/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.h +index d33364b48f..319c84b47d 100644 +--- a/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.h ++++ b/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.h +@@ -14,10 +14,12 @@ + #include "DVDInputStream.h" + #include "DVDInputStreamFile.h" + #include "DVDStateSerializer.h" +-#include "DllDvdNav.h" + #include "cores/MenuType.h" + #include "utils/Geometry.h" + ++#include <dvdnav/dvdnav.h> ++#include <dvdnav/dvd_types.h> ++ + #include <string> + + #define DVD_VIDEO_BLOCKSIZE DVD_VIDEO_LB_LEN // 2048 bytes +@@ -155,7 +157,6 @@ protected: + */ + bool FillDVDState(DVDState& dvdstate); + +- DllDvdNav m_dll; + bool m_bCheckButtons; + bool m_bEOF; + +diff --git a/xbmc/cores/VideoPlayer/DVDInputStreams/DllDvdNav.h b/xbmc/cores/VideoPlayer/DVDInputStreams/DllDvdNav.h +deleted file mode 100644 +index 7a0c149e02..0000000000 +--- a/xbmc/cores/VideoPlayer/DVDInputStreams/DllDvdNav.h ++++ /dev/null +@@ -1,275 +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 +- +-extern "C" { +-#define DVDNAV_COMPILE +- #include <stdint.h> +- +- #include "dvdnav/dvdnav.h" +- +- #ifndef WIN32 +- #define WIN32 +- #endif // WIN32 +- +- #ifndef HAVE_CONFIG_H +- #define HAVE_CONFIG_H +- #endif +- +- #include "dvdnav/dvd_types.h" +- +- #ifdef WIN32 // WIN32INCLUDES +- #undef HAVE_CONFIG_H +- #endif +-} +-#include "DynamicDll.h" +- +-class DllDvdNavInterface +-{ +-public: +- virtual ~DllDvdNavInterface() = default; +- virtual dvdnav_status_t dvdnav_open(dvdnav_t **dest, const char *path)=0; +- virtual dvdnav_status_t dvdnav_open2(dvdnav_t** dest, +- void*, +- const dvdnav_logger_cb*, +- const char* path) = 0; +- virtual dvdnav_status_t dvdnav_open_stream(dvdnav_t **dest, void *stream, dvdnav_stream_cb *stream_cb) = 0; +- virtual dvdnav_status_t dvdnav_open_stream2(dvdnav_t** dest, +- void* stream, +- const dvdnav_logger_cb*, +- dvdnav_stream_cb* stream_cb) = 0; +- virtual dvdnav_status_t dvdnav_close(dvdnav_t *self)=0; +- virtual dvdnav_status_t dvdnav_reset(dvdnav_t *self)=0; +- virtual const char* dvdnav_err_to_string(dvdnav_t *self)=0; +- virtual dvdnav_status_t dvdnav_set_readahead_flag(dvdnav_t *self, int32_t read_ahead_flag)=0; +- virtual dvdnav_status_t dvdnav_set_PGC_positioning_flag(dvdnav_t *self, int32_t pgc_based_flag)=0; +- virtual dvdnav_status_t dvdnav_get_next_cache_block(dvdnav_t *self, uint8_t **buf, int32_t *event, int32_t *len)=0; +- virtual dvdnav_status_t dvdnav_free_cache_block(dvdnav_t *self, unsigned char *buf)=0; +- virtual dvdnav_status_t dvdnav_still_skip(dvdnav_t *self)=0; +- virtual dvdnav_status_t dvdnav_wait_skip(dvdnav_t *self)=0; +- virtual dvdnav_status_t dvdnav_stop(dvdnav_t *self)=0; +- virtual dvdnav_status_t dvdnav_button_select(dvdnav_t *self, pci_t *pci, int32_t button)=0; +- virtual dvdnav_status_t dvdnav_button_activate(dvdnav_t *self, pci_t *pci)=0; +- virtual dvdnav_status_t dvdnav_upper_button_select(dvdnav_t *self, pci_t *pci)=0; +- virtual dvdnav_status_t dvdnav_lower_button_select(dvdnav_t *self, pci_t *pci)=0; +- virtual dvdnav_status_t dvdnav_right_button_select(dvdnav_t *self, pci_t *pci)=0; +- virtual dvdnav_status_t dvdnav_left_button_select(dvdnav_t *self, pci_t *pci)=0; +- virtual dvdnav_status_t dvdnav_sector_search(dvdnav_t *self, uint64_t offset, int32_t origin)=0; +- virtual pci_t* dvdnav_get_current_nav_pci(dvdnav_t *self)=0; +- virtual dsi_t* dvdnav_get_current_nav_dsi(dvdnav_t *self)=0; +- virtual dvdnav_status_t dvdnav_get_position(dvdnav_t *self, uint32_t *pos, uint32_t *len)=0; +- virtual dvdnav_status_t dvdnav_current_title_info(dvdnav_t *self, int32_t *title, int32_t *part)=0; +- virtual dvdnav_status_t dvdnav_spu_language_select(dvdnav_t *self, char *code)=0; +- virtual dvdnav_status_t dvdnav_audio_language_select(dvdnav_t *self, char *code)=0; +- virtual dvdnav_status_t dvdnav_menu_language_select(dvdnav_t *self, char *code)=0; +- virtual int8_t dvdnav_is_domain_vts(dvdnav_t *self)=0; +- virtual int8_t dvdnav_get_active_spu_stream(dvdnav_t *self)=0; +- virtual int8_t dvdnav_get_spu_logical_stream(dvdnav_t *self, uint8_t subp_num)=0; +- virtual uint16_t dvdnav_spu_stream_to_lang(dvdnav_t *self, uint8_t stream)=0; +- virtual dvdnav_status_t dvdnav_get_current_highlight(dvdnav_t *self, int32_t *button)=0; +- virtual dvdnav_status_t dvdnav_menu_call(dvdnav_t *self, DVDMenuID_t menu)=0; +- virtual dvdnav_status_t dvdnav_prev_pg_search(dvdnav_t *self)=0; +- virtual dvdnav_status_t dvdnav_next_pg_search(dvdnav_t *self)=0; +- virtual dvdnav_status_t dvdnav_get_highlight_area(pci_t *nav_pci , int32_t button, int32_t mode, dvdnav_highlight_area_t *highlight)=0; +- virtual dvdnav_status_t dvdnav_go_up(dvdnav_t *self)=0; +- virtual int8_t dvdnav_get_active_audio_stream(dvdnav_t *self)=0; +- virtual uint16_t dvdnav_audio_stream_to_lang(dvdnav_t *self, uint8_t stream)=0; +- virtual int8_t dvdnav_get_audio_logical_stream(dvdnav_t *self, uint8_t audio_num)=0; +- virtual dvdnav_status_t dvdnav_set_region_mask(dvdnav_t *self, int32_t region_mask)=0; +- virtual uint8_t dvdnav_get_video_aspect(dvdnav_t *self)=0; +- virtual uint8_t dvdnav_get_video_scale_permission(dvdnav_t *self)=0; +- virtual dvdnav_status_t dvdnav_get_number_of_titles(dvdnav_t *self, int32_t *titles)=0; +- virtual dvdnav_status_t dvdnav_get_number_of_parts(dvdnav_t *self, int32_t title, int32_t *parts)=0; +- virtual dvdnav_status_t dvdnav_title_play(dvdnav_t *self, int32_t title)=0; +- virtual dvdnav_status_t dvdnav_part_play(dvdnav_t *self, int32_t title, int32_t part)=0; +- virtual dvdnav_status_t dvdnav_get_audio_attr(dvdnav_t * self, int32_t streamid, audio_attr_t* audio_attributes)=0; +- virtual dvdnav_status_t dvdnav_get_spu_attr(dvdnav_t * self, int32_t streamid, subp_attr_t* stitle_attributes)=0; +- virtual dvdnav_status_t dvdnav_jump_to_sector_by_time(dvdnav_t* self, +- uint64_t offset, +- int32_t origin) = 0; +- virtual int64_t dvdnav_convert_time(dvd_time_t *time)=0; +- virtual dvdnav_status_t dvdnav_get_angle_info(dvdnav_t *self, int32_t *current_angle,int32_t *number_of_angles)=0; +- virtual dvdnav_status_t dvdnav_angle_change(dvdnav_t *self, int32_t angle) = 0; +- virtual dvdnav_status_t dvdnav_mouse_activate(dvdnav_t *self, pci_t *pci, int32_t x, int32_t y)=0; +- virtual dvdnav_status_t dvdnav_mouse_select(dvdnav_t *self, pci_t *pci, int32_t x, int32_t y)=0; +- virtual dvdnav_status_t dvdnav_get_title_string(dvdnav_t *self, const char **title_str)=0; +- virtual dvdnav_status_t dvdnav_get_serial_string(dvdnav_t *self, const char **serial_str)=0; +- virtual const char* dvdnav_get_volid_string(dvdnav_t* self) = 0; +- virtual dvdnav_status_t dvdnav_get_disk_region_mask(dvdnav_t* self, int32_t* region_mask) = 0; +- virtual uint32_t dvdnav_describe_title_chapters(dvdnav_t* self, uint32_t title, uint64_t** times, uint64_t* duration)=0; +- virtual int64_t dvdnav_get_current_time(dvdnav_t* self) = 0; +- virtual int dvdnav_get_video_resolution(dvdnav_t* self, uint32_t* width, uint32_t* height)=0; +- virtual int8_t dvdnav_get_number_of_streams(dvdnav_t* self, dvdnav_stream_type_t stream_type) = 0; +- virtual dvdnav_status_t dvdnav_toggle_spu_stream(dvdnav_t* self, uint8_t visibility) = 0; +- virtual dvdnav_status_t dvdnav_set_active_stream(dvdnav_t* self, +- uint8_t stream_num, +- dvdnav_stream_type_t stream_type) = 0; +- virtual dvdnav_status_t dvdnav_program_play(dvdnav_t* self, +- int32_t title, +- int32_t pgcn, +- int32_t pgn) = 0; +- virtual dvdnav_status_t dvdnav_current_title_program(dvdnav_t* self, +- int32_t* title, +- int32_t* pgcn, +- int32_t* pgn) = 0; +-}; +- +-class DllDvdNav : public DllDynamic, DllDvdNavInterface +-{ +- DECLARE_DLL_WRAPPER(DllDvdNav, DLL_PATH_LIBDVDNAV) +- +- DEFINE_METHOD2(dvdnav_status_t, dvdnav_open, (dvdnav_t **p1, const char *p2)) +- DEFINE_METHOD4(dvdnav_status_t, +- dvdnav_open2, +- (dvdnav_t * *p1, void* p2, const dvdnav_logger_cb* p3, const char* p4)) +- DEFINE_METHOD3(dvdnav_status_t, dvdnav_open_stream, (dvdnav_t **p1, void *p2, dvdnav_stream_cb *p3)) +- DEFINE_METHOD4(dvdnav_status_t, +- dvdnav_open_stream2, +- (dvdnav_t * *p1, void* p2, const dvdnav_logger_cb* p3, dvdnav_stream_cb* p4)) +- DEFINE_METHOD1(dvdnav_status_t, dvdnav_close, (dvdnav_t *p1)) +- DEFINE_METHOD1(dvdnav_status_t, dvdnav_reset, (dvdnav_t *p1)) +- DEFINE_METHOD1(const char*, dvdnav_err_to_string, (dvdnav_t *p1)) +- DEFINE_METHOD2(dvdnav_status_t, dvdnav_set_readahead_flag, (dvdnav_t *p1, int32_t p2)) +- DEFINE_METHOD2(dvdnav_status_t, dvdnav_set_PGC_positioning_flag, (dvdnav_t *p1, int32_t p2)) +- DEFINE_METHOD4(dvdnav_status_t, dvdnav_get_next_cache_block, (dvdnav_t *p1, uint8_t **p2, int32_t *p3, int32_t *p4)) +- DEFINE_METHOD2(dvdnav_status_t, dvdnav_free_cache_block, (dvdnav_t *p1, unsigned char *p2)) +- DEFINE_METHOD1(dvdnav_status_t, dvdnav_still_skip, (dvdnav_t *p1)) +- DEFINE_METHOD1(dvdnav_status_t, dvdnav_wait_skip, (dvdnav_t *p1)) +- DEFINE_METHOD1(dvdnav_status_t, dvdnav_stop, (dvdnav_t *p1)) +- DEFINE_METHOD3(dvdnav_status_t, dvdnav_button_select, (dvdnav_t *p1, pci_t *p2, int32_t p3)) +- DEFINE_METHOD2(dvdnav_status_t, dvdnav_button_activate,(dvdnav_t *p1, pci_t *p2)) +- DEFINE_METHOD2(dvdnav_status_t, dvdnav_upper_button_select, (dvdnav_t *p1, pci_t *p2)) +- DEFINE_METHOD2(dvdnav_status_t, dvdnav_lower_button_select, (dvdnav_t *p1, pci_t *p2)) +- DEFINE_METHOD2(dvdnav_status_t, dvdnav_right_button_select, (dvdnav_t *p1, pci_t *p2)) +- DEFINE_METHOD2(dvdnav_status_t, dvdnav_left_button_select, (dvdnav_t *p1, pci_t *p2)) +- DEFINE_METHOD3(dvdnav_status_t, dvdnav_sector_search, (dvdnav_t *p1, uint64_t p2, int32_t p3)) +- DEFINE_METHOD1(pci_t*, dvdnav_get_current_nav_pci, (dvdnav_t *p1)) +- DEFINE_METHOD1(dsi_t*, dvdnav_get_current_nav_dsi, (dvdnav_t *p1)) +- DEFINE_METHOD3(dvdnav_status_t, dvdnav_get_position, (dvdnav_t *p1, uint32_t *p2, uint32_t *p3)) +- DEFINE_METHOD3(dvdnav_status_t, dvdnav_current_title_info, (dvdnav_t *p1, int32_t *p2, int32_t *p3)) +- DEFINE_METHOD2(dvdnav_status_t, dvdnav_spu_language_select, (dvdnav_t *p1, char *p2)) +- DEFINE_METHOD2(dvdnav_status_t, dvdnav_audio_language_select, (dvdnav_t *p1, char *p2)) +- DEFINE_METHOD2(dvdnav_status_t, dvdnav_menu_language_select, (dvdnav_t *p1, char *p2)) +- DEFINE_METHOD1(int8_t, dvdnav_is_domain_vts, (dvdnav_t *p1)) +- DEFINE_METHOD1(int8_t, dvdnav_get_active_spu_stream, (dvdnav_t *p1)) +- DEFINE_METHOD2(int8_t, dvdnav_get_spu_logical_stream, (dvdnav_t *p1, uint8_t p2)) +- DEFINE_METHOD2(uint16_t, dvdnav_spu_stream_to_lang, (dvdnav_t *p1, uint8_t p2)) +- DEFINE_METHOD2(dvdnav_status_t, dvdnav_get_current_highlight, (dvdnav_t *p1, int32_t *p2)) +- DEFINE_METHOD2(dvdnav_status_t, dvdnav_menu_call, (dvdnav_t *p1, DVDMenuID_t p2)) +- DEFINE_METHOD2(dvdnav_status_t, dvdnav_get_disk_region_mask, (dvdnav_t * p1, int32_t* p2)) +- DEFINE_METHOD1(dvdnav_status_t, dvdnav_prev_pg_search, (dvdnav_t *p1)) +- DEFINE_METHOD1(dvdnav_status_t, dvdnav_next_pg_search, (dvdnav_t *p1)) +- DEFINE_METHOD4(dvdnav_status_t, dvdnav_get_highlight_area, (pci_t *p1, int32_t p2, int32_t p3, dvdnav_highlight_area_t *p4)) +- DEFINE_METHOD1(dvdnav_status_t, dvdnav_go_up, (dvdnav_t *p1)) +- DEFINE_METHOD1(int8_t, dvdnav_get_active_audio_stream, (dvdnav_t *p1)) +- DEFINE_METHOD2(uint16_t, dvdnav_audio_stream_to_lang, (dvdnav_t *p1, uint8_t p2)) +- DEFINE_METHOD2(int8_t, dvdnav_get_audio_logical_stream, (dvdnav_t *p1, uint8_t p2)) +- DEFINE_METHOD2(int8_t, dvdnav_get_number_of_streams, (dvdnav_t * p1, dvdnav_stream_type_t p2)) +- DEFINE_METHOD2(dvdnav_status_t, dvdnav_set_region_mask, (dvdnav_t *p1, int32_t p2)) +- DEFINE_METHOD1(uint8_t, dvdnav_get_video_aspect, (dvdnav_t *p1)) +- DEFINE_METHOD1(uint8_t, dvdnav_get_video_scale_permission, (dvdnav_t *p1)) +- DEFINE_METHOD2(dvdnav_status_t, dvdnav_get_number_of_titles, (dvdnav_t *p1, int32_t *p2)) +- DEFINE_METHOD3(dvdnav_status_t, dvdnav_get_number_of_parts, (dvdnav_t *p1, int32_t p2, int32_t *p3)) +- DEFINE_METHOD2(dvdnav_status_t, dvdnav_title_play, (dvdnav_t *p1, int32_t p2)) +- DEFINE_METHOD3(dvdnav_status_t, dvdnav_part_play, (dvdnav_t *p1, int32_t p2, int32_t p3)) +- DEFINE_METHOD3(dvdnav_status_t, dvdnav_get_audio_attr, (dvdnav_t * p1, int32_t p2, audio_attr_t* p3)) +- DEFINE_METHOD3(dvdnav_status_t, dvdnav_get_spu_attr, (dvdnav_t * p1, int32_t p2, subp_attr_t* p3)) +- DEFINE_METHOD3(dvdnav_status_t, dvdnav_jump_to_sector_by_time, (dvdnav_t * p1, uint64_t p2, int32_t p3)) +- DEFINE_METHOD1(int64_t, dvdnav_convert_time, (dvd_time_t *p1)) +- DEFINE_METHOD3(dvdnav_status_t, dvdnav_get_angle_info, (dvdnav_t *p1, int32_t *p2,int32_t *p3)) +- DEFINE_METHOD2(dvdnav_status_t, dvdnav_angle_change, (dvdnav_t *p1, int32_t p2)) +- DEFINE_METHOD4(dvdnav_status_t, dvdnav_mouse_activate, (dvdnav_t *p1, pci_t *p2, int32_t p3, int32_t p4)) +- DEFINE_METHOD4(dvdnav_status_t, dvdnav_mouse_select, (dvdnav_t *p1, pci_t *p2, int32_t p3, int32_t p4)) +- DEFINE_METHOD2(dvdnav_status_t, dvdnav_get_title_string, (dvdnav_t *p1, const char **p2)) +- DEFINE_METHOD2(dvdnav_status_t, dvdnav_get_serial_string, (dvdnav_t *p1, const char **p2)) +- DEFINE_METHOD1(const char*, dvdnav_get_volid_string, (dvdnav_t * p1)) +- DEFINE_METHOD4(uint32_t, dvdnav_describe_title_chapters, (dvdnav_t* p1, uint32_t p2, uint64_t** p3, uint64_t* p4)) +- DEFINE_METHOD1(int64_t, dvdnav_get_current_time, (dvdnav_t * p1)) +- DEFINE_METHOD3(int, dvdnav_get_video_resolution, (dvdnav_t * p1, uint32_t* p2, uint32_t* p3)) +- DEFINE_METHOD2(dvdnav_status_t, dvdnav_toggle_spu_stream, (dvdnav_t * p1, uint8_t p2)) +- DEFINE_METHOD3(dvdnav_status_t, +- dvdnav_set_active_stream, +- (dvdnav_t * p1, uint8_t p2, dvdnav_stream_type_t p3)) +- DEFINE_METHOD4(dvdnav_status_t, +- dvdnav_program_play, +- (dvdnav_t * p1, int32_t p2, int32_t p3, int32_t p4)) +- DEFINE_METHOD4(dvdnav_status_t, +- dvdnav_current_title_program, +- (dvdnav_t * p1, int32_t* p2, int32_t* p3, int32_t* p4)) +- BEGIN_METHOD_RESOLVE() +- RESOLVE_METHOD(dvdnav_open) +- RESOLVE_METHOD(dvdnav_open2) +- RESOLVE_METHOD(dvdnav_open_stream) +- RESOLVE_METHOD(dvdnav_open_stream2) +- RESOLVE_METHOD(dvdnav_close) +- RESOLVE_METHOD(dvdnav_reset) +- RESOLVE_METHOD(dvdnav_err_to_string) +- RESOLVE_METHOD(dvdnav_set_readahead_flag) +- RESOLVE_METHOD(dvdnav_set_PGC_positioning_flag) +- RESOLVE_METHOD(dvdnav_get_next_cache_block) +- RESOLVE_METHOD(dvdnav_free_cache_block) +- RESOLVE_METHOD(dvdnav_still_skip) +- RESOLVE_METHOD(dvdnav_wait_skip) +- RESOLVE_METHOD(dvdnav_stop) +- RESOLVE_METHOD(dvdnav_get_number_of_streams) +- RESOLVE_METHOD(dvdnav_get_disk_region_mask) +- RESOLVE_METHOD(dvdnav_button_select) +- RESOLVE_METHOD(dvdnav_button_activate) +- RESOLVE_METHOD(dvdnav_upper_button_select) +- RESOLVE_METHOD(dvdnav_lower_button_select) +- RESOLVE_METHOD(dvdnav_right_button_select) +- RESOLVE_METHOD(dvdnav_left_button_select) +- RESOLVE_METHOD(dvdnav_sector_search) +- RESOLVE_METHOD(dvdnav_get_current_nav_pci) +- RESOLVE_METHOD(dvdnav_get_current_nav_dsi) +- RESOLVE_METHOD(dvdnav_get_position) +- RESOLVE_METHOD(dvdnav_current_title_info) +- RESOLVE_METHOD(dvdnav_spu_language_select) +- RESOLVE_METHOD(dvdnav_audio_language_select) +- RESOLVE_METHOD(dvdnav_menu_language_select) +- RESOLVE_METHOD(dvdnav_is_domain_vts) +- RESOLVE_METHOD(dvdnav_get_active_spu_stream) +- RESOLVE_METHOD(dvdnav_get_spu_logical_stream) +- RESOLVE_METHOD(dvdnav_spu_stream_to_lang) +- RESOLVE_METHOD(dvdnav_get_current_highlight) +- RESOLVE_METHOD(dvdnav_menu_call) +- RESOLVE_METHOD(dvdnav_prev_pg_search) +- RESOLVE_METHOD(dvdnav_next_pg_search) +- RESOLVE_METHOD(dvdnav_get_highlight_area) +- RESOLVE_METHOD(dvdnav_go_up) +- RESOLVE_METHOD(dvdnav_get_active_audio_stream) +- RESOLVE_METHOD(dvdnav_audio_stream_to_lang) +- RESOLVE_METHOD(dvdnav_get_audio_logical_stream) +- RESOLVE_METHOD(dvdnav_set_region_mask) +- RESOLVE_METHOD(dvdnav_get_video_aspect) +- RESOLVE_METHOD(dvdnav_get_video_scale_permission) +- RESOLVE_METHOD(dvdnav_get_number_of_titles) +- RESOLVE_METHOD(dvdnav_get_number_of_parts) +- RESOLVE_METHOD(dvdnav_title_play) +- RESOLVE_METHOD(dvdnav_part_play) +- RESOLVE_METHOD(dvdnav_get_audio_attr) +- RESOLVE_METHOD(dvdnav_get_spu_attr) +- RESOLVE_METHOD(dvdnav_jump_to_sector_by_time) +- RESOLVE_METHOD(dvdnav_convert_time) +- RESOLVE_METHOD(dvdnav_get_angle_info) +- RESOLVE_METHOD(dvdnav_angle_change) +- RESOLVE_METHOD(dvdnav_mouse_activate) +- RESOLVE_METHOD(dvdnav_mouse_select) +- RESOLVE_METHOD(dvdnav_get_title_string) +- RESOLVE_METHOD(dvdnav_get_serial_string) +- RESOLVE_METHOD(dvdnav_get_volid_string) +- RESOLVE_METHOD(dvdnav_describe_title_chapters) +- RESOLVE_METHOD(dvdnav_get_current_time) +- RESOLVE_METHOD(dvdnav_get_video_resolution) +- RESOLVE_METHOD(dvdnav_toggle_spu_stream) +- RESOLVE_METHOD(dvdnav_set_active_stream) +- RESOLVE_METHOD(dvdnav_program_play) +- RESOLVE_METHOD(dvdnav_current_title_program) +- END_METHOD_RESOLVE() +-}; +diff --git a/xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/config.h b/xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/config.h +deleted file mode 100644 +index 0a310ea40f..0000000000 +--- a/xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/config.h ++++ /dev/null +@@ -1,76 +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 +- +-/* config.h. Generated by hand. */ +-#if defined(TARGET_POSIX) +-#include "PlatformDefs.h" +-#else +-#include <windows.h> +-#endif +-#include <stdio.h> +- +-//#define HAVE_DLFCN_H 1 +-#define HAVE_DVDCSS_DVDCSS_H 1 +-/* #undef HAVE_DVDCSS_DVDCSS_H*/ +-/* #undef HAVE_INTTYPES_H */ +-#define HAVE_MEMORY_H 1 +-#define HAVE_STDINT_H 1 +-#define HAVE_STDLIB_H 1 +-#define HAVE_STRINGS_H 1 +-#define HAVE_STRING_H 1 +-#define HAVE_SYS_STAT_H 1 +-#define HAVE_SYS_TYPES_H 1 +-/* #undef HAVE_UNISTD_H */ +-#ifndef PACKAGE +-#define PACKAGE "libdvdread" +-#endif +-#ifndef PACKAGE_BUGREPORT +-#define PACKAGE_BUGREPORT "" +-#endif +-#ifndef PACKAGE_NAME +-#define PACKAGE_NAME "" +-#endif +-#ifndef PACKAGE_STRING +-#define PACKAGE_STRING "" +-#endif +-#ifndef PACKAGE_TARNAME +-#define PACKAGE_TARNAME "" +-#endif +-#ifndef PACKAGE_VERSION +-#define PACKAGE_VERSION "" +-#endif +-#define STDC_HEADERS 1 +-#ifndef VERSION +-#define VERSION "1.2.6" +-#endif +-/* #undef WORDS_BIGENDIAN */ +-/* #undef __DARWIN__ */ +-/* #undef const */ +-#define inline __inline +-/* #undef size_t */ +- +-#define ssize_t int +- +-#ifndef PATH_MAX +-#define PATH_MAX MAX_PATH +-#endif +- +-#ifndef S_ISDIR +-#define S_ISDIR(m) ((m) & _S_IFDIR) +-#endif +-#ifndef S_ISREG +-#define S_ISREG(m) ((m) & _S_IFREG) +-#endif +-#ifndef S_ISBLK +-#define S_ISBLK(m) 0 +-#endif +-#ifndef S_ISCHR +-#define S_ISCHR(m) 0 +-#endif +diff --git a/xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/dvd_reader.h b/xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/dvd_reader.h +deleted file mode 100644 +index ba802628f2..0000000000 +--- a/xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/dvd_reader.h ++++ /dev/null +@@ -1,370 +0,0 @@ +-/* +- * Copyright (C) 2001, 2002 Billy Biggs <vektor@dumbterm.net>, +- * Håkan Hjort <d95hjort@dtek.chalmers.se>, +- * Björn Englund <d4bjorn@dtek.chalmers.se> +- * +- * This file is part of libdvdread. +- * +- * libdvdread is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * libdvdread is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License along +- * with libdvdread; if not, write to the Free Software Foundation, Inc., +- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +- */ +- +-#pragma once +- +-#ifdef _MSC_VER +-#include "config.h" +- +-#include <stdio.h> +-#include <stdlib.h> +-#endif +- +-#include <sys/types.h> +-//#include <inttypes.h> +-#include <stdarg.h> +- +-/***************************************************************************** +-* iovec structure: vectored data entry +-*****************************************************************************/ +-#ifdef TARGET_WINDOWS +-struct iovec +-{ +- void *iov_base; /* Pointer to data. */ +- size_t iov_len; /* Length of data. */ +-}; +-#else +-# include <sys/uio.h> /* struct iovec */ +-#endif +- +-/** +- * The DVD access interface. +- * +- * This file contains the functions that form the interface for +- * reading files located on a DVD. +- */ +- +-/** +- * The length of one Logical Block of a DVD. +- */ +-#define DVD_VIDEO_LB_LEN 2048 +- +-/** +- * Maximum length of filenames allowed in UDF. +- */ +-#define MAX_UDF_FILE_NAME_LEN 2048 +- +-#ifdef __cplusplus +-extern "C" { +-#endif +- +-/** +- * Opaque type that is used as a handle for one instance of an opened DVD. +- */ +-typedef struct dvd_reader_s dvd_reader_t; +-typedef struct dvd_reader_device_s dvd_reader_device_t; +- +-/** +- * Opaque type for a file read handle, much like a normal fd or FILE *. +- */ +-typedef struct dvd_file_s dvd_file_t; +- +-struct dvd_reader_stream_cb +-{ +- int (*pf_seek)(void* p_stream, uint64_t i_pos); +- int (*pf_read)(void* p_stream, void* buffer, int i_read); +- int (*pf_readv)(void* p_stream, void* p_iovec, int i_blocks); +-}; +-typedef struct dvd_reader_stream_cb dvd_reader_stream_cb; +- +-/** +- * Custom logger callback for DVDOpen[Stream]2 +- * @param private Handle as provided in Open functions +- * @param level Log level +- * @param fmt Format string +- * @param args Arguments list +- * pf_log(priv, level, fmt, args); +- */ +-typedef enum +-{ +- DVD_LOGGER_LEVEL_INFO, +- DVD_LOGGER_LEVEL_ERROR, +- DVD_LOGGER_LEVEL_WARN, +- DVD_LOGGER_LEVEL_DEBUG, +-} dvd_logger_level_t; +- +-typedef struct +-{ +- void (*pf_log)(void*, dvd_logger_level_t, const char*, va_list); +-} dvd_logger_cb; +- +-/** +- * Public type that is used to provide statistics on a handle. +- */ +-typedef struct { +- off_t size; /**< Total size of file in bytes */ +- int nr_parts; /**< Number of file parts */ +- off_t parts_size[9]; /**< Size of each part in bytes */ +-} dvd_stat_t; +- +-/** +- * Opens a block device of a DVD-ROM file, or an image file, or a directory +- * name for a mounted DVD or HD copy of a DVD. +- * The second form of Open function (DVDOpenStream) can be used to +- * provide custom stream_cb functions to access the DVD (see libdvdcss). +- * +- * If the given file is a block device, or is the mountpoint for a block +- * device, then that device is used for CSS authentication using libdvdcss. +- * If no device is available, then no CSS authentication is performed, +- * and we hope that the image is decrypted. +- * +- * If the path given is a directory, then the files in that directory may be +- * in any one of these formats: +- * +- * path/VIDEO_TS/VTS_01_1.VOB +- * path/video_ts/vts_01_1.vob +- * path/VTS_01_1.VOB +- * path/vts_01_1.vob +- * +- * @param path Specifies the the device, file or directory to be used. +- * @param stream is a private handle used by stream_cb +- * @param stream_cb is a struct containing seek and read functions +- * @return If successful a a read handle is returned. Otherwise 0 is returned. +- * +- * dvd = DVDOpen(path); +- * dvd = DVDOpenStream(stream, &stream_cb); +- */ +-dvd_reader_t *DVDOpen( const char * ); +-dvd_reader_t* DVDOpenStream(void*, dvd_reader_stream_cb*); +- +-/** +- * Same as DVDOpen, but with private handle to be passed back on callbacks +- * +- * @param path Specifies the the device, file or directory to be used. +- * @param priv is a private handle +- * @param logcb is a custom logger callback struct, or NULL if none needed +- * @param stream_cb is a struct containing seek and read functions +- * @return If successful a a read handle is returned. Otherwise 0 is returned. +- * +- * dvd = DVDOpen2(priv, logcb, path); +- * dvd = DVDOpenStream2(priv, logcb, &stream_cb); +- */ +-dvd_reader_t* DVDOpen2(void*, const dvd_logger_cb*, const char*); +-dvd_reader_t* DVDOpenStream2(void*, const dvd_logger_cb*, dvd_reader_stream_cb*); +- +-/** +- * Closes and cleans up the DVD reader object. +- * +- * You must close all open files before calling this function. +- * +- * @param dvd A read handle that should be closed. +- * +- * DVDClose(dvd); +- */ +-void DVDClose( dvd_reader_t * ); +- +-/** +- * +- */ +-typedef enum +-{ +- DVD_READ_INFO_FILE, /**< VIDEO_TS.IFO or VTS_XX_0.IFO (title) */ +- DVD_READ_INFO_BACKUP_FILE, /**< VIDEO_TS.BUP or VTS_XX_0.BUP (title) */ +- DVD_READ_MENU_VOBS, /**< VIDEO_TS.VOB or VTS_XX_0.VOB (title) */ +- DVD_READ_TITLE_VOBS /**< VTS_XX_[1-9].VOB (title). All files in +- the title set are opened and read as a +- single file. */ +-} dvd_read_domain_t; +- +-/** +- * Stats a file on the DVD given the title number and domain. +- * The information about the file is stored in a dvd_stat_t +- * which contains information about the size of the file and +- * the number of parts in case of a multipart file and the respective +- * sizes of the parts. +- * A multipart file is for instance VTS_02_1.VOB, VTS_02_2.VOB, VTS_02_3.VOB +- * The size of VTS_02_1.VOB will be stored in stat->parts_size[0], +- * VTS_02_2.VOB in stat->parts_size[1], ... +- * The total size (sum of all parts) is stored in stat->size and +- * stat->nr_parts will hold the number of parts. +- * Only DVD_READ_TITLE_VOBS (VTS_??_[1-9].VOB) can be multipart files. +- * +- * This function is only of use if you want to get the size of each file +- * in the filesystem. These sizes are not needed to use any other +- * functions in libdvdread. +- * +- * @param dvd A dvd read handle. +- * @param titlenum Which Video Title Set should be used, VIDEO_TS is 0. +- * @param domain Which domain. +- * @param stat Pointer to where the result is stored. +- * @return If successful 0, otherwise -1. +- * +- * int DVDFileStat(dvd, titlenum, domain, stat); +- */ +-int DVDFileStat(dvd_reader_t *, int, dvd_read_domain_t, dvd_stat_t *); +- +-/** +- * Opens a file on the DVD given the title number and domain. +- * +- * If the title number is 0, the video manager information is opened +- * (VIDEO_TS.[IFO,BUP,VOB]). Returns a file structure which may be +- * used for reads, or 0 if the file was not found. +- * +- * @param dvd A dvd read handle. +- * @param titlenum Which Video Title Set should be used, VIDEO_TS is 0. +- * @param domain Which domain. +- * @return If successful a a file read handle is returned, otherwise 0. +- * +- * dvd_file = DVDOpenFile(dvd, titlenum, domain); */ +-dvd_file_t *DVDOpenFile( dvd_reader_t *, int, dvd_read_domain_t ); +- +-/** +- * Closes a file and frees the associated structure. +- * +- * @param dvd_file The file read handle to be closed. +- * +- * DVDCloseFile(dvd_file); +- */ +-void DVDCloseFile( dvd_file_t * ); +- +-/** +- * Reads block_count number of blocks from the file at the given block offset. +- * Returns number of blocks read on success, -1 on error. This call is only +- * for reading VOB data, and should not be used when reading the IFO files. +- * When reading from an encrypted drive, blocks are decrypted using libdvdcss +- * where required. +- * +- * @param dvd_file A file read handle. +- * @param offset Block offset from the start of the file to start reading at. +- * @param block_count Number of block to read. +- * @param data Pointer to a buffer to write the data into. +- * @return Returns number of blocks read on success, -1 on error. +- * +- * blocks_read = DVDReadBlocks(dvd_file, offset, block_count, data); +- */ +-ssize_t DVDReadBlocks( dvd_file_t *, int, size_t, unsigned char * ); +- +-/** +- * Seek to the given position in the file. Returns the resulting position in +- * bytes from the beginning of the file. The seek position is only used for +- * byte reads from the file, the block read call always reads from the given +- * offset. +- * +- * @param dvd_file A file read handle. +- * @param seek_offset Byte offset from the start of the file to seek to. +- * @return The resulting position in bytes from the beginning of the file. +- * +- * offset_set = DVDFileSeek(dvd_file, seek_offset); +- */ +-int32_t DVDFileSeek( dvd_file_t *, int32_t ); +- +-/** +- * Reads the given number of bytes from the file. This call can only be used +- * on the information files, and may not be used for reading from a VOB. This +- * reads from and increments the current seek position for the file. +- * +- * @param dvd_file A file read handle. +- * @param data Pointer to a buffer to write the data into. +- * @param bytes Number of bytes to read. +- * @return Returns number of bytes read on success, -1 on error. +- * +- * bytes_read = DVDReadBytes(dvd_file, data, bytes); +- */ +-ssize_t DVDReadBytes( dvd_file_t *, void *, size_t ); +- +-/** +- * Returns the file size in blocks. +- * +- * @param dvd_file A file read handle. +- * @return The size of the file in blocks, -1 on error. +- * +- * blocks = DVDFileSize(dvd_file); +- */ +-ssize_t DVDFileSize( dvd_file_t * ); +- +-/** +- * Get a unique 128 bit disc ID. +- * This is the MD5 sum of VIDEO_TS.IFO and the VTS_0?_0.IFO files +- * in title order (those that exist). +- * If you need a 'text' representation of the id, print it as a +- * hexadecimal number, using lowercase letters, discid[0] first. +- * I.e. the same format as the command-line 'md5sum' program uses. +- * +- * @param dvd A read handle to get the disc ID from +- * @param discid The buffer to put the disc ID into. The buffer must +- * have room for 128 bits (16 chars). +- * @return 0 on success, -1 on error. +- */ +-int DVDDiscID( dvd_reader_t *, unsigned char * ); +- +-/** +- * Get the UDF VolumeIdentifier and VolumeSetIdentifier +- * from the PrimaryVolumeDescriptor. +- * +- * @param dvd A read handle to get the disc ID from +- * @param volid The buffer to put the VolumeIdentifier into. +- * The VolumeIdentifier is latin-1 encoded (8bit unicode) +- * null terminated and max 32 bytes (including '\0') +- * @param volid_size No more than volid_size bytes will be copied to volid. +- * If the VolumeIdentifier is truncated because of this +- * it will still be null terminated. +- * @param volsetid The buffer to put the VolumeSetIdentifier into. +- * The VolumeIdentifier is 128 bytes as +- * stored in the UDF PrimaryVolumeDescriptor. +- * Note that this is not a null terminated string. +- * @param volsetid_size At most volsetid_size bytes will be copied to volsetid. +- * @return 0 on success, -1 on error. +- */ +-int DVDUDFVolumeInfo(dvd_reader_t*, char*, unsigned int, unsigned char*, unsigned int); +- +-int DVDFileSeekForce( dvd_file_t *, int offset, int force_size); +- +-/** +- * Get the ISO9660 VolumeIdentifier and VolumeSetIdentifier +- * +- * * Only use this function as fallback if DVDUDFVolumeInfo returns -1 * +- * * this will happen on a disc mastered only with a iso9660 filesystem * +- * * All video DVD discs have UDF filesystem * +- * +- * @param dvd A read handle to get the disc ID from +- * @param volid The buffer to put the VolumeIdentifier into. +- * The VolumeIdentifier is coded with '0-9','A-Z','_' +- * null terminated and max 33 bytes (including '\0') +- * @param volid_size No more than volid_size bytes will be copied to volid. +- * If the VolumeIdentifier is truncated because of this +- * it will still be null terminated. +- * @param volsetid The buffer to put the VolumeSetIdentifier into. +- * The VolumeIdentifier is 128 bytes as +- * stored in the ISO9660 PrimaryVolumeDescriptor. +- * Note that this is not a null terminated string. +- * @param volsetid_size At most volsetid_size bytes will be copied to volsetid. +- * @return 0 on success, -1 on error. +- */ +-int DVDISOVolumeInfo(dvd_reader_t*, char*, unsigned int, unsigned char*, unsigned int); +- +-/** +- * Sets the level of caching that is done when reading from a device +- * +- * @param dvd A read handle to get the disc ID from +- * @param level The level of caching wanted. +- * -1 - returns the current setting. +- * 0 - UDF Cache turned off. +- * 1 - (default level) Pointers to IFO files and some data from +- * PrimaryVolumeDescriptor are cached. +- * +- * @return The level of caching. +- */ +-int DVDUDFCacheLevel( dvd_reader_t *, int ); +- +-#ifdef __cplusplus +-}; +-#endif +diff --git a/xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/dvd_types.h b/xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/dvd_types.h +deleted file mode 100644 +index 5b2e802951..0000000000 +--- a/xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/dvd_types.h ++++ /dev/null +@@ -1,282 +0,0 @@ +-/* +- * Copyright (C) 2000, 2001 Björn Englund, Håkan Hjort +- * +- * This file is part of libdvdnav, a DVD navigation library. It is a modified +- * file originally part of the Ogle DVD player project. +- * +- * libdvdnav is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * libdvdnav is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License along +- * with libdvdnav; if not, write to the Free Software Foundation, Inc., +- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +- */ +- +-/* +- * Various useful structs and enums for DVDs. +- */ +- +-#pragma once +- +-#include <stdint.h> +- +-/* +- * DVD Menu ID +- * (see dvdnav_menu_call()) +- */ +-typedef enum { +- /* When used in VTS domain, DVD_MENU_Escape behaves like DVD_MENU_Root, +- * but from within a menu domain, DVD_MENU_Escape resumes playback. */ +- DVD_MENU_Escape = 0, +- DVD_MENU_Title = 2, +- DVD_MENU_Root = 3, +- DVD_MENU_Subpicture = 4, +- DVD_MENU_Audio = 5, +- DVD_MENU_Angle = 6, +- DVD_MENU_Part = 7 +-} DVDMenuID_t; +- +-/* +- * Stream Types +- * (see dvdnav_get_number_of_streams()) +- */ +-typedef enum +-{ +- DVD_SUBTITLE_STREAM = 0, +- DVD_AUDIO_STREAM = 1 +-} dvdnav_stream_type_t; +- +-/* Domain */ +-typedef enum +-{ +- DVD_DOMAIN_FirstPlay = 1, /* First Play Domain */ +- DVD_DOMAIN_VTSTitle = 2, /* Video Title Set Domain */ +- DVD_DOMAIN_VMGM = 4, /* Video Manager Domain */ +- DVD_DOMAIN_VTSMenu = 8 /* Video Title Set Menu Domain */ +-} DVDDomain_t; +- +-/* +- * Structure containing info on highlight areas +- * (see dvdnav_get_highlight_area()) +- */ +-typedef struct { +- uint32_t palette; /* The CLUT entries for the highlight palette +- (4-bits per entry -> 4 entries) */ +- uint16_t sx,sy,ex,ey; /* The start/end x,y positions */ +- uint32_t pts; /* Highlight PTS to match with SPU */ +- +- /* button number for the SPU decoder/overlaying engine */ +- uint32_t buttonN; +-} dvdnav_highlight_area_t; +- +-/* The audio format */ +-typedef enum +-{ +- DVD_AUDIO_FORMAT_AC3 = 0, +- DVD_AUDIO_FORMAT_UNKNOWN_1 = 1, +- DVD_AUDIO_FORMAT_MPEG = 2, +- DVD_AUDIO_FORMAT_MPEG2_EXT = 3, +- DVD_AUDIO_FORMAT_LPCM = 4, +- DVD_AUDIO_FORMAT_UNKNOWN_5 = 5, +- DVD_AUDIO_FORMAT_DTS = 6, +- DVD_AUDIO_FORMAT_SDDS = 7 +-} DVDAudioFormat_t; +- +-/* the following types are currently unused */ +- +-#if 0 +- +-/* User operation permissions */ +-typedef enum { +- UOP_FLAG_TitleOrTimePlay = 0x00000001, +- UOP_FLAG_ChapterSearchOrPlay = 0x00000002, +- UOP_FLAG_TitlePlay = 0x00000004, +- UOP_FLAG_Stop = 0x00000008, +- UOP_FLAG_GoUp = 0x00000010, +- UOP_FLAG_TimeOrChapterSearch = 0x00000020, +- UOP_FLAG_PrevOrTopPGSearch = 0x00000040, +- UOP_FLAG_NextPGSearch = 0x00000080, +- UOP_FLAG_ForwardScan = 0x00000100, +- UOP_FLAG_BackwardScan = 0x00000200, +- UOP_FLAG_TitleMenuCall = 0x00000400, +- UOP_FLAG_RootMenuCall = 0x00000800, +- UOP_FLAG_SubPicMenuCall = 0x00001000, +- UOP_FLAG_AudioMenuCall = 0x00002000, +- UOP_FLAG_AngleMenuCall = 0x00004000, +- UOP_FLAG_ChapterMenuCall = 0x00008000, +- UOP_FLAG_Resume = 0x00010000, +- UOP_FLAG_ButtonSelectOrActivate = 0x00020000, +- UOP_FLAG_StillOff = 0x00040000, +- UOP_FLAG_PauseOn = 0x00080000, +- UOP_FLAG_AudioStreamChange = 0x00100000, +- UOP_FLAG_SubPicStreamChange = 0x00200000, +- UOP_FLAG_AngleChange = 0x00400000, +- UOP_FLAG_KaraokeAudioPresModeChange = 0x00800000, +- UOP_FLAG_VideoPresModeChange = 0x01000000 +-} DVDUOP_t; +- +-/* Parental Level */ +-typedef enum { +- DVD_PARENTAL_LEVEL_1 = 1, +- DVD_PARENTAL_LEVEL_2 = 2, +- DVD_PARENTAL_LEVEL_3 = 3, +- DVD_PARENTAL_LEVEL_4 = 4, +- DVD_PARENTAL_LEVEL_5 = 5, +- DVD_PARENTAL_LEVEL_6 = 6, +- DVD_PARENTAL_LEVEL_7 = 7, +- DVD_PARENTAL_LEVEL_8 = 8, +- DVD_PARENTAL_LEVEL_None = 15 +-} DVDParentalLevel_t; +- +-/* Language ID (ISO-639 language code) */ +-typedef uint16_t DVDLangID_t; +- +-/* Country ID (ISO-3166 country code) */ +-typedef uint16_t DVDCountryID_t; +- +-/* Register */ +-typedef uint16_t DVDRegister_t; +-typedef enum { +- DVDFalse = 0, +- DVDTrue = 1 +-} DVDBool_t; +-typedef DVDRegister_t DVDGPRMArray_t[16]; +-typedef DVDRegister_t DVDSPRMArray_t[24]; +- +-/* Navigation */ +-typedef int DVDStream_t; +-typedef int DVDPTT_t; +-typedef int DVDTitle_t; +- +-/* Angle number (1-9 or default?) */ +-typedef int DVDAngle_t; +- +-/* Timecode */ +-typedef struct { +- uint8_t Hours; +- uint8_t Minutes; +- uint8_t Seconds; +- uint8_t Frames; +-} DVDTimecode_t; +- +-/* Subpicture stream number (0-31,62,63) */ +-typedef int DVDSubpictureStream_t; +- +-/* Audio stream number (0-7, 15(none)) */ +-typedef int DVDAudioStream_t; +- +-/* The audio application mode */ +-typedef enum { +- DVD_AUDIO_APP_MODE_None = 0, +- DVD_AUDIO_APP_MODE_Karaoke = 1, +- DVD_AUDIO_APP_MODE_Surround = 2, +- DVD_AUDIO_APP_MODE_Other = 3 +-} DVDAudioAppMode_t; +- +-/* Audio language extension */ +-typedef enum { +- DVD_AUDIO_LANG_EXT_NotSpecified = 0, +- DVD_AUDIO_LANG_EXT_NormalCaptions = 1, +- DVD_AUDIO_LANG_EXT_VisuallyImpaired = 2, +- DVD_AUDIO_LANG_EXT_DirectorsComments1 = 3, +- DVD_AUDIO_LANG_EXT_DirectorsComments2 = 4 +-} DVDAudioLangExt_t; +- +-/* Subpicture language extension */ +-typedef enum { +- DVD_SUBPICTURE_LANG_EXT_NotSpecified = 0, +- DVD_SUBPICTURE_LANG_EXT_NormalCaptions = 1, +- DVD_SUBPICTURE_LANG_EXT_BigCaptions = 2, +- DVD_SUBPICTURE_LANG_EXT_ChildrensCaptions = 3, +- DVD_SUBPICTURE_LANG_EXT_NormalCC = 5, +- DVD_SUBPICTURE_LANG_EXT_BigCC = 6, +- DVD_SUBPICTURE_LANG_EXT_ChildrensCC = 7, +- DVD_SUBPICTURE_LANG_EXT_Forced = 9, +- DVD_SUBPICTURE_LANG_EXT_NormalDirectorsComments = 13, +- DVD_SUBPICTURE_LANG_EXT_BigDirectorsComments = 14, +- DVD_SUBPICTURE_LANG_EXT_ChildrensDirectorsComments = 15, +-} DVDSubpictureLangExt_t; +- +-/* Karaoke Downmix mode */ +-typedef enum { +- DVD_KARAOKE_DOWNMIX_0to0 = 0x0001, +- DVD_KARAOKE_DOWNMIX_1to0 = 0x0002, +- DVD_KARAOKE_DOWNMIX_2to0 = 0x0004, +- DVD_KARAOKE_DOWNMIX_3to0 = 0x0008, +- DVD_KARAOKE_DOWNMIX_4to0 = 0x0010, +- DVD_KARAOKE_DOWNMIX_Lto0 = 0x0020, +- DVD_KARAOKE_DOWNMIX_Rto0 = 0x0040, +- DVD_KARAOKE_DOWNMIX_0to1 = 0x0100, +- DVD_KARAOKE_DOWNMIX_1to1 = 0x0200, +- DVD_KARAOKE_DOWNMIX_2to1 = 0x0400, +- DVD_KARAOKE_DOWNMIX_3to1 = 0x0800, +- DVD_KARAOKE_DOWNMIX_4to1 = 0x1000, +- DVD_KARAOKE_DOWNMIX_Lto1 = 0x2000, +- DVD_KARAOKE_DOWNMIX_Rto1 = 0x4000 +-} DVDKaraokeDownmix_t; +-typedef int DVDKaraokeDownmixMask_t; +- +-/* Display mode */ +-typedef enum { +- DVD_DISPLAY_MODE_ContentDefault = 0, +- DVD_DISPLAY_MODE_16x9 = 1, +- DVD_DISPLAY_MODE_4x3PanScan = 2, +- DVD_DISPLAY_MODE_4x3Letterboxed = 3 +-} DVDDisplayMode_t; +- +-/* Audio attributes */ +-typedef struct { +- DVDAudioAppMode_t AppMode; +- DVDAudioFormat_t AudioFormat; +- DVDLangID_t Language; +- DVDAudioLangExt_t LanguageExtension; +- DVDBool_t HasMultichannelInfo; +- DVDAudioSampleFreq_t SampleFrequency; +- DVDAudioSampleQuant_t SampleQuantization; +- DVDChannelNumber_t NumberOfChannels; +-} DVDAudioAttributes_t; +-typedef int DVDAudioSampleFreq_t; +-typedef int DVDAudioSampleQuant_t; +-typedef int DVDChannelNumber_t; +- +-/* Subpicture attributes */ +-typedef enum { +- DVD_SUBPICTURE_TYPE_NotSpecified = 0, +- DVD_SUBPICTURE_TYPE_Language = 1, +- DVD_SUBPICTURE_TYPE_Other = 2 +-} DVDSubpictureType_t; +-typedef enum { +- DVD_SUBPICTURE_CODING_RunLength = 0, +- DVD_SUBPICTURE_CODING_Extended = 1, +- DVD_SUBPICTURE_CODING_Other = 2 +-} DVDSubpictureCoding_t; +-typedef struct { +- DVDSubpictureType_t Type; +- DVDSubpictureCoding_t CodingMode; +- DVDLangID_t Language; +- DVDSubpictureLangExt_t LanguageExtension; +-} DVDSubpictureAttributes_t; +- +-/* Video attributes */ +-typedef struct { +- DVDBool_t PanscanPermitted; +- DVDBool_t LetterboxPermitted; +- int AspectX; +- int AspectY; +- int FrameRate; +- int FrameHeight; +- DVDVideoCompression_t Compression; +- DVDBool_t Line21Field1InGop; +- DVDBool_t Line21Field2InGop; +- int more_to_come; +-} DVDVideoAttributes_t; +-typedef int DVDVideoCompression_t; +- +-#endif +diff --git a/xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/dvdnav.h b/xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/dvdnav.h +deleted file mode 100644 +index 63d501b959..0000000000 +--- a/xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/dvdnav.h ++++ /dev/null +@@ -1,789 +0,0 @@ +-/* +- * Copyright (C) 2001 Rich Wareham <richwareham@users.sourceforge.net> +- * +- * This file is part of libdvdnav, a DVD navigation library. +- * +- * libdvdnav is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * libdvdnav is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License along +- * with libdvdnav; if not, write to the Free Software Foundation, Inc., +- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +- */ +- +-/* +- * This is the main header file applications should include if they want +- * to access dvdnav functionality. +- */ +- +-#pragma once +- +-#ifdef __cplusplus +-extern "C" { +-#endif +- +-#include "dvd_reader.h" +-#include "dvd_types.h" +-#include "dvdnav_events.h" +-#include "nav_types.h" +-#include "version.h" +- +-#include <stdarg.h> +- +- /********************************************************************* +- * dvdnav data types * +- *********************************************************************/ +- +- /* +- * Opaque data-type can be viewed as a 'DVD handle'. You should get +- * a pointer to a dvdnav_t from the dvdnav_open() function. +- * Never call free() on the pointer, you have to give it back with +- * dvdnav_close(). +- */ +- typedef struct dvdnav_s dvdnav_t; +- +- /* Status as reported by most of libdvdnav's functions */ +- typedef int32_t dvdnav_status_t; +- +- typedef dvd_reader_stream_cb dvdnav_stream_cb; +- +-/* +- * Unless otherwise stated, all functions return DVDNAV_STATUS_OK if +- * they succeeded, otherwise DVDNAV_STATUS_ERR is returned and the error may +- * be obtained by calling dvdnav_err_to_string(). +- */ +-#define DVDNAV_STATUS_ERR 0 +-#define DVDNAV_STATUS_OK 1 +- +-/********************************************************************* +- * initialisation & housekeeping functions * +- *********************************************************************/ +- +-/* +- * Logger callback definition +- */ +-typedef enum +-{ +- DVDNAV_LOGGER_LEVEL_INFO, +- DVDNAV_LOGGER_LEVEL_ERROR, +- DVDNAV_LOGGER_LEVEL_WARN, +- DVDNAV_LOGGER_LEVEL_DEBUG, +-} dvdnav_logger_level_t; +- +-typedef struct +-{ +- void (*pf_log)(void*, dvdnav_logger_level_t, const char*, va_list); +-} dvdnav_logger_cb; +- +-/* +- * These functions allow you to open a DVD device and associate it +- * with a dvdnav_t. +- */ +- +-/* +- * Attempts to open the DVD drive at the specified path or using external +- * seek/read functions (dvdnav_open_stream) and pre-cache the CSS-keys. +- * libdvdread is used to access the DVD, so any source supported by libdvdread +- * can be given with "path" or "stream_cb". Currently, using dvdnav_open, +- * libdvdread can access : DVD drives, DVD image files, DVD file-by-file +- * copies. Using dvdnav_open_stream, libdvdread can access any kind of DVD +- * storage via custom implementation of seek/read functions. +- * +- * The resulting dvdnav_t handle will be written to *dest. +- */ +-dvdnav_status_t dvdnav_open(dvdnav_t **dest, const char *path); +-dvdnav_status_t dvdnav_open_stream(dvdnav_t** dest, void* priv, dvdnav_stream_cb* stream_cb); +- +-dvdnav_status_t dvdnav_open2(dvdnav_t** dest, void*, const dvdnav_logger_cb*, const char* path); +-dvdnav_status_t dvdnav_open_stream2(dvdnav_t** dest, +- void* priv, +- const dvdnav_logger_cb*, +- dvdnav_stream_cb* stream_cb); +- +-dvdnav_status_t dvdnav_dup(dvdnav_t** dest, dvdnav_t* src); +-dvdnav_status_t dvdnav_free_dup(dvdnav_t* _this); +- +-/* +- * Closes a dvdnav_t previously opened with dvdnav_open(), freeing any +- * memory associated with it. +- */ +-dvdnav_status_t dvdnav_close(dvdnav_t *self); +- +-/* +- * Resets the DVD virtual machine and cache buffers. +- */ +-dvdnav_status_t dvdnav_reset(dvdnav_t *self); +- +-/* +- * Fills a pointer with a value pointing to a string describing +- * the path associated with an open dvdnav_t. It assigns *path to NULL +- * on error. +- */ +-dvdnav_status_t dvdnav_path(dvdnav_t *self, const char **path); +- +-/* +- * Returns a human-readable string describing the last error. +- */ +-const char* dvdnav_err_to_string(dvdnav_t *self); +- +-const char* dvdnav_version(void); +- +-/********************************************************************* +- * changing and reading DVD player characteristics * +- *********************************************************************/ +- +-/* +- * These functions allow you to manipulate the various global characteristics +- * of the DVD playback engine. +- */ +- +-/* +- * Sets the region mask (bit 0 set implies region 1, bit 1 set implies +- * region 2, etc) of the virtual machine. Generally you will only need to set +- * this if you are playing RCE discs which query the virtual machine as to its +- * region setting. +- * +- * This has _nothing_ to do with the region setting of the DVD drive. +- */ +-dvdnav_status_t dvdnav_set_region_mask(dvdnav_t *self, int32_t region_mask); +- +-/* +- * Returns the region mask (bit 0 set implies region 1, bit 1 set implies +- * region 2, etc) of the virtual machine. +- * +- * This has _nothing_ to do with the region setting of the DVD drive. +- */ +-dvdnav_status_t dvdnav_get_region_mask(dvdnav_t *self, int32_t *region_mask); +- +-/* +- * Specify whether read-ahead caching should be used. You may not want this if your +- * decoding engine does its own buffering. +- * +- * The default read-ahead cache does not use an additional thread for the reading +- * (see read_cache.c for a threaded cache, but note that this code is currently +- * unmaintained). It prebuffers on VOBU level by reading ahead several buffers +- * on every read request. The speed of this prebuffering has been optimized to +- * also work on slow DVD drives. +- * +- * If in addition you want to prevent memcpy's to improve performance, have a look +- * at dvdnav_get_next_cache_block(). +- */ +-dvdnav_status_t dvdnav_set_readahead_flag(dvdnav_t *self, int32_t read_ahead_flag); +- +-/* +- * Query whether read-ahead caching/buffering will be used. +- */ +-dvdnav_status_t dvdnav_get_readahead_flag(dvdnav_t *self, int32_t *read_ahead_flag); +- +-/* +- * Specify whether the positioning works PGC or PG based. +- * Programs (PGs) on DVDs are similar to Chapters and a program chain (PGC) +- * usually covers a whole feature. This affects the behaviour of the +- * functions dvdnav_get_position() and dvdnav_sector_search(). See there. +- * Default is PG based positioning. +- */ +-dvdnav_status_t dvdnav_set_PGC_positioning_flag(dvdnav_t *self, int32_t pgc_based_flag); +- +-/* +- * Query whether positioning is PG or PGC based. +- */ +-dvdnav_status_t dvdnav_get_PGC_positioning_flag(dvdnav_t *self, int32_t *pgc_based_flag); +- +- +-/********************************************************************* +- * reading data * +- *********************************************************************/ +- +-/* +- * These functions are used to poll the playback engine and actually get data +- * off the DVD. +- */ +- +-/* +- * Attempts to get the next block off the DVD and copies it into the buffer 'buf'. +- * If there is any special actions that may need to be performed, the value +- * pointed to by 'event' gets set accordingly. +- * +- * If 'event' is DVDNAV_BLOCK_OK then 'buf' is filled with the next block +- * (note that means it has to be at /least/ 2048 bytes big). 'len' is +- * then set to 2048. +- * +- * Otherwise, buf is filled with an appropriate event structure and +- * len is set to the length of that structure. +- * +- * See the dvdnav_events.h header for information on the various events. +- */ +-dvdnav_status_t dvdnav_get_next_block(dvdnav_t* self, uint8_t* buf, int32_t* event, int32_t* len); +- +-/* +- * This basically does the same as dvdnav_get_next_block. The only difference is +- * that it avoids a memcopy, when the requested block was found in the cache. +- * In such a case (cache hit) this function will return a different pointer than +- * the one handed in, pointing directly into the relevant block in the cache. +- * Those pointers must _never_ be freed but instead returned to the library via +- * dvdnav_free_cache_block(). +- */ +-dvdnav_status_t dvdnav_get_next_cache_block(dvdnav_t* self, +- uint8_t** buf, +- int32_t* event, +- int32_t* len); +- +-/* +- * All buffers which came from the internal cache (when dvdnav_get_next_cache_block() +- * returned a buffer different from the one handed in) have to be freed with this +- * function. Although handing in other buffers not from the cache doesn't cause any harm. +- */ +-dvdnav_status_t dvdnav_free_cache_block(dvdnav_t *self, unsigned char *buf); +- +-/* +- * If we are currently in a still-frame this function skips it. +- * +- * See also the DVDNAV_STILL_FRAME event. +- */ +-dvdnav_status_t dvdnav_still_skip(dvdnav_t *self); +- +-/* +- * If we are currently in WAIT state, that is: the application is required to +- * wait for its fifos to become empty, calling this signals libdvdnav that this +- * is achieved and that it can continue. +- * +- * See also the DVDNAV_WAIT event. +- */ +-dvdnav_status_t dvdnav_wait_skip(dvdnav_t *self); +- +-/* +- * Returns the still time from the currently playing cell. +- * The still time is given in seconds with 0xff meaning an indefinite still. +- * +- * This function can be used to detect still frames before they are reached. +- * Some players might need this to prepare for a frame to be shown for a +- * longer time than usual. +- */ +-uint32_t dvdnav_get_next_still_flag(dvdnav_t *self); +- +-/* +- * Stops playback. The next event obtained with one of the get_next_block +- * functions will be a DVDNAV_STOP event. +- * +- * It is not required to call this before dvdnav_close(). +- */ +-dvdnav_status_t dvdnav_stop(dvdnav_t *self); +- +-/* +- * Returns the region mask (bit 0 set implies region 1, bit 1 set implies +- * region 2, etc) reported by the dvd disc being played. +- * +- * Note this has no relation with the region setting of the DVD drive. +- * Old DVD drives (RPC-I) used to delegate most of the RCE handling to the CPU and +- * will actually call the virtual machine (VM) for its region setting. In those cases, +- * changing the VM region mask via dvdnav_set_region_mask() will circunvent +- * the region protection scheme. This is no longer the case with more recent (RPC-II) drives +- * as RCE is handled internally by the drive firmware. +- * +- */ +-dvdnav_status_t dvdnav_get_disk_region_mask(dvdnav_t* self, int32_t* region_mask); +- +-/********************************************************************* +- * title/part navigation * +- *********************************************************************/ +- +-/* +- * Returns the number of titles on the disk. +- */ +-dvdnav_status_t dvdnav_get_number_of_titles(dvdnav_t *self, int32_t *titles); +- +-/* +- * Returns the number of parts within the given title. +- */ +-dvdnav_status_t dvdnav_get_number_of_parts(dvdnav_t *self, int32_t title, int32_t *parts); +- +-/* +- * Returns the number of angles for the given title. +- */ +-dvdnav_status_t dvdnav_get_number_of_angles(dvdnav_t* self, int32_t title, int32_t* angles); +- +-/* +- * Plays the specified title of the DVD from its beginning (that is: part 1). +- */ +-dvdnav_status_t dvdnav_title_play(dvdnav_t *self, int32_t title); +- +-/* +- * Plays the specified title, starting from the specified part. +- */ +-dvdnav_status_t dvdnav_part_play(dvdnav_t *self, int32_t title, int32_t part); +- +-/* +- * Plays the specified title, starting from the specified program +- */ +-dvdnav_status_t dvdnav_program_play(dvdnav_t *self, int32_t title, int32_t pgcn, int32_t pgn); +- +-/* +- * Stores in *times an array (that the application *must* free) of +- * dvdtimes corresponding to the chapter times for the chosen title. +- * *duration will have the duration of the title +- * The number of entries in *times is the result of the function. +- * On error *times is NULL and the output is 0 +- */ +-uint32_t dvdnav_describe_title_chapters(dvdnav_t *self, int32_t title, uint64_t **times, uint64_t *duration); +- +-/* +- * Play the specified amount of parts of the specified title of +- * the DVD then STOP. +- * +- * Currently unimplemented! +- */ +-dvdnav_status_t dvdnav_part_play_auto_stop(dvdnav_t* self, +- int32_t title, +- int32_t part, +- int32_t parts_to_play); +- +-/* +- * Play the specified title starting from the specified time. +- * +- * Currently unimplemented! +- */ +-dvdnav_status_t dvdnav_time_play(dvdnav_t* self, int32_t title, uint64_t time); +- +-/* +- * Stop playing the current position and jump to the specified menu. +- * +- * See also DVDMenuID_t from libdvdread +- */ +-dvdnav_status_t dvdnav_menu_call(dvdnav_t *self, DVDMenuID_t menu); +- +-/* +- * Return the title number and part currently being played. +- * A title of 0 indicates we are in a menu. In this case, part +- * is set to the current menu's ID. +- */ +-dvdnav_status_t dvdnav_current_title_info(dvdnav_t* self, int32_t* title, int32_t* part); +- +-/* +- * Return the title number, pgcn and pgn currently being played. +- * A title of 0 indicates, we are in a menu. +- */ +-dvdnav_status_t dvdnav_current_title_program(dvdnav_t* self, +- int32_t* title, +- int32_t* pgcn, +- int32_t* pgn); +- +-/* +- * Return the current position (in blocks) within the current +- * title and the length (in blocks) of said title. +- * +- * Current implementation is wrong and likely to behave unpredictably! +- * Use is discouraged! +- */ +-dvdnav_status_t dvdnav_get_position_in_title(dvdnav_t* self, uint32_t* pos, uint32_t* len); +- +-/* +- * This function is only available for compatibility reasons. +- * +- * Stop playing the current position and start playback of the current title +- * from the specified part. +- */ +-dvdnav_status_t dvdnav_part_search(dvdnav_t *self, int32_t part); +- +- +-/********************************************************************* +- * program chain/program navigation * +- *********************************************************************/ +- +-/* +- * Stop playing the current position and start playback from the last +- * VOBU boundary before the given sector. The sector number is not +- * meant to be an absolute physical DVD sector, but a relative sector +- * in the current program. This function cannot leave the current +- * program and will fail if asked to do so. +- * +- * If program chain based positioning is enabled +- * (see dvdnav_set_PGC_positioning_flag()), this will seek to the relative +- * sector inside the current program chain. +- * +- * 'origin' can be one of SEEK_SET, SEEK_CUR, SEEK_END as defined in +- * fcntl.h. +- */ +-dvdnav_status_t dvdnav_sector_search(dvdnav_t* self, int64_t offset, int32_t origin); +- +-/* +- returns the current stream time in PTS ticks as reported by the IFO structures +- divide it by 90000 to get the current play time in seconds +- */ +-int64_t dvdnav_get_current_time(dvdnav_t *self); +- +-/* +- * Stop playing the current position and start playback of the title +- * from the specified timecode. +- * +- * Currently implemented using interpolation. That interpolation is slightly +- * inaccurate. +- */ +-dvdnav_status_t dvdnav_time_search(dvdnav_t* self, uint64_t time); +- +-/* +- * Find the nearest vobu and jump to it +- * +- * Alternative to dvdnav_time_search (see full documentation on searching.jump_to_time.readme) +- * Jumps to the provided PTS (which is defined as time_in_ms * 90). mode means the navigation mode, +- * currently only the Default (0) is implemented: +- * 0: Default. Jump to a time which may be either <> time_in_pts_ticks +- * 1: After. Always jump to a time that is > time_in_pts_ticks +- * -1: Before. Always jump to a time that is < time_in_pts_ticks +- */ +-dvdnav_status_t dvdnav_jump_to_sector_by_time(dvdnav_t* self, +- uint64_t time_in_pts_ticks, +- int32_t mode); +- +-/* +- * Stop playing current position and play the "GoUp"-program chain. +- * (which generally leads to the title menu or a higher-level menu). +- */ +-dvdnav_status_t dvdnav_go_up(dvdnav_t *self); +- +-/* +- * Stop playing the current position and start playback at the +- * previous program (if it exists). +- */ +-dvdnav_status_t dvdnav_prev_pg_search(dvdnav_t *self); +- +-/* +- * Stop playing the current position and start playback at the +- * first program. +- */ +-dvdnav_status_t dvdnav_top_pg_search(dvdnav_t *self); +- +-/* +- * Stop playing the current position and start playback at the +- * next program (if it exists). +- */ +-dvdnav_status_t dvdnav_next_pg_search(dvdnav_t *self); +- +-/* +- * Return the current position (in blocks) within the current +- * program and the length (in blocks) of current program. +- * +- * If program chain based positioning is enabled +- * (see dvdnav_set_PGC_positioning_flag()), this will return the +- * relative position in and the length of the current program chain. +- */ +-dvdnav_status_t dvdnav_get_position(dvdnav_t* self, uint32_t* pos, uint32_t* len); +- +-/********************************************************************* +- * menu highlights * +- *********************************************************************/ +- +-/* +- * Most functions related to highlights take a NAV PCI packet as a parameter. +- * While you can get such a packet from libdvdnav, this will result in +- * errors for players with internal FIFOs because due to the FIFO length, +- * libdvdnav will be ahead in the stream compared to what the user is +- * seeing on screen. Therefore, player applications who have a NAV +- * packet available, which is better in sync with the actual playback, +- * should always pass this one to these functions. +- */ +- +-/* +- * Get the currently highlighted button +- * number (1..36) or 0 if no button is highlighted. +- */ +-dvdnav_status_t dvdnav_get_current_highlight(dvdnav_t *self, int32_t *button); +- +-/* +- * Returns the Presentation Control Information (PCI) structure associated +- * with the current position. +- * +- * Read the general notes above. +- * See also libdvdreads nav_types.h for definition of pci_t. +- */ +-pci_t* dvdnav_get_current_nav_pci(dvdnav_t *self); +- +-/* +- * Returns the DSI (data search information) structure associated +- * with the current position. +- * +- * Read the general notes above. +- * See also libdvdreads nav_types.h for definition of dsi_t. +- */ +-dsi_t* dvdnav_get_current_nav_dsi(dvdnav_t *self); +- +-/* +- * Get the area associated with a certain button. +- */ +-dvdnav_status_t dvdnav_get_highlight_area(pci_t* nav_pci, +- int32_t button, +- int32_t mode, +- dvdnav_highlight_area_t* highlight); +- +-/* +- * Move button highlight around as suggested by function name (e.g. with arrow keys). +- */ +-dvdnav_status_t dvdnav_upper_button_select(dvdnav_t *self, pci_t *pci); +-dvdnav_status_t dvdnav_lower_button_select(dvdnav_t *self, pci_t *pci); +-dvdnav_status_t dvdnav_right_button_select(dvdnav_t *self, pci_t *pci); +-dvdnav_status_t dvdnav_left_button_select(dvdnav_t *self, pci_t *pci); +- +-/* +- * Activate ("press") the currently highlighted button. +- */ +-dvdnav_status_t dvdnav_button_activate(dvdnav_t *self, pci_t *pci); +- +-/* +- * Highlight a specific button. +- */ +-dvdnav_status_t dvdnav_button_select(dvdnav_t *self, pci_t *pci, int32_t button); +- +-/* +- * Activate ("press") specified button. +- */ +-dvdnav_status_t dvdnav_button_select_and_activate(dvdnav_t *self, pci_t *pci, int32_t button); +- +-/* +- * Activate ("press") a button and execute specified command. +- */ +-dvdnav_status_t dvdnav_button_activate_cmd(dvdnav_t *self, int32_t button, vm_cmd_t *cmd); +- +-/* +- * Select button at specified video frame coordinates. +- */ +-dvdnav_status_t dvdnav_mouse_select(dvdnav_t *self, pci_t *pci, int32_t x, int32_t y); +- +-/* +- * Activate ("press") button at specified video frame coordinates. +- */ +-dvdnav_status_t dvdnav_mouse_activate(dvdnav_t *self, pci_t *pci, int32_t x, int32_t y); +- +- +-/********************************************************************* +- * languages * +- *********************************************************************/ +- +-/* +- * The language codes expected by these functions are two character +- * codes as defined in ISO639. +- */ +- +-/* +- * Set which menu language we should use per default. +- */ +-dvdnav_status_t dvdnav_menu_language_select(dvdnav_t* self, char* code); +- +-/* +- * Set which audio language we should use per default. +- */ +-dvdnav_status_t dvdnav_audio_language_select(dvdnav_t* self, char* code); +- +-/* +- * Set which spu language we should use per default. +- */ +-dvdnav_status_t dvdnav_spu_language_select(dvdnav_t* self, char* code); +- +-/********************************************************************* +- * obtaining stream attributes * +- *********************************************************************/ +- +-/* +- * Return a string describing the title of the DVD. +- * This is an ID string encoded on the disc by the author. In many cases +- * this is a descriptive string such as `THE_MATRIX' but sometimes is singularly +- * uninformative such as `PDVD-011421'. Some DVD authors even forget to set this, +- * so you may also read the default of the authoring software they used, like +- * `DVDVolume'. +- */ +-dvdnav_status_t dvdnav_get_title_string(dvdnav_t *self, const char **title_str); +- +-/* +- * Returns a string containing the serial number of the DVD. +- * This has a max of 15 characters and should be more unique than the +- * title string. +- */ +-dvdnav_status_t dvdnav_get_serial_string(dvdnav_t *self, const char **serial_str); +- +-/* +- * Returns the VolumeIdentifier of the disc or NULL if it could +- * not be obtained. The VolumeIdentifier might be latin-1 encoded +- * (8bit unicode) null terminated and max 32 bytes (including '\0'); +- * or coded with '0-9','A-Z','_' null terminated and max 33 bytes +- * (including '\0'). +- * See also dvdnav_get_title_string +- * +- * Note: The string is malloc'd so caller has to free() the returned +- * string when done with it. +- */ +-const char* dvdnav_get_volid_string(dvdnav_t* self); +- +-/* +- * Get video aspect code. +- * The aspect code does only change on VTS boundaries. +- * See the DVDNAV_VTS_CHANGE event. +- * +- * 0 -- 4:3, 2 -- 16:9 +- */ +-uint8_t dvdnav_get_video_aspect(dvdnav_t *self); +- +-/* +- * Get video resolution. +- */ +-dvdnav_status_t dvdnav_get_video_resolution(dvdnav_t* self, uint32_t* width, uint32_t* height); +- +-/* +- * Get video scaling permissions. +- * The scaling permission does only change on VTS boundaries. +- * See the DVDNAV_VTS_CHANGE event. +- * +- * bit0 set = deny letterboxing, bit1 set = deny pan&scan +- */ +-uint8_t dvdnav_get_video_scale_permission(dvdnav_t *self); +- +-/* +- * Converts a *logical* audio stream id into language code +- * (returns 0xffff if no such stream). +- */ +-uint16_t dvdnav_audio_stream_to_lang(dvdnav_t *self, uint8_t stream); +- +-/* +- * Returns the format of *logical* audio stream 'stream' +- * (returns 0xffff if no such stream). +- */ +-uint16_t dvdnav_audio_stream_format(dvdnav_t *self, uint8_t stream); +- +-/* +- * Returns number of channels in *logical* audio stream 'stream' +- * (returns 0xffff if no such stream). +- */ +-uint16_t dvdnav_audio_stream_channels(dvdnav_t *self, uint8_t stream); +- +-/* +- * Converts a *logical* subpicture stream id into country code +- * (returns 0xffff if no such stream). +- */ +-uint16_t dvdnav_spu_stream_to_lang(dvdnav_t *self, uint8_t stream); +- +-/* +- * Converts a *physical* (MPEG) audio stream id into a logical stream number. +- */ +-int8_t dvdnav_get_audio_logical_stream(dvdnav_t *self, uint8_t audio_num); +- +-#define HAVE_GET_AUDIO_ATTR +-/* +- * Get audio attr +- */ +-dvdnav_status_t dvdnav_get_audio_attr(dvdnav_t *self, uint8_t audio_mum, audio_attr_t *audio_attr); +- +-/* +- * Converts a *physical* (MPEG) subpicture stream id into a logical stream number. +- */ +-int8_t dvdnav_get_spu_logical_stream(dvdnav_t *self, uint8_t subp_num); +- +-#define HAVE_GET_SPU_ATTR +-/* +- * Get spu attr +- */ +-dvdnav_status_t dvdnav_get_spu_attr(dvdnav_t *self, uint8_t audio_mum, subp_attr_t *subp_attr); +- +-/* +- * Get active audio stream. +- */ +-int8_t dvdnav_get_active_audio_stream(dvdnav_t *self); +- +-/* +- * Get active spu stream. +- */ +-int8_t dvdnav_get_active_spu_stream(dvdnav_t *self); +- +-/* +- * Get the set of user operations that are currently prohibited. +- * There are potentially new restrictions right after +- * DVDNAV_CHANNEL_HOP and DVDNAV_NAV_PACKET. +- */ +-user_ops_t dvdnav_get_restrictions(dvdnav_t *self); +- +-/* +- * Returns the number of streams provided its type (e.g. subtitles, audio, etc) +- */ +-int8_t dvdnav_get_number_of_streams(dvdnav_t* self, dvdnav_stream_type_t stream_type); +- +-/********************************************************************* +- * setting stream attributes * +- *********************************************************************/ +- +-/* +- * Set the visible (enable) status of the current spu stream +- * (to enable/disable subtitles) +- * visibility defines if the spu stream should be enabled/visible (1) or disabled (0) +- */ +-dvdnav_status_t dvdnav_toggle_spu_stream(dvdnav_t* self, uint8_t visibility); +- +-/* +- * Set the given stream id and stream type as active +- * stream_num - the physical index of the stream +- * stream_type - the stream type (audio or subtitles) +- */ +-dvdnav_status_t dvdnav_set_active_stream(dvdnav_t* self, +- uint8_t stream_num, +- dvdnav_stream_type_t stream_type); +- +-/********************************************************************* +- * multiple angles * +- *********************************************************************/ +- +-/* +- * The libdvdnav library abstracts away the difference between seamless and +- * non-seamless angles. From the point of view of the programmer you just set the +- * angle number and all is well in the world. You will always see only the +- * selected angle coming from the get_next_block functions. +- * +- * Note: +- * It is quite possible that some tremendously strange DVD feature might change the +- * angle number from under you. Generally you should always view the results from +- * dvdnav_get_angle_info() as definitive only up to the next time you call +- * dvdnav_get_next_block(). +- */ +- +-/* +- * Sets the current angle. If you try to follow a non existent angle +- * the call fails. +- */ +-dvdnav_status_t dvdnav_angle_change(dvdnav_t *self, int32_t angle); +- +-/* +- * Returns the current angle and number of angles present. +- */ +-dvdnav_status_t dvdnav_get_angle_info(dvdnav_t* self, +- int32_t* current_angle, +- int32_t* number_of_angles); +- +-/********************************************************************* +- * domain queries * +- *********************************************************************/ +- +-/* +- * Are we in the First Play domain? +- */ +-int8_t dvdnav_is_domain_fp(dvdnav_t *self); +- +-/* +- * Are we in the Video management Menu domain? +- */ +-int8_t dvdnav_is_domain_vmgm(dvdnav_t *self); +- +-/* +- * Are we in the Video Title Menu domain? +- */ +-int8_t dvdnav_is_domain_vtsm(dvdnav_t *self); +- +-/* +- * Are we in the Video Title Set domain? +- */ +-int8_t dvdnav_is_domain_vts(dvdnav_t *self); +- +- +-#ifdef __cplusplus +-} +-#endif +diff --git a/xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/dvdnav_events.h b/xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/dvdnav_events.h +deleted file mode 100644 +index 970fa6a937..0000000000 +--- a/xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/dvdnav_events.h ++++ /dev/null +@@ -1,226 +0,0 @@ +-/* +- * Copyright (C) 2001 Rich Wareham <richwareham@users.sourceforge.net> +- * +- * This file is part of libdvdnav, a DVD navigation library. +- * +- * libdvdnav is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * libdvdnav is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License along +- * with libdvdnav; if not, write to the Free Software Foundation, Inc., +- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +- */ +- +-/* +- * This header defines events and event types +- */ +- +-#pragma once +- +-/* +- * DVDNAV_BLOCK_OK +- * +- * A regular data block from the DVD has been returned. +- * This one should be demuxed and decoded for playback. +- */ +-#define DVDNAV_BLOCK_OK 0 +- +-/* +- * DVDNAV_NOP +- * +- * Just ignore this. +- */ +-#define DVDNAV_NOP 1 +- +-/* +- * DVDNAV_STILL_FRAME +- * +- * We have reached a still frame. The player application should wait +- * the amount of time specified by the still's length while still handling +- * user input to make menus and other interactive stills work. +- * The last delivered frame should be kept showing. +- * Once the still has timed out, call dvdnav_skip_still(). +- * A length of 0xff means an infinite still which has to be skipped +- * indirectly by some user interaction. +- */ +-#define DVDNAV_STILL_FRAME 2 +- +-typedef struct { +- /* The length (in seconds) the still frame should be displayed for, +- * or 0xff if infinite. */ +- int length; +-} dvdnav_still_event_t; +- +- +-/* +- * DVDNAV_SPU_STREAM_CHANGE +- * +- * Inform the SPU decoding/overlaying engine to switch SPU channels. +- */ +-#define DVDNAV_SPU_STREAM_CHANGE 3 +- +-typedef struct { +- /* The physical (MPEG) stream number for widescreen SPU display. +- * Use this, if you blend the SPU on an anamorphic image before +- * unsqueezing it. */ +- int physical_wide; +- +- /* The physical (MPEG) stream number for letterboxed display. +- * Use this, if you blend the SPU on an anamorphic image after +- * unsqueezing it. */ +- int physical_letterbox; +- +- /* The physical (MPEG) stream number for pan&scan display. +- * Use this, if you blend the SPU on an anamorphic image after +- * unsqueezing it the pan&scan way. */ +- int physical_pan_scan; +- +- /* The logical (DVD) stream number. */ +- int logical; +-} dvdnav_spu_stream_change_event_t; +- +- +-/* +- * DVDNAV_AUDIO_STREAM_CHANGE +- * +- * Inform the audio decoder to switch channels. +- */ +-#define DVDNAV_AUDIO_STREAM_CHANGE 4 +- +-typedef struct { +- /* The physical (MPEG) stream number. */ +- int physical; +- +- /* The logical (DVD) stream number. */ +- int logical; +-} dvdnav_audio_stream_change_event_t; +- +- +-/* +- * DVDNAV_VTS_CHANGE +- * +- * Some status information like video aspect and video scale permissions do +- * not change inside a VTS. Therefore this event can be used to query such +- * information only when necessary and update the decoding/displaying +- * accordingly. +- */ +-#define DVDNAV_VTS_CHANGE 5 +- +-typedef struct { +- int old_vtsN; /* the old VTS number */ +- DVDDomain_t old_domain; /* the old domain */ +- int new_vtsN; /* the new VTS number */ +- DVDDomain_t new_domain; /* the new domain */ +-} dvdnav_vts_change_event_t; +- +- +-/* +- * DVDNAV_CELL_CHANGE +- * +- * Some status information like the current Title and Part numbers do not +- * change inside a cell. Therefore this event can be used to query such +- * information only when necessary and update the decoding/displaying +- * accordingly. +- * Some useful information for accurate time display is also reported +- * together with this event. +- */ +-#define DVDNAV_CELL_CHANGE 6 +- +-typedef struct { +- int cellN; /* the new cell number */ +- int pgN; /* the current program number */ +- int64_t cell_length; /* the length of the current cell in sectors */ +- int64_t pg_length; /* the length of the current program in sectors */ +- int64_t pgc_length; /* the length of the current program chain in PTS ticks */ +- int64_t cell_start; /* the start offset of the current cell relatively to the PGC in sectors */ +- int64_t pg_start; /* the start offset of the current PG relatively to the PGC in sectors */ +-} dvdnav_cell_change_event_t; +- +- +-/* +- * DVDNAV_NAV_PACKET +- * +- * NAV packets are useful for various purposes. They define the button +- * highlight areas and VM commands of DVD menus, so they should in any +- * case be sent to the SPU decoder/overlaying engine for the menus to work. +- * NAV packets also provide a way to detect PTS discontinuities, because +- * they carry the start and end PTS values for the current VOBU. +- * (pci.vobu_s_ptm and pci.vobu_e_ptm) Whenever the start PTS of the +- * current NAV does not match the end PTS of the previous NAV, a PTS +- * discontinuity has occurred. +- * NAV packets can also be used for time display, because they are +- * timestamped relatively to the current Cell. +- */ +-#define DVDNAV_NAV_PACKET 7 +- +-/* +- * DVDNAV_STOP +- * +- * Applications should end playback here. A subsequent dvdnav_get_next_block() +- * call will restart the VM from the beginning of the DVD. +- */ +-#define DVDNAV_STOP 8 +- +-/* +- * DVDNAV_HIGHLIGHT +- * +- * The current button highlight changed. Inform the overlaying engine to +- * highlight a different button. Please note, that at the moment only mode 1 +- * highlights are reported this way. That means, when the button highlight +- * has been moved around by some function call, you will receive an event +- * telling you the new button. But when a button gets activated, you have +- * to handle the mode 2 highlighting (that is some different colour the +- * button turns to on activation) in your application. +- */ +-#define DVDNAV_HIGHLIGHT 9 +- +-typedef struct { +- /* highlight mode: 0 - hide, 1 - show, 2 - activate, currently always 1 */ +- int display; +- +- /* FIXME: these fields are currently not set */ +- uint32_t palette; /* The CLUT entries for the highlight palette +- (4-bits per entry -> 4 entries) */ +- uint16_t sx,sy,ex,ey; /* The start/end x,y positions */ +- uint32_t pts; /* Highlight PTS to match with SPU */ +- +- /* button number for the SPU decoder/overlaying engine */ +- uint32_t buttonN; +-} dvdnav_highlight_event_t; +- +- +-/* +- * DVDNAV_SPU_CLUT_CHANGE +- * +- * Inform the SPU decoder/overlaying engine to update its colour lookup table. +- * The CLUT is given as 16 uint32_t's in the buffer. +- */ +-#define DVDNAV_SPU_CLUT_CHANGE 10 +- +-/* +- * DVDNAV_HOP_CHANNEL +- * +- * A non-seamless operation has been performed. Applications can drop all +- * their internal fifo's content, which will speed up the response. +- */ +-#define DVDNAV_HOP_CHANNEL 12 +- +-/* +- * DVDNAV_WAIT +- * +- * We have reached a point in DVD playback, where timing is critical. +- * Player application with internal fifos can introduce state +- * inconsistencies, because libdvdnav is always the fifo's length +- * ahead in the stream compared to what the application sees. +- * Such applications should wait until their fifos are empty +- * when they receive this type of event. +- * Once this is achieved, call dvdnav_skip_wait(). +- */ +-#define DVDNAV_WAIT 13 +diff --git a/xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/ifo_types.h b/xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/ifo_types.h +deleted file mode 100644 +index 4191b67922..0000000000 +--- a/xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/ifo_types.h ++++ /dev/null +@@ -1,754 +0,0 @@ +-/* +- * Copyright (C) 2000, 2001 Björn Englund <d4bjorn@dtek.chalmers.se>, +- * Håkan Hjort <d95hjort@dtek.chalmers.se> +- * +- * This file is part of libdvdread. +- * +- * libdvdread is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * libdvdread is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License along +- * with libdvdread; if not, write to the Free Software Foundation, Inc., +- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +- */ +- +-#pragma once +- +-//#include <inttypes.h> +-#include "dvd_reader.h" +- +- +-#undef ATTRIBUTE_PACKED +- +-#if defined(__GNUC__) +-#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95) +-#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) && !defined(__clang__) +-#define ATTRIBUTE_PACKED __attribute__((packed, gcc_struct)) +-#else +-#define ATTRIBUTE_PACKED __attribute__((packed)) +-#endif +-#define PRAGMA_PACK 0 +-#endif +-#endif +- +-#if !defined(ATTRIBUTE_PACKED) +-#define ATTRIBUTE_PACKED +-#define PRAGMA_PACK 1 +-#endif +- +-#if PRAGMA_PACK +-#pragma pack(1) +-#endif +- +- +-/** +- * Common +- * +- * The following structures are used in both the VMGI and VTSI. +- */ +- +- +-/** +- * DVD Time Information. +- */ +-typedef struct { +- uint8_t hour; +- uint8_t minute; +- uint8_t second; +- uint8_t frame_u; /* The two high bits are the frame rate. */ +-} ATTRIBUTE_PACKED dvd_time_t; +- +-/** +- * Type to store per-command data. +- */ +-typedef struct { +- uint8_t bytes[8]; +-} ATTRIBUTE_PACKED vm_cmd_t; +-#define COMMAND_DATA_SIZE 8U +- +- +-/** +- * Video Attributes. +- */ +-typedef struct { +- unsigned char mpeg_version : 2; +- unsigned char video_format : 2; +- unsigned char display_aspect_ratio : 2; +- unsigned char permitted_df : 2; +- +- unsigned char line21_cc_1 : 1; +- unsigned char line21_cc_2 : 1; +- unsigned char unknown1 : 1; +- unsigned char bit_rate : 1; +- +- unsigned char picture_size : 2; +- unsigned char letterboxed : 1; +- unsigned char film_mode : 1; +-} ATTRIBUTE_PACKED video_attr_t; +- +-/** +- * Audio Attributes. +- */ +-typedef struct { +- unsigned char audio_format : 3; +- unsigned char multichannel_extension : 1; +- unsigned char lang_type : 2; +- unsigned char application_mode : 2; +- +- unsigned char quantization : 2; +- unsigned char sample_frequency : 2; +- unsigned char unknown1 : 1; +- unsigned char channels : 3; +- uint16_t lang_code; +- uint8_t lang_extension; +- uint8_t code_extension; +- uint8_t unknown3; +- union { +- struct ATTRIBUTE_PACKED { +- unsigned char unknown4 : 1; +- unsigned char channel_assignment : 3; +- unsigned char version : 2; +- unsigned char mc_intro : 1; /* probably 0: true, 1:false */ +- unsigned char mode : 1; /* Karaoke mode 0: solo 1: duet */ +- } karaoke; +- struct ATTRIBUTE_PACKED { +- unsigned char unknown5 : 4; +- unsigned char dolby_encoded : 1; /* suitable for surround decoding */ +- unsigned char unknown6 : 3; +- } surround; +- } ATTRIBUTE_PACKED app_info; +-} ATTRIBUTE_PACKED audio_attr_t; +- +- +-/** +- * MultiChannel Extension +- */ +-typedef struct { +- unsigned char zero1 : 7; +- unsigned char ach0_gme : 1; +- +- unsigned char zero2 : 7; +- unsigned char ach1_gme : 1; +- +- unsigned char zero3 : 4; +- unsigned char ach2_gv1e : 1; +- unsigned char ach2_gv2e : 1; +- unsigned char ach2_gm1e : 1; +- unsigned char ach2_gm2e : 1; +- +- unsigned char zero4 : 4; +- unsigned char ach3_gv1e : 1; +- unsigned char ach3_gv2e : 1; +- unsigned char ach3_gmAe : 1; +- unsigned char ach3_se2e : 1; +- +- unsigned char zero5 : 4; +- unsigned char ach4_gv1e : 1; +- unsigned char ach4_gv2e : 1; +- unsigned char ach4_gmBe : 1; +- unsigned char ach4_seBe : 1; +- uint8_t zero6[19]; +-} ATTRIBUTE_PACKED multichannel_ext_t; +- +- +-/** +- * Subpicture Attributes. +- */ +-typedef struct { +- /* +- * type: 0 not specified +- * 1 language +- * 2 other +- * coding mode: 0 run length +- * 1 extended +- * 2 other +- * language: indicates language if type == 1 +- * lang extension: if type == 1 contains the lang extension +- */ +- unsigned char code_mode : 3; +- unsigned char zero1 : 3; +- unsigned char type : 2; +- uint8_t zero2; +- uint16_t lang_code; +- uint8_t lang_extension; +- uint8_t code_extension; +-} ATTRIBUTE_PACKED subp_attr_t; +- +- +- +-/** +- * PGC Command Table. +- */ +-typedef struct { +- uint16_t nr_of_pre; +- uint16_t nr_of_post; +- uint16_t nr_of_cell; +- uint16_t last_byte; +- vm_cmd_t *pre_cmds; +- vm_cmd_t *post_cmds; +- vm_cmd_t *cell_cmds; +-} ATTRIBUTE_PACKED pgc_command_tbl_t; +-#define PGC_COMMAND_TBL_SIZE 8U +- +-/** +- * PGC Program Map +- */ +-typedef uint8_t pgc_program_map_t; +- +-/** +- * Cell Playback Information. +- */ +-typedef struct { +- unsigned char block_mode : 2; +- unsigned char block_type : 2; +- unsigned char seamless_play : 1; +- unsigned char interleaved : 1; +- unsigned char stc_discontinuity : 1; +- unsigned char seamless_angle : 1; +- unsigned char zero_1 : 1; +- unsigned char playback_mode : 1; /**< When set, enter StillMode after each VOBU */ +- unsigned char restricted : 1; /**< ?? drop out of fastforward? */ +- unsigned char cell_type : 5; /** for karaoke, reserved otherwise */ +- uint8_t still_time; +- uint8_t cell_cmd_nr; +- dvd_time_t playback_time; +- uint32_t first_sector; +- uint32_t first_ilvu_end_sector; +- uint32_t last_vobu_start_sector; +- uint32_t last_sector; +-} ATTRIBUTE_PACKED cell_playback_t; +- +-#define BLOCK_TYPE_NONE 0x0 +-#define BLOCK_TYPE_ANGLE_BLOCK 0x1 +- +-#define BLOCK_MODE_NOT_IN_BLOCK 0x0 +-#define BLOCK_MODE_FIRST_CELL 0x1 +-#define BLOCK_MODE_IN_BLOCK 0x2 +-#define BLOCK_MODE_LAST_CELL 0x3 +- +-/** +- * Cell Position Information. +- */ +-typedef struct { +- uint16_t vob_id_nr; +- uint8_t zero_1; +- uint8_t cell_nr; +-} ATTRIBUTE_PACKED cell_position_t; +- +-/** +- * User Operations. +- */ +-typedef struct { +- unsigned char zero : 7; /* 25-31 */ +- unsigned char video_pres_mode_change : 1; /* 24 */ +- +- unsigned char karaoke_audio_pres_mode_change : 1; /* 23 */ +- unsigned char angle_change : 1; +- unsigned char subpic_stream_change : 1; +- unsigned char audio_stream_change : 1; +- unsigned char pause_on : 1; +- unsigned char still_off : 1; +- unsigned char button_select_or_activate : 1; +- unsigned char resume : 1; /* 16 */ +- +- unsigned char chapter_menu_call : 1; /* 15 */ +- unsigned char angle_menu_call : 1; +- unsigned char audio_menu_call : 1; +- unsigned char subpic_menu_call : 1; +- unsigned char root_menu_call : 1; +- unsigned char title_menu_call : 1; +- unsigned char backward_scan : 1; +- unsigned char forward_scan : 1; /* 8 */ +- +- unsigned char next_pg_search : 1; /* 7 */ +- unsigned char prev_or_top_pg_search : 1; +- unsigned char time_or_chapter_search : 1; +- unsigned char go_up : 1; +- unsigned char stop : 1; +- unsigned char title_play : 1; +- unsigned char chapter_search_or_play : 1; +- unsigned char title_or_time_play : 1; /* 0 */ +-} ATTRIBUTE_PACKED user_ops_t; +- +-/** +- * Program Chain Information. +- */ +-typedef struct { +- uint16_t zero_1; +- uint8_t nr_of_programs; +- uint8_t nr_of_cells; +- dvd_time_t playback_time; +- user_ops_t prohibited_ops; +- uint16_t audio_control[8]; /* New type? */ +- uint32_t subp_control[32]; /* New type? */ +- uint16_t next_pgc_nr; +- uint16_t prev_pgc_nr; +- uint16_t goup_pgc_nr; +- uint8_t pg_playback_mode; +- uint8_t still_time; +- uint32_t palette[16]; /* New type struct {zero_1, Y, Cr, Cb} ? */ +- uint16_t command_tbl_offset; +- uint16_t program_map_offset; +- uint16_t cell_playback_offset; +- uint16_t cell_position_offset; +- pgc_command_tbl_t *command_tbl; +- pgc_program_map_t *program_map; +- cell_playback_t *cell_playback; +- cell_position_t *cell_position; +- int ref_count; +-} ATTRIBUTE_PACKED pgc_t; +-#define PGC_SIZE 236U +- +-/** +- * Program Chain Information Search Pointer. +- */ +-typedef struct { +- uint8_t entry_id; +- unsigned char block_mode : 2; +- unsigned char block_type : 2; +- unsigned char zero_1 : 4; +- uint16_t ptl_id_mask; +- uint32_t pgc_start_byte; +- pgc_t *pgc; +-} ATTRIBUTE_PACKED pgci_srp_t; +-#define PGCI_SRP_SIZE 8U +- +-/** +- * Program Chain Information Table. +- */ +-typedef struct { +- uint16_t nr_of_pgci_srp; +- uint16_t zero_1; +- uint32_t last_byte; +- pgci_srp_t *pgci_srp; +- int ref_count; +-} ATTRIBUTE_PACKED pgcit_t; +-#define PGCIT_SIZE 8U +- +-/** +- * Menu PGCI Language Unit. +- */ +-typedef struct { +- uint16_t lang_code; +- uint8_t lang_extension; +- uint8_t exists; +- uint32_t lang_start_byte; +- pgcit_t *pgcit; +-} ATTRIBUTE_PACKED pgci_lu_t; +-#define PGCI_LU_SIZE 8U +- +-/** +- * Menu PGCI Unit Table. +- */ +-typedef struct { +- uint16_t nr_of_lus; +- uint16_t zero_1; +- uint32_t last_byte; +- pgci_lu_t *lu; +-} ATTRIBUTE_PACKED pgci_ut_t; +-#define PGCI_UT_SIZE 8U +- +-/** +- * Cell Address Information. +- */ +-typedef struct { +- uint16_t vob_id; +- uint8_t cell_id; +- uint8_t zero_1; +- uint32_t start_sector; +- uint32_t last_sector; +-} ATTRIBUTE_PACKED cell_adr_t; +- +-/** +- * Cell Address Table. +- */ +-typedef struct { +- uint16_t nr_of_vobs; /* VOBs */ +- uint16_t zero_1; +- uint32_t last_byte; +- cell_adr_t *cell_adr_table; /* No explicit size given. */ +-} ATTRIBUTE_PACKED c_adt_t; +-#define C_ADT_SIZE 8U +- +-/** +- * VOBU Address Map. +- */ +-typedef struct { +- uint32_t last_byte; +- uint32_t *vobu_start_sectors; +-} ATTRIBUTE_PACKED vobu_admap_t; +-#define VOBU_ADMAP_SIZE 4U +- +- +- +- +-/** +- * VMGI +- * +- * The following structures relate to the Video Manager. +- */ +- +-/** +- * Video Manager Information Management Table. +- */ +-typedef struct { +- char vmg_identifier[12]; +- uint32_t vmg_last_sector; +- uint8_t zero_1[12]; +- uint32_t vmgi_last_sector; +- uint8_t zero_2; +- uint8_t specification_version; +- uint32_t vmg_category; +- uint16_t vmg_nr_of_volumes; +- uint16_t vmg_this_volume_nr; +- uint8_t disc_side; +- uint8_t zero_3[19]; +- uint16_t vmg_nr_of_title_sets; /* Number of VTSs. */ +- char provider_identifier[32]; +- uint64_t vmg_pos_code; +- uint8_t zero_4[24]; +- uint32_t vmgi_last_byte; +- uint32_t first_play_pgc; +- uint8_t zero_5[56]; +- uint32_t vmgm_vobs; /* sector */ +- uint32_t tt_srpt; /* sector */ +- uint32_t vmgm_pgci_ut; /* sector */ +- uint32_t ptl_mait; /* sector */ +- uint32_t vts_atrt; /* sector */ +- uint32_t txtdt_mgi; /* sector */ +- uint32_t vmgm_c_adt; /* sector */ +- uint32_t vmgm_vobu_admap; /* sector */ +- uint8_t zero_6[32]; +- +- video_attr_t vmgm_video_attr; +- uint8_t zero_7; +- uint8_t nr_of_vmgm_audio_streams; /* should be 0 or 1 */ +- audio_attr_t vmgm_audio_attr; +- audio_attr_t zero_8[7]; +- uint8_t zero_9[17]; +- uint8_t nr_of_vmgm_subp_streams; /* should be 0 or 1 */ +- subp_attr_t vmgm_subp_attr; +- subp_attr_t zero_10[27]; /* XXX: how much 'padding' here? */ +-} ATTRIBUTE_PACKED vmgi_mat_t; +- +-typedef struct { +- unsigned char zero_1 : 1; +- unsigned char multi_or_random_pgc_title : 1; /* 0: one sequential pgc title */ +- unsigned char jlc_exists_in_cell_cmd : 1; +- unsigned char jlc_exists_in_prepost_cmd : 1; +- unsigned char jlc_exists_in_button_cmd : 1; +- unsigned char jlc_exists_in_tt_dom : 1; +- unsigned char chapter_search_or_play : 1; /* UOP 1 */ +- unsigned char title_or_time_play : 1; /* UOP 0 */ +-} ATTRIBUTE_PACKED playback_type_t; +- +-/** +- * Title Information. +- */ +-typedef struct { +- playback_type_t pb_ty; +- uint8_t nr_of_angles; +- uint16_t nr_of_ptts; +- uint16_t parental_id; +- uint8_t title_set_nr; +- uint8_t vts_ttn; +- uint32_t title_set_sector; +-} ATTRIBUTE_PACKED title_info_t; +- +-/** +- * PartOfTitle Search Pointer Table. +- */ +-typedef struct { +- uint16_t nr_of_srpts; +- uint16_t zero_1; +- uint32_t last_byte; +- title_info_t *title; +-} ATTRIBUTE_PACKED tt_srpt_t; +-#define TT_SRPT_SIZE 8U +- +- +-/** +- * Parental Management Information Unit Table. +- * Level 1 (US: G), ..., 7 (US: NC-17), 8 +- */ +-#define PTL_MAIT_NUM_LEVEL 8 +-typedef uint16_t pf_level_t[PTL_MAIT_NUM_LEVEL]; +- +-/** +- * Parental Management Information Unit Table. +- */ +-typedef struct { +- uint16_t country_code; +- uint16_t zero_1; +- uint16_t pf_ptl_mai_start_byte; +- uint16_t zero_2; +- pf_level_t *pf_ptl_mai; /* table of (nr_of_vtss + 1), video_ts is first */ +-} ATTRIBUTE_PACKED ptl_mait_country_t; +-#define PTL_MAIT_COUNTRY_SIZE 8U +- +-/** +- * Parental Management Information Table. +- */ +-typedef struct { +- uint16_t nr_of_countries; +- uint16_t nr_of_vtss; +- uint32_t last_byte; +- ptl_mait_country_t *countries; +-} ATTRIBUTE_PACKED ptl_mait_t; +-#define PTL_MAIT_SIZE 8U +- +-/** +- * Video Title Set Attributes. +- */ +-typedef struct { +- uint32_t last_byte; +- uint32_t vts_cat; +- +- video_attr_t vtsm_vobs_attr; +- uint8_t zero_1; +- uint8_t nr_of_vtsm_audio_streams; /* should be 0 or 1 */ +- audio_attr_t vtsm_audio_attr; +- audio_attr_t zero_2[7]; +- uint8_t zero_3[16]; +- uint8_t zero_4; +- uint8_t nr_of_vtsm_subp_streams; /* should be 0 or 1 */ +- subp_attr_t vtsm_subp_attr; +- subp_attr_t zero_5[27]; +- +- uint8_t zero_6[2]; +- +- video_attr_t vtstt_vobs_video_attr; +- uint8_t zero_7; +- uint8_t nr_of_vtstt_audio_streams; +- audio_attr_t vtstt_audio_attr[8]; +- uint8_t zero_8[16]; +- uint8_t zero_9; +- uint8_t nr_of_vtstt_subp_streams; +- subp_attr_t vtstt_subp_attr[32]; +-} ATTRIBUTE_PACKED vts_attributes_t; +-#define VTS_ATTRIBUTES_SIZE 542U +-#define VTS_ATTRIBUTES_MIN_SIZE 356U +- +-/** +- * Video Title Set Attribute Table. +- */ +-typedef struct { +- uint16_t nr_of_vtss; +- uint16_t zero_1; +- uint32_t last_byte; +- vts_attributes_t *vts; +- uint32_t *vts_atrt_offsets; /* offsets table for each vts_attributes */ +-} ATTRIBUTE_PACKED vts_atrt_t; +-#define VTS_ATRT_SIZE 8U +- +-/** +- * Text Data. (Incomplete) +- */ +-typedef struct { +- uint32_t last_byte; /* offsets are relative here */ +- uint16_t offsets[100]; /* == nr_of_srpts + 1 (first is disc title) */ +-#if 0 +- uint16_t unknown; /* 0x48 ?? 0x48 words (16bit) info following */ +- uint16_t zero_1; +- +- uint8_t type_of_info; /* ?? 01 == disc, 02 == Title, 04 == Title part */ +- uint8_t unknown1; +- uint8_t unknown2; +- uint8_t unknown3; +- uint8_t unknown4; /* ?? always 0x30 language?, text format? */ +- uint8_t unknown5; +- uint16_t offset; /* from first */ +- +- char text[12]; /* ended by 0x09 */ +-#endif +-} ATTRIBUTE_PACKED txtdt_t; +- +-/** +- * Text Data Language Unit. (Incomplete) +- */ +-typedef struct { +- uint16_t lang_code; +- uint8_t zero_1; +- uint8_t +- char_set; /* 0x00 reserved Unicode, 0x01 ISO 646, 0x10 JIS Roman & JIS Kanji, 0x11 ISO 8859-1, 0x12 Shift JIS Kanji */ +- uint32_t txtdt_start_byte; /* prt, rel start of vmg_txtdt_mgi */ +- txtdt_t *txtdt; +-} ATTRIBUTE_PACKED txtdt_lu_t; +-#define TXTDT_LU_SIZE 8U +- +-/** +- * Text Data Manager Information. (Incomplete) +- */ +-typedef struct { +- char disc_name[12]; +- uint16_t unknown1; +- uint16_t nr_of_language_units; +- uint32_t last_byte; +- txtdt_lu_t *lu; +-} ATTRIBUTE_PACKED txtdt_mgi_t; +-#define TXTDT_MGI_SIZE 20U +- +- +-/** +- * VTS +- * +- * Structures relating to the Video Title Set (VTS). +- */ +- +-/** +- * Video Title Set Information Management Table. +- */ +-typedef struct { +- char vts_identifier[12]; +- uint32_t vts_last_sector; +- uint8_t zero_1[12]; +- uint32_t vtsi_last_sector; +- uint8_t zero_2; +- uint8_t specification_version; +- uint32_t vts_category; +- uint16_t zero_3; +- uint16_t zero_4; +- uint8_t zero_5; +- uint8_t zero_6[19]; +- uint16_t zero_7; +- uint8_t zero_8[32]; +- uint64_t zero_9; +- uint8_t zero_10[24]; +- uint32_t vtsi_last_byte; +- uint32_t zero_11; +- uint8_t zero_12[56]; +- uint32_t vtsm_vobs; /* sector */ +- uint32_t vtstt_vobs; /* sector */ +- uint32_t vts_ptt_srpt; /* sector */ +- uint32_t vts_pgcit; /* sector */ +- uint32_t vtsm_pgci_ut; /* sector */ +- uint32_t vts_tmapt; /* sector */ +- uint32_t vtsm_c_adt; /* sector */ +- uint32_t vtsm_vobu_admap; /* sector */ +- uint32_t vts_c_adt; /* sector */ +- uint32_t vts_vobu_admap; /* sector */ +- uint8_t zero_13[24]; +- +- video_attr_t vtsm_video_attr; +- uint8_t zero_14; +- uint8_t nr_of_vtsm_audio_streams; /* should be 0 or 1 */ +- audio_attr_t vtsm_audio_attr; +- audio_attr_t zero_15[7]; +- uint8_t zero_16[17]; +- uint8_t nr_of_vtsm_subp_streams; /* should be 0 or 1 */ +- subp_attr_t vtsm_subp_attr; +- subp_attr_t zero_17[27]; +- uint8_t zero_18[2]; +- +- video_attr_t vts_video_attr; +- uint8_t zero_19; +- uint8_t nr_of_vts_audio_streams; +- audio_attr_t vts_audio_attr[8]; +- uint8_t zero_20[17]; +- uint8_t nr_of_vts_subp_streams; +- subp_attr_t vts_subp_attr[32]; +- uint16_t zero_21; +- multichannel_ext_t vts_mu_audio_attr[8]; +- /* XXX: how much 'padding' here, if any? */ +-} ATTRIBUTE_PACKED vtsi_mat_t; +- +-/** +- * PartOfTitle Unit Information. +- */ +-typedef struct { +- uint16_t pgcn; +- uint16_t pgn; +-} ATTRIBUTE_PACKED ptt_info_t; +- +-/** +- * PartOfTitle Information. +- */ +-typedef struct { +- uint16_t nr_of_ptts; +- ptt_info_t *ptt; +-} ATTRIBUTE_PACKED ttu_t; +- +-/** +- * PartOfTitle Search Pointer Table. +- */ +-typedef struct { +- uint16_t nr_of_srpts; +- uint16_t zero_1; +- uint32_t last_byte; +- ttu_t *title; +- uint32_t *ttu_offset; /* offset table for each ttu */ +-} ATTRIBUTE_PACKED vts_ptt_srpt_t; +-#define VTS_PTT_SRPT_SIZE 8U +- +- +-/** +- * Time Map Entry. +- */ +-/* Should this be bit field at all or just the uint32_t? */ +-typedef uint32_t map_ent_t; +- +-/** +- * Time Map. +- */ +-typedef struct { +- uint8_t tmu; /* Time unit, in seconds */ +- uint8_t zero_1; +- uint16_t nr_of_entries; +- map_ent_t *map_ent; +-} ATTRIBUTE_PACKED vts_tmap_t; +-#define VTS_TMAP_SIZE 4U +- +-/** +- * Time Map Table. +- */ +-typedef struct { +- uint16_t nr_of_tmaps; +- uint16_t zero_1; +- uint32_t last_byte; +- vts_tmap_t *tmap; +- uint32_t *tmap_offset; /* offset table for each tmap */ +-} ATTRIBUTE_PACKED vts_tmapt_t; +-#define VTS_TMAPT_SIZE 8U +- +- +-#if PRAGMA_PACK +-#pragma pack() +-#endif +- +- +-/** +- * The following structure defines an IFO file. The structure is divided into +- * two parts, the VMGI, or Video Manager Information, which is read from the +- * VIDEO_TS.[IFO,BUP] file, and the VTSI, or Video Title Set Information, which +- * is read in from the VTS_XX_0.[IFO,BUP] files. +- */ +-typedef struct { +- /* VMGI */ +- vmgi_mat_t *vmgi_mat; +- tt_srpt_t *tt_srpt; +- pgc_t *first_play_pgc; +- ptl_mait_t *ptl_mait; +- vts_atrt_t *vts_atrt; +- txtdt_mgi_t *txtdt_mgi; +- +- /* Common */ +- pgci_ut_t *pgci_ut; +- c_adt_t *menu_c_adt; +- vobu_admap_t *menu_vobu_admap; +- +- /* VTSI */ +- vtsi_mat_t *vtsi_mat; +- vts_ptt_srpt_t *vts_ptt_srpt; +- pgcit_t *vts_pgcit; +- vts_tmapt_t *vts_tmapt; +- c_adt_t *vts_c_adt; +- vobu_admap_t *vts_vobu_admap; +-} ifo_handle_t; +- +diff --git a/xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/nav_types.h b/xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/nav_types.h +deleted file mode 100644 +index aa33f23d4d..0000000000 +--- a/xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/nav_types.h ++++ /dev/null +@@ -1,258 +0,0 @@ +-/* +- * Copyright (C) 2000, 2001, 2002 Håkan Hjort <d95hjort@dtek.chalmers.se> +- * +- * SPDX-License-Identifier: GPL-2.0-only +- * See LICENSES/README.md for more information. +- * +- * The data structures in this file should represent the layout of the +- * pci and dsi packets as they are stored in the stream. Information +- * found by reading the source to VOBDUMP is the base for the structure +- * and names of these data types. +- * +- * VOBDUMP: a program for examining DVD .VOB files. +- * Copyright 1998, 1999 Eric Smith <eric@brouhaha.com> +- */ +- +-#pragma once +- +-//#include <inttypes.h> +-#include "ifo_types.h" /* only dvd_time_t, vm_cmd_t and user_ops_t */ +- +- +-#undef ATTRIBUTE_PACKED +-#undef PRAGMA_PACK_BEGIN +-#undef PRAGMA_PACK_END +- +-#if defined(__GNUC__) +-#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95) +-#define ATTRIBUTE_PACKED __attribute__ ((packed)) +-#define PRAGMA_PACK 0 +-#endif +-#endif +- +-#if !defined(ATTRIBUTE_PACKED) +-#define ATTRIBUTE_PACKED +-#define PRAGMA_PACK 1 +-#endif +- +- +-/* The length including the substream id byte. */ +-#define PCI_BYTES 0x3d4 +-#define DSI_BYTES 0x3fa +- +-#define PS2_PCI_SUBSTREAM_ID 0x00 +-#define PS2_DSI_SUBSTREAM_ID 0x01 +- +-/* Remove this */ +-#define DSI_START_BYTE 1031 +- +- +-#if PRAGMA_PACK +-#pragma pack(1) +-#endif +- +- +-/** +- * PCI General Information +- */ +-typedef struct { +- uint32_t nv_pck_lbn; /**< sector address of this nav pack */ +- uint16_t vobu_cat; /**< 'category' of vobu */ +- uint16_t zero1; /**< reserved */ +- user_ops_t vobu_uop_ctl; /**< UOP of vobu */ +- uint32_t vobu_s_ptm; /**< start presentation time of vobu */ +- uint32_t vobu_e_ptm; /**< end presentation time of vobu */ +- uint32_t vobu_se_e_ptm; /**< end ptm of sequence end in vobu */ +- dvd_time_t e_eltm; /**< Cell elapsed time */ +- char vobu_isrc[32]; +-} ATTRIBUTE_PACKED pci_gi_t; +- +-/** +- * Non Seamless Angle Information +- */ +-typedef struct { +- uint32_t nsml_agl_dsta[9]; /**< address of destination vobu in AGL_C#n */ +-} ATTRIBUTE_PACKED nsml_agli_t; +- +-/** +- * Highlight General Information +- * +- * For btngrX_dsp_ty the bits have the following meaning: +- * 000b: normal 4/3 only buttons +- * XX1b: wide (16/9) buttons +- * X1Xb: letterbox buttons +- * 1XXb: pan&scan buttons +- */ +-typedef struct { +- uint16_t hli_ss; /**< status, only low 2 bits 0: no buttons, 1: different 2: equal 3: equal except for button cmds */ +- uint32_t hli_s_ptm; /**< start ptm of hli */ +- uint32_t hli_e_ptm; /**< end ptm of hli */ +- uint32_t btn_se_e_ptm; /**< end ptm of button select */ +- unsigned int zero1 : 2; /**< reserved */ +- unsigned int btngr_ns : 2; /**< number of button groups 1, 2 or 3 with 36/18/12 buttons */ +- unsigned int zero2 : 1; /**< reserved */ +- unsigned int btngr1_dsp_ty : 3; /**< display type of subpic stream for button group 1 */ +- unsigned int zero3 : 1; /**< reserved */ +- unsigned int btngr2_dsp_ty : 3; /**< display type of subpic stream for button group 2 */ +- unsigned int zero4 : 1; /**< reserved */ +- unsigned int btngr3_dsp_ty : 3; /**< display type of subpic stream for button group 3 */ +- uint8_t btn_ofn; /**< button offset number range 0-255 */ +- uint8_t btn_ns; /**< number of valid buttons <= 36/18/12 (low 6 bits) */ +- uint8_t nsl_btn_ns; /**< number of buttons selectable by U_BTNNi (low 6 bits) nsl_btn_ns <= btn_ns */ +- uint8_t zero5; /**< reserved */ +- uint8_t fosl_btnn; /**< forcedly selected button (low 6 bits) */ +- uint8_t foac_btnn; /**< forcedly activated button (low 6 bits) */ +-} ATTRIBUTE_PACKED hl_gi_t; +- +- +-/** +- * Button Color Information Table +- * Each entry being a 32bit word that contains the color indexes and alpha +- * values to use. They are all represented by 4 bit number and stored +- * like this [Ci3, Ci2, Ci1, Ci0, A3, A2, A1, A0]. The actual palette +- * that the indexes reference is in the PGC. +- * @TODO split the uint32_t into a struct +- */ +-typedef struct { +- uint32_t btn_coli[3][2]; /**< [button color number-1][select:0/action:1] */ +-} ATTRIBUTE_PACKED btn_colit_t; +- +-/** +- * Button Information +- * +- * NOTE: I've had to change the structure from the disk layout to get +- * the packing to work with Sun's Forte C compiler. +- * The 4 and 7 bytes are 'rotated' was: ABC DEF GHIJ is: ABCG DEFH IJ +- */ +-typedef struct { +- unsigned int btn_coln : 2; /**< button color number */ +- unsigned int x_start : 10; /**< x start offset within the overlay */ +- unsigned int zero1 : 2; /**< reserved */ +- unsigned int x_end : 10; /**< x end offset within the overlay */ +- +- unsigned int auto_action_mode : 2; /**< 0: no, 1: activated if selected */ +- unsigned int y_start : 10; /**< y start offset within the overlay */ +- unsigned int zero2 : 2; /**< reserved */ +- unsigned int y_end : 10; /**< y end offset within the overlay */ +- +- unsigned int zero3 : 2; /**< reserved */ +- unsigned int up : 6; /**< button index when pressing up */ +- unsigned int zero4 : 2; /**< reserved */ +- unsigned int down : 6; /**< button index when pressing down */ +- unsigned int zero5 : 2; /**< reserved */ +- unsigned int left : 6; /**< button index when pressing left */ +- unsigned int zero6 : 2; /**< reserved */ +- unsigned int right : 6; /**< button index when pressing right */ +- vm_cmd_t cmd; +-} ATTRIBUTE_PACKED btni_t; +- +-/** +- * Highlight Information +- */ +-typedef struct { +- hl_gi_t hl_gi; +- btn_colit_t btn_colit; +- btni_t btnit[36]; +-} ATTRIBUTE_PACKED hli_t; +- +-/** +- * PCI packet +- */ +-typedef struct { +- pci_gi_t pci_gi; +- nsml_agli_t nsml_agli; +- hli_t hli; +- uint8_t zero1[189]; +-} ATTRIBUTE_PACKED pci_t; +- +- +- +- +-/** +- * DSI General Information +- */ +-typedef struct { +- uint32_t nv_pck_scr; +- uint32_t nv_pck_lbn; /**< sector address of this nav pack */ +- uint32_t vobu_ea; /**< end address of this VOBU */ +- uint32_t vobu_1stref_ea; /**< end address of the 1st reference image */ +- uint32_t vobu_2ndref_ea; /**< end address of the 2nd reference image */ +- uint32_t vobu_3rdref_ea; /**< end address of the 3rd reference image */ +- uint16_t vobu_vob_idn; /**< VOB Id number that this VOBU is part of */ +- uint8_t zero1; /**< reserved */ +- uint8_t vobu_c_idn; /**< Cell Id number that this VOBU is part of */ +- dvd_time_t c_eltm; /**< Cell elapsed time */ +-} ATTRIBUTE_PACKED dsi_gi_t; +- +-/** +- * Seamless Playback Information +- */ +-typedef struct { +- uint16_t category; /**< 'category' of seamless VOBU */ +- uint32_t ilvu_ea; /**< end address of interleaved Unit */ +- uint32_t ilvu_sa; /**< start address of next interleaved unit */ +- uint16_t size; /**< size of next interleaved unit */ +- uint32_t vob_v_s_s_ptm; /**< video start ptm in vob */ +- uint32_t vob_v_e_e_ptm; /**< video end ptm in vob */ +- struct { +- uint32_t stp_ptm1; +- uint32_t stp_ptm2; +- uint32_t gap_len1; +- uint32_t gap_len2; +- } vob_a[8]; +-} ATTRIBUTE_PACKED sml_pbi_t; +- +-/** +- * Seamless Angle Information for one angle +- */ +-typedef struct { +- uint32_t address; /**< offset to next ILVU, high bit is before/after */ +- uint16_t size; /**< byte size of the ILVU pointed to by address */ +-} ATTRIBUTE_PACKED sml_agl_data_t; +- +-/** +- * Seamless Angle Information +- */ +-typedef struct { +- sml_agl_data_t data[9]; +-} ATTRIBUTE_PACKED sml_agli_t; +- +-/** +- * VOBU Search Information +- */ +-typedef struct { +- uint32_t next_video; /**< Next vobu that contains video */ +- uint32_t fwda[19]; /**< Forwards, time */ +- uint32_t next_vobu; +- uint32_t prev_vobu; +- uint32_t bwda[19]; /**< Backwards, time */ +- uint32_t prev_video; +-} ATTRIBUTE_PACKED vobu_sri_t; +- +-#define SRI_END_OF_CELL 0x3fffffff +- +-/** +- * Synchronous Information +- */ +-typedef struct { +- uint16_t a_synca[8]; /**< offset to first audio packet for this VOBU */ +- uint32_t sp_synca[32]; /**< offset to first subpicture packet */ +-} ATTRIBUTE_PACKED synci_t; +- +-/** +- * DSI packet +- */ +-typedef struct { +- dsi_gi_t dsi_gi; +- sml_pbi_t sml_pbi; +- sml_agli_t sml_agli; +- vobu_sri_t vobu_sri; +- synci_t synci; +- uint8_t zero1[471]; +-} ATTRIBUTE_PACKED dsi_t; +- +- +-#if PRAGMA_PACK +-#pragma pack() +-#endif +- +diff --git a/xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/version.h b/xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/version.h +deleted file mode 100644 +index dced5e766a..0000000000 +--- a/xbmc/cores/VideoPlayer/DVDInputStreams/dvdnav/version.h ++++ /dev/null +@@ -1,29 +0,0 @@ +-/* +-* This file is part of libdvdnav, a DVD navigation library. +-* +- * This program is free software; you can redistribute it and/or modify it +- * under the terms of the GNU Lesser General Public License as published by +- * the Free Software Foundation; either version 2.1 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU Lesser General Public License for more details. +- * +- * You should have received a copy of the GNU Lesser General Public License +- * along with this program; if not, write to the Free Software Foundation, +- * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. +-*/ +-#pragma once +- +-#define DVDNAV_VERSION_CODE(major, minor, micro) (((major)*10000) + ((minor)*100) + ((micro)*1)) +- +-#define DVDNAV_VERSION_MAJOR 6 +-#define DVDNAV_VERSION_MINOR 1 +-#define DVDNAV_VERSION_MICRO 1 +- +-#define DVDNAV_VERSION_STRING "6.1.1" +- +-#define DVDNAV_VERSION \ +- DVDNAV_VERSION_CODE(DVDNAV_VERSION_MAJOR, DVDNAV_VERSION_MINOR, DVDNAV_VERSION_MICRO) +-- +2.35.1 + + +From d5d87a09d04f427826387f980ffaeeab737c2d78 Mon Sep 17 00:00:00 2001 +From: fuzzard <fuzzard@kodi.tv> +Date: Mon, 27 Jun 2022 19:48:48 +1000 +Subject: [PATCH 2/9] WIP!: allow system libs for dvdread/nav/css + +--- + CMakeLists.txt | 1 + + cmake/modules/FindLibDvd.cmake | 13 -- + cmake/modules/FindLibDvdCSS.cmake | 124 ++++++++------- + cmake/modules/FindLibDvdNav.cmake | 140 +++++++++-------- + cmake/modules/FindLibDvdRead.cmake | 144 ++++++++++-------- + .../DVDInputStreamNavigator.cpp | 4 +- + .../DVDInputStreams/DVDInputStreamNavigator.h | 8 +- + 7 files changed, 233 insertions(+), 201 deletions(-) + +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 19881e4708..71660392e5 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -70,6 +70,7 @@ option(ENABLE_INTERNAL_FFMPEG "Enable internal ffmpeg?" OFF) + dependent_option(ENABLE_INTERNAL_FLATBUFFERS "Enable internal flatbuffers?") + dependent_option(ENABLE_INTERNAL_FMT "Enable internal fmt?") ++dependent_option(ENABLE_INTERNAL_LIBDVD "Enable internal libdvd* libs?") + dependent_option(ENABLE_INTERNAL_NFS "Enable internal libnfs?") + dependent_option(ENABLE_INTERNAL_PCRE "Enable internal pcre?") + dependent_option(ENABLE_INTERNAL_SPDLOG "Enable internal spdlog?") + dependent_option(ENABLE_INTERNAL_TAGLIB "Enable internal taglib?") +diff --git a/cmake/modules/FindLibDvd.cmake b/cmake/modules/FindLibDvd.cmake +index 6853e84618..91e98d3d46 100644 +--- a/cmake/modules/FindLibDvd.cmake ++++ b/cmake/modules/FindLibDvd.cmake +@@ -7,19 +7,6 @@ unset(FPHSA_NAME_MISMATCHED) + + set(_dvdlibs ${LIBDVDREAD_LIBRARY} ${LIBDVDCSS_LIBRARY}) + +-if(NOT CORE_SYSTEM_NAME MATCHES windows) +- # link a shared dvdnav library that includes the whole archives of dvdread and dvdcss as well +- # the quotes around _dvdlibs are on purpose, since we want to pass a list to the function that will be unpacked automatically +- core_link_library(${LIBDVDNAV_LIBRARY} system/players/VideoPlayer/libdvdnav libdvdnav archives "${_dvdlibs}") +-else() +- set(LIBDVD_TARGET_DIR .) +- if(CORE_SYSTEM_NAME STREQUAL windowsstore) +- set(LIBDVD_TARGET_DIR dlls) +- endif() +- copy_file_to_buildtree(${DEPENDS_PATH}/bin/libdvdnav.dll DIRECTORY ${LIBDVD_TARGET_DIR}) +- add_dependencies(export-files LibDvdNav::LibDvdNav) +-endif() +- + set(LIBDVD_INCLUDE_DIRS ${LIBDVDREAD_INCLUDE_DIR} ${LIBDVDNAV_INCLUDE_DIR}) + set(LIBDVD_LIBRARIES ${LIBDVDNAV_LIBRARY} ${LIBDVDREAD_LIBRARY}) + if(TARGET LibDvdCSS::LibDvdCSS) +diff --git a/cmake/modules/FindLibDvdNav.cmake b/cmake/modules/FindLibDvdNav.cmake +index 681610ea6c..0135aba11e 100644 +--- a/cmake/modules/FindLibDvdNav.cmake ++++ b/cmake/modules/FindLibDvdNav.cmake +@@ -25,82 +25,94 @@ if(NOT TARGET LibDvdNav::LibDvdNav) + + set(MODULE_LC libdvdnav) + +- # We require this due to the odd nature of github URL's compared to our other tarball +- # mirror system. If User sets LIBDVDNAV_URL or libdvdnav_URL, allow get_filename_component in SETUP_BUILD_VARS +- if(LIBDVDNAV_URL OR ${MODULE_LC}_URL) +- if(${MODULE_LC}_URL) +- set(LIBDVDNAV_URL ${${MODULE_LC}_URL}) ++ if(ENABLE_INTERNAL_LIBDVD) ++ ++ # We require this due to the odd nature of github URL's compared to our other tarball ++ # mirror system. If User sets LIBDVDNAV_URL or libdvdnav_URL, allow get_filename_component in SETUP_BUILD_VARS ++ if(LIBDVDNAV_URL OR ${MODULE_LC}_URL) ++ set(LIBDVDNAV_URL_PROVIDED TRUE) + endif() +- set(LIBDVDNAV_URL_PROVIDED TRUE) +- endif() + +- SETUP_BUILD_VARS() ++ SETUP_BUILD_VARS() + +- if(NOT LIBDVDNAV_URL_PROVIDED) +- # override LIBDVDNAV_URL due to tar naming when retrieved from github release +- set(LIBDVDNAV_URL ${LIBDVDNAV_BASE_URL}/archive/${LIBDVDNAV_VER}.tar.gz) +- endif() ++ if(NOT LIBDVDNAV_URL_PROVIDED) ++ # override LIBDVDNAV_URL due to tar naming when retrieved from github release ++ set(LIBDVDNAV_URL ${LIBDVDNAV_BASE_URL}/archive/${LIBDVDNAV_VER}.tar.gz) ++ endif() + +- set(LIBDVDNAV_VERSION ${${MODULE}_VER}) +- +- set(HOST_ARCH ${ARCH}) +- if(CORE_SYSTEM_NAME STREQUAL android) +- if(ARCH STREQUAL arm) +- set(HOST_ARCH arm-linux-androideabi) +- elseif(ARCH STREQUAL aarch64) +- set(HOST_ARCH aarch64-linux-android) +- elseif(ARCH STREQUAL i486-linux) +- set(HOST_ARCH i686-linux-android) +- elseif(ARCH STREQUAL x86_64) +- set(HOST_ARCH x86_64-linux-android) ++ set(LIBDVDNAV_VERSION ${${MODULE}_VER}) ++ ++ set(HOST_ARCH ${ARCH}) ++ if(CORE_SYSTEM_NAME STREQUAL android) ++ if(ARCH STREQUAL arm) ++ set(HOST_ARCH arm-linux-androideabi) ++ elseif(ARCH STREQUAL aarch64) ++ set(HOST_ARCH aarch64-linux-android) ++ elseif(ARCH STREQUAL i486-linux) ++ set(HOST_ARCH i686-linux-android) ++ elseif(ARCH STREQUAL x86_64) ++ set(HOST_ARCH x86_64-linux-android) ++ endif() ++ elseif(CORE_SYSTEM_NAME STREQUAL windowsstore) ++ set(LIBDVD_ADDITIONAL_ARGS "-DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME}" "-DCMAKE_SYSTEM_VERSION=${CMAKE_SYSTEM_VERSION}") + endif() +- elseif(CORE_SYSTEM_NAME STREQUAL windowsstore) +- set(LIBDVD_ADDITIONAL_ARGS "-DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME}" "-DCMAKE_SYSTEM_VERSION=${CMAKE_SYSTEM_VERSION}") +- endif() + +- string(APPEND LIBDVDNAV_CFLAGS "-D_XBMC") ++ string(APPEND LIBDVDNAV_CFLAGS "-D_XBMC") + +- if(APPLE) +- set(LIBDVDNAV_LDFLAGS "-framework CoreFoundation") +- string(APPEND LIBDVDNAV_CFLAGS " -D__DARWIN__") +- if(NOT CORE_SYSTEM_NAME STREQUAL darwin_embedded) +- string(APPEND LIBDVDNAV_LDFLAGS " -framework IOKit") ++ if(APPLE) ++ set(LIBDVDNAV_LDFLAGS "-framework CoreFoundation") ++ string(APPEND LIBDVDNAV_CFLAGS " -D__DARWIN__") ++ if(NOT CORE_SYSTEM_NAME STREQUAL darwin_embedded) ++ string(APPEND LIBDVDNAV_LDFLAGS " -framework IOKit") ++ endif() + endif() +- endif() + +- if(CORE_SYSTEM_NAME MATCHES windows) +- set(CMAKE_ARGS -DDUMMY_DEFINE=ON +- ${LIBDVD_ADDITIONAL_ARGS}) +- else() ++ if(CORE_SYSTEM_NAME MATCHES windows) ++ set(CMAKE_ARGS -DDUMMY_DEFINE=ON ++ ${LIBDVD_ADDITIONAL_ARGS}) ++ else() ++ ++ string(APPEND LIBDVDNAV_CFLAGS " -I$<TARGET_PROPERTY:LibDvdRead::LibDvdRead,INTERFACE_INCLUDE_DIRECTORIES> $<TARGET_PROPERTY:LibDvdRead::LibDvdRead,INTERFACE_COMPILE_DEFINITIONS>") ++ ++ find_program(AUTORECONF autoreconf REQUIRED) ++ find_program(MAKE_EXECUTABLE make REQUIRED) ++ ++ set(CONFIGURE_COMMAND ${AUTORECONF} -vif ++ COMMAND ac_cv_path_GIT= ./configure ++ --target=${HOST_ARCH} ++ --host=${HOST_ARCH} ++ --enable-static ++ --disable-shared ++ --with-pic ++ --prefix=${DEPENDS_PATH} ++ --libdir=${DEPENDS_PATH}/lib ++ "CC=${CMAKE_C_COMPILER}" ++ "CFLAGS=${CMAKE_C_FLAGS} ${LIBDVDNAV_CFLAGS}" ++ "LDFLAGS=${CMAKE_EXE_LINKER_FLAGS} ${LIBDVDNAV_LDFLAGS}" ++ "PKG_CONFIG_PATH=${DEPENDS_PATH}/lib/pkgconfig") ++ ++ set(BUILD_COMMAND ${MAKE_EXECUTABLE}) ++ set(INSTALL_COMMAND ${MAKE_EXECUTABLE} install) ++ set(BUILD_IN_SOURCE 1) ++ endif() + +- string(APPEND LIBDVDNAV_CFLAGS " -I$<TARGET_PROPERTY:LibDvdRead::LibDvdRead,INTERFACE_INCLUDE_DIRECTORIES> $<TARGET_PROPERTY:LibDvdRead::LibDvdRead,INTERFACE_COMPILE_DEFINITIONS>") +- +- find_program(AUTORECONF autoreconf REQUIRED) +- find_program(MAKE_EXECUTABLE make REQUIRED) +- +- set(CONFIGURE_COMMAND ${AUTORECONF} -vif +- COMMAND ac_cv_path_GIT= ./configure +- --target=${HOST_ARCH} +- --host=${HOST_ARCH} +- --enable-static +- --disable-shared +- --with-pic +- --prefix=${DEPENDS_PATH} +- --libdir=${DEPENDS_PATH}/lib +- "CC=${CMAKE_C_COMPILER}" +- "CFLAGS=${CMAKE_C_FLAGS} ${LIBDVDNAV_CFLAGS}" +- "LDFLAGS=${CMAKE_EXE_LINKER_FLAGS} ${LIBDVDNAV_LDFLAGS}" +- "PKG_CONFIG_PATH=${DEPENDS_PATH}/lib/pkgconfig") +- +- set(BUILD_COMMAND ${MAKE_EXECUTABLE}) +- set(INSTALL_COMMAND ${MAKE_EXECUTABLE} install) +- set(BUILD_IN_SOURCE 1) +- endif() ++ BUILD_DEP_TARGET() ++ ++ if(TARGET LibDvdRead::LibDvdRead) ++ add_dependencies(libdvdnav LibDvdRead::LibDvdRead) ++ endif() ++ else() ++ if(PKG_CONFIG_FOUND) ++ pkg_check_modules(PC_DVDNAV dvdnav QUIET) ++ endif() + +- BUILD_DEP_TARGET() ++ find_path(LIBDVDNAV_INCLUDE_DIR NAMES dvdnav.h ++ PATH_SUFFIXES dvdnav ++ PATHS ${PC_DVDNAV_INCLUDEDIR}) ++ find_library(LIBDVDNAV_LIBRARY NAMES dvdnav libdvdnav ++ PATHS ${PC_DVDNAV_LIBDIR}) + +- if(TARGET LibDvdRead::LibDvdRead) +- add_dependencies(libdvdnav LibDvdRead::LibDvdRead) ++ set(LIBDVDNAV_VERSION ${PC_DVDNAV_VERSION}) + endif() + endif() + +diff --git a/cmake/modules/FindLibDvdRead.cmake b/cmake/modules/FindLibDvdRead.cmake +index d7e8e882fa..0a8261e758 100644 +--- a/cmake/modules/FindLibDvdRead.cmake ++++ b/cmake/modules/FindLibDvdRead.cmake +@@ -27,86 +27,98 @@ if(NOT TARGET LibDvdRead::LibDvdRead) + + set(MODULE_LC libdvdread) + +- # We require this due to the odd nature of github URL's compared to our other tarball +- # mirror system. If User sets LIBDVDREAD_URL or libdvdread_URL, allow get_filename_component in SETUP_BUILD_VARS +- if(LIBDVDREAD_URL OR ${MODULE_LC}_URL) +- if(${MODULE_LC}_URL) +- set(LIBDVDREAD_URL ${${MODULE_LC}_URL}) ++ if(ENABLE_INTERNAL_LIBDVD) ++ ++ # We require this due to the odd nature of github URL's compared to our other tarball ++ # mirror system. If User sets LIBDVDREAD_URL or libdvdread_URL, allow get_filename_component in SETUP_BUILD_VARS ++ if(LIBDVDREAD_URL OR ${MODULE_LC}_URL) ++ set(LIBDVDREAD_URL_PROVIDED TRUE) + endif() +- set(LIBDVDREAD_URL_PROVIDED TRUE) +- endif() + +- SETUP_BUILD_VARS() ++ SETUP_BUILD_VARS() + +- if(NOT LIBDVDREAD_URL_PROVIDED) +- # override LIBDVDREAD_URL due to tar naming when retrieved from github release +- set(LIBDVDREAD_URL ${LIBDVDREAD_BASE_URL}/archive/${LIBDVDREAD_VER}.tar.gz) +- endif() ++ if(NOT LIBDVDREAD_URL_PROVIDED) ++ # override LIBDVDREAD_URL due to tar naming when retrieved from github release ++ set(LIBDVDREAD_URL ${LIBDVDREAD_BASE_URL}/archive/${LIBDVDREAD_VER}.tar.gz) ++ endif() + +- set(LIBDVDREAD_VERSION ${${MODULE}_VER}) +- +- set(HOST_ARCH ${ARCH}) +- if(CORE_SYSTEM_NAME STREQUAL android) +- if(ARCH STREQUAL arm) +- set(HOST_ARCH arm-linux-androideabi) +- elseif(ARCH STREQUAL aarch64) +- set(HOST_ARCH aarch64-linux-android) +- elseif(ARCH STREQUAL i486-linux) +- set(HOST_ARCH i686-linux-android) +- elseif(ARCH STREQUAL x86_64) +- set(HOST_ARCH x86_64-linux-android) ++ set(LIBDVDREAD_VERSION ${${MODULE}_VER}) ++ ++ set(HOST_ARCH ${ARCH}) ++ if(CORE_SYSTEM_NAME STREQUAL android) ++ if(ARCH STREQUAL arm) ++ set(HOST_ARCH arm-linux-androideabi) ++ elseif(ARCH STREQUAL aarch64) ++ set(HOST_ARCH aarch64-linux-android) ++ elseif(ARCH STREQUAL i486-linux) ++ set(HOST_ARCH i686-linux-android) ++ elseif(ARCH STREQUAL x86_64) ++ set(HOST_ARCH x86_64-linux-android) ++ endif() ++ elseif(CORE_SYSTEM_NAME STREQUAL windowsstore) ++ set(LIBDVD_ADDITIONAL_ARGS "-DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME}" "-DCMAKE_SYSTEM_VERSION=${CMAKE_SYSTEM_VERSION}") + endif() +- elseif(CORE_SYSTEM_NAME STREQUAL windowsstore) +- set(LIBDVD_ADDITIONAL_ARGS "-DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME}" "-DCMAKE_SYSTEM_VERSION=${CMAKE_SYSTEM_VERSION}") +- endif() + +- string(APPEND LIBDVDREAD_CFLAGS "-D_XBMC") ++ string(APPEND LIBDVDREAD_CFLAGS "-D_XBMC") + +- if(APPLE) +- set(LIBDVDREAD_LDFLAGS "-framework CoreFoundation") +- string(APPEND LIBDVDREAD_CFLAGS " -D__DARWIN__") +- if(NOT CORE_SYSTEM_NAME STREQUAL darwin_embedded) +- string(APPEND LIBDVDREAD_LDFLAGS " -framework IOKit") ++ if(APPLE) ++ set(LIBDVDREAD_LDFLAGS "-framework CoreFoundation") ++ string(APPEND LIBDVDREAD_CFLAGS " -D__DARWIN__") ++ if(NOT CORE_SYSTEM_NAME STREQUAL darwin_embedded) ++ string(APPEND LIBDVDREAD_LDFLAGS " -framework IOKit") ++ endif() + endif() +- endif() + +- if(CORE_SYSTEM_NAME MATCHES windows) +- set(CMAKE_ARGS -DDUMMY_DEFINE=ON +- ${LIBDVD_ADDITIONAL_ARGS}) +- else() ++ if(CORE_SYSTEM_NAME MATCHES windows) ++ set(CMAKE_ARGS -DDUMMY_DEFINE=ON ++ ${LIBDVD_ADDITIONAL_ARGS}) ++ else() ++ ++ if(TARGET LibDvdCSS::LibDvdCSS) ++ string(APPEND LIBDVDREAD_CFLAGS " -I$<TARGET_PROPERTY:LibDvdCSS::LibDvdCSS,INTERFACE_INCLUDE_DIRECTORIES> $<TARGET_PROPERTY:LibDvdCSS::LibDvdCSS,INTERFACE_COMPILE_DEFINITIONS>") ++ string(APPEND with-css "--with-libdvdcss") ++ endif() ++ ++ find_program(AUTORECONF autoreconf REQUIRED) ++ find_program(MAKE_EXECUTABLE make REQUIRED) ++ ++ set(CONFIGURE_COMMAND ${AUTORECONF} -vif ++ COMMAND ac_cv_path_GIT= ./configure ++ --target=${HOST_ARCH} ++ --host=${HOST_ARCH} ++ --enable-static ++ --disable-shared ++ --with-pic ++ --prefix=${DEPENDS_PATH} ++ --libdir=${DEPENDS_PATH}/lib ++ ${with-css} ++ "CC=${CMAKE_C_COMPILER}" ++ "CFLAGS=${CMAKE_C_FLAGS} ${LIBDVDREAD_CFLAGS}" ++ "LDFLAGS=${CMAKE_EXE_LINKER_FLAGS} ${LIBDVDREAD_LDFLAGS}" ++ "PKG_CONFIG_PATH=${DEPENDS_PATH}/lib/pkgconfig") ++ ++ set(BUILD_COMMAND ${MAKE_EXECUTABLE}) ++ set(INSTALL_COMMAND ${MAKE_EXECUTABLE} install) ++ set(BUILD_IN_SOURCE 1) ++ endif() ++ ++ BUILD_DEP_TARGET() + + if(TARGET LibDvdCSS::LibDvdCSS) +- string(APPEND LIBDVDREAD_CFLAGS " -I$<TARGET_PROPERTY:LibDvdCSS::LibDvdCSS,INTERFACE_INCLUDE_DIRECTORIES> $<TARGET_PROPERTY:LibDvdCSS::LibDvdCSS,INTERFACE_COMPILE_DEFINITIONS>") +- string(APPEND with-css "--with-libdvdcss") ++ add_dependencies(libdvdread LibDvdCSS::LibDvdCSS) ++ endif() ++ else() ++ if(PKG_CONFIG_FOUND) ++ pkg_check_modules(PC_DVDREAD dvdread QUIET) + endif() + +- find_program(AUTORECONF autoreconf REQUIRED) +- find_program(MAKE_EXECUTABLE make REQUIRED) +- +- set(CONFIGURE_COMMAND ${AUTORECONF} -vif +- COMMAND ac_cv_path_GIT= ./configure +- --target=${HOST_ARCH} +- --host=${HOST_ARCH} +- --enable-static +- --disable-shared +- --with-pic +- --prefix=${DEPENDS_PATH} +- --libdir=${DEPENDS_PATH}/lib +- ${with-css} +- "CC=${CMAKE_C_COMPILER}" +- "CFLAGS=${CMAKE_C_FLAGS} ${LIBDVDREAD_CFLAGS}" +- "LDFLAGS=${CMAKE_EXE_LINKER_FLAGS} ${LIBDVDREAD_LDFLAGS}" +- "PKG_CONFIG_PATH=${DEPENDS_PATH}/lib/pkgconfig") +- +- set(BUILD_COMMAND ${MAKE_EXECUTABLE}) +- set(INSTALL_COMMAND ${MAKE_EXECUTABLE} install) +- set(BUILD_IN_SOURCE 1) +- endif() +- +- BUILD_DEP_TARGET() ++ find_path(LIBDVDREAD_INCLUDE_DIR NAMES dvd_reader.h ++ PATH_SUFFIXES dvdread ++ PATHS ${PC_DVDREAD_INCLUDEDIR}) ++ find_library(LIBDVDREAD_LIBRARY NAMES dvdread libdvdread ++ PATHS ${PC_DVDREAD_LIBDIR}) + +- if(TARGET LibDvdCSS::LibDvdCSS) +- add_dependencies(libdvdread LibDvdCSS::LibDvdCSS) ++ set(LIBDVDREAD_VERSION ${PC_DVDREAD_VERSION}) + endif() + endif() + +diff --git a/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.cpp b/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.cpp +index 859762348b..069bfccd7b 100644 +--- a/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.cpp ++++ b/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.cpp +@@ -27,6 +27,8 @@ + #include "platform/Environment.h" + #endif + ++#include <sys/uio.h> ++ + namespace + { + constexpr int HOLDMODE_NONE = 0; +@@ -1414,7 +1416,7 @@ std::string CDVDInputStreamNavigator::GetDVDVolIdString() + if (!m_dvdnav) + return ""; + +- const char* volIdTmp = m_dll.dvdnav_get_volid_string(m_dvdnav); ++ const char* volIdTmp = dvdnav_get_volid_string(m_dvdnav); + if (volIdTmp) + { + std::string volId{volIdTmp}; +diff --git a/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.h b/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.h +index 319c84b47d..99b01df2ab 100644 +--- a/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.h ++++ b/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.h +@@ -17,9 +17,15 @@ + #include "cores/MenuType.h" + #include "utils/Geometry.h" + ++#ifdef __cplusplus ++extern "C" ++{ ++#endif + #include <dvdnav/dvdnav.h> + #include <dvdnav/dvd_types.h> +- ++#ifdef __cplusplus ++} ++#endif + #include <string> + + #define DVD_VIDEO_BLOCKSIZE DVD_VIDEO_LB_LEN // 2048 bytes +-- +2.35.1 + + +From 9625e95c0ac5b17125d875178461e54ba7ae5057 Mon Sep 17 00:00:00 2001 +From: enen92 <92enen@gmail.com> +Date: Tue, 26 Jul 2022 23:43:21 +0100 +Subject: [PATCH 3/9] Add dvdcallbacks for vfs files + +--- + .../DVDInputStreamNavigator.cpp | 43 ++--- + xbmc/filesystem/CMakeLists.txt | 2 + + xbmc/filesystem/DvdCallback.cpp | 150 ++++++++++++++++++ + xbmc/filesystem/DvdCallback.h | 47 ++++++ + 4 files changed, 216 insertions(+), 26 deletions(-) + create mode 100644 xbmc/filesystem/DvdCallback.cpp + create mode 100644 xbmc/filesystem/DvdCallback.h + +diff --git a/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.cpp b/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.cpp +index 069bfccd7b..8280a5a1b9 100644 +--- a/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.cpp ++++ b/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.cpp +@@ -8,6 +8,7 @@ + + #include "DVDInputStreamNavigator.h" + #include "filesystem/IFileTypes.h" ++#include "filesystem/DvdCallback.h" + #include "utils/LangCodeExpander.h" + #include "../DVDDemuxSPU.h" + #include "settings/Settings.h" +@@ -67,7 +68,8 @@ constexpr int DVD_AUDIO_LANG_EXT_DIRECTORSCOMMENTS2 = 4; + static int dvd_inputstreamnavigator_cb_seek(void * p_stream, uint64_t i_pos); + static int dvd_inputstreamnavigator_cb_read(void * p_stream, void * buffer, int i_read); + static int dvd_inputstreamnavigator_cb_readv(void * p_stream, void * p_iovec, int i_blocks); +-static void dvd_logger(void* priv, dvdnav_logger_level_t level, const char* fmt, va_list va); ++ ++static dvdnav_filesystem kodiDvdFilesystem; + + CDVDInputStreamNavigator::CDVDInputStreamNavigator(IVideoPlayer* player, const CFileItem& fileitem) + : CDVDInputStream(DVDSTREAM_TYPE_DVD, fileitem), m_pstream(nullptr) +@@ -136,7 +138,7 @@ bool CDVDInputStreamNavigator::Open() + + #if DVDNAV_VERSION >= 60100 + dvdnav_logger_cb loggerCallback; +- loggerCallback.pf_log = dvd_logger; ++ loggerCallback.pf_log = CDVDCallback::dvd_logger; + #endif + + // open up the DVD device +@@ -157,6 +159,19 @@ bool CDVDInputStreamNavigator::Open() + } + } + #if DVDNAV_VERSION >= 60100 ++ else if (URIUtils::IsNetworkFilesystem(path)) ++ { ++ kodiDvdFilesystem.dir_open = CDVDCallback::dir_open; ++ kodiDvdFilesystem.file_open = CDVDCallback::file_open; ++ kodiDvdFilesystem.stat = CDVDCallback::stat; ++ kodiDvdFilesystem.close = CDVDCallback::close; ++ if (dvdnav_open_vfs_files(&m_dvdnav, nullptr, &loggerCallback, path.c_str(), &kodiDvdFilesystem) != DVDNAV_STATUS_OK) ++ { ++ CLog::Log(LOGERROR, "Error on dvdnav_open_vfs_files"); ++ Close(); ++ return false; ++ } ++ } + else if (dvdnav_open2(&m_dvdnav, nullptr, &loggerCallback, path.c_str()) != + DVDNAV_STATUS_OK) + #else +@@ -1511,30 +1526,6 @@ int dvd_inputstreamnavigator_cb_read(void * p_stream, void * buffer, int i_read) + return i_ret; + } + +-void dvd_logger(void* priv, dvdnav_logger_level_t level, const char* fmt, va_list va) +-{ +- const std::string message = StringUtils::FormatV(fmt, va); +- auto logLevel = LOGDEBUG; +- switch (level) +- { +- case DVDNAV_LOGGER_LEVEL_INFO: +- logLevel = LOGINFO; +- break; +- case DVDNAV_LOGGER_LEVEL_ERROR: +- logLevel = LOGERROR; +- break; +- case DVDNAV_LOGGER_LEVEL_WARN: +- logLevel = LOGWARNING; +- break; +- case DVDNAV_LOGGER_LEVEL_DEBUG: +- logLevel = LOGDEBUG; +- break; +- default: +- break; +- }; +- CLog::Log(logLevel, "Libdvd: {}", message); +-} +- + int dvd_inputstreamnavigator_cb_readv(void * p_stream, void * p_iovec, int i_blocks) + { + // NOTE/TODO: this vectored read callback somehow doesn't seem to be called by libdvdnav. +diff --git a/xbmc/filesystem/CMakeLists.txt b/xbmc/filesystem/CMakeLists.txt +index 8bbaa44201..449736a392 100644 +--- a/xbmc/filesystem/CMakeLists.txt ++++ b/xbmc/filesystem/CMakeLists.txt +@@ -11,6 +11,7 @@ set(SOURCES AddonsDirectory.cpp + DirectoryFactory.cpp + DirectoryHistory.cpp + DllLibCurl.cpp ++ DvdCallback.cpp + EventsDirectory.cpp + FavouritesDirectory.cpp + FileCache.cpp +@@ -73,6 +74,7 @@ set(HEADERS AddonsDirectory.h + DirectoryFactory.h + DirectoryHistory.h + DllLibCurl.h ++ DvdCallback.h + EventsDirectory.h + FTPDirectory.h + FTPParse.h +diff --git a/xbmc/filesystem/DvdCallback.cpp b/xbmc/filesystem/DvdCallback.cpp +new file mode 100644 +index 0000000000..2f247fff1f +--- /dev/null ++++ b/xbmc/filesystem/DvdCallback.cpp +@@ -0,0 +1,150 @@ ++/* ++ * 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 "DvdCallback.h" ++ ++#include "FileItem.h" ++#include "filesystem/Directory.h" ++#include "filesystem/File.h" ++#include "utils/StringUtils.h" ++#include "utils/URIUtils.h" ++#include "utils/log.h" ++ ++using namespace XFILE; ++ ++struct SDirState ++{ ++ CFileItemList list; ++ int curr = 0; ++}; ++ ++void CDVDCallback::dvd_logger(void* priv, dvdnav_logger_level_t level, const char* fmt, va_list va) ++{ ++ const std::string message = StringUtils::FormatV(fmt, va); ++ auto logLevel = LOGDEBUG; ++ switch (level) ++ { ++ case DVDNAV_LOGGER_LEVEL_INFO: ++ logLevel = LOGINFO; ++ break; ++ case DVDNAV_LOGGER_LEVEL_ERROR: ++ logLevel = LOGERROR; ++ break; ++ case DVDNAV_LOGGER_LEVEL_WARN: ++ logLevel = LOGWARNING; ++ break; ++ case DVDNAV_LOGGER_LEVEL_DEBUG: ++ logLevel = LOGDEBUG; ++ break; ++ default: ++ break; ++ }; ++ CLog::Log(logLevel, "Libdvd: {}", message); ++} ++ ++void CDVDCallback::dir_close(dvd_dir_h *dir) ++{ ++ if (dir) ++ { ++ CLog::Log(LOGDEBUG, "CDVDCallback - Closed dir ({})", fmt::ptr(dir)); ++ delete static_cast<SDirState*>(dir->internal); ++ delete dir; ++ } ++} ++ ++dvd_dir_h* CDVDCallback::dir_open(const char* strDirname) ++{ ++ CLog::Log(LOGDEBUG, "CDVDCallback - Opening dir {}", CURL::GetRedacted(strDirname)); ++ ++ SDirState *st = new SDirState(); ++ if (!CDirectory::GetDirectory(strDirname, st->list, "", DIR_FLAG_DEFAULTS)) ++ { ++ if (!CFile::Exists(strDirname)) ++ CLog::Log(LOGDEBUG, "CDVDCallback - Error opening dir! ({})", ++ CURL::GetRedacted(strDirname)); ++ delete st; ++ return nullptr; ++ } ++ ++ dvd_dir_h* dir = new dvd_dir_h; ++ dir->close = dir_close; ++ dir->read = dir_read; ++ dir->internal = (void*)st; ++ ++ return dir; ++} ++ ++int CDVDCallback::dir_read(dvd_dir_h *dir, dvd_dirent_t *entry) ++{ ++ SDirState* state = static_cast<SDirState*>(dir->internal); ++ ++ if (state->curr >= state->list.Size()) ++ return 1; ++ ++ strncpy(entry->d_name, state->list[state->curr]->GetLabel().c_str(), sizeof(entry->d_name)); ++ entry->d_name[sizeof(entry->d_name) - 1] = 0; ++ state->curr++; ++ ++ return 0; ++} ++ ++int64_t CDVDCallback::file_close(dvd_file_h *file) ++{ ++ if (file) ++ { ++ delete static_cast<CFile*>(file->internal); ++ delete file; ++ } ++ return 0; ++} ++ ++dvd_file_h * CDVDCallback::file_open(const char *filename, const char *cmode) ++{ ++ dvd_file_h* file = new dvd_file_h; ++ ++ file->close = file_close; ++ file->seek = file_seek; ++ file->read = file_read; ++ ++ CFile* fp = new CFile(); ++ if (fp->Open(filename)) ++ { ++ file->internal = (void*)fp; ++ return file; ++ } ++ ++ CLog::Log(LOGDEBUG, "CDVDCallback - Error opening file! ({})", CURL::GetRedacted(filename)); ++ ++ delete fp; ++ delete file; ++ ++ return nullptr; ++} ++ ++int64_t CDVDCallback::file_seek(dvd_file_h *file, int64_t offset, int32_t origin) ++{ ++ return static_cast<CFile*>(file->internal)->Seek(offset, origin); ++} ++ ++int64_t CDVDCallback::file_read(dvd_file_h *file, char *buf, int64_t size) ++{ ++ return static_cast<int64_t>(static_cast<CFile*>(file->internal)->Read(buf, static_cast<size_t>(size))); ++} ++ ++ ++ int CDVDCallback::stat(const char *path, dvdstat_t* statbuff) ++ { ++ struct __stat64 tStat; ++ int result = CFile::Stat(path, &tStat); ++ statbuff->size = tStat.st_size; ++ statbuff->is_blk = S_ISBLK(tStat.st_mode); ++ statbuff->is_chr = S_ISCHR(tStat.st_mode); ++ statbuff->is_dir = S_ISDIR(tStat.st_mode); ++ statbuff->is_reg = S_ISREG(tStat.st_mode); ++ return result; ++ } +diff --git a/xbmc/filesystem/DvdCallback.h b/xbmc/filesystem/DvdCallback.h +new file mode 100644 +index 0000000000..673108ec66 +--- /dev/null ++++ b/xbmc/filesystem/DvdCallback.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 ++ ++#ifdef __cplusplus ++extern "C" ++{ ++#endif ++#include <dvdread/dvd_filesystem.h> ++#include <dvdnav/dvdnav.h> ++#ifdef __cplusplus ++} ++#endif ++ ++class CDVDCallback ++{ ++public: ++ // logger implementation ++ static void dvd_logger(void* priv, dvdnav_logger_level_t level, const char* fmt, va_list va); ++ ++ // filesystem close ++ static void close(void *) {}; ++ ++ // dir ++ static void dir_close(dvd_dir_h* dir); ++ static dvd_dir_h* dir_open(const char* strDirname); ++ static int dir_read(dvd_dir_h* dir, dvd_dirent_t* entry); ++ ++ // file ++ static dvd_file_h* file_open(const char* filename, const char *cmode); ++ static int64_t file_close(dvd_file_h* file); ++ static int64_t file_read(dvd_file_h* file, char* buf, int64_t size); ++ static int64_t file_seek(dvd_file_h* file, int64_t offset, int32_t origin); ++ ++ // stat ++ static int stat(const char *path, dvdstat_t* statbuf); ++ ++private: ++ CDVDCallback() = default; ++ ~CDVDCallback() = default; ++}; +\ No newline at end of file +-- +2.35.1 + + +From 8dd8d11a55a7060bd7352623da92d102e7861bc3 Mon Sep 17 00:00:00 2001 +From: enen92 <92enen@gmail.com> +Date: Fri, 29 Jul 2022 14:05:57 +0100 +Subject: [PATCH 4/9] Updates + +--- + xbmc/DllPaths.h | 2 +- + .../VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.cpp | 4 ++-- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/xbmc/DllPaths.h b/xbmc/DllPaths.h +index 33fb46635e..9f8979355b 100644 +--- a/xbmc/DllPaths.h ++++ b/xbmc/DllPaths.h +@@ -10,7 +10,7 @@ + + #if defined (TARGET_ANDROID) + #include "DllPaths_generated_android.h" +-#else ++#elif !defined (TARGET_WINDOWS) + #include "DllPaths_generated.h" + #endif + +diff --git a/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.cpp b/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.cpp +index 8280a5a1b9..9221048789 100644 +--- a/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.cpp ++++ b/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.cpp +@@ -165,9 +165,9 @@ bool CDVDInputStreamNavigator::Open() + kodiDvdFilesystem.file_open = CDVDCallback::file_open; + kodiDvdFilesystem.stat = CDVDCallback::stat; + kodiDvdFilesystem.close = CDVDCallback::close; +- if (dvdnav_open_vfs_files(&m_dvdnav, nullptr, &loggerCallback, path.c_str(), &kodiDvdFilesystem) != DVDNAV_STATUS_OK) ++ if (dvdnav_open_files(&m_dvdnav, nullptr, &loggerCallback, path.c_str(), &kodiDvdFilesystem) != DVDNAV_STATUS_OK) + { +- CLog::Log(LOGERROR, "Error on dvdnav_open_vfs_files"); ++ CLog::Log(LOGERROR, "Error on dvdnav_open_files"); + Close(); + return false; + } +-- +2.35.1 + + +From 8cca2455a993b822270610cc87b63f60d2228079 Mon Sep 17 00:00:00 2001 +From: enen92 <92enen@gmail.com> +Date: Fri, 29 Jul 2022 14:41:39 +0100 +Subject: [PATCH 5/9] update dvdnav version + +--- + tools/depends/target/libdvdnav/LIBDVDNAV-VERSION | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/tools/depends/target/libdvdnav/LIBDVDNAV-VERSION b/tools/depends/target/libdvdnav/LIBDVDNAV-VERSION +index 3d6d1ec699..f5541697ac 100644 +--- a/tools/depends/target/libdvdnav/LIBDVDNAV-VERSION ++++ b/tools/depends/target/libdvdnav/LIBDVDNAV-VERSION +@@ -1,7 +1,7 @@ + LIBNAME=libdvdnav +-BASE_URL=https://github.com/xbmc/libdvdnav +-VERSION=6.1.1-Next-Nexus-Alpha2-2 ++BASE_URL=https://github.com/enen92/libdvdnav ++VERSION=upstream_submission_kodi + ARCHIVE=$(LIBNAME)-$(VERSION).tar.gz +-SHA512=51e6fc033121241354a5f0b3fc9a430577ae3ff6bb7f31445aa548ef4893037fb80eea3b2c6774c81e9ebaf9c45e9b490c98c2c65eb38f9f7daba84b236f7e1d ++SHA512=fca8c19a6787bb7a88a6a5e35f6a524505b607861b3bb391e3eca1e91b67d05b12417153542b161da0f13c4f5152f1d4860a34a6d230155c9c8c767fb35725b2 + BYPRODUCT=libdvdnav.a + BYPRODUCT_WIN=libdvdnav.lib +-- +2.35.1 + + +From be49396a22eb405d63a65bc56d3d1a24c6dcefab Mon Sep 17 00:00:00 2001 +From: enen92 <92enen@gmail.com> +Date: Fri, 29 Jul 2022 15:13:55 +0100 +Subject: [PATCH 6/9] update versions + +--- + tools/depends/target/libdvdread/LIBDVDREAD-VERSION | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/tools/depends/target/libdvdread/LIBDVDREAD-VERSION b/tools/depends/target/libdvdread/LIBDVDREAD-VERSION +index d51b629bd2..74428acf49 100644 +--- a/tools/depends/target/libdvdread/LIBDVDREAD-VERSION ++++ b/tools/depends/target/libdvdread/LIBDVDREAD-VERSION +@@ -1,7 +1,7 @@ + LIBNAME=libdvdread +-BASE_URL=https://github.com/xbmc/libdvdread +-VERSION=6.1.3-Next-Nexus-Alpha2-2 ++BASE_URL=https://github.com/enen92/libdvdread ++VERSION=upstream_submission_kodi + ARCHIVE=$(LIBNAME)-$(VERSION).tar.gz +-SHA512=629a41157d07b8ec0ea1fe89ae5ec48f63047472a862782b805c531ae31a0376fc4dc15175f8280c3ef91d7fa977bacebb1b51232640034a34bab2293210fc5e ++SHA512=d2fb890ccca8b8e7834470922f0b010f70b4016e829d71f51d3aaf30e2517ab7d98b46448313dd9c63141a71e794a8e679db4c1e0905e887c4897f7a5c194dc0 + BYPRODUCT=libdvdread.a + BYPRODUCT_WIN=dvdread.lib +-- +2.35.1 + + +From 4cf9e76978906e92ffb66441701d19f6e40c96fa Mon Sep 17 00:00:00 2001 +From: enen92 <92enen@gmail.com> +Date: Fri, 29 Jul 2022 15:39:43 +0100 +Subject: [PATCH 7/9] fixup + +--- + tools/depends/target/libdvdread/LIBDVDREAD-VERSION | 4 ++-- + .../VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.cpp | 2 +- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/tools/depends/target/libdvdread/LIBDVDREAD-VERSION b/tools/depends/target/libdvdread/LIBDVDREAD-VERSION +index 74428acf49..38b7a10d8b 100644 +--- a/tools/depends/target/libdvdread/LIBDVDREAD-VERSION ++++ b/tools/depends/target/libdvdread/LIBDVDREAD-VERSION +@@ -1,7 +1,7 @@ + LIBNAME=libdvdread + BASE_URL=https://github.com/enen92/libdvdread +-VERSION=upstream_submission_kodi ++VERSION=upstream_skodi7 + ARCHIVE=$(LIBNAME)-$(VERSION).tar.gz +-SHA512=d2fb890ccca8b8e7834470922f0b010f70b4016e829d71f51d3aaf30e2517ab7d98b46448313dd9c63141a71e794a8e679db4c1e0905e887c4897f7a5c194dc0 ++SHA512=932e83a9aeb949265538d935aab4689b9e8d8fe0611faad8ab066c97a418ad2dd907e65655b299950b296d7ff51394b89f51d41609cbfabb7db3d9201711e370 + BYPRODUCT=libdvdread.a + BYPRODUCT_WIN=dvdread.lib +diff --git a/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.cpp b/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.cpp +index 9221048789..db5679d9bf 100644 +--- a/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.cpp ++++ b/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.cpp +@@ -28,7 +28,7 @@ + #include "platform/Environment.h" + #endif + +-#include <sys/uio.h> ++//#include <sys/uio.h> + + namespace + { +-- +2.35.1 + + +From 423f4633ba64465004f5ad9894c934ba8b4725bf Mon Sep 17 00:00:00 2001 +From: enen92 <92enen@gmail.com> +Date: Fri, 29 Jul 2022 21:16:11 +0100 +Subject: [PATCH 8/9] update libs for win + +--- + .../depends/target/libdvdnav/LIBDVDNAV-VERSION | 6 +++--- + .../target/libdvdread/LIBDVDREAD-VERSION | 4 ++-- + .../DVDInputStreams/DVDInputStreamNavigator.cpp | 17 ++++++++++++++++- + xbmc/filesystem/DvdCallback.cpp | 6 ++++++ + 4 files changed, 27 insertions(+), 6 deletions(-) + +diff --git a/tools/depends/target/libdvdnav/LIBDVDNAV-VERSION b/tools/depends/target/libdvdnav/LIBDVDNAV-VERSION +index f5541697ac..2f6110e0b6 100644 +--- a/tools/depends/target/libdvdnav/LIBDVDNAV-VERSION ++++ b/tools/depends/target/libdvdnav/LIBDVDNAV-VERSION +@@ -1,7 +1,7 @@ + LIBNAME=libdvdnav + BASE_URL=https://github.com/enen92/libdvdnav +-VERSION=upstream_submission_kodi ++VERSION=upstream_submission_kodi2 + ARCHIVE=$(LIBNAME)-$(VERSION).tar.gz +-SHA512=fca8c19a6787bb7a88a6a5e35f6a524505b607861b3bb391e3eca1e91b67d05b12417153542b161da0f13c4f5152f1d4860a34a6d230155c9c8c767fb35725b2 ++SHA512=36bfedfd5628014164d757588e9165a7c4eb9f0dcd0c3fc393c7d6e1457d33f64f88a3a488c90d2862bfe65f99de274baa81c8e446ca9ad74d76d13166cebe24 + BYPRODUCT=libdvdnav.a +-BYPRODUCT_WIN=libdvdnav.lib ++BYPRODUCT_WIN=libdvdnav.lib +\ No newline at end of file +diff --git a/tools/depends/target/libdvdread/LIBDVDREAD-VERSION b/tools/depends/target/libdvdread/LIBDVDREAD-VERSION +index 38b7a10d8b..001f7572f6 100644 +--- a/tools/depends/target/libdvdread/LIBDVDREAD-VERSION ++++ b/tools/depends/target/libdvdread/LIBDVDREAD-VERSION +@@ -1,7 +1,7 @@ + LIBNAME=libdvdread + BASE_URL=https://github.com/enen92/libdvdread +-VERSION=upstream_skodi7 ++VERSION=upstream_skodi8 + ARCHIVE=$(LIBNAME)-$(VERSION).tar.gz +-SHA512=932e83a9aeb949265538d935aab4689b9e8d8fe0611faad8ab066c97a418ad2dd907e65655b299950b296d7ff51394b89f51d41609cbfabb7db3d9201711e370 ++SHA512=7946172ce3eeba869017038eaa215d915dff96550bc9b20d400fbe218ffe2622afb8de47df804ab165763330e4c818092c8d687ebc45422969062e0367c9fb6f + BYPRODUCT=libdvdread.a + BYPRODUCT_WIN=dvdread.lib +diff --git a/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.cpp b/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.cpp +index db5679d9bf..be369d95dc 100644 +--- a/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.cpp ++++ b/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.cpp +@@ -28,7 +28,22 @@ + #include "platform/Environment.h" + #endif + +-//#include <sys/uio.h> ++//FIXME ++#ifdef TARGET_WINDOWS ++#include "platform/win32/dirent.h" ++#else ++#include <dirent.h> ++#endif ++ ++#ifdef TARGET_WINDOWS ++struct iovec ++{ ++ void* iov_base; /* Pointer to data. */ ++ size_t iov_len; /* Length of data. */ ++}; ++#else ++#include <sys/uio.h> /* struct iovec */ ++#endif + + namespace + { +diff --git a/xbmc/filesystem/DvdCallback.cpp b/xbmc/filesystem/DvdCallback.cpp +index 2f247fff1f..a3bb72e808 100644 +--- a/xbmc/filesystem/DvdCallback.cpp ++++ b/xbmc/filesystem/DvdCallback.cpp +@@ -17,6 +17,12 @@ + + using namespace XFILE; + ++#ifdef TARGET_WINDOWS ++#include "platform/win32/dirent.h" ++#else ++#include <dirent.h> ++#endif ++ + struct SDirState + { + CFileItemList list; +-- +2.35.1 + + +From 070cccd1e3900dabbc21248055c31329ec1bc4e5 Mon Sep 17 00:00:00 2001 +From: enen92 <92enen@gmail.com> +Date: Tue, 9 Aug 2022 11:03:01 +0100 +Subject: [PATCH 9/9] Backup new version + +--- + .../DVDInputStreams/DVDInputStreamNavigator.cpp | 2 +- + xbmc/filesystem/DvdCallback.cpp | 17 +++++++---------- + xbmc/filesystem/DvdCallback.h | 12 ++++++------ + 3 files changed, 14 insertions(+), 17 deletions(-) + +diff --git a/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.cpp b/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.cpp +index be369d95dc..253c95cd1c 100644 +--- a/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.cpp ++++ b/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamNavigator.cpp +@@ -84,7 +84,7 @@ static int dvd_inputstreamnavigator_cb_seek(void * p_stream, uint64_t i_pos); + static int dvd_inputstreamnavigator_cb_read(void * p_stream, void * buffer, int i_read); + static int dvd_inputstreamnavigator_cb_readv(void * p_stream, void * p_iovec, int i_blocks); + +-static dvdnav_filesystem kodiDvdFilesystem; ++static dvdnav_filesystem_h kodiDvdFilesystem; + + CDVDInputStreamNavigator::CDVDInputStreamNavigator(IVideoPlayer* player, const CFileItem& fileitem) + : CDVDInputStream(DVDSTREAM_TYPE_DVD, fileitem), m_pstream(nullptr) +diff --git a/xbmc/filesystem/DvdCallback.cpp b/xbmc/filesystem/DvdCallback.cpp +index a3bb72e808..16b359b27e 100644 +--- a/xbmc/filesystem/DvdCallback.cpp ++++ b/xbmc/filesystem/DvdCallback.cpp +@@ -63,7 +63,7 @@ void CDVDCallback::dir_close(dvd_dir_h *dir) + } + } + +-dvd_dir_h* CDVDCallback::dir_open(const char* strDirname) ++dvd_dir_h* CDVDCallback::dir_open(dvdnav_filesystem_h *fs, const char* strDirname) + { + CLog::Log(LOGDEBUG, "CDVDCallback - Opening dir {}", CURL::GetRedacted(strDirname)); + +@@ -99,7 +99,7 @@ int CDVDCallback::dir_read(dvd_dir_h *dir, dvd_dirent_t *entry) + return 0; + } + +-int64_t CDVDCallback::file_close(dvd_file_h *file) ++int CDVDCallback::file_close(dvd_file_h *file) + { + if (file) + { +@@ -109,7 +109,7 @@ int64_t CDVDCallback::file_close(dvd_file_h *file) + return 0; + } + +-dvd_file_h * CDVDCallback::file_open(const char *filename, const char *cmode) ++dvd_file_h * CDVDCallback::file_open(dvdnav_filesystem_h *fs, const char *filename) + { + dvd_file_h* file = new dvd_file_h; + +@@ -137,20 +137,17 @@ int64_t CDVDCallback::file_seek(dvd_file_h *file, int64_t offset, int32_t origin + return static_cast<CFile*>(file->internal)->Seek(offset, origin); + } + +-int64_t CDVDCallback::file_read(dvd_file_h *file, char *buf, int64_t size) ++ssize_t CDVDCallback::file_read(dvd_file_h *file, char *buf, size_t size) + { +- return static_cast<int64_t>(static_cast<CFile*>(file->internal)->Read(buf, static_cast<size_t>(size))); ++ return static_cast<ssize_t>(static_cast<CFile*>(file->internal)->Read(buf, size)); + } + + +- int CDVDCallback::stat(const char *path, dvdstat_t* statbuff) ++ int CDVDCallback::stat(dvdnav_filesystem_h *fs, const char *path, dvdstat_t* statbuff) + { + struct __stat64 tStat; + int result = CFile::Stat(path, &tStat); + statbuff->size = tStat.st_size; +- statbuff->is_blk = S_ISBLK(tStat.st_mode); +- statbuff->is_chr = S_ISCHR(tStat.st_mode); +- statbuff->is_dir = S_ISDIR(tStat.st_mode); +- statbuff->is_reg = S_ISREG(tStat.st_mode); ++ statbuff->st_mode = tStat.st_mode; + return result; + } +diff --git a/xbmc/filesystem/DvdCallback.h b/xbmc/filesystem/DvdCallback.h +index 673108ec66..8451372422 100644 +--- a/xbmc/filesystem/DvdCallback.h ++++ b/xbmc/filesystem/DvdCallback.h +@@ -25,21 +25,21 @@ public: + static void dvd_logger(void* priv, dvdnav_logger_level_t level, const char* fmt, va_list va); + + // filesystem close +- static void close(void *) {}; ++ static void close(dvdnav_filesystem_h *fs) {}; + + // dir + static void dir_close(dvd_dir_h* dir); +- static dvd_dir_h* dir_open(const char* strDirname); ++ static dvd_dir_h* dir_open(dvdnav_filesystem_h *fs, const char* strDirname); + static int dir_read(dvd_dir_h* dir, dvd_dirent_t* entry); + + // file +- static dvd_file_h* file_open(const char* filename, const char *cmode); +- static int64_t file_close(dvd_file_h* file); +- static int64_t file_read(dvd_file_h* file, char* buf, int64_t size); ++ static dvd_file_h* file_open(dvdnav_filesystem_h *fs, const char* filename); ++ static int file_close(dvd_file_h* file); ++ static ssize_t file_read(dvd_file_h* file, char* buf, size_t size); + static int64_t file_seek(dvd_file_h* file, int64_t offset, int32_t origin); + + // stat +- static int stat(const char *path, dvdstat_t* statbuf); ++ static int stat(dvdnav_filesystem_h *fs, const char *path, dvdstat_t* statbuf); + + private: + CDVDCallback() = default; +-- +2.35.1 + diff --git a/debian/patches/workarounds/0004-ffmpeg6.patch b/debian/patches/workarounds/0004-ffmpeg6.patch new file mode 100644 index 0000000..d0c4563 --- /dev/null +++ b/debian/patches/workarounds/0004-ffmpeg6.patch @@ -0,0 +1,662 @@ +From c9e25dc15acf1214b079da7021ad89acf85fa77d Mon Sep 17 00:00:00 2001 +From: CastagnaIT <gottardo.stefano.83@gmail.com> +Date: Sun, 29 Jan 2023 17:51:51 +0100 +Subject: [PATCH] [VideoPlayerVideo] Log an error when codec extradata is + required + +--- + xbmc/cores/VideoPlayer/VideoPlayerVideo.cpp | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/xbmc/cores/VideoPlayer/VideoPlayerVideo.cpp b/xbmc/cores/VideoPlayer/VideoPlayerVideo.cpp +index 20f6b3b1cb51d..38f63f0766718 100644 +--- a/xbmc/cores/VideoPlayer/VideoPlayerVideo.cpp ++++ b/xbmc/cores/VideoPlayer/VideoPlayerVideo.cpp +@@ -114,8 +114,11 @@ bool CVideoPlayerVideo::OpenStream(CDVDStreamInfo hint) + hint.codec == AV_CODEC_ID_WMV3 || + hint.codec == AV_CODEC_ID_VC1 || + hint.codec == AV_CODEC_ID_AV1) +- // clang-format on ++ { ++ CLog::LogF(LOGERROR, "Codec id {} require extradata.", hint.codec); + return false; ++ } ++ // clang-format on + } + + CLog::Log(LOGINFO, "Creating video codec with codec id: {}", hint.codec); + + +From 2559466404d342428d43076bf90fcacc24313af0 Mon Sep 17 00:00:00 2001 +From: enen92 <92enen@gmail.com> +Date: Mon, 6 Feb 2023 15:36:11 +0000 +Subject: [PATCH] video: remove ffmpeg bsf hack + +Manually setting the codecID on the bsf filter is wrong. +avcodec_parameters_copy should be used instead. +--- + xbmc/cores/FFmpeg.cpp | 13 ++++++++----- + xbmc/cores/FFmpeg.h | 3 +-- + .../VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp | 10 +++++++++- + .../VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp | 3 +-- + 4 files changed, 19 insertions(+), 10 deletions(-) + +diff --git a/xbmc/cores/FFmpeg.cpp b/xbmc/cores/FFmpeg.cpp +index d071f6d8e33a3..73b7ea2ae875c 100644 +--- a/xbmc/cores/FFmpeg.cpp ++++ b/xbmc/cores/FFmpeg.cpp +@@ -135,9 +135,7 @@ void ff_avutil_log(void* ptr, int level, const char* format, va_list va) + buffer.erase(0, start); + } + +-std::tuple<uint8_t*, int> GetPacketExtradata(const AVPacket* pkt, +- const AVCodecParserContext* parserCtx, +- AVCodecContext* codecCtx) ++std::tuple<uint8_t*, int> GetPacketExtradata(const AVPacket* pkt, const AVCodecParameters* codecPar) + { + constexpr int FF_MAX_EXTRADATA_SIZE = ((1 << 28) - AV_INPUT_BUFFER_PADDING_SIZE); + +@@ -151,7 +149,7 @@ std::tuple<uint8_t*, int> GetPacketExtradata(const AVPacket* pkt, + * for certain codecs, as noted in discussion of PR#21248 + */ + +- AVCodecID codecId = codecCtx->codec_id; ++ AVCodecID codecId = codecPar->codec_id; + + // clang-format off + if ( +@@ -178,7 +176,12 @@ std::tuple<uint8_t*, int> GetPacketExtradata(const AVPacket* pkt, + if (ret < 0) + return std::make_tuple(nullptr, 0); + +- bsf->par_in->codec_id = codecId; ++ ret = avcodec_parameters_copy(bsf->par_in, codecPar); ++ if (ret < 0) ++ { ++ av_bsf_free(&bsf); ++ return std::make_tuple(nullptr, 0); ++ } + + ret = av_bsf_init(bsf); + if (ret < 0) +diff --git a/xbmc/cores/FFmpeg.h b/xbmc/cores/FFmpeg.h +index 05547a0ba2b5f..5e35d58c6b0a6 100644 +--- a/xbmc/cores/FFmpeg.h ++++ b/xbmc/cores/FFmpeg.h +@@ -73,5 +73,4 @@ class CFFmpegLog + }; + + std::tuple<uint8_t*, int> GetPacketExtradata(const AVPacket* pkt, +- const AVCodecParserContext* parserCtx, +- AVCodecContext* codecCtx); ++ const AVCodecParameters* codecPar); +diff --git a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp +index 052332331702a..9ca07b9a2dd39 100644 +--- a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp ++++ b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp +@@ -162,7 +162,15 @@ bool CDVDDemuxClient::ParsePacket(DemuxPacket* pkt) + avpkt->size = pkt->iSize; + avpkt->dts = avpkt->pts = AV_NOPTS_VALUE; + +- auto [retExtraData, len] = GetPacketExtradata(avpkt, stream->m_parser, stream->m_context); ++ AVCodecParameters* codecPar = nullptr; ++ int ret = avcodec_parameters_from_context(codecPar, stream->m_context); ++ if (ret < 0) ++ { ++ CLog::LogF(LOGERROR, "avcodec_parameters_from_context failed"); ++ return false; ++ } ++ ++ auto [retExtraData, len] = GetPacketExtradata(avpkt, codecPar); + if (len > 0) + { + st->changes++; +diff --git a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp +index 7e6a2e10616d7..bc6b54c87235d 100644 +--- a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp ++++ b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp +@@ -2290,8 +2290,7 @@ void CDVDDemuxFFmpeg::ParsePacket(AVPacket* pkt) + parser->second->m_parserCtx->parser && + !st->codecpar->extradata) + { +- auto [retExtraData, i] = +- GetPacketExtradata(pkt, parser->second->m_parserCtx, parser->second->m_codecCtx); ++ auto [retExtraData, i] = GetPacketExtradata(pkt, st->codecpar); + if (i > 0) + { + st->codecpar->extradata_size = i; + + +From 3ad9588656e30abd421e48147b23aee9fb4b3557 Mon Sep 17 00:00:00 2001 +From: Miguel Borges de Freitas <92enen@gmail.com> +Date: Sun, 12 Feb 2023 12:08:36 +0000 +Subject: [PATCH] [video] fix crash in avcodec_parameters_from_context + +--- + xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp +index 9ca07b9a2dd39..26fa9522eea7a 100644 +--- a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp ++++ b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp +@@ -162,11 +162,12 @@ bool CDVDDemuxClient::ParsePacket(DemuxPacket* pkt) + avpkt->size = pkt->iSize; + avpkt->dts = avpkt->pts = AV_NOPTS_VALUE; + +- AVCodecParameters* codecPar = nullptr; ++ AVCodecParameters* codecPar = avcodec_parameters_alloc(); + int ret = avcodec_parameters_from_context(codecPar, stream->m_context); + if (ret < 0) + { + CLog::LogF(LOGERROR, "avcodec_parameters_from_context failed"); ++ avcodec_parameters_free(&codecPar); + return false; + } + +@@ -188,7 +189,7 @@ bool CDVDDemuxClient::ParsePacket(DemuxPacket* pkt) + avcodec_close(stream->m_context); + } + } +- ++ avcodec_parameters_free(&codecPar); + av_packet_free(&avpkt); + } + + + +From f30f1e6418ea60bc7cb081c59f5f1d9431d264e6 Mon Sep 17 00:00:00 2001 +From: Lukas Rusak <lorusak@gmail.com> +Date: Sat, 11 Mar 2023 13:28:38 -0800 +Subject: [PATCH 01/10] CDVDAudioCodecFFmpeg: ifdef use of + AV_CODEC_FLAG_TRUNCATED for ffmpeg 6.0 + +Signed-off-by: Lukas Rusak <lorusak@gmail.com> +--- + xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp +index b2849c797dbc4..325bb0b7549ab 100644 +--- a/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp ++++ b/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp +@@ -73,8 +73,10 @@ bool CDVDAudioCodecFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options + m_pCodecContext->debug = 0; + m_pCodecContext->workaround_bugs = 1; + ++#if LIBAVCODEC_VERSION_MAJOR < 60 + if (pCodec->capabilities & AV_CODEC_CAP_TRUNCATED) + m_pCodecContext->flags |= AV_CODEC_FLAG_TRUNCATED; ++#endif + + m_matrixEncoding = AV_MATRIX_ENCODING_NONE; + m_channels = 0; + +From 3b71910ee0bb650816456ecc9a21251aff650c4d Mon Sep 17 00:00:00 2001 +From: Lukas Rusak <lorusak@gmail.com> +Date: Sat, 11 Mar 2023 13:29:18 -0800 +Subject: [PATCH 02/10] CDVDAudioCodecFFmpeg: fix setting channel layout mask + when opening codec + +Signed-off-by: Lukas Rusak <lorusak@gmail.com> +--- + .../DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp | 17 ++++++++++++++--- + 1 file changed, 14 insertions(+), 3 deletions(-) + +diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp +index 325bb0b7549ab..d1fb2cfe96afc 100644 +--- a/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp ++++ b/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp +@@ -80,13 +80,21 @@ + m_channels = 0; + #if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ + LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) +- av_channel_layout_uninit(&m_pCodecContext->ch_layout); +- m_pCodecContext->ch_layout.order = AV_CHANNEL_ORDER_NATIVE; +- m_pCodecContext->ch_layout.nb_channels = hints.channels; ++ if (hints.channels > 0 && hints.channellayout > 0) ++ { ++ m_pCodecContext->ch_layout.order = AV_CHANNEL_ORDER_NATIVE; ++ m_pCodecContext->ch_layout.nb_channels = hints.channels; ++ m_pCodecContext->ch_layout.u.mask = hints.channellayout; ++ } ++ else if (hints.channels > 0) ++ { ++ av_channel_layout_default(&m_pCodecContext->ch_layout, hints.channels); ++ } ++ ++ m_hint_layout = m_pCodecContext->ch_layout.u.mask; + #else + m_pCodecContext->channels = hints.channels; + #endif +- m_hint_layout = hints.channellayout; + m_pCodecContext->sample_rate = hints.samplerate; + m_pCodecContext->block_align = hints.blockalign; + m_pCodecContext->bit_rate = hints.bitrate; + +From f4fadb3ba4583c45fb06908a3eb352be8c29f235 Mon Sep 17 00:00:00 2001 +From: Lukas Rusak <lorusak@gmail.com> +Date: Sat, 11 Mar 2023 13:29:34 -0800 +Subject: [PATCH 03/10] CDVDAudioCodecFFmpeg: drop unneeded use of + AVFMT_FLAG_PRIV_OPT + +Signed-off-by: Lukas Rusak <lorusak@gmail.com> +--- + xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp +index bc6b54c87235d..016d198206716 100644 +--- a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp ++++ b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp +@@ -323,7 +323,6 @@ bool CDVDDemuxFFmpeg::Open(const std::shared_ptr<CDVDInputStream>& pInput, bool + } + if (result < 0) + { +- m_pFormatContext->flags |= AVFMT_FLAG_PRIV_OPT; + if (avformat_open_input(&m_pFormatContext, strFile.c_str(), iformat, &options) < 0) + { + CLog::Log(LOGDEBUG, "Error, could not open file {}", CURL::GetRedacted(strFile)); +@@ -335,7 +334,6 @@ bool CDVDDemuxFFmpeg::Open(const std::shared_ptr<CDVDInputStream>& pInput, bool + avformat_close_input(&m_pFormatContext); + m_pFormatContext = avformat_alloc_context(); + m_pFormatContext->interrupt_callback = int_cb; +- m_pFormatContext->flags &= ~AVFMT_FLAG_PRIV_OPT; + AVDictionary* options = GetFFMpegOptionsFromInput(); + av_dict_set_int(&options, "load_all_variants", 0, AV_OPT_SEARCH_CHILDREN); + if (avformat_open_input(&m_pFormatContext, strFile.c_str(), iformat, &options) < 0) + +From 7d03f33b83e5fb127a7495798a20c3b63ac06795 Mon Sep 17 00:00:00 2001 +From: Lukas Rusak <lorusak@gmail.com> +Date: Wed, 15 Mar 2023 19:58:56 -0700 +Subject: [PATCH 04/10] CDVDVideoCodecFFmpeg: update filter args to use + key/value pairs + +Signed-off-by: Lukas Rusak <lorusak@gmail.com> +--- + .../VideoPlayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp +index bb9c20bf9d06e..c080589896ce7 100644 +--- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp ++++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp +@@ -1164,8 +1164,9 @@ int CDVDVideoCodecFFmpeg::FilterOpen(const std::string& filters, bool scale) + const AVFilter* outFilter = avfilter_get_by_name("buffersink"); // should be last filter in the graph for now + + std::string args = StringUtils::Format( +- "{}:{}:{}:{}:{}:{}:{}", m_pCodecContext->width, m_pCodecContext->height, +- m_pCodecContext->pix_fmt, m_pCodecContext->time_base.num ? m_pCodecContext->time_base.num : 1, ++ "video_size={}x{}:pix_fmt={}:time_base={}/{}:pixel_aspect={}/{}", m_pCodecContext->width, ++ m_pCodecContext->height, m_pCodecContext->pix_fmt, ++ m_pCodecContext->time_base.num ? m_pCodecContext->time_base.num : 1, + m_pCodecContext->time_base.num ? m_pCodecContext->time_base.den : 1, + m_pCodecContext->sample_aspect_ratio.num != 0 ? m_pCodecContext->sample_aspect_ratio.num : 1, + m_pCodecContext->sample_aspect_ratio.num != 0 ? m_pCodecContext->sample_aspect_ratio.den : 1); + +From 30bd7912802cf0f608751c452c48fc1a2eb8d91b Mon Sep 17 00:00:00 2001 +From: Lukas Rusak <lorusak@gmail.com> +Date: Wed, 15 Mar 2023 19:59:27 -0700 +Subject: [PATCH 05/10] CFFmpegPostproc: update filter args to use key/value + pairs + +Signed-off-by: Lukas Rusak <lorusak@gmail.com> +--- + xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.cpp | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.cpp +index 81b969d119667..6c4f664591a04 100644 +--- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.cpp ++++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.cpp +@@ -2962,10 +2962,11 @@ bool CFFmpegPostproc::Init(EINTERLACEMETHOD method) + const AVFilter* srcFilter = avfilter_get_by_name("buffer"); + const AVFilter* outFilter = avfilter_get_by_name("buffersink"); + +- std::string args = StringUtils::Format("{}:{}:{}:{}:{}:{}:{}", m_config.vidWidth, +- m_config.vidHeight, AV_PIX_FMT_NV12, 1, 1, +- (m_config.aspect.num != 0) ? m_config.aspect.num : 1, +- (m_config.aspect.num != 0) ? m_config.aspect.den : 1); ++ std::string args = ++ StringUtils::Format("video_size={}x{}:pix_fmt={}:time_base={}/{}:pixel_aspect={}/{}", ++ m_config.vidWidth, m_config.vidHeight, AV_PIX_FMT_NV12, 1, 1, ++ (m_config.aspect.num != 0) ? m_config.aspect.num : 1, ++ (m_config.aspect.num != 0) ? m_config.aspect.den : 1); + + if (avfilter_graph_create_filter(&m_pFilterIn, srcFilter, "src", args.c_str(), NULL, m_pFilterGraph) < 0) + { + +From 54a21151374a2d40a2a452fae2709205ed8e8836 Mon Sep 17 00:00:00 2001 +From: Lukas Rusak <lorusak@gmail.com> +Date: Sat, 11 Mar 2023 19:32:09 -0800 +Subject: [PATCH 08/10] DXVA: CDecoder: replace removed av_mallocz_array with + av_calloc + +ref: https://ffmpeg.org/doxygen/5.0/group__lavu__mem__funcs.html\#ga6627f140c3f70847bc6d9690a2fd001f + +Signed-off-by: Lukas Rusak <lorusak@gmail.com> +--- + xbmc/cores/VideoPlayer/DVDCodecs/Video/DXVA.cpp | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DXVA.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DXVA.cpp +index a1bc3761c59d1..c06bd1ac0c7e6 100644 +--- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DXVA.cpp ++++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DXVA.cpp +@@ -972,7 +972,8 @@ CDecoder::CDecoder(CProcessInfo& processInfo) + m_event.Set(); + m_avD3D11Context = av_d3d11va_alloc_context(); + m_avD3D11Context->cfg = reinterpret_cast<D3D11_VIDEO_DECODER_CONFIG*>(av_mallocz(sizeof(D3D11_VIDEO_DECODER_CONFIG))); +- m_avD3D11Context->surface = reinterpret_cast<ID3D11VideoDecoderOutputView**>(av_mallocz_array(32, sizeof(ID3D11VideoDecoderOutputView*))); ++ m_avD3D11Context->surface = reinterpret_cast<ID3D11VideoDecoderOutputView**>( ++ av_calloc(32, sizeof(ID3D11VideoDecoderOutputView*))); + m_bufferPool.reset(); + + DX::Windowing()->Register(this); + +From be1247d627cee6561174467094f1e8a46357df79 Mon Sep 17 00:00:00 2001 +From: Lukas Rusak <lorusak@gmail.com> +Date: Sat, 11 Mar 2023 19:45:46 -0800 +Subject: [PATCH 09/10] CFFmpegImage: remove deprecated use of pkt_duration + +ref: https://ffmpeg.org/doxygen/6.0/structAVFrame.html\#a91725a40000e348b0607adf7f577e646 + +Signed-off-by: Lukas Rusak <lorusak@gmail.com> +--- + xbmc/guilib/FFmpegImage.cpp | 16 +++++++++++++++- + 1 file changed, 15 insertions(+), 1 deletion(-) + +diff --git a/xbmc/guilib/FFmpegImage.cpp b/xbmc/guilib/FFmpegImage.cpp +index e71980998b2e5..7171c046a9ce5 100644 +--- a/xbmc/guilib/FFmpegImage.cpp ++++ b/xbmc/guilib/FFmpegImage.cpp +@@ -294,7 +294,15 @@ AVFrame* CFFmpegImage::ExtractFrame() + return nullptr; + } + //we need milliseconds +- frame->pkt_duration = av_rescale_q(frame->pkt_duration, m_fctx->streams[0]->time_base, AVRational{ 1, 1000 }); ++ ++#if LIBAVCODEC_VERSION_MAJOR < 60 ++ frame->pkt_duration = ++ av_rescale_q(frame->pkt_duration, m_fctx->streams[0]->time_base, AVRational{1, 1000}); ++#else ++ frame->duration = ++ av_rescale_q(frame->duration, m_fctx->streams[0]->time_base, AVRational{1, 1000}); ++#endif ++ + m_height = frame->height; + m_width = frame->width; + m_originalWidth = m_width; +@@ -745,7 +753,13 @@ std::shared_ptr<Frame> CFFmpegImage::ReadFrame() + if (avframe == nullptr) + return nullptr; + std::shared_ptr<Frame> frame(new Frame()); ++ ++#if LIBAVCODEC_VERSION_MAJOR < 60 + frame->m_delay = (unsigned int)avframe->pkt_duration; ++#else ++ frame->m_delay = (unsigned int)avframe->duration; ++#endif ++ + frame->m_pitch = avframe->width * 4; + frame->m_pImage = (unsigned char*) av_malloc(avframe->height * frame->m_pitch); + DecodeFrame(avframe, avframe->width, avframe->height, frame->m_pitch, frame->m_pImage); + +From c12af890b0973f7c86316087e823f8a31c6b2ed3 Mon Sep 17 00:00:00 2001 +From: Lukas Rusak <lorusak@gmail.com> +Date: Sat, 11 Mar 2023 19:45:01 -0800 +Subject: [PATCH 10/10] CDVDVideoCodecFFmpeg: remove deprecated use of + reordered_opaque + +ref: https://ffmpeg.org/doxygen/6.0/structAVFrame.html#a12f572ed19a2cba6be3790393cee76b5 + +Signed-off-by: Lukas Rusak <lorusak@gmail.com> +--- + .../DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp | 11 ++++++++++- + xbmc/cores/VideoPlayer/DVDCodecs/Video/DXVA.cpp | 6 ++++-- + xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.cpp | 3 +++ + xbmc/cores/VideoPlayer/DVDCodecs/Video/VDPAU.cpp | 5 ++++- + 4 files changed, 21 insertions(+), 4 deletions(-) + +diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp +index c080589896ce7..6a53ade4a7351 100644 +--- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp ++++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp +@@ -370,6 +370,10 @@ bool CDVDVideoCodecFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options + m_pCodecContext->get_format = GetFormat; + m_pCodecContext->codec_tag = hints.codec_tag; + ++#if LIBAVCODEC_VERSION_MAJOR >= 60 ++ m_pCodecContext->flags = AV_CODEC_FLAG_COPY_OPAQUE; ++#endif ++ + // setup threading model + if (!(hints.codecOptions & CODEC_FORCE_SOFTWARE)) + { +@@ -545,9 +549,10 @@ void CDVDVideoCodecFFmpeg::UpdateName() + CLog::Log(LOGDEBUG, "CDVDVideoCodecFFmpeg - Updated codec: {}", m_name); + } + ++#if LIBAVCODEC_VERSION_MAJOR < 60 + union pts_union + { +- double pts_d; ++ double pts_d; + int64_t pts_i; + }; + +@@ -557,6 +562,7 @@ static int64_t pts_dtoi(double pts) + u.pts_d = pts; + return u.pts_i; + } ++#endif + + bool CDVDVideoCodecFFmpeg::AddData(const DemuxPacket &packet) + { +@@ -575,7 +581,10 @@ bool CDVDVideoCodecFFmpeg::AddData(const DemuxPacket &packet) + m_started = true; + + m_dts = packet.dts; ++ ++#if LIBAVCODEC_VERSION_MAJOR < 60 + m_pCodecContext->reordered_opaque = pts_dtoi(packet.pts); ++#endif + + AVPacket* avpkt = av_packet_alloc(); + if (!avpkt) +diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DXVA.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DXVA.cpp +index c06bd1ac0c7e6..81451995ca1db 100644 +--- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DXVA.cpp ++++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DXVA.cpp +@@ -1538,8 +1538,6 @@ int CDecoder::GetBuffer(AVCodecContext* avctx, AVFrame* pic) + return -1; + } + +- pic->reordered_opaque = avctx->reordered_opaque; +- + for (unsigned i = 0; i < 4; i++) + { + pic->data[i] = nullptr; +@@ -1556,6 +1554,10 @@ int CDecoder::GetBuffer(AVCodecContext* avctx, AVFrame* pic) + } + pic->buf[0] = buffer; + ++#if LIBAVCODEC_VERSION_MAJOR < 60 ++ pic->reordered_opaque = avctx->reordered_opaque; ++#endif ++ + Acquire(); + + return 0; +diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.cpp +index 6c4f664591a04..447a13495d4e8 100644 +--- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.cpp ++++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.cpp +@@ -867,7 +867,10 @@ int CDecoder::FFGetBuffer(AVCodecContext *avctx, AVFrame *pic, int flags) + } + pic->buf[0] = buffer; + ++#if LIBAVCODEC_VERSION_MAJOR < 60 + pic->reordered_opaque = avctx->reordered_opaque; ++#endif ++ + va->Acquire(); + return 0; + } +diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/VDPAU.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/VDPAU.cpp +index ec07af79de819..50e16d492ebc7 100644 +--- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/VDPAU.cpp ++++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/VDPAU.cpp +@@ -1041,7 +1041,10 @@ int CDecoder::FFGetBuffer(AVCodecContext *avctx, AVFrame *pic, int flags) + } + pic->buf[0] = buffer; + +- pic->reordered_opaque= avctx->reordered_opaque; ++#if LIBAVCODEC_VERSION_MAJOR < 60 ++ pic->reordered_opaque = avctx->reordered_opaque; ++#endif ++ + return 0; + } + + +From 928a7e4196046154419727a23c734d904e5e1b6c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Markus=20H=C3=A4rer?= <markus.haerer@gmx.net> +Date: Sun, 23 Apr 2023 23:29:28 +0200 +Subject: [PATCH] FFmpegImage: Switch back to jpeg_pipe for FFmpeg>=6.0 + +--- + xbmc/guilib/FFmpegImage.cpp | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +diff --git a/xbmc/guilib/FFmpegImage.cpp b/xbmc/guilib/FFmpegImage.cpp +index 7171c046a9ce5..429037740a7d2 100644 +--- a/xbmc/guilib/FFmpegImage.cpp ++++ b/xbmc/guilib/FFmpegImage.cpp +@@ -198,9 +198,16 @@ bool CFFmpegImage::Initialize(unsigned char* buffer, size_t bufSize) + bool is_png = (bufSize > 3 && buffer[1] == 'P' && buffer[2] == 'N' && buffer[3] == 'G'); + bool is_tiff = (bufSize > 2 && buffer[0] == 'I' && buffer[1] == 'I' && buffer[2] == '*'); + ++ // See Github #19113 ++#if LIBAVCODEC_VERSION_MAJOR < 60 ++ constexpr char jpegFormat[] = "image2"; ++#else ++ constexpr char jpegFormat[] = "jpeg_pipe"; ++#endif ++ + FFMPEG_FMT_CONST AVInputFormat* inp = nullptr; + if (is_jpeg) +- inp = av_find_input_format("image2"); ++ inp = av_find_input_format(jpegFormat); + else if (m_strMimeType == "image/apng") + inp = av_find_input_format("apng"); + else if (is_png) +@@ -213,7 +220,7 @@ bool CFFmpegImage::Initialize(unsigned char* buffer, size_t bufSize) + inp = av_find_input_format("webp_pipe"); + // brute force parse if above check already failed + else if (m_strMimeType == "image/jpeg" || m_strMimeType == "image/jpg") +- inp = av_find_input_format("image2"); ++ inp = av_find_input_format(jpegFormat); + else if (m_strMimeType == "image/png") + inp = av_find_input_format("png_pipe"); + else if (m_strMimeType == "image/tiff") + + +From 9d7f4dfd00d89d4a5d6d8095ee9b0b746051b30c Mon Sep 17 00:00:00 2001 +From: CrystalP <crystalp@kodi.tv> +Date: Mon, 1 May 2023 13:26:56 -0400 +Subject: [PATCH] [fix] extern C for ffmpeg includes + +--- + xbmc/cores/RetroPlayer/process/RPProcessInfo.h | 3 +++ + xbmc/cores/RetroPlayer/rendering/RenderTranslator.h | 3 +++ + xbmc/cores/VideoPlayer/DVDFileInfo.cpp | 4 ++-- + xbmc/cores/VideoPlayer/VideoRenderers/windows/RendererDXVA.h | 4 ++++ + .../VideoPlayer/VideoRenderers/windows/RendererShaders.h | 4 ++++ + 5 files changed, 16 insertions(+), 2 deletions(-) + +diff --git a/xbmc/cores/RetroPlayer/process/RPProcessInfo.h b/xbmc/cores/RetroPlayer/process/RPProcessInfo.h +index 9f930e78e9d84..f5ffe670d68aa 100644 +--- a/xbmc/cores/RetroPlayer/process/RPProcessInfo.h ++++ b/xbmc/cores/RetroPlayer/process/RPProcessInfo.h +@@ -17,7 +17,10 @@ + #include <string> + #include <vector> + ++extern "C" ++{ + #include <libavutil/pixfmt.h> ++} + + class CDataCacheCore; + +diff --git a/xbmc/cores/RetroPlayer/rendering/RenderTranslator.h b/xbmc/cores/RetroPlayer/rendering/RenderTranslator.h +index 575ad814fc125..d78e1c25e4070 100644 +--- a/xbmc/cores/RetroPlayer/rendering/RenderTranslator.h ++++ b/xbmc/cores/RetroPlayer/rendering/RenderTranslator.h +@@ -10,7 +10,10 @@ + + #include "cores/GameSettings.h" + ++extern "C" ++{ + #include <libavutil/pixfmt.h> ++} + + namespace KODI + { +diff --git a/xbmc/cores/VideoPlayer/DVDFileInfo.cpp b/xbmc/cores/VideoPlayer/DVDFileInfo.cpp +index 0860b40475b18..c7253bbd5497f 100644 +--- a/xbmc/cores/VideoPlayer/DVDFileInfo.cpp ++++ b/xbmc/cores/VideoPlayer/DVDFileInfo.cpp +@@ -32,8 +32,6 @@ + #include "DVDDemuxers/DVDDemuxVobsub.h" + #include "Process/ProcessInfo.h" + +-#include <libavcodec/avcodec.h> +-#include <libswscale/swscale.h> + #include "filesystem/File.h" + #include "cores/FFmpeg.h" + #include "TextureCache.h" +@@ -44,7 +42,9 @@ + #include <memory> + + extern "C" { ++#include <libavcodec/avcodec.h> + #include <libavformat/avformat.h> ++#include <libswscale/swscale.h> + } + + bool CDVDFileInfo::GetFileDuration(const std::string &path, int& duration) +diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/windows/RendererDXVA.h b/xbmc/cores/VideoPlayer/VideoRenderers/windows/RendererDXVA.h +index 9412377157f94..0eed9503dc9ac 100644 +--- a/xbmc/cores/VideoPlayer/VideoRenderers/windows/RendererDXVA.h ++++ b/xbmc/cores/VideoPlayer/VideoRenderers/windows/RendererDXVA.h +@@ -13,7 +13,11 @@ + #include <map> + + #include <d3d11_4.h> ++ ++extern "C" ++{ + #include <libavutil/pixfmt.h> ++} + + enum RenderMethod; + +diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/windows/RendererShaders.h b/xbmc/cores/VideoPlayer/VideoRenderers/windows/RendererShaders.h +index 945cadda76841..af4d677aae923 100644 +--- a/xbmc/cores/VideoPlayer/VideoRenderers/windows/RendererShaders.h ++++ b/xbmc/cores/VideoPlayer/VideoRenderers/windows/RendererShaders.h +@@ -13,7 +13,11 @@ + #include <map> + + #include <d3d11_4.h> ++ ++extern "C" ++{ + #include <libavutil/pixfmt.h> ++} + + #define PLANE_Y 0 + #define PLANE_U 1 diff --git a/debian/patches/workarounds/0005-pcre2.patch b/debian/patches/workarounds/0005-pcre2.patch new file mode 100644 index 0000000..7dfda8c --- /dev/null +++ b/debian/patches/workarounds/0005-pcre2.patch @@ -0,0 +1,1219 @@ +Description: Port to PCRE2. +Bug-Debian: https://bugs.debian.org/1000113 +Author: Yavor Doganov <yavor@gnu.org> +Forwarded: no +Last-Update: 2024-01-07 +--- + +--- kodi-20.2+dfsg.orig/cmake/modules/FindPCRE.cmake ++++ kodi-20.2+dfsg/cmake/modules/FindPCRE.cmake +@@ -77,45 +77,34 @@ + + else() + # Populate paths for find_package_handle_standard_args +- find_path(PCRE_INCLUDE_DIR pcre.h) ++ find_path(PCRE_INCLUDE_DIR pcre2.h) + +- find_library(PCRECPP_LIBRARY_RELEASE NAMES pcrecpp) +- find_library(PCRECPP_LIBRARY_DEBUG NAMES pcrecppd) +- +- find_library(PCRE_LIBRARY_RELEASE NAMES pcre) +- find_library(PCRE_LIBRARY_DEBUG NAMES pcred) ++ find_library(PCRE_LIBRARY_RELEASE NAMES pcre2-8) + endif() + else() + + if(PKG_CONFIG_FOUND) +- pkg_check_modules(PC_PCRE libpcrecpp QUIET) ++ pkg_check_modules(PC_PCRE libpcre2-8 QUIET) + endif() + +- find_path(PCRE_INCLUDE_DIR pcrecpp.h ++ find_path(PCRE_INCLUDE_DIR pcre2.h + PATHS ${PC_PCRE_INCLUDEDIR}) +- find_library(PCRECPP_LIBRARY_RELEASE NAMES pcrecpp +- PATHS ${PC_PCRE_LIBDIR}) +- find_library(PCRE_LIBRARY_RELEASE NAMES pcre ++ find_library(PCRE_LIBRARY_RELEASE NAMES pcre2-8 + PATHS ${PC_PCRE_LIBDIR}) +- find_library(PCRECPP_LIBRARY_DEBUG NAMES pcrecppd +- PATHS ${PC_PCRE_LIBDIR}) +- find_library(PCRE_LIBRARY_DEBUG NAMES pcred +- PATHS ${PC_PCRE_LIBDIR}) + set(PCRE_VERSION ${PC_PCRE_VERSION}) + + endif() + + include(SelectLibraryConfigurations) +- select_library_configurations(PCRECPP) + select_library_configurations(PCRE) + + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args(PCRE +- REQUIRED_VARS PCRECPP_LIBRARY PCRE_LIBRARY PCRE_INCLUDE_DIR ++ REQUIRED_VARS PCRE_LIBRARY PCRE_INCLUDE_DIR + VERSION_VAR PCRE_VERSION) + + if(PCRE_FOUND) +- set(PCRE_LIBRARIES ${PCRECPP_LIBRARY} ${PCRE_LIBRARY}) ++ set(PCRE_LIBRARIES ${PCRE_LIBRARY}) + set(PCRE_INCLUDE_DIRS ${PCRE_INCLUDE_DIR}) + if(WIN32) + set(PCRE_DEFINITIONS -DPCRE_STATIC=1) +@@ -166,5 +155,5 @@ + endif() + endif() + +- mark_as_advanced(PCRE_INCLUDE_DIR PCRECPP_LIBRARY PCRE_LIBRARY) ++ mark_as_advanced(PCRE_INCLUDE_DIR PCRE_LIBRARY) + endif() +--- kodi-20.2+dfsg.orig/xbmc/utils/RegExp.h ++++ kodi-20.2+dfsg/xbmc/utils/RegExp.h +@@ -13,16 +13,8 @@ + #include <string> + #include <vector> + +-/* make sure stdlib.h is included before including pcre.h inside the +- namespace; this works around stdlib.h definitions also living in +- the PCRE namespace */ +-#include <stdlib.h> +- +-namespace PCRE { +-struct real_pcre_jit_stack; // forward declaration for PCRE without JIT +-typedef struct real_pcre_jit_stack pcre_jit_stack; +-#include <pcre.h> +-} ++#define PCRE2_CODE_UNIT_WIDTH 8 ++#include <pcre2.h> + + class CRegExp + { +@@ -143,17 +135,17 @@ + void Cleanup(); + inline bool IsValidSubNumber(int iSub) const; + +- PCRE::pcre* m_re; +- PCRE::pcre_extra* m_sd; ++ pcre2_code* m_re; ++ pcre2_match_context* m_ctxt; + static const int OVECCOUNT=(m_MaxNumOfBackrefrences + 1) * 3; + unsigned int m_offset; +- int m_iOvector[OVECCOUNT]; ++ PCRE2_SIZE* m_iOvector; + utf8Mode m_utf8Mode; + int m_iMatchCount; +- int m_iOptions; ++ uint32_t m_iOptions; + bool m_jitCompiled; + bool m_bMatched; +- PCRE::pcre_jit_stack* m_jitStack; ++ pcre2_jit_stack* m_jitStack; + std::string m_subject; + std::string m_pattern; + static int m_Utf8Supported; +--- kodi-20.2+dfsg.orig/xbmc/filesystem/FTPParse.cpp ++++ kodi-20.2+dfsg/xbmc/filesystem/FTPParse.cpp +@@ -9,8 +9,10 @@ + #include "FTPParse.h" + + #include <cmath> ++#include <cstring> + +-#include <pcrecpp.h> ++#define PCRE2_CODE_UNIT_WIDTH 8 ++#include <pcre2.h> + + CFTPParse::CFTPParse() + { +@@ -46,26 +48,31 @@ + + void CFTPParse::setTime(const std::string& str) + { ++ pcre2_code *re, *unix_re, *multinet_re, *msdos_re; ++ pcre2_match_data *md; ++ PCRE2_SPTR unix_pat, multinet_pat, msdos_pat, str_sptr; ++ PCRE2_SIZE offset; ++ int err; + /* Variables used to capture patterns via the regexes */ +- std::string month; +- std::string day; +- std::string year; +- std::string hour; +- std::string minute; +- std::string second; +- std::string am_or_pm; ++ char *month = NULL; ++ PCRE2_UCHAR *day = NULL; ++ PCRE2_UCHAR *year = NULL; ++ PCRE2_UCHAR *hour = NULL; ++ PCRE2_UCHAR *minute = NULL; ++ PCRE2_UCHAR *second = NULL; ++ PCRE2_UCHAR *am_or_pm = NULL; + + /* time struct used to set the time_t variable */ + struct tm time_struct = {}; + + /* Regex to read Unix, NetWare and NetPresenz time format */ +- pcrecpp::RE unix_re("^([A-Za-z]{3})" // month ++ unix_pat = reinterpret_cast<PCRE2_SPTR>("^([A-Za-z]{3})" // month + "\\s+(\\d{1,2})" // day of month + "\\s+([:\\d]{4,5})$" // time of day or year + ); + + /* Regex to read MultiNet time format */ +- pcrecpp::RE multinet_re("^(\\d{1,2})" // day of month ++ multinet_pat = reinterpret_cast<PCRE2_SPTR>("^(\\d{1,2})" // day of month + "-([A-Za-z]{3})" // month + "-(\\d{4})" // year + "\\s+(\\d{2})" // hour +@@ -74,7 +81,7 @@ + ); + + /* Regex to read MSDOS time format */ +- pcrecpp::RE msdos_re("^(\\d{2})" // month ++ msdos_pat = reinterpret_cast<PCRE2_SPTR>("^(\\d{2})" // month + "-(\\d{2})" // day of month + "-(\\d{2})" // year + "\\s+(\\d{2})" // hour +@@ -82,48 +89,53 @@ + "([AP]M)$" // AM or PM + ); + +- if (unix_re.FullMatch(str, &month, &day, &year)) +- { ++ unix_re = pcre2_compile(unix_pat, PCRE2_ZERO_TERMINATED, ++ 0, &err, &offset, NULL); ++ multinet_re = pcre2_compile(multinet_pat, PCRE2_ZERO_TERMINATED, ++ 0, &err, &offset, NULL); ++ msdos_re = pcre2_compile(msdos_pat, PCRE2_ZERO_TERMINATED, ++ 0, &err, &offset, NULL); ++ str_sptr = reinterpret_cast<PCRE2_SPTR>(str.c_str()); ++ md = pcre2_match_data_create(30, NULL); ++ ++ if (pcre2_match(unix_re, str_sptr, PCRE2_ZERO_TERMINATED, 0, 0, md, NULL) ++ > 0) ++ { ++ pcre2_substring_get_bynumber(md, 1, ++ reinterpret_cast<PCRE2_UCHAR **>(&month), ++ &offset); ++ pcre2_substring_get_bynumber(md, 2, &day, &offset); ++ pcre2_substring_get_bynumber(md, 3, &year, &offset); ++ re = pcre2_compile(reinterpret_cast<PCRE2_SPTR>("(\\d{2}):(\\d{2})"), ++ PCRE2_ZERO_TERMINATED, 0, &err, &offset, NULL); + /* set the month */ +- if (pcrecpp::RE("jan", +- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month)) ++ if (strcasestr(month, "jan")) + time_struct.tm_mon = 0; +- else if (pcrecpp::RE("feb", +- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month)) ++ else if (strcasestr(month, "feb")) + time_struct.tm_mon = 1; +- else if (pcrecpp::RE("mar", +- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month)) ++ else if (strcasestr(month, "mar")) + time_struct.tm_mon = 2; +- else if (pcrecpp::RE("apr", +- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month)) ++ else if (strcasestr(month, "apr")) + time_struct.tm_mon = 3; +- else if (pcrecpp::RE("may", +- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month)) ++ else if (strcasestr(month, "may")) + time_struct.tm_mon = 4; +- else if (pcrecpp::RE("jun", +- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month)) ++ else if (strcasestr(month, "jun")) + time_struct.tm_mon = 5; +- else if (pcrecpp::RE("jul", +- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month)) ++ else if (strcasestr(month, "jul")) + time_struct.tm_mon = 6; +- else if (pcrecpp::RE("aug", +- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month)) ++ else if (strcasestr(month, "aug")) + time_struct.tm_mon = 7; +- else if (pcrecpp::RE("sep", +- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month)) ++ else if (strcasestr(month, "sep")) + time_struct.tm_mon = 8; +- else if (pcrecpp::RE("oct", +- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month)) ++ else if (strcasestr(month, "oct")) + time_struct.tm_mon = 9; +- else if (pcrecpp::RE("nov", +- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month)) ++ else if (strcasestr(month, "nov")) + time_struct.tm_mon = 10; +- else if (pcrecpp::RE("dec", +- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month)) ++ else if (strcasestr(month, "dec")) + time_struct.tm_mon = 11; + + /* set the day of the month */ +- time_struct.tm_mday = atoi(day.c_str()); ++ time_struct.tm_mday = atoi(reinterpret_cast<const char *>(day)); + + time_t t = time(NULL); + struct tm *current_time; +@@ -133,11 +145,14 @@ + #else + current_time = localtime(&t); + #endif +- if (pcrecpp::RE("(\\d{2}):(\\d{2})").FullMatch(year, &hour, &minute)) ++ if (pcre2_match(re, reinterpret_cast<PCRE2_SPTR>(year), ++ PCRE2_ZERO_TERMINATED, 0, 0, md, NULL) > 0) + { ++ pcre2_substring_get_bynumber(md, 1, &hour, &offset); ++ pcre2_substring_get_bynumber(md, 2, &minute, &offset); + /* set the hour and minute */ +- time_struct.tm_hour = atoi(hour.c_str()); +- time_struct.tm_min = atoi(minute.c_str()); ++ time_struct.tm_hour = atoi(reinterpret_cast<const char *>(hour)); ++ time_struct.tm_min = atoi(reinterpret_cast<const char *>(minute)); + + /* set the year */ + if ((current_time->tm_mon - time_struct.tm_mon < 0) || +@@ -150,93 +165,99 @@ + else + { + /* set the year */ +- time_struct.tm_year = atoi(year.c_str()) - 1900; ++ time_struct.tm_year = atoi(reinterpret_cast<const char *>(year)) - 1900; + } + + /* set the day of the week */ + time_struct.tm_wday = getDayOfWeek(time_struct.tm_mon + 1, + time_struct.tm_mday, + time_struct.tm_year + 1900); ++ pcre2_code_free(re); + } +- else if (multinet_re.FullMatch(str, &day, &month, &year, +- &hour, &minute, (void*)NULL, &second)) ++ else if (pcre2_match(multinet_re, str_sptr, PCRE2_ZERO_TERMINATED, ++ 0, 0, md, NULL) > 0) + { ++ pcre2_substring_get_bynumber(md, 1, &day, &offset); ++ pcre2_substring_get_bynumber(md, 2, ++ reinterpret_cast<PCRE2_UCHAR **>(&month), ++ &offset); ++ pcre2_substring_get_bynumber(md, 3, &year, &offset); ++ pcre2_substring_get_bynumber(md, 4, &hour, &offset); ++ pcre2_substring_get_bynumber(md, 5, &minute, &offset); ++ pcre2_substring_get_bynumber(md, 7, &second, &offset); + /* set the month */ +- if (pcrecpp::RE("jan", +- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month)) ++ if (strcasestr(month, "jan")) + time_struct.tm_mon = 0; +- else if (pcrecpp::RE("feb", +- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month)) ++ else if (strcasestr(month, "feb")) + time_struct.tm_mon = 1; +- else if (pcrecpp::RE("mar", +- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month)) ++ else if (strcasestr(month, "mar")) + time_struct.tm_mon = 2; +- else if (pcrecpp::RE("apr", +- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month)) ++ else if (strcasestr(month, "apr")) + time_struct.tm_mon = 3; +- else if (pcrecpp::RE("may", +- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month)) ++ else if (strcasestr(month, "may")) + time_struct.tm_mon = 4; +- else if (pcrecpp::RE("jun", +- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month)) ++ else if (strcasestr(month, "jun")) + time_struct.tm_mon = 5; +- else if (pcrecpp::RE("jul", +- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month)) ++ else if (strcasestr(month, "jul")) + time_struct.tm_mon = 6; +- else if (pcrecpp::RE("aug", +- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month)) ++ else if (strcasestr(month, "aug")) + time_struct.tm_mon = 7; +- else if (pcrecpp::RE("sep", +- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month)) ++ else if (strcasestr(month, "sep")) + time_struct.tm_mon = 8; +- else if (pcrecpp::RE("oct", +- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month)) ++ else if (strcasestr(month, "oct")) + time_struct.tm_mon = 9; +- else if (pcrecpp::RE("nov", +- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month)) ++ else if (strcasestr(month, "nov")) + time_struct.tm_mon = 10; +- else if (pcrecpp::RE("dec", +- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month)) ++ else if (strcasestr(month, "dec")) + time_struct.tm_mon = 11; + + /* set the day of the month and year */ +- time_struct.tm_mday = atoi(day.c_str()); +- time_struct.tm_year = atoi(year.c_str()) - 1900; ++ time_struct.tm_mday = atoi(reinterpret_cast<const char *>(day)); ++ time_struct.tm_year = atoi(reinterpret_cast<const char *>(year)) - 1900; + + /* set the hour and minute */ +- time_struct.tm_hour = atoi(hour.c_str()); +- time_struct.tm_min = atoi(minute.c_str()); ++ time_struct.tm_hour = atoi(reinterpret_cast<const char *>(hour)); ++ time_struct.tm_min = atoi(reinterpret_cast<const char *>(minute)); + + /* set the second if given*/ +- if (second.length() > 0) +- time_struct.tm_sec = atoi(second.c_str()); ++ if (strlen(reinterpret_cast<const char *>(second)) > 0) ++ time_struct.tm_sec = atoi(reinterpret_cast<const char *>(second)); + + /* set the day of the week */ + time_struct.tm_wday = getDayOfWeek(time_struct.tm_mon + 1, + time_struct.tm_mday, + time_struct.tm_year + 1900); + } +- else if (msdos_re.FullMatch(str, &month, &day, +- &year, &hour, &minute, &am_or_pm)) ++ else if (pcre2_match(msdos_re, str_sptr, PCRE2_ZERO_TERMINATED, ++ 0, 0, md, NULL) > 0) + { ++ pcre2_substring_get_bynumber(md, 1, ++ reinterpret_cast<PCRE2_UCHAR **>(&month), ++ &offset); ++ pcre2_substring_get_bynumber(md, 2, &day, &offset); ++ pcre2_substring_get_bynumber(md, 3, &year, &offset); ++ pcre2_substring_get_bynumber(md, 4, &hour, &offset); ++ pcre2_substring_get_bynumber(md, 5, &minute, &offset); ++ pcre2_substring_get_bynumber(md, 6, &am_or_pm, &offset); ++ + /* set the month and the day of the month */ +- time_struct.tm_mon = atoi(month.c_str()) - 1; +- time_struct.tm_mday = atoi(day.c_str()); ++ time_struct.tm_mon = atoi(month) - 1; ++ time_struct.tm_mday = atoi(reinterpret_cast<const char *>(day)); + + /* set the year */ +- time_struct.tm_year = atoi(year.c_str()); ++ time_struct.tm_year = atoi(reinterpret_cast<const char *>(year)); + if (time_struct.tm_year < 70) + time_struct.tm_year += 100; + + /* set the hour */ +- time_struct.tm_hour = atoi(hour.c_str()); ++ time_struct.tm_hour = atoi(reinterpret_cast<const char *>(hour)); + if (time_struct.tm_hour == 12) + time_struct.tm_hour -= 12; +- if (pcrecpp::RE("PM").FullMatch(am_or_pm)) ++ if (strstr(reinterpret_cast<const char *>(am_or_pm), "PM")) + time_struct.tm_hour += 12; + + /* set the minute */ +- time_struct.tm_min = atoi(minute.c_str()); ++ time_struct.tm_min = atoi(reinterpret_cast<const char *>(minute)); + + /* set the day of the week */ + time_struct.tm_wday = getDayOfWeek(time_struct.tm_mon + 1, +@@ -246,6 +267,18 @@ + + /* now set m_time */ + m_time = mktime(&time_struct); ++ ++ pcre2_code_free(unix_re); ++ pcre2_code_free(multinet_re); ++ pcre2_code_free(msdos_re); ++ pcre2_match_data_free(md); ++ pcre2_substring_free(reinterpret_cast<PCRE2_UCHAR *>(month)); ++ pcre2_substring_free(day); ++ pcre2_substring_free(year); ++ pcre2_substring_free(hour); ++ pcre2_substring_free(minute); ++ pcre2_substring_free(second); ++ pcre2_substring_free(am_or_pm); + } + + int CFTPParse::getDayOfWeek(int month, int date, int year) +@@ -325,22 +358,22 @@ + + int CFTPParse::FTPParse(const std::string& str) + { ++ pcre2_code *unix_re, *netware_re, *netpresenz_re, *eplf_re, *multinet_re, ++ *msdos_re; ++ pcre2_match_data *md; ++ PCRE2_SPTR unix_pat, netware_pat, netpresenz_pat, eplf_pat, multinet_pat, ++ msdos_pat, str_sptr; ++ PCRE2_SIZE offset; ++ int err; + /* Various variable to capture patterns via the regexes */ +- std::string permissions; +- std::string link_count; +- std::string owner; +- std::string group; +- std::string size; +- std::string date; +- std::string name; +- std::string type; +- std::string stuff; +- std::string facts; +- std::string version; +- std::string file_id; ++ char *type = NULL; ++ PCRE2_UCHAR *size = NULL; ++ PCRE2_UCHAR *date = NULL; ++ PCRE2_UCHAR *name = NULL; ++ PCRE2_UCHAR *facts; + + /* Regex for standard Unix listing formats */ +- pcrecpp::RE unix_re("^([-bcdlps])" // type ++ unix_pat = reinterpret_cast<PCRE2_SPTR>("^([-bcdlps])" // type + "([-rwxXsStT]{9})" // permissions + "\\s+(\\d+)" // hard link count + "\\s+(\\w+)" // owner +@@ -352,7 +385,7 @@ + + /* Regex for NetWare listing formats */ + /* See http://www.novell.com/documentation/oes/ftp_enu/data/a3ep22p.html#fbhbaijf */ +- pcrecpp::RE netware_re("^([-d])" // type ++ netware_pat = reinterpret_cast<PCRE2_SPTR>("^([-d])" // type + "\\s+(\\[[-SRWCIEMFA]{8}\\])" // rights + "\\s+(\\w+)" // owner + "\\s+(\\d+)" // size +@@ -363,7 +396,7 @@ + /* Regex for NetPresenz */ + /* See http://files.stairways.com/other/ftp-list-specs-info.txt */ + /* Here we will capture permissions and size if given */ +- pcrecpp::RE netpresenz_re("^([-dl])" // type ++ netpresenz_pat = reinterpret_cast<PCRE2_SPTR>("^([-dl])" // type + "([-rwx]{9}|)" // permissions + "\\s+(.*)" // stuff + "\\s+(\\d+|)" // size +@@ -374,7 +407,7 @@ + /* Regex for EPLF */ + /* See http://cr.yp.to/ftp/list/eplf.html */ + /* SAVE: "(/,|r,|s\\d+,|m\\d+,|i[\\d!#@$%^&*()]+(\\.[\\d!#@$%^&*()]+|),)+" */ +- pcrecpp::RE eplf_re("^\\+" // initial "plus" sign ++ eplf_pat = reinterpret_cast<PCRE2_SPTR>("^\\+" // initial "plus" sign + "([^\\s]+)" // facts + "\\s(.+)$" // name + ); +@@ -382,7 +415,7 @@ + /* Regex for MultiNet */ + /* Best documentation found was + * http://www-sld.slac.stanford.edu/SLDWWW/workbook/vms_files.html */ +- pcrecpp::RE multinet_re("^([^;]+)" // name ++ multinet_pat = reinterpret_cast<PCRE2_SPTR>("^([^;]+)" // name + ";(\\d+)" // version + "\\s+([\\d/]+)" // file id + "\\s+(\\d{1,2}-[A-Za-z]{3}-\\d{4}\\s+\\d{2}:\\d{2}(:\\d{2})?)" // date +@@ -391,20 +424,42 @@ + ); + + /* Regex for MSDOS */ +- pcrecpp::RE msdos_re("^(\\d{2}-\\d{2}-\\d{2}\\s+\\d{2}:\\d{2}[AP]M)" // date ++ msdos_pat = reinterpret_cast<PCRE2_SPTR>("^(\\d{2}-\\d{2}-\\d{2}\\s+\\d{2}:\\d{2}[AP]M)" // date + "\\s+(<DIR>|[\\d]+)" // dir or size + "\\s+(.+)$" // name + ); + +- if (unix_re.FullMatch(str, &type, &permissions, &link_count, &owner, &group, &size, &date, &name)) +- { +- m_name = name; +- m_size = (uint64_t)strtod(size.c_str(), NULL); +- if (pcrecpp::RE("d").FullMatch(type)) ++ unix_re = pcre2_compile(unix_pat, PCRE2_ZERO_TERMINATED, ++ 0, &err, &offset, NULL); ++ netware_re = pcre2_compile(netware_pat, PCRE2_ZERO_TERMINATED, ++ 0, &err, &offset, NULL); ++ netpresenz_re = pcre2_compile(netpresenz_pat, PCRE2_ZERO_TERMINATED, ++ 0, &err, &offset, NULL); ++ eplf_re = pcre2_compile(eplf_pat, PCRE2_ZERO_TERMINATED, ++ 0, &err, &offset, NULL); ++ multinet_re = pcre2_compile(multinet_pat, PCRE2_ZERO_TERMINATED, ++ 0, &err, &offset, NULL); ++ msdos_re = pcre2_compile(msdos_pat, PCRE2_ZERO_TERMINATED, ++ 0, &err, &offset, NULL); ++ md = pcre2_match_data_create(30, NULL); ++ str_sptr = reinterpret_cast<PCRE2_SPTR>(str.c_str()); ++ ++ if (pcre2_match(unix_re, str_sptr, PCRE2_ZERO_TERMINATED, 0, 0, md, NULL) ++ > 0) ++ { ++ pcre2_substring_get_bynumber(md, 1, ++ reinterpret_cast<PCRE2_UCHAR **>(&type), ++ &offset); ++ pcre2_substring_get_bynumber(md, 6, &size, &offset); ++ pcre2_substring_get_bynumber(md, 7, &date, &offset); ++ pcre2_substring_get_bynumber(md, 8, &name, &offset); ++ m_name = reinterpret_cast<const char *>(name); ++ m_size = (uint64_t)strtod(reinterpret_cast<const char *>(size), NULL); ++ if (strstr(type, "d")) + m_flagtrycwd = 1; +- if (pcrecpp::RE("-").FullMatch(type)) ++ if (strstr(type, "-")) + m_flagtryretr = 1; +- if (pcrecpp::RE("l").FullMatch(type)) ++ if (strstr(type, "l")) + { + m_flagtrycwd = m_flagtryretr = 1; + // handle symlink +@@ -412,31 +467,67 @@ + if (found != std::string::npos) + m_name = m_name.substr(0, found); + } +- setTime(date); ++ setTime(reinterpret_cast<const char *>(date)); ++ pcre2_substring_free(reinterpret_cast<PCRE2_UCHAR *>(type)); ++ pcre2_substring_free(size); ++ pcre2_substring_free(date); ++ pcre2_substring_free(name); ++ pcre2_match_data_free(md); ++ pcre2_code_free(unix_re); ++ pcre2_code_free(netware_re); ++ pcre2_code_free(netpresenz_re); ++ pcre2_code_free(eplf_re); ++ pcre2_code_free(multinet_re); ++ pcre2_code_free(msdos_re); + + return 1; + } +- if (netware_re.FullMatch(str, &type, &permissions, &owner, &size, &date, &name)) ++ if (pcre2_match(netware_re, str_sptr, PCRE2_ZERO_TERMINATED, 0, 0, md, NULL) ++ > 0) + { +- m_name = name; +- m_size = (uint64_t)strtod(size.c_str(), NULL); +- if (pcrecpp::RE("d").FullMatch(type)) ++ pcre2_substring_get_bynumber(md, 1, ++ reinterpret_cast<PCRE2_UCHAR **>(&type), ++ &offset); ++ pcre2_substring_get_bynumber(md, 4, &size, &offset); ++ pcre2_substring_get_bynumber(md, 5, &date, &offset); ++ pcre2_substring_get_bynumber(md, 6, &name, &offset); ++ m_name = reinterpret_cast<const char *>(name); ++ m_size = (uint64_t)strtod(reinterpret_cast<const char *>(size), NULL); ++ if (strstr(type, "d")) + m_flagtrycwd = 1; +- if (pcrecpp::RE("-").FullMatch(type)) ++ if (strstr(type, "-")) + m_flagtryretr = 1; +- setTime(date); ++ setTime(reinterpret_cast<const char *>(date)); ++ pcre2_substring_free(reinterpret_cast<PCRE2_UCHAR *>(type)); ++ pcre2_substring_free(size); ++ pcre2_substring_free(date); ++ pcre2_substring_free(name); ++ pcre2_match_data_free(md); ++ pcre2_code_free(unix_re); ++ pcre2_code_free(netware_re); ++ pcre2_code_free(netpresenz_re); ++ pcre2_code_free(eplf_re); ++ pcre2_code_free(multinet_re); ++ pcre2_code_free(msdos_re); + + return 1; + } +- if (netpresenz_re.FullMatch(str, &type, &permissions, &stuff, &size, &date, &name)) ++ if (pcre2_match(netpresenz_re, str_sptr, PCRE2_ZERO_TERMINATED, ++ 0, 0, md, NULL) > 0) + { +- m_name = name; +- m_size = (uint64_t)strtod(size.c_str(), NULL); +- if (pcrecpp::RE("d").FullMatch(type)) ++ pcre2_substring_get_bynumber(md, 1, ++ reinterpret_cast<PCRE2_UCHAR **>(&type), ++ &offset); ++ pcre2_substring_get_bynumber(md, 4, &size, &offset); ++ pcre2_substring_get_bynumber(md, 5, &date, &offset); ++ pcre2_substring_get_bynumber(md, 6, &name, &offset); ++ m_name = reinterpret_cast<const char *>(name); ++ m_size = (uint64_t)strtod(reinterpret_cast<const char *>(size), NULL); ++ if (strstr(type, "d")) + m_flagtrycwd = 1; +- if (pcrecpp::RE("-").FullMatch(type)) ++ if (strstr(type, "-")) + m_flagtryretr = 1; +- if (pcrecpp::RE("l").FullMatch(type)) ++ if (strstr(type, "l")) + { + m_flagtrycwd = m_flagtryretr = 1; + // handle symlink +@@ -444,48 +535,118 @@ + if (found != std::string::npos) + m_name = m_name.substr(0, found); + } +- setTime(date); ++ setTime(reinterpret_cast<const char *>(date)); ++ pcre2_substring_free(reinterpret_cast<PCRE2_UCHAR *>(type)); ++ pcre2_substring_free(size); ++ pcre2_substring_free(date); ++ pcre2_substring_free(name); ++ pcre2_match_data_free(md); ++ pcre2_code_free(unix_re); ++ pcre2_code_free(netware_re); ++ pcre2_code_free(netpresenz_re); ++ pcre2_code_free(eplf_re); ++ pcre2_code_free(multinet_re); ++ pcre2_code_free(msdos_re); + + return 1; + } +- if (eplf_re.FullMatch(str, &facts, &name)) ++ if (pcre2_match(eplf_re, str_sptr, PCRE2_ZERO_TERMINATED, 0, 0, md, NULL) ++ > 0) + { ++ pcre2_code *re; ++ ++ pcre2_substring_get_bynumber(md, 1, &facts, &offset); ++ pcre2_substring_get_bynumber(md, 2, &name, &offset); + /* Get the type, size, and date from the facts */ +- pcrecpp::RE("(\\+|,)(r|/),").PartialMatch(facts, (void*)NULL, &type); +- pcrecpp::RE("(\\+|,)s(\\d+),").PartialMatch(facts, (void*)NULL, &size); +- pcrecpp::RE("(\\+|,)m(\\d+),").PartialMatch(facts, (void*)NULL, &date); +- +- m_name = name; +- m_size = (uint64_t)strtod(size.c_str(), NULL); +- if (pcrecpp::RE("/").FullMatch(type)) ++ re = pcre2_compile(reinterpret_cast<PCRE2_SPTR>("(\\+|,)(r|/),"), ++ PCRE2_ZERO_TERMINATED, 0, &err, &offset, NULL); ++ if (pcre2_match(re, facts, PCRE2_ZERO_TERMINATED, 0, ++ PCRE2_PARTIAL_SOFT, md, NULL) > 0) ++ pcre2_substring_get_bynumber(md, 2, ++ reinterpret_cast<PCRE2_UCHAR **>(&type), ++ &offset); ++ pcre2_code_free(re); ++ re = pcre2_compile(reinterpret_cast<PCRE2_SPTR>("(\\+|,)s(\\d+),"), ++ PCRE2_ZERO_TERMINATED, 0, &err, &offset, NULL); ++ if (pcre2_match(re, facts, PCRE2_ZERO_TERMINATED, 0, ++ PCRE2_PARTIAL_SOFT, md, NULL) > 0) ++ pcre2_substring_get_bynumber(md, 2, &size, &offset); ++ pcre2_code_free(re); ++ re = pcre2_compile(reinterpret_cast<PCRE2_SPTR>("(\\+|,)m(\\d+),"), ++ PCRE2_ZERO_TERMINATED, 0, &err, &offset, NULL); ++ if (pcre2_match(re, facts, PCRE2_ZERO_TERMINATED, 0, ++ PCRE2_PARTIAL_SOFT, md, NULL) > 0) ++ pcre2_substring_get_bynumber(md, 2, &date, &offset); ++ pcre2_code_free(re); ++ pcre2_substring_free(facts); ++ ++ m_name = reinterpret_cast<const char *>(name); ++ m_size = (uint64_t)strtod(reinterpret_cast<const char *>(size), NULL); ++ if (strstr(type, "/")) + m_flagtrycwd = 1; +- if (pcrecpp::RE("r").FullMatch(type)) ++ if (strstr(type, "r")) + m_flagtryretr = 1; + /* eplf stores the date in time_t format already */ +- m_time = atoi(date.c_str()); ++ m_time = atoi(reinterpret_cast<const char *>(date)); ++ pcre2_substring_free(reinterpret_cast<PCRE2_UCHAR *>(type)); ++ pcre2_substring_free(size); ++ pcre2_substring_free(date); ++ pcre2_substring_free(name); ++ pcre2_match_data_free(md); ++ pcre2_code_free(unix_re); ++ pcre2_code_free(netware_re); ++ pcre2_code_free(netpresenz_re); ++ pcre2_code_free(eplf_re); ++ pcre2_code_free(multinet_re); ++ pcre2_code_free(msdos_re); + + return 1; + } +- if (multinet_re.FullMatch(str, &name, &version, &file_id, &date, (void*)NULL, &owner, &permissions)) ++ if (pcre2_match(multinet_re, str_sptr, PCRE2_ZERO_TERMINATED, 0, 0, md, NULL) ++ > 0) + { +- if (pcrecpp::RE("\\.DIR$").PartialMatch(name)) ++ pcre2_code *re; ++ std::string tmp; ++ ++ pcre2_substring_get_bynumber(md, 1, &name, &offset); ++ pcre2_substring_get_bynumber(md, 4, &date, &offset); ++ re = pcre2_compile(reinterpret_cast<PCRE2_SPTR>("\\.DIR$"), ++ PCRE2_ZERO_TERMINATED, 0, &err, &offset, NULL); ++ //if (pcrecpp::RE("\\.DIR$").PartialMatch(name)) ++ tmp = reinterpret_cast<const char *>(name); ++ if (pcre2_match(re, name, PCRE2_ZERO_TERMINATED, 0, PCRE2_PARTIAL_SOFT, ++ md, NULL) > 0) + { +- name.resize(name.size() - 4); ++ tmp.resize(tmp.size() - 4); + m_flagtrycwd = 1; + } + else + m_flagtryretr = 1; +- m_name = name; +- setTime(date); ++ m_name = tmp; ++ setTime(reinterpret_cast<const char *>(date)); + /* Multinet doesn't provide a size */ + m_size = 0; ++ pcre2_substring_free(date); ++ pcre2_substring_free(name); ++ pcre2_match_data_free(md); ++ pcre2_code_free(re); ++ pcre2_code_free(unix_re); ++ pcre2_code_free(netware_re); ++ pcre2_code_free(netpresenz_re); ++ pcre2_code_free(eplf_re); ++ pcre2_code_free(multinet_re); ++ pcre2_code_free(msdos_re); + + return 1; + } +- if (msdos_re.FullMatch(str, &date, &size, &name)) ++ if (pcre2_match(msdos_re, str_sptr, PCRE2_ZERO_TERMINATED, 0, 0, md, NULL) ++ > 0) + { +- m_name = name; +- if (pcrecpp::RE("<DIR>").FullMatch(size)) ++ pcre2_substring_get_bynumber(md, 1, &date, &offset); ++ pcre2_substring_get_bynumber(md, 2, &size, &offset); ++ pcre2_substring_get_bynumber(md, 3, &name, &offset); ++ m_name = reinterpret_cast<const char *>(name); ++ if (strstr(reinterpret_cast<const char *>(size), "<DIR>")) + { + m_flagtrycwd = 1; + m_size = 0; +@@ -493,12 +654,29 @@ + else + { + m_flagtryretr = 1; +- m_size = (uint64_t)strtod(size.c_str(), NULL); ++ m_size = (uint64_t)strtod(reinterpret_cast<const char *>(size), NULL); + } +- setTime(date); ++ setTime(reinterpret_cast<const char *>(date)); ++ pcre2_substring_free(date); ++ pcre2_substring_free(size); ++ pcre2_substring_free(name); ++ pcre2_match_data_free(md); ++ pcre2_code_free(unix_re); ++ pcre2_code_free(netware_re); ++ pcre2_code_free(netpresenz_re); ++ pcre2_code_free(eplf_re); ++ pcre2_code_free(multinet_re); ++ pcre2_code_free(msdos_re); + + return 1; + } ++ pcre2_match_data_free(md); ++ pcre2_code_free(unix_re); ++ pcre2_code_free(netware_re); ++ pcre2_code_free(netpresenz_re); ++ pcre2_code_free(eplf_re); ++ pcre2_code_free(multinet_re); ++ pcre2_code_free(msdos_re); + + return 0; + } +--- kodi-20.2+dfsg.orig/xbmc/utils/RegExp.cpp ++++ kodi-20.2+dfsg/xbmc/utils/RegExp.cpp +@@ -16,27 +16,6 @@ + #include <stdlib.h> + #include <string.h> + +-using namespace PCRE; +- +-#ifndef PCRE_UCP +-#define PCRE_UCP 0 +-#endif // PCRE_UCP +- +-#ifdef PCRE_CONFIG_JIT +-#define PCRE_HAS_JIT_CODE 1 +-#endif +- +-#ifndef PCRE_STUDY_JIT_COMPILE +-#define PCRE_STUDY_JIT_COMPILE 0 +-#endif +-#ifndef PCRE_INFO_JIT +-// some unused number +-#define PCRE_INFO_JIT 2048 +-#endif +-#ifndef PCRE_HAS_JIT_CODE +-#define pcre_free_study(x) pcre_free((x)) +-#endif +- + int CRegExp::m_Utf8Supported = -1; + int CRegExp::m_UcpSupported = -1; + int CRegExp::m_JitSupported = -1; +@@ -51,25 +30,24 @@ + { + m_utf8Mode = utf8; + m_re = NULL; +- m_sd = NULL; +- m_iOptions = PCRE_DOTALL | PCRE_NEWLINE_ANY; ++ m_ctxt = NULL; ++ m_iOptions = PCRE2_DOTALL; + if(caseless) +- m_iOptions |= PCRE_CASELESS; ++ m_iOptions |= PCRE2_CASELESS; + if (m_utf8Mode == forceUtf8) + { + if (IsUtf8Supported()) +- m_iOptions |= PCRE_UTF8; ++ m_iOptions |= PCRE2_UTF; + if (AreUnicodePropertiesSupported()) +- m_iOptions |= PCRE_UCP; ++ m_iOptions |= PCRE2_UCP; + } + + m_offset = 0; + m_jitCompiled = false; + m_bMatched = false; + m_iMatchCount = 0; ++ m_iOvector = NULL; + m_jitStack = NULL; +- +- memset(m_iOvector, 0, sizeof(m_iOvector)); + } + + CRegExp::CRegExp(bool caseless, CRegExp::utf8Mode utf8, const char *re, studyMode study /*= NoStudy*/) +@@ -225,7 +203,8 @@ + CRegExp::CRegExp(const CRegExp& re) + { + m_re = NULL; +- m_sd = NULL; ++ m_ctxt = NULL; ++ m_iOvector = NULL; + m_jitStack = NULL; + m_utf8Mode = re.m_utf8Mode; + m_iOptions = re.m_iOptions; +@@ -240,12 +219,13 @@ + m_pattern = re.m_pattern; + if (re.m_re) + { +- if (pcre_fullinfo(re.m_re, NULL, PCRE_INFO_SIZE, &size) >= 0) ++ if (pcre2_pattern_info(re.m_re, PCRE2_INFO_SIZE, &size) >= 0) + { +- if ((m_re = (pcre*)malloc(size))) ++ if ((m_re = pcre2_code_copy(re.m_re))) + { +- memcpy(m_re, re.m_re, size); +- memcpy(m_iOvector, re.m_iOvector, OVECCOUNT*sizeof(int)); ++ if (re.m_ctxt) ++ m_ctxt = pcre2_match_context_copy(re.m_ctxt); ++ m_iOvector = re.m_iOvector; + m_offset = re.m_offset; + m_iMatchCount = re.m_iMatchCount; + m_bMatched = re.m_bMatched; +@@ -273,18 +253,28 @@ + m_jitCompiled = false; + m_bMatched = false; + m_iMatchCount = 0; +- const char *errMsg = NULL; +- int errOffset = 0; +- int options = m_iOptions; ++ pcre2_compile_context *ctxt; ++ int errCode; ++ char errMsg[120]; ++ PCRE2_SIZE errOffset; ++ uint32_t options = m_iOptions; + if (m_utf8Mode == autoUtf8 && requireUtf8(re)) +- options |= (IsUtf8Supported() ? PCRE_UTF8 : 0) | (AreUnicodePropertiesSupported() ? PCRE_UCP : 0); ++ options |= (IsUtf8Supported() ? PCRE2_UTF : 0) | (AreUnicodePropertiesSupported() ? PCRE2_UCP : 0); + + Cleanup(); + +- m_re = pcre_compile(re, options, &errMsg, &errOffset, NULL); ++ ctxt = pcre2_compile_context_create(NULL); ++ pcre2_set_newline(ctxt, PCRE2_NEWLINE_ANY); ++ m_re = pcre2_compile(reinterpret_cast<PCRE2_SPTR>(re), ++ PCRE2_ZERO_TERMINATED, options, ++ &errCode, &errOffset, ctxt); ++ pcre2_compile_context_free(ctxt); ++ + if (!m_re) + { + m_pattern.clear(); ++ pcre2_get_error_message(errCode, reinterpret_cast<PCRE2_UCHAR *>(errMsg), ++ sizeof(errMsg)); + CLog::Log(LOGERROR, "PCRE: {}. Compilation failed at offset {} in expression '{}'", errMsg, + errOffset, re); + return false; +@@ -295,23 +285,12 @@ + if (study) + { + const bool jitCompile = (study == StudyWithJitComp) && IsJitSupported(); +- const int studyOptions = jitCompile ? PCRE_STUDY_JIT_COMPILE : 0; + +- m_sd = pcre_study(m_re, studyOptions, &errMsg); +- if (errMsg != NULL) +- { +- CLog::Log(LOGWARNING, "{}: PCRE error \"{}\" while studying expression", __FUNCTION__, +- errMsg); +- if (m_sd != NULL) +- { +- pcre_free_study(m_sd); +- m_sd = NULL; +- } +- } +- else if (jitCompile) ++ if (jitCompile) + { +- int jitPresent = 0; +- m_jitCompiled = (pcre_fullinfo(m_re, m_sd, PCRE_INFO_JIT, &jitPresent) == 0 && jitPresent == 1); ++ pcre2_jit_compile(m_re, PCRE2_JIT_COMPLETE); ++ size_t jitPresent = 0; ++ m_jitCompiled = (pcre2_pattern_info(m_re, PCRE2_INFO_JITSIZE, &jitPresent) == 0 && jitPresent > 0); + } + } + +@@ -325,6 +304,9 @@ + + int CRegExp::PrivateRegFind(size_t bufferLen, const char *str, unsigned int startoffset /* = 0*/, int maxNumberOfCharsToTest /*= -1*/) + { ++ pcre2_match_data *md; ++ PCRE2_SIZE offset; ++ + m_offset = 0; + m_bMatched = false; + m_iMatchCount = 0; +@@ -347,37 +329,47 @@ + return -1; + } + +-#ifdef PCRE_HAS_JIT_CODE ++ if (!m_ctxt) ++ m_ctxt = pcre2_match_context_create(NULL); ++ + if (m_jitCompiled && !m_jitStack) + { +- m_jitStack = pcre_jit_stack_alloc(32*1024, 512*1024); ++ m_jitStack = pcre2_jit_stack_create(32*1024, 512*1024, NULL); + if (m_jitStack == NULL) + CLog::Log(LOGWARNING, "{}: can't allocate address space for JIT stack", __FUNCTION__); + +- pcre_assign_jit_stack(m_sd, NULL, m_jitStack); ++ pcre2_jit_stack_assign(m_ctxt, NULL, m_jitStack); + } +-#endif + + if (maxNumberOfCharsToTest >= 0) + bufferLen = std::min<size_t>(bufferLen, startoffset + maxNumberOfCharsToTest); + + m_subject.assign(str + startoffset, bufferLen - startoffset); +- int rc = pcre_exec(m_re, NULL, m_subject.c_str(), m_subject.length(), 0, 0, m_iOvector, OVECCOUNT); ++ md = pcre2_match_data_create(OVECCOUNT, NULL); ++ int rc = pcre2_match(m_re, ++ reinterpret_cast<PCRE2_SPTR>(m_subject.c_str()), ++ m_subject.length(), 0, 0, md, m_ctxt); ++ m_iOvector = pcre2_get_ovector_pointer(md); ++ offset = pcre2_get_startchar(md); ++ pcre2_match_data_free(md); + + if (rc<1) + { + static const int fragmentLen = 80; // length of excerpt before erroneous char for log + switch(rc) + { +- case PCRE_ERROR_NOMATCH: ++ case PCRE2_ERROR_NOMATCH: + return -1; + +- case PCRE_ERROR_MATCHLIMIT: ++ case PCRE2_ERROR_MATCHLIMIT: + CLog::Log(LOGERROR, "PCRE: Match limit reached"); + return -1; + +-#ifdef PCRE_ERROR_SHORTUTF8 +- case PCRE_ERROR_SHORTUTF8: ++ case PCRE2_ERROR_UTF8_ERR1: ++ case PCRE2_ERROR_UTF8_ERR2: ++ case PCRE2_ERROR_UTF8_ERR3: ++ case PCRE2_ERROR_UTF8_ERR4: ++ case PCRE2_ERROR_UTF8_ERR5: + { + const size_t startPos = (m_subject.length() > fragmentLen) ? CUtf8Utils::RFindValidUtf8Char(m_subject, m_subject.length() - fragmentLen) : 0; + if (startPos != std::string::npos) +@@ -389,22 +381,41 @@ + CLog::Log(LOGERROR, "PCRE: Bad UTF-8 character at the end of string"); + return -1; + } +-#endif +- case PCRE_ERROR_BADUTF8: ++ case PCRE2_ERROR_UTF8_ERR6: ++ case PCRE2_ERROR_UTF8_ERR7: ++ case PCRE2_ERROR_UTF8_ERR8: ++ case PCRE2_ERROR_UTF8_ERR9: ++ case PCRE2_ERROR_UTF8_ERR10: ++ case PCRE2_ERROR_UTF8_ERR11: ++ case PCRE2_ERROR_UTF8_ERR12: ++ case PCRE2_ERROR_UTF8_ERR13: ++ case PCRE2_ERROR_UTF8_ERR14: ++ case PCRE2_ERROR_UTF8_ERR15: ++ case PCRE2_ERROR_UTF8_ERR16: ++ case PCRE2_ERROR_UTF8_ERR17: ++ case PCRE2_ERROR_UTF8_ERR18: ++ case PCRE2_ERROR_UTF8_ERR19: ++ case PCRE2_ERROR_UTF8_ERR20: ++ case PCRE2_ERROR_UTF8_ERR21: + { ++ char errbuf[120]; ++ ++ pcre2_get_error_message(rc, ++ reinterpret_cast<PCRE2_UCHAR *>(errbuf), ++ sizeof(errbuf)); + const size_t startPos = (m_iOvector[0] > fragmentLen) ? CUtf8Utils::RFindValidUtf8Char(m_subject, m_iOvector[0] - fragmentLen) : 0; +- if (m_iOvector[0] >= 0 && startPos != std::string::npos) ++ if ((int)m_iOvector[0] >= 0 && startPos != std::string::npos) + CLog::Log(LOGERROR, + "PCRE: Bad UTF-8 character, error code: {}, position: {}. Text before bad " + "char: \"{}\"", +- m_iOvector[1], m_iOvector[0], ++ errbuf, offset, + m_subject.substr(startPos, m_iOvector[0] - startPos + 1)); + else + CLog::Log(LOGERROR, "PCRE: Bad UTF-8 character, error code: {}, position: {}", +- m_iOvector[1], m_iOvector[0]); ++ errbuf, offset); + return -1; + } +- case PCRE_ERROR_BADUTF8_OFFSET: ++ case PCRE2_ERROR_BADUTFOFFSET: + CLog::Log(LOGERROR, "PCRE: Offset is pointing to the middle of UTF-8 character"); + return -1; + +@@ -423,7 +434,7 @@ + { + int c = -1; + if (m_re) +- pcre_fullinfo(m_re, NULL, PCRE_INFO_CAPTURECOUNT, &c); ++ pcre2_pattern_info(m_re, PCRE2_INFO_CAPTURECOUNT, &c); + return c; + } + +@@ -524,7 +535,7 @@ + bool CRegExp::GetNamedSubPattern(const char* strName, std::string& strMatch) const + { + strMatch.clear(); +- int iSub = pcre_get_stringnumber(m_re, strName); ++ int iSub = pcre2_substring_number_from_name(m_re, reinterpret_cast<PCRE2_SPTR>(strName)); + if (!IsValidSubNumber(iSub)) + return false; + strMatch = GetMatch(iSub); +@@ -533,7 +544,7 @@ + + int CRegExp::GetNamedSubPatternNumber(const char* strName) const + { +- return pcre_get_stringnumber(m_re, strName); ++ return pcre2_substring_number_from_name(m_re, reinterpret_cast<PCRE2_SPTR>(strName)); + } + + void CRegExp::DumpOvector(int iLog /* = LOGDEBUG */) +@@ -558,23 +569,21 @@ + { + if (m_re) + { +- pcre_free(m_re); ++ pcre2_code_free(m_re); + m_re = NULL; + } + +- if (m_sd) ++ if (m_ctxt) + { +- pcre_free_study(m_sd); +- m_sd = NULL; ++ pcre2_match_context_free(m_ctxt); ++ m_ctxt = NULL; + } + +-#ifdef PCRE_HAS_JIT_CODE + if (m_jitStack) + { +- pcre_jit_stack_free(m_jitStack); ++ pcre2_jit_stack_free(m_jitStack); + m_jitStack = NULL; + } +-#endif + } + + inline bool CRegExp::IsValidSubNumber(int iSub) const +@@ -587,7 +596,7 @@ + { + if (m_Utf8Supported == -1) + { +- if (pcre_config(PCRE_CONFIG_UTF8, &m_Utf8Supported) != 0) ++ if (pcre2_config(PCRE2_CONFIG_UNICODE, &m_Utf8Supported) < 0) + m_Utf8Supported = 0; + } + +@@ -596,13 +605,11 @@ + + bool CRegExp::AreUnicodePropertiesSupported(void) + { +-#if defined(PCRE_CONFIG_UNICODE_PROPERTIES) && PCRE_UCP != 0 + if (m_UcpSupported == -1) + { +- if (pcre_config(PCRE_CONFIG_UNICODE_PROPERTIES, &m_UcpSupported) != 0) ++ if (pcre2_config(PCRE2_CONFIG_UNICODE, &m_UcpSupported) < 0) + m_UcpSupported = 0; + } +-#endif + + return m_UcpSupported == 1; + } +@@ -625,13 +632,13 @@ + + if (!utf8FullSupport) + { ++ char ver[24]; ++ ++ pcre2_config(PCRE2_CONFIG_VERSION, ver); + CLog::Log(LOGINFO, +- "Consider installing PCRE lib version 8.10 or later with enabled Unicode properties " ++ "Consider installing PCRE lib version 10.10 or later with enabled Unicode properties " + "and UTF-8 support. Your PCRE lib version: {}", +- PCRE::pcre_version()); +-#if PCRE_UCP == 0 +- CLog::Log(LOGINFO, "You will need to rebuild XBMC after PCRE lib update."); +-#endif ++ ver); + } + + return utf8FullSupport; +@@ -641,9 +648,7 @@ + { + if (m_JitSupported == -1) + { +-#ifdef PCRE_HAS_JIT_CODE +- if (pcre_config(PCRE_CONFIG_JIT, &m_JitSupported) != 0) +-#endif ++ if (pcre2_config(PCRE2_CONFIG_JIT, &m_JitSupported) < 0) + m_JitSupported = 0; + } + +--- kodi-20.2+dfsg.orig/xbmc/utils/test/TestRegExp.cpp ++++ kodi-20.2+dfsg/xbmc/utils/test/TestRegExp.cpp +@@ -30,6 +30,29 @@ + EXPECT_EQ(-1, regex.RegFind("Test string.")); + } + ++TEST(TestRegExp, InvalidPattern) ++{ ++ CRegExp regex; ++ ++ EXPECT_FALSE(regex.RegComp("+")); ++} ++ ++TEST(TestRegExp, Unicode) ++{ ++ CRegExp regex; ++ ++ EXPECT_TRUE(regex.RegComp("Бог!$")); ++ EXPECT_EQ(12, regex.RegFind("С нами Бог!")); ++} ++ ++TEST(TestRegExp, JIT) ++{ ++ CRegExp regex; ++ ++ EXPECT_TRUE(regex.RegComp(".JIT.", CRegExp::StudyWithJitComp)); ++ EXPECT_EQ(12, regex.RegFind("Test string, JIT-matched.")); ++} ++ + TEST(TestRegExp, GetReplaceString) + { + CRegExp regex; diff --git a/debian/patches/workarounds/0006-loongarch.patch b/debian/patches/workarounds/0006-loongarch.patch new file mode 100644 index 0000000..e028ae4 --- /dev/null +++ b/debian/patches/workarounds/0006-loongarch.patch @@ -0,0 +1,40 @@ +From 1c2c5150eb17f432a5d9ad81a97d999662a4e669 Mon Sep 17 00:00:00 2001 +From: Dandan Zhang <zhangdandan@loongson.cn> +Date: Tue, 24 Oct 2023 07:59:42 +0000 +Subject: [PATCH] Add LoongArch support to system info + +--- + xbmc/utils/SystemInfo.cpp | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/xbmc/utils/SystemInfo.cpp b/xbmc/utils/SystemInfo.cpp +index d1e53c41bb95e..92ef021efb158 100644 +--- a/xbmc/utils/SystemInfo.cpp ++++ b/xbmc/utils/SystemInfo.cpp +@@ -952,7 +952,7 @@ int CSysInfo::GetKernelBitness(void) + std::string machine(un.machine); + if (machine == "x86_64" || machine == "amd64" || machine == "arm64" || machine == "aarch64" || + machine == "ppc64" || machine == "ppc64el" || machine == "ppc64le" || machine == "ia64" || +- machine == "mips64" || machine == "s390x" || machine == "riscv64" || ++ machine == "loongarch64" || machine == "mips64" || machine == "s390x" || machine == "riscv64" || + machine == "sparc64" || machine == "alpha") + kernelBitness = 64; + else +@@ -1080,6 +1080,8 @@ const std::string& CSysInfo::GetKernelCpuFamily(void) + std::string machine(un.machine); + if (machine.compare(0, 3, "arm", 3) == 0 || machine.compare(0, 7, "aarch64", 7) == 0) + kernelCpuFamily = "ARM"; ++ else if (machine.compare(0, 9, "loongarch", 9) == 0 || machine.compare(0, 7, "loong64", 7) == 0) ++ kernelCpuFamily = "LoongArch"; + else if (machine.compare(0, 4, "mips", 4) == 0) + kernelCpuFamily = "MIPS"; + else if (machine.compare(0, 4, "i686", 4) == 0 || machine == "i386" || machine == "amd64" || machine.compare(0, 3, "x86", 3) == 0) +@@ -1466,6 +1468,8 @@ std::string CSysInfo::GetBuildTargetCpuFamily(void) + return "ARM (Thumb)"; + #elif defined(__arm__) || defined(_M_ARM) || defined (__aarch64__) + return "ARM"; ++#elif defined(__loongarch__) ++ return "LoongArch"; + #elif defined(__mips__) || defined(mips) || defined(__mips) + return "MIPS"; + #elif defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64) || \ diff --git a/debian/patches/workarounds/0007-swig.patch b/debian/patches/workarounds/0007-swig.patch new file mode 100644 index 0000000..94fbcf9 --- /dev/null +++ b/debian/patches/workarounds/0007-swig.patch @@ -0,0 +1,10 @@ +diff --git a/xbmc/interfaces/swig/AddonModuleXbmcaddon.i b/xbmc/interfaces/swig/AddonModuleXbmcaddon.i +index 6c00a1caa2..d38794c043 100644 +--- a/xbmc/interfaces/swig/AddonModuleXbmcaddon.i ++++ b/xbmc/interfaces/swig/AddonModuleXbmcaddon.i +@@ -33,5 +33,6 @@ using namespace xbmcaddon; + %include "interfaces/legacy/AddonString.h" + + %include "interfaces/legacy/Addon.h" ++%nodefaultctor Settings; + %include "interfaces/legacy/Settings.h" |