How use canvas from external video? - javascript

I have the following code:
<!DOCTYPE html>
<title>Video/Canvas Gray Effect</title>
<script>
document.addEventListener('DOMContentLoaded', function(){
var v = document.getElementById('v');
var canvas = document.getElementById('c');
var context = canvas.getContext('2d');
var back = document.createElement('canvas');
var backcontext = back.getContext('2d');
var cw,ch;
v.addEventListener('play', function(){
cw = v.clientWidth;
ch = v.clientHeight;
canvas.width = cw;
canvas.height = ch;
back.width = cw;
back.height = ch;
draw(v,context,backcontext,cw,ch);
},false);
},false);
function draw(v,c,bc,w,h) {
if(v.paused || v.ended) return false;
// First, draw it into the backing canvas
bc.drawImage(v,0,0,w,h);
// Grab the pixel data from the backing canvas
var idata = bc.getImageData(0,0,w,h);
var data = idata.data;
// Loop through the pixels, turning them grayscale
for(var i = 0; i < data.length; i+=4) {
var r = data[i];
var g = data[i+1];
var b = data[i+2];
var brightness = (3*r+4*g+b)>>>3;
data[i] = brightness;
data[i+1] = brightness;
data[i+2] = brightness;
}
idata.data = data;
// Draw the pixels onto the visible canvas
c.putImageData(idata,0,0);
// Start over!
setTimeout(draw,20,v,c,bc,w,h);
}
</script>
<video id=v controls loop>
<source src=video.webm type=video/webm>
</video>
<canvas id=c></canvas>
<style>
#c {
position: absolute;
top: 50%;
left: 50%;
margin: -180px 0 0 20px;
}
#v {
position: absolute;
top: 50%;
left: 50%;
margin: -180px 0 0 -500px;
}
</style>
The canvas work only if the video hosted in my site, but if a external video the canvas not working only work if make a proxy using the same domain, for example:
Working if a hosted the video on my site:
<video id=v controls loop>
<source src=video.webm type=video/webm>
</video>
Working if a use a proxy, but I will not use a proxy:
<video id=v controls loop>
<source src=./proxy.php?url_toexternal_video=http://host.com/video.webm type=video/webm>
</video>
Not working if a use the direct link to the video:
<video id=v controls loop>
<source src=http://host.com/video.webm type=video/webm>
</video>
any way to make it work if it is from an external video? Thanks! ;)

Nope, there's no way to use getImageData on a canvas that has been tainted by cross-origin content.

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.

Best way to capture paused video frame to canvas

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>

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%.

Can you stop a HTML5 video pausing/stopping on scroll?

I have a HTML5 video banner at the top of my page. It has the autoplay and loop attributes added. When I begin to scroll down the page the video stops and never restarts when I scroll back upwards. I'd like the video to carry on playing no matter if the user scrolls or not.
There doesn't seem to be any attributes listed in the W3C spec that suggests a solution, so is there another way of disabling this functionality?
The HTML and CSS is very simple so I'm wondering if I need some JS to help along the way:
HTML:
<video preload="none" autoplay loop>
<source src="/media/test.mp4" type="video/mp4">
</video>
CSS:
video {
width: 100%;
height: auto;
}
Any help would be much appreciated.
You can use isInViewport jQuery plugin as below:
$('video').each(function(){
if ($(this).is(":in-viewport")) {
$(this)[0].play();
} else {
$(this)[0].pause();
}
})
it works fine for me,, if you want to change yiur viewport then change fraction = 0.5; in my code
var videos = document.getElementsByTagName("video"),
fraction = 0.5;
function checkScroll() {
for(var i = 0; i < videos.length; i++) {
var video = videos[i];
var x = video.offsetLeft, y = video.offsetTop, w = video.offsetWidth, h = video.offsetHeight, r = x + w, //right
b = y + h, //bottom
visibleX, visibleY, visible;
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);
div {padding-top:300px; width:320px;}
video {
padding-bottom:300px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<video id="video1" preload="auto" loop="loop">
<source src="http://www.w3schools.com/html/movie.mp4" type="video/mp4">>
bgvideo
</video>
</div>
This can be disabled by using the attribute data-keepplaying.
<video preload="none" autoplay loop>
<source src="/media/test.mp4" type="video/mp4">
</video>
if using fullpage.js
<video autoplay muted loop data-keepplaying>
<source src="myvide.mp4" type="video/mp4">
</video>
works

Canvas drawImage of html5 video works on browsers but not Android

Why does this code work on normal browsers, but show the same screenshot for Android browsers?
Html
<div class="video">
<video id="video" src="http://www.w3schools.com/html/mov_bbb.mp4" type="video/mp4" muted controls autoplay></video>
</div>
<div class="timeline" id="timeline"></div>
JavaScript
var timeline = document.getElementById('timeline'),
video = document.getElementById('video'),
interval = null;
video.addEventListener("playing", onStart);
video.addEventListener("pause", onStop);
video.addEventListener("ended", onEnd);
function onStart() {
if (interval == null) {
interval = window.setInterval(createImage, 1000);
}
}
function onStop() {
if (interval) {
clearInterval(interval);
interval = null;
}
}
function onEnd() {
onStop();
video.removeEventListener("playing", onStart);
video.removeEventListener("pause", onStop);
video.removeEventListener("ended", onEnd);
}
function createImage() {
console.log('createImage', video.currentTime, video.videoWidth, video.videoHeight);
var canvas = document.createElement('canvas'),
ctx = canvas.getContext('2d');
ctx.drawImage(video, 0, 0, video.videoWidth, video.videoHeight);
timeline.appendChild(canvas);
}
Here is the full code:
http://jsfiddle.net/kmturley/z99cmwtq/6/
how come this works for me in chrome android 4.4.4 ?
drawImage()
codepen

Categories