I'm trying to determine when the buffering has finished from a HTML5 audio element, but so far I can't find any loadComplete or similar event. I've tried using the progress event however it doesn't fire when finished downloading - only while downloading and therefore I can't use that to check. I've also tried the standard load event but that seems not to fire at all.
What other events are there that would allow me to check if buffering is finished, or would I have to use a timer to keep checking if a.buffered.end(0) == a.duration?
Thanks,
The Audio Data API provides an event called MozAudioAvailable which does what you need. This is in Firefox 4 only, but other modern browsers may implement it in the future.
Related
I'm looking for a way to create something like a loading animation on a html5 video similar to the Youtube Video display (reference: https://www.youtube.com/watch?v=5vcCBHVyG50)
I tried it with the canplay-Event but I think I misunderstood the real meaning of this event.
My thought of this event was that enough data has been loaded and buffered so that the video can be played again.
But in my case this event just fires once. At the beginning of the video.
Is there any special Event which will be fired when the video is playable or needs to load more data?
Use fontAwesome framework. It has got your animation.
I'm messing around with HTML5 videos and custom controls and I'm looking to use the waiting event to ideally display a loading image but just writing to the console will do for now.
The waiting event
Playback has stopped because the next frame is not available, but the
user agent expects that frame to become available in due course.
I've set an example up here -> http://jsbin.com/uvipev/2/edit#javascript,html,live
Here's the video code minus the controls:
<video controls preload="meta">
<source src="http://www.tools4movies.com/dvd_catalyst_profile_samples/The%20Amazing%20Spiderman%20tablet.mp4" />
This is video fallback
</video>
And here's my event listener for the waiting event.
var video = document.getElementsByTagName('video')[0];
video.addEventListener('waiting', function() {
console.log('waiting');
}, false);
Can anyone see why this isn't running? The waiting event sounds like what I need.
Are you looking to display a waiting image while the video buffers for the first time? If so, you probably aren't looking for waiting.
Take a look at this demo: http://www.w3.org/2010/05/video/mediaevents.html
If you call play() without any preloading, you should see waiting fire, even on a cached copy. If you call load() before play(), you may never see waiting fire, since the next frame could always be available.
The best process would be to display your image, call load() and then listen wait for either canplay or canplaythrough. At that point, hide your image and kick off play().
Update
Looking at the video in this fiddle: http://jsfiddle.net/bnickel/zE8F3/ Chrome isn't sending the waiting event but is instead sending the stalled event shortly after the video freezes up. You're probably going to need to check how things work on each browser you support. Bear in mind, players like VideoJS are huge (~142KB) because they deal with a lot of browser inconsistencies.
There's a good chart here that attempts to document the behavior of different browsers in a "buffer underrun" scenario, which is what I think you're looking for.
https://web.archive.org/web/20130902074352/http://www.longtailvideo.com/html5/buffering/
Unfortunately, the browsers are wildly inconsistent, so while I do believe the "waiting" event is what you want, Chrome doesn't fire it.
I've been experimenting with "guessing" when the player is buffering based on the elapsed time of the video, checking for play/pause/etc. events so that I know when the time should be increasing.
I'm building a jQuery plugin for managing HTML5 videos. I'm trying to capture the canplay and canplaythrough events. In Chrome, the event is fired without problem. In Firefox, sometime it's triggered, sometime it's not.
I'm simplifying my code a little here:
$('#my_video').on('canplay canplaythrough', function(){
console.log('canplay event fired');
});
I also tried with the native javascript .addEventListener() and it's not working.
Any idea why the event is not called on Firefox and how to fix that?
NOTE: Please do not tell me to use one of the already available plugins like jplayer and video-js, I know that they exist and work well, but I have to build an in-house solution.
The problem is that your video element has triggered the canplaythrough event before you registered the event handler.
As you pointed out in your own answer, you can put your scripts in the <head>, but this is bad for your page performance.
A better way to fix your problem is to check the readystate attribute and execute your function manually in that case:
var $video = $('video'),
videoElement = $video[0];
$video.on('canplaythrough', callback);
// If the video is in the cache of the browser,
// the 'canplaythrough' event might have been triggered
// before we registered the event handler.
if (videoElement.readyState > 3) {
callback();
}
The most likely reason you're seeing this probably has to do with timing issues. You stated in your accepted answer that putting jQuery into the head rather than the footer solves the problem. This tells me that the issue is DOM parsing and script execution order. The most likely culprit is that the "canplay" and "canplaythrough" events were being fired before jquery and your page script were parsed and the event handlers added - but only sometimes, depending on network traffic and load times. By putting the script in the head, you forced your event binding to occur before the DOM elements were created, thereby ensuring that you didn't miss any events.
As an aside, the performance benefits of putting script elements at the bottom of the page are debatable. If you really want to tweak page performance, use something like LABjs to manage parallel script loading.
In my case, this was determined by the preload attribute specified for the element. I did not have it specified at all, so different browsers were choosing to do different things.
Once I specified preload="auto", the on("canplay") event handler worked fine/as expected.
Even if my question didn't get any attention whatsoever, I think it's a good idea to give an explanation for people who may stumble on this in the future...
The problem is really weird: if the jQuery core is included in the footer, some of the video events do not work. If the jQuery core is included in the head of the document, all events are called correctly.
So the solution is to include the jQuery core in the html head even if "best practices" for optimization recommends placing all script at the end of the body for faster loading times.
I do also think this is a race condition. The way I got around it is as follows:
In the HTML of the video element add the attribute preload="metadata" - to just preload the video metadata. So:
<video id="myVideo" width="640" height="480" preload="metadata" />
Next, inside the JS:
var $vid = $("#myVideo");
$vid.bind("canplaythrough", console.log("can play through full video"));
$vid.get(0).load();
This logged the message for me in Chrome - haven't tested elsewhere.
If you expect the Firefox to load the whole audio after you trigger load then it would not do this. It will fire the loadstart but will not download anything. No progress events will be fired. And it will actually do no request to that file. You can see this behavior in the Firebug.
Firefox will only start loading the file after you trigger 'play`.
Proof. See console output.
Adding:
var video = $('video');
video.trigger('load');
After adding the canplaythrough event listener fixed it for me on Firefox and Safari.
After 1.5 days of trying different approaches from here (in vanilla). The events "canplay" and "canplaythrough" with addEventListner don't work in Edge. They work fine in every other Browser. So I ended up with a check of "ready-state" with setTimout :-(. Not realy elegant, but it works for me.
Controller.prototype.backGroundControl = function () {
var vid = document.querySelector('#bgvid');
var bgImg = document.querySelector('#bgimg');
_this = this;
if (vid.readyState === 4){
bgImg.style.opacity = "0"
} else{
setTimeout(function(){
_this.backGroundControl();
},500)
}
}
I am using jQuery 1.5 and jPlayer 2.0.0, please ignore the fact that this is going to auto play music, I am going to supply enough warning before it starts, the user has to press a big button to initiate the page and I will provide a big STOP button.
I would like the audio file to begin playing and a function be called after the page is ready and the audio is loaded.
I have the following javascript (I have modified the code so it can be understood better).
function FemeMusic() {
FemeMusic.prototype.addMusic = function(actionAfterMusic) {
$("#jp").jPlayer({
ready: function() {
var jPlayerElement = $(this);
jPlayerElement.jPlayer('setMedia', {
mp3: 'aSongByJamesBlunt.mp3'
});
jPlayerElement.bind($.jPlayer.event.progress,
function(event) {
if (event.jPlayer.status.seekPercent === 100) {
jPlayerElement.jPlayer("play");
}
if (actionAfterMusic) {
actionAfterMusic.call();
}
});
},
swfPath: "/flash",
preload: "auto"
});
}
}
I have this function to trigger the above code.
$(document).ready(function() {
var femeMusic = new FemeMusic();
femeMusic.addMusic(killMyself);
});
I was using the same code but with the $.jPlayer.event.loadeddata event without the if statement instead of $.jPlayer.event.progress and it worked fine in some browsers but isn't compatible when it comes to using flash because it doesn't fire the event (Also I had a problem with it in firefox 3.5 but I don't know why). The above seems to work in Firefox
I read this
"I suggest you use the progress event instead and check that the:
event.jPlayer.status.seekPercent === 100. "
On this post http://groups.google.com/group/jplayer/browse_thread/thread/9dc9736f9d6947bd?pli=1 by the creator
Any one got any suggestions?
Edit
Having not got this working in chrome and safari I tested this on a new version 3.6 of Firefox (which I should have done in the first place) and it worked as expected, despite the fact that in the documentation event.progress id described as:
A robust jPlayer event supported by Flash and HTML5 browsers
and in the link above the creator suggests to use event.progress to get round browser problems I can only assume it's a browser specific issue.
Would be nice to get some clarification on this though.
From the creator of jPlayer:
So your goal here is to auto-play AFTER the media is buffered?
If you want the short answer. Forget it. x-browser buffering is a mine
field. Some simply ignore it as you have found. Just setMedia and play it.
If you really want to try and do it. Then a play then pause would help,
since a media.play() is better x-browser than a media.load() i.e. its
operation varies less. The iOS Safari would ignore the play completely
though. The user would need to click on something that starts the
operation i.e. a play button.
That last point applies to trying any form of autoplay, so ensure that there
is a play button available. The jPlayer interface will cope with iOS not
playing through feedback from the browser events i.e. stalled.
I had problems with the progress event with flash and html5 backend in most browsers. as far as I can see the timeupdate event is working much better.
I'm working on a site for a client and they're insistent on using HTML5's video tag as the delivery method for some of their video content. I currently have it up and running with a little help from http://videojs.com/ to handle the Internet Explorer Flash fallback.
One thing they've asked me to do is, after the videos finish playing (they're all a different length), fade them out and then fade a picture in place of the video --- think of it like a poster frame after the video.
Is this even possible? Can you get the timecode of a currently playing movie via Javascript or some other method? I know Flowplayer (http://flowplayer.org/demos/scripting/grow.html) has an onFinish function, is that the route I should take in lieu of the HTML5 video method? Does the fact that IE users will be getting a Flash player require two separate solutions?
Any input would be greatly appreciated. I'm currently using jQuery on the site, so I'd like to keep the solution in that realm if at all possible. Thanks!
You can view a complete list of events in the spec here.
For example:
$("video").bind("ended", function() {
alert("I'm done!");
});
You can bind to the event on the element like anything else in jQuery...as for your comment question, whatever element you're delivering for IE, yes, it would need a separate handler rigged up to whatever event it provides.
For the other question about timecode, the timeupdate event occurs when it's playing, and the durationchange event occurs when the overall duration changes. You can bind to and use them just like I showed with the ended event above. With timeupdate you'll probably want the currentTime property, with durationchange you'll want the duration property, each of which you get directly off the DOM object, like this:
$("video").bind("durationchange", function() {
alert("Current duration is: " + this.duration);
});
There is an OnEnded event associated with the video tag. However, it does not work for me in the current version of Google Chrome.
HTML 5 Video OnEnded Event not Firing
and see also
Detect when an HTML5 video finishes
For a general-purpose solution (supports video tag with fallback see)
http://camendesign.com/code/video_for_everybody
or
http://www.kaltura.org/project/HTML5_Video_Media_JavaScript_Library or http://www.mediafront.org/
I used this code. It basically reloads the video which will get the poster to show again. Assuming you want the image at the end to be the same as the poster. I only have one video on the page so using the video tag works. I have my video set to autoplay on page load so I added the pause after the reload.
<script type="text/javascript">
var video= $('video')[0];
var videoJ= $('video');
videoJ.on('ended',function(){
video.load();
video.pause();
});
</script>