I'm doing one of them stop-shot-scroll-controlled-playback sites like Sony's Be Moved.
The problem that I'm facing, considering the stop-shot technique, is the time that it takes for image to be rasterized before browser draws it on screen. It takes a lot on mobile. Probably resizing the image takes most of the cpu, but I'm not sure. This is how I show the frames:
<div
style="
position: fixed;
top:0; right:0; bottom:0; left:0;
background-image: url(...);
background-position: center;
background-size: cover;
"
></div>
The question:
Is there a way to cache a rasterized version of an image? Maybe canvas supports this? That way, when I decide to show it on screen, it'll be ready.
Right now, this is the only way I know how to cache an image.
var image = new Image();
image.src = '...';
Ref comments - there is a way to pre-cache video frames. Each frame will use a full memory block for the bitmap (which in any case also is the case with preloaded image sequences).
preload set to auto1 / FPS.timeupdate event for every currentTime update as setting current time is asynchronous.Chose an in-point in the video, cache (this can take a while due to the event cycle), store to a frame buffer using a canvas element for each frame. Then playback the buffer when and as needed (this also gives you the ability to play video backwards as shown below, a feature not yet supported in the browsers).
This example will load a video from net, cache 90 (3 sec @ 30 fps) frames to memory, then play back the sequence ping-pong in the window (the images you see are from the cache obviously):
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>
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