From 52100abb0b0a8a06e2d5960faa9f809a287fbe1d Mon Sep 17 00:00:00 2001 From: TheDaChicken Date: Sat, 21 Oct 2023 01:56:36 -0700 Subject: [PATCH] Create MF session & improved code --- lib/mfcdm/CMakeLists.txt | 2 + lib/mfcdm/mfcdm/MediaFoundationCdm.cpp | 38 ++-- lib/mfcdm/mfcdm/MediaFoundationCdm.h | 37 ++-- lib/mfcdm/mfcdm/MediaFoundationCdmFactory.cpp | 172 +++++++++--------- lib/mfcdm/mfcdm/MediaFoundationCdmFactory.h | 14 +- lib/mfcdm/mfcdm/MediaFoundationCdmSession.cpp | 112 +++++++++--- lib/mfcdm/mfcdm/MediaFoundationCdmSession.h | 22 ++- lib/mfcdm/mfcdm/MediaFoundationCdmTypes.h | 43 +++++ lib/mfcdm/mfcdm/utils/PMPHostWrapper.h | 23 ++- lib/mfcdm/mfcdm/utils/ScopedCoMem.h | 44 +++++ lib/mfcdm/mfcdm/utils/ScopedPropVariant.h | 87 ++++++--- lib/mfcdm/mfcdm/utils/Wide.h | 42 +++++ .../MFCencSingleSampleDecrypter.cpp | 107 +++++------ .../MFCencSingleSampleDecrypter.h | 39 ++-- .../mediafoundation/MFDecrypter.cpp | 8 +- src/parser/DASHTree.cpp | 1 + 16 files changed, 504 insertions(+), 287 deletions(-) create mode 100644 lib/mfcdm/mfcdm/MediaFoundationCdmTypes.h create mode 100644 lib/mfcdm/mfcdm/utils/ScopedCoMem.h create mode 100644 lib/mfcdm/mfcdm/utils/Wide.h diff --git a/lib/mfcdm/CMakeLists.txt b/lib/mfcdm/CMakeLists.txt index b317c50bb..5414d40e2 100644 --- a/lib/mfcdm/CMakeLists.txt +++ b/lib/mfcdm/CMakeLists.txt @@ -3,6 +3,8 @@ project(mfcdm_library) add_library(mfcdm_library STATIC mfcdm/MediaFoundationCdm.h + mfcdm/MediaFoundationCdmConfig.h + mfcdm/MediaFoundationCdmTypes.h mfcdm/MediaFoundationCdm.cpp mfcdm/MediaFoundationCdmFactory.cpp mfcdm/MediaFoundationCdmSession.cpp diff --git a/lib/mfcdm/mfcdm/MediaFoundationCdm.cpp b/lib/mfcdm/mfcdm/MediaFoundationCdm.cpp index b0e008e4b..eda007493 100644 --- a/lib/mfcdm/mfcdm/MediaFoundationCdm.cpp +++ b/lib/mfcdm/mfcdm/MediaFoundationCdm.cpp @@ -8,19 +8,19 @@ #include "MediaFoundationCdm.h" -#include "Log.h" #include "MediaFoundationCdmFactory.h" #include "MediaFoundationCdmModule.h" #include "MediaFoundationCdmSession.h" +#include "Log.h" #include "utils/PMPHostWrapper.h" +MediaFoundationCdm::MediaFoundationCdm() = default; MediaFoundationCdm::~MediaFoundationCdm() = default; -bool MediaFoundationCdm::Initialize(const std::string &keySystem, - const std::string &basePath, - const media::CdmConfig &cdmConfig, - media::CdmAdapterClient* client) +bool MediaFoundationCdm::Initialize(const MediaFoundationCdmConfig& cdmConfig, + std::string_view keySystem, + std::string_view basePath) { bool ret = true; @@ -52,8 +52,6 @@ bool MediaFoundationCdm::Initialize(const std::string &keySystem, Log(MFCDM::MFLOG_DEBUG, "MF CDM created."); SetupPMPServer(); - - m_client = client; return true; } @@ -82,32 +80,36 @@ void MediaFoundationCdm::SetupPMPServer() const m_module->SetPMPHostApp(spIMFPMPHostApp.get()); } -void MediaFoundationCdm::SetServerCertificate(uint32_t promise_id, - const uint8_t* serverCertificateData, +bool MediaFoundationCdm::SetServerCertificate(const uint8_t* serverCertificateData, uint32_t serverCertificateDataSize) const { m_module->SetServerCertificate(serverCertificateData, serverCertificateDataSize); + return true; } -void MediaFoundationCdm::CreateSessionAndGenerateRequest(uint32_t promise_id, cdm::SessionType sessionType, - cdm::InitDataType initDataType, const uint8_t *init_data, - uint32_t init_data_size) +bool MediaFoundationCdm::CreateSessionAndGenerateRequest(SessionType sessionType, + InitDataType initDataType, + const std::vector& initData, + SessionClient* client) { - auto session = std::make_unique(); + auto session = std::make_unique(client); - if (!session->Initialize(sessionType, m_module.get())) + if (!session->Initialize(m_module.get(), sessionType)) { - Log(MFCDM::MFLOG_ERROR, "Failed to create session."); - return; + return false; } int session_token = next_session_token_++; - session->GenerateRequest(initDataType, init_data, init_data_size); + if (!session->GenerateRequest(initDataType, initData)) + { + return false; + } m_cdm_sessions.emplace(session_token, std::move(session)); + return true; } -void MediaFoundationCdm::LoadSession(cdm::SessionType session_type, +void MediaFoundationCdm::LoadSession(SessionType session_type, const std::string &session_id) { diff --git a/lib/mfcdm/mfcdm/MediaFoundationCdm.h b/lib/mfcdm/mfcdm/MediaFoundationCdm.h index 8e94af382..8798f9df5 100644 --- a/lib/mfcdm/mfcdm/MediaFoundationCdm.h +++ b/lib/mfcdm/mfcdm/MediaFoundationCdm.h @@ -9,52 +9,45 @@ #pragma once #include "MediaFoundationSession.h" +#include "MediaFoundationCdmConfig.h" +#include "MediaFoundationCdmTypes.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" +#include class MediaFoundationCdmSession; -class MediaFoundationCdmFactory; class MediaFoundationCdmModule; class MediaFoundationCdm { public: + MediaFoundationCdm(); ~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); + bool Initialize(const MediaFoundationCdmConfig& cdmConfig, + std::string_view keySystem, + std::string_view basePath); - void SetServerCertificate(uint32_t promise_id, - const uint8_t* serverCertificateData, + bool SetServerCertificate(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); + bool CreateSessionAndGenerateRequest(SessionType sessionType, + InitDataType initDataType, + const std::vector& initData, + SessionClient* client); + void LoadSession(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}; + std::unique_ptr m_module; int next_session_token_{0}; std::map> m_cdm_sessions; - - media::CdmAdapterClient* m_client{nullptr}; }; diff --git a/lib/mfcdm/mfcdm/MediaFoundationCdmFactory.cpp b/lib/mfcdm/mfcdm/MediaFoundationCdmFactory.cpp index 2ef9c4c94..636ebf055 100644 --- a/lib/mfcdm/mfcdm/MediaFoundationCdmFactory.cpp +++ b/lib/mfcdm/mfcdm/MediaFoundationCdmFactory.cpp @@ -10,53 +10,45 @@ #include "MediaFoundationCdmModule.h" #include "MediaFoundationCdm.h" -#include "Log.h" - #include "utils/ScopedPropVariant.h" - -#include -#include +#include "utils/Wide.h" +#include "Log.h" #include #include -#include -static void InitPropVariantFromBSTR(const wchar_t* str, PROPVARIANT* propvariant) { - propvariant->vt = VT_BSTR; - propvariant->bstrVal = SysAllocString(str); -} +using namespace UTILS; -static std::wstring ConvertUtf8ToWide(const std::string& str) +static void InitPropVariantFromBSTR(const wchar_t* str, PROPVARIANT* propVariant) { - const int count = - MultiByteToWideChar(CP_UTF8, 0, str.c_str(), static_cast(str.length()), nullptr, 0); - std::wstring wstr(count, 0); - MultiByteToWideChar(CP_UTF8, 0, str.c_str(), static_cast(str.length()), wstr.data(), - count); - return wstr; + propVariant->vt = VT_BSTR; + propVariant->bstrVal = SysAllocString(str); } -MediaFoundationCdmFactory::MediaFoundationCdmFactory(std::string key_system) - : m_keySystem(std::move(key_system)) +MediaFoundationCdmFactory::MediaFoundationCdmFactory(std::string_view keySystem) + : m_keySystem(keySystem) { } bool MediaFoundationCdmFactory::Initialize() { - const winrt::com_ptr class_factory = winrt::create_instance( - CLSID_MFMediaEngineClassFactory, CLSCTX_INPROC_SERVER); - const std::wstring key_system_str = ConvertUtf8ToWide(m_keySystem); + const winrt::com_ptr classFactory = winrt::create_instance( + CLSID_MFMediaEngineClassFactory, CLSCTX_INPROC_SERVER); + const std::wstring keySystemWide = ConvertUtf8ToWide(m_keySystem); - return SUCCEEDED(class_factory->CreateContentDecryptionModuleFactory( - key_system_str.c_str(), IID_PPV_ARGS(&m_cdmFactory))); + return SUCCEEDED(classFactory->CreateContentDecryptionModuleFactory( + keySystemWide.c_str(), IID_PPV_ARGS(&m_cdmFactory))); } -bool MediaFoundationCdmFactory::IsTypeSupported(const std::string &key_system) const { - return m_cdmFactory->IsTypeSupported(ConvertUtf8ToWide(key_system).c_str(), nullptr); +bool MediaFoundationCdmFactory::IsTypeSupported(std::string_view keySystem) const +{ + return m_cdmFactory->IsTypeSupported(ConvertUtf8ToWide(keySystem).c_str(), nullptr); } -// Returns a property store similar to EME MediaKeySystemMediaCapability. -bool CreateVideoCapability(const media::CdmConfig& cdm_config, +/*! + * \brief Returns a property store similar to EME MediaKeySystemMediaCapability. + */ +bool CreateVideoCapability(const MediaFoundationCdmConfig& cdm_config, winrt::com_ptr& video_capability) { winrt::com_ptr temp_video_capability; @@ -66,21 +58,24 @@ bool CreateVideoCapability(const media::CdmConfig& cdm_config, return false; } - ScopedPropVariant robustness; - if (cdm_config.use_hw_secure_codecs) { - PROPVARIANT* ptr = robustness.Receive(); - ptr->vt = VT_BSTR; - ptr->bstrVal = SysAllocString(L"HW_SECURE_ALL"); + if (cdm_config.use_hw_secure_codecs) + { + ScopedPropVariant robustness; + robustness->vt = VT_BSTR; + robustness->bstrVal = SysAllocString(L"HW_SECURE_ALL"); temp_video_capability->SetValue(MF_EME_ROBUSTNESS, robustness.get()); } + video_capability = temp_video_capability; + return true; } /*! + * \brief Creates a IPropertyStore for CDM based on cdm config settings. * \link https://github.com/chromium/chromium/blob/ea198b54e3f6b0cfdd6bacbb01c2307fd1797b63/media/cdm/win/media_foundation_cdm_util.cc#L68 * \link https://github.com/microsoft/media-foundation/blob/969f38b9fff9892f5d75bc353c72d213da807739/samples/MediaEngineEMEUWPSample/src/media/eme/MediaKeySystemConfiguration.cpp#L74 */ -bool BuildCdmAccessConfigurations(const media::CdmConfig& cdm_config, +bool BuildCdmAccessConfigurations(const MediaFoundationCdmConfig& cdmConfig, winrt::com_ptr& properties) { winrt::com_ptr temp_configurations; @@ -90,13 +85,10 @@ bool BuildCdmAccessConfigurations(const media::CdmConfig& cdm_config, return false; } - PROPVARIANT* receive; - // Add an empty audio capability. ScopedPropVariant audio_capabilities; - PROPVARIANT* var_to_set = audio_capabilities.Receive(); - var_to_set->vt = VT_VARIANT | VT_VECTOR; - var_to_set->capropvar.cElems = 0; + audio_capabilities->vt = VT_VARIANT | VT_VECTOR; + audio_capabilities->capropvar.cElems = 0; if (FAILED(temp_configurations->SetValue(MF_EME_AUDIOCAPABILITIES, audio_capabilities.get()))) { @@ -106,31 +98,30 @@ bool BuildCdmAccessConfigurations(const media::CdmConfig& cdm_config, // Add a video capability. winrt::com_ptr video_capability; - if (!CreateVideoCapability(cdm_config, video_capability)) + if (!CreateVideoCapability(cdmConfig, video_capability)) return false; - ScopedPropVariant video_config; - auto* video_config_ptr = video_config.Receive(); - video_config_ptr->vt = VT_UNKNOWN; - video_config_ptr->punkVal = video_capability.detach(); + ScopedPropVariant videoConfig; + videoConfig->vt = VT_UNKNOWN; + videoConfig->punkVal = video_capability.detach(); - ScopedPropVariant video_capabilities; - var_to_set = video_capabilities.Receive(); - var_to_set->vt = VT_VARIANT | VT_VECTOR; - var_to_set->capropvar.cElems = 1; - var_to_set->capropvar.pElems = - static_cast(CoTaskMemAlloc(sizeof(PROPVARIANT))); - if (!var_to_set->capropvar.pElems) - throw std::bad_alloc(); + ScopedPropVariant videoCapabilities; + videoCapabilities->vt = VT_VARIANT | VT_VECTOR; + videoCapabilities->capropvar.cElems = 1; + videoCapabilities->capropvar.pElems = static_cast(CoTaskMemAlloc(sizeof(PROPVARIANT))); + if (!videoCapabilities->capropvar.pElems) + { + Log(MFCDM::MFLOG_ERROR, "Failed to allocate video capability array."); + return false; + } - if (FAILED(PropVariantCopy(var_to_set->capropvar.pElems, video_config.ptr()))) + if (FAILED(PropVariantCopy(videoCapabilities->capropvar.pElems, videoConfig.ptr()))) { Log(MFCDM::MFLOG_ERROR, "Failed to set copy video config into video capabilities."); return false; } - if (FAILED( - temp_configurations->SetValue(MF_EME_VIDEOCAPABILITIES, video_capabilities.get()))) + if (FAILED(temp_configurations->SetValue(MF_EME_VIDEOCAPABILITIES, videoCapabilities.get()))) { Log(MFCDM::MFLOG_ERROR, "Failed to set persisted state."); return false; @@ -138,17 +129,15 @@ bool BuildCdmAccessConfigurations(const media::CdmConfig& cdm_config, // Persistent state ScopedPropVariant persisted_state; - - if (FAILED(InitPropVariantFromUInt32(cdm_config.allow_persistent_state + if (FAILED(InitPropVariantFromUInt32(cdmConfig.allow_persistent_state ? MF_MEDIAKEYS_REQUIREMENT_REQUIRED - : MF_MEDIAKEYS_REQUIREMENT_NOT_ALLOWED, - persisted_state.Receive()))) + : MF_MEDIAKEYS_REQUIREMENT_NOT_ALLOWED, + persisted_state.ptr()))) { Log(MFCDM::MFLOG_ERROR, "Failed to create prop variant for persistent state."); return false; } - if (FAILED(temp_configurations->SetValue(MF_EME_PERSISTEDSTATE, persisted_state.get()))) { Log(MFCDM::MFLOG_ERROR, "Failed to set persisted state."); @@ -157,20 +146,19 @@ bool BuildCdmAccessConfigurations(const media::CdmConfig& cdm_config, // Distinctive ID ScopedPropVariant allow_distinctive_identifier; - - if (FAILED(InitPropVariantFromUInt32(cdm_config.allow_distinctive_identifier + if (FAILED(InitPropVariantFromUInt32(cdmConfig.allow_distinctive_identifier ? MF_MEDIAKEYS_REQUIREMENT_REQUIRED : MF_MEDIAKEYS_REQUIREMENT_NOT_ALLOWED, - allow_distinctive_identifier.Receive()))) + allow_distinctive_identifier.ptr()))) { Log(MFCDM::MFLOG_ERROR, "Failed to create prop variant for distinctive identifier."); return false; } if (FAILED(temp_configurations->SetValue(MF_EME_DISTINCTIVEID, - allow_distinctive_identifier.get()))) + allow_distinctive_identifier.get()))) { - Log(MFCDM::MFLOG_ERROR, "Failed to set DISTINCTIVE id."); + Log(MFCDM::MFLOG_ERROR, "Failed to set distinctive identifier."); return false; } @@ -178,8 +166,9 @@ bool BuildCdmAccessConfigurations(const media::CdmConfig& cdm_config, return true; } -bool BuildCdmProperties(const std::filesystem::path& store_path, - winrt::com_ptr& properties) { +bool BuildCdmProperties(const std::filesystem::path& storePath, + winrt::com_ptr& properties) +{ winrt::com_ptr temp_properties; if (FAILED(PSCreateMemoryPropertyStore(IID_PPV_ARGS(&temp_properties)))) { @@ -187,10 +176,10 @@ bool BuildCdmProperties(const std::filesystem::path& store_path, return false; } - ScopedPropVariant store_path_var; - InitPropVariantFromBSTR(store_path.wstring().c_str(), store_path_var.Receive()); + ScopedPropVariant storePathVar; + InitPropVariantFromBSTR(storePath.wstring().c_str(), storePathVar.ptr()); - if (FAILED(temp_properties->SetValue(MF_EME_CDM_STOREPATH, store_path_var.get()))) + if (FAILED(temp_properties->SetValue(MF_EME_CDM_STOREPATH, storePathVar.get()))) { Log(MFCDM::MFLOG_ERROR, "Failed to set CDM Storage Path."); return false; @@ -200,45 +189,54 @@ bool BuildCdmProperties(const std::filesystem::path& store_path, return true; } -bool MediaFoundationCdmFactory::CreateMfCdm(const media::CdmConfig& cdm_config, - const std::filesystem::path& cdm_path, - std::unique_ptr& mf_cdm) const +bool MediaFoundationCdmFactory::CreateMfCdm(const MediaFoundationCdmConfig& cdmConfig, + const std::filesystem::path& cdmPath, + std::unique_ptr& mfCdm) const { const auto key_system_str = ConvertUtf8ToWide(m_keySystem); if (!m_cdmFactory->IsTypeSupported(key_system_str.c_str(), nullptr)) { - Log(MFCDM::MFLOG_ERROR, "%s not supported by MF CdmFactory", m_keySystem); + Log(MFCDM::MFLOG_ERROR, "%s is not supported by MF CdmFactory", m_keySystem); return false; } - if (!std::filesystem::create_directory(cdm_path) && !std::filesystem::exists(cdm_path)) - return false; - - winrt::com_ptr cdm_access; - - winrt::com_ptr property_store; - if (!BuildCdmAccessConfigurations(cdm_config, property_store)) + winrt::com_ptr cdmConfigProp; + if (!BuildCdmAccessConfigurations(cdmConfig, cdmConfigProp)) + { + Log(MFCDM::MFLOG_ERROR, "Failed to build cdm access configuration."); return false; + } - IPropertyStore* configurations[] = {property_store.get()}; + winrt::com_ptr cdmAccess; + IPropertyStore* configurations[] = {cdmConfigProp.get()}; if (FAILED(m_cdmFactory->CreateContentDecryptionModuleAccess( - key_system_str.c_str(), configurations, ARRAYSIZE(configurations), cdm_access.put()))) + key_system_str.c_str(), configurations, ARRAYSIZE(configurations), cdmAccess.put()))) { Log(MFCDM::MFLOG_ERROR, "Failed to create module access."); return false; } + + // Ensure path exists to the cdm path. + if (!std::filesystem::create_directory(cdmPath) && !std::filesystem::exists(cdmPath)) + { + Log(MFCDM::MFLOG_ERROR, "CDM Path %s doesn't exist.", cdmPath.string()); + return false; + } - winrt::com_ptr cdm_properties; - if (!BuildCdmProperties(cdm_path, cdm_properties)) + winrt::com_ptr cdmProperties; + if (!BuildCdmProperties(cdmPath, cdmProperties)) + { + Log(MFCDM::MFLOG_ERROR, "Failed to build cdm properties."); return false; + } winrt::com_ptr cdm; - if (FAILED(cdm_access->CreateContentDecryptionModule(cdm_properties.get(), cdm.put()))) + if (FAILED(cdmAccess->CreateContentDecryptionModule(cdmProperties.get(), cdm.put()))) { Log(MFCDM::MFLOG_ERROR, "Failed to create cdm module."); return false; } - mf_cdm = std::make_unique(cdm); + mfCdm = std::make_unique(cdm); return true; } diff --git a/lib/mfcdm/mfcdm/MediaFoundationCdmFactory.h b/lib/mfcdm/mfcdm/MediaFoundationCdmFactory.h index 5e127dbce..eaab6b2cc 100644 --- a/lib/mfcdm/mfcdm/MediaFoundationCdmFactory.h +++ b/lib/mfcdm/mfcdm/MediaFoundationCdmFactory.h @@ -8,6 +8,8 @@ #pragma once +#include "MediaFoundationCdmConfig.h" + #include #include #include @@ -18,20 +20,18 @@ #include #include -#include - class MediaFoundationCdmModule; class MediaFoundationCdmFactory { public: - explicit MediaFoundationCdmFactory(std::string key_system); + explicit MediaFoundationCdmFactory(std::string_view keySystem); bool Initialize(); - bool IsTypeSupported(const std::string& key_system) const; + bool IsTypeSupported(std::string_view keySystem) const; - bool CreateMfCdm(const media::CdmConfig& cdm_config, - const std::filesystem::path& cdm_path, - std::unique_ptr& mf_cdm) const; + bool CreateMfCdm(const MediaFoundationCdmConfig& cdmConfig, + const std::filesystem::path& cdmPath, + std::unique_ptr& mfCdm) const; private: std::string m_keySystem; diff --git a/lib/mfcdm/mfcdm/MediaFoundationCdmSession.cpp b/lib/mfcdm/mfcdm/MediaFoundationCdmSession.cpp index ee494c77d..dfc351a26 100644 --- a/lib/mfcdm/mfcdm/MediaFoundationCdmSession.cpp +++ b/lib/mfcdm/mfcdm/MediaFoundationCdmSession.cpp @@ -9,8 +9,11 @@ #include "MediaFoundationCdmSession.h" #include "MediaFoundationCdmModule.h" +#include "utils/ScopedCoMem.h" +#include "utils/Wide.h" #include "Log.h" +#include #include #include @@ -19,13 +22,15 @@ #include #include -MF_MEDIAKEYSESSION_TYPE ToMFSessionType(cdm::SessionType session_type) +using namespace UTILS; + +MF_MEDIAKEYSESSION_TYPE ToMFSessionType(SessionType session_type) { switch (session_type) { - case cdm::SessionType::kPersistentLicense: + case MFPersistentLicense: return MF_MEDIAKEYSESSION_TYPE_PERSISTENT_LICENSE; - case cdm::SessionType::kTemporary: + case MFTemporary: default: return MF_MEDIAKEYSESSION_TYPE_TEMPORARY; } @@ -34,35 +39,56 @@ MF_MEDIAKEYSESSION_TYPE ToMFSessionType(cdm::SessionType session_type) /*! * \link https://www.w3.org/TR/eme-initdata-registry/ */ -LPCWSTR InitDataTypeToString(cdm::InitDataType init_data_type) +LPCWSTR InitDataTypeToString(InitDataType init_data_type) { switch (init_data_type) { - case cdm::InitDataType::kWebM: + case MFWebM: return L"webm"; - case cdm::InitDataType::kCenc: + case MFCenc: return L"cenc"; - case cdm::InitDataType::kKeyIds: + case MFKeyIds: return L"keyids"; default: return L"unknown"; } } +KeyStatus ToCdmKeyStatus(MF_MEDIAKEY_STATUS status) +{ + switch (status) + { + case MF_MEDIAKEY_STATUS_USABLE: + return MFKeyUsable; + case MF_MEDIAKEY_STATUS_EXPIRED: + return MFKeyExpired; + // This is for legacy use and should not happen in normal cases. Map it to + // internal error in case it happens. + case MF_MEDIAKEY_STATUS_OUTPUT_NOT_ALLOWED: + return MFKeyError; + case MF_MEDIAKEY_STATUS_INTERNAL_ERROR: + return MFKeyError; + } +} + class SessionCallbacks : public winrt::implements< SessionCallbacks, IMFContentDecryptionModuleSessionCallbacks> { -public: - SessionCallbacks() = default; + public: + using SessionMessage = + std::function& message, std::string_view destinationUrl)>; + + SessionCallbacks(SessionMessage sessionMessage) : m_sessionMessage(std::move(sessionMessage)){}; IFACEMETHODIMP KeyMessage(MF_MEDIAKEYSESSION_MESSAGETYPE message_type, const BYTE* message, DWORD message_size, LPCWSTR destination_url) final { - std::wstring messageStr = std::wstring(reinterpret_cast(message), message_size); - //std::wcout << "KeyMessage: " << messageStr << std::endl; - Log(MFCDM::MFLOG_DEBUG, "Destination Url %S", destination_url); + Log(MFCDM::MFLOG_DEBUG, "Message size: %d Destination Url: %S", + message_size, destination_url); + m_sessionMessage(std::vector(message, message + message_size), + ConvertWideToUTF8(destination_url)); return S_OK; } @@ -71,15 +97,24 @@ class SessionCallbacks : public winrt::implements< std::cout << "KeyStatusChanged" << std::endl; return S_OK; } +private: + SessionMessage m_sessionMessage; }; -bool MediaFoundationCdmSession::Initialize(cdm::SessionType session_type, - MediaFoundationCdmModule* mf_cdm) +MediaFoundationCdmSession::MediaFoundationCdmSession(SessionClient* client) + : m_client(client) { - const winrt::com_ptr - session_callbacks = winrt::make(); + assert(m_client != nullptr); +} + +bool MediaFoundationCdmSession::Initialize(MediaFoundationCdmModule* mfCdm, + SessionType sessionType) +{ + const auto session_callbacks = winrt::make( + std::bind(&MediaFoundationCdmSession::OnSessionMessage, this, std::placeholders::_1, std::placeholders::_2) + ); // |mf_cdm_session_| holds a ref count to |session_callbacks|. - if (FAILED(mf_cdm->CreateSession(ToMFSessionType(session_type), session_callbacks.get(), + if (FAILED(mfCdm->CreateSession(ToMFSessionType(sessionType), session_callbacks.get(), mfCdmSession.put()))) { Log(MFCDM::MFLOG_ERROR, "Failed to create MF CDM session."); @@ -88,14 +123,45 @@ bool MediaFoundationCdmSession::Initialize(cdm::SessionType session_type, return true; } -void MediaFoundationCdmSession::GenerateRequest(cdm::InitDataType init_data_type, const uint8_t *init_data, - uint32_t init_data_size) +bool MediaFoundationCdmSession::GenerateRequest(InitDataType initDataType, + const std::vector& initData) { - if (FAILED(mfCdmSession->GenerateRequest(InitDataTypeToString(init_data_type), init_data, - init_data_size))) + if (FAILED(mfCdmSession->GenerateRequest(InitDataTypeToString(initDataType), initData.data(), + static_cast(initData.size())))) { Log(MFCDM::MFLOG_ERROR, "Failed to generate MF CDM request."); - return; + return false; + } + return true; +} + +bool MediaFoundationCdmSession::Update(const std::vector& response) +{ + if (FAILED(mfCdmSession->Update(response.data(), static_cast(response.size())))) + { + Log(MFCDM::MFLOG_ERROR, "Failed to update MF CDM with response."); + return false; } - + return true; } + +void MediaFoundationCdmSession::OnSessionMessage(const std::vector& message, + std::string_view destinationUrl) const +{ + if (!m_client) + return; + m_client->OnSessionMessage(GetSessionId(), message, destinationUrl); +} + +std::string MediaFoundationCdmSession::GetSessionId() const +{ + ScopedCoMem sessionId; + + if (FAILED(mfCdmSession->GetSessionId(&sessionId))) + { + Log(MFCDM::MFLOG_ERROR, "Failed to grab MF session's id."); + return ""; + } + + return ConvertWideToUTF8(sessionId.get()); +} \ No newline at end of file diff --git a/lib/mfcdm/mfcdm/MediaFoundationCdmSession.h b/lib/mfcdm/mfcdm/MediaFoundationCdmSession.h index 90e8fc07a..8cfd04c4e 100644 --- a/lib/mfcdm/mfcdm/MediaFoundationCdmSession.h +++ b/lib/mfcdm/mfcdm/MediaFoundationCdmSession.h @@ -8,21 +8,31 @@ #pragma once +#include "MediaFoundationCdmTypes.h" + #include #include #include #include -#include - class MediaFoundationCdmModule; class MediaFoundationCdmSession { public: - bool Initialize(cdm::SessionType session_type, MediaFoundationCdmModule* mf_cdm); - void GenerateRequest(cdm::InitDataType init_data_type, - const uint8_t* init_data, uint32_t init_data_size); + MediaFoundationCdmSession(SessionClient* client); + + bool Initialize(MediaFoundationCdmModule* mfCdm, SessionType sessionType); + + bool GenerateRequest(InitDataType initDataType, const std::vector& initData); + bool Update(const std::vector& response); + + std::string GetSessionId() const; + private: - winrt::com_ptr mfCdmSession; + + void OnSessionMessage(const std::vector& message, std::string_view destinationUrl) const; + + winrt::com_ptr mfCdmSession; + SessionClient* m_client; }; diff --git a/lib/mfcdm/mfcdm/MediaFoundationCdmTypes.h b/lib/mfcdm/mfcdm/MediaFoundationCdmTypes.h new file mode 100644 index 000000000..f978f8341 --- /dev/null +++ b/lib/mfcdm/mfcdm/MediaFoundationCdmTypes.h @@ -0,0 +1,43 @@ +/* + * 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 +#include +#include + +#pragma once + +enum SessionType : uint32_t +{ + MFTemporary = 0, + MFPersistentLicense = 1 +}; + +enum InitDataType : uint32_t +{ + MFCenc = 0, + MFKeyIds = 1, + MFWebM = 2 +}; + +enum KeyStatus : uint32_t +{ + MFKeyUsable = 0, + MFKeyExpired = 1, + MFKeyError = 2 +}; + +class SessionClient +{ +public: + virtual ~SessionClient() = default; + + virtual void OnSessionMessage(std::string_view session, + const std::vector& message, + std::string_view destinationUrl) = 0; +}; diff --git a/lib/mfcdm/mfcdm/utils/PMPHostWrapper.h b/lib/mfcdm/mfcdm/utils/PMPHostWrapper.h index 3b0bc66f0..3ce2a8d7d 100644 --- a/lib/mfcdm/mfcdm/utils/PMPHostWrapper.h +++ b/lib/mfcdm/mfcdm/utils/PMPHostWrapper.h @@ -33,31 +33,34 @@ class PMPHostWrapper : public winrt::implements { } IFACEMETHODIMP ActivateClassById(LPCWSTR id, IStream* stream, REFIID riid, void** activated_class) override { - HRESULT ret; + HRESULT ret = S_OK; wchar_t guid[MAX_PATH] = {}; - StringFromGUID2(riid, guid, std::size(guid)); + StringFromGUID2(riid, guid, MAX_PATH); winrt::com_ptr creation_attributes; ret = MFCreateAttributes(creation_attributes.put(), 3); if (FAILED(ret)) return ret; + ret = creation_attributes->SetString(GUID_ClassName, id); if (FAILED(ret)) return ret; if (stream) { - STATSTG statstg; - ret = stream->Stat(&statstg, STATFLAG_NOOPEN | STATFLAG_NONAME); + STATSTG statStg; + + ret = stream->Stat(&statStg, STATFLAG_NOOPEN | STATFLAG_NONAME); if (FAILED(ret)) return ret; - std::vector stream_blob(statstg.cbSize.LowPart); - unsigned long read_size = 0; + std::vector stream_blob(statStg.cbSize.LowPart); + ULONG read_size = 0; - ret = stream->Read(&stream_blob[0], stream_blob.size(), &read_size); + ret = stream->Read(&stream_blob[0], static_cast(stream_blob.size()), &read_size); if (FAILED(ret)) return ret; + ret = creation_attributes->SetBlob(GUID_ObjectStream, &stream_blob[0], read_size); if (FAILED(ret)) return ret; @@ -68,21 +71,25 @@ class PMPHostWrapper : public winrt::implements { ret = CreateStreamOnHGlobal(nullptr, TRUE, output_stream.put()); if (FAILED(ret)) return ret; + ret = MFSerializeAttributesToStream(creation_attributes.get(), 0, output_stream.get()); if (FAILED(ret)) return ret; + ret = output_stream->Seek({}, STREAM_SEEK_SET, nullptr); if (FAILED(ret)) return ret; winrt::com_ptr activator; ret = m_spIMFPMPHost->CreateObjectByCLSID(CLSID_EMEStoreActivate, output_stream.get(), - IID_PPV_ARGS(&activator)); + IID_PPV_ARGS(&activator)); if (FAILED(ret)) return ret; + ret = activator->ActivateObject(riid, activated_class); if (FAILED(ret)) return ret; + return S_OK; } private: diff --git a/lib/mfcdm/mfcdm/utils/ScopedCoMem.h b/lib/mfcdm/mfcdm/utils/ScopedCoMem.h new file mode 100644 index 000000000..1ea5f9d47 --- /dev/null +++ b/lib/mfcdm/mfcdm/utils/ScopedCoMem.h @@ -0,0 +1,44 @@ +/* + * 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 + +namespace UTILS +{ + +/*! + * \brief Class to automatically release memory allocated in COM. + */ +template +class ScopedCoMem +{ +public: + ScopedCoMem() : m_ptr(nullptr) {} + + ~ScopedCoMem() { Reset(); } + + ScopedCoMem(const ScopedCoMem&) = delete; + ScopedCoMem& operator=(const ScopedCoMem&) = delete; + + inline T* operator->() { return m_ptr; } + inline T** operator&() { return &m_ptr; } + + void Reset() + { + if (m_ptr) + CoTaskMemFree(m_ptr); + m_ptr = nullptr; + } + + T* get() const { return m_ptr; } + +private: + T* m_ptr; +}; + +} // namespace UTILS diff --git a/lib/mfcdm/mfcdm/utils/ScopedPropVariant.h b/lib/mfcdm/mfcdm/utils/ScopedPropVariant.h index 075cd000d..ca64cc958 100644 --- a/lib/mfcdm/mfcdm/utils/ScopedPropVariant.h +++ b/lib/mfcdm/mfcdm/utils/ScopedPropVariant.h @@ -1,47 +1,78 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE 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 #include +namespace UTILS +{ + /*! - * \brief A MS PROPVARIANT that is automatically initialized and cleared upon respective - * construction and destruction of this class. + * \brief A MS PROPVARIANT that is automatically initialized and cleared + * upon respective construction and destruction of this class. */ -class ScopedPropVariant { +class ScopedPropVariant +{ public: - ScopedPropVariant() { PropVariantInit(&pv_); } + ScopedPropVariant() { PropVariantInit(&pv_); } - ScopedPropVariant(const ScopedPropVariant&) = delete; - ScopedPropVariant& operator=(const ScopedPropVariant&) = delete; + ScopedPropVariant(const ScopedPropVariant&) = delete; + ScopedPropVariant& operator=(const ScopedPropVariant&) = delete; - ~ScopedPropVariant() { Reset(); } + ~ScopedPropVariant() { Reset(); } - /*! - * \brief Returns a pointer to the underlying PROPVARIANT. - * Example: Use as an out param in a function call. + /*! + * \brief Clears the instance & prepares it for re-use (e.g., via Receive). */ - PROPVARIANT* Receive() { - assert(pv_.vt == VT_EMPTY); - return &pv_; - } + void Reset() + { + if (pv_.vt == VT_EMPTY) + return; + + HRESULT result = PropVariantClear(&pv_); + assert(result == S_OK); + } + + inline PROPVARIANT* operator->() { return &pv_; } - /*! - * \brief Clears the instance to prepare it for re-use (e.g., via Receive). + const PROPVARIANT& get() const + { + assert(pv_.vt == VT_EMPTY); + return pv_; + } + + /*! + * \brief Returns a pointer to the underlying PROPVARIANT. + * Example: Use as an out param in a function call. */ - void Reset() { - if (pv_.vt != VT_EMPTY) { - HRESULT result = PropVariantClear(&pv_); - assert(result == S_OK); - } - } + PROPVARIANT* ptr() + { + assert(pv_.vt == VT_EMPTY); + return &pv_; + } + + PROPVARIANT release() noexcept + { + PROPVARIANT value(pv_); + PropVariantInit(&pv_); + return value; + } - [[nodiscard]] const PROPVARIANT& get() const { return pv_; } - [[nodiscard]] const PROPVARIANT* ptr() const { return &pv_; } + const PROPVARIANT* ptr() const + { + assert(pv_.vt == VT_EMPTY); + return &pv_; + } private: - PROPVARIANT pv_; + PROPVARIANT pv_; }; + +} // namespace UTILS diff --git a/lib/mfcdm/mfcdm/utils/Wide.h b/lib/mfcdm/mfcdm/utils/Wide.h new file mode 100644 index 000000000..20c016ef9 --- /dev/null +++ b/lib/mfcdm/mfcdm/utils/Wide.h @@ -0,0 +1,42 @@ +/* + * 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 + +#include + +namespace UTILS +{ + + static std::wstring ConvertUtf8ToWide(std::string_view str) + { + const int charCount = + MultiByteToWideChar(CP_UTF8, 0, str.data(), static_cast(str.length()), nullptr, 0); + if (charCount <= 0) + return {}; + + std::wstring wide(charCount, 0); + MultiByteToWideChar(CP_UTF8, 0, str.data(), static_cast(str.length()), wide.data(), + charCount); + return wide; + } + + static std::string ConvertWideToUTF8(std::wstring_view wstr) + { + const int charCount = + WideCharToMultiByte(CP_UTF8, 0, wstr.data(), static_cast(wstr.length()), nullptr, 0, nullptr, nullptr); + if (charCount <= 0) + return {}; + + std::string str(charCount, 0); + WideCharToMultiByte(CP_UTF8, 0, wstr.data(), static_cast(wstr.length()), str.data(), + charCount, nullptr, nullptr); + return str; + } + +} //namespace UTILS diff --git a/src/decrypters/mediafoundation/MFCencSingleSampleDecrypter.cpp b/src/decrypters/mediafoundation/MFCencSingleSampleDecrypter.cpp index 40636f0af..f8cd27cca 100644 --- a/src/decrypters/mediafoundation/MFCencSingleSampleDecrypter.cpp +++ b/src/decrypters/mediafoundation/MFCencSingleSampleDecrypter.cpp @@ -15,6 +15,7 @@ #include "../../utils/StringUtils.h" #include "../../utils/Utils.h" #include "../../utils/log.h" +#include "pugixml.hpp" #include "MFDecrypter.h" #include "mfcdm/MediaFoundationCdm.h" @@ -22,21 +23,10 @@ #include #include +using namespace pugi; using namespace kodi::tools; using namespace UTILS; -void CMFCencSingleSampleDecrypter::SetSession(const char* session, - uint32_t sessionSize, - const uint8_t* data, - size_t dataSize) -{ - std::lock_guard lock(m_renewalLock); - - m_strSession = std::string(session, sessionSize); - m_challenge.SetData(data, dataSize); - LOG::LogF(LOGDEBUG, "Opened widevine session ID: %s", m_strSession.c_str()); -} - CMFCencSingleSampleDecrypter::CMFCencSingleSampleDecrypter(CMFDecrypter& host, std::vector& pssh, std::string_view defaultKeyId, @@ -69,7 +59,7 @@ CMFCencSingleSampleDecrypter::CMFCencSingleSampleDecrypter(CMFDecrypter& host, FILESYS::PathCombine(m_host.GetProfilePath(), "9A04F079-9840-4286-AB92-E65BE0885F95.init"); std::string data{reinterpret_cast(pssh.data()), pssh.size()}; - UTILS::FILESYS::SaveFile(debugFilePath, data, true); + FILESYS::SaveFile(debugFilePath, data, true); } // No cenc init data with PSSH box format, create one @@ -97,9 +87,7 @@ CMFCencSingleSampleDecrypter::CMFCencSingleSampleDecrypter(CMFDecrypter& host, m_pssh = psshAtom; } - m_host.GetCdm()->CreateSessionAndGenerateRequest( - m_promiseId++, cdm::SessionType::kTemporary, cdm::InitDataType::kCenc, - m_pssh.data(), m_pssh.size()); + m_host.GetCdm()->CreateSessionAndGenerateRequest(MFTemporary, MFCenc, m_pssh, this); int retryCount = 0; while (m_strSession.empty() && ++retryCount < 100) @@ -118,6 +106,42 @@ CMFCencSingleSampleDecrypter::CMFCencSingleSampleDecrypter(CMFDecrypter& host, ; } +void CMFCencSingleSampleDecrypter::OnSessionMessage(std::string_view session, + const std::vector& message, + std::string_view destinationUrl) +{ + xml_document doc; + + // Load wide string XML + xml_parse_result parseRes = doc.load_buffer(message.data(), message.size()); + if (parseRes.status != status_ok) + { + LOG::LogF(LOGERROR, "Failed to parse PlayReady session message", parseRes.status); + return; + } + + if (m_host.IsDebugSaveLicense()) + { + std::string debugFilePath = + FILESYS::PathCombine(m_host.GetProfilePath(), "9A04F079-9840-4286-AB92-E65BE0885F95.message"); + + doc.save_file(debugFilePath.c_str()); + } + + xml_node nodeKeyMessage = doc.child("PlayReadyKeyMessage"); + if (!nodeKeyMessage) + { + LOG::LogF(LOGERROR, "Failed to get Playready's tag element."); + return; + } + + std::lock_guard lock(m_renewalLock); + + m_strSession = session; + //m_challenge.SetData(message.data(), message.size()); + LOG::LogF(LOGDEBUG, "Opened playready session ID: %s", m_strSession.c_str()); +} + CMFCencSingleSampleDecrypter::~CMFCencSingleSampleDecrypter() { //m_wvCdmAdapter.removessd(this); @@ -157,7 +181,7 @@ void CMFCencSingleSampleDecrypter::CloseSessionId() { if (!m_strSession.empty()) { - LOG::LogF(LOGDEBUG, "Closing widevine session ID: %s", m_strSession.c_str()); + LOG::LogF(LOGDEBUG, "Closing MF session ID: %s", m_strSession.c_str()); //m_wvCdmAdapter.GetCdmAdapter()->CloseSession(++m_promiseId, m_strSession.data(), // m_strSession.size()); @@ -199,7 +223,7 @@ bool CMFCencSingleSampleDecrypter::SendSessionMessage() m_host.GetProfilePath(), "9A04F079-9840-4286-AB92-E65BE0885F95.challenge"); std::string data{reinterpret_cast(m_challenge.GetData()), m_challenge.GetDataSize()}; - UTILS::FILESYS::SaveFile(debugFilePath, data, true); + FILESYS::SaveFile(debugFilePath, data, true); } //Process placeholder in GET String @@ -449,7 +473,7 @@ void CMFCencSingleSampleDecrypter::AddSessionKey(const uint8_t* data, key.m_keyId = std::string((const char*)data, dataSize); if ((res = std::find(m_keys.begin(), m_keys.end(), key)) == m_keys.end()) res = m_keys.insert(res, key); - res->status = static_cast(status); + res->status = static_cast(status); } bool CMFCencSingleSampleDecrypter::HasKeyId(std::string_view keyid) @@ -504,28 +528,6 @@ void CMFCencSingleSampleDecrypter::RemovePool(AP4_UI32 poolId) m_fragmentPool[poolId].m_key.clear(); } -void CMFCencSingleSampleDecrypter::LogDecryptError(const cdm::Status status, const AP4_UI08* key) -{ - char buf[36]; - buf[32] = 0; - AP4_FormatHex(key, 16, buf); - LOG::LogF(LOGDEBUG, "Decrypt failed with error: %d and key: %s", status, buf); -} - -void CMFCencSingleSampleDecrypter::SetCdmSubsamples(std::vector& subsamples, - bool isCbc) -{ - if (isCbc) - { - subsamples.resize(1); - subsamples[0] = {0, m_decryptIn.GetDataSize()}; - } - else - { - subsamples.push_back({0, m_decryptIn.GetDataSize()}); - } -} - void CMFCencSingleSampleDecrypter::RepackSubsampleData(AP4_DataBuffer& dataIn, AP4_DataBuffer& dataOut, size_t& pos, @@ -552,27 +554,6 @@ void CMFCencSingleSampleDecrypter::UnpackSubsampleData(AP4_DataBuffer& dataIn, pos += bytesOfEncryptedData[subsamplePos]; } -void CMFCencSingleSampleDecrypter::SetInput(cdm::InputBuffer_2& cdmInputBuffer, - const AP4_DataBuffer& inputData, - const unsigned int subsampleCount, - const uint8_t* iv, - const FINFO& fragInfo, - const std::vector& subsamples) -{ - cdmInputBuffer.data = inputData.GetData(); - cdmInputBuffer.data_size = inputData.GetDataSize(); - cdmInputBuffer.num_subsamples = subsampleCount; - cdmInputBuffer.iv = iv; - cdmInputBuffer.iv_size = 16; //Always 16, see AP4_CencSingleSampleDecrypter declaration. - cdmInputBuffer.key_id = fragInfo.m_key.data(); - cdmInputBuffer.key_id_size = 16; - cdmInputBuffer.subsamples = subsamples.data(); - //cdmInputBuffer.encryption_scheme = media::ToCdmEncryptionScheme(fragInfo.m_cryptoInfo.m_mode); - cdmInputBuffer.timestamp = 0; - cdmInputBuffer.pattern = {fragInfo.m_cryptoInfo.m_cryptBlocks, - fragInfo.m_cryptoInfo.m_skipBlocks}; -} - /*---------------------------------------------------------------------- | CWVCencSingleSampleDecrypter::DecryptSampleData +---------------------------------------------------------------------*/ @@ -619,7 +600,7 @@ void CMFCencSingleSampleDecrypter::AddKeyId(std::string_view keyId) { WVSKEY key; key.m_keyId = keyId; - key.status = cdm::KeyStatus::kUsable; + key.status = MFKeyUsable; if (std::find(m_keys.begin(), m_keys.end(), key) == m_keys.end()) { diff --git a/src/decrypters/mediafoundation/MFCencSingleSampleDecrypter.h b/src/decrypters/mediafoundation/MFCencSingleSampleDecrypter.h index 9537bb04b..472e90959 100644 --- a/src/decrypters/mediafoundation/MFCencSingleSampleDecrypter.h +++ b/src/decrypters/mediafoundation/MFCencSingleSampleDecrypter.h @@ -10,7 +10,8 @@ #include "../../common/AdaptiveCencSampleDecrypter.h" #include "../IDecrypter.h" -#include "cdm/media/cdm/api/content_decryption_module.h" + +#include #include #include @@ -19,14 +20,10 @@ class CMFDecrypter; class CWVCdmAdapter; -namespace media -{ -class CdmVideoFrame; -} - using namespace DRM; -class ATTR_DLL_LOCAL CMFCencSingleSampleDecrypter : public Adaptive_CencSingleSampleDecrypter +class ATTR_DLL_LOCAL CMFCencSingleSampleDecrypter : public Adaptive_CencSingleSampleDecrypter, + public SessionClient { public: // methods @@ -35,7 +32,7 @@ class ATTR_DLL_LOCAL CMFCencSingleSampleDecrypter : public Adaptive_CencSingleSa std::string_view defaultKeyId, bool skipSessionMessage, CryptoMode cryptoMode); - virtual ~CMFCencSingleSampleDecrypter(); + ~CMFCencSingleSampleDecrypter() override; void GetCapabilities(std::string_view key, uint32_t media, @@ -45,7 +42,9 @@ class ATTR_DLL_LOCAL CMFCencSingleSampleDecrypter : public Adaptive_CencSingleSa void CloseSessionId(); AP4_DataBuffer GetChallengeData(); - void SetSession(const char* session, uint32_t sessionSize, const uint8_t* data, size_t dataSize); + void OnSessionMessage(std::string_view session, + const std::vector& message, + std::string_view destinationUrl) override; void AddSessionKey(const uint8_t* data, size_t dataSize, uint32_t status); bool HasKeyId(std::string_view keyid); @@ -100,7 +99,7 @@ class ATTR_DLL_LOCAL CMFCencSingleSampleDecrypter : public Adaptive_CencSingleSa { bool operator==(WVSKEY const& other) const { return m_keyId == other.m_keyId; }; std::string m_keyId; - cdm::KeyStatus status; + KeyStatus status; }; std::vector m_keys; @@ -120,8 +119,8 @@ class ATTR_DLL_LOCAL CMFCencSingleSampleDecrypter : public Adaptive_CencSingleSa CryptoInfo m_cryptoInfo; }; std::vector m_fragmentPool; - void LogDecryptError(const cdm::Status status, const AP4_UI08* key); - void SetCdmSubsamples(std::vector& subsamples, bool isCbc); + //void LogDecryptError(const cdm::Status status, const AP4_UI08* key); + //void SetCdmSubsamples(std::vector& subsamples, bool isCbc); void RepackSubsampleData(AP4_DataBuffer& dataIn, AP4_DataBuffer& dataOut, size_t& startPos, @@ -134,19 +133,19 @@ class ATTR_DLL_LOCAL CMFCencSingleSampleDecrypter : public Adaptive_CencSingleSa const unsigned int subsamplePos, const AP4_UI16* bytesOfCleartextData, const AP4_UI32* bytesOfEncryptedData); - void SetInput(cdm::InputBuffer_2& cdmInputBuffer, - const AP4_DataBuffer& inputData, - const unsigned int subsampleCount, - const uint8_t* iv, - const FINFO& fragInfo, - const std::vector& subsamples); + //void SetInput(cdm::InputBuffer_2& cdmInputBuffer, + // const AP4_DataBuffer& inputData, + // const unsigned int subsampleCount, + // const uint8_t* iv, + // const FINFO& fragInfo, + // const std::vector& subsamples); uint32_t m_promiseId; bool m_isDrained; - std::list m_videoFrames; + //std::list m_videoFrames; std::mutex m_renewalLock; CryptoMode m_EncryptionMode; - std::optional m_currentVideoDecConfig; + //std::optional m_currentVideoDecConfig; }; diff --git a/src/decrypters/mediafoundation/MFDecrypter.cpp b/src/decrypters/mediafoundation/MFDecrypter.cpp index c417ace8a..e1b6962c4 100644 --- a/src/decrypters/mediafoundation/MFDecrypter.cpp +++ b/src/decrypters/mediafoundation/MFDecrypter.cpp @@ -4,8 +4,6 @@ #include "../../utils/log.h" #include -#include -#include #include #include @@ -57,7 +55,7 @@ CMFDecrypter::~CMFDecrypter() bool CMFDecrypter::Initialize() { m_cdm = new MediaFoundationCdm(); - return m_cdm != NULL; + return m_cdm != nullptr; } std::string CMFDecrypter::SelectKeySytem(std::string_view keySystem) @@ -80,8 +78,8 @@ bool CMFDecrypter::OpenDRMSystem(std::string_view licenseURL, return false; } - return m_cdm->Initialize("com.microsoft.playready.recommendation", m_strProfilePath, {true, true}, - nullptr); + return m_cdm->Initialize({true, true}, "com.microsoft.playready.recommendation", + m_strProfilePath); } Adaptive_CencSingleSampleDecrypter* CMFDecrypter::CreateSingleSampleDecrypter( diff --git a/src/parser/DASHTree.cpp b/src/parser/DASHTree.cpp index 365ae900a..0e454f8a1 100644 --- a/src/parser/DASHTree.cpp +++ b/src/parser/DASHTree.cpp @@ -1298,6 +1298,7 @@ bool adaptive::CDashTree::ParseTagContentProtection(pugi::xml_node nodeParent, PRProtectionParser parser; if (parser.ParseHeader(node.child_value())) protScheme.kid = parser.GetKID(); + protScheme.pssh = node.child_value(); } } protectionSchemes.emplace_back(protScheme);