Created
April 17, 2015 16:12
-
-
Save joeyparrish/1ad5e53b87953f9c289f to your computer and use it in GitHub Desktop.
Demo of MSE bug in Chrome (http://crbug.com/478151)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<script src="mse_bug.js"></script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var videoInfo = { | |
buf: null, | |
url: 'http://yt-dash-mse-test.commondatastorage.googleapis.com/media/car-20120827-85.mp4', | |
init: [0, 671], | |
segments: [ | |
[1148,171873], | |
[171874,341273], | |
[341274,510958], | |
[510959,680645], | |
[680646,850583], | |
[850584,1022789], | |
[1022790,1193041], | |
[1193042,1363045], | |
[1363046,1532644], | |
[1532645,1701248], | |
[1701249,1871395], | |
[1871396,2041046], | |
[2041047,2210795], | |
[2210796,2380198], | |
[2380199,2549524], | |
[2549525,2718759], | |
[2718760,2888765], | |
[2888766,3060318], | |
[3060319,3229793], | |
[3229794,3400203], | |
[3400204,3570529], | |
[3570530,3741610], | |
[3741611,3911736], | |
[3911737,4081630], | |
[4081631,4252016], | |
[4252017,4423280], | |
[4423281,4592599], | |
[4592600,4761492], | |
[4761493,4931337], | |
[4931338,5101772], | |
[5101773,5270235], | |
[5270236,5439912], | |
[5439913,5571173], | |
[5571174,5740890], | |
[5740891,5910860], | |
[5910861,6000693], | |
[6000694,6015000] | |
] | |
}; | |
var audioInfo = { | |
buf: null, | |
url: 'http://yt-dash-mse-test.commondatastorage.googleapis.com/media/car-20120827-8c.mp4', | |
init: [0, 591], | |
segments: [ | |
[852,159831], | |
[159832,318918], | |
[318919,477538], | |
[477539,636700], | |
[636701,795505], | |
[795506,954032], | |
[954033,1113101], | |
[1113102,1272061], | |
[1272062,1430569], | |
[1430570,1589429], | |
[1589430,1748577], | |
[1748578,1906922], | |
[1906923,2065912], | |
[2065913,2224917], | |
[2224918,2383359], | |
[2383360,2542405], | |
[2542406,2701219], | |
[2701220,2859901], | |
[2859902,2884571] | |
] | |
}; | |
function fetch(info, idx) { | |
console.log('Fetching segment', idx); | |
var resolve, reject; | |
var p = new Promise(function(resolveCallback, rejectCallback) { | |
resolve = resolveCallback; | |
reject = rejectCallback; | |
}); | |
var range = idx == null ? info.init : info.segments[idx]; | |
var begin = range[0]; | |
var end = range[1]; | |
var xhr = new XMLHttpRequest(); | |
xhr.open('GET', info.url, true); | |
xhr.responseType = 'arraybuffer'; | |
xhr.onload = function() { | |
console.log('Appending segment', idx); | |
info.buf.appendBuffer(xhr.response); | |
resolve(); | |
}; | |
xhr.onerror = function() { | |
console.error('XHR error', xhr); | |
reject(); | |
}; | |
var rangeString = begin + '-' + (end != null ? end : ''); | |
xhr.setRequestHeader('Range', 'bytes=' + rangeString); | |
xhr.send(); | |
return p; | |
} | |
function wait(s) { | |
return function() { | |
return new Promise(function(resolve) { setTimeout(resolve, s * 1000); }); | |
}; | |
} | |
function fetchA(idx) { | |
return fetch.bind(null, audioInfo, idx); | |
} | |
function fetchV(idx) { | |
return fetch.bind(null, videoInfo, idx); | |
} | |
function flattenBuffered(buffered) { | |
var ranges = []; | |
for (var i = 0; i < buffered.length; ++i) { | |
ranges.push([buffered.start(i), buffered.end(i)]); | |
} | |
return ranges; | |
} | |
function isBuffered(buffered, time) { | |
for (var i = 0; i < buffered.length; ++i) { | |
if (time >= buffered.start(i) && time <= buffered.end(i)) { | |
return true; | |
} | |
} | |
return false; | |
} | |
function breakEverything() { | |
video = document.createElement('video'); | |
video.controls = true; | |
document.body.appendChild(video); | |
mediaSource = new MediaSource(); | |
video.addEventListener('seeking', function() { | |
console.log('Seek to', video.currentTime); | |
// clear both buffers if we seek outside the buffered range. | |
if (!isBuffered(video.buffered, video.currentTime)) { | |
console.log('Clearing buffers'); | |
abuf.remove(0, Number.POSITIVE_INFINITY); | |
vbuf.remove(0, Number.POSITIVE_INFINITY); | |
} | |
}); | |
mediaSource.addEventListener('sourceopen', function() { | |
mediaSource.duration = 181.63; | |
vbuf = mediaSource.addSourceBuffer('video/mp4; codecs="avc1.640028"'); | |
abuf = mediaSource.addSourceBuffer('audio/mp4; codecs="mp4a.40.2"'); | |
videoInfo.buf = vbuf; | |
audioInfo.buf = abuf; | |
Promise.resolve(). | |
// get init and first segments | |
then(fetchV(null)).then(fetchA(null)).then(fetchV(0)).then(fetchA(0)). | |
// play for two seconds | |
then(function() { video.play(); }).then(wait(2.0)). | |
// seek | |
then(function() { video.currentTime = 40; }). | |
// get segments for the new position | |
then(fetchV(7)).then(fetchV(8)). | |
then(fetchA(3)).then(fetchA(4)). | |
// play for two seconds | |
then(wait(2.0)). | |
// seek two video segments backward | |
then(function() { video.currentTime = 30; }). | |
// get segments for new position, around 10s ahead of this position | |
then(fetchV(5)).then(fetchV(6)).then(fetchV(7)).then(fetchV(8)). | |
then(fetchA(2)).then(fetchA(3)). | |
// play for five seconds | |
then(wait(5.0)). | |
// now we are stuck! | |
then(function() { | |
console.log('====='); | |
console.log('currentTime', video.currentTime); | |
console.assert(video.currentTime > 31, 'video is stuck!'); | |
console.log('seeking', video.seeking); | |
console.assert(video.seeking == false, 'should be done seeking!'); | |
console.log('readyState', video.readyState); | |
console.assert(video.readyState >= HTMLVideoElement.HAVE_FUTURE_DATA, | |
'video should have some future data at least!'); | |
console.log('buffered', | |
JSON.stringify(flattenBuffered(video.buffered))); | |
console.assert(isBuffered(video.buffered, video.currentTime), | |
'currentTime is buffered, so this passes.'); | |
if (video.currentTime < 31) { | |
console.info('video.currentTime += 0.001 to unstick the video.'); | |
} else { | |
console.info('video did not get stuck!'); | |
} | |
}); | |
}); | |
video.src = URL.createObjectURL(mediaSource); | |
} | |
document.addEventListener('DOMContentLoaded', breakEverything); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment