Skip to content

Commit 2afe7b8

Browse files
committed
Implement DRM auto-selection
1 parent a1a6ff3 commit 2afe7b8

75 files changed

Lines changed: 2392 additions & 1856 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

inputstream.adaptive/resources/language/resource.language.en_gb/strings.po

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -164,14 +164,7 @@ msgctxt "#30171"
164164
msgid "Defines the initial bandwidth when it cannot be automatically determined. This value can be overridden by the minimum bandwidth setting."
165165
msgstr ""
166166

167-
msgctxt "#30172"
168-
msgid "Ignore HDCP status"
169-
msgstr ""
170-
171-
#. Description of setting with label #30172
172-
msgctxt "#30173"
173-
msgid "Some DRM-protected HD / UHD videos may only be played if the HDCP status is ignored."
174-
msgstr ""
167+
#empty strings from id 30171 to 30173
175168

176169
#. To set the stream selection type (refer to RepresentationChooser's)
177170
msgctxt "#30174"

inputstream.adaptive/resources/settings.xml.in

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -161,13 +161,6 @@
161161
</control>
162162
</setting>
163163
</group>
164-
<group id="misc">
165-
<setting id="HDCPOVERRIDE" type="boolean" label="30172" help="30173">
166-
<level>1</level>
167-
<default>false</default>
168-
<control type="toggle" />
169-
</setting>
170-
</group>
171164
</category>
172165
<category id="expert" label="30120">
173166
<group id="misc">

plugin.video.isasamples/menu_data.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -353,7 +353,7 @@
353353
'drm': '{"org.w3.clearkey": {"license": {"keyids": {"feedf00deedeadbeeff0baadf00dd00d": "00112233445566778899aabbccddeeff", "1234f00deedeadbeeff0baadf00dd00d": "8899aabbccddeeff8899aabbccddeeff"}}}}',
354354
}
355355
},
356-
'Bitmovin art of motion [widevine to clear key, keys on property]': {
356+
'Bitmovin art of motion [WV to CK, keys on property]': {
357357
SI_ENCRYPT: 'DRMCK',
358358
SI_INFO: 'Override widevine content protection to use clear key',
359359
SI_CONFIG: {
@@ -587,6 +587,15 @@
587587
'drm': '{"com.microsoft.playready": {"license": {"server_url": "https://test.playready.microsoft.com/service/rightsmanager.asmx?cfg=(persist:false,sl:150)"}}}'
588588
}
589589
},
590+
'Microsoft tears of steel 4k [PR to CK, keys on property]': {
591+
SI_ENCRYPT: 'DRMCK',
592+
SI_INFO: 'Override PlayReady content protection to use ClearKey',
593+
SI_CONFIG: {
594+
'manifest_url': 'https://test.playready.microsoft.com/media/profficialsite/tearsofsteel_4k.ism.smoothstreaming/manifest',
595+
'drm_legacy': 'org.w3.clearkey|6f651ae1dbe44434bcb4690d1564c41c:88da852ae4fa2e1e36aeb2d5c94997b1',
596+
'drm': '{"org.w3.clearkey": {"license": {"keyids": {"6f651ae1dbe44434bcb4690d1564c41c": "88da852ae4fa2e1e36aeb2d5c94997b1"}}}}',
597+
}
598+
},
590599
},
591600
'ISM Live': {
592601
MI_CONFIG: {},

src/CompKodiProps.cpp

Lines changed: 82 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,13 @@
2121
#include <rapidjson/document.h>
2222

2323
using namespace UTILS;
24+
using namespace ADP::KODI_PROPS;
2425

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

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

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

5859
constexpr std::string_view PROP_CONFIG = "inputstream.adaptive.config";
5960
constexpr std::string_view PROP_DRM = "inputstream.adaptive.drm";
@@ -280,11 +281,25 @@ void ADP::KODI_PROPS::CCompKodiProps::InitStage1(const std::map<std::string, std
280281
else
281282
{
282283
auto first = m_drmConfigs.begin();
283-
first->second.license.serverUrl = licenseUrl;
284+
first->second.license.serverUri = licenseUrl;
284285
}
285286
}
286287
}
287288

289+
bool ADP::KODI_PROPS::CCompKodiProps::HasDrmConfig(std::string_view keySystem) const
290+
{
291+
return STRING::KeyExists(m_drmConfigs, keySystem);
292+
}
293+
294+
const ADP::KODI_PROPS::DrmCfg ADP::KODI_PROPS::CCompKodiProps::GetDrmConfig(
295+
std::string_view keySystem) const
296+
{
297+
if (STRING::KeyExists(m_drmConfigs, keySystem))
298+
return m_drmConfigs.at(keySystem.data());
299+
300+
return {}; // default values
301+
}
302+
288303
void ADP::KODI_PROPS::CCompKodiProps::ParseConfig(const std::string& data)
289304
{
290305
/*
@@ -314,6 +329,38 @@ void ADP::KODI_PROPS::CCompKodiProps::ParseConfig(const std::string& data)
314329
{
315330
m_config.internalCookies = jDictVal.GetBool();
316331
}
332+
else if (configName == "check_hdcp" && jDictVal.IsString())
333+
{
334+
std::string_view value = jDictVal.GetString();
335+
336+
if (value.empty() || value == "default")
337+
m_config.hdcpCheck = HdcpCheckType::DEFAULT;
338+
else if (value == "license")
339+
m_config.hdcpCheck = HdcpCheckType::LICENSE;
340+
else
341+
LOG::LogF(LOGERROR, "Value \"%s\" isnt supported on \"%s\" config of \"%s\" property",
342+
value.data(), configName.c_str(), PROP_MANIFEST_CONFIG.data());
343+
}
344+
else if (configName == "resolution_limit" && jDictVal.IsString())
345+
{
346+
std::string_view value = jDictVal.GetString();
347+
if (!value.empty())
348+
{
349+
auto pos = value.find('x');
350+
if (pos != std::string_view::npos)
351+
{
352+
const int width = STRING::ToInt32(value.substr(0, pos));
353+
const int height = STRING::ToInt32(value.substr(pos + 1));
354+
m_config.resolutionLimit = width * height;
355+
}
356+
else
357+
{
358+
LOG::LogF(LOGERROR,
359+
"Invalid resolution format \"%s\" on \"%s\" config of \"%s\" property",
360+
value.data(), configName.c_str(), PROP_MANIFEST_CONFIG.data());
361+
}
362+
}
363+
}
317364
else
318365
{
319366
LOG::LogF(LOGERROR, "Unsupported \"%s\" config or wrong data type on \"%s\" property",
@@ -379,9 +426,7 @@ void ADP::KODI_PROPS::CCompKodiProps::ParseDrmOldProps(
379426

380427
if (!STRING::KeyExists(props, PROP_LICENSE_TYPE))
381428
return;
382-
/*
383-
*! @todo: TO UNCOMMENT WHEN DRM AUTO-SELECTION WILL BE FULL IMPLEMENTED
384-
*
429+
385430
LOG::Log(LOGWARNING, "<<<<<<<<< DEPRECATION NOTICE >>>>>>>>>\n"
386431
"DEPRECATED PROPERTIES HAS BEEN USED TO SET THE DRM CONFIGURATION.\n"
387432
"THE FOLLOWING PROPERTIES WILL BE REMOVED FROM FUTURE KODI VERSIONS:\n"
@@ -392,11 +437,11 @@ void ADP::KODI_PROPS::CCompKodiProps::ParseDrmOldProps(
392437
"- inputstream.adaptive.server_certificate\n"
393438
"- inputstream.adaptive.pre_init_data\n"
394439
"YOU SHOULD CONSIDER MIGRATING TO THE NEW PROPERTIES:\n"
395-
"- inputstream.adaptive.drm\n"
396440
"- inputstream.adaptive.drm_legacy\n"
441+
"- inputstream.adaptive.drm\n"
397442
"FOR MORE INFO, PLEASE READ THE WIKI PAGE: "
398443
"https://github.com/xbmc/inputstream.adaptive/wiki/Integration-DRM");
399-
*/
444+
400445
std::string drmKeySystem{DRM::KS_NONE};
401446
if (STRING::KeyExists(props, PROP_LICENSE_TYPE))
402447
drmKeySystem = props.at(PROP_LICENSE_TYPE.data());
@@ -426,6 +471,8 @@ void ADP::KODI_PROPS::CCompKodiProps::ParseDrmOldProps(
426471

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

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

490537
// Field 2: HTTP request headers
491538
if (fieldCount >= 2)
@@ -567,8 +614,8 @@ void ADP::KODI_PROPS::CCompKodiProps::ParseDrmOldProps(
567614
// Position 2: The dict Key name to get HDCP value (optional)
568615
if (jPaths.size() >= 2)
569616
{
570-
drmCfg.license.unwrapperParams["path_hdcp_traverse"] = "true";
571-
drmCfg.license.unwrapperParams["path_hdcp"] = jPaths[1];
617+
drmCfg.license.unwrapperParams["path_hdcp_res_traverse"] = "true";
618+
drmCfg.license.unwrapperParams["path_hdcp_res"] = jPaths[1];
572619
}
573620
}
574621
}
@@ -608,7 +655,7 @@ bool ADP::KODI_PROPS::CCompKodiProps::ParseDrmConfig(const std::string& data)
608655
continue;
609656
}
610657

611-
DrmCfg& drmCfg = m_drmConfigs[keySystem];
658+
DrmCfg& drmCfg = m_drmConfigs[keySystem]; // create new configuration
612659
auto& jDictVal = jChildObj.value;
613660

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

623670
LogDrmJsonDictKeys("main", jDictVal, keySystem);
624671

672+
if (jDictVal.HasMember("force_single_session") && jDictVal["force_single_session"].IsBool())
673+
drmCfg.isForceSingleSession = jDictVal["force_single_session"].GetBool();
674+
625675
if (jDictVal.HasMember("persistent_storage") && jDictVal["persistent_storage"].IsBool())
626676
drmCfg.isPersistentStorage = jDictVal["persistent_storage"].GetBool();
627677

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

665715
if (jDictLic.HasMember("server_url") && jDictLic["server_url"].IsString())
666-
drmCfg.license.serverUrl = jDictLic["server_url"].GetString();
716+
drmCfg.license.serverUri = jDictLic["server_url"].GetString();
667717

668718
if (jDictLic.HasMember("use_http_get_request") && jDictLic["use_http_get_request"].IsBool())
669719
drmCfg.license.isHttpGetRequest = jDictLic["use_http_get_request"].GetBool();
@@ -687,11 +737,21 @@ bool ADP::KODI_PROPS::CCompKodiProps::ParseDrmConfig(const std::string& data)
687737
{
688738
for (auto& jPairUnwrap : jDictLic["unwrapper_params"].GetObject()) // Iterate JSON dict
689739
{
690-
if (jPairUnwrap.name.IsString() && jPairUnwrap.value.IsString())
740+
if (!jPairUnwrap.name.IsString() ||
741+
!(jPairUnwrap.value.IsString() || jPairUnwrap.value.IsBool()))
691742
{
692-
drmCfg.license.unwrapperParams.emplace(jPairUnwrap.name.GetString(),
693-
jPairUnwrap.value.GetString());
743+
LOG::LogF(LOGERROR,
744+
"The license parameter \"unwrapper_params\" contains invalid values");
745+
break;
694746
}
747+
748+
std::string value;
749+
if (jPairUnwrap.value.IsString())
750+
value = jPairUnwrap.value.GetString();
751+
else if (jPairUnwrap.value.IsBool())
752+
value = jPairUnwrap.value.GetBool() ? "true" : "false";
753+
754+
drmCfg.license.unwrapperParams.emplace(jPairUnwrap.name.GetString(), value);
695755
}
696756
}
697757

@@ -704,9 +764,6 @@ bool ADP::KODI_PROPS::CCompKodiProps::ParseDrmConfig(const std::string& data)
704764
}
705765
}
706766
}
707-
708-
//! @todo: temporary support only one DRM config, must be reworked the CSession for DRM auto-selection
709-
break;
710767
}
711768

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

753810
if (!licenseStr.empty())
754811
{
755-
if (URL::IsValidUrl(licenseStr)) // License server URL
812+
if (URL::IsValidUrl(licenseStr) || URL::IsValidUri(licenseStr)) // License server URI
756813
{
757-
drmCfg.license.serverUrl = licenseStr;
814+
drmCfg.license.serverUri = licenseStr;
758815
}
759816
else // Assume are keyid's for ClearKey DRM
760817
{

src/CompKodiProps.h

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,12 @@ struct ChooserProps
3535
std::pair<int, int> m_resolutionSecureMax; // Res. limit for DRM protected videos (values 0 means auto)
3636
};
3737

38+
enum class HdcpCheckType
39+
{
40+
DEFAULT,
41+
LICENSE, // To check HDCP values from DRM license response
42+
};
43+
3844
// Generic add-on configuration
3945
struct Config
4046
{
@@ -43,6 +49,10 @@ struct Config
4349
bool curlSSLVerifyPeer{true};
4450
// Determines if cookies are internally handled by InputStream Adaptive add-on
4551
bool internalCookies{false};
52+
// Determines how HDCP should be checked
53+
HdcpCheckType hdcpCheck{HdcpCheckType::DEFAULT};
54+
// Force limit resolutions of manifest streams to the specified value included (value in px, height x width)
55+
int resolutionLimit{0};
4656
};
4757

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

8294
struct License
8395
{
8496
// The license server certificate encoded as base64
8597
std::string serverCert;
86-
// The license server url
87-
std::string serverUrl;
98+
// The license server uri
99+
std::string serverUri;
88100
// To force an HTTP GET request, instead that POST request
89101
bool isHttpGetRequest{false};
90102
// HTTP request headers
@@ -152,20 +164,13 @@ class ATTR_DLL_LOCAL CCompKodiProps
152164
// \brief Specifies the manifest configuration
153165
const ManifestConfig& GetManifestConfig() const { return m_manifestConfig; }
154166

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

156-
//! @todo: temporary method, for future rework
157-
const std::string GetDrmKeySystem()
158-
{
159-
return m_drmConfigs.empty() ? "" : m_drmConfigs.begin()->first;
160-
}
161-
//! @todo: temporary method, for future rework
162-
const DrmCfg& GetDrmConfig() { return m_drmConfigs[GetDrmKeySystem()]; }
163-
164-
165-
// \brief Get DRM configuration for specified keysystem, if not found will return default values
166-
const DrmCfg& GetDrmConfig(const std::string& keySystem) { return m_drmConfigs[keySystem]; }
167-
const DrmCfg& GetDrmConfig(std::string_view keySystem) { return m_drmConfigs[std::string(keySystem)]; }
170+
// \brief Gets the DRM configuration for the specified keysystem. If not found, returns default values.
171+
const DrmCfg GetDrmConfig(std::string_view keySystem) const;
168172

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

171176
private:

src/CompSettings.cpp

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,6 @@
1818
using namespace ADP::SETTINGS;
1919
using namespace UTILS;
2020

21-
bool ADP::SETTINGS::CCompSettings::IsHdcpOverride() const
22-
{
23-
return kodi::addon::GetSettingBoolean("HDCPOVERRIDE");
24-
}
25-
2621
StreamSelMode ADP::SETTINGS::CCompSettings::GetStreamSelMode() const
2722
{
2823
const std::string mode = kodi::addon::GetSettingString("adaptivestream.streamselection.mode");

src/CompSettings.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,6 @@ class ATTR_DLL_LOCAL CCompSettings
4242
CCompSettings() = default;
4343
~CCompSettings() = default;
4444

45-
bool IsHdcpOverride() const;
46-
4745
// Chooser's settings
4846

4947
StreamSelMode GetStreamSelMode() const;

src/Iaes_decrypter.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ class IAESDecrypter
2626
size_t dstOffset,
2727
size_t& dataSize,
2828
bool lastChunk) = 0;
29-
virtual std::string convertIV(const std::string& input) = 0;
29+
virtual std::vector<uint8_t> convertIV(const std::string& input) = 0;
3030
virtual void ivFromSequence(uint8_t* buffer, uint64_t sid) = 0;
3131
// virtual const std::string& getLicenseKey() const = 0;
3232
// virtual bool RenewLicense(const std::string& pluginUrl) = 0;

0 commit comments

Comments
 (0)