Published
Edited
Jan 16, 2021
Insert cell
md`# canvas video recorder step by step`
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
saveVideo = (renderCanvas) => {
var stopRequest = false;
var saveRequest = false;
let frame = 0;
let capturer;
let animationFrame = 0;
var started = false;
var framerate;
var div = html`<div class="sbsr">
<style>
.sbsr { color:#606060; font-family:arial; height:200px;}
.sbsr>* { margin-right:6px;}
.sbsr .fr { width:80px;}
.sbsr .label { display: inline-block; width:80px; font-size:.8em; color:#000080;}
.sbsr .buttons {margin-top:10px;}
</style>
<div>
step by step recorder
</div>
<div>
<span class="label">type</span>
<select class="ty">
<option value="jpg">jpg</option>
<option value="gif">gif</option>
<option value="png">png</option>
<option value="webm" selected>webm</option>
<option value="webm-mediarecorder">webm-mediarecorder</option>
</select>
</div>
<div>
<span class="label">framerate</span>
<input class="fr" type="range" min="0.1" max="60" step="0.1" value="60">
<span class="label frshow"/>
</div>
<div class="buttons">
<button class="start">start recording</button>
<button class="sv">save video</button>
<button class="stop">stop</button>
<button class="rs">reset</button>
<span class="label frame"></span>
<a href="#" class="outlink" download="">wait...</a>
</div>
</div>`;

Object.freeze(HTMLVideoElement.prototype);
$('.start', div).click(startRecording);

$('.sv', div).click(function () { saveRequest = true; });
$('.stop', div).click(function () { saveRequest = stopRequest = true; });
$('.rs', div).click(reset);

$('.fr', div).change(function () {
framerate = Math.floor($('.fr', div).val());
$('.frshow', div).text('f.rate: ' + framerate);
}).trigger('change');

function save() {
console.log('onsave');
var format = $('.ty', div).val();
var ext = { jpg: "jpge", png: "png", webm: "webm", "webm-mediarecorder": "webm" }[format];
capturer.save(function (blob) {
console.log('on capture save');
var url = URL.createObjectURL(blob);
$('.outlink', div).attr('href', url).attr('download', 'output.' + ext).text('download video at frame'+frame);
});
}

function setEnabled(sel, value) {
if (value)
$(sel, div).removeAttr('disabled');
else
$(sel, div).attr('disabled', 'disabled');
}

function stop() {
capturer.stop();
started=false;
setEnabled('.stop, .rs, .sv', true);
setEnabled('.start', true);
}


function reset() {
capturer=undefined;
started=false;
frame = 0;
animationFrame = 0;
stopRequest = false;
saveRequest = false;

setEnabled('.stop, .rs, .sv', false);
setEnabled('.start', true);
}

async function startRecording() {
if (started)
return;

var format = $('.ty', div).val();

var mainResolve;
capturer = new ccapture({
format,
framerate,
verbose: false
});

async function render() {
if (stopRequest) {
stopRequest = false;
cancelAnimationFrame(animationFrame);
stop();
mainResolve();
}
if (saveRequest) {
saveRequest = false;
save();
}
if (started) {
const c = await renderCanvas(frame);
capturer.capture(c);
frame = frame + 1;
$('.frame', div).text("F:" + frame);
animationFrame = requestAnimationFrame(render);
}
};

setEnabled('.stop, .rs, .sv', true);
setEnabled('.start', false);
started = true;

capturer.start();
render();
mainResolve = function(){};

// return new Promise((resolve, reject) => {
// mainResolve = resolve;
// capturer.start();
// return render();
// });
}

reset();
return div;

}
Insert cell
Insert cell
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more