我正在做一个像索尼Be Moved这样的停止 - 滚动控制 - 回放网站。
考虑到停止拍摄技术,我面临的问题是在浏览器在屏幕上绘制图像之前对图像进行栅格化所需的时间。移动设备需要很多。可能调整大小的图像占用了大部分cpu,但我不确定。这就是我展示框架的方式:
<div
style="
position: fixed;
top:0; right:0; bottom:0; left:0;
background-image: url(...);
background-position: center;
background-size: cover;
"
></div>
问题:
有没有办法缓存图像的栅格化版本?也许画布支持这个?这样,当我决定在屏幕上显示它时,它就会准备就绪。
现在,这是我知道如何缓存图像的唯一方法。
var image = new Image();
image.src = '...';
答案 0 :(得分:3)
参考评论 - 有一种方法可以预先缓存视频帧。每个帧将使用一个完整的内存块用于位图(在任何情况下也是预装图像序列的情况)。
preload
设置为auto
1 / FPS
。timeupdate
次更新使用currentTime
事件,因为设置当前时间异步。选择视频中的入点,缓存(由于事件周期,这可能需要一段时间),使用每个帧的canvas元素存储到帧缓冲区。然后根据需要播放缓冲区(这也使您能够向后播放视频,如下所示,这是浏览器尚不支持的功能)。
此示例将视频从网络,缓存90(3秒@ 30 fps)帧加载到内存,然后在窗口中播放序列乒乓(显示的图像显然来自缓存):
var canvas = document.querySelector("canvas"),
ctx = canvas.getContext("2d"),
video = document.createElement("video"),
frames = [],
w = canvas.width, h = canvas.height;
video.addEventListener("canplay", cache);
video.preload = "auto";
video.src = "http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4";
function cache() {
this.removeEventListener("canplay", cache); // remove to avoid recalls
var fps = 30, // assuming 30 FPS
delta = 1 / fps, // time delta
count = 0, // current cached frame
max = fps * 3, // 3 seconds
div = document.querySelector("div"); // just for info
this.addEventListener("timeupdate", cacheFrame); // time update is aync
this.currentTime = 19; // start with initial time
function cacheFrame() {
div.innerHTML = "Caching frame: " + count;
if (count++ < max) {
// create canvas for frame-buffer;
var canvas = document.createElement("canvas"),
ctx = canvas.getContext("2d");
canvas.width = this.videoWidth; // canvas size = video frame
canvas.height = this.videoHeight;
ctx.drawImage(video, 0, 0); // draw current frame
frames.push(canvas); // store frame
this.currentTime += delta; // update time, wait..
}
else {
this.removeEventListener("timeupdate", cacheFrame); // remove!!
play(); // play back cached sequence
}
}
}
// to demo the cached frames
function play() {
var current = 0, max = frames.length, dlt = 1,
div = document.querySelector("div"),
toggle = false,
mem = max * video.videoWidth * video.videoHeight * 4; // always RGBA
mem = (mem / 1024) / 1024; //mb
ctx.fillStyle = "red";
(function loop() {
toggle = !toggle; // toggle FPS to 30 FPS
requestAnimationFrame(loop);
if (toggle) {
div.innerHTML = "Playing frame: " + current +
" (raw mem: " + mem.toFixed(1) + " mb)";
ctx.drawImage(frames[current], 0, 0, w, h); // using frame-buffer
ctx.fillRect(0, 0, current/max * w, 3);
current += dlt;
if (!current || current === max-1) dlt = -dlt; // pong-pong
}
})();
}
html, body {width:100%;height:100%}
body {margin:0; overflow:hidden;background:#aaa}
div {font:bold 20px monospace;padding:12px;color:#000}
canvas {z-index:-1;position:fixed;left:0;top:0;width:100%;height:100%;min-height:400px}
<div>Pre-loading video... wait for it, wait for it...</div>
<canvas width=600 height=360></canvas>
答案 1 :(得分:1)
画布绘图源是image&amp;视频对象(以及其他一些现在不相关的来源)。因此,如果在初始下载和渲染期间发生了不必要的延迟,那么画布将花费更长的时间,因为传入的图像必须首先渲染到图像对象上,然后再次渲染到画布上 - 两步而不是一步。
你的答案不在canvas元素中,所以你回到了通常的解决方案:通过降低图像质量(质量较低的jpg)来减少下载的图像位数量。
您也可以(正如您所指出的那样)预先加载&amp;将所有图像缓存在new Image
中,以便在需要时立即使用。通常的成本适用:缓存图像的内存使用量增加,以及在下载所有必需图像时应用程序启动时的延迟。