Skip to content
Open
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
4 changes: 4 additions & 0 deletions resources/language/resource.language.en_gb/strings.po
Original file line number Diff line number Diff line change
Expand Up @@ -1073,3 +1073,7 @@ msgstr ""
msgctxt "#30332"
msgid "Helix API"
msgstr ""

msgctxt "#30333"
msgid "Use inputstream.ffmpegdirect for live streams"
msgstr ""
18 changes: 18 additions & 0 deletions resources/lib/twitch_addon/addon/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,24 @@ def inputstream_adpative_supports(feature):
return False


def use_ffmpegdirect_for_live():
"""Whether live streams should be played through inputstream.ffmpegdirect.

Optional alternative live-playback backend (off by default): ffmpegdirect uses
ffmpeg's own demuxer and manages realtime buffering itself, instead of
inputstream.adaptive / Kodi's direct player. Some devices and setups play
Twitch live more reliably through it (e.g. it avoids the inputstream.adaptive
live-HLS demuxer issues seen on some Kodi 22 / CoreELEC builds, and the
occasional "cache full 100%" buffering stall). Returns False when the option
is off or the add-on isn't installed/enabled, leaving the default IA / direct
behaviour untouched. VODs and clips are never affected.
"""
if kodi.get_setting('live_use_ffmpegdirect') != 'true':
return False
# addon_enabled() returns True/False when installed, None when missing.
return kodi.addon_enabled('inputstream.ffmpegdirect') is True


def format_isa_headers(headers):
# key=value&... (url-encoded) for InputStream Adaptive stream_headers / manifest_headers properties.
return '&'.join(['%s=%s' % (key, quote_plus(headers[key])) for key in headers])
Expand Down
27 changes: 24 additions & 3 deletions resources/lib/twitch_addon/routes/play.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,17 +151,28 @@ def _set_seek_time(value):
if result:
quality_label = result['name']

# Optional alternative live-playback backend (off by default): when enabled
# and available, play live streams through inputstream.ffmpegdirect instead
# of inputstream.adaptive / the direct player. Live only -- VODs and clips
# keep the default behaviour.
use_ffmpegdirect = is_live and utils.use_ffmpegdirect_for_live()

request = None
play_url = None
if quality_label == 'Adaptive' and use_ia:
if quality_label == 'Adaptive' and (use_ia or use_ffmpegdirect):
if video_id:
request = api.video_request(video_id)
elif is_live:
request = api.live_request(name)
if request:
if kodi.get_kodi_version().major >= 18:
request['headers']['verifypeer'] = 'false'
play_url = request['url'] # headers passed via ISA stream/manifest_headers below
if use_ffmpegdirect:
# ffmpegdirect (open_mode=ffmpeg) reads HTTP headers from the
# URL's |Header=... suffix, not from ISA manifest_headers.
play_url = request['url'] + utils.append_headers(request['headers'])
else:
play_url = request['url'] # headers passed via ISA stream/manifest_headers below

if not play_url:
play_url = result['url']
Expand Down Expand Up @@ -197,7 +208,17 @@ def _set_seek_time(value):
playback_item.setMimeType('video/mp4')
except AttributeError:
pass
if quality_label == 'Adaptive' and use_ia:
if use_ffmpegdirect:
inputstream_property = 'inputstream'
if kodi.get_kodi_version().major < 19:
inputstream_property += 'addon'
# ffmpeg's demuxer + its own realtime buffering. Covers both a specific
# quality (variant URL) and Adaptive (master URL).
playback_item.setProperty(inputstream_property, 'inputstream.ffmpegdirect')
playback_item.setProperty('inputstream.ffmpegdirect.is_realtime_stream', 'true')
playback_item.setProperty('inputstream.ffmpegdirect.manifest_type', 'hls')
playback_item.setProperty('inputstream.ffmpegdirect.open_mode', 'ffmpeg')
elif quality_label == 'Adaptive' and use_ia:
inputstream_property = 'inputstream'
if kodi.get_kodi_version().major < 19:
inputstream_property += 'addon'
Expand Down
4 changes: 4 additions & 0 deletions resources/settings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@
<setting id="video_quality_ia_configure" type="action" label="30224" enable="eq(-1,true)+eq(-2,true)" visible="eq(-1,true)+eq(-2,true)" option="close" action="RunPlugin(plugin://$ID/?mode=configure_ia)"/>
<!-- Supported codecs (Twitch Enhanced Broadcasting: HEVC enables 1440p+ variants; requires hardware decode) -->
<setting id="supported_codecs" type="enum" label="30307" lvalues="30308|30309" default="0"/>
<!-- Optional alternative live-playback backend: play live streams through
inputstream.ffmpegdirect instead of inputstream.adaptive / the direct player.
Off by default; only affects live (not VODs/clips). -->
<setting id="live_use_ffmpegdirect" type="bool" label="30333" default="false"/>
<!-- Title Display -->
<setting id="title_display" type="enum" label="30045" lvalues="30046|30047|30048|30049|30051|30067|30054" default="0"/>
<!-- Truncate titles -->
Expand Down