Skip to content

HLS streams fail on Kodi 21.3 with FFmpeg 8 (allowed_segment_extensions rejects .txt segments) #215

@frankykubo

Description

@frankykubo

Summary

On systems where Kodi 21.3 is built against FFmpeg 8.x (e.g. CoreELEC avdvplus R9, and other forks following current CoreELEC), all HLS playback from TheCrew fails at the demuxer stage with:

```
ffmpeg[...]: [hls] URL https://.../p1775426897142998435_2266.txt is not in allowed_segment_extensions,
consider updating hls.c and submitting a patch to ffmpeg-devel, if this should be added
[hls] parse_playlist error Invalid data found when processing input [https://.../caxi]
OpenDemuxStream - Error creating demuxer
```

This affects live channels, sports, and any TheCrew source that serves HLS manifests whose segments have a `.txt` extension.

Root cause

FFmpeg 8 enforces a strict `allowed_segment_extensions` allow-list in `libavformat/hls.c`. The default is:

```
3gp,aac,avi,ac3,eac3,flac,mkv,m3u8,m4a,m4s,m4v,mpg,mov,
mp2,mp3,mp4,mpeg,mpegts,ogg,ogv,oga,ts,vob,vtt,wav,webvtt,cmfv,cmfa
```

Segments with a `.txt` extension are rejected. FFmpeg upstream will not add it (intentional security behaviour). FFmpeg 8.1 keeps the same list, so future CoreELEC releases do not fix this either.

On Windows Kodi 21.2 and similar builds still on FFmpeg 7.x the same streams play fine — so this is a regression visible only once a user's Kodi build moves to FFmpeg 8.

Fix

Route HLS playback through `inputstream.adaptive` instead of Kodi's built-in FFmpeg HLS demuxer. `inputstream.adaptive` has its own HLS parser and never consults the FFmpeg allow-list.

File: `script.module.thecrew/lib/resources/lib/indexers/lists.py`
Function: `player().play()` (around line 1122 in 0.4.x-era builds)

Patch

Before:

```python
item = control.item(path=url)
try: item.setArt({'icon': icon})
except: pass
item.setInfo(type='Video', infoLabels = meta)
control.player.play(url, item)
control.resolve(int(sys.argv[1]), True, item)
```

After:

```python
item = control.item(path=url)
try: item.setArt({'icon': icon})
except: pass
item.setInfo(type='Video', infoLabels = meta)

Force inputstream.adaptive for HLS URLs — FFmpeg 8 rejects .txt segments

if any(x in url.lower() for x in ['.m3u8', '.m3u', 'load-playlist']):
_hdrs = url.split('|', 1)[1] if '|' in url else ''
item.setProperty('inputstream', 'inputstream.adaptive')
item.setProperty('inputstream.adaptive.manifest_type', 'hls')
if _hdrs:
item.setProperty('inputstream.adaptive.manifest_headers', _hdrs)
item.setProperty('inputstream.adaptive.stream_headers', _hdrs)
item.setMimeType('application/vnd.apple.mpegurl')
item.setContentLookup(False)
control.player.play(url, item)
control.resolve(int(sys.argv[1]), True, item)
```

Three non-obvious details worth noting for any future PR

  1. Channel/live playback goes through `lists.py`, not `modules/player.py`. `modules/player.py` already has a similar `inputstream.adaptive` block but it's on a different code path and isn't reached by the channel/`action=play` flow.
  2. Properties must be set before `control.player.play(url, item)`. In the `action=play` plugin flow `sys.argv[1]` is `-1`, so `setResolvedUrl` silently fails — `player.play()` is what actually starts playback, and the `inputstream` property must be on the listitem before that call.
  3. Sub-playlist headers must be propagated. The top-level manifest fetch works with Kodi's `|Header=value` URL-suffix syntax, but inputstream.adaptive's sub-requests go out without those headers and hit HTTP 403 on the inner playlists. Passing the header string via `inputstream.adaptive.manifest_headers` + `inputstream.adaptive.stream_headers` fixes it. This is why a naive one-line property set (just `inputstream = inputstream.adaptive`) still breaks with HTTP 403 after the manifest parses.

Note on `modules/player.py`

The sibling file `script.module.thecrew/lib/resources/lib/modules/player.py` has an analogous block (around line 81-85). In current zips that block has an indentation inconsistency (mixed tab + spaces on the `if any(x in url.lower()...` line) which causes `TabError` on Python 3 module import — the whole module fails to load, so the existing `inputstream.adaptive` setup silently doesn't apply there either. Worth fixing in the same pass (use spaces only for that line).

Verification

With Kodi debug logging on, a successful playback now shows:

```
AddOnLog: inputstream.adaptive: Open()
AddOnLog: inputstream.adaptive: Manifest successfully parsed (Periods: 1, Streams in first period: 2, Type: live)
AddOnLog: inputstream.adaptive: OpenStream(1001)
```

And no `ffmpeg[...]: [hls] URL ... is not in allowed_segment_extensions` lines.

Environment where this was reproduced

  • Device: Homatics Box R4 Plus (Amlogic S905X4)
  • OS: CoreELEC avdvplus R9 (FFmpeg 8.0.1)
  • Kodi: 21.3 Omega
  • inputstream.adaptive: 21.5.18.1
  • TheCrew repository: 0.3.x / `script.module.thecrew` current version

Cross-referenced at avdvplus/Builds#118 where the same issue was reported against the CoreELEC build; concluded the fix belongs here in TheCrew rather than in the FFmpeg layer.

Happy to supply a full diff / patched zip if that's easier to integrate than a prose patch.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions