From 2b8c2cef3ec780170a007c5cf82d507198c5e6f3 Mon Sep 17 00:00:00 2001 From: CastagnaIT Date: Thu, 21 Sep 2023 10:43:48 +0200 Subject: [PATCH 1/3] [FileUtils] add GetAddonPath --- src/utils/FileUtils.cpp | 23 +++++++++++++++++++++++ src/utils/FileUtils.h | 6 ++++++ 2 files changed, 29 insertions(+) diff --git a/src/utils/FileUtils.cpp b/src/utils/FileUtils.cpp index e1ecf2fbf..a01ac988c 100644 --- a/src/utils/FileUtils.cpp +++ b/src/utils/FileUtils.cpp @@ -57,6 +57,29 @@ std::string UTILS::FILESYS::GetAddonUserPath() return kodi::addon::GetUserPath(); } +std::string UTILS::FILESYS::GetAddonPath() +{ + std::array searchPaths = { + kodi::vfs::TranslateSpecialProtocol("special://xbmcbinaddons/inputstream.adaptive/"), + kodi::vfs::TranslateSpecialProtocol("special://xbmcaltbinaddons/inputstream.adaptive/"), + kodi::addon::GetAddonInfo("path"), + }; + + for (auto searchPath : searchPaths) + { + std::vector items; + if (!kodi::vfs::DirectoryExists(searchPath) || !kodi::vfs::GetDirectory(searchPath, "", items)) + continue; + + for (auto item : items) + { + if (!item.IsFolder() && item.Label().find("inputstream.adaptive") != std::string::npos) + return searchPath; + } + } + return {}; +} + bool UTILS::FILESYS::CheckDuplicateFilePath(std::string& filePath, uint32_t filesLimit /* = 0 */) { const size_t extensionPos = filePath.rfind('.'); diff --git a/src/utils/FileUtils.h b/src/utils/FileUtils.h index a1ffeb55e..f667e9f4f 100644 --- a/src/utils/FileUtils.h +++ b/src/utils/FileUtils.h @@ -40,6 +40,12 @@ std::string PathCombine(std::string path, std::string filePath); */ std::string GetAddonUserPath(); +/*! + * \brief Get the data folder of the addon. + * \return The path. + */ +std::string GetAddonPath(); + /*! * \brief Check for duplicates for the file path, and change the filename * based on the number of duplicate files. From d81d87f0cd560206ab4f0c8d4289652b186535b9 Mon Sep 17 00:00:00 2001 From: CastagnaIT Date: Thu, 21 Sep 2023 10:54:16 +0200 Subject: [PATCH 2/3] [kodiStubs] add some VFS entries and GetAddonInfo --- src/test/KodiStubs.h | 87 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/src/test/KodiStubs.h b/src/test/KodiStubs.h index ce5051114..60fba9572 100644 --- a/src/test/KodiStubs.h +++ b/src/test/KodiStubs.h @@ -13,6 +13,7 @@ #include #include #include +#include #ifdef _WIN32 // windows #if !defined(_SSIZE_T_DEFINED) && !defined(HAVE_SSIZE_T) @@ -86,6 +87,11 @@ namespace addon { class InputstreamInfo; +inline std::string GetAddonInfo(const std::string& id) +{ + return ""; +} + inline std::string GetLocalizedString(uint32_t labelId, const std::string& defaultStr = "") { return defaultStr; @@ -114,8 +120,72 @@ inline std::string GetUserPath(const std::string& append = "") } // namespace addon +struct VFSProperty +{ + char* name; + char* val; +}; + +struct VFSDirEntry +{ + char* label; //!< item label + char* title; //!< item title + char* path; //!< item path + unsigned int num_props; //!< Number of properties attached to item + struct VFSProperty* properties; //!< Properties + time_t date_time; //!< file creation date & time + bool folder; //!< Item is a folder + uint64_t size; //!< Size of file represented by item +}; + namespace vfs { +class ATTR_DLL_LOCAL CDirEntry +{ +public: + CDirEntry(const std::string& label = "", + const std::string& path = "", + bool folder = false, + int64_t size = -1, + time_t dateTime = 0) + : m_label(label), m_path(path), m_folder(folder), m_size(size), m_dateTime(dateTime) + { + } + + explicit CDirEntry(const VFSDirEntry& dirEntry) + : m_label(dirEntry.label ? dirEntry.label : ""), + m_path(dirEntry.path ? dirEntry.path : ""), + m_folder(dirEntry.folder), + m_size(dirEntry.size), + m_dateTime(dirEntry.date_time) + { + } + + const std::string& Label(void) const { return m_label; } + const std::string& Title(void) const { return m_title; } + const std::string& Path(void) const { return m_path; } + bool IsFolder(void) const { return m_folder; } + int64_t Size(void) const { return m_size; } + time_t DateTime() { return m_dateTime; } + void SetLabel(const std::string& label) { m_label = label; } + void SetTitle(const std::string& title) { m_title = title; } + void SetPath(const std::string& path) { m_path = path; } + void SetFolder(bool folder) { m_folder = folder; } + void SetSize(int64_t size) { m_size = size; } + void SetDateTime(time_t dateTime) { m_dateTime = dateTime; } + void AddProperty(const std::string& id, const std::string& value) { m_properties[id] = value; } + void ClearProperties() { m_properties.clear(); } + const std::map& GetProperties() const { return m_properties; } +private: + std::string m_label; + std::string m_title; + std::string m_path; + std::map m_properties; + bool m_folder; + int64_t m_size; + time_t m_dateTime; +}; + class CFile { public: @@ -183,11 +253,28 @@ inline bool FileExists(const std::string& filename, bool usecache = false) return false; } +inline bool DirectoryExists(const std::string& path) +{ + return false; +} + inline bool RemoveDirectory(const std::string& path, bool recursive = false) { return true; } +inline std::string TranslateSpecialProtocol(const std::string& source) +{ + return ""; +} + +inline bool GetDirectory(const std::string& path, + const std::string& mask, + std::vector& items) +{ + return false; +} + } // namespace vfs namespace gui From 597ff9b602cbe75813ab890d2459d8f2b3081cbb Mon Sep 17 00:00:00 2001 From: CastagnaIT Date: Thu, 21 Sep 2023 10:39:13 +0200 Subject: [PATCH 3/3] [widevine] Reintroduce CDM aarch64 support --- CMakeLists.txt | 11 ++++++ Helpers.cmake | 6 +++ lib/cdm_aarch64/CMakeLists.txt | 8 ++++ lib/cdm_aarch64/cdm_loader.cpp | 31 +++++++++++++++ src/decrypters/widevine/CMakeLists.txt | 7 ++++ src/decrypters/widevine/WVDecrypter.cpp | 50 +++++++++++++++++++++++++ src/decrypters/widevine/WVDecrypter.h | 3 ++ 7 files changed, 116 insertions(+) create mode 100644 lib/cdm_aarch64/CMakeLists.txt create mode 100644 lib/cdm_aarch64/cdm_loader.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 7e58e4efc..91ed3fb83 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,6 +26,7 @@ if(WIN32) list(APPEND DEPLIBS ${dlfcn-win32_LIBRARIES}) include_directories(${dlfcn-win32_INCLUDE_DIRS}) else() + list(APPEND DEPLIBS ${CMAKE_DL_LIBS}) # Required on some old linux platforms to use macro like PRIu64 add_definitions(-D__STDC_FORMAT_MACROS) endif() @@ -68,6 +69,16 @@ endforeach() get_property(DEPS_NAMES_LIST GLOBAL PROPERTY GlobalDepsNamesList) list(APPEND DEPLIBS ${DEPS_NAMES_LIST}) +# Add additional shared dependencies +get_property(DEPS_FOLDERS_LIST GLOBAL PROPERTY GlobalSharedDepsFoldersList) +foreach(DEP_FOLDER ${DEPS_FOLDERS_LIST}) + add_subdirectory(${DEP_FOLDER}) +endforeach() +get_property(DEPS_NAMES_LIST GLOBAL PROPERTY GlobalSharedDepsNamesList) +foreach(DEP_NAME ${DEPS_NAMES_LIST}) + list(APPEND ADP_ADDITIONAL_BINARY $) +endforeach() + build_addon(inputstream.adaptive ADP DEPLIBS) if(NOT CMAKE_CROSSCOMPILING AND BUILD_TESTING) diff --git a/Helpers.cmake b/Helpers.cmake index f94782325..6f02d63a7 100644 --- a/Helpers.cmake +++ b/Helpers.cmake @@ -71,3 +71,9 @@ function(add_dependency project_name folder) set_property(GLOBAL APPEND PROPERTY GlobalDepsNamesList "${project_name}") set_property(GLOBAL APPEND PROPERTY GlobalDepsFoldersList "${folder}") endfunction(add_dependency) + +# Function to add an additional shared dependency to global properties GlobalSharedDepsNamesList/GlobalSharedDepsFoldersList +function(add_shared_dependency project_name folder) + set_property(GLOBAL APPEND PROPERTY GlobalSharedDepsNamesList "${project_name}") + set_property(GLOBAL APPEND PROPERTY GlobalSharedDepsFoldersList "${folder}") +endfunction(add_shared_dependency) diff --git a/lib/cdm_aarch64/CMakeLists.txt b/lib/cdm_aarch64/CMakeLists.txt new file mode 100644 index 000000000..b59c09034 --- /dev/null +++ b/lib/cdm_aarch64/CMakeLists.txt @@ -0,0 +1,8 @@ +cmake_minimum_required(VERSION 3.10) +project(cdm_aarch64_loader) + +add_library(cdm_aarch64_loader SHARED + cdm_loader.cpp +) + +set_target_properties(cdm_aarch64_loader PROPERTIES POSITION_INDEPENDENT_CODE True) diff --git a/lib/cdm_aarch64/cdm_loader.cpp b/lib/cdm_aarch64/cdm_loader.cpp new file mode 100644 index 000000000..5dd47b74e --- /dev/null +++ b/lib/cdm_aarch64/cdm_loader.cpp @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2023 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 + +extern "C" +{ +// Linux arm64 version of libwidevinecdm.so depends on two dynamic symbols. +// See https://github.com/xbmc/inputstream.adaptive/issues/1128 +#if defined(__linux__) && (defined(__aarch64__) || defined(__arm64__)) + + __attribute__((target("no-outline-atomics"))) int32_t __aarch64_ldadd4_acq_rel(int32_t value, + int32_t* ptr) + { + return __atomic_fetch_add(ptr, value, __ATOMIC_ACQ_REL); + } + + __attribute__((target("no-outline-atomics"))) int32_t __aarch64_swp4_acq_rel(int32_t value, + int32_t* ptr) + { + return __atomic_exchange_n(ptr, value, __ATOMIC_ACQ_REL); + } +#endif +} diff --git a/src/decrypters/widevine/CMakeLists.txt b/src/decrypters/widevine/CMakeLists.txt index 2d27fdfb0..46594f0c8 100644 --- a/src/decrypters/widevine/CMakeLists.txt +++ b/src/decrypters/widevine/CMakeLists.txt @@ -20,3 +20,10 @@ add_dir_sources(SOURCES HEADERS) # Native CDM library add_dependency(cdm_library lib/cdm) + +# Patch to load CDM library on aarch64 platforms +if(${CMAKE_SYSTEM_NAME} STREQUAL Linux) +if(CMAKE_SYSTEM_PROCESSOR MATCHES "^aarch64" OR CMAKE_SYSTEM_PROCESSOR MATCHES "^arm64") + add_shared_dependency(cdm_aarch64_loader lib/cdm_aarch64) +endif() +endif() diff --git a/src/decrypters/widevine/WVDecrypter.cpp b/src/decrypters/widevine/WVDecrypter.cpp index 9675e3d1d..0bf74eb0c 100644 --- a/src/decrypters/widevine/WVDecrypter.cpp +++ b/src/decrypters/widevine/WVDecrypter.cpp @@ -11,10 +11,16 @@ #include "WVCdmAdapter.h" #include "WVCencSingleSampleDecrypter.h" #include "utils/Base64Utils.h" +#include "utils/FileUtils.h" +#include "utils/StringUtils.h" #include "utils/log.h" #include +#if defined(__linux__) && (defined(__aarch64__) || defined(__arm64__)) +#include +#endif + using namespace DRM; using namespace UTILS; using namespace kodi::tools; @@ -24,6 +30,50 @@ CWVDecrypter::~CWVDecrypter() { delete m_WVCdmAdapter; m_WVCdmAdapter = nullptr; +#if defined(__linux__) && (defined(__aarch64__) || defined(__arm64__)) + if (m_hdlLibLoader) + dlclose(m_hdlLibLoader); +#endif +} + +bool CWVDecrypter::Initialize() +{ +#if defined(__linux__) && (defined(__aarch64__) || defined(__arm64__)) + // On linux arm64, libwidevinecdm.so depends on two dynamic symbols: + // __aarch64_ldadd4_acq_rel + // __aarch64_swp4_acq_rel + // These are defined from a separate library cdm_aarch64_loader, + // but to make them available in the main binary's PLT, we need RTLD_GLOBAL. + // Kodi kodi::tools::CDllHelper LoadDll() cannot be used because use RTLD_LOCAL, + // and we need the RTLD_GLOBAL flag. + std::string binaryPath; + std::vector items; + if (kodi::vfs::GetDirectory(FILESYS::GetAddonPath(), "", items)) + { + for (auto item : items) + { + if (!STRING::Contains(item.Label(), "cdm_aarch64_loader")) + continue; + + binaryPath = item.Path(); + break; + } + } + if (binaryPath.empty()) + { + LOG::Log(LOGERROR, "Cannot find the cdm_aarch64_loader file"); + return false; + } + + m_hdlLibLoader = dlopen(binaryPath.c_str(), RTLD_GLOBAL | RTLD_LAZY); + if (!m_hdlLibLoader) + { + LOG::LogF(LOGERROR, "Failed to load CDM aarch64 loader from path \"%s\", error: %s", + binaryPath.c_str(), dlerror()); + return false; + } +#endif + return true; } const char* CWVDecrypter::SelectKeySytem(const char* keySystem) diff --git a/src/decrypters/widevine/WVDecrypter.h b/src/decrypters/widevine/WVDecrypter.h index 5e810598b..76dc0342c 100644 --- a/src/decrypters/widevine/WVDecrypter.h +++ b/src/decrypters/widevine/WVDecrypter.h @@ -25,6 +25,8 @@ class ATTR_DLL_LOCAL CWVDecrypter : public IDecrypter CWVDecrypter() : m_WVCdmAdapter(nullptr), m_decodingDecrypter(nullptr){}; virtual ~CWVDecrypter() override; + virtual bool Initialize() override; + virtual const char* SelectKeySytem(const char* keySystem) override; virtual bool OpenDRMSystem(const char* licenseURL, const AP4_DataBuffer& serverCertificate, @@ -69,4 +71,5 @@ class ATTR_DLL_LOCAL CWVDecrypter : public IDecrypter std::string m_strProfilePath; std::string m_strLibraryPath; bool m_isDebugSaveLicense; + void* m_hdlLibLoader{nullptr}; // Aarch64 loader library handle };