Skip to content

Instantly share code, notes, and snippets.

@peaBerberian
Created August 3, 2018 15:23
Show Gist options
  • Select an option

  • Save peaBerberian/2cada8ee1559965ebe62d5792148db60 to your computer and use it in GitHub Desktop.

Select an option

Save peaBerberian/2cada8ee1559965ebe62d5792148db60 to your computer and use it in GitHub Desktop.
const INIT_AUDIO_URL = "https://bitmovin-a.akamaihd.net/content/sintel/audio/stereo/en/128kbit/init.mp4";
const INIT_VIDEO_URL = "https://bitmovin-a.akamaihd.net/content/sintel/video/500kbit/init.mp4";
const VIDEO_SEGMENTS = [
"https://bitmovin-a.akamaihd.net/content/sintel/video/500kbit/segment_1.m4s",
];
const AUDIO_SEGMENTS = [
"https://bitmovin-a.akamaihd.net/content/sintel/audio/stereo/en/128kbit/segment_1.m4s",
];
const VIDEO_CODEC = "video/mp4; codecs=\"avc1.42E01E\"";
const AUDIO_CODEC = "audio/mp4; codecs=\"mp4a.40.2\"";
const videoElement = document.getElementsByTagName("video")[0];
function startStream() {
const mediaSource = new MediaSource();
videoElement.src = URL.createObjectURL(mediaSource);
mediaSource.addEventListener("sourceopen", onSourceOpen);
}
function onSourceOpen() {
const mediaSource = this;
const audioSourceBuffer = mediaSource.addSourceBuffer(AUDIO_CODEC);
const videoSourceBuffer = mediaSource.addSourceBuffer(VIDEO_CODEC);
let audioSegmentStep = 0;
let videoSegmentStep = 0;
videoSourceBuffer.addEventListener("update", function() {
if (videoSegmentStep >= VIDEO_SEGMENTS.length) {
return;
}
const newVideoSegmentURL = VIDEO_SEGMENTS[videoSegmentStep++];
if (!newVideoSegmentURL) {
return;
}
fetchAndPushSegment(newVideoSegmentURL, videoSourceBuffer);
});
audioSourceBuffer.addEventListener("update", function() {
if (audioSegmentStep >= AUDIO_SEGMENTS.length) {
return;
}
const newVideoSegmentURL = AUDIO_SEGMENTS[audioSegmentStep++];
if (!newVideoSegmentURL) {
return;
}
fetchAndPushSegment(newVideoSegmentURL, audioSourceBuffer);
});
Promise.all([
getURL(INIT_AUDIO_URL),
getURL(INIT_VIDEO_URL),
]).then(([audioInitSegment, videoInitSegment]) => {
videoSourceBuffer.appendBuffer(videoInitSegment);
audioSourceBuffer.appendBuffer(audioInitSegment);
});
}
/**
* @param {string} url
* @param {SourceBuffer} sourceBuffer
*/
function fetchAndPushSegment(url, sourceBuffer) {
getURL(url).then(arrayBuffer => {
sourceBuffer.appendBuffer(arrayBuffer);
});
}
/**
* @param {string} url
* @returns {Promise.<ArrayBuffer>}
*/
function getURL(url) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest;
xhr.open("get", url);
xhr.responseType = "arraybuffer";
xhr.onerror = function(err) {
reject(err);
};
xhr.onload = function () {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300) {
resolve(xhr.response);
} else {
reject(new Error("XHR status:" + xhr.status));
}
}
};
xhr.send();
});
}
window.startStream = startStream;
@peaBerberian

peaBerberian commented Aug 3, 2018

Copy link
Copy Markdown
Author

Some minimal MSE implementation to debug basic segment issues on various browsers:

  1. update the URL at the top
  2. Add the code to a page with a video element in it
  3. call startStream()

This script will then download all segments and push them in order (first initialisation segments then the video and audio segments in parallel, one by one).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment