Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -164,14 +164,7 @@ msgctxt "#30171"
msgid "Defines the initial bandwidth when it cannot be automatically determined. This value can be overridden by the minimum bandwidth setting."
msgstr ""

msgctxt "#30172"
msgid "Ignore HDCP status"
msgstr ""

#. Description of setting with label #30172
msgctxt "#30173"
msgid "Some DRM-protected HD / UHD videos may only be played if the HDCP status is ignored."
msgstr ""
#empty strings from id 30171 to 30173

#. To set the stream selection type (refer to RepresentationChooser's)
msgctxt "#30174"
Expand Down
7 changes: 0 additions & 7 deletions inputstream.adaptive/resources/settings.xml.in
Original file line number Diff line number Diff line change
Expand Up @@ -161,13 +161,6 @@
</control>
</setting>
</group>
<group id="misc">
<setting id="HDCPOVERRIDE" type="boolean" label="30172" help="30173">
<level>1</level>
<default>false</default>
<control type="toggle" />
</setting>
</group>
</category>
<category id="expert" label="30120">
<group id="misc">
Expand Down
11 changes: 10 additions & 1 deletion plugin.video.isasamples/menu_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,7 @@
'drm': '{"org.w3.clearkey": {"license": {"keyids": {"feedf00deedeadbeeff0baadf00dd00d": "00112233445566778899aabbccddeeff", "1234f00deedeadbeeff0baadf00dd00d": "8899aabbccddeeff8899aabbccddeeff"}}}}',
}
},
'Bitmovin art of motion [widevine to clear key, keys on property]': {
'Bitmovin art of motion [WV to CK, keys on property]': {
SI_ENCRYPT: 'DRMCK',
SI_INFO: 'Override widevine content protection to use clear key',
SI_CONFIG: {
Expand Down Expand Up @@ -587,6 +587,15 @@
'drm': '{"com.microsoft.playready": {"license": {"server_url": "https://test.playready.microsoft.com/service/rightsmanager.asmx?cfg=(persist:false,sl:150)"}}}'
}
},
'Microsoft tears of steel 4k [PR to CK, keys on property]': {
SI_ENCRYPT: 'DRMCK',
SI_INFO: 'Override PlayReady content protection to use ClearKey',
SI_CONFIG: {
'manifest_url': 'https://test.playready.microsoft.com/media/profficialsite/tearsofsteel_4k.ism.smoothstreaming/manifest',
'drm_legacy': 'org.w3.clearkey|6f651ae1dbe44434bcb4690d1564c41c:88da852ae4fa2e1e36aeb2d5c94997b1',
'drm': '{"org.w3.clearkey": {"license": {"keyids": {"6f651ae1dbe44434bcb4690d1564c41c": "88da852ae4fa2e1e36aeb2d5c94997b1"}}}}',
}
},
},
'ISM Live': {
MI_CONFIG: {},
Expand Down
107 changes: 82 additions & 25 deletions src/CompKodiProps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,13 @@
#include <rapidjson/document.h>

using namespace UTILS;
using namespace ADP::KODI_PROPS;

namespace
{
// clang-format off
constexpr std::string_view PROP_LICENSE_TYPE = "inputstream.adaptive.license_type"; //! @todo: to be deprecated
constexpr std::string_view PROP_LICENSE_KEY = "inputstream.adaptive.license_key"; //! @todo: to be deprecated
constexpr std::string_view PROP_LICENSE_TYPE = "inputstream.adaptive.license_type"; //! @todo: deprecated to be removed on Kodi 23
constexpr std::string_view PROP_LICENSE_KEY = "inputstream.adaptive.license_key"; //! @todo: deprecated to be removed on Kodi 23
// PROP_LICENSE_URL and PROP_LICENSE_URL_APPEND has been added as workaround for Kodi PVR API bug
// where limit property values to max 1024 chars, if exceeds the string is truncated.
// Since some services provide license urls that exceeds 1024 chars,
Expand All @@ -36,9 +37,9 @@ constexpr std::string_view PROP_LICENSE_KEY = "inputstream.adaptive.license_key"
// -> this problem has been fixed on Kodi 22
constexpr std::string_view PROP_LICENSE_URL = "inputstream.adaptive.license_url"; //! @todo: deprecated to be removed on Kodi 23
constexpr std::string_view PROP_LICENSE_URL_APPEND = "inputstream.adaptive.license_url_append"; //! @todo: deprecated to be removed on Kodi 23
constexpr std::string_view PROP_LICENSE_DATA = "inputstream.adaptive.license_data"; //! @todo: to be deprecated
constexpr std::string_view PROP_LICENSE_FLAGS = "inputstream.adaptive.license_flags"; //! @todo: to be deprecated
constexpr std::string_view PROP_SERVER_CERT = "inputstream.adaptive.server_certificate"; //! @todo: to be deprecated
constexpr std::string_view PROP_LICENSE_DATA = "inputstream.adaptive.license_data"; //! @todo: deprecated to be removed on Kodi 23
constexpr std::string_view PROP_LICENSE_FLAGS = "inputstream.adaptive.license_flags"; //! @todo: deprecated to be removed on Kodi 23
constexpr std::string_view PROP_SERVER_CERT = "inputstream.adaptive.server_certificate"; //! @todo: deprecated to be removed on Kodi 23

constexpr std::string_view PROP_COMMON_HEADERS = "inputstream.adaptive.common_headers";

Expand All @@ -53,7 +54,7 @@ constexpr std::string_view PROP_STREAM_HEADERS = "inputstream.adaptive.stream_he
constexpr std::string_view PROP_AUDIO_LANG_ORIG = "inputstream.adaptive.original_audio_language";
constexpr std::string_view PROP_PLAY_TIMESHIFT_BUFFER = "inputstream.adaptive.play_timeshift_buffer";
constexpr std::string_view PROP_LIVE_DELAY = "inputstream.adaptive.live_delay"; //! @todo: deprecated to be removed on Kodi 23
constexpr std::string_view PROP_PRE_INIT_DATA = "inputstream.adaptive.pre_init_data"; //! @todo: to be deprecated
constexpr std::string_view PROP_PRE_INIT_DATA = "inputstream.adaptive.pre_init_data"; //! @todo: deprecated to be removed on Kodi 23

constexpr std::string_view PROP_CONFIG = "inputstream.adaptive.config";
constexpr std::string_view PROP_DRM = "inputstream.adaptive.drm";
Expand Down Expand Up @@ -280,11 +281,25 @@ void ADP::KODI_PROPS::CCompKodiProps::InitStage1(const std::map<std::string, std
else
{
auto first = m_drmConfigs.begin();
first->second.license.serverUrl = licenseUrl;
first->second.license.serverUri = licenseUrl;
}
}
}

bool ADP::KODI_PROPS::CCompKodiProps::HasDrmConfig(std::string_view keySystem) const
{
return STRING::KeyExists(m_drmConfigs, keySystem);
}

const ADP::KODI_PROPS::DrmCfg ADP::KODI_PROPS::CCompKodiProps::GetDrmConfig(
std::string_view keySystem) const
{
if (STRING::KeyExists(m_drmConfigs, keySystem))
return m_drmConfigs.at(keySystem.data());

return {}; // default values
}

void ADP::KODI_PROPS::CCompKodiProps::ParseConfig(const std::string& data)
{
/*
Expand Down Expand Up @@ -314,6 +329,38 @@ void ADP::KODI_PROPS::CCompKodiProps::ParseConfig(const std::string& data)
{
m_config.internalCookies = jDictVal.GetBool();
}
else if (configName == "check_hdcp" && jDictVal.IsString())
{
std::string_view value = jDictVal.GetString();

if (value.empty() || value == "default")
m_config.hdcpCheck = HdcpCheckType::DEFAULT;
else if (value == "license")
m_config.hdcpCheck = HdcpCheckType::LICENSE;
else
LOG::LogF(LOGERROR, "Value \"%s\" isnt supported on \"%s\" config of \"%s\" property",
value.data(), configName.c_str(), PROP_MANIFEST_CONFIG.data());
}
else if (configName == "resolution_limit" && jDictVal.IsString())
{
std::string_view value = jDictVal.GetString();
if (!value.empty())
{
auto pos = value.find('x');
if (pos != std::string_view::npos)
{
const int width = STRING::ToInt32(value.substr(0, pos));
const int height = STRING::ToInt32(value.substr(pos + 1));
m_config.resolutionLimit = width * height;
}
else
{
LOG::LogF(LOGERROR,
"Invalid resolution format \"%s\" on \"%s\" config of \"%s\" property",
value.data(), configName.c_str(), PROP_MANIFEST_CONFIG.data());
}
}
}
else
{
LOG::LogF(LOGERROR, "Unsupported \"%s\" config or wrong data type on \"%s\" property",
Expand Down Expand Up @@ -379,9 +426,7 @@ void ADP::KODI_PROPS::CCompKodiProps::ParseDrmOldProps(

if (!STRING::KeyExists(props, PROP_LICENSE_TYPE))
return;
/*
*! @todo: TO UNCOMMENT WHEN DRM AUTO-SELECTION WILL BE FULL IMPLEMENTED
*

LOG::Log(LOGWARNING, "<<<<<<<<< DEPRECATION NOTICE >>>>>>>>>\n"
"DEPRECATED PROPERTIES HAS BEEN USED TO SET THE DRM CONFIGURATION.\n"
"THE FOLLOWING PROPERTIES WILL BE REMOVED FROM FUTURE KODI VERSIONS:\n"
Expand All @@ -392,11 +437,11 @@ void ADP::KODI_PROPS::CCompKodiProps::ParseDrmOldProps(
"- inputstream.adaptive.server_certificate\n"
"- inputstream.adaptive.pre_init_data\n"
"YOU SHOULD CONSIDER MIGRATING TO THE NEW PROPERTIES:\n"
"- inputstream.adaptive.drm\n"
"- inputstream.adaptive.drm_legacy\n"
"- inputstream.adaptive.drm\n"
"FOR MORE INFO, PLEASE READ THE WIKI PAGE: "
"https://github.com/xbmc/inputstream.adaptive/wiki/Integration-DRM");
*/

std::string drmKeySystem{DRM::KS_NONE};
if (STRING::KeyExists(props, PROP_LICENSE_TYPE))
drmKeySystem = props.at(PROP_LICENSE_TYPE.data());
Expand Down Expand Up @@ -426,6 +471,8 @@ void ADP::KODI_PROPS::CCompKodiProps::ParseDrmOldProps(

// As legacy behaviour its expected to force the unique drm configuration available
drmCfg.priority = 1;
// As legacy behaviour force single session (as in the old ISA versions <= v21)
drmCfg.isForceSingleSession = true;

// Parse DRM properties
const bool isRedacted = !CSrvBroker::GetSettings().IsDebugVerbose();
Expand Down Expand Up @@ -485,7 +532,7 @@ void ADP::KODI_PROPS::CCompKodiProps::ParseDrmOldProps(
{
// Field 1: License server url
if (fieldCount >= 1)
drmCfg.license.serverUrl = fields[0];
drmCfg.license.serverUri = fields[0];

// Field 2: HTTP request headers
if (fieldCount >= 2)
Expand Down Expand Up @@ -567,8 +614,8 @@ void ADP::KODI_PROPS::CCompKodiProps::ParseDrmOldProps(
// Position 2: The dict Key name to get HDCP value (optional)
if (jPaths.size() >= 2)
{
drmCfg.license.unwrapperParams["path_hdcp_traverse"] = "true";
drmCfg.license.unwrapperParams["path_hdcp"] = jPaths[1];
drmCfg.license.unwrapperParams["path_hdcp_res_traverse"] = "true";
drmCfg.license.unwrapperParams["path_hdcp_res"] = jPaths[1];
}
}
}
Expand Down Expand Up @@ -608,7 +655,7 @@ bool ADP::KODI_PROPS::CCompKodiProps::ParseDrmConfig(const std::string& data)
continue;
}

DrmCfg& drmCfg = m_drmConfigs[keySystem];
DrmCfg& drmCfg = m_drmConfigs[keySystem]; // create new configuration
auto& jDictVal = jChildObj.value;

if (!jDictVal.IsObject())
Expand All @@ -622,6 +669,9 @@ bool ADP::KODI_PROPS::CCompKodiProps::ParseDrmConfig(const std::string& data)

LogDrmJsonDictKeys("main", jDictVal, keySystem);

if (jDictVal.HasMember("force_single_session") && jDictVal["force_single_session"].IsBool())
drmCfg.isForceSingleSession = jDictVal["force_single_session"].GetBool();

if (jDictVal.HasMember("persistent_storage") && jDictVal["persistent_storage"].IsBool())
drmCfg.isPersistentStorage = jDictVal["persistent_storage"].GetBool();

Expand Down Expand Up @@ -663,7 +713,7 @@ bool ADP::KODI_PROPS::CCompKodiProps::ParseDrmConfig(const std::string& data)
drmCfg.license.serverCert = jDictLic["server_certificate"].GetString();

if (jDictLic.HasMember("server_url") && jDictLic["server_url"].IsString())
drmCfg.license.serverUrl = jDictLic["server_url"].GetString();
drmCfg.license.serverUri = jDictLic["server_url"].GetString();

if (jDictLic.HasMember("use_http_get_request") && jDictLic["use_http_get_request"].IsBool())
drmCfg.license.isHttpGetRequest = jDictLic["use_http_get_request"].GetBool();
Expand All @@ -687,11 +737,21 @@ bool ADP::KODI_PROPS::CCompKodiProps::ParseDrmConfig(const std::string& data)
{
for (auto& jPairUnwrap : jDictLic["unwrapper_params"].GetObject()) // Iterate JSON dict
{
if (jPairUnwrap.name.IsString() && jPairUnwrap.value.IsString())
if (!jPairUnwrap.name.IsString() ||
!(jPairUnwrap.value.IsString() || jPairUnwrap.value.IsBool()))
{
drmCfg.license.unwrapperParams.emplace(jPairUnwrap.name.GetString(),
jPairUnwrap.value.GetString());
LOG::LogF(LOGERROR,
"The license parameter \"unwrapper_params\" contains invalid values");
break;
}

std::string value;
if (jPairUnwrap.value.IsString())
value = jPairUnwrap.value.GetString();
else if (jPairUnwrap.value.IsBool())
value = jPairUnwrap.value.GetBool() ? "true" : "false";

drmCfg.license.unwrapperParams.emplace(jPairUnwrap.name.GetString(), value);
}
}

Expand All @@ -704,9 +764,6 @@ bool ADP::KODI_PROPS::CCompKodiProps::ParseDrmConfig(const std::string& data)
}
}
}

//! @todo: temporary support only one DRM config, must be reworked the CSession for DRM auto-selection
break;
}

return true;
Expand Down Expand Up @@ -752,9 +809,9 @@ bool ADP::KODI_PROPS::CCompKodiProps::ParseDrmLegacyConfig(const std::string& da

if (!licenseStr.empty())
{
if (URL::IsValidUrl(licenseStr)) // License server URL
if (URL::IsValidUrl(licenseStr) || URL::IsValidUri(licenseStr)) // License server URI
{
drmCfg.license.serverUrl = licenseStr;
drmCfg.license.serverUri = licenseStr;
}
else // Assume are keyid's for ClearKey DRM
{
Expand Down
33 changes: 19 additions & 14 deletions src/CompKodiProps.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ struct ChooserProps
std::pair<int, int> m_resolutionSecureMax; // Res. limit for DRM protected videos (values 0 means auto)
};

enum class HdcpCheckType
{
DEFAULT,
LICENSE, // To check HDCP values from DRM license response
};

// Generic add-on configuration
struct Config
{
Expand All @@ -43,6 +49,10 @@ struct Config
bool curlSSLVerifyPeer{true};
// Determines if cookies are internally handled by InputStream Adaptive add-on
bool internalCookies{false};
// Determines how HDCP should be checked
HdcpCheckType hdcpCheck{HdcpCheckType::DEFAULT};
// Force limit resolutions of manifest streams to the specified value included (value in px, height x width)
int resolutionLimit{0};
};

struct ManifestConfig
Expand Down Expand Up @@ -78,13 +88,15 @@ struct DrmCfg
std::optional<bool> isSecureDecoderEnabled;
// Optional parameters to make the CDM key request (CDM specific parameters)
std::map<std::string, std::string> optKeyReqParams;
// Enforce the use of a single session (license is assumed to return all keys in one request)
bool isForceSingleSession{false};

struct License
{
// The license server certificate encoded as base64
std::string serverCert;
// The license server url
std::string serverUrl;
// The license server uri
std::string serverUri;
// To force an HTTP GET request, instead that POST request
bool isHttpGetRequest{false};
// HTTP request headers
Expand Down Expand Up @@ -152,20 +164,13 @@ class ATTR_DLL_LOCAL CCompKodiProps
// \brief Specifies the manifest configuration
const ManifestConfig& GetManifestConfig() const { return m_manifestConfig; }

// \brief Checks whether there is a DRM configuration for the specified key system
bool HasDrmConfig(std::string_view keySystem) const;

//! @todo: temporary method, for future rework
const std::string GetDrmKeySystem()
{
return m_drmConfigs.empty() ? "" : m_drmConfigs.begin()->first;
}
//! @todo: temporary method, for future rework
const DrmCfg& GetDrmConfig() { return m_drmConfigs[GetDrmKeySystem()]; }


// \brief Get DRM configuration for specified keysystem, if not found will return default values
const DrmCfg& GetDrmConfig(const std::string& keySystem) { return m_drmConfigs[keySystem]; }
const DrmCfg& GetDrmConfig(std::string_view keySystem) { return m_drmConfigs[std::string(keySystem)]; }
// \brief Gets the DRM configuration for the specified keysystem. If not found, returns default values.
const DrmCfg GetDrmConfig(std::string_view keySystem) const;

// \brief Gets the DRM configurations (Key System, DRM config)
const std::map<std::string, DrmCfg>& GetDrmConfigs() const { return m_drmConfigs; }

private:
Expand Down
5 changes: 0 additions & 5 deletions src/CompSettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,6 @@
using namespace ADP::SETTINGS;
using namespace UTILS;

bool ADP::SETTINGS::CCompSettings::IsHdcpOverride() const
{
return kodi::addon::GetSettingBoolean("HDCPOVERRIDE");
}

StreamSelMode ADP::SETTINGS::CCompSettings::GetStreamSelMode() const
{
const std::string mode = kodi::addon::GetSettingString("adaptivestream.streamselection.mode");
Expand Down
2 changes: 0 additions & 2 deletions src/CompSettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,6 @@ class ATTR_DLL_LOCAL CCompSettings
CCompSettings() = default;
~CCompSettings() = default;

bool IsHdcpOverride() const;

// Chooser's settings

StreamSelMode GetStreamSelMode() const;
Expand Down
2 changes: 1 addition & 1 deletion src/Iaes_decrypter.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class IAESDecrypter
size_t dstOffset,
size_t& dataSize,
bool lastChunk) = 0;
virtual std::string convertIV(const std::string& input) = 0;
virtual std::vector<uint8_t> convertIV(const std::string& input) = 0;
virtual void ivFromSequence(uint8_t* buffer, uint64_t sid) = 0;
// virtual const std::string& getLicenseKey() const = 0;
// virtual bool RenewLicense(const std::string& pluginUrl) = 0;
Expand Down
Loading