Best way to capture paused video frame to canvas - javascript

I know how to copy on frame by frame basis from a playing HTML5 video to a canvas using 2D context.
But I want to work with a paused video, change dinamically its currentTime and copy current frame of video to canvas.
My guess is some process is not called yet when video position is set with currentTime property, although the video itself does update the image it shows (but not to the canvas).
I've found that it's posible to overcome this by setting a setTimeout to do the canvas ´drawImage´ in the next step.
You can see here a jsfiddle that proves the point.
As you can see in the fiddle you can play the video, and canvas updates, but if you pause the video, mouse scroll moves currentTime of video. There, a ´seTimeout´ is needed to update the canvas, if I call the drawImage method directly, canvas doesn't update.
In short, my question is:
Is there a better way to do this? Is it posible to do this without setTimeout and inside de loop itself? Pros & Cons?
Thank you very much for reading through here!

Every time you change the currentTime of your VideoElement, a seeked Event will trigger when the video actually changed its position.
var vid = document.getElementById("v");
var canvas = document.getElementById("c");
var context = canvas.getContext('2d');
var targetFrame = document.getElementById('t');
var cw = canvas.width = 200;
var ch = canvas.height = Math.round(cw / 1.7777);
var targetOffset = 0;
window.addEventListener('wheel', function(e) {
e.preventDefault();
targetOffset = targetOffset + (e.deltaY / 1000);
targetFrame.value = targetOffset;
seek(); // for demo purpose, we only listen to wheel
return false;
});
// that's all is needed
vid.addEventListener('seeked', function() {
context.drawImage(vid, 0, 0, cw, ch);
});
// for demo
// removed the rendering loop
// now it only changes the video's currentTime property
function seek() {
targetOffset = targetOffset * 0.9;
targetFrame.value = Math.round(targetOffset * 100) / 100;
var vct = vid.currentTime - targetOffset;
if (vct < 0) {
vct = vid.duration + vct;
} else if (vct > vid.duration) {
vct = vct - vid.duration;
}
vid.currentTime = vct;
}
.column {
float: left;
width: 50%;
}
.row:after {
content: "";
display: table;
clear: both;
}
#c {
border: 1px solid black;
}
<h3>
scroll up is forward
</h3>
<div class="row">
<div class="column">
<div>
Video element:
</div>
<video controls height="120" id="v" tabindex="-1" autobuffer="auto" preload="auto">
<source type="video/webm" src="https://www.html5rocks.com/tutorials/video/basics/Chrome_ImF.webm"/>
</video>
</div>
<div class="column">
<div>
Canvas element:
</div>
<canvas id="c"></canvas>
<div>
Momentum: <input type=text id="t">
</div>
</div>
</div>

Related

downloading multiple html5 generated images as a zip file

i am building a video hosting site. my video player generates video player screenshots by the onclick() function. i am also not sure if these images are deleted or stored after generating.
i have tried surfing around here trying to find a definitive assistance as i lack in javascript knowledge and it's so frustrating. please help me. ask me if you need any more info. :)
here is my html:
<body>
<div id="videoPanel">
<div id="instructions">
<video id="my_video_1" class="video-js vjs-default-skin" width="720px" height="400px" controls preload="none" poster='' autoplay data-setup='{ "aspectRatio":"640:500", "playbackRates": [1, 1.5, 2] }'>
<source src="/Custom-Video-Player/Masamune kun no Revenge - 07.mp4" type='video/mp4' />
</video>
</div>
<button id="clicker" onclick="shoot()">Capture</button><br />
<button id="download" onclick=""> download</button> <br/>
<div id="output" style="display: inline-block; top: 4px; position: relative; border: dotted 1px #ccc; padding: 2px;"></div>
</div>
</body>
this is the javascript for the screenshot generation:
var videoId = 'my_video_1';
var scaleFactor = 0.25;
var snapshots = [];
var w = 720 * scaleFactor;
var h = 400 * scaleFactor;
function capture(video, scaleFactor) {
if (scaleFactor == null) {
scaleFactor = 1;
}
var canvas = document.createElement('canvas');
canvas.width = w;
canvas.height = h;
var ctx = canvas.getContext('2d');
ctx.drawImage(video, 0, 0, w, h);
return canvas;
}
function shoot() {
var video = document.getElementById(videoId);
var output = document.getElementById('output');
var canvas = capture(video, scaleFactor);
canvas.onclick = function () {
window.open(this.toDataURL());
};
snapshots.unshift(canvas);
output.innerHTML = '';
for (var i = 0; i < 4; i++) {
output.appendChild(snapshots[i]);
}
}
theres also a download button that i want to be able to function as such:
it will number all images in accordance to their generation in regard to the 'capture' button, put them all in a zip file and download when download is pressed.

Detecting type of mouse scroll wheel (Smooth vs Notched) with javascript

I've been working in a web project that uses mouse scroll wheel for different actions over a video. At some point I have to establish a coefficient for the relation between the deltaY and the number of frames that deltaY should roll. So different types of mouses return very different deltaY, specially smooth scroll ones.
In the fiddle I provide bellow this is done in:
targetOffset = targetOffset + (e.deltaY/1000); // 16000 aprox for smooth scroll mice
And 1000 is the coefficient that works well for a Notched Scroll Wheel common mouse. But if I use that coefficient with a Smooth Scroll Touch "wheel", like those of mac computers (that don't have a wheel really) that coefficient is "just too much", like 16 times "too much".
Is there something that could be done to detect this or to callibrate the coefficient in some way?
var FF = !(window.mozInnerScreenX == null); // is firefox?
var vid = document.getElementById("v");
var canvas = document.getElementById("c");
var context = canvas.getContext('2d');
var targetFrame = document.getElementById('t');
var cw = 200;
var ch = Math.round(cw/1.7777);
canvas.width = cw;
canvas.height = ch;
var directionScroll = 0;
var targetOffset = 0;
var coefficient = 1000;
var modes = ['pixels', 'lines', 'page'];
vid.pause();
vid.addEventListener('seeked', function() {
context.drawImage(vid, 0, 0, cw, ch);
});
window.addEventListener('wheel', function(e) {
e.preventDefault();
// Normally scrolling this should be a substraction
// not a sum but "I like it like this!"
// Changed this with help of #Kaiido 's answer as partially solves the discrepancies between Firefox and Chrome
// alert(modes[e.deltaMode]);
if (modes[e.deltaMode]=='pixels') coefficient = 1000;
else if (modes[e.deltaMode]=='lines') coefficient = 30; // This should correspond to line-height??
else return false; // Disable page scrolling, modes[e.deltaMode]=='page'
targetOffset = targetOffset + (e.deltaY/coefficient); // e.deltaY is the thing!!
if (e.deltaY < 0) directionScroll = 1;
if (e.deltaY > 0) directionScroll = -1;
targetFrame.value = targetOffset;
return false;
});
var renderLoop = function(){
requestAnimationFrame( function(){
context.drawImage(vid,0,0,cw,ch);
if (vid.paused || vid.ended) {
targetOffset = targetOffset*0.9;
targetFrame.value=Math.round(targetOffset*100)/100;
var vct = vid.currentTime-targetOffset;
if (vct<0) {
vct = vid.duration + vct;
} else if (vct>vid.duration) {
vct = vct - vid.duration;
}
vid.currentTime = vct;
}
renderLoop();
});
};
renderLoop();
.column {
float: left;
width: 50%;
}
/* Clear floats after the columns */
.row:after {
content: "";
display: table;
clear: both;
}
#c {
border:1px solid black;
}
<h3>
scroll up is forward
</h3>
<div class="row">
<div class="column">
<div>
Video element:
</div>
<video controls height="120" id="v" tabindex="-1" autobuffer="auto" preload="auto">
<source type="video/webm" src="https://www.html5rocks.com/tutorials/video/basics/Chrome_ImF.webm"></source>
</video>
</div>
<div class="column">
<div>
Canvas element:
</div>
<canvas id="c"></canvas>
<div>
Momentum: <input type=text id="t">
</div>
</div>
</div>
Any help appreciated.
Edit 1:
I've updated the code so that a simple condition is applied to the coefficient, but that does not quite solve the issue as many variants are posible due to browser/plattform/mouse. Some way of callibrate the mouse could work?
Edit 2:
#Kaiido 's answer turned to resolve Firefox and Chrome differences. Firefox returns lines as deltaMode while Chrome returns pixels. I've edited the snippet to consider this.
But the problem still stands with the 'smooth scroll' mouse. To puzzle me even more, that mouse needs a coefficient opposite to the one of lines, it needs a coefficient larger instead of smaller.
See UPDATE at the end!
My original answer:
I don't have a mac nor a 'smooth' mouse, but I've tested your snippet both on Chrome and Firefox both on Windows and Linux boxes.
Works great on Chrome both on Windows and Linux but...
looks like the coefficient isn't the right one for Firefox... it works better (not as good as in Chrome) with 200.
One more thing:
Have you tested the mac fancy mouse on windows and vice-versa? Could it be a mac related problem?
UPDATE:
Other answers are great but I got puzzled by your question and learned a lot with the code and with what other answers pointed out, but something kept in my mind like a bug.
Searching for this topic I found this question very informative. It included a possible mouse scroll calibration script in this answer and a function getScrollLineHeight for Detecting the line-height used by DOM_DELTA_LINE triggered scroll events.
I've copied this function in the snippet for completeness, but at the end it's not needed for what I've thought. I've commented out the line that calls getScrollLineHeight because it does not work in this site for security reasons, but works in this fiddle.
My confusion was to think of scrolling as I normally do, in terms of pixels on a page. But your code really doesn't care about that. I mean, does not care about mouse scroll wheel event.deltaY magnitude. Only if it's positive or negative and consider that one step forward or backwards in a video timeline.
So this does not resolve the problem of "touch sensitive scroll mice", but it does resolve easily Firefox/Chrome and any Pixel/Line/Page deltaMode also. Now it runs smoothly both in Chrome and Firefox. I can't test on other browser because of WEBM video format, and I haven't been able to create a video in any format that works (look at my P.D. at the end).
So, every call is just one step: -1 or 1. Though it seems that only Firefox returns anything than "pixels" for deltaMode. I used this fiddle to test... Now you can focus on that smooth scrolling mouse and see how fast it sends every call, that is what really matters in this particular case (note that many macs have smooth scrolling software or inverted scrolling).
I've commented every line of your code and my modifications for my self but may be useful for others.
// detect if browser firefox as it appears to be the only
// browser that return deltaModes different than DOM_DELTA_PIXEL
// Ref: https://stackoverflow.com/a/37474225/4146962
var FF = !(window.mozInnerScreenX == null);
// Function grabbed from the reference above
// It tries to read current line-height of document (for 'lines' deltaMode)
function getScrollLineHeight() {
var r;
var iframe = document.createElement('iframe');
iframe.src = '#';
document.body.appendChild(iframe);
var iwin = iframe.contentWindow;
var idoc = iwin.document;
idoc.open();
idoc.write('<!DOCTYPE html><html><head></head><body><span>a</span></body></html>');
idoc.close();
var span = idoc.body.firstElementChild;
r = span.offsetHeight;
document.body.removeChild(iframe);
return r;
}
// html5 elements
var vid = document.getElementById("v"); // HTML5 video element
var canvas = document.getElementById("c"); // HTML5 canvas element
var context = canvas.getContext('2d'); // Canvas context
var momentum = document.getElementById('m'); // Current momentum display
var delta = document.getElementById('d'); // Current deltaMode display
var lineheight = document.getElementById('l'); // Current deltaMode display
// global variables
var ch = 120; // canvas with (could be window.innerHeight)
var cw = Math.round(ch * (16 / 9)); // 16/9 proportion width
var targetOffset = 0; // Video offset target position when scrolling
// deltaY to FPS coefficients (for fine tuning)
// Possible mouse scroll wheel 'event.deltaMode'
// modes are: 0:'pixels', 1:'lines', 2:'page'
var pc = 1000; // 'pixels' deltaY coefficient
var lh = "disabled"; //getScrollLineHeight(); // get line-height of deltaMode 'lines'
lineheight.value = lh; // display current document line height
coefficient = 30;
var deltaModes = ['pixels', 'lines', 'page']; // For deltaMode display
// Sets canvas dimensions
canvas.width = cw;
canvas.height = ch;
// Pauses video (this also starts to load the video)
vid.pause();
// Listens video changes time position
vid.addEventListener('seeked', function() {
// Updates canvas with current video frame
context.drawImage(vid, 0, 0, cw, ch);
});
// Listens mouse scroll wheel
window.addEventListener('wheel', function(e) {
// Don't do what scroll wheel normally does
e.preventDefault();
// You don't need an amount, just positive or negative value: -1, 1
var deltabs = 1;
if (e.deltaY<0) deltabs = -1;
// Disable page scrolling, modes[e.deltaMode]=='page'
if (e.deltaMode>1) return false;
delta.value = deltaModes[e.deltaMode];
// Normally scrolling this should be a subtraction
// not a sum but "I like it like this!"
// targetOffset = targetOffset + (e.deltaY / coefficient); // e.deltaY is the thing!!
targetOffset = targetOffset + (deltabs/coefficient);
// Shows current momentum
momentum.value = targetOffset;
return false;
});
// Updates canvas on a loop (both for play or pause state)
var renderLoop = function() {
requestAnimationFrame(function() {
// This parts updates canvas when video is paused
// Needs 'seeked' listener above
if (vid.paused || vid.ended) {
// Reduce target offset gradually
targetOffset = targetOffset * 0.9;
// Show current momentum
momentum.value = Math.round(targetOffset * 100) / 100;
// this part joins start and end of video when scrolling
// forward & backwards
var vct = vid.currentTime - targetOffset;
if (vct < 0) {
vct = vid.duration + vct;
} else if (vct > vid.duration) {
vct = vct - vid.duration;
}
vid.currentTime = vct;
// This parts updates canvas when video is playing
} else {
// update canvas with current video frame
context.drawImage(vid, 0, 0, cw, ch);
}
renderLoop(); // Recursive call to loop
});
};
renderLoop(); // Initial call to loop
input {
width: 50px;
}
.column {
float: left;
width: 50%;
}
/* Clear floats after the columns */
.row:after {
content: "";
display: table;
clear: both;
}
<h3>
mouse scroll video
</h3>
<div class="row">
<div class="column">
<div>
Video element:
</div>
<video controls height="120" id="v" tabindex="-1" autobuffer="auto" preload="auto">
<source type="video/webm" src="https://www.html5rocks.com/tutorials/video/basics/Chrome_ImF.webm"/>
</video>
</div>
<div class="column">
<div>
Canvas element:
</div>
<canvas id="c"></canvas>
<div>
Momentum: <input type=text id="m">
</div>
<div>
deltaMode: <input type=text id="d">
</div>
<div>
lineHeight: <input type=text id="l">
</div>
</div>
</div>
P.D. I have a question (too specific for explaining elsewhere)... I've tested with my own videos and got very bad results... why is that? Something to do with specific video encoding settings? Do you know which encoding cmd would be needed for FFMPEG conversion to WEBM format like the video used in your example?
That's a wild guess, because I don't have such a Notched mouse to test with, but this 16 times factor really sounds like your delta values are not set on the same mode.
Indeed, the wheel event has 3 possible modes:
0 => pixels (probably smooth scroll / Apple mice)
1 => lines (probably the Notched Mice)
2 => pages (keyboard ?)
So you may have to check your wheel event's deltaMode property to react accordingly.
onwheel = e => {
var modes = ['pixels', 'lines', 'page'];
console.log('scrolled by %s %s', e.deltaY, modes[e.deltaMode]);
}
<h1> scroll </h1>
Why not just detect if the delta is greater than some threshold, and if so, divide by 16. I would think something like:
if (Math.abs(e.deltaY) > 400) slowdown = 16;
else if (Math.abs(e.deltaY) < 15) slowdown = 1;
targetOffset = targetOffset + (e.deltaY/1000/slowdown);
would do the trick.
var vid = document.getElementById("v");
var canvas = document.getElementById("c");
var context = canvas.getContext('2d');
var targetFrame = document.getElementById('t');
var cw = 200;
var ch = Math.round(cw/1.7777);
canvas.width = cw;
canvas.height = ch;
var directionScroll = 0;
var targetOffset = 0;
var maxDelta = 0;
// vid.pause();
vid.addEventListener('seeked', function() {
context.drawImage(vid, 0, 0, cw, ch);
});
var slowdown = 1;
window.addEventListener('wheel', function(e) {
e.preventDefault();
// Normally scrolling this should be a substraction
// not a sum but "I like it like this!"
if (Math.abs(e.deltaY) > 400) slowdown = 16;
else if (Math.abs(e.deltaY) < 15) slowdown = 1;
targetOffset = targetOffset + (e.deltaY/1000/slowdown); // e.deltaY is the thing!!
if (e.deltaY < 0) directionScroll = 1;
if (e.deltaY > 0) directionScroll = -1;
targetFrame.value = targetOffset;
return false;
});
var renderLoop = function(){
requestAnimationFrame( function(){
context.drawImage(vid,0,0,cw,ch);
if (vid.paused || vid.ended) {
// setTimeout(function(){
targetOffset = targetOffset*0.9;
targetFrame.value=Math.round(targetOffset*100)/100;
var vct = vid.currentTime-targetOffset;
if (vct<0) {
vct = vid.duration + vct;
} else if (vct>vid.duration) {
vct = vct - vid.duration;
}
vid.currentTime = vct;
// }, 0);
}
renderLoop();
});
};
renderLoop();
.column {
float: left;
width: 50%;
}
/* Clear floats after the columns */
.row:after {
content: "";
display: table;
clear: both;
}
#c {
border:1px solid black;
}
<h3>
scroll up is forward
</h3>
<div class="row">
<div class="column">
<div>
Video element:
</div>
<video controls height="120" id="v" tabindex="-1" autobuffer="auto" preload="auto">
<source type="video/webm" src="https://www.html5rocks.com/tutorials/video/basics/Chrome_ImF.webm"></source>
</video>
</div>
<div class="column">
<div>
Canvas element:
</div>
<canvas id="c"></canvas>
<div>
Momentum: <input type=text id="t">
</div>
</div>
</div>
I tried it in Firefox and is not comparable with the Chrome "performance", so you can try adding this.
var vid = document.getElementById("v");
var canvas = document.getElementById("c");
var context = canvas.getContext('2d');
var targetFrame = document.getElementById('t');
var cw = 200;
var ch = Math.round(cw/1.7777);
canvas.width = cw;
canvas.height = ch;
var directionScroll = 0;
var targetOffset = 0;
// vid.pause();
vid.addEventListener('seeked', function() {
context.drawImage(vid, 0, 0, cw, ch);
});
function normalizeDelta(wheelEvent) {
var delta = 0;
var wheelDelta = wheelEvent.wheelDelta;
var deltaY = wheelEvent.deltaY;
// CHROME WIN/MAC | SAFARI 7 MAC | OPERA WIN/MAC | EDGE
if (wheelDelta) {
delta = -wheelDelta / 120;
}
// FIREFOX WIN / MAC | IE
if(deltaY) {
deltaY > 0 ? delta = 1 : delta = -1;
}
return delta;
}
window.addEventListener('wheel', function(e) {
e.preventDefault();
// Normally scrolling this should be a substraction
// not a sum but "I like it like this!"
targetOffset = targetOffset + normalizeDelta(e); // e.deltaY is the thing!!
if (e.deltaY < 0) directionScroll = 1;
if (e.deltaY > 0) directionScroll = -1;
targetFrame.value = targetOffset;
return false;
});
var renderLoop = function(){
requestAnimationFrame( function(){
context.drawImage(vid,0,0,cw,ch);
if (vid.paused || vid.ended) {
// setTimeout(function(){
targetOffset = targetOffset*0.9;
targetFrame.value=Math.round(targetOffset*100)/100;
var vct = vid.currentTime-targetOffset;
if (vct<0) {
vct = vid.duration + vct;
} else if (vct>vid.duration) {
vct = vct - vid.duration;
}
vid.currentTime = vct;
// }, 0);
}
renderLoop();
});
};
renderLoop();
.column {
float: left;
width: 50%;
}
/* Clear floats after the columns */
.row:after {
content: "";
display: table;
clear: both;
}
#c {
border:1px solid black;
}
<h3>
scroll up is forward
</h3>
<div class="row">
<div class="column">
<div>
Video element:
</div>
<video controls height="120" id="v" tabindex="-1" autobuffer="auto" preload="auto">
<source type="video/webm" src="https://www.html5rocks.com/tutorials/video/basics/Chrome_ImF.webm"></source>
</video>
</div>
<div class="column">
<div>
Canvas element:
</div>
<canvas id="c"></canvas>
<div>
Momentum: <input type=text id="t">
</div>
</div>
</div>
Reference: https://stackoverflow.com/a/49095733/9648076
In case of deleted question, the answer purposed is this:
private normalizeDelta(wheelEvent: WheelEvent):number {
var delta = 0;
var wheelDelta = wheelEvent.wheelDelta;
var deltaY = wheelEvent.deltaY;
// CHROME WIN/MAC | SAFARI 7 MAC | OPERA WIN/MAC | EDGE
if (wheelDelta) {
delta = -wheelDelta / 120;
}
// FIREFOX WIN / MAC | IE
if(deltaY) {
deltaY > 0 ? delta = 1 : delta = -1;
}
return delta;
}

drawImage in canvas from a video frame change the hue

I wrote a simple script that take a frame from a video and draw it to a canvas. My problem is that the colors are changing between the video and the drawn image.
I put here the result next to the original to make it easier to see. The original one is on the left. It's seems to be way more visible on chrome browser btw. All the test I made where on OSX.
Here a snippet, canvas on left, video on right:
// Get our mask image
var canvas = document.querySelector(".canvas");
var video = document.querySelector(".video");
var ctx = canvas.getContext('2d');
function drawMaskedVideo() {
ctx.drawImage(video, 0, 0, video.videoWidth/2, video.videoHeight, 0,0, video.videoWidth/2, video.videoHeight);
}
requestAnimationFrame(function loop() {
drawMaskedVideo();
requestAnimationFrame(loop.bind(this));
});
html, body {
margin: 0 auto;
}
.video, .canvas {
width: 100%;
}
.canvas {
position: absolute;
top: 0;
left: 0;
}
<video class="video" autoplay="autoplay" muted="muted" preload="auto" loop="loop">
<source src="http://mazwai.com/system/posts/videos/000/000/214/original/finn-karstens_winter-wonderland-kiel.mp4" type="video/mp4">
</video>
<canvas class='canvas' width='1280' height='720'></canvas>
I'd like to know why this thing happen, and if it possible to get rid of it in a cross browser way ?
Here the simple script I wrote:
let video = document.querySelector('#my-video') // .mp4 file used
let w = video.videoWidth;
let h = video.videoHeight;
let canvas = document.createElement('canvas');
canvas.width = w;
canvas.height = h;
let ctx = canvas.getContext('2d');
ctx.drawImage(video, 0, 0, w, h)
document.querySelector('.canvas-container').appendChild(canvas);
The solution might be as simple as setting a css filter to the video element:
.video {
-webkit-filter: contrast(100%);
}
I can't reason about this since it was discovered accident (playing with your demo and reading related answers), so I leave the technical explanation for someone else and leave you with some magic for now.
Any sufficiently advanced technology is indistinguishable from magic.
— Arthur C. Clarke
// Get our mask image
var canvas = document.querySelector(".canvas");
var video = document.querySelector(".video");
var ctx = canvas.getContext('2d');
function drawMaskedVideo() {
ctx.drawImage(video, 0, 0, video.videoWidth/2, video.videoHeight, 0,0, video.videoWidth/2, video.videoHeight);
}
requestAnimationFrame(function loop() {
drawMaskedVideo();
requestAnimationFrame(loop.bind(this));
});
html, body {
margin: 0 auto;
}
.video, .canvas {
width: 100%;
}
.video {
-webkit-filter: contrast(100%);
}
.canvas {
position: absolute;
top: 0;
left: 0;
}
<video class="video" autoplay="autoplay" muted="muted" preload="auto" loop="loop">
<source src="http://mazwai.com/system/posts/videos/000/000/214/original/finn-karstens_winter-wonderland-kiel.mp4" type="video/mp4">
</video>
<canvas class='canvas' width='1280' height='720'></canvas>
Note:
Running this on a Macbook Pro (2,3 GHz Intel Core i5) I could see no difference performance wise. Tracked CPU during the video playback and both demos idle at around 28%.

html5 video: play/pause custom button issue

I am using an HTML5 Video on my website, with certain other codes that basically makes usability more customized.
The video is intended to play when in view and pause when not in view. Additionally it also has a play and pause button that comes into view when the mouse hovers on the video.
At the end of the video it turns into an image because by default the html5 video would just turn to blank.
The problem is that the image turns up in the end, but the play/pause continue to appear on hover and function as play pause but only audio. You cannot see the video.
I originally wanted it to just show the picture. But would prefer to have the play pause turn into a restart button if the video ends.
I tried looking for something that would fit my existing setup, but I am not sure how to make it happen and which of these codes would I play with.
Here is a link for the site
http://minhasdistillery.com/blumersmoonshine/
<section id="feature">
<div id="trail">
<div id="videocontrol">
<a id="play-pause" class="play"><img src="images/pause.png"/></a>
</div>
<video id="video_background" preload="auto" volume="5"><!--or turn on loop="loop"-->
<source src="videos/video.webm" type="video/webm">
<source src="videos/video.mp4" type="video/mp4">
<source src="videos/video.ogv" type="video/ogg ogv">
</video>
<img id="image_background" src="images/blumer.jpg" width="100%" height="100%" />
</div><!--trail-->
</section><!--feature-->
Javascript that brings up play/pause button
<script>
window.onload = function() {
var video = document.getElementById("video_background");
var playButton = document.getElementById("play-pause");
playButton.addEventListener("click", function() {
if (video.paused == true) {
video.play();
playButton.innerHTML = "<img src='images/pause.png'/>";
} else {
video.pause();
playButton.innerHTML = "<img src='images/play.png'/>";
}
});
}
</script>
The code sets the video to play on when visible and pause otherwise
<script>
//play when video is visible
var videos = document.getElementsByTagName("video"), fraction = 0.8;
function checkScroll() {
for(var i = 0; i < videos.length; i++) {
var video = videos[i];
var x = 0,
y = 0,
w = video.offsetWidth,
h = video.offsetHeight,
r, //right
b, //bottom
visibleX, visibleY, visible,
parent;
parent = video;
while (parent && parent !== document.body) {
x += parent.offsetLeft;
y += parent.offsetTop;
parent = parent.offsetParent;
}
r = x + w;
b = y + h;
visibleX = Math.max(0, Math.min(w, window.pageXOffset + window.innerWidth - x, r - window.pageXOffset));
visibleY = Math.max(0, Math.min(h, window.pageYOffset + window.innerHeight - y, b - window.pageYOffset));
visible = visibleX * visibleY / (w * h);
if (visible > fraction) {
video.play();
} else {
video.pause();
}
}
}
window.addEventListener('scroll', checkScroll, false);
window.addEventListener('resize', checkScroll, false);
//check at least once so you don't have to wait for scrolling for the video to start
window.addEventListener('load', checkScroll, false);
checkScroll();
</script>
This one adds the photo in the end.
<script>
var video = document.getElementById('video_background');
var wrapper = document.getElementById('wrapper');
var image = document.getElementById('image_background');
video.addEventListener('ended', function() {
video.style.display = 'none';
image.style.display = 'inline';
}, false);
</script>
A JSBin of the same issue is here
JSBin For Issue
as you will see at the end of the video it will continue to show pause and play and will only play audio.
How do I get it to read that the video ended and switch the button to "replay"
Initially video display style is block and image display style is none.
Video ended event handler sets video display to none and image display to inline.
You can check video display style in button click event handler and toggle it:
playButton.addEventListener(
'click',
function(event) {
if (video.style.display === 'none') {
image.style.display = 'none';
video.style.display = 'block';
}
...
},
false
);
As an alternative add boolean flag which is intially set to false, on video ended event set it to true:
var needReplay = false;
video.addEventListener(
'ended',
function() {
...
needReplay = true;
},
false
);
playButton.addEventListener(
'click',
function(event) {
if (needReplay) {
image.style.display = 'none';
video.style.display = 'block';
needReplay = false;
}
...
},
false
);
Demo

Webcam Capture to <img>

Using javascript or Jquery I want to get the current image from the webcam feed on my page and put it in an tag.
I have a bit of script which generates tags dynamically with unique Id's so after generating one all I want to do is capture an image from the webcam at that exact moment and save the image in the generated tag. After taking the image I just want the webcam to carry until the next time it takes a picture.
I already have a webcam feed running using a library which does face tracking, however I want to extend this with this feature to create a gallery of captured images on the page.
The library I am using is ClmTracker
Creator of the library suggested calling getImageData(x,y,w,h) on the video element and I have tried this. also tried to implement tutorials I have seen on other websites but to no avail. It would seem the answer would need to be specific to my code. I have tried to use canvas instead of tags to put the image in to, but I kept getting errors due to them being created dynamically in the code.
var vid = document.getElementById('videoel');
var overlay = document.getElementById('overlay');
var overlayCC = overlay.getContext('2d');
/********** check and set up video/webcam **********/
function enablestart() {
var startbutton = document.getElementById('startbutton');
startbutton.value = "start";
startbutton.disabled = null;
}
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
window.URL = window.URL || window.webkitURL || window.msURL || window.mozURL;
// check for camerasupport
if (navigator.getUserMedia) {
// set up stream
var videoSelector = {
video: true
};
if (window.navigator.appVersion.match(/Chrome\/(.*?) /)) {
var chromeVersion = parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10);
if (chromeVersion < 20) {
videoSelector = "video";
}
};
navigator.getUserMedia(videoSelector, function (stream) {
if (vid.mozCaptureStream) {
vid.mozSrcObject = stream;
} else {
vid.src = (window.URL && window.URL.createObjectURL(stream)) || stream;
}
vid.play();
}, function () {
//insertAltVideo(vid);
alert("There was some problem trying to fetch video from your webcam. If you have a webcam, please make sure to accept when the browser asks for access to your webcam.");
});
} else {
//insertAltVideo(vid);
alert("This demo depends on getUserMedia, which your browser does not seem to support. :(");
}
vid.addEventListener('canplay', enablestart, false);
How can I capture an image from the webcam and put it in a div using the code above as a basis?
I'm not sure I can give any more details as I have not got the knowledge on how to do this.
First, draw it to a canvas:
var canvas = document.createElement('canvas');
canvas.height = video.height;
canvas.width = video.width;
canvas.getContext('2d').drawImage(video, 0, 0);
And now you can create the image:
var img = document.createElement('img');
img.src = canvas.toDataURL();
I cannot get to seem to get the screenshot porting working, but the webcam part is working fine, I'll update when complete.
JSFiddle
HTML
<div id="container">
<video autoplay="true" id="videoElement">dsasd</video>
<br>
<button onclick="snap()">Screenshot</button>
<canvas></canvas>
</div>
JS
var video = document.querySelector("#videoElement");
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia || navigator.oGetUserMedia;
if (navigator.getUserMedia) {
navigator.getUserMedia({
video: true
}, handleVideo, videoError);
}
function handleVideo(stream) {
video.src = window.URL.createObjectURL(stream);
}
function videoError(e) {
// do something
}
// Get handles on the video and canvas elements
var video = document.querySelector('video');
var canvas = document.querySelector('canvas');
// Get a handle on the 2d context of the canvas element
var context = canvas.getContext('2d');
// Define some vars required later
var w, h, ratio;
// Add a listener to wait for the 'loadedmetadata' state so the video's dimensions can be read
video.addEventListener('loadedmetadata', function() {
// Calculate the ratio of the video's width to height
ratio = video.videoWidth / video.videoHeight;
// Define the required width as 100 pixels smaller than the actual video's width
w = video.videoWidth - 100;
// Calculate the height based on the video's width and the ratio
h = parseInt(w / ratio, 10);
// Set the canvas width and height to the values just calculated
canvas.width = w;
canvas.height = h;
}, false);
// Takes a snapshot of the video
function snap() {
// Define the size of the rectangle that will be filled (basically the entire element)
context.fillRect(0, 0, w, h);
// Grab the image from the video
context.drawImage(video, 0, 0, w, h);
}
CSS
container {
margin: 0px auto;
width: 500px;
height: 375px;
border: 10px #333 solid;
}
videoElement, canvas {
width: 500px;
height: 375px;
background-color: #666;
}

Categories