Html html5:在画布内显示视频
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4429440/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
html5: display video inside canvas
提问by clamp
is it possible to display a html5-video as part of the canvas?
是否可以将 html5 视频显示为画布的一部分?
basically the same way as you draw an Image in the canvas.
与在画布中绘制图像的方式基本相同。
context.drawVideo(vid, 0, 0);
thanks!
谢谢!
回答by
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>
回答by Blindman67
Using canvas to display Videos
使用画布显示视频
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.
显示视频与显示图像非常相似。细微的区别与 onload 事件以及您需要在每一帧都渲染视频或者您只会看到一帧而不是动画帧的事实有关。
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.
下面的演示与示例有一些细微差别。静音功能(在视频下单击静音/声音以切换声音)和一些错误检查以捕获 IE9+ 和 Edge(如果它们没有正确的驱动程序)。
Keeping answers current.保持最新的答案。The previous answers by user372551is 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.
user372551的先前答案已过时(2010 年 12 月),并且所使用的渲染技术存在缺陷。它使用setTimeout
33.333..ms 的速率,setTimeout 将四舍五入为 33ms,这将导致每两秒丢弃一次帧,如果视频帧速率高于 30,则可能丢弃更多。使用setTimeout
还将引入视频剪切创建是因为 setTimeout 无法同步到显示硬件。
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
目前没有可靠的方法可以确定视频帧速率,除非您事先知道视频帧速率,否则您应该以浏览器上可能的最大显示刷新率显示它。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.
给出的最佳答案是当时(6 年前)最好的解决方案,requestAnimationFrame
因为没有得到广泛支持(如果有的话),但requestAnimationFrame
现在是主要浏览器的标准,应该使用而不是 setTimeout 来减少或删除掉帧,并防止剪切。
The example demo.
示例演示。
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.comDownload IE9+ WebM support
请注意 IE9+ 和 Edge 用户。您可能无法播放视频格式 WebM,因为它需要额外的驱动程序来播放视频。它们可以在tools.google.com上找到下载 IE9+ WebM 支持
// 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>
Canvas extras
帆布附加品
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.
使用画布渲染视频为您提供了有关在 fx 中显示和混合的其他选项。下图显示了您可以使用画布获得的一些 FX。使用 2D API 提供了大量的创意可能性。
Image relating to answer Fade canvas video from greyscale to color
与答案相关的图像从灰度到彩色淡化画布视频
See video title in above demo for attribution of content in above inmage.
请参阅上面演示中的视频标题,了解上面图片中内容的归属。
回答by David
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:
一些有用的链接:
回答by Lysy
You need to update currentTime video element and then draw the frame in canvas. Don't init play() event on the video.
您需要更新 currentTime 视频元素,然后在画布中绘制帧。不要在视频上初始化 play() 事件。
You can also use for ex. this plugin https://github.com/tstabla/stVideo
您也可以使用 for ex。这个插件https://github.com/tstabla/stVideo