html 5 video tracking with percentage - javascript

how to track the status of video watched or not
if I write like this after 60%, I can send an ajax call and update the status to watched 60%
var i=0;
$("#video").bind("timeupdate", function(){
var currentTime = this.currentTime;
if(currentTime > 0.66*(this.duration)) {
if(i<1) {
/* Watched 66% ajax call will be here*/
}
i=i+1; //Reset for duplicates
}
});
Similarly.
if I write like this after 100% I can send an ajax call and update the status to completely watched 100%
$("#video").bind("ended", function() {
if(j<1) {
/* Watched 100% Finished */
}
j=j+1; //Reset for duplicates
});
But when someone forwarded the video to 90% and started playing from there then also 100% ajax call will trigger so what is the logic should I use to update the status to not watched in this case.

How about manipulating the functions like this
var watchPoints = [];
$("#video").bind("timeupdate", function(){
var currentTime = this.currentTime;
var watchPoint = Math.floor((currentTime/this.duration) * 100);
if(watchPoints.indexOf(watchPoint) == -1){
watchPoints.push(Math.floor(watchPoint))
}
});
/* Assuming that this will be called regardless of whether the user watches till the end point */
$("#video").bind("ended", function() {
/* use the watchPoints array to do the analysis(ordered array)
Eg.1 [1,2,3,4,5....100] - length is 100
2.[90,91..100] - length is only 10 and the starting point is 90
3.[1,2,3,4,5,50,51,52,61,62,63,64,65,66,67,68,69,70,98,99,100] - length is 21 and the index of 66 is 13 which clearly tells the user has skipped most of the parts
*/
});

With the research and little hard work i got the solution like this:
my HTML is this:
<div id="videoData">
<video width="75%" style="max-width: 60em;" autoplay="" controls="" class="center-block" id="video">
<source type="video/mp4" src="http://amerytech.net/lc_production/uploads/course_videos/Time Speed & Distance/Time Speed & Distance.mp4" le="max-width: 60em;" sty="">
</source>
</video>
</div>
<p id="display">asdddddd</p>
my javascript is this:
$(document).ajaxStop(function() {
var video = document.querySelector('video');
if (video) {
video.addEventListener("loadedmetadata", function() {
totalTime = this.duration;
});
$("#video").bind("timeupdate", function() {
var currentTime = this.currentTime;
var totalPlayed = 0;
var played = video.played;
for (var i = 0; i < played.length; i++) {
totalPlayed += played.end(i) - played.start(i);
console.log(totalPlayed);
$("#display").html(totalPlayed);
}
});
} else {
alert("not coming");
}
});

Related

HTML5 audio on IOS: how can currentTime be less than initial value?

I have to play a short fragment of bigger audio. I use currentTime to set starting point in time, and timeupdate event to stop audio when required.
I noticed that on few early timeupdate events sometimes currentTime is less than its initial value, despite there is (obviously) no "rewind" actions.
Here is code example:
var start = 1;
var end = 1.3;
var audio = document.getElementById('audio');
audio.addEventListener('timeupdate', function () {
console.log(audio.currentTime);
if (audio.currentTime < start || audio.currentTime > end) {
audio.pause();
}
});
audio.currentTime = start;
audio.play();
For example, output of console log can be this:
1
0.85
0.85
1
1.02
...
Here's an example.
Tested on iPad with iOS 11.4.1. This problem appears only on very short time ranges ~0.3sec.
At first you have a wrong question because you want that your script works on iOS. And because of this your question in title is irrelevant. We have a lot of bugs on iOS and the iOS developers do not want to correct them. It is a bug. Write to support from iOS and ask there "How is it possible?".
At second you have two questions in your post because your script does not work on iOS like you it want.
I wrote for you the solution. Make sure you are not trying to call the audio before the audio element has metadata loaded (first mistake). Then you have the second mistake: instead of:
if(audio.currentTime < start || audio.currentTime > end) //your mistake
you have to write:
if(audio.currentTime >= end)
The solution (it works on iOS too)
var start = 1,
end = 1.3,
audio = document.getElementById('audio'),
button = document.getElementById('button'),
log = document.getElementById('log');
audio.addEventListener('timeupdate', function()
{
writeLog(audio.currentTime);
//your mistake: if(audio.currentTime < start || audio.currentTime > end)
if(audio.currentTime >= end)
{
audio.pause();
}
});
function writeLog(value)
{
var div = document.createElement('div');
div.innerHTML = value;
log.insertBefore(div, log.firstChild);
}
audio.addEventListener('loadedmetadata', function()
{
audio.pause();
button.removeAttribute('disabled');
});
button.addEventListener('click', function()
{
log.insertBefore(log.lastChild.cloneNode(!0), log.firstChild);
audio.currentTime = start;
audio.play();
});
#log
{
width:100%;
height:18em;
overflow-y:auto;
font:3em 'Courier New';
background:#069;
color:#7e0
}
#log div:last-child{display:none}
<!--
For this link from your example (on jsfiddle.net) is only a download is possible, but not using as source:
http://techslides.com/demos/samples/sample.m4a
-->
<audio id="audio" preload="auto">
<source src="http://techslides.com/demos/samples/sample.mp3" type="audio/mpeg"/>
<source src="http://techslides.com/demos/samples/sample.ogg" type="audio/ogg"/>
<source src="http://techslides.com/demos/samples/sample.aac" type="audio/aac"/>
</audio>
<button id="button" disabled style="width:9em;height:3em;font-size:3em">Play</button>
<br><br>
<div id="log"><div><hr></div></div>
The snippet on SO does not work because it is in sandbox.
See this working example on codepen.io.

addEventListener 'playing' only fires once.

I have the following script which gets all video elements on a given page and then applies a playing event to them:
var video = document.getElementsByTagName("video");
for(var i = 0; i < video.length; i++){
(function(vid) {
vid.addEventListener('playing', function(){
var percentComplete = Math.round((vid.currentTime / vid.duration) * 100);
console.log(percentComplete);
});
})
(video[i]);
}
Now when I run the page and click on video 1 for example I see the percentComplete being logged to the console log, however when video 1 finishes and I click video 2 nothing is written to the console, it seems this addEventListener is only applied to the first video that is clicked, can someone explain why and how I can resolve this so it fires every time a video is played?
Try removing the outer closure and using event.target within your listener.
var video = document.getElementsByTagName("video");
for (var i = 0; i < video.length; i++) {
video[i].addEventListener('playing', function (event) {
var vid = event.target
var progress = Math.round((vid.currentTime / vid.duration) * 100)
console.log(progress)
})
}
For anyone interested, here's the full list of media events.

loop a html5 video in specific timline with js

i had a html5 video box with only one video inside. in this video their is a animated figure with different moves. as an example: second 1-5 the figure walks inside, second 5-7 the figure say "hello", ... i would like to control these animations with js and i would like to loop the main animation.
this is the html5 videoplayer:
<video id="vidplayer">
<source src="animation.mp4" type="video/mp4"</source>
</video>
i have tested following code to loop the video between the second 7-9 and it doesnt work:
var vid = $("#vidplayer").get(0);
vid.ontimeupdate = function(e) {
if(this.currentTime = 9) {
vid.currentTime = 7;
}
};
it works only with
(this.currentTime >= 9)
but with this ">=" i cant use animations above 9 seconds (like 21-29 seconds).
can you please help me? Thx!
you will need to check for both the start/stop of the fragments you want to loop within in order to constrain the test.
In the example below it will loop from the 15s mark (or greater) back to 10s; from the 9s mark back to 7; from the 5s mark back to 1.
For a production version I'd probably create an array of the jump points and use that to avoid having to type the times as an upper/lower, but this should give you a framework to go on from:
<video preload="auto" controls id="vidplayer">
<source src="BigBuck.m4v" type='video/mp4;'"></source></video>
<script>
var vid = document.getElementById("vidplayer")
vid.addEventListener('timeupdate', timeupdate, false);
function timeupdate() {
if (vid.currentTime >= 15) {
vid.currentTime = 10;
} else if (vid.currentTime >= 9 && vid.currentTime < 10) {
vid.currentTime = 7;
} else if (vid.currentTime >= 5 && vid.currentTime < 7) {
vid.currentTime = 1;
}
}
</script>
I had the same problem and wrote a plugin to solve it. See https://github.com/phhu/videojs-abloop . This allows javascript commands to be used to control looping of section of video. The example shows how you might control switching different sections of video using callbacks or otherwise.

jQuery: Incorrect use of variables on video function

Tying to play videos but The use of my variables are not working.
First video play only once, when stops second video starts.
Second video plays and loops.
Video should play smoothly with no gaps and no jumps.
My Demo: http://jsfiddle.net/654geqvp/1/
var start = [
"http://praegnanz.de/html5video/player/video_SD.webm",
"http://praegnanz.de/html5video/player/video_SD.webm",
"http://praegnanz.de/html5video/player/video_SD.mp4"];
var loop = [
"http://broken-links.com/tests/media/BigBuck.webm",
"http://broken-links.com/tests/media/BigBuck.theora.ogv",
"http://broken-links.com/tests/media/BigBuck.m4v"];
var curSrc = 0;
$(function() {
$('#start').attr(start, start[curSrc % start.length]);
curSrc++;
var video = $('#start').get(0);
$('#start').on('loadedmetadata', function() {
video.currentTime = 0.01;
video.play();
}).on('ended', function() {
//console.log('ended');
video.loop = loop[curSrc % loop.length];
video.load();
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<video id="start" style="width:100%;"></video>
I figured it out, I changed some variable names around. You need to set the loop attribute on the video to true. You can remove the controls attribute it you wish. I converted the original to a jQuery plugin.
To get rid of the black flash when transitioning videos, you can set the poster attribute of the video element to be the first frame of the second video.
$.fn.videoLoop = function(options) {
var video = $(this),
videoEl = video.get(0),
selVideoIdx = 0;
options = options || {};
var playlist = options.playlist || [],
// Use a white background by default if a poster is not provided. This
// should prevent the transition from showing a black screen. If possible,
// use the first frame of the looping video or a solid color to match
// the backdrop of the video.
poster = options.poster || "http://placehold.it/1024x768/FFFFFF/FFFFFF";
if (playlist.length > 1) {
video.attr('src', playlist[selVideoIdx % playlist.length]);
video.attr('poster', poster);
video.attr('autoload', true);
selVideoIdx++;
video.on('loadedmetadata', function() {
videoEl.currentTime = 0.5;
videoEl.play();
}).bind('ended', function() {
videoEl.src = playlist[selVideoIdx % playlist.length];
videoEl.loop = true;
videoEl.load();
});
}
};
$(function() {
$('#start').videoLoop({
'playlist': [
'../video-start/Homepage_video_ref_v01.mp4',
'../video-loop/7_Sec_Loop_v01.mp4'
],
'poster': "http://placehold.it/1024x768/6DBBD2/6DBBD2"
});
});
video {
width: 100%;
background: #53abc5;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<video id="start" controls="controls"></video>

Using JQuery to create animation frames from PSD layers

I have a PSD file with a bunch of layers that are frames for an animation. How can I create an animation from this using JQuery/JavaScript?
Will I have to save each layer as a separate image, is there a way to have the one image with multiple layers animated? To clarify, I don't want the actual image to move, I just want different layers to be displayed as if they were frames of an animation. What's the standard way this is done with JavaScript?
Thanks!
Here is a fiddle that demonstrates the javascript timer + individual images approach.
Fiddle: http://jsfiddle.net/ZVFu8/2/
The basic idea is to create an array with the names of your images.
var img_name_arr = [];
var img_name_root = "anim-";
var img_name_ext = ".gif";
var num_images = 12;
// init arr of img names assuming frames are named [root]+i+[extension]
for (i = 0; i<=num_images; i++) {
img_name_arr.push(img_name_root + i + img_name_ext);
}
For the animation, use setInterval(). In javascript, an interval executes periodically. You specify the code to execute and the interval at which the code should be run (in milliseconds).
Every time your interval is called, you can display a new image by setting the "src" attribute of the image tag to the next index in the image_name array.
// Create an interval, and save a handle to the interval so it can be stopped later
anim_interval = setInterval(function() {
$("#player").attr("src", s + img_name_arr[(anim_frame++ % num_images)+1] );
}, frame_interval);
Depending on how long your animation is and how large each image file is, it might be necessary to optimize this by pre-loading these images. Before the animation starts, you could create an img tag for each image and hide it. Then, instead of altering the "src" attribute to change the image, you would actually hide the current image and un-hide the next image in the previous image's place.
Here is the full code if you wish to run this locally:
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<a id="anim_control" href="">Start</a>
<img id="player" src="" />
<script>
var s = "http://" + atob("YmVucmlkb3V0LmNvbQ==") + "/";
var img_name_arr = [];
var img_name_root = "anim-";
var img_name_ext = ".gif";
var num_images = 12;
var framerate = 1; // Desired frames per second
var frame_interval = 1000/framerate;
$(function(){
// Document is ready
// init arr of img names
for (i = 0; i <= num_images; i++) {
img_name_arr.push(img_name_root + i + img_name_ext);
}
var anim_interval = null;
var playing = false;
var anim_frame = 0;
// Define an interval that will execute every [frame_interval] milliseconds
$("#anim_control").on("click", function(e) {
e.preventDefault();
if (playing == true) {
playing = false;
$(this).html("Start");
clearInterval(anim_interval);
} else {
playing = true;
$(this).html("Stop");
anim_interval = setInterval(function() {
//console.log(s + img_name_arr[(anim_frame++ % num_images)+1]);
$("#player").attr("src", s + img_name_arr[(anim_frame++ % num_images)+1] );
}, frame_interval);
}
});
});
</script>
<style>
#player {
width: 320px;
height: 240px;
border: 1px solid #000;
}
</style>

Categories