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);
}
});
Related
I am using a Wordpress plugin to add timestamp links of videos that will seek the video automatically to a certain timeframe.
Javascript:
function onYouTubeIframeAPIReady(){
console.log('Confirmation of call to onYouTubeIframeAPIReady()');
var STT = {
settings: STTSettings,
media: undefined,
skipTo: undefined,
isHTML5: false,
isYoutube: true,
doHTML5Skip: function() {
STT.media.removeEventListener('canplaythrough', STT.doHTML5Skip);
STT.media.currentTime = STT.skipTo;
STT.media.play();
},
doYoutubeSkip: function() {
STT.media.seekTo(STT.skipTo);
STT.media.playVideo();
}
};
STTSkipTo = function(time) {
var audio = document.getElementsByTagName('audio'),
video = document.getElementsByTagName('video'),
iframe = document.getElementsByTagName('iframe'),
timeArray = time.split(':').reverse(),
seconds = parseInt(timeArray[0]),
minutes = timeArray.length > 1 ? parseInt(timeArray[1]) : 0,
hours = timeArray.length > 2 ? parseInt(timeArray[2]) : 0;
STT.skipTo = seconds + (minutes * 60) + (hours * 3600);
if (STT.media) {
console.log(STT.media.seekTo);
STT.doSkip();
return;
}
if ((parseInt(STT.settings.link_audio) && audio.length) ||
(parseInt(STT.settings.link_video) && video.length))
{
STT.doSkip = STT.doHTML5Skip;
if (parseInt(STT.settings.link_audio) && audio.length) {
STT.media = audio[0];
} else {
STT.media = video[0];
}
STT.media.addEventListener('canplaythrough', STT.doHTML5Skip);
STT.media.load();
STT.media.play();
return;
} else if (parseInt(STT.settings.link_youtube && iframe.length)) {
// Inspect the iframes, looking for a src with youtube in the URI
for (var i = 0; i < iframe.length; i++) {
if (iframe[i].src.search('youtube') !== -1) {
// Set up the JS interface
STT.doSkip = STT.doYoutubeSkip;
iframe[0].id = 'stt-youtube-player';
STT.media = new YT.Player('stt-youtube-player', {
events: {
onReady: STT.doYoutubeSkip
}
});
return;
}
}
}
console.log('Skip to Timestamp: No media player found!');
return;
}
}
On my localhost, the plugin works seamlessly but on my hosted website, I get the following error with the stack as follows:
Uncaught TypeError: STT.media.seekTo is not a function
I think for some reason the website is unable to load the www-widgetapi.js which is a dependency for YouTube iframe API and thus is unable to generate the required function definition. However, I did try to include the script manually in the header but it still didn't work.
If anyone knows of any other wordpress plugin, please advice.
Based from this documentation, you need to set both the two parameter of the player.seekTo(seconds:Number, allowSeekAhead:Boolean).
Seeks to a specified time in the video. If the player is paused when the function is called, it will remain paused. If the function is called from another state (playing, video cued, etc.), the player will play the video.
The seconds parameter identifies the time to which the player should advance.
The player will advance to the closest keyframe before that time unless the player has already downloaded the portion of the video to which the user is seeking.
The allowSeekAhead parameter determines whether the player will make a new request to the server if the seconds parameter specifies a time outside of the currently buffered video data.
It should be like: Player.seekTo(120, true)//120 seconds
I have a playlist of videos, with a list of each video in a sidebar. When I click on the name of the video I want to load in the sidebar, the player switches the current video to the one I just clicked.
Some videos have sections, and those sections need to start playing at a certain time in the video. For example, I have a video with 2 sections, Section 1 starts at 0:00, but when I click on "Section 2" in the sidebar, the video should start playing at 1:30 seconds into the video.
Now I got this working with the following code, but the poster image is still playing over the video when I click on Section 2 which should start playing in the middle of the video. How can I get rid of the poster image when starting a video with currentTime offset?
(function($) {
var current, gototime;
var istime = false;
// video.js object
var $player = videojs('ppi-video');
$('a').on('click', function(e) {
e.preventDefault();
var attr = $(this).attr('data-video');
var time = $(this).attr('data-time');
if(typeof time !== 'undefined' && time !== false) {
istime = true;
gototime = time;
}else {
istime = false;
gototime = undefined;
}
// If link has data-video attribute... continue
if(typeof attr !== 'undefined' && attr !== false) {
if( current == attr ) return;
var image_path = "images/screens/";
var content_path = "source/";
// Wait till player is ready
$player.ready(function() {
// Hide the player?
$("#ppi-video_html5_api").fadeOut(400, function() {
// Change poster
$("#ppi-video_html5_api").attr('poster', image_path + attr + ".jpg");
$player.poster(image_path + attr + ".jpg");
});
$player.src([
{ type: "video/mp4", src: content_path + attr + ".mp4" },
{ type: "video/webm", src: content_path + attr + ".webm" },
]);
// Set the currently playing variable
current = attr;
$("#ppi-video_html5_api").fadeIn();
});
}
});
function updateVideo() {
if( istime ) {
$player.currentTime(gototime);
$player.ready(function() {
/**
* Trying to get rid of poster here, but not working
*/
$("#ppi-video_html5_api").attr('poster', '');
$player.poster('');
$player.play();
});
}else {
$player.currentTime(0);
}
}
// update video when metadata has loaded
$player.on('loadedmetadata', updateVideo);
})(jQuery);
I found myself in the same situation where i needed to programmatically hide the poster image. (i wanted the posterimage to hide on drag of a custom scrubbar)
I found two ways that might help someone else who is in the same situation (i know this is an old post, but i came across it looking for an answer).
First and most simply you can hide the poster image using css:
.vjs-poster.vjs-poster.vjs-poster {
display: none;
}
// specificity bumped for default css, your mileage may vary.
However because i wanted this to be done on drag event i figured i might as well just use js:
player.posterImage.hide();
It looks like on Chrome and Firefox, setting currentTime() needs to be delayed a bit. What I did was call play() and then pause() to remove the poster before the video starts. Then I set a timeout of 200 milliseconds which has a callback which then calls currentTime().
Kind of a makeshift workaround but it is working nicely.
I have multiple videos on a site (mediaelement.js)
When i play one, all others pause and end which is fine.
But i want to show also the poster again.
How can i do it?
for now i modified the pauseOtherPlayers (function) to set the time back to 0 but i want the poster to show not only the beginning.
// FOCUS: when a video starts playing, it takes focus from other players (possibily pausing them)
media.addEventListener('play', function() {
var playerIndex;
// go through all other players
for (playerIndex in mejs.players) {
var p = mejs.players[playerIndex];
if (p.id != t.id && t.options.pauseOtherPlayers && !p.paused && !p.ended) {
p.pause();
p.setCurrentTime(0);
}
p.hasFocus = false;
}
t.hasFocus = true;
},false);
Whats the function to show the poster?
poster.show(); somehow does not work
thx
//////////////////////////////////////////////////////////////////////////////////////////
ok figured it out myself.
heres the code if anyone interested:
success: function (mediaElement, domObject) {
mediaElement.addEventListener("pause", function(e){
// Revert to the poster image when ended
var $thisMediaElement = (mediaElement.id) ? jQuery("#"+mediaElement.id) : jQuery(mediaElement);
$thisMediaElement.parents(".mejs-inner").find(".mejs-poster").show();
});
}
I've been looking around a lot of JavaScript answers but I haven't found one that really answers my problem yet. What I'm trying to do is load an image, grab the pixel data, perform an analysis, and then load another image to repeat the process.
My problem is that I can't preload all of the images because this script has to be able to work on large amounts of images and preloading could be too resource heavy. So I'm stuck trying to load a new image each time through a loop, but I'm stuck with a race condition between the image loading and the script drawing it to the canvas's context. At least I'm pretty sure that's what is happening because the script will work fine with the images precached (for example if I refresh after loading the page previously).
As you'll see there are several lines of code commented out because I'm incredibly new to JavaScript and they weren't working the way I thought they would, but I didn't want to forget about them if I needed the functionality later.
This is the snippet of code that I believe is giving rise to the problem:
EDIT: So I got my function to work after following a suggestion
function myFunction(imageURLarray) {
var canvas = document.getElementById('imagecanvas');
console.log("Canvas Grabbed");
if (!canvas || !canvas.getContext) {
return;
}
var context = canvas.getContext('2d');
if (!context || !context.putImageData) {
return;
}
window.loadedImageCount = 0;
loadImages(context, canvas.width, canvas.height, imageURLarray, 0);
}
function loadImages(context, width, height, imageURLarray, currentIndex) {
if (imageURLarray.length == 0 || imageURLarray.length == currentIndex) {
return false;
}
if (typeof currentIndex == 'undefined') {
currentIndex = 0;
}
var currentimage = new Image();
currentimage.src = imageURLarray[currentIndex];
var tempindex = currentIndex;
currentimage.onload = function(e) {
// Function code here
window.loadedImageCount++;
if (loadedImageCount == imageURLarray.length) {
// Function that happens after all images are loaded here
}
}
currentIndex++;
loadImages(context, width, height, imageURLarray, currentIndex);
return;
}
Maybe this will help:
currentimage.onload = function(e){
// code, run after image load
}
If it is necessary to wait for the image to load, the following code will load the next image (currentIndex is your "img" variable):
var loadImages = function(imageURLarray, currentIndex){
if (imageURLarray.length == 0 || imageURLarray.length == currentIndex) return false;
if (typeof currentIndex == 'undefined'){
currentIndex = 0;
}
// your top code
currentimage.onload = function(e){
// code, run after image load
loadImages(imageURLArray, currentIndex++);
}
}
Instead of a "for" loop, use for example this function:
loadImages(imageURLarray);
Maybe try this:
http://jsfiddle.net/jnt9f/
Setting onload handler before setting img src will make sure the onload event be fired even the image is cached
var $imgs = $(),i=0;
for (var img = 0; img < imageURLarray.length; img++) {
$imgs = $imgs.add('<img/>');
}
var fctn = (function fctn(i){
$imgs.eq(i).on('load',function(){
//do some stuff
//...
fctn(++i);
}).attr('src',imageURLarray[i]);
})(0);
Actually...a lot of developers are pointing here to detect when images are done loading after a jQuery event..
https://github.com/desandro/imagesloaded
If you can determine when the event triggers your images to load (for example, adding an Id or class onto the page right before your images begin to load), then you should be able to blend that in with this plug-in on github.
Good Luck!
As I hover a small img, I read it's larger image attribute, and create that image to display.
The problem is that I want to set Timeout before to display the image.
And while waiting for that timeout, we suppose to already have set an src to make it load early.
For some reason it never works in IE. ie, it only triggers the load even on the second time I hover the small image. I've no idea what has gone wrong with it, I had very similar animation on the other page it has been working just fine with a timeout.
Any ideas?..
$(document).ready(function(){
var nn_pp_trail=0;
$('div.nn_pp_in').hover(function(){
var limg=$(this).children('img').attr('limg');
var img=new Image();
//img.src=limg;
img.className='nn_pp_z';
img.src=limg;
var a=(function(img,par,limg){
return function(){
nn_pp_trail=window.setTimeout(showtrail,50);
$(img).one('load',(function(par){ //.attr('src',limg).
return function(){
// alert('loaded');
window.clearTimeout(nn_pp_trail);
hidetrail();
var width=this.width;
var height=this.height;
var coef=width/313;
var newHeight=height/coef;
var newHpeak=newHeight*1.7;
var nn=par.parents('.tata_psychopata').nextAll('.nn_wrap').first();
var pheight=nn.height();
var ptop=nn.position().top-2+pheight/2-1;
var pleft=nn.position().left+90+157-1;
$(this).appendTo(nn).css('left',pleft+'px').css('top',ptop+'px')
.animate({opacity:0.6},0)
.animate({opacity:1,top:'-='+newHpeak/2+'px',height:'+='+(newHpeak)+'px',left:'-=10px',width:'+=20px'},130,(function(newHeight,newHpeak){
return function(){
$(this).animate({left:'-='+(156-10)+'px',width:'+='+(313-20)+'px',height:newHeight+'px',top:'+='+(newHpeak-newHeight)/2+'px'},200,function(){});
}
})(newHeight,newHpeak)
);
}
})(par)
).each(function(){
if(this.complete || this.readyState == 4 || this.readyState == "complete" || (jQuery.browser.msie && parseInt(jQuery.browser.version) <=6))
$(this).trigger("load");}); ;
}
})(img,$(this),limg);
window.setTimeout(a,20); //if I set 0 - it loads all the time.
//if I set more than 0 timeout
//the load triggers only on the 2nd time I hover.
$(this).data('img',$(img));
},function(){
});
});
img.src=limg;
This was the problem, in IE we need not to set src as we create an image object, but first attach load event to it, and only then set attr src, and then trigger complete with an each, eg:
img.one(load, function(){}).attr('src','i.png').each(function(){ /*loaded? then it's complete*/ });
Hope someone learn on my mistakes :-)
Thank you, this helped me a lot. I had a similar situation.
As you said: First the "load"-event, then the "src" for IE.
// This was not working in IE (all other Browsers yes)
var image = new Image();
image.src = "/img/mypic.jpg";
$(image).load(function() {
//pic is loaded: now display it
});
// This was working well also in IE
var image = new Image();
imagSrc = "/img/mypic.jpg";
$(image).load(function() {
//pic is loaded: now resize and display
}).attr('src',imageSrc);