Integration DRM - xbmc/inputstream.adaptive GitHub Wiki
To play DRM-protected content is required, in addition to the standard properties described on Integration page, configure the DRM(s) to be used.
Let's start by saying that a manifest (e.g. DASH, HLS, ...) can support one or more DRM's, but a device (operative system) may support only some DRM's, moreover this add-on has some limitations based on the operative system used, see also matrix scheme of supported DRM's on the wiki main page.
Until Kodi v21 the choice of the DRM will have to be handled "manually" by the add-on or playlist that starts the playback, by taking into account the variables mentioned earlier (matrix scheme, etc), and so by configuring it by using "old properties" method, or the inputstream.adaptive.drm_legacy
.
Starting with Kodi v22 the choice of DRM will be handled automatically by ISA thanks also to the new inputstream.adaptive.drm
property, and then you will have to provide DRM configurations only if requested.
Note
The Widevine CDM library for operating systems other than Android must be installed separately because it is not included in this add-on. To handle the library installation automatically we suggest to use InputStream Helper add-on.
The way in which configuration is required has changed slightly from older versions of Kodi, as follows:
- Until to Kodi v21: it is always mandatory to use one of the following methods to set which DRM to use.
- From Kodi v22 and above: Only if the DRM have mandatory requirements, you need to set one of the following methods to configure the DRM, otherwise, you do not need to configure the DRM because the video will still play.
The following DRMs require some mandatory configurations:
- Widevine / Wiseplay DRM: its mandatory set the license server url.
- PlayReady DRM: if the manifest does not embed the license server url, then its mandatory set the license server url.
- ClearKey DRM: if the manifest does not embed the license server url, then its mandatory set the license server url or the keyids.
π old properties
- Deprecated advanced method [from Kodi v18 to v22] [click to expand]
Available from Kodi 18 to Kodi 22
This is the old advanced method that makes use of multiple properties. Has been deprecated on Kodi v22.
Recommendations: We suggest to use this old method with older versions of Kodi until to v21.
Starting with Kodi v22 we suggest the use of the new "drm" property interface. If instead you don't need of an advanced method, you can use directly the "drm_legacy" property starting from Kodi v21.
Open "Integration DRM (old)" page to learn how to use the old properties.
The support of this old method will be removed in future versions of Kodi.
π inputstream.adaptive.drm_legacy
- Simple method to configure a single DRM [Kodi v21+] [click to expand]
Available from v.21.5.0 / Kodi 21
The simple way to configure a DRM can be used for cases where the provider does not require advanced configurations such as wrappers, certificate, etc... it can configure a single DRM, that will have the higher priority (over others DRM's, if any on the manifest).
DRM sessions, Kodi v22 breaking-change: unlike the old properties and
drm_legacy
on Kodi v21 that forced the DRM with a single session,drm_legacy
on Kodi v22 will no longer force a single DRM session, this is to prevent old standing playback problems. If you want force again the single session you have to make use ofinputstream.adaptive.drm
property whereforce_single_session
parameter allow you to change this behavior.
The expected value is a string, which can be extended with 2 more optional pipes |
as required:
[DRM KeySystem] | [License server URL or KeyId's] | [License server headers]
Template fields:
-
[DRM Key System]
The Key System of the DRM to configure, the supported Key System strings are shown in the table above. -
[License server URL or KeyId's]
Supported string values:- URL: it can also override the one embedded in the manifest, if any
-
KID/KeyId's pairs: Only ClearKey DRM, with following format:
kid1:key1,kid2:key2,...
where the values are in HEX format. -
URI "data" scheme: Only ClearKey DRM, example
data:application/json;base64,CK_LICENSE_AS_BASE64
-
[License server headers]
Allow you to add custom HTTP headers for the license HTTP request. With some providers it may be necessary to avoid a server rejection of the HTTP request.
We suggest to URL encode the headers values. The headers string must follow the scheme:param1=value1¶m2=value2
Example for Widevine:
# Flat string example
listitem.setProperty('inputstream.adaptive.drm_legacy', 'com.widevine.alpha|https://license.server.com/licenserequest|User-Agent=Mozilla%2F5.0+%28Windows+NT+10.0%3B+Win64%3B+x64%29+AppleWebKit%2F537.36+%28KHTML%2C+like+Gecko%29+Chrome%2F106.0.0.0+Safari%2F537.36')
# Constructed string example (recommended)
license_headers = {
'Content-Type': 'application/octet-stream',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/109.0',
}
from urllib.parse import urlencode
drm_config = { # Keeping items in order
'DRM KeySystem': 'com.widevine.alpha'
'License server url': 'https://license.server.com/licenserequest',
'License headers': urlencode(license_headers)
}
listitem.setProperty('inputstream.adaptive.drm_legacy', '|'.join(drm_config.values()))
Example for PlayReady:
listitem.setProperty('inputstream.adaptive.drm_legacy', 'com.microsoft.playready|https://www.licenseserver.com/AcquireLicense/')
Example for ClearKey:
# KeyId's provided by manifest:
listitem.setProperty('inputstream.adaptive.drm_legacy', 'org.w3.clearkey')
# KeyId's provided by property:
listitem.setProperty('inputstream.adaptive.drm_legacy', 'org.w3.clearkey|000102030405060708090a0b0c0d0e0f:00112233445566778899aabbccddeeff')
# License URL provided by property: (supported from v21.5.3)
listitem.setProperty('inputstream.adaptive.drm_legacy', 'org.w3.clearkey|https://www.licenseserver.com/AcquireLicense/')
# License URI "data" scheme provided by property: (supported from v22.2.0)
listitem.setProperty('inputstream.adaptive.drm_legacy', 'org.w3.clearkey|data:application/json;base64,CK_LICENSE_AS_BASE64')
π inputstream.adaptive.drm
- Advanced method to configure one or more DRM's [Kodi v22+] [click to expand]
Available from v.22.1.5 / Kodi 22
The advanced method allows you to configure one or multiple DRM's at same time with more complex parameters. Setting multiple DRMs makes sense when a manifest incorporates support for multiple DRMs that will allow ISA to select the most appropriate DRM based for example on the operating system in use and other parameters. In case you want to alter the automatic DRM selection, you can make use of the βpriorityβ parameter.
The expected value is a json converted as string. The base scheme is structured by a dictionary, where the key is a Key System string, and the value is a dictionary with most of the time optionals parameters, as in the following example:
# Brief example for python, full examples on relative chapter
drm_configs = {
# This is Widevine DRM Key System
"com.widevine.alpha": {
"license": {
"server_url": "https://theserverurl.com"
}
}
}
list_item.setProperty('inputstream.adaptive.drm', json.dumps(drm_configs))
You can specify a DRM Key System string (example "com.widevine.alpha", see the complete KS list at the end of the page), or "none" value. The "none" value is reserved for special cases such as HLS encryption (e.g. AES-128) which can be used in order to configure these specific use cases (see chapter examples).
DRM sessions note: unlike the old properties that forced the DRM with a single session,
drm
property will not force a single DRM session by default, this is to prevent old standing playback problems. If you want change this behavior you can make use of theforce_single_session
parameter.
To configure a DRM you can use following parameters, each parameter is optional unless otherwise specified, or required by your service provider.
π΅ priority - The DRM priority over others DRM's
Allows this DRM to be given a higher priority than the others (if multiple).
This can be useful when a manifest support more DRM's and the operating system in use supports all of them. So for example if a specific DRM provides higher resolutions, you can prioritize that DRM over the others.
The value can start from 1 to "n" where lower number have the higher priority. Invalid values are: 0 or a same value used on multiple DRM's.
DATA TYPE: int
EXAMPLE: "priority": 1
π΅ license - To configure the license request
The configuration for the license request is strictly dependent on the streaming services requirements so we cannot provide guidelines for every use case, so we just provide generalities.
DATA TYPE: dict
The license dictionary support these parameters:
π’ server_certificate - To set a license server certificate
Specifies a server certificate to be used to encrypt messages to the license server. Must be encoded as Base64.
DATA TYPE: str
EXAMPLE: "server_certificate": "base64 data"
π’ server_url - To set a license server URL
Specifies the license server URL where make the license HTTP request.
Supported string values:
- URL: it can also override the one embedded in the manifest, if any
-
URI "data" scheme: Only ClearKey DRM, example
data:application/json;base64,CK_LICENSE_AS_BASE64
For Widevine DRM: In the URL is possible optionally inject the DRM challenge (key request) by using following placeholders:
-
{CHA-B64U}
To inject to the URL the DRM Challenge as base64, URL encoded -
{CHA-MD5}
To inject to the URL the DRM Challenge hashed as MD5
DATA TYPE: str
EXAMPLE: "server_url": "http://the-server-url.com/challenge/{CHA-B64U}"
π’ use_http_get_request - Force HTTP GET for the license request
Widevine, Playready, Wiseplay only.
By enabling this parameter will force an HTTP GET request to request the license (by default the request is done with an HTTP POST request).
DATA TYPE: bool
EXAMPLE: "use_http_get_request": True
π’ req_headers - To set the HTTP headers for the license request
Allows to add the HTTP headers to the license HTTP request, values of headers must be URL encoded (see also chapter "examples").
DATA TYPE: str
EXAMPLE: "req_headers": "param1=valueUrlEncoded1¶m2=valueUrlEncoded2"
π’ req_params - To set parameters to the license URL
Allows to append to the license URL, some URL parameters.
DATA TYPE: str
EXAMPLE: "req_params": "/one/two/three-path"
π’ req_data - To customize the data for the license request
Allows to provide custom data for the license request. The data must be base 64 encoded.
It is usually used when a license requet/response makes use of wrappers, so the data structure is customized with other types of formats by the service provider, such as JSON, BASE64, etc... (see wrapper
/unwrapper
parameters).
You can construct the format of the required data structure as a string and use the following placeholders to inject specific data into the constructed string:
-
{CHA-RAW}
Challenge (key request) data as is, raw bytes -
{CHA-B64}
Challenge (key request) data base64 encoded -
{CHA-B64U}
Challenge (key request) data base64 and URL encoded -
{CHA-DEC}
Challenge (key request) data decimal converted (each char converted as integer concatenated by comma) -
{SID-RAW}
Session ID as is, raw text -
{SID-B64}
Session ID base64 encoded -
{SID-B64U}
Session ID base64 and URL encoded -
{KID-UUID}
KeyID as UUID format -
{KID-HEX}
KeyID as HEX format -
{PSSH-B64}
Initialization PSSH data base64 encoded -
{PSSH-B64U}
Initialization PSSH data base64 and URL encoded
DATA TYPE: str
EXAMPLE: Example of provider customized license request data as JSON with injected challenge data and session ID
lic_req_data = json.dumps({"movie_id": "123456", "challenge_base64": "{CHA-B64}", "SID": "{SID-B64}"}).encode("utf-8")
drm_configs = {
"...": {
"license": {
"req_data": base64.b64encode(lic_req_data).decode("utf-8"),
...
}
}
}
π’ wrapper / unwrapper / unwrapper_params - Widevine only. To wrap/unwrap the license data
Widevine only.
Some services use custom data for license server request/response, where the data are wrapped in other types of formats, such as Base64, JSON, XML, etc... but Widevine by default works only with raw binary data, so its needed to prepare the license data wrapped in a suitable way accepted by the server to make the license request, and after extract the raw data from the wrapped data of the server license response.
There are two ways to manage a custom license:
- Use built-in wrappers/unwrappers
- Via proxy server. An add-on must implement a proxy server to translate the license request response (as explained on How-to-provide-custom-manifest-and-license)
The built-in method is the simplest, but may be not suitable if the custom license is too much complex.
wrapper
parameter flags:
-
base64
To encode as base 64 -
urlenc
To encode as URL -
none
To keep data as it is raw (explicit way, as if the parameter was not set)
Multiple flags are accepted and must be splitted by ,
char, the sequence order declares the way in which to wrap the data.
unwrapper
parameter flags:
-
auto
Try auto-detect the wrapping types (single-use only) -
base64
To decode as base 64 -
json
To parse JSON data, requiredunwrapper_params
-
xml
To parse XML data, requiredunwrapper_params
-
none
To keep data as it is raw (explicit way, as if the parameter was not set)
Multiple flags are accepted and must be splitted by ,
char, the sequence order declares the way in which to unwrap the data.
unwrapper_params
parameters:
- "path_data": Can be used to specify an absolute JSON or XML path to get the license data.
-
"path_data_traverse": bool, If
True
the search withpath_data
will be performed by traversing all the dict's to find a specified key instead of an absolute path. - "path_hdcp_res": Can be used to specify the absolute JSON path to get the HDCP resolution limit. Read HDCP resolution limit page for details.
-
"path_hdcp_res_traverse": bool, If
True
the search withpath_hdcp_res
will be performed by traversing all the dict's to find a specified key instead of an absolute path. - "path_hdcp_ver": Can be used to specify the absolute JSON path to get the HDCP resolution limit. Read HDCP resolution limit page for details.
-
"path_hdcp_ver_traverse": bool, If
True
the search withpath_hdcp_ver
will be performed by traversing all the dict's to find a specified key instead of an absolute path.
We cannot provide examples for every use case, here we provide an example that can also be adapted for other use cases as they are similar.
Example to configure built-in wrappers/unwrappers for JSON/BASE64 wrapped license:
- The service require that the license request is encoded as BASE64, the encoded data must be in JSON format. The Json is a dictionary
challenge_base64
that contains the challenge (widevine key request) raw data encoded as base 64. - The license server give a response BASE64 encoded, where contains a JSON with nested dictionaries. The first dictionary is
licenseresponse
that contains a nesteddata
dictionary, having the license raw data encoded as base 64.
lic_req_data = json.dumps({"challenge_base64": "{CHA-B64}"}).encode("utf-8") # Prepared Json string, {CHA-B64} used to jniect the challenge as base64
drm_configs = {
"com.widevine.alpha": {
"license": {
"server_url": "https://theserverurl.com",
"req_data": base64.b64encode(lic_req_data).decode("utf-8"), # Encoded as base64, because its a requirement of the "req_data" parameter.
"wrapper": "base64", # Encode "req_data" data as base 64, before make the request
"unwrapper": "base64,json,base64", # From the response -> (1) decode as base 64 -> (2) parse JSON path -> (3) decode base 64 the value
"unwrapper_params": {"path_data": "licenseresponse/data"}
}
}
}
# Expected license response data that will be unwrapped by the configuration:
response_data = "eyJsaWNlbnNlcmVzcG9uc2UiOiB7ImRhdGEiOiAiZEdocGN5QnBjeUJ5WVhjZ1pHRjBZUT09In19Cg=="
To check if you are sending/receive the data correctly, you can enable the ISA expert setting to save the license data and so inspect the saved files. In short, the ".request" file should reflect the format required by your service provider, while ".response" file should show that it contains only the license data (raw) bytes.
π’ keyids - ClearKey DRM only. Map of KID/Key pairs
Allows to specify a map of unencrypted KID/Key pairs to decrypt stream CENC content, can be useful for diagnosing problems and testing integrations.
Both KID/Key values must be in hex format.
DATA TYPE: dict
EXAMPLE: "keyids": { "KID_1": "KEY_1", "KID_2": "KEY_2" }
π΅ init_data - To set custom initialization data
Allow to provide a initialization data (PSSH box) to initialize the CDM sessions, in case the manifest provides one, this will replace it.
Accepted values are: a standard PSSH box or else a Widevine PSSH, encoded as base64.
For the Widevine PSSH case, two placeholders can be optionally used to inject data in to the custom data:
-
{KID}
to inject the KID as bytes -
{UUID}
to inject the KID as UUID string
The placeholders if used must be encoded as base64 together with the raw data, and not separately.
Technically speaking the Widevine PSSH data will be added to content_id
field of WidevinePsshData
structure. The WidevinePsshData
generated will be enclosed into a standard PSSH box.
DATA TYPE: str
EXAMPLE: "init_data": "base64 data"
π΅ pre_init_data - Widevine only, for custom licensed manifests
Widevine DRM only.
NOTE: To use this feature, its mandatory set to Widevine DRM configuration priority
parameter to 1.
Pre-initialize the DRM is required for services that make use of licensed manifests (custom manifests). Compared to the standard manifests (e.g. DASH) this encloses also the license data. To request these custom manifests usually you need to provide the DRM session id and the challenge (widevine key request).
To obtain these two data, this parameter allows you to pre-initialize the DRM by opening a DRM session.
To open a DRM session you need to provide a PSSH and KID, both values must be base 64 encoded and splitted by a pipe char |
.
After that, you need to implement a proxy in your add-on to intercept the ISAdaptive HTTP manifest/license requests, as in the example How to provide custom manifest and license, will allow your addon to manage and convert the manifest/license data. When you will get the HTTP manifest response, you will also need to transfer the license data into the ISA license HTTP request.
With the HTTP manifest request, two custom HTTP headers will be provided:
-
challengeB64
Provide the challenge (key request) encoded as base 64, and URL encoded. -
sessionId
Provide the DRM session id.
WARNING: Do not enable pre_init_data
parameter without a proxy server in your add-on, otherwise the license data will not be managed.
WARNING: This feature is currently intended for non-Android systems. Can works also on Android system, but to keep in mind that it is not possible to maintain the same DRM session, this mismatch will result in the license data may not working.
DATA TYPE: str
EXAMPLE: "pre_init_data": "PSSH encoded base 64|KID encoded base 64"
π΅ persistent_storage - Enables the CDM persistent state
Set to `True` to enable the CDM persistent state. This allow to store locally the session data or other type of state. To be enabled only if the streaming service requires it.
DATA TYPE: bool
EXAMPLE: "persistent_storage": True
π΅ secure_decoder - To enable/disable secure decoder
Set to `True` or `False` to "force" enable or disable the secure decoder, every time this is set will override the user settings set on the ISA add-on settings window.
NOTE: If you dont want override the ISA add-on user settings, remember to remove secure_decoder
parameter and so add it only when needed.
Disable the secure decoder could be helpful for some android devices where playback may result in a black screen, usually due to faulty Widevine L1 certifications.
DATA TYPE: bool
EXAMPLE: "secure_decoder": True
π΅ force_single_session - To enforce the usage of a single DRM session
Depending on the DRM-backend capabilities it may be needed to execute one or more requests towards the backend in order to get all the keys needed for the playback, this is the case of multi-key playback. One of the multi-key setup is with audio and video tracks being encrypted with different keys. In this case when the player dont know what KIDs are supported by the license it creates two DRM sessions by default, one for audio and one for video. To disable this behaviour (when possible) you can enforce the usage of a single DRM session if DRM-backend is certain to return all the keys in one request. Disabling it can save time by avoiding multiple license requests, but it may lead to playback problems such as corrupted/pixellated videos.
DATA TYPE: bool
EXAMPLE: "force_single_session": True
π΅ optional_key_req_params - To set specific initialization CDM parameters
This parameter is closely related to the type of CDM used, allows you to configure CDM initialization parameters usually used for the key request.
PlayReady DRM:
custom_data
Allow to set data to the PRCustomData
CDM parameter to make the key request.
DATA TYPE: dict
EXAMPLE: "optional_key_req_params": {"custom_data": "the data"}
π inputstream.adaptive.drm
- Examples [click to expand]
listitem = xbmcgui.ListItem(path='https://www.videoservice.com/manifest.mpd', offscreen=True)
# These two lines are needed to prevent the HTTP HEAD request from Kodi core, used to determine the mimetype
listitem.setMimeType('application/dash+xml')
listitem.setContentLookup(False)
listitem.setProperty('inputstream', 'inputstream.adaptive')
license_headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/109.0',
'Content-Type': 'application/octet-stream'
}
# Example configuration with drm_legacy property
listitem.setProperty('inputstream.adaptive.drm_legacy', 'com.widevine.alpha|https://www.licenseserver.com/acquirelicense|' + urlencode(license_headers))
# Example configuration with drm property
drm_cfg = {"com.widevine.alpha":
{"license":
{"server_url": "https://www.licenseserver.com/acquirelicense",
"req_headers": urlencode(license_headers)}
}
}
listitem.setProperty('inputstream.adaptive.drm', json.dumps(drm_cfg))
xbmcplugin.setResolvedUrl(pluginhandle, True, listitem=listitem)
#KODIPROP:inputstream=inputstream.adaptive
# Example configuration with drm_legacy property
#KODIPROP:inputstream.adaptive.drm_legacy=com.widevine.alpha|https://www.licenseserver.com/acquirelicense|User-Agent=Mozilla%2F5.0+%28Windows+NT+10.0%3B+Win64%3B+x64%29+AppleWebKit%2F537.36+%28KHTML%2C+like+Gecko%29+Chrome%2F106.0.0.0+Safari%2F537.36
# Example configuration with drm property
#KODIPROP:inputstream.adaptive.drm={"com.widevine.alpha":{"license": {"server_url": "https://www.licenseserver.com/acquirelicense","req_headers": "User-Agent=Mozilla%2F5.0+%28Windows+NT+10.0%3B+Win64%3B+x64%29+AppleWebKit%2F537.36+%28KHTML%2C+like+Gecko%29+Chrome%2F106.0.0.0+Safari%2F537.36"}}}
#KODIPROP:mimetype=application/dash+xml
https://www.videoservice.com/manifest.mpd
listitem = xbmcgui.ListItem(path='https://www.videoservice.com/tearsofsteel_4k.ism/manifest', offscreen=True)
# These two lines are needed to prevent the HTTP HEAD request from Kodi core, used to determine the mimetype
listitem.setMimeType('application/vnd.ms-sstr+xml')
listitem.setContentLookup(False)
listitem.setProperty('inputstream', 'inputstream.adaptive')
# Example configuration with drm_legacy property
listitem.setProperty('inputstream.adaptive.drm_legacy', 'com.microsoft.playready')
# Example configuration with drm property
listitem.setProperty('inputstream.adaptive.drm', '{"com.microsoft.playready": {}}')
xbmcplugin.setResolvedUrl(pluginhandle, True, listitem=listitem)
listitem = xbmcgui.ListItem(path='https://www.videoservice.com/master_manifest.m3u8', offscreen=True)
# These two lines are needed to prevent the HTTP HEAD request from Kodi core, used to determine the mimetype
listitem.setMimeType('application/vnd.apple.mpegurl')
listitem.setContentLookup(False)
listitem.setProperty('inputstream', 'inputstream.adaptive')
# Usually there is no need to set inputstream.adaptive.drm or inputstream.adaptive.drm_legacy
# but, if you need to add custom headers or parameters to the HLS HTTP key request's
# you can use the following configuration (the Key System is, none):
encrypt_cfg = {"none":{"license": {"req_headers": "User-Agent=Mozilla%2F5.0+%28Windows+NT+10.0%3B+Win64%3B+x64%29+AppleWebKit%2F537.36+%28KHTML%2C+like+Gecko%29+Chrome%2F106.0.0.0+Safari%2F537.36", "req_params": "/example/param"}}}
listitem.setProperty('inputstream.adaptive.drm', json.dumps(encrypt_cfg))
xbmcplugin.setResolvedUrl(pluginhandle, True, listitem=listitem)
listitem = xbmcgui.ListItem(path='https://www.videoservice.com/manifest.mpd', offscreen=True)
# These two lines are needed to prevent the HTTP HEAD request from Kodi core, used to determine the mimetype
listitem.setMimeType('application/dash+xml')
listitem.setContentLookup(False)
listitem.setProperty('inputstream', 'inputstream.adaptive')
# To provide clear keys, use:
drm_cfg = {"org.w3.clearkey":
{"license":
{"keyids": { "KID_1": "KEY_1", "KID_2": "KEY_2" }}
}
}
# To set a license server url, use:
drm_cfg = {"org.w3.clearkey":
{"license":
{"server_url": "https://www.licenseserver.com/AcquireLicense/"}
}
}
# If the manifest embed the license server url, you can leave empty:
drm_cfg = {"org.w3.clearkey": {} }
listitem.setProperty('inputstream.adaptive.drm', json.dumps(drm_cfg))
xbmcplugin.setResolvedUrl(pluginhandle, True, listitem=listitem)
List of supported DRM Key Systems, required to set a DRM configuration.
DRM Name | Key System |
---|---|
Widevine | com.widevine.alpha |
PlayReady (android only) | com.microsoft.playready |
Wiseplay (android only) | com.huawei.wiseplay |
ClearKey (from v.21.5.0 / Kodi 21) | org.w3.clearkey |
Special case, for encryptions without DRM (Kodi 22+) | none |
The special case none
can be used to set some parameters to other encryption cases for example HLS AES-128.
π€ License URL too long - How to solve PVR binary API bug (Only for Kodi v20-v21) [click to expand]
On all Kodi versions until v21, there is a know Kodi PVR API interface bug, that truncate ISAdaptive properties values to max 1024 chars, then if the server license URL is too long will trucate the data set on the InputStream properties (e.g. inputstream.adaptive.license_key
), and the video playback will fails.
The PVR API bug has been fixed on Kodi v22.
To workaround this bug, has been added these two properties (that can be used only on Kodi 20/21) to split the URL on two parts of 1024 chars:
-
inputstream.adaptive.license_url
[deprecated on Kodi 22] -
inputstream.adaptive.license_url_append
[deprecated on Kodi 22]
How to do:
- Leave empty the field used to set the license URL (e.g. on
inputstream.adaptive.license_key
the [license server URL] template field) - Take care to split the license server url in two parts of 1024 chars, then use
license_url
to specify the first 1024 chars, andlicense_url_append
to add the last part of remaining url chars.
NOTE: On Kodi v20, has been introduced from ISA v20.3.15
π€ How to configure a PlayReady manifest to use Widevine [click to expand]
Some video services can use manifests (often SmoothStreaming) protected with PlayReady DRM and provide also a Widevine server license URL. Then it is possible try to force use Widevine DRM to play the contents protected with PlayReady DRM. This is useful because currently the use of PlayReady is limited on android only, and some android devices may not support PlayReady.
NOTE: Works only when the manifest provides a single DRM encryption scheme and there is set only one DRM configuration (when using the inputstream.adaptive.drm
property).
To force Widevine you need just to specify "com.widevine.alpha" (instead of "com.microsoft.playready") and set the license server URL, as follow:
listitem = xbmcgui.ListItem(path='https://www.videoservice.com/tearsofsteel_4k.ism/manifest', offscreen=True)
# These two lines are needed to prevent the HTTP HEAD request from Kodi core, used to determine the mimetype
listitem.setMimeType('application/vnd.ms-sstr+xml')
listitem.setContentLookup(False)
listitem.setProperty('inputstream', 'inputstream.adaptive')
listitem.setProperty('inputstream.adaptive.manifest_type', 'ism') # Deprecated on Kodi 21, removed on Kodi 22
if Kodi < v21:
listitem.setProperty('inputstream.adaptive.license_type', 'com.widevine.alpha')
listitem.setProperty('inputstream.adaptive.license_key', 'https://widevinelicenseserverurl')
if Kodi >= v21:
listitem.setProperty('inputstream.adaptive.drm_legacy', 'com.widevine.alpha|https://widevinelicenseserverurl')
xbmcplugin.setResolvedUrl(pluginhandle, True, listitem=listitem)
-
On Kodi <= v21: Set your custom data by using
inputstream.adaptive.license_data
property. -
On Kodi >= v22: Set your custom data by using
init_data
parameter frominputstream.adaptive.drm
property.
# Example for Kodi >= v22
drm_config = {
"com.widevine.alpha": {
"license": {
"server_url": "https://theserverurl.com"
},
"init_data": base64.b64encode(b'CUSTOMDATA').decode('utf-8')
}
}
listitem.setProperty('inputstream.adaptive.drm', json.dumps(drm_config))
xbmcplugin.setResolvedUrl(pluginhandle, True, listitem=listitem)
Read properties/parameters guide for more details.
π€ ClearKey DRM remarks and limitations [click to expand]
- This DRM was implemented later time in Kodi v21 and can be configured from Kodi v21 by using the
inputstream.adaptive.drm_legacy
property, and from Kodi v22 also by using theinputstream.adaptive.drm
property. This choice was made because the deprecated old DRM properties will be removed in near future. So we want to encourage the use of the new methods to limit future changes needed. - It can be used to test streams protected with other types of DRM's, by providing the appropriate kid / key's pairs.
- CBCS encryption is supported from Kodi v22.
- The format for the license request and response meets the W3C standard https://www.w3.org/TR/encrypted-media/#clear-key-request-format
- Streams using DRM Key Rotation feature cant be supported.
- Compatibility with Microsoft SmoothStreaming manifest (to override DRM) has been implemented from Kodi v22.