Skip to content

WebVTT subtitle segments in LL-HLS are downloaded only as full segments, not partials #7522

@SangwonOh

Description

@SangwonOh

What version of Hls.js are you using?

v1.6.11

What browser (including version) are you using?

Chrome 139.0.7258.155(official build) (x86_64)

What OS (including version) are you using?

Windows 10

Test stream

https://hlsjs.video-dev.org/demo/?src=https%3A%2F%2Fllhls-demo.ovenmediaengine.com%2Fapp%2Fstream%2Fllhls.m3u8&demoConfig=eyJlbmFibGVTdHJlYW1pbmciOnRydWUsImF1dG9SZWNvdmVyRXJyb3IiOnRydWUsInN0b3BPblN0YWxsIjpmYWxzZSwiZHVtcGZNUDQiOmZhbHNlLCJsZXZlbENhcHBpbmciOi0xLCJsaW1pdE1ldHJpY3MiOi0xfQ==

Configuration

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

Additional player setup steps

This is a WebVTT LL-HLS stream prepared for reproducing the issue:
https://llhls-demo.ovenmediaengine.com/app/stream/llhls.m3u8

We will keep this stream available for some time to help with debugging and resolving the issue.

Checklist

Steps to reproduce

  1. Play the test stream.
  2. This issue is always reproducible.

Expected behaviour

The player should download the appropriate WebVTT parts and display subtitles accordingly.
Since each WebVTT part provides subtitles at 1-second intervals, subtitles are expected to appear every second.
This works as expected in Safari.

WebVTT Playlist: chunklist_4_subtitle_sXaLiUtm_llhls.m3u8?session=17_&_HLS_msn=3563&_HLS_part=3

#EXTM3U
#EXT-X-VERSION:6
#EXT-X-TARGETDURATION:6
#EXT-X-SERVER-CONTROL:CAN-BLOCK-RELOAD=YES,PART-HOLD-BACK=3.006000
#EXT-X-PART-INF:PART-TARGET=1.000000
#EXT-X-MEDIA-SEQUENCE:3554
#EXT-X-PROGRAM-DATE-TIME:2025-09-02T13:37:40.962+00:00
#EXTINF:6.000000,
seg_4_3554_subtitle_sXaLiUtm_llhls.vtt?session=17_
#EXT-X-PROGRAM-DATE-TIME:2025-09-02T13:37:46.962+00:00
#EXTINF:6.000000,
seg_4_3555_subtitle_sXaLiUtm_llhls.vtt?session=17_
#EXT-X-PROGRAM-DATE-TIME:2025-09-02T13:37:52.962+00:00
#EXTINF:6.000000,
seg_4_3556_subtitle_sXaLiUtm_llhls.vtt?session=17_
#EXT-X-PROGRAM-DATE-TIME:2025-09-02T13:37:58.962+00:00
#EXTINF:6.000000,
seg_4_3557_subtitle_sXaLiUtm_llhls.vtt?session=17_
#EXT-X-PROGRAM-DATE-TIME:2025-09-02T13:38:04.962+00:00
#EXTINF:6.000000,
seg_4_3558_subtitle_sXaLiUtm_llhls.vtt?session=17_
#EXT-X-PROGRAM-DATE-TIME:2025-09-02T13:38:10.962+00:00
#EXTINF:6.000000,
seg_4_3559_subtitle_sXaLiUtm_llhls.vtt?session=17_
#EXT-X-PROGRAM-DATE-TIME:2025-09-02T13:38:16.962+00:00
#EXTINF:6.000000,
seg_4_3560_subtitle_sXaLiUtm_llhls.vtt?session=17_
#EXT-X-PROGRAM-DATE-TIME:2025-09-02T13:38:22.962+00:00
#EXT-X-PART:DURATION=1.000000,URI="part_4_3561_0_subtitle_sXaLiUtm_llhls.vtt?session=17_",INDEPENDENT=YES
#EXT-X-PART:DURATION=1.000000,URI="part_4_3561_1_subtitle_sXaLiUtm_llhls.vtt?session=17_",INDEPENDENT=YES
#EXT-X-PART:DURATION=1.000000,URI="part_4_3561_2_subtitle_sXaLiUtm_llhls.vtt?session=17_",INDEPENDENT=YES
#EXT-X-PART:DURATION=1.000000,URI="part_4_3561_3_subtitle_sXaLiUtm_llhls.vtt?session=17_",INDEPENDENT=YES
#EXT-X-PART:DURATION=1.000000,URI="part_4_3561_4_subtitle_sXaLiUtm_llhls.vtt?session=17_",INDEPENDENT=YES
#EXT-X-PART:DURATION=1.000000,URI="part_4_3561_5_subtitle_sXaLiUtm_llhls.vtt?session=17_",INDEPENDENT=YES
#EXTINF:6.000000,
seg_4_3561_subtitle_sXaLiUtm_llhls.vtt?session=17_
#EXT-X-PROGRAM-DATE-TIME:2025-09-02T13:38:28.962+00:00
#EXT-X-PART:DURATION=1.000000,URI="part_4_3562_0_subtitle_sXaLiUtm_llhls.vtt?session=17_",INDEPENDENT=YES
#EXT-X-PART:DURATION=1.000000,URI="part_4_3562_1_subtitle_sXaLiUtm_llhls.vtt?session=17_",INDEPENDENT=YES
#EXT-X-PART:DURATION=1.000000,URI="part_4_3562_2_subtitle_sXaLiUtm_llhls.vtt?session=17_",INDEPENDENT=YES
#EXT-X-PART:DURATION=1.000000,URI="part_4_3562_3_subtitle_sXaLiUtm_llhls.vtt?session=17_",INDEPENDENT=YES
#EXT-X-PART:DURATION=1.000000,URI="part_4_3562_4_subtitle_sXaLiUtm_llhls.vtt?session=17_",INDEPENDENT=YES
#EXT-X-PART:DURATION=1.000000,URI="part_4_3562_5_subtitle_sXaLiUtm_llhls.vtt?session=17_",INDEPENDENT=YES
#EXTINF:6.000000,
seg_4_3562_subtitle_sXaLiUtm_llhls.vtt?session=17_
#EXT-X-PROGRAM-DATE-TIME:2025-09-02T13:38:34.962+00:00
#EXT-X-PART:DURATION=1.000000,URI="part_4_3563_0_subtitle_sXaLiUtm_llhls.vtt?session=17_",INDEPENDENT=YES
#EXT-X-PART:DURATION=1.000000,URI="part_4_3563_1_subtitle_sXaLiUtm_llhls.vtt?session=17_",INDEPENDENT=YES
#EXT-X-PART:DURATION=1.000000,URI="part_4_3563_2_subtitle_sXaLiUtm_llhls.vtt?session=17_",INDEPENDENT=YES
#EXT-X-PART:DURATION=1.000000,URI="part_4_3563_3_subtitle_sXaLiUtm_llhls.vtt?session=17_",INDEPENDENT=YES
#EXT-X-PRELOAD-HINT:TYPE=PART,URI="part_4_3563_4_subtitle_sXaLiUtm_llhls.vtt?session=17_"
#EXT-X-RENDITION-REPORT:URI="chunklist_3_subtitle_sXaLiUtm_llhls.m3u8?session=17_",LAST-MSN=3563,LAST-PART=3

WebVTT part Example

part_4_3563_3_subtitle_sXaLiUtm_llhls.vtt?session=17_

WEBVTT
X-TIMESTAMP-MAP=LOCAL:00:00:00.000,MPEGTS:1924299990


00:00:00.954 --> 00:00:01.954 line:80%
Hello OvenMediaEngine Subtitles 2025-09-02 13:38:38

part_4_3563_4_subtitle_sXaLiUtm_llhls.vtt?session=17_

WEBVTT
X-TIMESTAMP-MAP=LOCAL:00:00:00.000,MPEGTS:1924389990


00:00:00.962 --> 00:00:01.962 line:80%
Hello OvenMediaEngine Subtitles 2025-09-02 13:38:39

What actually happened?

The player always downloads the WebVTT as full segments instead of partials.
As a result, subtitles are not displayed correctly in the player.

Image

chunklist_4_subtitle_sXaLiUtm_llhls.m3u8?session=17_&_HLS_msn=3780&_HLS_part=1

#EXTM3U
#EXT-X-VERSION:6
#EXT-X-TARGETDURATION:6
#EXT-X-SERVER-CONTROL:CAN-BLOCK-RELOAD=YES,PART-HOLD-BACK=3.006000
#EXT-X-PART-INF:PART-TARGET=1.000000
#EXT-X-MEDIA-SEQUENCE:3771
#EXT-X-PROGRAM-DATE-TIME:2025-09-02T13:59:23.395+00:00
#EXTINF:6.000000,
seg_4_3771_subtitle_sXaLiUtm_llhls.vtt?session=17_
#EXT-X-PROGRAM-DATE-TIME:2025-09-02T13:59:29.395+00:00
#EXTINF:6.000000,
seg_4_3772_subtitle_sXaLiUtm_llhls.vtt?session=17_
#EXT-X-PROGRAM-DATE-TIME:2025-09-02T13:59:35.395+00:00
#EXTINF:6.000000,
seg_4_3773_subtitle_sXaLiUtm_llhls.vtt?session=17_
#EXT-X-PROGRAM-DATE-TIME:2025-09-02T13:59:41.395+00:00
#EXTINF:6.000000,
seg_4_3774_subtitle_sXaLiUtm_llhls.vtt?session=17_
#EXT-X-PROGRAM-DATE-TIME:2025-09-02T13:59:47.395+00:00
#EXTINF:6.000000,
seg_4_3775_subtitle_sXaLiUtm_llhls.vtt?session=17_
#EXT-X-PROGRAM-DATE-TIME:2025-09-02T13:59:53.395+00:00
#EXTINF:6.000000,
seg_4_3776_subtitle_sXaLiUtm_llhls.vtt?session=17_
#EXT-X-PROGRAM-DATE-TIME:2025-09-02T13:59:59.395+00:00
#EXTINF:6.000000,
seg_4_3777_subtitle_sXaLiUtm_llhls.vtt?session=17_
#EXT-X-PROGRAM-DATE-TIME:2025-09-02T14:00:05.395+00:00
#EXT-X-PART:DURATION=1.000000,URI="part_4_3778_0_subtitle_sXaLiUtm_llhls.vtt?session=17_",INDEPENDENT=YES
#EXT-X-PART:DURATION=1.000000,URI="part_4_3778_1_subtitle_sXaLiUtm_llhls.vtt?session=17_",INDEPENDENT=YES
#EXT-X-PART:DURATION=1.000000,URI="part_4_3778_2_subtitle_sXaLiUtm_llhls.vtt?session=17_",INDEPENDENT=YES
#EXT-X-PART:DURATION=1.000000,URI="part_4_3778_3_subtitle_sXaLiUtm_llhls.vtt?session=17_",INDEPENDENT=YES
#EXT-X-PART:DURATION=1.000000,URI="part_4_3778_4_subtitle_sXaLiUtm_llhls.vtt?session=17_",INDEPENDENT=YES
#EXT-X-PART:DURATION=1.000000,URI="part_4_3778_5_subtitle_sXaLiUtm_llhls.vtt?session=17_",INDEPENDENT=YES
#EXTINF:6.000000,
seg_4_3778_subtitle_sXaLiUtm_llhls.vtt?session=17_
#EXT-X-PROGRAM-DATE-TIME:2025-09-02T14:00:11.395+00:00
#EXT-X-PART:DURATION=1.000000,URI="part_4_3779_0_subtitle_sXaLiUtm_llhls.vtt?session=17_",INDEPENDENT=YES
#EXT-X-PART:DURATION=1.000000,URI="part_4_3779_1_subtitle_sXaLiUtm_llhls.vtt?session=17_",INDEPENDENT=YES
#EXT-X-PART:DURATION=1.000000,URI="part_4_3779_2_subtitle_sXaLiUtm_llhls.vtt?session=17_",INDEPENDENT=YES
#EXT-X-PART:DURATION=1.000000,URI="part_4_3779_3_subtitle_sXaLiUtm_llhls.vtt?session=17_",INDEPENDENT=YES
#EXT-X-PART:DURATION=1.000000,URI="part_4_3779_4_subtitle_sXaLiUtm_llhls.vtt?session=17_",INDEPENDENT=YES
#EXT-X-PART:DURATION=1.000000,URI="part_4_3779_5_subtitle_sXaLiUtm_llhls.vtt?session=17_",INDEPENDENT=YES
#EXTINF:6.000000,
seg_4_3779_subtitle_sXaLiUtm_llhls.vtt?session=17_
#EXT-X-PROGRAM-DATE-TIME:2025-09-02T14:00:17.395+00:00
#EXT-X-PART:DURATION=1.000000,URI="part_4_3780_0_subtitle_sXaLiUtm_llhls.vtt?session=17_",INDEPENDENT=YES
#EXT-X-PART:DURATION=1.000000,URI="part_4_3780_1_subtitle_sXaLiUtm_llhls.vtt?session=17_",INDEPENDENT=YES
#EXT-X-PRELOAD-HINT:TYPE=PART,URI="part_4_3780_2_subtitle_sXaLiUtm_llhls.vtt?session=17_"
#EXT-X-RENDITION-REPORT:URI="chunklist_3_subtitle_sXaLiUtm_llhls.m3u8?session=17_",LAST-MSN=3780,LAST-PART=1

seg_4_3779_subtitle_sXaLiUtm_llhls.vtt?session=17_

WEBVTT
X-TIMESTAMP-MAP=LOCAL:00:00:00.000,MPEGTS:2040708960


00:00:00.803 --> 00:00:01.803 line:80%
Hello OvenMediaEngine Subtitles 2025-09-02 14:00:12

00:00:01.810 --> 00:00:02.810 line:80%
Hello OvenMediaEngine Subtitles 2025-09-02 14:00:13

00:00:02.818 --> 00:00:03.818 line:80%
Hello OvenMediaEngine Subtitles 2025-09-02 14:00:14

00:00:03.837 --> 00:00:04.837 line:80%
Hello OvenMediaEngine Subtitles 2025-09-02 14:00:15

00:00:04.839 --> 00:00:05.839 line:80%
Hello OvenMediaEngine Subtitles 2025-09-02 14:00:16

00:00:05.854 --> 00:00:06.854 line:80%
Hello OvenMediaEngine Subtitles 2025-09-02 14:00:17


Console output

[level-controller]: Loading level index 0 at sn 3704 part 5 age 1.0 https://llhls-subtitle.airensoft.com/app/stream/chunklist_0_video_sXaLiUtm_llhls.m3u8?session=17_&_HLS_msn=3704&_HLS_part=5
[stream-controller]: Level 0 loaded [3695,3703][part-3704-4], cc [0, 0] duration:59.033000000000015
[buffer-controller]: Updating MediaSource duration to 131.067
[stream-controller]: Loading main sn: 3704 part: 4 (17/17) of level 0 (part:[130.067-131.067]INDEPENDENT=YES) cc: 0 [3695-3703], target: 130.067
[stream-controller]: IDLE->FRAG_LOADING
[stream-controller]: FRAG_LOADING->PARSING
[transmuxer.ts]: Flushed main sn: 3704 part: 4 of level 0
[stream-controller]: PARSING->PARSED
[stream-controller]: Parsed main sn: 3704 part: 4 of level 0 (part:[130.067-131.067]INDEPENDENT=YES)
[stream-controller]: Buffered main sn: 3704 part: 4 of level 0 (part:[130.067-131.067]INDEPENDENT=YES > buffer:[52.034-131.067])
[stream-controller]: PARSED->IDLE
[audio-track-controller]: Audio track 0 "Audio_1" lang:undefined group:bypass_audio loaded [3696-3703]
[audio-track-controller]: live playlist 0 REFRESHED 3704-5
[audio-track-controller]: Loading audio-track 0 "Audio_1" lang:undefined group:bypass_audio at sn 3704 part 6 age 0.0 https://llhls-subtitle.airensoft.com/app/stream/chunklist_1_audio_sXaLiUtm_llhls.m3u8?session=17_&_HLS_msn=3704&_HLS_part=6
[audio-stream-controller]: Audio track 0 "Audio_1" of "bypass_audio" loaded [3696,3703][part-3704-5],duration:54.006
[audio-stream-controller]: Loading audio sn: 3704 part: 5 (17/17) of track 0 (part:[130.670-131.662]) cc: 0 [3696-3703], target: 130.67
[audio-stream-controller]: IDLE->FRAG_LOADING
[audio-stream-controller]: FRAG_LOADING->PARSING
[transmuxer.ts]: Flushed audio sn: 3704 part: 5 of track 0
[audio-stream-controller]: PARSING->PARSED
[audio-stream-controller]: Parsed audio sn: 3704 part: 5 of track 0 (part:[130.670-131.662])
[audio-stream-controller]: Buffered audio sn: 3704 part: 5 of track 0 (part:[130.670-131.662] > buffer:[52.675-131.662])
[audio-stream-controller]: PARSED->IDLE
[subtitle-track-controller]: Subtitle track 0 "Korean" lang:ko group:subtitle loaded [3696-3703]
[subtitle-track-controller]: live playlist 0 REFRESHED 3704-5
[subtitle-track-controller]: Loading subtitle 0 "Korean" lang:ko group:subtitle at sn 3704 part 6 age 0.0 https://llhls-subtitle.airensoft.com/app/stream/chunklist_3_subtitle_sXaLiUtm_llhls.m3u8?session=17_&_HLS_msn=3704&_HLS_part=6
[subtitle-stream-controller]: Subtitle track 0 loaded [3696,3703][part-3704-5],duration:54.033000000000015
[level-controller]: live playlist 0 REFRESHED 3704-5
[level-controller]: Loading level index 0 at sn 3704 part 6 age 1.0 https://llhls-subtitle.airensoft.com/app/stream/chunklist_0_video_sXaLiUtm_llhls.m3u8?session=17_&_HLS_msn=3704&_HLS_part=6
[stream-controller]: Level 0 loaded [3696,3703][part-3704-5], cc [0, 0] duration:54.033000000000015
[buffer-controller]: Updating MediaSource duration to 132.067
[stream-controller]: Loading main sn: 3704 part: 5 (18/18) of level 0 (part:[131.067-132.067]INDEPENDENT=YES) cc: 0 [3696-3703], target: 131.067
[stream-controller]: IDLE->FRAG_LOADING
[stream-controller]: FRAG_LOADING->PARSING
[transmuxer.ts]: Flushed main sn: 3704 part: 5 of level 0
[stream-controller]: PARSING->PARSED
[stream-controller]: Parsed main sn: 3704 part: 5 of level 0 (part:[131.067-132.067]INDEPENDENT=YES)
[stream-controller]: Buffered main sn: 3704 part: 5 of level 0 (part:[131.067-132.067]INDEPENDENT=YES > buffer:[52.034-132.067])
[stream-controller]: PARSED->IDLE
[audio-track-controller]: Audio track 0 "Audio_1" lang:undefined group:bypass_audio loaded [3696-3704]
[audio-track-controller]: live playlist 0 REFRESHED 3705-0
[audio-track-controller]: Loading audio-track 0 "Audio_1" lang:undefined group:bypass_audio at sn 3705 part 1 age 0.0 https://llhls-subtitle.airensoft.com/app/stream/chunklist_1_audio_sXaLiUtm_llhls.m3u8?session=17_&_HLS_msn=3705&_HLS_part=1
[audio-stream-controller]: Audio track 0 "Audio_1" of "bypass_audio" loaded [3696,3704][part-3705-0],duration:55.00800000000001
[audio-stream-controller]: Loading audio sn: 3705 part: 0 (12/12) of track 0 (part:[131.662-132.664]) cc: 0 [3696-3704], target: 131.662
[audio-stream-controller]: IDLE->FRAG_LOADING
[audio-stream-controller]: FRAG_LOADING->PARSING
[transmuxer.ts]: Flushed audio sn: 3705 part: 0 of track 0
[audio-stream-controller]: PARSING->PARSED
[audio-stream-controller]: Parsed audio sn: 3705 part: 0 of track 0 (part:[131.662-132.664])
[audio-stream-controller]: Buffered audio sn: 3705 part: 0 of track 0 (part:[131.662-132.664] > buffer:[52.675-132.664])
[audio-stream-controller]: PARSED->IDLE
[subtitle-track-controller]: Subtitle track 0 "Korean" lang:ko group:subtitle loaded [3696-3704]
[subtitle-track-controller]: live playlist 0 REFRESHED 3705-0
[subtitle-track-controller]: Loading subtitle 0 "Korean" lang:ko group:subtitle at sn 3705 part 1 age 0.0 https://llhls-subtitle.airensoft.com/app/stream/chunklist_3_subtitle_sXaLiUtm_llhls.m3u8?session=17_&_HLS_msn=3705&_HLS_part=1
[subtitle-stream-controller]: Subtitle track 0 loaded [3696,3704][part-3705-0],duration:55.033000000000015
[subtitle-stream-controller]: Loading subtitle sn: 3704 of track 0 (frag:[126.067-132.067]) cc: 0 [3696-3704], target: 128.823
[subtitle-stream-controller]: IDLE->FRAG_LOADING
[level-controller]: live playlist 0 REFRESHED 3705-0

Chrome media internals output

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    Status

    Done

    Status

    Done

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions