xbmc / inputstream.adaptive

kodi inputstream addon for several manifest types
Other
454 stars 242 forks source link

kodi crash with some streams with inputstream.adaptive #963

Closed TermeHansen closed 2 years ago

TermeHansen commented 2 years ago

Bug report

Describe the bug

When starting playback of some specific streams via the plugin.video.drnu addon, kodi will crash when using the adaptive inputstream. When using the normal ffmpeg demuxer it will play but will crash when trying to skip.

Expected Behavior

Normal playback of hls stream

Actual Behavior

kodi crashes with no errors in debug log

To Reproduce

Play a .strm file with:

#KODIPROP:inputstream=inputstream.adaptive
#KODIPROP:inputstream.adaptive.manifest_type=hls
https://drod22d.akamaized.net/dk/encrypted/none/b4/625ef6edaa5a612268e778b4/00022162620/stream_fmp4/master_manifest.m3u8

master_manifest.m3u8

Debuglog

The debug log can be found here: https://pastebin.com/qPSALQ9v

crashlog https://pastebin.com/fk89XGBc

Additional context

tried with ffmpegdirect. It starts but kodi crash when trying to skip...

#KODIPROP:inputstream=inputstream.ffmpegdirect
#KODIPROP:mimetype=application/x-mpegURL
#KODIPROP:inputstream.ffmpegdirect.manifest_type=hls
https://drod22d.akamaized.net/dk/encrypted/none/b4/625ef6edaa5a612268e778b4/00022162620/stream_fmp4/master_manifest.m3u8

Your Environment

Used Operating system:

CastagnaIT commented 2 years ago

i need two more things: attach here the https://drod22d.akamaized.net/dk/encrypted/none/b4/625ef6edaa5a612268e778b4/00022162620/stream_fmp4/master_manifest.m3u8 file

and provide stacktrace error, you can get it by running this in your ubuntu terminal:

should display the error stack trace list

TermeHansen commented 2 years ago

I already wrote the link earlier for the master_manifest.m3u8 that I have posted to pastebin as I can not attach .m3u8 files here...

gdb gave this:

[New Thread 0x7fffd67fc700 (LWP 51058)]
--Type <RET> for more, q to quit, c to continue without paging--

Thread 6 "ActiveAE" received signal SIGFPE, Arithmetic exception.
[Switching to Thread 0x7fffd77fe700 (LWP 51017)]
0x000055555703b2f3 in ActiveAE::CActiveAEBufferPool::Create(unsigned int) ()
(gdb) bt full
#0  0x000055555703b2f3 in ActiveAE::CActiveAEBufferPool::Create(unsigned int) ()
No symbol table info available.
#1  0x00005555570342fd in ActiveAE::CActiveAE::Configure(AEAudioFormat*) ()
No symbol table info available.
#2  0x000055555703778f in ActiveAE::CActiveAE::StateMachine(int, Actor::Protocol*, Actor::Message*) ()
No symbol table info available.
#3  0x0000555557038743 in ActiveAE::CActiveAE::Process() ()
No symbol table info available.
#4  0x0000555556609331 in CThread::Action() ()
No symbol table info available.
#5  0x000055555660b565 in ?? ()
No symbol table info available.
#6  0x000055555660c08d in ?? ()
No symbol table info available.
#7  0x00007ffff5e02de4 in ?? () from /lib/x86_64-linux-gnu/libstdc++.so.6
No symbol table info available.
#8  0x00007ffff7624609 in start_thread (arg=<optimized out>) at pthread_create.c:477
        ret = <optimized out>
        pd = <optimized out>
        unwind_buf = {cancel_jmp_buf = {{jmp_buf = {140736808871680, -8742103893974472751, 140737488345598, 
                140737488345599, 140737488345600, 140736808868928, 8742155572215261137, 8742085113886910417}, 
              mask_was_saved = 0}}, priv = {pad = {0x0, 0x0, 0x0, 0x0}, data = {prev = 0x0, cleanup = 0x0, 
              canceltype = 0}}}
        not_first_call = 0
#9  0x00007ffff6241163 in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95
No locals.

and then

(gdb) continue
Continuing.
Couldn't get registers: No such process.
Couldn't get registers: No such process.
(gdb) [Thread 0x7fffd67fc700 (LWP 51058) exited]
[Thread 0x7fff6cff9700 (LWP 51057) exited]
[Thread 0x7fff6d7fa700 (LWP 51056) exited]
[Thread 0x7fff6dffb700 (LWP 51055) exited]
[Thread 0x7fff6e7fc700 (LWP 51054) exited]
[Thread 0x7fff6effd700 (LWP 51053) exited]
[Thread 0x7fff6f7fe700 (LWP 51052) exited]
[Thread 0x7fff6ffff700 (LWP 51051) exited]
[Thread 0x7fff88c49700 (LWP 51046) exited]
[Thread 0x7fff89ffb700 (LWP 51039) exited]
[Thread 0x7fff8a7fc700 (LWP 51038) exited]
[Thread 0x7fff8affd700 (LWP 51037) exited]
[Thread 0x7fff8bfff700 (LWP 51035) exited]
[Thread 0x7fffa0ff9700 (LWP 51034) exited]
[Thread 0x7fffa17fa700 (LWP 51033) exited]
[Thread 0x7fffa1ffb700 (LWP 51032) exited]
[Thread 0x7fffa27fc700 (LWP 51031) exited]
[Thread 0x7fffa2ffd700 (LWP 51030) exited]
[Thread 0x7fffa37fe700 (LWP 51029) exited]
[Thread 0x7fffa3fff700 (LWP 51028) exited]
[Thread 0x7fffb0f0b700 (LWP 51027) exited]
[Thread 0x7fffb2139700 (LWP 51024) exited]
[Thread 0x7fffb3fff700 (LWP 51023) exited]
[Thread 0x7fffd6ffd700 (LWP 51018) exited]
[Thread 0x7fffd77fe700 (LWP 51017) exited]
[Thread 0x7ffff0d70700 (LWP 51015) exited]
[Thread 0x7ffff1571700 (LWP 51013) exited]
[Thread 0x7ffff15750c0 (LWP 51009) exited]

Program terminated with signal SIGFPE, Arithmetic exception.
The program no longer exists.
CastagnaIT commented 2 years ago

thank you i have reopened xbmc Issue the bug now seem to be on kodi side, we keep both opened until a maintainer of that code section gives an answer

matthuisman commented 2 years ago

Do we have a link to the Kodi bug?

I'm seeing reports of lots of playback broken on latest Nexus: https://forum.kodi.tv/showthread.php?tid=358484&pid=3096948#pid3096948

I wonder if this is the same issue?

TermeHansen commented 2 years ago

https://github.com/xbmc/xbmc/issues/21353

TermeHansen commented 2 years ago

now looking a bit closer with gdb on a debug build I did of kodi I see

from running the stream with ffmpeg direct ffmpeg_variables from running the stream with ISA inputstream_variables

So I now think the problem lies in the information that ISA provides, I will try to debug from ISA side and see if I get smarter. Totally new to debugging kodi and ISA, so any points on where to put breakpoints in ISA will be appreciated :)

@CastagnaIT can you help me where to debug this in the ISA code?

CastagnaIT commented 2 years ago

i dont know what you have debugged, without a working stream is difficult to me what say i can suggest to try start debug on these methods of main.cpp:

bool CInputStreamAdaptive::OpenStream(int streamid) void Session::UpdateStream(STREAM& stream)

to take in account that ffmpeg is different

TermeHansen commented 2 years ago

I think I need a bit more help to dig further into this.

With a breakpoint at https://github.com/xbmc/inputstream.adaptive/blob/62f60ff6c8876e48d2b7c0e2b7bc1a14505fc8ea/src/main.cpp#L1095

GetSampleDescription returns a desc with TYPE_UNKNOWN, m_format = 0 for my mp4 audio container, while for a similar stream that works I get TYPE_MPEG back as it should.

So what and where is this GetSampleDescription And how do debug this further?

failed_sampledescription works_sampledescription

TermeHansen commented 2 years ago

hmm downloading the mp4 audio data with curl myself, I can see that something is fishy. it's very small and ffprobe and file on linux can not help me on with kind of data this is - does it make sense to you @CastagnaIT

https://paste.c-net.org/AusterEpiphany

termo@X250 ~/k/k/build (Matrix)> file audio_128.mp4                                                               (base) 
audio_128.mp4: data
termo@X250 ~/k/k/build (Matrix)> ffprobe -v error -show_format -show_streams audio_128.mp4                        (base) 
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x559b850a3f00] moov atom not found
audio_128.mp4: Invalid data found when processing input
termo@X250 ~/k/k/build (Matrix) [1]> ffmpeg -i audio_128.mp4                                                      (base) 
ffmpeg version 4.2.4-1ubuntu0.1 Copyright (c) 2000-2020 the FFmpeg developers
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x559869ac0600] Format mov,mp4,m4a,3gp,3g2,mj2 detected only with low score of 1, misdetection possible!
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x559869ac0600] moov atom not found
audio_128.mp4: Invalid data found when processing input
TermeHansen commented 2 years ago

with ffmpeg I am able to download the audio stream from the master.m3u8 (can I with ffmpeg download only the first segment?). When looking at the ffprobe output between the stream that works and the one that doesn't, I see:

failing audio stream

TAG:major_brand=isom
TAG:minor_version=512
TAG:compatible_brands=isomiso2mp41
TAG:encoder=Lavf58.29.100

and for the one that works:

TAG:major_brand=iso5
TAG:minor_version=512
TAG:compatible_brands=iso6mp41iso5dash
TAG:encoder=Hybrik 1.228.25

edit: looking at the output from ffmpeg when it downloaded the audio stream it says:

    Stream #0:1(en): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 128 kb/s (default)
    Metadata:
      variant_bitrate : 1394222
      comment         : English
      major_brand     : iso5
      minor_version   : 512
      compatible_brands: iso6mp41iso5dash
      encoder         : Hybrik 1.228.25

so maybe the diff in the final files is only because of ffmpeg processing...

glennguy commented 2 years ago

@TermeHansen The audio_128.mp4 that you posted doesn't look to be an mp4 file. In the sub m3u8 file containing these segments, is there AES-128 encryption? If so the first answer here https://stackoverflow.com/questions/16132088/how-to-decrypt-aes-128-encrypted-m3u8-video-files seems to have a quick way for you to get some of the unencrypted fragments

Alternatively, if you're somehow able to mirror/download one of these 'faulty' streams as-is so we can host locally we can join the debugging efforts. What I mean is the master m3u8, sub m3u8s, and segments/keys within. But that's a lot of work for you

EDIT Also can you please attach one of the sub-m3u8 files as an example?

glennguy commented 2 years ago

Should have mentioned - the point to getting the segments is you can open them in something like https://gpac.github.io/mp4box.js/test/filereader.html to see all the details of each box

CastagnaIT commented 2 years ago

So what and where is this GetSampleDescription And how do debug this further?

this method come from bento4 sources downloaded when you build ISA: https://github.com/axiomatic-systems/Bento4 source is under folder: source/c++/core/

but we apply also other patches to upstream, that you can find in this path: https://github.com/xbmc/inputstream.adaptive/tree/Nexus/depends/common/bento4

TermeHansen commented 2 years ago

@glennguy thks for your pointers. I have tried based on https://gist.github.com/delimitry/053db410f7fdd4e1d6034a0a7fd45d9b to download and decrypt some of the segments, but I don't see something useful in the mp4box.js :(

The problem here is that the key is without IV, and as I read

An EXT-X-KEY tag with a KEYFORMAT of "identity" that does not have an IV attribute indicates that the Media Sequence Number is to be used as the IV when decrypting a Media Segment, by putting its big-endian binary representation into a 16-octet (128-bit) buffer and padding (on the left) with zeros.

I think I have done it correctly :/


import requests
import sys
from Crypto.Cipher import AES
import m3u8

base = "https://drod22d.akamaized.net/dk/encrypted/none/b4/625ef6edaa5a612268e778b4/00022162620/stream_fmp4/"
audio = "19670288-c1a4b3d4-2f57-4d1e-899d-475356f6b3b9_audio_128kbps.m3u8?aka_me_session_id=AAAAAAAAAAC9CYFiAAAAAPcWUmBPMS8F2ndUH72XjvRiD6D%2f79NvIhqU8VapMZP6GD5pzGB69w8nrlS8lSojj+%2fWPug2sX1+&aka_media_format_type=hls"

m = m3u8.load(base + audio)

def decrypt(data, key, iv):
    """Decrypt using AES CBC"""
    decryptor = AES.new(key, AES.MODE_CBC, IV=iv)
    return decryptor.decrypt(data)

def get_binary(url):
    """Get binary data from URL"""
    data = b''
    for chunk in requests.get(url, stream=True):
        data += chunk
    return data

def dump_segments(m):
    key = None
    if m.keys[0]:
        key = get_binary(m.keys[0].uri)
    i = 0
    for s in m.segments[:5]:
        data = get_binary(m.base_uri + s.uri)
        if key:
            print()
            print(i, int(i).to_bytes(16, "big"))
            print(s.uri)
            decr_data = decrypt(data, key, int(i).to_bytes(16, "big"))
        else:
            decr_data = data
        with open(f'seg_{i}.mp4','wb') as fh:
            fh.write(decr_data)
        i += 1

the decrypted mp4 audio files: https://paste.c-net.org/JacksonRomance

the raw data (not tried to decrypt) https://paste.c-net.org/PerformsChilly key = b'\xe9p;\xd4\xe7\xf5\x7f\x84\x04\x98*\x8b\x11\xfc\xb1\xe4'

top part of audio m3u8:

#EXTM3U
#EXT-X-VERSION:6
#EXT-X-PLAYLIST-TYPE:VOD
#EXT-X-INDEPENDENT-SEGMENTS
#EXT-X-TARGETDURATION:10
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-MAP:URI="19670288-c1a4b3d4-2f57-4d1e-899d-475356f6b3b9_audio_128kbps.mp4?aka_me_pasthr=AAAAAAAAAADHrX9iAAAAAKnmNv+WiZ%2f3qHxHKe02zPoEqLu+jCaXxr2gWuRLZDNo6s0WwhFVyzE589AFUXNwdaxw+2YcCEKc&aka_media_format_type=hls&aka_sign=fXPtK0QnZ6i3G03vdIRDe%2bervsUpvGLyqawy%2bfNPREQ%3d",BYTERANGE="748@0"
#EXT-X-KEY:METHOD=AES-128,URI="https://drod22d.akamaized.net/dk/encrypted/none/b4/625ef6edaa5a612268e778b4/00022162620/stream_fmp4/serve.key?aka_me_session_id=AAAAAAAAAADHrX9iAAAAAKnmNv+WiZ%2f3qHxHKe02zPoEqLu+jCaXxr2gWuRLZDNo6s0WwhFVyzE589AFUXNwdaxw+2YcCEKc"
#EXTINF:10.005333,
19670288-c1a4b3d4-2f57-4d1e-899d-475356f6b3b9_audio_128kbps.mp4?aka_me_session_id=AAAAAAAAAADHrX9iAAAAAKnmNv+WiZ%2f3qHxHKe02zPoEqLu+jCaXxr2gWuRLZDNo6s0WwhFVyzE589AFUXNwdaxw+2YcCEKc&aka_msn=0&aka_hls_version=6&aka_br=bytes=4124-166634&aka_media_format_type=hls
TermeHansen commented 2 years ago

python print output from the script above:

In [3]: dump_segments(m)

0 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
19670288-c1a4b3d4-2f57-4d1e-899d-475356f6b3b9_audio_128kbps.mp4?aka_me_session_id=AAAAAAAAAAC9CYFiAAAAAPcWUmBPMS8F2ndUH72XjvRiD6D%2f79NvIhqU8VapMZP6GD5pzGB69w8nrlS8lSojj+%2fWPug2sX1+&aka_msn=0&aka_hls_version=6&aka_br=bytes=4124-166634&aka_media_format_type=hls

1 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01'
19670288-c1a4b3d4-2f57-4d1e-899d-475356f6b3b9_audio_128kbps.mp4?aka_me_session_id=AAAAAAAAAAC9CYFiAAAAAPcWUmBPMS8F2ndUH72XjvRiD6D%2f79NvIhqU8VapMZP6GD5pzGB69w8nrlS8lSojj+%2fWPug2sX1+&aka_msn=1&aka_hls_version=6&aka_br=bytes=166635-328661&aka_media_format_type=hls

2 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02'
19670288-c1a4b3d4-2f57-4d1e-899d-475356f6b3b9_audio_128kbps.mp4?aka_me_session_id=AAAAAAAAAAC9CYFiAAAAAPcWUmBPMS8F2ndUH72XjvRiD6D%2f79NvIhqU8VapMZP6GD5pzGB69w8nrlS8lSojj+%2fWPug2sX1+&aka_msn=2&aka_hls_version=6&aka_br=bytes=328662-490702&aka_media_format_type=hls

3 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03'
19670288-c1a4b3d4-2f57-4d1e-899d-475356f6b3b9_audio_128kbps.mp4?aka_me_session_id=AAAAAAAAAAC9CYFiAAAAAPcWUmBPMS8F2ndUH72XjvRiD6D%2f79NvIhqU8VapMZP6GD5pzGB69w8nrlS8lSojj+%2fWPug2sX1+&aka_msn=3&aka_hls_version=6&aka_br=bytes=490703-652833&aka_media_format_type=hls

4 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04'
19670288-c1a4b3d4-2f57-4d1e-899d-475356f6b3b9_audio_128kbps.mp4?aka_me_session_id=AAAAAAAAAAC9CYFiAAAAAPcWUmBPMS8F2ndUH72XjvRiD6D%2f79NvIhqU8VapMZP6GD5pzGB69w8nrlS8lSojj+%2fWPug2sX1+&aka_msn=4&aka_hls_version=6&aka_br=bytes=652834-814705&aka_media_format_type=hls
glennguy commented 2 years ago

Decrypted files look fine, thanks for that!

What would be very useful is getting the initialization file, the one held here: #EXT-X-MAP:URI="19670288-c1a4b3d4-2f57-4d1e-899d-475356f6b3b9_audio_128kbps.mp4?aka_me_pasthr=AAAAAAAAAADHrX9iAAAAAKnmNv+WiZ%2f3qHxHKe02zPoEqLu+jCaXxr2gWuRLZDNo6s0WwhFVyzE589AFUXNwdaxw+2YcCEKc&aka_media_format_type=hls&aka_sign=fXPtK0QnZ6i3G03vdIRDe%2bervsUpvGLyqawy%2bfNPREQ%3d",BYTERANGE="748@0"

just need bytes 0-748, you can try putting &aka_br=bytes=0-748 at the end of the url for this. If you omit that parameter you might just get the whole audio file in one piece? Interesting though that this init segment (according to playlist) isn't encrypted, but still from the same URI (except parameters are different)

TermeHansen commented 2 years ago

Here is the first 748 bytes (init) and dump with no range (all.mp4):

https://paste.c-net.org/ValidityGlobe

with open("init", "wb") as fh:
    fh.write(get_binary(base + m.segments[0].uri.replace("4124-166634", "0-748")))
glennguy commented 2 years ago

Ok thanks for that.

Looks like 2 problems here: 1: The init segment is encrypted even though the playlist says it is not: https://datatracker.ietf.org/doc/html/draft-pantos-hls-rfc8216bis-11#section-4.4.4.4 Any Media Segment or Media Initialization Section that precedes the first EXT-X-KEY tag is unencrypted

Btw, have you tried playing this stream with another player, eg. VLC? - interested to see how that goes. Obviously this particular video works fine with DRNU official player right?

2: Even if that key tag was before the ext-x-map one, IA does not act on it. So I'll work on fixing that now.

Also, strange in your log that it doesn't disable the stream (and probably prevent the crashing). I'm testing on my end by using that init segment for a playlist I serve locally. When it tries to read the init segment before creating the FragmentedSampleReader it errors with ERROR <general>: AddOnLog: inputstream.adaptive: No MOOV in stream!

TermeHansen commented 2 years ago

@glennguy sounds awesome. Yes ffmpeg and by that ffmpegdirect in kodi works fine for that stream. Only issue is in general for le with ffmpegdirect that skipping does not work for the hls streams (and slow start).

Sounds great to use this bug also to avoid the hard crash of kodi...

glennguy commented 2 years ago

@TermeHansen I've just done up a draft PR to allow for encrypted init segments in Kodi 20 - #985 I know you're on 19 but you'd have to build yourself anyway in Linux. Should be able to cherry pick the commit (only worry about changes to HLSTree.cpp)

On your end however, since the playlist is 'incorrect' or rather broken, you'd have to set up a proxy to run the playlist through to IA to make the modification. Should be fine to just move the EXT-X-KEY line before the EXT-X-MAP one.

Yes ffmpeg and by that ffmpegdirect in kodi works fine for that stream uri.replace("4124-166634", "0-748")))

Did you download the init using the same URI the segments use? If so could you try again using the specific URI provided in EXT-X-MAP? The url parameters are different, and I'm wondering if it comes unencrypted that way. Normally the player would add range headers to get the required range of bytes e.g requests.get(url, headers={"Range": "bytes=0-748"}) so please try that and post the file back here

TermeHansen commented 2 years ago

the init from the correct uri :)

r = requests.get(m.segment_map[0].absolute_uri, headers={"Range": "bytes=0-748"})
with open("init.map", "wb") as fh:
    fh.write(r.content)

https://paste.c-net.org/PantingDiners

I think you are right it is not encrypted like this. But if that is the case, then the m3u8 should work correctly with IA as is right? So then back to initial problem, why is the format and sampling rate not set correct for this stream?

CastagnaIT commented 2 years ago

from here seem that if BYTERANGE value is found the initialization will be ignored: https://github.com/xbmc/inputstream.adaptive/blob/20.2.0-Nexus/src/parser/HLSTree.cpp#L692-L696 then also the range values are not parsed

TermeHansen commented 2 years ago

from here seem that if BYTERANGE value is found the initialization will be ignored: https://github.com/xbmc/inputstream.adaptive/blob/20.2.0-Nexus/src/parser/HLSTree.cpp#L692-L696 then also the range values are not parsed

That seems very odd, can git blame maybe point in a direction to why that line is there (on mobile right now)

glennguy commented 2 years ago

I think you are right it is not encrypted like this

Ok that's good to know :)

@CastagnaIT yes you are right

The init segment is found implicitly by using the start byterange of the first media segment then working backwards. Since there are no EXT-X-BYTERANGE tags for the media segments in this case, the setting of the init segment never happens.

I'll post a solution soon

glennguy commented 2 years ago

Ok PR in #986 @CastagnaIT Thanks heaps for steering me towards the real problem @TermeHansen Are you able to cherry-pick and build the changes on your system to test? Alternatively if you have access to Kodi 20 on Mac/Windows/Android then a build is available here: https://jenkins.kodi.tv/blue/organizations/jenkins/xbmc%2Finputstream.adaptive/detail/PR-986/1/artifacts https://jenkins.kodi.tv/blue/organizations/jenkins/xbmc%2Finputstream.adaptive/detail/PR-986/2/artifacts

TermeHansen commented 2 years ago

@glennguy I Will cherry pick and check for my addon on kodi stable, and then start the nexus branch of my addon to test also there 🤓

I will report here....

@glennguy tested and works great for this problem - thks! Will you bump to 19.0.5? I use inputstreamhelper in my addon, will that automatically update ISA on my users devices or how does that work?

TermeHansen commented 2 years ago

@glennguy but maybe we should have a check on m_sampleRate never should be set to 0, as it will bring kodi to crash, and instead either drop the stream or have ISA fail and write something to kodi?

CastagnaIT commented 2 years ago

although we send missing data kodi itself should not crashes means that in kodi core something is unhandled

glennguy commented 2 years ago

Updates are handled by Kodi and the user's settings. I'm not an expert in inputstreamhelper, does it do more than making sure the user has libwidevinecdm?

As far as crashing goes - what @CastagnaIT said. Really though the condition that lead to that has been solved now so it shouldn't be an issue at least in this case.

matthuisman commented 2 years ago

@TermeHansen Inputstream helper does not update ISA. Kodi should automatically update ISA on most platforms except Linux (they need to manually update the inputstream package outside of Kodi)

Oh, and not uwp (Xbox) . Xbox needs it to be built-in to Kodi itself so that would need to wait till 19.5