Reputation: 680
I can play a mp4 video by requesting chunk of data using GET request and Range header.
var FILE = 'Momokuri_Ep_09-10_SUB_ITA_dashinit.mp4';
var NUM_CHUNKS = 10;
var chunk_size = 256 * 1024; // 2Kb
var current_chunk = 0;
var file_size = 1;
window.MediaSource = window.MediaSource || window.WebKitMediaSource;
if (!!!window.MediaSource) {
alert('MediaSource API is not available');
}
var mediaSource = new MediaSource();
var sourceBuffer;
video.src = window.URL.createObjectURL(mediaSource);
function callback(e) {
sourceBuffer = mediaSource.addSourceBuffer('video/mp4; codecs="avc1.640029, mp4a.40.5"');
console.log('mediaSource readyState: ' + this.readyState);
var readChunk = function() {
GET(FILE, current_chunk, function(uInt8Array) {
sourceBuffer.appendBuffer(uInt8Array);
});
};
sourceBuffer.addEventListener('update', function(e) {
if (!sourceBuffer.updating) {
if (current_chunk == Math.ceil(file_size/chunk_size)-1) {
if ( mediaSource.readyState!='ended' )
mediaSource.endOfStream();
} else {
current_chunk++;
readChunk();
if (video.paused) {
video.play();
}
}
}
});
readChunk();
}
mediaSource.addEventListener('sourceopen', callback, false);
mediaSource.addEventListener('webkitsourceopen', callback, false);
mediaSource.addEventListener('webkitsourceended', function(e) {
console.log('mediaSource readyState: ' + this.readyState);
}, false);
function GET(url, chunk_index, callback) {
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.setRequestHeader('Range', 'bytes='+(chunk_index*chunk_size)+'-'+(++chunk_index*chunk_size-1));
xhr.responseType = 'arraybuffer';
xhr.send();
xhr.onload = function(e) {
if (xhr.status != 200 && xhr.status != 206) {
alert("Unexpected status code " + xhr.status + " for " + url);
return false;
}
file_size = parseInt(this.getResponseHeader('content-range').split("/").pop());
callback(new Uint8Array(xhr.response));
};
}
But I can't seek the video. So anyone can tell me how to solve these problems :
Thanks
Upvotes: 3
Views: 3789
Reputation: 2048
I've been looking for the solution to this myself, and I think I found it.
Have a look at this example.
Whenever a seeking
event is emitted from the video element, indicating the user has requested a seek, the old sourcebuffer is closed using sourceBuffer.abort();
.
The mediasource then emits a new sourceopen
event which allows you to create a new sourcebuffer the same way you did the first time, but this time instead of appending data from the start of the file, you append data from an offset corresponding to the videoElem.currentTime
.
How you turn a time offset into a byte offset seems to be left up to you, as it depends on the format of the media you're playing.
In a constant bitrate file, you might be able to get away with basically dividing the file length in bytes by the video length in seconds (and adding a little safety margin). For anything else, you will probably need to parse the file and get timestamps and byte offsets of keyframes.
Upvotes: 3