我正在开始一个项目,我想从单个视频中切片部分,并将这些部分重新绘制到屏幕上的不同对象上。 我知道我可以通过使用drawImage将视频的各个部分重新绘制到画布元素上来做到这一点。 在进行研究时,似乎可以在WebGL中使用动画纹理做同样的事情。 有谁知道使用 WebGL 动画纹理而不是 drawImage 来执行此操作是否会有任何性能提升?
WebGL在2D画布性能方面具有优势,但是,由于您正在处理视频,那么问题是使用WebGL是否有任何意义。
考虑到NTSC世界中的视频很少超过30 FPS(PAL 25 fps(,您将有一个很好的时间预算来切片视频并重绘它们。另外,考虑到drawImage
是一个非常快速的操作,并且也有硬件支持(并且没有硬件支持(,你可以权衡这些与WebGL的困扰,WebGL不适用于所有硬件(如低端消费者和旧硬件(,并且对它的支持各不相同(在撰写本文时(。
在这种情况下,我最初会坚持使用 2D 画布。如果您需要将切片包装和投影到 3D 对象上,那么 2D 画布不是最佳选择。您可以直接在画布元素上使用 CSS 3D 转换,例如四边形转换。如果您需要不同的转换,只需使用不同的画布元素,每个元素代表一个切片。
顺便说一句,这里的一个技巧是创建一个屏幕外画布,您首先将框架绘制到其中。这样,您就不必从正在运行的视频的元素中抓取,这可能是一个昂贵的操作,具体取决于浏览器将如何抓取视频位图数据。
举个例子:
var ctx = canvas.getContext('2d'),
sw = 32,
frame = document.createElement("canvas"), // "frame buffer"
fctx = frame.getContext("2d");
frame.width = 500;
frame.height = 280;
video.addEventListener("playing", sliceAndDice, false);
function sliceAndDice() {
fctx.drawImage(video, 0, 0); // video to "frame buffer" to make it more smooth
// some misc slicing
for(var x = 0; x < frame.width; x += sw) {
var y = Math.sin(x*1.5) * sw + 20;
ctx.drawImage(frame, x , 0, sw, frame.height, // source slice
x * 1.1, y, sw, frame.height); // dest. slice
}
requestAnimationFrame(sliceAndDice);
}
<canvas id="canvas" width=560 height=320></canvas>
<video style="display:none" id="video" width="500" height="280" preload="auto" autoplay="true">
<source src="//clips.vorwaerts-gmbh.de/big_buck_bunny.mp4" type="video/mp4">
<source src="//clips.vorwaerts-gmbh.de/big_buck_bunny.webm" type="video/webm">
<source src="//clips.vorwaerts-gmbh.de/big_buck_bunny.ogv" type="video/ogg">
</video>
一个包含 320 个切片的替代演示,表明您只需使用 2D 画布就可以将其推得很远:
var ctx = canvas.getContext('2d'),
frame = document.createElement("canvas"), // "frame buffer"
fctx = frame.getContext("2d"),
dlt = 0;
frame.width = video.width;
frame.height = video.height;
video.addEventListener("playing", sliceAndDice, false);
function sliceAndDice() {
fctx.drawImage(video, 0, 0); // video to frame buffer to make it smoother
// some misc slicing
for(var x = 0, y; x < frame.width; x++) {
y = Math.sin(x*32+dlt) * 3 + 10; // "random" y pos.
ctx.drawImage(frame, x, 0, 1, frame.height, // source slice
x, y, 1, frame.height); // dest. slice
}
dlt += 0.2;
requestAnimationFrame(sliceAndDice);
};
<canvas id="canvas" width=560 height=320></canvas>
<video style="display:none" id="video" width="500" height="280"
preload="auto" autoplay="true">
<source src="//clips.vorwaerts-gmbh.de/big_buck_bunny.mp4" type="video/mp4">
<source src="//clips.vorwaerts-gmbh.de/big_buck_bunny.webm"type="video/webm">
<source src="//clips.vorwaerts-gmbh.de/big_buck_bunny.ogv" type="video/ogg">
</video>