chrome html5 video buffered.end event - javascript

I'm trying to detect when a video file has completed loading. i made it work successfully on firefox and safari but on chrome, buffered event behaves strange..
so,
in my local host chrome works fine but when i upload to server;
buffer percentage stops about %50 but buffers %100,
when page refreshed, percentage stay at %0 but it continues to buffering..
here is my javascript
function loaded()
{
var v = document.getElementById('myVideo');
var r = v.buffered;
var total = v.duration;
var current=v.currentTime;
var start = r.start(0);
var end = r.end(0);
var downloadPercent= Math.round((end / total)*100)
$("#loadProgress").css('width',downloadPercent+ '%');
if(downloadPercent==100){
$("#preloaderWrapper").fadeOut(function(){
document.getElementById('myVideo').play();
clearInterval(ratoteLoad);
$(this).remove();
});
}
}
$('#myVideo').bind('progress', function()
{
loaded();
});
any idea?
thank you

try this instead:
myVideoTag = document.getElementById('video');
myVideoTag.addEventListener('progress', function(e) {
var percent = null;
// FF4+, Chrome
if (myVideoTag && myVideoTag.buffered && myVideoTag.buffered.length > 0 && myVideoTag.buffered.end && myVideoTag.duration) {
percent = myVideoTag.buffered.end(0) / myVideoTag.duration;
}
// Some browsers (e.g., FF3.6 and Safari 5) cannot calculate target.bufferered.end()
// to be anything other than 0. If the byte count is available we use this instead.
// Browsers that support the else if do not seem to have the bufferedBytes value and
// should skip to there. Tested in Safari 5, Webkit head, FF3.6, Chrome 6, IE 7/8.
else if (myVideoTag && myVideoTag.bytesTotal != undefined && myVideoTag.bytesTotal > 0 && myVideoTag.bufferedBytes != undefined) {
percent = myVideoTag.bufferedBytes / myVideoTag.bytesTotal;
}
if (percent !== null) {
percent = 100 * Math.min(1, Math.max(0, percent));
// ... do something with var percent here (e.g. update the progress bar)
}
}, false);
... comments copied from mediaelement.js, code as well but adjusted for easier display here. I omitted the code for Firefox 3.0 as it's less than relevant.
working fine in all current browsers
PS: thx to John Dyer for mejs - great stuff ;)

Related

D3 event showing 'ReferenceError: event is not defined' in Firefox

I am using mouse wheel zoom in my d3 Map.Following Code am using.
.on("wheel.zoom", function() {
var currScale = projection41039.scale();
var newScale = currScale - 1 * event.deltaY;
if (newScale >= 150) {
var currTranslate = projection41039.translate();
var coords = projection41039.invert([event.offsetX, event.offsetY]);
projection41039.scale(newScale);
var newPos = projection41039(coords);
projection41039.translate([currTranslate[0] + (event.offsetX - newPos[0]),
currTranslate[1] + (event.offsetY - newPos[1])
]);
updateContents();
}
})
This works fine for Chrome, but throws an error in Firefox:
ReferenceError: event is not defined
The issue here is that Chrome follows the Internet Explorer feature of Window.event, while Firefox doesn't:
For instance, given a button or any other element, the following snippet will work on Chrome, but not on Firefox:
d3.select("button").on("click", function() {
console.log(event)
})
Try it here: https://jsfiddle.net/b9h4ntn0/ (I normally use Stack Snippets, but the snippet will freeze in that particular example)
Solution
Use d3.event. That way, you don't rely on Window.event:
d3.select("button").on("click", function() {
console.log(d3.event)
})
The following code works both on Chrome and Firefox: https://jsfiddle.net/qj787zmj/

FabricJS - performance threading

Sorry if the title was misleading, it's the closest approximation I could come up with, haha.
Okay so I'm using FabricJS for a proof-of-concept for a fabric-printing client, and they require 300PPI images (i.e, freaking huge). Now, if you check the JsFiddle I've popped in below you'll see the tiling is done with some while loops which seem to work fine, except for the fact that the whole browser freezes while loading, meaning I can't even stick up a loader icon.
Have I done something horribly wrong, or is that just sorta how it works? The long loading times are fine as long as I can a) put up a loader and b) it doesn't, uh, "He's dead, Jim!" my Chrome. I'm getting the images with base64, if that helps at all.
Cheers everyone!
EDIT For context, here's one of the functions that creates a pattern from an uploaded file:
function renderMirror(){
showLoader();
var isFullRows = false;
var rowIndex = 0;
var totalHeight = 0;
while(isFullRows == false){
// let's start with filling up the row's columns. start the width at zero.
var totalWidth = 0;
var isFullCols = false;
var colIndex = 0;
if(rowIndex % 2){
var isRowMirrored = false;
}else{
var isRowMirrored = true;
}
while(isFullCols == false){
colIndex++
if(rowIndex == 1){
console.log('row');
}
if(totalWidth >= canvas.width){
isFullCols = true;
}
if(colIndex % 2){
var isColMirrored = false;
}else{
var isColMirrored = true;
}
canvas.add(new fabric.Rect({
left: totalWidth,
top: totalHeight,
fill: pattern,
flipX: isColMirrored,
flipY: isRowMirrored,
height: newImgHeight,
width: newImgWidth,
selectable: false
}));
totalWidth+= newImgWidth;
// safeguard
if(colIndex > 100){
isFullCols = true;
}
}
// now instantiate the row.
rowIndex++;
if(totalHeight >= canvas.height){
isFullRows = true;
}
totalHeight+= newImgHeight;
// safeguard
if(rowIndex > 100){
isFullRows = true;
}
}
hideLoader();
}
The whole thing is here, if you'd like to have a proper look?
I've experienced something similar to generate PDF at 300. I tried two different solutions:
Using webWorkers which will do the heavy work on the background and is not going to freeze the browser, however this approach was a little bit slower in my use case.
The second approach I took was create an endpoint where I get just the base 64 image and then with that data of the image I generate a PDF using imagemagick to create the PDF at 300 DPI also I create a virtual canvas with JS to generate the real size of the image from a scaled canvas in order to make it a little bit faster as well.

ff and rewind without using the currentTime attribute

I'm working on a HTML5 (for HLS videos) video player and i'm having problems to do trickplay actions (ff and rewind). the main issue is that the player doesn't seem to work with the currentTime attribute. is there any other property that i could use, don't know something like seekByTime , or SkippTo .
Any help?
this is my code (actually not working) :
function fastForward(mediaPlayer){
var a=mediaPlayer.duration;
var b=mediaPlayer.currentTime;
if(a>b){
mediaPlayer.currentTime=mediaPlayer.currentTime+10;
}
};
function rewind(mediaPlayer){
var a=mediaPlayer.duration;
var b=mediaPlayer.currentTime;
if(b>10){
mediaPlayer.currentTime=mediaPlayer.currentTime-60;
}
};
I try changing currentTime on Chrome 36, and IE 11 and run like a charm. In iOS you can also use PlaybackRate with negative values.
The code that I tested:
function changeCurrentTime(direction) {
if (direction == "-" && _video.currentTime > 5)
_video.currentTime -= 5;
else if (direction == "+" && _video.currentTime < _video.duration + 5)
_video.currentTime += 5;
}
In http://jsfiddle.net/5v2etjfg/6/ you can find my complete example.
Inspired on: https://developer.mozilla.org/en-US/Apps/Build/Audio_and_video_delivery/HTML5_playbackRate_explained
Hope this help.

Javascript/HTML 5 Video - Detect if video is not loading

Because IOS prevents auto-loading of video it is necessary to add a 'poster' image to indicate a play button (in this case).
However I also want to display a loading image for slow connections by swapping the poster image for a loading image when loading has started.
The problem is on normal connections the play button shows for a split second before the loading image.
So how can I show the play poster image for when it is detected that no loading is going to take place until the play button is pressed.
if ( yourVideoElement.readyState === HAVE_ENOUGH_DATA ) {
// it's loaded
}
https://developer.mozilla.org/en/DOM/HTMLMediaElement
UPDATE
Or you could use jQuery:
var videoDuration = $html5Video.prop('duration');
var updateProgressBar = function(){
if ($html5Video.prop('readyState')) {
var buffered = $html5Video.prop("buffered").end(0);
var percent = 100 * buffered / videoDuration;
//Your code here
//If finished buffering buffering quit calling it
if (buffered >= videoDuration) {
clearInterval(this.watchBuffer);
}
}
};
var watchBuffer = setInterval(updateProgressBar, 500);
You have to check two things, first the networkState and the readyState additionally you have to make sure, that either the preload attribute has a value other than 'none' or you are using an autoplay attribute. In this case you can write the following code (better to wait untill window.onload):
$(window).on('load', function(){
var myVideo = $('video');
if(myVideo.prop('readyState') < 1 && myVideo.prop('networkState') != 2){
//no automatically loading code
myVideo.prop('poster', 'noloading.jpg');
}
});
This is not tested, readyState == 0 means that there is no data and networkState 2 means it does not try to load.
With a timeout:
$(window).on('load', function(){
var myVideo = $('video');
if(myVideo.prop('readyState') < 1 && myVideo.prop('networkState') != 2){
//probably no automatically loading code
setTimeout(function(){
if(myVideo.prop('readyState') < 1 && myVideo.prop('networkState') != 2){
//no automatically loading code
myVideo.prop('poster', 'noloading.jpg');
}
}, 1000);
}
});

Asset.images slow? How do I execute functions so they don't freeze the browser?

I recently downloaded a nice mootools plugin to provide a rating system for search results on my site: MooStarRating.
It works quite well, but it is very slow to initialize. Here are the execution times I have logged (for pulling back 50 search results).
======== starrating ========
init: 0.06ms 50
img: 5.40ms 50
str: 0.54ms 50
each: 3.04ms 50
inject: 0.86ms 50
end: 1.52ms 50
subtotal: 11.42ms 50
-----------------
total: 571.00ms
Here is the initialize function these logs refer to (just for reference):
initialize: function (options) {
lstart("starrating");
// Setup options
this.setOptions(options);
// Fix image folder
if ((this.options.imageFolder.length != 0) && (this.options.imageFolder.substr(-1) != "/"))
this.options.imageFolder += "/";
// Hover image as full if none specified
if (this.options.imageHover == null) this.options.imageHover = this.options.imageFull;
lrec("init");
// Preload images
try {
Asset.images([
this.options.imageEmpty,
this.options.imageFull,
this.options.imageHover
]);
} catch (e) { };
lrec("img");
// Build radio selector
var formQuery = this.options.form;
this.options.form = $(formQuery);
if (!this.options.form) this.options.form = $$('form[name=' + formQuery + "]")[0];
if (this.options.form) {
var uniqueId = 'star_' + String.uniqueID();
this.options.form.addClass(uniqueId);
this.options.selector += 'form.' + uniqueId + ' ';
}
this.options.selector += 'input[type=radio][name=' + this.options.radios + "]";
// Loop elements
var i = 0;
var me = this;
var lastElement = null;
var count = $$(this.options.selector).length;
var width = this.options.width.toInt();
var widthOdd = width;
var height = this.options.height.toInt();
if (this.options.half) {
width = (width / 2).toInt();
widthOdd = widthOdd - width;
}
lrec("str");
$$(this.options.selector).each(function (item) {
// Add item to radio list
this.radios[i] = item;
if (item.get('checked')) this.currentIndex = i;
// If disabled, whole star rating control is disabled
if (item.get('disabled')) this.options.disabled = true;
// Hide and replace
item.setStyle('display', 'none');
this.stars[i] = new Element('a').addClass(this.options.linksClass);
this.stars[i].store('ratingIndex', i);
this.stars[i].setStyles({
'background-image': 'url("' + this.options.imageEmpty + '")',
'background-repeat': 'no-repeat',
'display': 'inline-block',
'width': ((this.options.half && (i % 2)) ? widthOdd : width),
'height': height
});
if (this.options.half)
this.stars[i].setStyle('background-position', ((i % 2) ? '-' + width + 'px 0' : '0 0'));
this.stars[i].addEvents({
'mouseenter': function () { me.starEnter(this.retrieve('ratingIndex')); },
'mouseleave': function () { me.starLeave(); }
});
// Tip
if (this.options.tip) {
var title = this.options.tip;
title = title.replace('[VALUE]', item.get('value'));
title = title.replace('[COUNT]', count);
if (this.options.tipTarget) this.stars[i].store('ratingTip', title);
else this.stars[i].setProperty('title', title);
}
// Click event
var that = this;
this.stars[i].addEvent('click', function () {
if (!that.options.disabled) {
me.setCurrentIndex(this.retrieve('ratingIndex'));
me.fireEvent('click', me.getValue());
}
});
// Go on
lastElement = item;
i++;
}, this);
lrec("each");
// Inject items
$$(this.stars).each(function (star, index) {
star.inject(lastElement, 'after');
lastElement = star;
}, this);
lrec("inject");
// Enable / disable
if (this.options.disabled) this.disable(); else this.enable();
// Fill stars
this.fillStars();
lrec("end");
return this;
},
So, the slowest part of the function is this:
// Preload images
try {
Asset.images([
this.options.imageEmpty,
this.options.imageFull,
this.options.imageHover
]);
} catch (e) { };
Which is strange. What does Asset.images do? Does the script block until these images have been loaded by the browser? Is there a way to preload images that runs faster?
How can I make the scripts on my page execute faster? It is a big problem for them to take 800ms to execute, but 200ms is still quite bad. At the moment, my search results all pop into existence at once. Is it possible to make it so that individual search results are created separately, so that they don't block the browser while being created? Similarly, is it possible to do this for the individual components of the search results, such as the MooStarRating plugin?
no. Asset.images is non-blocking as each of these gets loaded separately and a singular event is being dispatched when all done.
the speed for loading will be dependent on the browser but it be will multi-threaded to whatever capability it has for parallel downloading from the same host.
https://github.com/mootools/mootools-more/blob/master/Source/Utilities/Assets.js#L115-129
immediately, it returns an Element collection with the PROMISE of elements that may still be downloading. that's fine - you can use it to inject els, attach events, classes etc - you just cannot read image properties yet like width, height.
each individual image has it's own onload that fires an onProgress and when all done, an onComplete for the lot - i would advise you to enable that, remove the try/catch block and see which image is creating a delay. you certainly don't need to wait for anything from Asset.images to come back.
you also seem to be using it as a 'prime the cache' method, more than anything - as you are NOT really saving a reference into the class instance. your 'each' iteration can probably be optimised so it uses half the time if objects and functions are cached and so are references. probably more if you can use event delegation.
To answer your questions about not freezing the browser due to the single-threaded nature of javascript, you defer the code via setTimeout (or Function.delay in mootools) with a timer set to 0 or a 10ms due to browser interpretations. You also write the function to to exec a callback when done, in which you can pass the function result, if any (think ajax!).

Categories

Resources