http-streaming
http-streaming copied to clipboard
Uncaught exception at 'addSourceBuffer' when changing source or disposing/re-creating video
Description
In our scenario, we need to dynamically create a video, change its source several times within few seconds (user will be previewing videos), and dispose and re-create it at some point.
Using our video source files, when in the middle of a video, we change the video source through videojs().src
function, an Uncaught DOMException: Failed to execute 'addSourceBuffer' on 'MediaSource': This MediaSource has reached the limit of SourceBuffer objects it can handle. is received.
Here is a reduced test case on jsbin: http://jsbin.com/tojewagula/edit?html,console,output
Here are the source files you can download and check (npm install and npm start should be enough): https://drive.google.com/file/d/0B-Ny3L4qtHdUXzRaZlltWjF0YXM/view?usp=sharing
Here are some example M3U8 URLs we are using: https://scdn.golden-race.net/hlsvideos/dog6/d6-5-4-3-1437.m3u8?st=JMUY2EVWtAHdK-GDFcNyMw&e=1485420418 https://scdn.golden-race.net/hlsvideos/sp/s4-4-3-054.m3u8?st=BvMPTBAMEamHQICmFvEoJg&e=1485424078 https://scdn.golden-race.net/hlsvideos/mt/mt-5-4-1-0229.m3u8?st=yYu5J6ml4wkTdgSrbAkY9Q&e=1485424498
Sources
We realized that inserting a debug point in the function createRealSourceBuffers_()
provoked that this exception is never thrown, so we just inserted a simple wait of just before the buffer is created with _this2.mediaSource_.nativeMediaSource_.addSourceBuffer(...)
, and it's working almost all the times (we still get the exception sometimes on extreme conditions).
Steps to reproduce
Using the given jsbin example:
- Choose one of our URLs, paste it in the text input, and press Load. In the browser console you can check that the video is created with the given url and it starts playing.
- After waiting a couple of seconds, press Load again with the same video or choose a different one (may have to do that several times until the error is found).
- Encounter the error.
Note: Can be also discovered even though video is disposed.
Results
Expected
Video should be working correctly, even though is Loaded several times and/or disposed.
Error output
An unexpected error is found and video looses sound.
Additional Information
We were're NOT able to reproduce this issue with a couple of example videos found on the internet ( e.g. https://bitdash-a.akamaihd.net/content/MI201109210084_1/m3u8s/f08e80da-bf1d-4e3d-8899-f0f6155f6efa.m3u8 ), but trying to figure out what were the differences between both videos, we found that they're almost the same: same enconding, videos with different resolutions and several audio streams... It's driving us crazy!
videojs-contrib-hls version
videojs-contrib-hls 4.1.0
videojs version
video.js 5.15.1
Browsers
All
Platforms
All
Other Plugins
No other plugins are being used.
Other JavaScript
jQuery 1.8.0
Hello,
Any news on this?
Taking a look at the video-contrib-hls.js class, we did some logs around the line that is causing the trouble ( buffer = _this2.mediaSource_.nativeMediaSource_.addSourceBuffer(type + '/mp4;codecs="' + _this2[type + 'Codec_'] + '"');
) and we found that there seems to be an active source buffer in the nativeMediaSource_
object that is not being destroyed on time, and it seems to be the audio buffer...
If in the function createRealSourceBuffers_()
, at the point where the buffer is either recovered from the mediaSource_[]
array or created by the previously mentioned addSourceBuffer() function, if we insert a little delay (~100ms) before its creation we managed to avoid the error (but not every time). We tried to look for a way to correctly free the buffers but we couldn't. Disposing the videojs object doesn't resolve the problem.
Here is our modification of the createRealSourceBuffers_() function:
}, {
key: 'createRealSourceBuffers_',
value: function createRealSourceBuffers_() {
var _this2 = this;
var types = ['audio', 'video'];
types.forEach(function (type) {
// ...
// If the mediasource already has a SourceBuffer for the codec
// use that
if (_this2.mediaSource_[type + 'Buffer_']) {
buffer = _this2.mediaSource_[type + 'Buffer_'];
} else {
// JUST WAIT FOR A LITTLE ---------------------------
function delayTime(delay) {
var start = new Date().getTime();
while (new Date().getTime() < start + delay);
}
delayTime(75);
// --------------------------------------------------
buffer = _this2.mediaSource_.nativeMediaSource_.addSourceBuffer(type + '/mp4;codecs="' + _this2[type + 'Codec_'] + '"');
_this2.mediaSource_[type + 'Buffer_'] = buffer;
}
_this2[type + 'Buffer_'] = buffer;
// ...
Any help will be very appreciated.
Thanks!
Hey @carlosllera , sorry this ticket has gone a while without much attention. I noticed those sources were down, but tried a bunch of times in your example page and locally with the latest player with a source provided in https://github.com/videojs/videojs-contrib-hls/issues/1033 and couldn't reproduce the exact issue. I was only able to get: "Failed to execute 'appendBuffer' on 'SourceBuffer': This SourceBuffer has been removed from the parent media source." however the video still played. Are you still able to reproduce the issue?
Hi @gesinger, I also get exactly this error. This error only occurs for HLS v4. If I understand correctly in this version of HLS has the ability to split video and audio stream. The problem related to the processing of the audio stream. In my case the plugin successfully processes the video stream, but the processing of the audio stream, the problem arises.
I used HLS http://cds.v8d5x6g5.hwcdn.net/00992/492441_24522882544b9d9636c1e92af1d6f533/492441.m3u8 to reproduce this error in this template. An error occurs after repeated attempt to play.
Thanks, Oleg
Hello @gesinger ,
Thanks for your reply. I'm afraid we had to continue with the project and decided to move to other library, so now we're using HLS.js and we are not suffering that problem.
I hope you are able to solve the problem and everything goes alright. Great job guys.
@gesinger Hey. We also see this issue and I can confirm it is related to a race-condition around creating native SourceBuffers.
The race becomes much more probably it seems when respective segments are cached, which leads them to "load" faster and thus creation sequence to happen in an undefined state somehow.
So if you make sure that caching is enabled (in dev tools mode you might need to untick the disable-cache box for that)
We are currently looking it how we could fix this properly. Any help or advice from videojs folks is greatly appreciated! :)
Otherwise, we can also confirm that this issue i.e the native DOM exception displayed does never happen with Hls.js or other libs.
Here is a full log / stacktrace of the crash:
video.js:498 VIDEOJS: ERROR: DOMException: Failed to execute 'addSourceBuffer' on 'MediaSource': This MediaSource has reached the limit of SourceBuffer objects it can handle. No additional SourceBuffer objects may be added.
at makeWrappedSourceBuffer (https://pbm-dev1.media.compuccino.tv/vendor/videojs-contrib-hls/dist/videojs-contrib-hls.js:18987:34)
at https://pbm-dev1.media.compuccino.tv/vendor/videojs-contrib-hls/dist/videojs-contrib-hls.js:19307:20
at Array.forEach (<anonymous>)
at VirtualSourceBuffer.createRealSourceBuffers_ (https://pbm-dev1.media.compuccino.tv/vendor/videojs-contrib-hls/dist/videojs-contrib-hls.js:19274:13)
at HtmlMediaSource.addSourceBuffer (https://pbm-dev1.media.compuccino.tv/vendor/videojs-contrib-hls/dist/videojs-contrib-hls.js:18508:18)
at createSourceBuffer (https://pbm-dev1.media.compuccino.tv/vendor/videojs-contrib-hls/dist/videojs-contrib-hls.js:6960:41)
at new SourceUpdater (https://pbm-dev1.media.compuccino.tv/vendor/videojs-contrib-hls/dist/videojs-contrib-hls.js:6990:7)
at SegmentLoader.init_ (https://pbm-dev1.media.compuccino.tv/vendor/videojs-contrib-hls/dist/videojs-contrib-hls.js:5900:29)
at SegmentLoader.load (https://pbm-dev1.media.compuccino.tv/vendor/videojs-contrib-hls/dist/videojs-contrib-hls.js:5876:21)
at PlaylistLoader.<anonymous> (https://pbm-dev1.media.compuccino.tv/vendor/videojs-contrib-hls/dist/videojs-contrib-hls.js:1633:38)
logByType @ video.js:498
videojs-contrib-hls.js:6144 Uncaught TypeError: Cannot read property 'updating' of null
at SegmentLoader.fillBuffer_ (videojs-contrib-hls.js:6144)
at SegmentLoader.monitorBufferTick_ (videojs-contrib-hls.js:6121)
videojs-contrib-hls.js:6144 Uncaught TypeError: Cannot read property 'updating' of null
at SegmentLoader.fillBuffer_ (videojs-contrib-hls.js:6144)
at SegmentLoader.monitorBufferTick_ (videojs-contrib-hls.js:6121)
@gesinger Another update: It seems we found a fairly good way to prevent the race from within the SourceUpdater
class constructor.
I'll post a patch in a bit :)
Note: this seems to also happen with much higher probability when there audio stream is in a seperate rendition - as opposed to having a single segment-loader "main" type, with audio/video muxed into the same transport stream.
Here you go: https://github.com/videojs/videojs-contrib-hls/pull/1330
👋 Thanks for opening your first issue here! 👋
If you're reporting a 🐞 bug, please make sure you include steps to reproduce it. We get a lot of issues on this repo, so please be patient and we will get back to you as soon as we can. To help make it easier for us to investigate your issue, please follow the contributing guidelines.
onsourceopen因为play()的原因会重复执行,sourceBuffer不要重复初始化, 判断mediaSource.sourceBuffers.length等于0的时候初始化!
var mediaSource = new MediaSource(); mediaSource.onsourceopen = function () { if (mediaSource.sourceBuffers.length == 0) { var sourceBuffer = mediaSource.addSourceBuffer(mimeType); map.set(msg.session, sourceBuffer); sourceBuffer.onupdateend = function () { mediaSource.endOfStream(); video[0].play(); }; sourceBuffer.appendBuffer(buffer); } }; video.attr("src", URL.createObjectURL(mediaSource));