Run a script while HTML5 video plays - html

When using HTML5 video, is it possible to have a constantly running script while the video is playing (but only when its playing)?
For example:
video.onplaying = function(e){
alert("playing");
}
video.bind("ended", function(){
alert('Video Ended');
});
These are examples I found and tried to incorporate into my player with little success.

When video starts call setInterval() to start your background task and give it the repeat frequency.
Do tasks in this function.
When video stops call clearInterval().
https://developer.mozilla.org/en/window.setInterval

Related

How can I tell if a short (<10s) HTML5 video clip has started properly playing?

Occassionally* our web app host is slow (not sure why yet) and short video clips in our web app do not play.
Is there some dependable "video started " or "video finished" event that fires in Chrome and Safari (current versions) ?
We don't know how frequent "occassionally" is (hence this question :) )
This reference: http://www.w3schools.com/tags/ref_av_dom.asp contains all HTML5 audio/video properties, methods, and events.
I have recently implemented an audio recorder and playback using the html5 audio tag and both the play & ended events always fired (on all ie, safari, firefox, & chrome...we don't support opera so I didn't test it).
In your case, if the play event triggers at least once, and the ended event triggers, I would say this is conclusive that the video played through.
If one or both of those events don't trigger, then I would suggest looking into some of the other properties of the audio/video element (ie. readyState, or canPlayThrough) to confirm the media source is available.
For more detailed debugging, I suggest the following console.log debugging so you know all events that are occurring. This example is using jQuery, but can easily be implemented without:
var video = $("#player video")[0];
$(video)
.bind('loadstart', function() {
console.log("Loadstart");
if(video.networkState === 3){
console.log("Error loading file");
}
}) .bind('loadedmetadata', function() {
console.log('loadedMetaData');
})
.bind('stalled', function (){
console.log('stalled');
})
.bind('suspend', function(){
console.log('suspend');
).
.bind('canplaythrough', function() {
console.log('canplaythrough');
})
.bind('play', function() {
console.log('play');
})
.bind('pause', function() {
console.log('pause');
})
.bind('ended', function() {
console.log('ended');
});
While the above code won't solve the problem for you, it may expose events in your video player you weren't aware fired. I noticed safari will fire stalled, suspend events more than other browsers will. While it makes sense to include the 'error' event, I never saw it fire myself....YMMV -- Couldn't hurt to include it.
Good luck.

Firefox firing the 'pause' event on videos when the time is changed or it ends

I have a video embedded on a website and I'm getting some odd behavior in Firefox.
Every time I change the playback position by clicking on the time slider, the pause event is fired. Similarly, every time the video ends the pause event is fired, even before the ended event.
I was first wondering if I had an error in some JS I had written (to make the video bigger on playback, and then shrink it on pause - code here). However, I tested with just this simple code and the behavior still exists -
$(document).ready(function(){
video = $('#intro-video');
video.on('pause', function(){
alert('pause');
});
});
This doesn't happen in other browsers, and it is very undesirable behavior for Firefox. Is there a way to prevent this from happening? Thanks,
Note
If anyone is interested, here is the link to Pastebin containing my code, but after testing with the above I'm pretty sure this is not the issue.
Update
I have found this thread which suggests the behavior described about is actually by design, but I find that hard to believe. The author says that IE, Opera and Safari get it wrong while Firefox gets it right, but surely that's not correct...
I have been working on monitoring events for HTML5 video/audio and from time to time I find something that you described: it is not consistent across browsers and given the same browser it can vary between versions. I would suggest you stick to the specs in this case:
ended event: it should fire a pause event right before the ended event (given you have no current media controller ie multiple sync media players). Here Firefox does it as expected.
seeking: it should not fire a pause event. There is no mention of that in the specs. Here Firefox seems to drop the ball. However if the video is paused in FF and you seek then the pause event is not fired.
Amongst IE 11, FF 28 and Chrome 34 I found that only Chrome does fit the specs to the letter for this question on both events.
You could consider asking Mozilla why is such a behavior implemented?
If you want to bypass this behavior (do not know how to call it) you need to build you own custom controls in JS. The code below illustrates that the pause event does not fire if you programmatically seek to a point in time of the video (the #seekBar div):
<video id="intro-video" width="640" height="360" controls>
<source src="../media/360p.mp4" type='video/mp4' />
</video>
<div id="seekBar">Seek +5sec</div>
<script type="text/javascript">
$(document).ready(function(){
video = $('#intro-video');
videoJ = $('#intro-video')[0];
video.on('pause', function(){
console.log('pause');
});
video.on('play', function(){
console.log('play');
});
video.on('ended', function(event){
console.log('ended');
});
video.on('seeking', function(){
console.log('seeking');
});
video.on('seeked', function(){
console.log('seeked');
});
$('#seekBar').on('click',function(){
var currentT = videoJ.currentTime;
videoJ.currentTime = currentT + 5;//on click seek forward + 5 sec
});
});
</script>
You can have a look here to start building your own controls.
Maybe a lib like videojs can fix it for you (not tested on this chain of events)
I was able to work around this issue on Firefox by adding a timeout and checking if the video is paused inside the timeout. Only when the video.paused returns true, I execute my code:
const showOverlay = video => video.closest('.jsvideo').classList.remove('is--playing');
$$('.js-video video', video => {
video.addEventListener('pause', () => {
if (video.readyState !== 4) {
return true;
}
// Firefox dispatches the pause event but
// doesn't set the video to paused
setTimeout(() => {
if (video.paused) {
showOverlay();
}
}, 250);
});
video.addEventListener('ended', showOverlay);
});
The $$ functions is just a helper function which queries the DOM.
I used a 250ms timeout but I think it can be significantly reduced (even to zero) because the check will be executed after the pause event is triggered.
The actual UX is left untouched because the timeout is unnoticeable and doesn't affect the speed of the UI updates.

How to "autoplay" an HTML5 audio element in Mobile Safari?

I am porting a vehicle in-dash display unit app over to the browser. The big goal is to get it running completely within Mobile Safari.
It's an HTML5/JS music app that relies heavily on jQuery.load to move around between different "screens" by loading in page fragments.
The issue is that when a user selects a track to play, they are taken to the "now playing" screen, which should start playback of the track. The track is not playing though once this screen is reached, and the user instead needs to explicitly click play from this screen in order for audio playback to start. Once this has happened for the first time, autoplay works for the duration of the app.
I understand that Mobile Safari intentionally put blockers in place to prevent audio from autoplaying so that web apps are kept from consuming data unless in direct response to user input.
The thing is, my audio playback IS in direct response to user input...sort of. However, a bunch of things need to happen before my playback actually starts, and those things happen within the now playing page (calling API to get URL for track to be played, report user is playing track, get track metadata, yatta yatta yatta).
To try and get around this, I have the app preload a silent .1s mp3 file into the audio element on startup. Then in direct response to a click event to transition to now playing screen, I call .play() on the audio element.
I assumed that having a call to .play in direct response to user input would the subsequent call to .play() within the now playing page to work, since this is the behavior I had previously observed.
Only, it didn't seem to make any difference.
Any ideas on how I can adjust my flow in order for audio playback to start after loading the now playing screen?
EDIT:
Added some code snippets below
Vehicle.audio = {
init: function () {
audioElement.setAttribute("src", "/audioinit.mp3");
audioElement.play();
},
play: function (source) {
log("VEHICLE: playing audio from source " + source);
Vehicle.audio.stop();
audioElement.setAttribute("src", source);
audioElement.play();
},
In response to user selecting a track:
$(document).on("click", "a.play-track", function () {
Vehicle.audio.init();
/* my wrapper function for jQuery.load() */
replace_wrap("nowplaying.html");
});
Then on the now playing page, Vehicle.audio.play() is called.
The thing is, my audio playback IS in direct response to user input...sort of. However, a bunch of things need to happen before my playback actually starts, and those things happen within the now playing page (calling API to get URL for track to be played, report user is playing track, get track metadata, yatta yatta yatta).
Try adding a "touchstart" event listener to the entire "now playing page" which will then synchronously call .play() on the audio element:
$(document).one("touchstart", function () {
Vehicle.audio.init()
})
This way as soon as an iOS user touches anywhere on the now playing page, the audio should begin loading/playing.
AFAIK it is a restriction placed intentionally by iOS. User must interract with the device (touch/click event) before the script is allowed to start playback.

HTML5 Multiple Video Display - Hover Over to Play

Okay so I have followed a good tutorial regarding embedding videos via HTML5 video tag, which can be found here. Basically the idea is that on hover the video plays, on hover out it stops playing.
Well, I've been trying to include multiple videos on one page (all the same video, mind you) in hopes that I could create a sort of interactive multi-tiled board of sorts. In other words, you hover over each video, it creates varying images based on where in each video you end up, etc.
Whatever, the question I am asking is: based on this tutorial that I've followed, what is the best way to create multiple, tiled videos? I'll paste the code I've been working with. The problem I'm having is that if I create multiple javascript functions, it shows only the video of the last function I've created, rather than all videos.
I hope this makes sense. Here is the link to what I've been working on so far. NOTE: the video takes a while to load, so until then it will play the sound but no image.
Thanks in advance for any help!
Here is the solution I found:
The only warning I give you is to set the videos to preload="none" because if they all load it will be nightmare on your bandwidth. I had to switch mine and now I am looking for a solution to let people know a video is loading.
var vid = document.getElementsByTagName("video");
[].forEach.call(vid, function (item) {
item.addEventListener('mouseover', hoverVideo, false);
item.addEventListener('mouseout', hideVideo, false);
});
function hoverVideo(e)
{
this.play();
}
function hideVideo(e)
{
this.pause();
}
Here is where I got the answer: http://www.dreamincode.net/forums/topic/281583-video-plays-on-mouse-over-but-not-with-multiple-videos/
For anyone that's looking to achieve this using jQuery, here's a solution that I use for dynamically loaded content:
//play video on hover
$(document).on('mouseover', 'video', function() {
$(this).get(0).play();
});
//pause video on mouse leave
$(document).on('mouseleave', 'video', function() {
$(this).get(0).pause();
});
This can be used for a page with 1 - N videos, and only the hovered video will play at each time, while each will pause on the current frame on mouseleave.
Here's an example of it in action: http://jsfiddle.net/cc7w0pda/
Try this, it's easy to understand
<!DOCTYPE html>
<html>
<video id="vv" width="500" height="500" controls onmouseout="this.pause()" onmouseover="this.play()">
<source src="xx.mp4">
Your browser does not support this file
</video>
</html>

HTML5 video (videojs) pause() & play() doesn't work?

I have a fully functional HTML5 video, it's ID is "#html5-video-7345".
I'm trying to control it using jQuery but I don't know how.
NOTE: I don't need an autoplay, this is just simplified version of what I need:
jQuery(document).ready(function(){
alert('test1');
jQuery('#html5-video-7345').player.play();
alert('test2');
});
Alerts "test1" twice.
The same happens with jQuery('#html5-video-7345')[0].player.play() or jQuery('#html5-video-7345')[0].play().
What's wrong? How to stop() / play() HTML5 videos using jQuery/JS?
I wasn't able to find videojs function reference and Google was totally misleading. Luckily I found this solution, and it works perfect:
jQuery('#html5-video-7345').player.play(); //wrong
jQuery('#html5-video-7345').player().play(); //correct
Make sure the canplay event has fired before trying to calling .play():
jQuery('#html5-video-7345').bind("canplay", function() {
this.play(); // Should start video
});
The canplay event is fired when the browser can start playing the video, but it doesn't guarantee that it can play the video to completion. If that doesn't suite your purposes, there are a couple of other related events that you can listen to such as loadeddata and canplaythrough.