This question already has an answer here:
Event for every frame of HTML Video?
(1 answer)
Closed 24 days ago.
I need detect all frames changes of a video in HTML 5, i tried the follow code, but i can't get all changes, only i can get eight or nine updates per second..
<body>
<canvas id="Canvas" width="800" height="450" style="position:absolute; left:5; top:5">Can't Load Canvas</canvas>
<video id="videoPlay" muted controls>
<source src="assets/soccer.webm" type="video/webm">
<source src="assets/soccer.mp4" type="video/mp4">
Your browser does not support the video tag.
</video>
</body>
<script type="text/javascript">
videoPlay.addEventListener('timeupdate', function (){
putOverlay();
});
function putOverlay(){
console.log(videoPlay.currentTime);
console.log("another frame");
}
</script>
</html>
I tried the following code too, but with a timer there is a loss of synchronization between the frame and the value given by the timer, over time..
<body>
<canvas id="LeCanvas" width="800" height="450" style="position:absolute; left:5; top:5">Can't Load Canvas</canvas>
<!-- Video -->
<video id="videoPlay" controls>
<source src="assets/soccer.webm" type="video/webm">
<source src="assets/soccer.mp4" type="video/mp4">
Your browser does not support the video tag.
</video>
</body>
<!-- Play Video-->
<script>
//Play Damn Video
var videoPlay = $('#videoPlay')[0];
videoPlay.play(1);
</script>
<!-- Canvas Animation -->
<script>
//Animation
function animate() {
console.log("frame change");
}
setInterval(animate, 1000/29.97);
</script>
Any suggestions for my problem?
Sorry my english
regards
Alex
As noted in the comments above, timeupdate only fires every 15-250ms, and in practice it appears to be closer to 250ms. It seems as though timeupdate was designed to provide enough accuracy to display the currentTime every second. So your best option is to run a timer that runs at the rate you want and query currentTime on every iteration.
But rather than use setInterval or even setTimeout, you should be using requestAnimationFrame. This will run approximately every 16ms (60fps), but it will be synchronized with the video card refresh rate. If you use setTimeout, you may see flicker or screen tearing on certain devices, especially mobile ones. It also allows the browser to throttle your frame rate when the tab is not visible to save on CPU cycles (and therefore battery usage).
It's also better than setInterval because, if for some reason your render code takes longer than the 30 or 16ms you've allotted, setInterval may pile up calls and cause timing problems, but requestAnimationFrame will skip frames to get you back on track.
Assuming you've used the polyfill as above, the code would look something like this:
var video = document.getElementById('videoPlay'),
lastTime = -1;
function draw() {
var time = video.currentTime;
if (time !== lastTime) {
console.log('time: ' + time);
//todo: do your rendering here
lastTime = time;
}
//wait approximately 16ms and run again
requestAnimationFrame(draw);
}
draw();
The above code has a check on time to make sure you don't draw the same frame twice in a row. You don't really need that, but it will save you a few CPU cycles. But when drawing a video to canvas, the frame is a couple of milliseconds behind what's reported by currentTime. So if you pause the video and then skip around, you will almost definitely be one frame behind. Usually, if the currentTime hasn't changed since my last draw but the video is paused, I'll keep drawing every cycle for another half second or so. Or you could just take the time check out.
Related
So the HTML5 video has no controls. Basically I want to show a loading gif that shows over the video only when the video is loading (buffering and paused)
<video id="myvideo" width="100%"><source src="video/Good.mp4" type="video/mp4"><source src="movie.html" type="video/ogg"></video>
How about using the built-in browser animation instead of a gif.
All you have to do is set the controls to TRUE and then back to FALSE depending on the buffering state.
The best practice for me looks like this,
<video src="myVideo.fileExtension" onplaying="hideControls(this)" onwaiting="showControls(this)" preload="auto" poster="myAnimatedWebpOrGifThatSaysVideoIsNotYetReady.fileExtension">No video support?</video>
<script type="text/javascript">
//We hide the video control buttons and the playhead when the video is playing and enjoyed by the viewer
function hideControls(event){ event.controls=false; }
//If the video has to pause and wait for data from the server we let controls be seen if the user hovers or taps on the video. As a bonus this also makes the built-in loading animation of the browser appear e.g. the rotating circular shape and we give it a little delay (like 1 sec) because I would say it looks and feels better.
function showControls(event){ setTimeout(function(){ event.controls=true; },1000); }
</script>
Maybe you could use ontimeupdate instead of onplaying which would fire continuously.
As for the delay time actually not 1 but 4 seconds -to me- is the best.
I have an undetermined amount of very short videos that I would like to loop through.
I have the following HTML:
<video class="bgvid bgvid--0 bgvid--visible" poster="<?= URL ;?>img/vidframe.jpg" src="1920x800.webm" playsinline muted></video>
<video class="bgvid bgvid--1 bgvid--hidden" poster="<?= URL ;?>img/vidframe.jpg" src="1920x800.2.webm" playsinline muted></video>
<video class="bgvid bgvid--2 bgvid--hidden" poster="<?= URL ;?>img/vidframe.jpg" src="1920x800.2.webm" playsinline muted></video>
In my CSS I show the one video with class bgvid--visible, and hide all others with class bgvid--hidden as follows:
.bgvid--hidden { opacity: 0; }
.bgvid--visible { opacity: 1; }
In my JS I start playback of my initial video by doing the following:
$('.bgvid--0').get(0).play();
Then after 5 seconds using CSS transitions and by switching the bgvid--visible and bgvid--hidden classes I "fade out" the current "active" video, and start playback and "fade in" the following video as follows:
setTimeout(function(){
$('.bgvid--0').removeClass('bgvid--visible').addClass('bgvid--hidden');
}, 5000);
setTimeout(function(){
$('.bgvid--1').get(0).play();
$('.bgvid--1').removeClass('bgvid--hidden').addClass('bgvid--visible');
}, 4500);
Notice the second timeout being slightly shorter than the first in order to create the impression of a seamless transition by fading in the next video prior to fading out the active one.
I have read about "ended" events, but the transition has to start before the video has ended. How can I turn this into a loop of some kind that loops this way through an undetermined amount of videos?
You can get the length of your video using videoElement.duration, and the current time with videoElement.currentTime.
You can use the HTML Audio/Video timeupdate event to monitor if the current time reached the last 5 seconds, and then start the transition to the next video.
videoElement.ontimeupdate = function() {
if (videoElement.currentTime >= videoElement.duration - 5) {
startTransition();
}
};
You could use only the duration, and simply set your timeout accordingly, but nothing guarantees that a 30 seconds video will really end 30 seconds later. It can be paused, or it can buffer for some time. But this method will tell you when the video is really 5 seconds from the end.
I am developing a page with a full width / full height intro video (100vw / 100vh), looks "full screen" until you scroll down.
Currently I am using HTML5 <video> to accomplish this, but I've noticed the page can get a little choppy, particularly while scrolling. The video is about 4mb.
Would I see an increase in performance if I were to replace the <video> with a <canvas>, and load the video frames directly through the canvas object instead? both elements are GPU accelerated so I'd figure it shouldn't make a difference, but I'm not sure.
No, all the cost of decoding a video frame is still there. Using a canvas would in addition to that add more cost, not less.
If the video is without sound you could temporary pause the video while scrolling, as well as pause it permanently when out of view:
var vt;
window.onscroll = function() {
video.pause(); // pause video
clearTimeout(vt); // clear timer
vt = setTimeout(function() { // create a new timer
var r = video.getBoudingClientRect(); // abs. bound
if (window.scrollY < r.height) video.play(); // assumes video is in top
}, 70); // 70ms
...
};
Another key, although not of very much difference, is to make sure the video code is easy to decode. You can achieve this by removing noise, use flat colors and large surfaces, good lighting conditions, low depth-of-field to blur background as well as lower contrast and avoid too many details in the main subject(s) (this will also produce smaller files).
var video = document.querySelector("video"),
vt;
window.onscroll = function() {
video.pause();
clearTimeout(vt);
vt = setTimeout(function() {
var r = video.getBoundingClientRect();
if (window.scrollY < r.height) video.play();
}, 70);
};
html, body {width:100%; height: 2000px}
video {
width:100%;
height:auto;
}
<video muted width="500" height="280" autoplay="true">
<source src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4" type="video/mp4">
<source src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.webm" type="video/webm">
<source src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.ogv" type="video/ogg">
</video>
I am trying to skip a video ahead, using currentTime.
I set my video up like this:
<style>
#video-player {
display:inline-block;
width:500px;
height:358px;
margin-left:20px;
}
</style>
<video id="video-player" controls autoplay>
<source src="messi.mp4" type="video/mp4">
</video>
Later on, I have a click event set up on a button.
var video = document.getElementById('video-player');
video.currentTime = parseInt(video.currentTime) - 2;
All I want that button to do is to move the video back 2 seconds in time.
But when I click, it either moves the video to the beginning to freezes it up.
So this is very strange, but the issue went away when I tested my code on a live url.
I was testing using a local Python web server where I encountered the problem. Hope this helps someone.
I'm trying to achieve something with html5 video and haven't been able to find an answer elsewhere. Is it possible? Any help is much appreciated.
Here's the html:
<video autoplay="autoplay" poster="http://dummyimage.com/320x240/ffffff/fff">
<source src="videos/ship.mp4" type="video/mp4" />
</video>
I want to:
- on page load, display the video paused on the first frame (use poster?)
- at vertical scroll of X pixels, play the video once through (alternatively, inject it onto the page at X scroll?)
- then, when I scroll back beyond the X pixels value play the video again in reverse once through (does this work aMediaElement.playbackRate = -1; ?)
sadly the simplest solution playbackRate = -1 doesn't seem to be implemented anywhere yet.
you could fake it with some code like below to jump the currentTime back at whatever rate you need but from playing around it doesn't look very smooth.
my suggestion would be - if practical - to actually encode a a reversed version of the video if being able to play it backwards is the goal and then swap the source or toggle the visible <video> tag
Oh, and as usual... any video you're planning to stream on the web make sure you optimize and get the moov atom in the right place (see sample ffmpeg)
<script>
var intervalRewind = 0;
var v = document.getElementById("v")
function rewind() {
intervalRewind = setInterval(
function(){
v.playbackRate = 1.0;
if(v.currentTime == 0){
clearInterval(intervalRewind);
v.pause();
} else {
v.currentTime += -.1;
}
},30);
}
</script>
...
<video id="v" onclick="clearInterval(intervalRewind)" width="320" height="240" controls="controls">
<source type="video/mp4" src="video-fs.mp4" />
</video>
<button onclick="rewind()">Rewind</button>