From 6c2e8d5bf694a4e17998cf5284ebe32074637ae5 Mon Sep 17 00:00:00 2001 From: Aidan Date: Sun, 15 Oct 2023 21:24:54 -0700 Subject: [PATCH] Update to latest Omega --- lib/mfcdm/CMakeLists.txt | 34 +- lib/mfcdm/mfcdm/MediaFoundationCdm.cpp | 242 ++++++----- lib/mfcdm/mfcdm/MediaFoundationCdm.h | 120 +++--- src/decrypters/DrmFactory.cpp | 2 +- .../mediafoundation/MFDecrypter.cpp | 400 +++++++++--------- src/decrypters/mediafoundation/MFDecrypter.h | 182 ++++---- 6 files changed, 488 insertions(+), 492 deletions(-) diff --git a/lib/mfcdm/CMakeLists.txt b/lib/mfcdm/CMakeLists.txt index 96891887d..615c936ca 100644 --- a/lib/mfcdm/CMakeLists.txt +++ b/lib/mfcdm/CMakeLists.txt @@ -1,17 +1,17 @@ -cmake_minimum_required(VERSION 3.10) -project(mfcdm_library) - -add_library(mfcdm_library STATIC - mfcdm/MediaFoundationCdm.h - mfcdm/MediaFoundationCdm.cpp - mfcdm/MediaFoundationCdmFactory.cpp - mfcdm/MediaFoundationCdmSession.cpp - mfcdm/MediaFoundationSession.cpp - mfcdm/Log.cpp -) - -target_include_directories(mfcdm_library PUBLIC ${PROJECT_SOURCE_DIR}) - -target_link_libraries(mfcdm_library PRIVATE cdm_library propsys mf mfplat mfplay mfreadwrite mfuuid wmcodecdspuuid) - -set_target_properties(mfcdm_library PROPERTIES POSITION_INDEPENDENT_CODE True) +cmake_minimum_required(VERSION 3.10) +project(mfcdm_library) + +add_library(mfcdm_library STATIC + mfcdm/MediaFoundationCdm.h + mfcdm/MediaFoundationCdm.cpp + mfcdm/MediaFoundationCdmFactory.cpp + mfcdm/MediaFoundationCdmSession.cpp + mfcdm/MediaFoundationSession.cpp + mfcdm/Log.cpp +) + +target_include_directories(mfcdm_library PUBLIC ${PROJECT_SOURCE_DIR}) + +target_link_libraries(mfcdm_library PRIVATE cdm_library propsys mf mfplat mfplay mfreadwrite mfuuid wmcodecdspuuid) + +set_target_properties(mfcdm_library PROPERTIES POSITION_INDEPENDENT_CODE True) diff --git a/lib/mfcdm/mfcdm/MediaFoundationCdm.cpp b/lib/mfcdm/mfcdm/MediaFoundationCdm.cpp index c150881ef..9280a41f4 100644 --- a/lib/mfcdm/mfcdm/MediaFoundationCdm.cpp +++ b/lib/mfcdm/mfcdm/MediaFoundationCdm.cpp @@ -1,123 +1,119 @@ -/* - * 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. - */ - -#include "MediaFoundationCdm.h" - -#include "Log.h" -#include "MediaFoundationCdmFactory.h" -#include "MediaFoundationCdmModule.h" -#include "MediaFoundationCdmSession.h" - -#include "utils/PMPHostWrapper.h" - -MediaFoundationCdm::~MediaFoundationCdm() = default; - -bool MediaFoundationCdm::Initialize(const std::string &keySystem, - const std::string &basePath, - const media::CdmConfig &cdmConfig, - media::CdmAdapterClient* client) -{ - bool ret = true; - - m_session.Startup(); - - ret = m_session.HasMediaFoundation(); - if (!ret) - { - Log(MFCDM::MFLOG_ERROR, "MF doesn't exist on current system"); - return false; - } - - const auto m_factory = std::make_unique(keySystem); - - ret = m_factory->Initialize(); - if (!ret) - { - Log(MFCDM::MFLOG_ERROR, "MFFactory failed to initialize."); - return false; - } - - ret = m_factory->CreateMfCdm(cdmConfig, basePath, m_module); - if (!ret) - { - Log(MFCDM::MFLOG_ERROR, "MFFactory failed to create MF CDM."); - return false; - } - - Log(MFCDM::MFLOG_DEBUG, "MF CDM created."); - - SetupPMPServer(); - - m_client = client; - return true; -} - -/*! - * \brief Setup PMPHostApp - * IMFContentDecryptionModule->SetPMPHostApp - * needs to be set if not under UWP or else GenerateChallenge will fail - * \link https://github.com/microsoft/media-foundation/issues/37#issuecomment-1194534228 - */ -void MediaFoundationCdm::SetupPMPServer() const -{ - if (!m_module) - return; - - const winrt::com_ptr spIMFGetService = m_module->As(); - winrt::com_ptr pmpHostApp; - - if(FAILED(spIMFGetService->GetService( - MF_CONTENTDECRYPTIONMODULE_SERVICE, IID_PPV_ARGS(pmpHostApp.put())))) - { - Log(MFCDM::MFLOG_ERROR, "Failed to get MF CDM service."); - return; - } - - winrt::com_ptr spIMFPMPHostApp = winrt::make_self(pmpHostApp); - m_module->SetPMPHostApp(spIMFPMPHostApp.get()); -} - -void MediaFoundationCdm::SetServerCertificate(uint32_t promise_id, - const uint8_t* serverCertificateData, - uint32_t serverCertificateDataSize) const -{ - m_module->SetServerCertificate(serverCertificateData, serverCertificateDataSize); -} - -void MediaFoundationCdm::CreateSessionAndGenerateRequest(uint32_t promise_id, cdm::SessionType sessionType, - cdm::InitDataType initDataType, const uint8_t *init_data, - uint32_t init_data_size) -{ - auto session = std::make_unique(); - - if (!session->Initialize(sessionType, m_module.get())) - { - Log(MFCDM::MFLOG_ERROR, "Failed to create session."); - return; - } - - int session_token = next_session_token_++; - session->GenerateRequest(initDataType, init_data, init_data_size); - - m_cdm_sessions.emplace(session_token, std::move(session)); -} - -void MediaFoundationCdm::LoadSession(cdm::SessionType session_type, - const std::string &session_id) -{ - -} - -void MediaFoundationCdm::UpdateSession(const std::string &session_id) -{ - -} - - - - +/* + * 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. + */ + +#include "MediaFoundationCdm.h" + +#include "Log.h" +#include "MediaFoundationCdmFactory.h" +#include "MediaFoundationCdmModule.h" +#include "MediaFoundationCdmSession.h" + +#include "utils/PMPHostWrapper.h" + +MediaFoundationCdm::~MediaFoundationCdm() = default; + +bool MediaFoundationCdm::Initialize(const std::string &keySystem, + const std::string &basePath, + const media::CdmConfig &cdmConfig, + media::CdmAdapterClient* client) +{ + bool ret = true; + + m_session.Startup(); + + ret = m_session.HasMediaFoundation(); + if (!ret) + { + Log(MFCDM::MFLOG_ERROR, "MF doesn't exist on current system"); + return false; + } + + const auto m_factory = std::make_unique(keySystem); + + ret = m_factory->Initialize(); + if (!ret) + { + Log(MFCDM::MFLOG_ERROR, "MFFactory failed to initialize."); + return false; + } + + ret = m_factory->CreateMfCdm(cdmConfig, basePath, m_module); + if (!ret) + { + Log(MFCDM::MFLOG_ERROR, "MFFactory failed to create MF CDM."); + return false; + } + + Log(MFCDM::MFLOG_DEBUG, "MF CDM created."); + + SetupPMPServer(); + + m_client = client; + return true; +} + +/*! + * \brief Setup PMPHostApp + * IMFContentDecryptionModule->SetPMPHostApp + * needs to be set if not under UWP or else GenerateChallenge will fail + * \link https://github.com/microsoft/media-foundation/issues/37#issuecomment-1194534228 + */ +void MediaFoundationCdm::SetupPMPServer() const +{ + if (!m_module) + return; + + const winrt::com_ptr spIMFGetService = m_module->As(); + winrt::com_ptr pmpHostApp; + + if(FAILED(spIMFGetService->GetService( + MF_CONTENTDECRYPTIONMODULE_SERVICE, IID_PPV_ARGS(pmpHostApp.put())))) + { + Log(MFCDM::MFLOG_ERROR, "Failed to get MF CDM service."); + return; + } + + winrt::com_ptr spIMFPMPHostApp = winrt::make_self(pmpHostApp); + m_module->SetPMPHostApp(spIMFPMPHostApp.get()); +} + +void MediaFoundationCdm::SetServerCertificate(uint32_t promise_id, + const uint8_t* serverCertificateData, + uint32_t serverCertificateDataSize) const +{ + m_module->SetServerCertificate(serverCertificateData, serverCertificateDataSize); +} + +void MediaFoundationCdm::CreateSessionAndGenerateRequest(uint32_t promise_id, cdm::SessionType sessionType, + cdm::InitDataType initDataType, const uint8_t *init_data, + uint32_t init_data_size) +{ + auto session = std::make_unique(); + + if (!session->Initialize(sessionType, m_module.get())) + { + Log(MFCDM::MFLOG_ERROR, "Failed to create session."); + return; + } + + int session_token = next_session_token_++; + session->GenerateRequest(initDataType, init_data, init_data_size); + + m_cdm_sessions.emplace(session_token, std::move(session)); +} + +void MediaFoundationCdm::LoadSession(cdm::SessionType session_type, + const std::string &session_id) +{ + +} + +void MediaFoundationCdm::UpdateSession(const std::string &session_id) +{ + +} diff --git a/lib/mfcdm/mfcdm/MediaFoundationCdm.h b/lib/mfcdm/mfcdm/MediaFoundationCdm.h index 63138155d..8e94af382 100644 --- a/lib/mfcdm/mfcdm/MediaFoundationCdm.h +++ b/lib/mfcdm/mfcdm/MediaFoundationCdm.h @@ -1,60 +1,60 @@ -/* - * 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 "MediaFoundationSession.h" - -#include -#include -#include - -#include "cdm/media/base/cdm_config.h" -#include "cdm/media/cdm/api/content_decryption_module.h" -#include "cdm/media/cdm/cdm_adapter.h" - -class MediaFoundationCdmSession; -class MediaFoundationCdmFactory; -class MediaFoundationCdmModule; - -class MediaFoundationCdm { -public: - ~MediaFoundationCdm(); - - bool IsInitialized() const { return m_module != nullptr; } - - bool Initialize(const std::string& keySystem, - const std::string &basePath, - const media::CdmConfig &cdmConfig, - media::CdmAdapterClient* client); - - void SetServerCertificate(uint32_t promise_id, - const uint8_t* serverCertificateData, - uint32_t serverCertificateDataSize) const; - - void CreateSessionAndGenerateRequest(uint32_t promise_id, - cdm::SessionType sessionType, - cdm::InitDataType initDataType, - const uint8_t* init_data, - uint32_t init_data_size); - - void LoadSession(cdm::SessionType session_type, const std::string& session_id); - - void UpdateSession(const std::string& session_id); -private: - void SetupPMPServer() const; - - MediaFoundationSession m_session; - - std::unique_ptr m_module{nullptr}; - - int next_session_token_{0}; - std::map> m_cdm_sessions; - - media::CdmAdapterClient* m_client{nullptr}; -}; \ No newline at end of file +/* + * 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 "MediaFoundationSession.h" + +#include +#include +#include + +#include "cdm/media/base/cdm_config.h" +#include "cdm/media/cdm/api/content_decryption_module.h" +#include "cdm/media/cdm/cdm_adapter.h" + +class MediaFoundationCdmSession; +class MediaFoundationCdmFactory; +class MediaFoundationCdmModule; + +class MediaFoundationCdm { +public: + ~MediaFoundationCdm(); + + bool IsInitialized() const { return m_module != nullptr; } + + bool Initialize(const std::string& keySystem, + const std::string &basePath, + const media::CdmConfig &cdmConfig, + media::CdmAdapterClient* client); + + void SetServerCertificate(uint32_t promise_id, + const uint8_t* serverCertificateData, + uint32_t serverCertificateDataSize) const; + + void CreateSessionAndGenerateRequest(uint32_t promise_id, + cdm::SessionType sessionType, + cdm::InitDataType initDataType, + const uint8_t* init_data, + uint32_t init_data_size); + + void LoadSession(cdm::SessionType session_type, const std::string& session_id); + + void UpdateSession(const std::string& session_id); +private: + void SetupPMPServer() const; + + MediaFoundationSession m_session; + + std::unique_ptr m_module{nullptr}; + + int next_session_token_{0}; + std::map> m_cdm_sessions; + + media::CdmAdapterClient* m_client{nullptr}; +}; diff --git a/src/decrypters/DrmFactory.cpp b/src/decrypters/DrmFactory.cpp index 9f892803e..f5227498c 100644 --- a/src/decrypters/DrmFactory.cpp +++ b/src/decrypters/DrmFactory.cpp @@ -57,4 +57,4 @@ IDecrypter* DRM::FACTORY::GetDecrypter(STREAM_CRYPTO_KEY_SYSTEM keySystem) } return nullptr; -} \ No newline at end of file +} diff --git a/src/decrypters/mediafoundation/MFDecrypter.cpp b/src/decrypters/mediafoundation/MFDecrypter.cpp index 88e8a842f..c417ace8a 100644 --- a/src/decrypters/mediafoundation/MFDecrypter.cpp +++ b/src/decrypters/mediafoundation/MFDecrypter.cpp @@ -1,200 +1,200 @@ -#include "MFDecrypter.h" -#include "MFCencSingleSampleDecrypter.h" -#include "../../utils/Base64Utils.h" -#include "../../utils/log.h" - -#include -#include -#include - -#include -#include - -using namespace UTILS; -using namespace DRM; -using namespace kodi::tools; - -namespace -{ -void MFLog(int level, char* msg) -{ - if (msg[std::strlen(msg) - 1] == '\n') - msg[std::strlen(msg) - 1] = '\0'; - - switch (level) - { - case MFCDM::MFLOG_ERROR: - LOG::Log(LOGERROR, msg); - break; - case MFCDM::MFLOG_WARN: - LOG::Log(LOGWARNING, msg); - break; - case MFCDM::MFLOG_INFO: - LOG::Log(LOGINFO, msg); - break; - case MFCDM::MFLOG_DEBUG: - LOG::Log(LOGDEBUG, msg); - break; - default: - break; - } -} -} // unnamed namespace - - -CMFDecrypter::CMFDecrypter() - : m_cdm(nullptr) -{ - MFCDM::LogAll(); - MFCDM::SetMFMsgCallback(MFLog); -} - -CMFDecrypter::~CMFDecrypter() -{ - delete m_cdm; -} - -bool CMFDecrypter::Initialize() -{ - m_cdm = new MediaFoundationCdm(); - return m_cdm != NULL; -} - -std::string CMFDecrypter::SelectKeySytem(std::string_view keySystem) -{ - if (keySystem == "com.microsoft.playready") - return "urn:uuid:9A04F079-9840-4286-AB92-E65BE0885F95"; - return ""; -} - -bool CMFDecrypter::OpenDRMSystem(std::string_view licenseURL, - const std::vector& serverCertificate, - const uint8_t config) -{ - if (!m_cdm) - return false; - - if (!(config & DRM::IDecrypter::CONFIG_PERSISTENTSTORAGE)) - { - LOG::Log(LOGERROR, "MF PlayReady requires persistent storage to be optionally on or required."); - return false; - } - - return m_cdm->Initialize("com.microsoft.playready.recommendation", m_strProfilePath, {true, true}, - nullptr); -} - -Adaptive_CencSingleSampleDecrypter* CMFDecrypter::CreateSingleSampleDecrypter( - std::vector& pssh, - std::string_view optionalKeyParameter, - std::string_view defaultKeyId, - bool skipSessionMessage, - CryptoMode cryptoMode) -{ - CMFCencSingleSampleDecrypter* decrypter = new CMFCencSingleSampleDecrypter( - *this, pssh, defaultKeyId, skipSessionMessage, cryptoMode); - if (!decrypter->GetSessionId()) - { - delete decrypter; - decrypter = nullptr; - } - return decrypter; -} - -void CMFDecrypter::DestroySingleSampleDecrypter(Adaptive_CencSingleSampleDecrypter* decrypter) -{ - if (decrypter) - { - // close session before dispose - dynamic_cast(decrypter)->CloseSessionId(); - delete dynamic_cast(decrypter); - } -} - -void CMFDecrypter::GetCapabilities(Adaptive_CencSingleSampleDecrypter* decrypter, - std::string_view keyId, - uint32_t media, - IDecrypter::DecrypterCapabilites& caps) -{ - if (!decrypter) - { - caps = {0, 0, 0}; - return; - } - - dynamic_cast(decrypter)->GetCapabilities(keyId, media, caps); -} - -bool CMFDecrypter::HasLicenseKey(Adaptive_CencSingleSampleDecrypter* decrypter, - std::string_view keyId) -{ - if (decrypter) - return dynamic_cast(decrypter)->HasKeyId(keyId); - return false; -} - -std::string CMFDecrypter::GetChallengeB64Data(Adaptive_CencSingleSampleDecrypter* decrypter) -{ - if (!decrypter) - return ""; - - AP4_DataBuffer challengeData = - dynamic_cast(decrypter)->GetChallengeData(); - return BASE64::Encode(challengeData.GetData(), challengeData.GetDataSize()); -} - -bool CMFDecrypter::OpenVideoDecoder(Adaptive_CencSingleSampleDecrypter* decrypter, - const VIDEOCODEC_INITDATA* initData) -{ - if (!decrypter || !initData) - return false; - - m_decodingDecrypter = dynamic_cast(decrypter); - return m_decodingDecrypter->OpenVideoDecoder(initData); -} - -VIDEOCODEC_RETVAL CMFDecrypter::DecryptAndDecodeVideo( - kodi::addon::CInstanceVideoCodec* codecInstance, const DEMUX_PACKET* sample) -{ - if (!m_decodingDecrypter) - return VC_ERROR; - - return m_decodingDecrypter->DecryptAndDecodeVideo(codecInstance, sample); -} - -VIDEOCODEC_RETVAL CMFDecrypter::VideoFrameDataToPicture( - kodi::addon::CInstanceVideoCodec* codecInstance, VIDEOCODEC_PICTURE* picture) -{ - if (!m_decodingDecrypter) - return VC_ERROR; - - return m_decodingDecrypter->VideoFrameDataToPicture(codecInstance, picture); -} - -void CMFDecrypter::ResetVideo() -{ - if (m_decodingDecrypter) - m_decodingDecrypter->ResetVideo(); -} - -void CMFDecrypter::SetProfilePath(const std::string& profilePath) -{ - m_strProfilePath = profilePath; - - const char* pathSep{profilePath[0] && profilePath[1] == ':' && isalpha(profilePath[0]) ? "\\" - : "/"}; - - if (!m_strProfilePath.empty() && m_strProfilePath.back() != pathSep[0]) - m_strProfilePath += pathSep; - - //let us make cdm userdata out of the addonpath and share them between addons - m_strProfilePath.resize(m_strProfilePath.find_last_of(pathSep[0], m_strProfilePath.length() - 2)); - m_strProfilePath.resize(m_strProfilePath.find_last_of(pathSep[0], m_strProfilePath.length() - 1)); - m_strProfilePath.resize(m_strProfilePath.find_last_of(pathSep[0], m_strProfilePath.length() - 1) + - 1); - - kodi::vfs::CreateDirectory(m_strProfilePath); - m_strProfilePath += "cdm"; - m_strProfilePath += pathSep; - kodi::vfs::CreateDirectory(m_strProfilePath); -} +#include "MFDecrypter.h" +#include "MFCencSingleSampleDecrypter.h" +#include "../../utils/Base64Utils.h" +#include "../../utils/log.h" + +#include +#include +#include + +#include +#include + +using namespace UTILS; +using namespace DRM; +using namespace kodi::tools; + +namespace +{ +void MFLog(int level, char* msg) +{ + if (msg[std::strlen(msg) - 1] == '\n') + msg[std::strlen(msg) - 1] = '\0'; + + switch (level) + { + case MFCDM::MFLOG_ERROR: + LOG::Log(LOGERROR, msg); + break; + case MFCDM::MFLOG_WARN: + LOG::Log(LOGWARNING, msg); + break; + case MFCDM::MFLOG_INFO: + LOG::Log(LOGINFO, msg); + break; + case MFCDM::MFLOG_DEBUG: + LOG::Log(LOGDEBUG, msg); + break; + default: + break; + } +} +} // unnamed namespace + + +CMFDecrypter::CMFDecrypter() + : m_cdm(nullptr) +{ + MFCDM::LogAll(); + MFCDM::SetMFMsgCallback(MFLog); +} + +CMFDecrypter::~CMFDecrypter() +{ + delete m_cdm; +} + +bool CMFDecrypter::Initialize() +{ + m_cdm = new MediaFoundationCdm(); + return m_cdm != NULL; +} + +std::string CMFDecrypter::SelectKeySytem(std::string_view keySystem) +{ + if (keySystem == "com.microsoft.playready") + return "urn:uuid:9A04F079-9840-4286-AB92-E65BE0885F95"; + return ""; +} + +bool CMFDecrypter::OpenDRMSystem(std::string_view licenseURL, + const std::vector& serverCertificate, + const uint8_t config) +{ + if (!m_cdm) + return false; + + if (!(config & DRM::IDecrypter::CONFIG_PERSISTENTSTORAGE)) + { + LOG::Log(LOGERROR, "MF PlayReady requires persistent storage to be optionally on or required."); + return false; + } + + return m_cdm->Initialize("com.microsoft.playready.recommendation", m_strProfilePath, {true, true}, + nullptr); +} + +Adaptive_CencSingleSampleDecrypter* CMFDecrypter::CreateSingleSampleDecrypter( + std::vector& pssh, + std::string_view optionalKeyParameter, + std::string_view defaultKeyId, + bool skipSessionMessage, + CryptoMode cryptoMode) +{ + CMFCencSingleSampleDecrypter* decrypter = new CMFCencSingleSampleDecrypter( + *this, pssh, defaultKeyId, skipSessionMessage, cryptoMode); + if (!decrypter->GetSessionId()) + { + delete decrypter; + decrypter = nullptr; + } + return decrypter; +} + +void CMFDecrypter::DestroySingleSampleDecrypter(Adaptive_CencSingleSampleDecrypter* decrypter) +{ + if (decrypter) + { + // close session before dispose + dynamic_cast(decrypter)->CloseSessionId(); + delete dynamic_cast(decrypter); + } +} + +void CMFDecrypter::GetCapabilities(Adaptive_CencSingleSampleDecrypter* decrypter, + std::string_view keyId, + uint32_t media, + IDecrypter::DecrypterCapabilites& caps) +{ + if (!decrypter) + { + caps = {0, 0, 0}; + return; + } + + dynamic_cast(decrypter)->GetCapabilities(keyId, media, caps); +} + +bool CMFDecrypter::HasLicenseKey(Adaptive_CencSingleSampleDecrypter* decrypter, + std::string_view keyId) +{ + if (decrypter) + return dynamic_cast(decrypter)->HasKeyId(keyId); + return false; +} + +std::string CMFDecrypter::GetChallengeB64Data(Adaptive_CencSingleSampleDecrypter* decrypter) +{ + if (!decrypter) + return ""; + + AP4_DataBuffer challengeData = + dynamic_cast(decrypter)->GetChallengeData(); + return BASE64::Encode(challengeData.GetData(), challengeData.GetDataSize()); +} + +bool CMFDecrypter::OpenVideoDecoder(Adaptive_CencSingleSampleDecrypter* decrypter, + const VIDEOCODEC_INITDATA* initData) +{ + if (!decrypter || !initData) + return false; + + m_decodingDecrypter = dynamic_cast(decrypter); + return m_decodingDecrypter->OpenVideoDecoder(initData); +} + +VIDEOCODEC_RETVAL CMFDecrypter::DecryptAndDecodeVideo( + kodi::addon::CInstanceVideoCodec* codecInstance, const DEMUX_PACKET* sample) +{ + if (!m_decodingDecrypter) + return VC_ERROR; + + return m_decodingDecrypter->DecryptAndDecodeVideo(codecInstance, sample); +} + +VIDEOCODEC_RETVAL CMFDecrypter::VideoFrameDataToPicture( + kodi::addon::CInstanceVideoCodec* codecInstance, VIDEOCODEC_PICTURE* picture) +{ + if (!m_decodingDecrypter) + return VC_ERROR; + + return m_decodingDecrypter->VideoFrameDataToPicture(codecInstance, picture); +} + +void CMFDecrypter::ResetVideo() +{ + if (m_decodingDecrypter) + m_decodingDecrypter->ResetVideo(); +} + +void CMFDecrypter::SetProfilePath(const std::string& profilePath) +{ + m_strProfilePath = profilePath; + + const char* pathSep{profilePath[0] && profilePath[1] == ':' && isalpha(profilePath[0]) ? "\\" + : "/"}; + + if (!m_strProfilePath.empty() && m_strProfilePath.back() != pathSep[0]) + m_strProfilePath += pathSep; + + //let us make cdm userdata out of the addonpath and share them between addons + m_strProfilePath.resize(m_strProfilePath.find_last_of(pathSep[0], m_strProfilePath.length() - 2)); + m_strProfilePath.resize(m_strProfilePath.find_last_of(pathSep[0], m_strProfilePath.length() - 1)); + m_strProfilePath.resize(m_strProfilePath.find_last_of(pathSep[0], m_strProfilePath.length() - 1) + + 1); + + kodi::vfs::CreateDirectory(m_strProfilePath); + m_strProfilePath += "cdm"; + m_strProfilePath += pathSep; + kodi::vfs::CreateDirectory(m_strProfilePath); +} diff --git a/src/decrypters/mediafoundation/MFDecrypter.h b/src/decrypters/mediafoundation/MFDecrypter.h index 07c2397a8..405738c8e 100644 --- a/src/decrypters/mediafoundation/MFDecrypter.h +++ b/src/decrypters/mediafoundation/MFDecrypter.h @@ -1,91 +1,91 @@ -/* - * 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. - */ - -#include "../IDecrypter.h" -#include "mfcdm/MediaFoundationCdm.h" - -#include - -using namespace DRM; -using namespace kodi::tools; - -class MediaFoundationCdm; -class CMFCencSingleSampleDecrypter; - -/*********************************************************************************************/ - -class ATTR_DLL_LOCAL CMFDecrypter : public IDecrypter -{ -public: - CMFDecrypter(); - ~CMFDecrypter() override; - - bool Initialize() override; - - std::string SelectKeySytem(std::string_view keySystem) override; - bool OpenDRMSystem(std::string_view licenseURL, - const std::vector& serverCertificate, - const uint8_t config) override; - - Adaptive_CencSingleSampleDecrypter* CreateSingleSampleDecrypter( - std::vector& pssh, - std::string_view optionalKeyParameter, - std::string_view defaultKeyId, - bool skipSessionMessage, - CryptoMode cryptoMode) override; - - void DestroySingleSampleDecrypter(Adaptive_CencSingleSampleDecrypter* decrypter) override; - - void GetCapabilities(Adaptive_CencSingleSampleDecrypter* decrypter, - std::string_view keyId, - uint32_t media, - IDecrypter::DecrypterCapabilites& caps) override; - - bool HasLicenseKey(Adaptive_CencSingleSampleDecrypter* decrypter, - std::string_view keyId) override; - - std::string GetChallengeB64Data(Adaptive_CencSingleSampleDecrypter* decrypter) override; - - virtual bool OpenVideoDecoder(Adaptive_CencSingleSampleDecrypter* decrypter, - const VIDEOCODEC_INITDATA* initData) override; - - virtual VIDEOCODEC_RETVAL DecryptAndDecodeVideo(kodi::addon::CInstanceVideoCodec* codecInstance, - const DEMUX_PACKET* sample) override; - virtual VIDEOCODEC_RETVAL VideoFrameDataToPicture(kodi::addon::CInstanceVideoCodec* codecInstance, - VIDEOCODEC_PICTURE* picture) override; - virtual void ResetVideo() override; - - void SetLibraryPath(const char* libraryPath) override {}; - void SetProfilePath(const std::string& profilePath) override; - bool IsInitialised() override - { - if (!m_cdm) - return false; - return m_cdm->IsInitialized(); - } - - void SetDebugSaveLicense(bool isDebugSaveLicense) override - { - m_isDebugSaveLicense = isDebugSaveLicense; - } - - const bool IsDebugSaveLicense() const override { return m_isDebugSaveLicense; } - const char* GetLibraryPath() const override { return m_strLibraryPath.c_str(); } - const char* GetProfilePath() const override { return m_strProfilePath.c_str(); } - - MediaFoundationCdm* GetCdm() const { return m_cdm; } - -private: - MediaFoundationCdm* m_cdm; - CMFCencSingleSampleDecrypter* m_decodingDecrypter; - - std::string m_strProfilePath; - std::string m_strLibraryPath; - - bool m_isDebugSaveLicense; -}; \ No newline at end of file +/* + * 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. + */ + +#include "../IDecrypter.h" +#include "mfcdm/MediaFoundationCdm.h" + +#include + +using namespace DRM; +using namespace kodi::tools; + +class MediaFoundationCdm; +class CMFCencSingleSampleDecrypter; + +/*********************************************************************************************/ + +class ATTR_DLL_LOCAL CMFDecrypter : public IDecrypter +{ +public: + CMFDecrypter(); + ~CMFDecrypter() override; + + bool Initialize() override; + + std::string SelectKeySytem(std::string_view keySystem) override; + bool OpenDRMSystem(std::string_view licenseURL, + const std::vector& serverCertificate, + const uint8_t config) override; + + Adaptive_CencSingleSampleDecrypter* CreateSingleSampleDecrypter( + std::vector& pssh, + std::string_view optionalKeyParameter, + std::string_view defaultKeyId, + bool skipSessionMessage, + CryptoMode cryptoMode) override; + + void DestroySingleSampleDecrypter(Adaptive_CencSingleSampleDecrypter* decrypter) override; + + void GetCapabilities(Adaptive_CencSingleSampleDecrypter* decrypter, + std::string_view keyId, + uint32_t media, + IDecrypter::DecrypterCapabilites& caps) override; + + bool HasLicenseKey(Adaptive_CencSingleSampleDecrypter* decrypter, + std::string_view keyId) override; + + std::string GetChallengeB64Data(Adaptive_CencSingleSampleDecrypter* decrypter) override; + + virtual bool OpenVideoDecoder(Adaptive_CencSingleSampleDecrypter* decrypter, + const VIDEOCODEC_INITDATA* initData) override; + + virtual VIDEOCODEC_RETVAL DecryptAndDecodeVideo(kodi::addon::CInstanceVideoCodec* codecInstance, + const DEMUX_PACKET* sample) override; + virtual VIDEOCODEC_RETVAL VideoFrameDataToPicture(kodi::addon::CInstanceVideoCodec* codecInstance, + VIDEOCODEC_PICTURE* picture) override; + virtual void ResetVideo() override; + + void SetLibraryPath(const char* libraryPath) override {}; + void SetProfilePath(const std::string& profilePath) override; + bool IsInitialised() override + { + if (!m_cdm) + return false; + return m_cdm->IsInitialized(); + } + + void SetDebugSaveLicense(bool isDebugSaveLicense) override + { + m_isDebugSaveLicense = isDebugSaveLicense; + } + + const bool IsDebugSaveLicense() const override { return m_isDebugSaveLicense; } + const char* GetLibraryPath() const override { return m_strLibraryPath.c_str(); } + const char* GetProfilePath() const override { return m_strProfilePath.c_str(); } + + MediaFoundationCdm* GetCdm() const { return m_cdm; } + +private: + MediaFoundationCdm* m_cdm; + CMFCencSingleSampleDecrypter* m_decodingDecrypter; + + std::string m_strProfilePath; + std::string m_strLibraryPath; + + bool m_isDebugSaveLicense; +};