Playback freezes when switching videos with same configuration
What version of Hls.js are you using?
1.5.20
What browser (including version) are you using?
Chrome 134.0.6998.118 (Official Build) (x86_64)
What OS (including version) are you using?
macOS 15.3.2
Test stream
https://raw.githubusercontent.com/daveisfera/hls_switch_same_init/9ee116765e3296abc01cd3e530623321336d7755/video.m3u8
Configuration
{
"debug": true,
"enableWorker": true,
"lowLatencyMode": true,
"backBufferLength": 90
}
Additional player setup steps
Using demo page
Checklist
- [x] The issue observed is not already reported by searching on Github under https://github.com/video-dev/hls.js/issues
- [x] The issue occurs in the stable client (latest release) on https://hlsjs.video-dev.org/demo and not just on my page
- [x] The issue occurs in the latest client (main branch) on https://hlsjs-dev.video-dev.org/demo and not just on my page
- [x] The stream has correct Access-Control-Allow-Origin headers (CORS)
- [x] There are no network errors such as 404s in the browser console when trying to play the stream
Steps to reproduce
- Play above link on demo page
- Observe error output
Expected behaviour
Video plays through the switch
What actually happened?
Playback pauses when switch happens
Console output
9.194 | Media element detached
9.195 | Loading https://raw.githubusercontent.com/daveisfera/hls_switch_same_init/9ee116765e3296abc01cd3e530623321336d7755/video.m3u8
9.197 | Loading manifest and attaching video element...
9.204 | Media element attached
9.37 | 1 quality levels found
9.371 | Manifest successfully loaded, trying to recover media error.
13.532 | Media element detached
13.535 | The video playback was aborted due to a corruption problem or because the video used features your browser did not support - PIPELINE_ERROR_DECODE: Error Domain=NSOSStatusErrorDomain Code=-17694 "(null)" (-17694): VTDecompressionOutputCallback
13.541 | Media element attached, trying to swap audio codec and recover media error.
13.833 | Media element detached
13.836 | The video playback was aborted due to a corruption problem or because the video used features your browser did not support - PIPELINE_ERROR_DECODE: Error Domain=NSOSStatusErrorDomain Code=-17694 "(null)" (-17694): VTDecompressionOutputCallback
13.844 | Media element attached, cannot recover. Last media error recovery failed.
14.134 | The video playback was aborted due to a corruption problem or because the video used features your browser did not support - PIPELINE_ERROR_DECODE: Error Domain=NSOSStatusErrorDomain Code=-17694 "(null)" (-17694): VTDecompressionOutputCallback
Chrome media internals output
{
"465:4": {
"id": "465:4",
"properties": {
"render_id": 465,
"player_id": 4,
"created": "2025-03-21 04:23:19.134592 UTC",
"origin_url": "https://videojs-http-streaming.netlify.app/",
"kFrameUrl": "https://videojs-http-streaming.netlify.app/?debug=false&autoplay=false&muted=false&fluid=false&minified=false&sync-workers=false&liveui=true&llhls=true&url=https%3A%2F%2Fraw.githubusercontent.com%2Fdaveisfera%2Fhls_switch_same_init%2F9ee116765e3296abc01cd3e530623321336d7755%2Fsecond.m3u8&type=application%2Fx-mpegURL&keysystems=&buffer-water=false&exact-manifest-timings=false&pixel-diff-selector=false&network-info=true&dts-offset=false&override-native=true&object-fit=false&use-mms=true&preload=auto&mirror-source=true&forced-subtitles=false&native-text-tracks=false",
"kFrameTitle": "videojs-http-streaming Demo",
"url": "blob:https://videojs-http-streaming.netlify.app/57b3ff4c-c88e-4d97-82f0-868c0d5dbd94",
"info": "ChunkDemuxer",
"kRendererName": "RendererImpl",
"pipeline_state": "kStarting",
"duration": 4.005
},
"allEvents": [
{
"time": 0,
"key": "created",
"value": "2025-03-21 04:23:19.134592 UTC"
},
{
"time": 0.08300000429153442,
"key": "origin_url",
"value": "https://videojs-http-streaming.netlify.app/"
},
{
"time": 0.0910000205039978,
"key": "kFrameUrl",
"value": "https://videojs-http-streaming.netlify.app/?debug=false&autoplay=false&muted=false&fluid=false&minified=false&sync-workers=false&liveui=true&llhls=true&url=https%3A%2F%2Fraw.githubusercontent.com%2Fdaveisfera%2Fhls_switch_same_init%2F9ee116765e3296abc01cd3e530623321336d7755%2Fsecond.m3u8&type=application%2Fx-mpegURL&keysystems=&buffer-water=false&exact-manifest-timings=false&pixel-diff-selector=false&network-info=true&dts-offset=false&override-native=true&object-fit=false&use-mms=true&preload=auto&mirror-source=true&forced-subtitles=false&native-text-tracks=false"
},
{
"time": 0.09500002861022949,
"key": "kFrameTitle",
"value": "videojs-http-streaming Demo"
},
{
"time": 0.14899998903274536,
"key": "url",
"value": "blob:https://videojs-http-streaming.netlify.app/57b3ff4c-c88e-4d97-82f0-868c0d5dbd94"
},
{
"time": 0.17599999904632568,
"key": "info",
"value": "ChunkDemuxer"
},
{
"time": 0.18599998950958252,
"key": "kRendererName",
"value": "RendererImpl"
},
{
"time": 0.2200000286102295,
"key": "pipeline_state",
"value": "kStarting"
},
{
"time": 178.13499999046326,
"key": "duration",
"value": 4.005
}
],
"lastRendered": 0,
"firstTimestamp_": 307161374.866
}
}
Do you get the same Chrome media internals logs from https://hlsjs.video-dev.org/demo/ as you do from the https://videojs-http-streaming.netlify.app/ details shared above?
Please share whatever other details you can about the content encoding, cross-player testing, and open-source issues filed.
The video is encoded on iOS using AVAssetWriter
Video.js had another issue but runs into the same issue once that's addressed, but it plays in Safari
This appears to be a bug in Chrome. Have you filed a chromium issue?
I opened a bug for Chrome, but I tried it with HLS.js in Safari and it didn't play at all
but I tried it with HLS.js in Safari and it didn't play at all
I don't see any issues with playback in Safari against latest hls.js https://hlsjs.video-dev.org/demo/?src=https%3A%2F%2Fraw.githubusercontent.com%2Fdaveisfera%2Fhls_switch_same_init%2F9ee116765e3296abc01cd3e530623321336d7755%2Fvideo.m3u8&demoConfig=eyJlbmFibGVTdHJlYW1pbmciOnRydWUsImF1dG9SZWNvdmVyRXJyb3IiOmZhbHNlLCJzdG9wT25TdGFsbCI6ZmFsc2UsImR1bXBmTVA0IjpmYWxzZSwibGV2ZWxDYXBwaW5nIjotMSwibGltaXRNZXRyaWNzIjotMX0=
or in 1.5.20 (https://5982f183.hls-js-dev.pages.dev/demo/?src=...)
Do you want to file a new bug or provide more info?
I just did some tests with vanilla JS/MSE and this issue only shows up in Chrome, but it shows up every time. There is no overlap in the video but as long as Chrome tries to coalesce the discontiguous ranges, a pipeline/decode error occurs at 4 seconds.
The ranges would have to be appended at least 0.1s apart (start the second sequence at 4.1 instead of 4), to prevent the media error. But then playback would stall and a seek needed to jump the gap. It's not a worthwhile workaround. Chrome should be able to handle HEVC discontinuities.
I'm using an Intel Mac with macOS 15.4 and Safari 18.4 (20621.1.15.11.10)
Status:
0.02 | Loading https://raw.githubusercontent.com/daveisfera/hls_switch_same_init/9ee116765e3296abc01cd3e530623321336d7755/video.m3u8
0.022 | Loading manifest and attaching video element...
0.035 | 1 quality levels found
0.038 | Manifest successfully loaded
1.003 | Media element attached
1.222 | The video playback was aborted due to a corruption problem or because the video used features your browser did not support - Media failed to decode
Error:
1.211 | Buffer append error
1.211 | A media error occurred: bufferAppendError
What other info can I provide to help with that?
I'm using an Intel Mac with macOS 15.4 and Safari 18.4 (20621.1.15.11.10)
OK. I get a decode error on Intel Mac (Safari 15.6.1) but it has nothing to do with switching; first.m3u8 and second.m3u8 assets also fail. At best I see a frame of video and then the media element displays an error state.
MediaSource.isTypeSupported('video/mp4;codecs="hvc1.1.6.L150"') returns true and the HLS asset plays when loaded into QuickTime Player via "File > Open Location..." so I don't see why it shouldn't be supported in Safari with MSE.
I cannot reproduce the issue on Apple Silicon (tested in M3 MBP and iPhone 16 Pro Max).
Please report the issue to Feedback Assistant and share the id.
The video is encoded on iOS using AVAssetWriter
It would be good to include feedback on that article and sample code. Include as much information about the source movie file as you can (what it was shot on, movie info).
A co-worker was able to reproduce this issue using the previously linked example and Big Buck Bunny with the output set to H.265.
Here's links to those manifests to demonstrate the issue:
Works because it starts from the beginning: https://raw.githubusercontent.com/daveisfera/repeat_big_buck_bunny/cad5ff1ab79529fd46bb75140446e1298d1e7cd5/repeat.m3u8
Fails when using any segment other than the first (but doing the same with output from ffmpeg works without issue):
https://raw.githubusercontent.com/daveisfera/repeat_big_buck_bunny/cad5ff1ab79529fd46bb75140446e1298d1e7cd5/repeat2.m3u8
I created an entry in Feedback Assistant and the id is FB17355018
~@daveisfera the second segment in your playlist does not start with an IDR sample. I used this branch which checks whether mp4 segments are independent https://github.com/video-dev/hls.js/commit/f935c68f81842fdee3db808f31dd0e9bcfdaa250~
AVAssetWriter is writing the video and audio to the same .m4s in the example I linked to and the first video frame is an I-frame (i.e. the frames before that are audio and are independent so I believe this should still be compliant with the spec and holding true to the #EXT-X-INDEPENDENT-SEGMENTS that is being written), so the segment should be good
This is how I checked it with ffmpeg:
ffprobe -show_entries frame=pict_type,pts,pts_time -of csv=p=0 -i "concat:fileSequence0.mp4|fileSequence2.m4s"
Probably also worth pointing out that I've been able to reproduce the issue with separated video and audio, but I wanted to keep the reproducer as simple as possible and as close to the Apple example of using AVAssetWriter as I could.
the first video frame is an I-frame
You are right. There was an issue in the commit I shared, addressed in here: 42fc0cbd897958a9f429413eeb94106c15ced92f
Probably also worth pointing out that I've been able to reproduce the issue with separated video and audio, but I wanted to keep the reproducer as simple as possible and as close to the Apple example of using AVAssetWriter as I could.
When the tracks are demuxed are the duration of the audio and video segments the same?
The discontinuity is something you are added is it not? I'm wondering if the issue, in Chrome at least, may be related to the first segment in the discontinuity overlapping with content from the previous segment.
Probably also worth pointing out that I've been able to reproduce the issue with separated video and audio, but I wanted to keep the reproducer as simple as possible and as close to the Apple example of using AVAssetWriter as I could.
When the tracks are demuxed are the duration of the audio and video segments the same?
The video is 17.88 seconds and the audio is 18.00 seconds
The discontinuity is something you are added is it not? I'm wondering if the issue, in Chrome at least, may be related to the first segment in the discontinuity overlapping with content from the previous segment.
Yes, I manually added it because I wanted to show an example of jumping in the video. An example use case would be making a trailer from a full video by making a smaller manifest with EXT-X-DISCONTINUITY whenever a skip happens. I can do this with the output from ffmpeg and it works, so it's just the output from AVAssetWriter that is running into this issue.
Here's an example of jumping forward instead of repeating that runs into the same issue: https://raw.githubusercontent.com/daveisfera/repeat_big_buck_bunny/1dc0e9ed12d8beaeb4dae1b3be9e9d36703cd3dd/jump.m3u8
Can you please provide description with steps to reproduce for each asset. The additional examples, failures in different browsers and platforms for different reasons, aren't helping triage the issue.
An example use case would be making a trailer from a full video by making a smaller manifest with EXT-X-DISCONTINUITY whenever a skip happens. I can do this with the output from ffmpeg and it works, so it's just the output from AVAssetWriter that is running into this issue
I'm not following the meaning of "skip" in this context. If you add a discontinuity, the duration of the last segment should account for the time between the earliest and latest samples of either audio/video track. This can be avoided with demuxed audio and video.
Also if ffmpeg produces an HLS asset with a different result, please share that asset for comparison. What we want to know is if there is a significant difference in the segments or the HLS playlists.
It seems that the decode errors are a result of the browser failing to slice overlapping appends. HLS.js is performing alignment based on the video timestamps and/or playlist which are the same for samples above.
#7199 extends the end of the first discontinuity domain to match the end of the longer audio track, pushing out the append of the first segment in the discontinuity.
Let me know how this PR addresses the issue for your different samples and use-cases:
- #7199 branch preview: https://bugfix-muxed-fmp4-overlappin.hls-js-4zn.pages.dev/demo/
TLDR: the issue is that b-frames in the video are causing the issue (figured this out while filling out all of the details below)
Can you please provide description with steps to reproduce for each asset. The additional examples, failures in different browsers and platforms for different reasons, aren't helping triage the issue.
A co-worker used the AVAssetWriter example to turn Big Buck Bunny into HLS segments/manifest and then I trimmed it down to the examples I've included and added the EXT-X-DISCONTINUITY tags.
Here's the manifest trimmed to the first 4 segments that was what I used to manually create the rest of the variations: https://raw.githubusercontent.com/daveisfera/repeat_big_buck_bunny/15b2b9ccb3e0c0b11eed6b288caeb01ebb1a8a9a/main.m3u8
Here's a summary of the testing I've done with this output:
- Plays in Safari without issue
- Clip freezes in HLS.js and Video.js with Safari
- Clip won't play at all with HLS.js and Video.js in Chrome (made separate bug for that - https://issues.chromium.org/issues/410059459)
NOTE: Verified as working on Windows with Chrome and Firefox
An example use case would be making a trailer from a full video by making a smaller manifest with EXT-X-DISCONTINUITY whenever a skip happens. I can do this with the output from ffmpeg and it works, so it's just the output from AVAssetWriter that is running into this issue
I'm not following the meaning of "skip" in this context. If you add a discontinuity, the duration of the last segment should account for the time between the earliest and latest samples of either audio/video track. This can be avoided with demuxed audio and video.
My co-worker modified the AVAssetWriter to write separate video and audio, but the issue still happens. I could post an example with that content, but I was trying to keep the reproducer as simple as possible, and I wanted to use the AVAssetWriter provided by Apple to keep things as close to that as possible.
Also if ffmpeg produces an HLS asset with a different result, please share that asset for comparison. What we want to know is if there is a significant difference in the segments or the HLS playlists.
I used ffmpeg to re-write the segments/metadata but leave the content unchanged and it still has the issue:
https://raw.githubusercontent.com/daveisfera/repeat_big_buck_bunny/68a6bc0a2addc87d69b0f363e16d3789b3c8254a/jump_no.m3u8
Here's the command I used to do that:
ffmpeg -i ../main.m3u8 -c copy -tag:v hvc1 -f hls -hls_segment_type fmp4 -hls_init_time 5.9 -hls_time 6 -hls_flags independent_segments -start_number 1 -hls_list_size 0 -hls_fmp4_init_filename fileSequence0.mp4 fileSequence.m3u8
So I tried transcoding the content and it still had the issue: https://raw.githubusercontent.com/daveisfera/repeat_big_buck_bunny/5be4b189e0e5a56c6e3f788a6c1f596d5f4b648a/jump_no.m3u8
Here's the command I used to do that:
ffmpeg -i ../main.m3u8 -c:v libx265 -tag:v hvc1 -c:a copy -force_key_frames source -f hls -hls_segment_type fmp4 -hls_init_time 5.9 -hls_time 6 -hls_flags independent_segments -start_number 1 -hls_list_size 0 -hls_fmp4_init_filename fileSequence0.mp4 fileSequence.m3u8
So I tried disabling b-frames and the issue no longer happens:
https://raw.githubusercontent.com/daveisfera/repeat_big_buck_bunny/9078ffe0655b9b5d510bd3cfca5cd38b41d30e52/jump_no.m3u8
It seems that the decode errors are a result of the browser failing to slice overlapping appends. HLS.js is performing alignment based on the video timestamps and/or playlist which are the same for samples above.
#7199 extends the end of the first discontinuity domain to match the end of the longer audio track, pushing out the append of the first segment in the discontinuity.
Let me know how this PR addresses the issue for your different samples and use-cases:
- Prevent overlapping track appends in muxed fmp4 on discontinuity #7199 branch preview: https://bugfix-muxed-fmp4-overlappin.hls-js-4zn.pages.dev/demo/
The issue still happens with this version of the player when b-frames are present
The change in #7199 works for me with the discontinuity example:
https://bugfix-muxed-fmp4-overlappin.hls-js-4zn.pages.dev/demo/?src=https%3A%2F%2Fraw.githubusercontent.com%2Fdaveisfera%2Frepeat_big_buck_bunny%2Fcad5ff1ab79529fd46bb75140446e1298d1e7cd5%2Frepeat2.m3u8&demoConfig=eyJlbmFibGVTdHJlYW1pbmciOnRydWUsImF1dG9SZWNvdmVyRXJyb3IiOmZhbHNlLCJzdG9wT25TdGFsbCI6ZmFsc2UsImR1bXBmTVA0IjpmYWxzZSwibGV2ZWxDYXBwaW5nIjotMSwibGltaXRNZXRyaWNzIjotMX0=
There's a noticeable gap where the discontinuity is which the gap controller will traverse without a decode error on an Apple Silicon Mac Safari and Chrome. The above also passed on an 2017 Intel iMac in Chrome.
In the current release (v1.6.2 without the fix above) there is no gap between the last and second to last segment and that is where the decode error occurs (Apple Silicon Mac Safari and Chrome). https://e5abc373.hls-js-dev.pages.dev/demo/?src=https%3A%2F%2Fraw.githubusercontent.com%2Fdaveisfera%2Frepeat_big_buck_bunny%2Fcad5ff1ab79529fd46bb75140446e1298d1e7cd5%2Frepeat2.m3u8&demoConfig=eyJlbmFibGVTdHJlYW1pbmciOnRydWUsImF1dG9SZWNvdmVyRXJyb3IiOmZhbHNlLCJzdG9wT25TdGFsbCI6ZmFsc2UsImR1bXBmTVA0IjpmYWxzZSwibGV2ZWxDYXBwaW5nIjotMSwibGltaXRNZXRyaWNzIjotMX0=
I'm using a 2019 MacBook Pro with macOS 15.4.1
The change in #7199 works for me with the discontinuity example:
https://bugfix-muxed-fmp4-overlappin.hls-js-4zn.pages.dev/demo/?src=https%3A%2F%2Fraw.githubusercontent.com%2Fdaveisfera%2Frepeat_big_buck_bunny%2Fcad5ff1ab79529fd46bb75140446e1298d1e7cd5%2Frepeat2.m3u8&demoConfig=eyJlbmFibGVTdHJlYW1pbmciOnRydWUsImF1dG9SZWNvdmVyRXJyb3IiOnRydWUsInN0b3BPblN0YWxsIjpmYWxzZSwiZHVtcGZNUDQiOmZhbHNlLCJsZXZlbENhcHBpbmciOi0xLCJsaW1pdE1ldHJpY3MiOi0xfQ==
This one errors with the following output on Safari:
0.042 | Loading https://raw.githubusercontent.com/daveisfera/repeat_big_buck_bunny/cad5ff1ab79529fd46bb75140446e1298d1e7cd5/repeat2.m3u8
0.047 | Loading manifest and attaching video element...
0.124 | Media element attached
0.378 | 1 quality levels found
0.378 | Manifest successfully loaded, trying to recover media error.
19.115 | Media element detached
19.119 | The video playback was aborted due to a corruption problem or because the video used features your browser did not support - Media failed to decode
19.128 | Media element attached, trying to swap audio codec and recover media error.
19.328 | Media element detached
19.33 | The video playback was aborted due to a corruption problem or because the video used features your browser did not support - Media failed to decode
19.334 | Media element attached, cannot recover. Last media error recovery failed.
19.606 | The video playback was aborted due to a corruption problem or because the video used features your browser did not support - Media failed to decode
And outputs this on Chrome:
15.941 | Buffer stalled error
There's a noticeable gap where the discontinuity is which the gap controller will traverse without a decode error on an Apple Silicon Mac Safari and Chrome.
In the current release (v1.6.2 without the fix above) there is no gap between the last and second to last segment and that is where the decode error occurs (Apple Silicon Mac Safari and Chrome). https://e5abc373.hls-js-dev.pages.dev/demo/?src=https%3A%2F%2Fraw.githubusercontent.com%2Fdaveisfera%2Frepeat_big_buck_bunny%2Fcad5ff1ab79529fd46bb75140446e1298d1e7cd5%2Frepeat2.m3u8&demoConfig=eyJlbmFibGVTdHJlYW1pbmciOnRydWUsImF1dG9SZWNvdmVyRXJyb3IiOnRydWUsInN0b3BPblN0YWxsIjpmYWxzZSwiZHVtcGZNUDQiOmZhbHNlLCJsZXZlbENhcHBpbmciOi0xLCJsaW1pdE1ldHJpY3MiOi0xfQ==
Same error as above on this one with Safari
And errors about corruption as before with Chrome
Same error as above on this one with Safari
Right. the second link is the current release.
The first link is the one where I'm trying to understand failure. It should stall as there is a gap, but I would expect a seek over that gap on stall. It appears to prevent the decode error in Chrome. Safari appears to fail on seek (not sure how I observed it passing earlier).
TLDR: the issue is that
b-framesin the video are causing the issue (figured this out while filling out all of the details below)
As a further data point, my co-worker tried adding this setting so B-frames aren't included in the output of AVAssetWriter and HLS.js plays back all of the different variations I've included without issue, so that appears to definitely be the cause of the playback issues:
AVVideoCompressionPropertiesKey: [
...
AVVideoAllowFrameReorderingKey: false,
]
Closing as "Stream issue".