Skip to content
Stefano Gottardo edited this page Mar 26, 2024 · 115 revisions

To play multi bitrate streams from an add-on you need to set a few ListItem properties in order to tell Kodi

  • that inputstream.adaptive should be selected for demuxing the stream
  • how to handle the decryption (if the stream is DRM protected)

Here we provide examples for python add-ons but can also be adapted for binary add-ons.

Examples for Kodi v19 and above

Play unencrypted video stream

listitem = xbmcgui.ListItem(path='https://www.videoservice.com/manifest.mpd')

listitem.setMimeType('application/xml+dash')
listitem.setContentLookup(False)

listitem.setProperty('inputstream', 'inputstream.adaptive')
listitem.setProperty('inputstream.adaptive.manifest_type', 'mpd') # Deprecated on Kodi 21

xbmcplugin.setResolvedUrl(pluginhandle, True, listitem=listitem)

Play DRM encrypted video stream

listitem = xbmcgui.ListItem(path='https://www.videoservice.com/manifest.mpd')

listitem.setMimeType('application/xml+dash')
listitem.setContentLookup(False)

listitem.setProperty('inputstream', 'inputstream.adaptive')
listitem.setProperty('inputstream.adaptive.manifest_type', 'mpd') # Deprecated on Kodi 21
listitem.setProperty('inputstream.adaptive.license_type', 'com.widevine.alpha')

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',
    'Origin': 'https://www.somesite.com'
}
from urllib.parse import urlencode
license_config = { # for Python < v3.7 you should use OrderedDict to keep order
    'license_server_url': 'https://license.server.com/licenserequest',
    'headers': urlencode(license_headers),
    'post_data': 'R{SSM}',
    'response_data': 'R'
}
listitem.setProperty('inputstream.adaptive.license_key', '|'.join(license_config.values()))

xbmcplugin.setResolvedUrl(pluginhandle, True, listitem=listitem)

Properties

Deprecation meaning: When a property is marked as "deprecated" it means that a FEATURE could be REMOVED starting from the next Kodi version specified, and therefore changes are required in your add-on as soon as possible. To avoid playback problems, we recommend you to making the necessary changes to your add-on for the version of Kodi in which the property is marked as deprecated.

inputstreamaddon / inputstream

[mandatory]

This property must be set to tell kodi to use inputstream.adaptive add-on to handle the stream

For Kodi 19.x and above:

listitem.setProperty('inputstream', 'inputstream.adaptive')

For Kodi 18.x:

listitem.setProperty('inputstreamaddon', 'inputstream.adaptive')

inputstream.adaptive.manifest_type

[mandatory, until to Kodi v20]

Specify the manifest type of the media stream.

Possible values are:

  • mpd for MPEG-DASH
  • hls for HLS - HTTP Live Streaming
  • ism for Microsoft Smooth Streaming Media
listitem.setProperty('inputstream.adaptive.manifest_type', 'mpd')

WARNING: THIS PROPERTY HAS BEEN DEPRECATED ON Kodi v21, because the manifest type is now auto-detected. If you have experienced problems by removing this property by using proxy to manipulate manifests, more likely you miss to add the appropriate header in proxy manifest HTTP response, read "How to provide custom manifest and license" page for more details.

inputstream.adaptive.license_type

[mandatory for DRM encrypted media]

Specify which DRM system should be used, possible values are:

  • For Google Widevine: com.widevine.alpha *note 1
  • For Microsoft PlayReady: com.microsoft.playready (available on Android only)
  • For Huawei WisePlay: com.huawei.wiseplay (available on Android only)

*note 1: On all other systems different from Android is required the installation of Widevine library, not included with this add-on. To handle the library installation automatically we suggest to use InputStream Helper add-on.

listitem.setProperty('inputstream.adaptive.license_type', 'com.widevine.alpha')

inputstream.adaptive.license_key

[mandatory for some DRM encrypted media]

Specify the license_key to configure how InputStream Adaptive handle the DRM license for the decryption. Following guidelines can only be used for Widevine / WisePlay DRM's, The PlayReady DRM do not support this parameter, because license-URL is part of the PlayReady WRM header.

The license_key parameter is composed by a string template with 4 fields separated by pipe | chars:

[license server URL] | [Headers] | [Post-Data] | [Response-Data] (without spaces)

NOTE: For HLS AES encrypted, the key URL is supported in the HLS playlist, and for this use case the license_key parameter works this way, taking into account only the first two template fields:

[parameters to append to the key URL] | [Key URL Headers] || (without spaces)

Configuration example

license_headers = {
    'header-name': 'header-value',
    'Content-Type': 'application/octet-stream',
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/109.0',
    'Origin': 'https://www.somesite.com'
}

from urllib.parse import urlencode

license_config = { # for Python < v3.7 you should use OrderedDict to keep order
    'license_server_url': 'https://license.server.com/licenserequest',
    'headers': urlencode(license_headers),
    'post_data': 'R{SSM}',
    'response_data': 'R'
}

listitem.setProperty('inputstream.adaptive.license_key', '|'.join(license_config.values()))

# if you prefer you can set the configuration directly as a single string,
# just be careful to encode the fields in the appropriate way

listitem.setProperty('inputstream.adaptive.license_key', 'https:\\www.licserver.com\data\example\{HASH}||b{SSM}b{SID}|B')

Detailed explanation of the template fields

[license server URL]
The license server URL where make the license HTTP request. In the URL is possible optionally inject the DRM Challenge by using following placeholders:

  • B{SSM} Inject to the URL the DRM Challenge as base64, URL encoded
  • {HASH} Inject to the URL the DRM Challenge hashed as MD5

[Headers]
Allow you to add the HTTP headers for the license HTTP request, the paramters will be URL encoded automatically.

The headers must be follow this scheme: param1=value1&param2=value2

[Post-Data]
You can use this field to make an HTTP post request with data. Optionally this field can be set with URL encoded text. To enable the post request you have add the placeholder:

  • [R/b/B/D]{SSM} placeholder to transport the DRM Challenge After that you can add also other optional data as:
  • [R/b/B]{SID} placeholder to transport the DRM Session ID
  • [R/H]{KID} placeholder to transport the DRM Key ID
  • [b/B]{PSSH} placeholder to transport the initial PSSH (Android only)

Only 1 prefix parameter allowed, summary:
R - The data will be kept as is raw
b - The data will be base64 encoded
B - The data will be base64 encoded and URL encoded
D - The data will be decimal converted (each char converted as integer concatenated by comma)
H - The data will be hexadecimal converted (each character converted as hexadecimal and concatenated)

[Response-Data]
Specify how handle the data of HTTP license response:

  • Not specified, or, R if the response payload is in binary raw format
  • B if the response payload is encoded as base64
  • J[license tokens] if the response payload is in JSON format. You must specify the license tokens names to allow inputstream.adaptive searches for the license key and optionally the HDCP limit. The tokens must be separated by ;. The first token must be for the key license, the second one, optional, for the HDCP limit. The HDCP limit is the result of resolution width multiplied for its height. For example to limit until to 720p: 1280x720 the result will be 921600.
  • JB[license tokens] same meaning of J[license tokens] but the value contained in the JSON path is encoded as base64.
  • BJ[license tokens] same meaning of J[license tokens] but the JSON is encoded as base64 and the value contained in the JSON path is raw.
  • HB if the response payload is after two return chars \r\n\r\n in binary raw format.

Default behaviour when license_key parameter is not set

The template field will be filled as:

  • Widevine: [license server URL] | Content-Type=application/octet-stream | R{SSM} | R
  • PlayReady: [license server URL] | Content-Type=text/xml&SOAPAction=http://schemas.microsoft.com/DRM/2007/03/protocols/AcquireLicense | R{SSM} | R
  • WisePlay: [license server URL] | Content-Type=application/json | R{SSM} | R

inputstream.adaptive.license_data

Allow to specify the PSSH initialization license data.

Can be used when a MPEG-DASH manifest do not specify the ContentProtection tag with schemeIdUri attribute to identify a content protection scheme for a specific DRM. The data provided must be encoded as base64.

The placeholder {KID} can be used to specify where to inject the default KID into the initialization data, it must also be base64 encoded with the data.
WARNING: Due to its limited and specific use case, moreover for a difficult future maintenances, the placeholder {KID} HAS BEEN REMOVED FROM Kodi v21. We discourage its use even on older versions of Kodi, as the KID obtained is specifically limited only to some DASH PlayReady ContentProtection tags.

listitem.setProperty('inputstream.adaptive.license_data', 'base64data')

WARNING: Currently there are undocumented mixed features of this property that some old add-on may use, these will be reviewed and changed in the future versions, so may break your addon. But genarally speaking the main purpose to set the initialization PSSH data will be kept.

inputstream.adaptive.manifest_params

Specifies the HTTP parameters to be used to download the manifests.

For protocols like HLS, the parameters will be applied to all manifest urls childrens.

listitem.setProperty('inputstream.adaptive.stream_params', 'paramname=value&paramname2=value2')

inputstream.adaptive.license_url

[for PVR binary addons only]

The license_url and license_url_append properties are an exclusive workaround for PVR binary addons, the reason behind this is that Kodi PVR API has a bug that truncate ISAdaptive properties values to max 1024 chars, then when inputstream.adaptive.license_key exceeds the limit the video playback will fails.

The solution is:

  1. Leave empty the inputstream.adaptive.license_key [license server URL] template field
  2. Take care to split the license server url in two parts of 1024 chars, then use license_url to specify the first 1024 chars, and license_url_append to add the last part of remaining url chars.

NOTE: On Kodi v20 has been introduced from version 20.3.15

inputstream.adaptive.license_url_append

[for PVR binary addons only]

Used to add the license url remaining chars that exceeds 1024 chars limit, read inputstream.adaptive.license_url.

NOTE: On Kodi v20 has been introduced from version 20.3.15

inputstream.adaptive.manifest_headers

Specifies the HTTP headers to be used to download manifests.

For protocols like HLS, the headers will be applied to all manifest urls childrens.

listitem.setProperty('inputstream.adaptive.manifest_headers', 'headername=value&User-Agent=the_user_agent&cookie=the_cookies')

NOTE: if you set "cookie" header, the value containing the cookies should be URL encoded.

inputstream.adaptive.manifest_update_parameter

WARNING: THIS PROPERTY HAS BEEN DEPRECATED ON Kodi v21, please use manifest_upd_params instead.

This property force enable manifest updates for LIVE contents after each segment played, but usually it should be enabled automatically. In some cases could be used to solve HTTP error 404 when download the segments due to missing updates.

WARNING: Do not enable it with VOD type manifest.

To enable the manifest update

Set full as value. WARNING: THE "full" BEHAVIOUR PARAM HAS BEEN REMOVED ON Kodi v21 because now enabled by default, so when the MPD.Type is dynamic (live content).

To enable the manifest update and customize URL parameters

For MPEG-DASH manifest, you can enable and also customize the URL parameters for the manifest HTTP request.

Just set as value the URL paramenters to be add, URL encoded. In order to work you must add also the placeholder $START_NUMBER$ to set the next segment start number in the URL parameter.

Example: ?foo=bar&baz=qux&start_seq=$START_NUMBER$

listitem.setProperty('inputstream.adaptive.manifest_update_parameter', 'full')

NOTE: On Kodi v21 $START_NUMBER$ placeholder support has been removed.

inputstream.adaptive.manifest_upd_params

This property allows parameters to be added to the URL used to request manifest updates in LIVE content. Currently supported for DASH manifest only.

listitem.setProperty('inputstream.adaptive.manifest_upd_params', '?foo=bar&baz=qux')

inputstream.adaptive.stream_params

Specifies the HTTP parameters to be used to download streams (audio/video/subtitles).

listitem.setProperty('inputstream.adaptive.stream_params', 'paramname=value&paramname2=value2')

inputstream.adaptive.stream_headers

On Kodi v19 or below:
Specifies the HTTP headers to be used to download manifests and streams (audio/video/subtitles).

On Kodi v20:
Specifies the HTTP headers to be used to download manifests and streams (audio/video/subtitles).
NOTE: Use this property to set headers to the manifests is a deprecated behaviour, use inputstream.adaptive.manifest_headers instead.

From Kodi v21 or above:
Specifies the HTTP headers to be used to download streams (audio/video/subtitles) only.

listitem.setProperty('inputstream.adaptive.stream_headers', 'headername=value&User-Agent=the_user_agent&cookie=the_cookies')

NOTE: if you set "cookie" header, the value containing the cookies should be URL encoded.

inputstream.adaptive.server_certificate

Specifies a server certificate to be used to encrypt messages to the license server. Should be encoded as Base64.

listitem.setProperty('inputstream.adaptive.server_certificate', 'certificate_data')

inputstream.adaptive.license_flags

Can be used to force some behaviours.

Possible values are:

  • 'persistent_storage': To force the server certificate (available only on OS's other than Android)
  • 'force_secure_decoder': To force secure decoder

More than one flag can be set, you can separate by comma.

listitem.setProperty('inputstream.adaptive.license_flags', 'persistent_storage')

inputstream.adaptive.play_timeshift_buffer

Allow to start playing a LIVE stream from the beginning of the buffer instead of its end, useful for example for sports channels.

Possible values are: true / false (default)

listitem.setProperty('inputstream.adaptive.play_timeshift_buffer', 'true')

inputstream.adaptive.live_delay

Intended for LIVE contents, set a delay from the live edge, this may be used to mitigate problems caused by a player that requests segments that do not exist yet (getting http 404 errors or causing audio buzzing). A reasonable value may be 2 to 4 times the segment duration, but not smaller than 16 seconds.

Be aware that some manifest types already include the configuration of this property (e.g. DASH with suggestedPresentationDelay), so set this property will override the manifest value (if any).

Possible values are: a number greater or equal than 16 (default), lower values are so ignored.

listitem.setProperty('inputstream.adaptive.live_delay', '16')

inputstream.adaptive.max_bandwidth

Allows to set the maximum stream bandwidth. The value is defined in bit/s.

This property can override the user setting Maximum bandwidth, but only if the value is less than the user setting.

listitem.setProperty('inputstream.adaptive.max_bandwidth', '100000000000')

WARNING: THIS PROPERTY HAS BEEN DEPRECATED ON Kodi v20 and is replaced by another one, see page Stream selection types properties for more details.
WARNING: THIS PROPERTY HAS BEEN REMOVED FROM Kodi v21.

inputstream.adaptive.original_audio_language

Allow to set the Kodi flag "original audio language", to the audio streams that match the specified language code.

Should be set the language code with ISO 639-1 standard (Kodi support this standard only).

NOTE: If the manifest set the original language to the streams, this not override the manifest properties.

listitem.setProperty('inputstream.adaptive.original_audio_language', 'it')

inputstream.adaptive.pre_init_data

Some VOD services works with licensed manifests. Compared to the standard manifests, this one also encloses the license data in the manifest.

Usually the request for these types of manifests are customised by the service, so a proxy managed by your add-on will have to act as an intermediary between ISAdaptive and your VOD service, in order to allow your add-on to generate an appropriate manifest request with the DRM data and then make it instead of ISAdaptive.

Enabling this feature you must provide a PSSH and KID. Both values must be provided encoded as Base 64.

listitem.setProperty('inputstream.adaptive.pre_init_data', 'PSSH encoded base 64|KID encoded base 64')

This will pre-initialize the DRM by opening a DRM session and will provide these data in the ISAdaptive HTTP manifest request:

  • challengeB64 - The Challenge (Key Request) value encoded as base 64, and URL encoded.
  • sessionId - The Session ID value in clear.

You can intercept the ISAdaptive manifest/license HTTP requests by implementing a proxy server in your add-on, as in the example How to provide custom manifest and license, will allow you to create the appropriate manifest data and manage the HTTP request through your add-on. When you will get the HTTP manifest response, you will also need to transfer the license data into the ISAdaptive license HTTP request.

WARNINGS:

  • Do not enable this feature without a proxy server in an add-on, otherwise the DRM data will not be managed.
  • 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.

inputstream.adaptive.stream_selection_type

Allow an add-on to overridden the InputStream Adaptive "stream selection type" setting. Can be used to have customised behaviour on the selection of the audio/video quality of the streams.

Caution: This will make the "stream selection type" setting in the InputStream Adaptive setting window ineffective, so consider allowing the user choice to change this setting in your add-on.

inputstream.adaptive.internal_cookies

Some video services require you to accept cookies and send cookies along with requests such as manifest update, segments, etc.. Most common use case is when cookies are used as authentication to get files, so at the first HTTP request of the manifest, the server send a "Set-Cookies" header from HTTP response, which the client will have to use for each subsequent request.

Set to True to allow ISAdaptive add-on to handle cookies internally in a persistent way between HTTP sessions. If disabled (default) cookies will be handled by Kodi in a NON-persistent way, so they will be deleted after a certain period of time of video playback.

Possible values are: true / false (default)

listitem.setProperty('inputstream.adaptive.internal_cookies', 'true')
Clone this wiki locally