详解使用HTML5 Canvas(画布) 实时播放 Video(视频)
今天有人发帖找我帮忙,使用 HTML5 Canvas 实时播放 Video(视频)在 PC 端可以正常播放,到了手机端就不行了。我这里整理并翻译了一些 mozilla 上的相关文章。希望能解决部分人遇到的问题。
上图是使用 Canvas 播放 Video视频的一个截图。该实例的运行效果:https://developer.mozilla.org/samples/video/chroma-key/index.xhtml
通过在一个 canvas (画布)上结合 video 元素功能,你可以实时地操纵视频数据来合成各种视觉特效到正在呈现的视频画面中。本教程示范如何使用 JavaScript 代码执行色度键控(也被称为“绿屏效果”)。
下面是该实例的相关 HTML 代码。
<!DOCTYPE html>
<html>
<head>
<style>
body {
background: black;
color:#CCCCCC;
}
#c2 {
background-image: url(foo.png);
background-repeat: no-repeat;
}
div {
float: left;
border :1px solid #444444;
padding:10px;
margin: 10px;
background:#3B3B3B;
}
</style>
<script type="text/javascript;version=1.8" src="main.js"></script>
</head>
<body onload="processor.doLoad()">
<div>
<video id="video" src="video.ogv" controls="true"/>
</div>
<div>
<canvas id="c1" width="160" height="96"/>
<canvas id="c2" width="160" height="96"/>
</div>
</body>
</html>
重点部分做一下解释:
- 这篇文档布置了两个 canvas 元素,分别带着 ID 为 c1 和 c2 的属性。Canvas c1 用于显示原视频的当前帧,而 c2 用于显示执行了色度键控效果后的视频;c2 预先加载将被用于替换视频中绿幕(绿色背景)的静态图像。
- JavaScript 代码从一个名为 main.js 的脚本引入;这个脚本使用 JavaScript 1.8 特性,所以在22行引入脚本时它的 version(版本)是指定的。
- 当文档加载时,在 main.js 里的 processor.doLoad() 方法开始执行。
下面是 main.js 中的代码。
var processor;
processor.doLoad = function doLoad() {
this.video = document.getElementById('video');
this.c1 = document.getElementById('c1');
this.ctx1 = this.c1.getContext('2d');
this.c2 = document.getElementById('c2');
this.ctx2 = this.c2.getContext('2d');
let self = this;
this.video.addEventListener('play', function() {
self.width = self.video.videoWidth / 2;
self.height = self.video.videoHeight / 2;
self.timerCallback();
}, false);
},
processor.timerCallback = function timerCallback() {
if (this.video.paused || this.video.ended) {
return;
}
this.computeFrame();
let self = this;
setTimeout(function() {
self.timerCallback();
}, 0);
},
processor.computeFrame = function computeFrame() {
this.ctx1.drawImage(this.video, 0, 0, this.width, this.height);
let frame = this.ctx1.getImageData(0, 0, this.width, this.height);
let l = frame.data.length / 4;
for (let i = 0; i < l; i++) { let r = frame.data[i * 4 + 0];
let g = frame.data[i * 4 + 1]; let b = frame.data[i * 4 + 2]; if (g > 100 && r > 100 && b < 43)
frame.data[i * 4 + 3] = 0;
}
this.ctx2.putImageData(frame, 0, 0);
return;
};
当 HTML 文档最初加载时 doLoad() 方法被调用。这个方法的工作是准备色键处理代码所需的变量,并设置一个监听事件以便我们可以监测用户何时开始播放视频。
processor.doLoad 方法抓取 HTML 文档中关键元素的引用,即 video 元素和两个 canvas 元素。它也获取了两个 canvas 各自的图形上下文引用。这些将在我们真正做色键控制效果的时候被用到。
然后 addEventListener() 被调用来开始监视 video 元素以便我们在用户按下视频上的播放按钮时获得通知。为响应用户开始回放,这段代码获取了视频的宽度和高度,并各自减半(当我们执行色度键控效果的时候我们将减半视频的尺寸),然后调用 timerCallback() 方法来开始监视视频以及计算视觉效果。
processor.timerCallback 计时器回调最初在视频开始播放时(当“播放”事件发生时)被调用,然后负责设定自身定期被调用以便为每一帧启用键控效果。
回调做的第一件事情是检查视频是否正好在播放;如果不是,回调立即返回并不会做任何事情。
然后(如果视频正在播放)它调用 computeFrame() 方法,该方法对当前视频帧执行色度键控效果。
回调做的最后一件事是调用 setTimeout() 来设定它自身被尽快地再次调用。在真实环境中,你可能会根据视频的帧速率情况来计划实现这种调用。
computeFrame() 方法负责真实获取一帧数据并执行色度键控效果。当这段例行程序被调用时,video 元素正显示最新的视频数据帧,就像文章前面的示例图片一样。
现实中使用 Video 播放视频还是多数。Canvas + Video 来进行视频播放的应用不多。我们从这篇文章中更应该学会 Canva、Video 的使用,以及视频关键帧的操作。
参考资料:
扫描下方二维码,关注业余草微信公众号,回复“FFmpeg”关键词,获取 FFmpeg 视频教程!