Reputation: 196
i tried to use MediaSource API for a little player.
this is my code and it work if i use timestampOffset but because video files are not exactly 30 sec (maybe 30 sec and 3 milisecond) there is a gap while playing. it seem using timestampOffset
is not necessary so when i try to remove this line sourceBuffer.timestampOffset += settings.segment_time;
player only show first part. what i missed?
;(function ($) {
$.fn.player = function (options) {
var settings = $.extend({
mimeCodec: 'video/mp4; codecs="avc1.640015, mp4a.40.2',
segment_time: 30,
download_gap: 60,
end_on_error: true,
autoplay: true,
played: false,
controls: false,
}, options);
if (!('MediaSource' in window && MediaSource.isTypeSupported(settings.mimeCodec)))
throw 'Unsupported MIME type or codec: ' + settings.mimeCodec;
this.start = function () {
this.each(function () {
if (!settings.hasOwnProperty('segment_id'))
throw 'Property segment_id is required.';
var video = this;
if (settings.controls)
$(video).attr('controls', '');
var sourceBuffer = null;
var mediaSource = new MediaSource();
var segment_id = settings.segment_id;
video.src = URL.createObjectURL(mediaSource);
mediaSource.addEventListener('sourceopen', function () {
sourceBuffer = this.addSourceBuffer(settings.mimeCodec);
sourceBuffer.addEventListener('updateend', function () {
sourceBuffer.timestampOffset += settings.segment_time;
console.log('updateend:');
if (!settings.played && video.paused && settings.autoplay) {
console.log('play:');
video.play();
settings.played = true;
}
});
reader()
});
function reader() {
fetcher(video.currentTime);
interval(video, setInterval(function () {
fetcher(video.currentTime);
}, settings.segment_time * 1000 / 4))
}
function fetcher(currentTime) {
if (sourceBuffer.timestampOffset - currentTime < settings.download_gap) {
if (!sourceBuffer.updating) {
console.log('nexting:');
fetch('/tv/segments/next/' + segment_id).then(function (response) {
return response.json();
}).then(function (data) {
if (data.status === 200) {
fetch(data.result.current.filename).then(function (response) {
return response.arrayBuffer()
}).then(function (res) {
segment_id = data.result.next.id;
console.log('appending:');
sourceBuffer.appendBuffer(res);
});
} else {
if (settings.end_on_error)
mediaSource.endOfStream();
}
});
}
}
}
});
};
function interval(obj, data) {
if (data) {
$(obj).data('interval', data);
} else {
return $(obj).data('interval');
}
}
this.stop = function () {
this.each(function () {
clearInterval(interval(this));
});
};
return this;
};
}(jQuery));
Upvotes: 0
Views: 492