Chrome does not recognise old keyframes (LL-HLS issue)
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 16.9k
- Forks
- 2.8k
- Avg merge
- 1d 12h
- Merged PRs (30d)
- 27
Description
It appears that Chrome does not recognise keyframes that are inserted before the current media playhead. With LL-HLS and the current buffer appending logic, this can cause a playback freeze until a new keyframe appears, as documented below.
The Chrome behaviour is not new, eg. #680, but requires specific circumstances to trigger (near playhead, non-independent segments and/or bad keyframe alignment across levels). However, with LL-HLS, it is likely to be triggered for normal playback, since the PART-HOLD-BACK is easily less than a segment duration.
Ideas to hack around the issue:
- Detect when this will happen and do a seek to the current playhead once the new level data has been buffered. It could cause Chrome to re-evaluate the buffered contents.
- Add a "crappy MSE mode", which won't allow a level switch until the new level has a future independent part (relative to the current playhead) – possibly excluding forced / emergency switches.
What version of Hls.js are you using?
1.0.0-rc4
What browser and OS are you using?
Chrome 88.0.4324.192
Big Sur 11.2.3 (arm)
Test stream:
https://stream.sob.m-dn.net/live/sb1-ll/index.m3u8
Checklist
- The issue observed is not already reported by searching on Github under https://github.com/video-dev/hls.js/issues
- The issue occurs in the stable client on https://hls-js.netlify.com/demo and not just on my page
- The issue occurs in the latest client on https://hls-js-dev.netlify.com/demo and not just on my page
- The stream has correct Access-Control-Allow-Origin headers (CORS)
- There are no network errors such as 404s in the browser console when trying to play the stream
Steps to reproduce
- Use Chrome or Edge
- Force any level (eg. 2)
- Ensure video is playing, and at 2-3s from live head.
- Apply a manual next level switch (eg. to 3) right after playhead passes the first parts of a segment (using timeline view – see image).
- Observe that video plays remainder of current level buffer, and then freezes until the playhead reaches the next fragment (several seconds) – even though the new level data has been buffered.

Expected behavior
Smooth transition - like in Firefox and Safari.
Actual behavior
Video freezes for several seconds.
Console output
Partial media-internals log:
00:00:16.013 | duration | 79.8
-- | -- | --
00:00:16.697 | duration | 80.433333
00:00:18.018 | duration | 81.633333
00:00:19.012 | duration | 82.8
00:00:19.852 | duration | 83.499999
00:00:20.902 | info | "video decoder config changed midstream, new config: codec: h264, profile: h264 main, level: not available, alpha_mode: is_opaque, coded size: [640,360], visible rect: [0,0,640,360], natural size: [640,360], has extra data: false, encryption scheme: Unencrypted, rotation: 0°, flipped: 0, color space: {primaries:BT709, transfer:BT709, matrix:BT709, range:LIMITED}"
00:00:20.902 | kIsVideoDecryptingDemuxerStream | false
00:00:20.902 | kVideoDecoderName | "MojoVideoDecoder"
00:00:20.902 | kIsPlatformVideoDecoder | true
00:00:20.902 | info | "Selected MojoVideoDecoder for video decoding, config: codec: h264, profile: h264 main, level: not available, alpha_mode: is_opaque, coded size: [640,360], visible rect: [0,0,640,360], natural size: [640,360], has extra data: false, encryption scheme: Unencrypted, rotation: 0°, flipped: 0, color space: {primaries:BT709, transfer:BT709, matrix:BT709, range:LIMITED}"
00:00:20.902 | debug | "Media append that overlapped current playback position may cause time gap in playing VIDEO stream because the next keyframe is 2933ms beyond last overlapped frame. Media may appear temporarily frozen."
00:00:20.930 | dimensions | "640x360"
00:00:20.930 | kResolution | "640x360"
00:00:20.902 | duration | 84.699999
00:00:20.930 | pipeline_buffering_state | {"for_suspended_start":false,"state":"BUFFERING_HAVE_ENOUGH"}
00:00:22.100 | duration | 85.899999
00:00:22.705 | duration | 86.433333
00:00:23.932 | duration | 87.633333
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the hls.js demo and the supplied LL-HLS stream, reproduce the manual level switch 2–3 seconds from the live head, and inspect the media append and level-switch paths. The issue names no source files or tests, so trace the MSE buffering behavior and existing level-switch handling first. Done means Chrome transitions smoothly without freezing after the switch, with regression coverage if the relevant test area is found.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript, typescript
- Domain
- audio-video-rtc
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100