You need to update currentTime video element and then draw the frame in canvas. Don't init play() event on the video. Show activity on this post. I started with the answer from 2018 about requestAnimationFrame .
The canvas element is part of HTML5 and allows for dynamic, scriptable rendering of 2D shapes and bitmap images.
HTML inside of canvas is not possible.
You cannot place elements inside a canvas (and have both displayed); they are only displayed if the browser does not understand the canvas element.
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var video = document.getElementById('video');
video.addEventListener('play', function () {
var $this = this; //cache
(function loop() {
if (!$this.paused && !$this.ended) {
ctx.drawImage($this, 0, 0);
setTimeout(loop, 1000 / 30); // drawing at 30fps
}
})();
}, 0);
I guess the above code is self Explanatory, If not drop a comment below, I will try to explain the above few lines of code
Edit :
here's an online example, just for you :)
Demo
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var video = document.getElementById('video');
// set canvas size = video size when known
video.addEventListener('loadedmetadata', function() {
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
});
video.addEventListener('play', function() {
var $this = this; //cache
(function loop() {
if (!$this.paused && !$this.ended) {
ctx.drawImage($this, 0, 0);
setTimeout(loop, 1000 / 30); // drawing at 30fps
}
})();
}, 0);
<div id="theater">
<video id="video" src="http://upload.wikimedia.org/wikipedia/commons/7/79/Big_Buck_Bunny_small.ogv" controls="false"></video>
<canvas id="canvas"></canvas>
<label>
<br />Try to play me :)</label>
<br />
</div>
Here's a solution that uses more modern syntax and is less verbose than the ones already provided:
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
const video = document.querySelector("video");
video.addEventListener('play', () => {
function step() {
ctx.drawImage(video, 0, 0, canvas.width, canvas.height)
requestAnimationFrame(step)
}
requestAnimationFrame(step);
})
Some useful links:
Displaying a video is much the same as displaying an image. The minor differences are to do with onload events and the fact that you need to render the video every frame or you will only see one frame not the animated frames.
The demo below has some minor differences to the example. A mute function (under the video click mute/sound on to toggle sound) and some error checking to catch IE9+ and Edge if they don't have the correct drivers.
Keeping answers current.The previous answers by user372551 is out of date (December 2010) and has a flaw in the rendering technique used. It uses the setTimeout
and a rate of 33.333..ms which setTimeout will round down to 33ms this will cause the frames to be dropped every two seconds and may drop many more if the video frame rate is any higher than 30. Using setTimeout
will also introduce video shearing created because setTimeout can not be synced to the display hardware.
There is currently no reliable method that can determine a videos frame rate unless you know the video frame rate in advance you should display it at the maximum display refresh rate possible on browsers. 60fps
The given top answer was for the time (6 years ago) the best solution as requestAnimationFrame
was not widely supported (if at all) but requestAnimationFrame
is now standard across the Major browsers and should be used instead of setTimeout to reduce or remove dropped frames, and to prevent shearing.
Loads a video and set it to loop. The video will not play until the you click on it. Clicking again will pause. There is a mute/sound on button under the video. The video is muted by default.
Note users of IE9+ and Edge. You may not be able to play the video format WebM as it needs additional drivers to play the videos. They can be found at tools.google.com Download IE9+ WebM support
// This code is from the example document on stackoverflow documentation. See HTML for link to the example.
// This code is almost identical to the example. Mute has been added and a media source. Also added some error handling in case the media load fails and a link to fix IE9+ and Edge support.
// Code by Blindman67.
// Original source has returns 404
// var mediaSource = "http://video.webmfiles.org/big-buck-bunny_trailer.webm";
// New source from wiki commons. Attribution in the leading credits.
var mediaSource = "http://upload.wikimedia.org/wikipedia/commons/7/79/Big_Buck_Bunny_small.ogv"
var muted = true;
var canvas = document.getElementById("myCanvas"); // get the canvas from the page
var ctx = canvas.getContext("2d");
var videoContainer; // object to hold video and associated info
var video = document.createElement("video"); // create a video element
video.src = mediaSource;
// the video will now begin to load.
// As some additional info is needed we will place the video in a
// containing object for convenience
video.autoPlay = false; // ensure that the video does not auto play
video.loop = true; // set the video to loop.
video.muted = muted;
videoContainer = { // we will add properties as needed
video : video,
ready : false,
};
// To handle errors. This is not part of the example at the moment. Just fixing for Edge that did not like the ogv format video
video.onerror = function(e){
document.body.removeChild(canvas);
document.body.innerHTML += "<h2>There is a problem loading the video</h2><br>";
document.body.innerHTML += "Users of IE9+ , the browser does not support WebM videos used by this demo";
document.body.innerHTML += "<br><a href='https://tools.google.com/dlpage/webmmf/'> Download IE9+ WebM support</a> from tools.google.com<br> this includes Edge and Windows 10";
}
video.oncanplay = readyToPlayVideo; // set the event to the play function that
// can be found below
function readyToPlayVideo(event){ // this is a referance to the video
// the video may not match the canvas size so find a scale to fit
videoContainer.scale = Math.min(
canvas.width / this.videoWidth,
canvas.height / this.videoHeight);
videoContainer.ready = true;
// the video can be played so hand it off to the display function
requestAnimationFrame(updateCanvas);
// add instruction
document.getElementById("playPause").textContent = "Click video to play/pause.";
document.querySelector(".mute").textContent = "Mute";
}
function updateCanvas(){
ctx.clearRect(0,0,canvas.width,canvas.height);
// only draw if loaded and ready
if(videoContainer !== undefined && videoContainer.ready){
// find the top left of the video on the canvas
video.muted = muted;
var scale = videoContainer.scale;
var vidH = videoContainer.video.videoHeight;
var vidW = videoContainer.video.videoWidth;
var top = canvas.height / 2 - (vidH /2 ) * scale;
var left = canvas.width / 2 - (vidW /2 ) * scale;
// now just draw the video the correct size
ctx.drawImage(videoContainer.video, left, top, vidW * scale, vidH * scale);
if(videoContainer.video.paused){ // if not playing show the paused screen
drawPayIcon();
}
}
// all done for display
// request the next frame in 1/60th of a second
requestAnimationFrame(updateCanvas);
}
function drawPayIcon(){
ctx.fillStyle = "black"; // darken display
ctx.globalAlpha = 0.5;
ctx.fillRect(0,0,canvas.width,canvas.height);
ctx.fillStyle = "#DDD"; // colour of play icon
ctx.globalAlpha = 0.75; // partly transparent
ctx.beginPath(); // create the path for the icon
var size = (canvas.height / 2) * 0.5; // the size of the icon
ctx.moveTo(canvas.width/2 + size/2, canvas.height / 2); // start at the pointy end
ctx.lineTo(canvas.width/2 - size/2, canvas.height / 2 + size);
ctx.lineTo(canvas.width/2 - size/2, canvas.height / 2 - size);
ctx.closePath();
ctx.fill();
ctx.globalAlpha = 1; // restore alpha
}
function playPauseClick(){
if(videoContainer !== undefined && videoContainer.ready){
if(videoContainer.video.paused){
videoContainer.video.play();
}else{
videoContainer.video.pause();
}
}
}
function videoMute(){
muted = !muted;
if(muted){
document.querySelector(".mute").textContent = "Mute";
}else{
document.querySelector(".mute").textContent= "Sound on";
}
}
// register the event
canvas.addEventListener("click",playPauseClick);
document.querySelector(".mute").addEventListener("click",videoMute)
body {
font :14px arial;
text-align : center;
background : #36A;
}
h2 {
color : white;
}
canvas {
border : 10px white solid;
cursor : pointer;
}
a {
color : #F93;
}
.mute {
cursor : pointer;
display: initial;
}
<h2>Basic Video & canvas example</h2>
<p>Code example from Stackoverflow Documentation HTML5-Canvas<br>
<a href="https://stackoverflow.com/documentation/html5-canvas/3689/media-types-and-the-canvas/14974/basic-loading-and-playing-a-video-on-the-canvas#t=201607271638099201116">Basic loading and playing a video on the canvas</a></p>
<canvas id="myCanvas" width = "532" height ="300" ></canvas><br>
<h3><div id = "playPause">Loading content.</div></h3>
<div class="mute"></div><br>
<div style="font-size:small">Attribution in the leading credits.</div><br>
Using the canvas to render video gives you additional options in regard to displaying and mixing in fx. The following image shows some of the FX you can get using the canvas. Using the 2D API gives a huge range of creative possibilities.
Image relating to answer Fade canvas video from greyscale to color
See video title in above demo for attribution of content in above inmage.
You need to update currentTime video element and then draw the frame in canvas. Don't init play() event on the video.
You can also use for ex. this plugin https://github.com/tstabla/stVideo
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With