I'm experimenting with the new MediaSource API available in Chrome.
I'm trying to append binary data on the fly from a WebSocket to the video media source.
Starting with the example at https://html5-demos.appspot.com/static/media-source.html, my code is currently:
var websocket = new WebSocket('ws://localhost:8080');
websocket.binaryType = 'arraybuffer';
var mediaSource = new MediaSource();
var buffer;
var queue = [];
var video = $('.video')[0];
video.src = window.URL.createObjectURL(mediaSource);
mediaSource.addEventListener('sourceopen', function(e) {
video.play();
buffer = mediaSource.addSourceBuffer('video/mp4; codecs="avc1.64001E"');
buffer.addEventListener('updatestart', function(e) { console.log('updatestart: ' + mediaSource.readyState); });
buffer.addEventListener('update', function(e) { console.log('update: ' + mediaSource.readyState); });
buffer.addEventListener('updateend', function(e) { console.log('updateend: ' + mediaSource.readyState); });
buffer.addEventListener('error', function(e) { console.log('error: ' + mediaSource.readyState); });
buffer.addEventListener('abort', function(e) { console.log('abort: ' + mediaSource.readyState); });
buffer.addEventListener('update', function() { // Note: Have tried 'updateend'
if (queue.length > 0 && !buffer.updating) {
buffer.appendBuffer(queue.shift());
}
});
}, false);
mediaSource.addEventListener('sourceopen', function(e) { console.log('sourceopen: ' + mediaSource.readyState); });
mediaSource.addEventListener('sourceended', function(e) { console.log('sourceended: ' + mediaSource.readyState); });
mediaSource.addEventListener('sourceclose', function(e) { console.log('sourceclose: ' + mediaSource.readyState); });
mediaSource.addEventListener('error', function(e) { console.log('error: ' + mediaSource.readyState); });
websocket.addEventListener('message', function(e) {
if (typeof e.data !== 'string') {
if (buffer.updating || queue.length > 0) {
queue.push(e.data);
} else {
buffer.appendBuffer(e.data);
}
}
}, false);
I consistently get the error message: InvalidStateError: Failed to execute 'appendBuffer' on 'SourceBuffer': This SourceBuffer has been removed from the parent media source.
after one append. It looks like the MediaSource is closing immediately after the call to buffer.appendData()
.
Any way to do this elegantly?
Note: chrome://media-internals/ doesn't return any useful information.
Ultimately the issue was that I was sending h264 video down the websocket. The MediaSource API only supports MPEG-DASH and VP8 with keyframed segments currently (on Chrome 35).
Additionally, once I tried VP8, I saw that I was adding some frames out of order.
if (buffer.updating || queue.length > 0)
in websocket.onmessage
was required.if (queue.length > 0 && !buffer.updating)
in buffer.addEventListener('update', ...)
was also required.Note: I applied the edits mentioned here to the code in the question, so the only issue with the code in the question is that the codec is wrong