Skip to content

LL-HLS Subtitle Part Loading Issue #7638

@hongjun-bae

Description

@hongjun-bae

What version of Hls.js are you using?

1.6.13

What browser (including version) are you using?

Chrome 142.0.7444.162 (arm64)

What OS (including version) are you using?

Mac 26.0.1 Tahoe

Test stream

I have sent it via DM.

Configuration

{
  "debug": true,
  "enableWorker": true,
  "lowLatencyMode": true,
  "backBufferLength": 90
}

Additional player setup steps

No response

Checklist

Steps to reproduce

  1. Plays an LL-HLS subtitle stream with parts.

Expected behaviour

Fragment state management prevents loading remaining parts of an incomplete segment.
The subtitle-stream-controller's loadFragment method blocks part loading once a fragment state becomes OK

protected loadFragment(frag: Fragment, level: Level, targetBufferTime: number) {
    const fragState = this.fragmentTracker.getState(frag);
    if (
      fragState === FragmentState.NOT_LOADED ||
      fragState === FragmentState.PARTIAL
    ) {
      if (!isMediaFragment(frag)) {
        this._loadInitSegment(frag, level);
      } else {
        super.loadFragment(frag, level, targetBufferTime);
      }
    }
    // ❌ If fragState === OK, nothing happens!
  }

What actually happened?

The doTick method in subtitle-stream-controller doesn't advance to the next incomplete segment.

14:29:16.166 @@ doTick: currentTime=50.044, targetBufferTime=54.001, bufferLen=3.957
  14:29:16.166 @@ getNextFragment: loadingParts=true, using end=54.001
  14:29:16.166 @@ doTick: selected frag sn=68476, start=50.001, end=54.001
                ❌ Keeps selecting sn=68476 even though it has fragState=OK

Expected behavior: Should select fragment with higher sn or later parts
Actual behavior: Repeatedly selects same fragment that's already partially loaded

Additional Evidence

Part index calculation shows misalignment:

14:29:15.972 [warn] Need buffer at 50.000666 but next unloaded part starts at 40.30066600000001
14:29:15.973 [warn] Need buffer at 50.000666 but next unloaded part starts at 45.633999
14:29:15.973 @@ loadFragment: partIndex=36 for targetBufferTime=50.001

The getNextPart function struggles to find the correct part initially, suggesting the part
selection logic has issues with incomplete segments.

The revision direction I have in mind.

  1. Allow re-entering fragments with fragState=OK when loading parts?
  2. Modify getNextFragment to skip incomplete segments and move to the next one?
  3. Update fragmentTracker to use PARTIAL state for fragments with incomplete parts?

The main video works because it has different buffer management logic, but subtitles get stuck due
to this state check.

Console output

Initial successful part loading (parts 0-3):
14:29:15.972 @@ [subtitle-stream-controller] loadFragment: sn=68476, fragState=NOT_LOADED,
isMediaFragment=true
14:29:15.972 @@ [subtitle-stream-controller] loadFragment: calling super.loadFragment for sn=68476
14:29:15.972 @@ shouldLoadParts: ✅ ENABLING part loading
14:29:15.973 @@ loadFragment: partIndex=36 for targetBufferTime=50.001
14:29:15.973 [log] Loading subtitle sn: 68476 part: 0 (36/39) of track 0 (part:[50.001-51.001])
14:29:16.166 [log] Buffered subtitle sn: 68476 part: 3 of track 0 (part:[53.001-54.001] >
buffer:[50.001-54.001])

Subsequent failures (parts 4+ never load):
14:29:16.166 @@ [subtitle-stream-controller] doTick: selected frag sn=68476, start=50.001,
end=54.001
14:29:16.166 @@ [subtitle-stream-controller] loadFragment: sn=68476, fragState=OK,
isMediaFragment=true
                ❌ loadFragment returns early - super.loadFragment never called!

14:29:16.472 @@ [subtitle-stream-controller] doTick: selected frag sn=68476, start=50.001,
end=54.001
14:29:16.472 @@ [subtitle-stream-controller] loadFragment: sn=68476, fragState=OK,
isMediaFragment=true
                ❌ Same fragment selected, but fragState=OK blocks loading

14:29:16.817 @@ [subtitle-stream-controller] doTick: partList=41 parts, loadingParts=true
14:29:16.817 @@ [subtitle-stream-controller] doTick: selected frag sn=68476, start=50.001,
end=55.001
14:29:16.817 @@ [subtitle-stream-controller] loadFragment: sn=68476, fragState=OK,
isMediaFragment=true
                ❌ Playlist updated (40→41 parts), still stuck on same fragment

(repeats indefinitely with 42, 43 parts...)

Why Main Video Works But Subtitles Don't

Main video advances correctly:
14:29:16.803 @@ loadFragment: partIndex=40 for targetBufferTime=53.994
14:29:16.803 [log] Loading main sn: 68475 part: 4 (40/40)
14:29:16.861 [log] Buffered main sn: 68475 part: 4 (buffer:[41.708-54.996])

14:29:17.789 @@ loadFragment: partIndex=41 for targetBufferTime=54.996
14:29:17.789 [log] Loading main sn: 68475 part: 5 (41/41)
14:29:17.850 [log] Buffered main sn: 68475 part: 5 (buffer:[41.708-55.999])

Key differences:
- Main: targetBufferTime continuously advances (53.994 → 54.996 → 55.999)
- Main: Finds new parts and keeps loading
- Subtitles: targetBufferTime stuck at 54.001
- Subtitles: Same fragment selected repeatedly

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions