サンプルソース
テストしたのはChrome ver.143
sample.js
(async () => {
// ==== 設定 ====
const DURATION_SEC = 5; // 録画秒数(必要に応じて変更)
// 既に実行済みなら中断
if (window.__captureRunning) {
console.warn('既にキャプチャ中です');
return;
}
window.__captureRunning = true;
// 画面(またはタブ)をユーザーに選ばせる
/** @type {MediaStream} */
let stream;
try {
stream = await navigator.mediaDevices.getDisplayMedia({
video: {
frameRate: 60, // 60fps希望(実際のfpsは環境依存)
},
audio: false // 必要なら true に
});
} catch (err) {
console.error('getDisplayMedia がユーザーによって拒否されました', err);
window.__captureRunning = false;
return;
}
console.log('capture start');
// MediaRecorder を準備
const options = {
mimeType: 'video/webm; codecs=vp9' // vp8, vp9, h264 などブラウザ依存
};
/** @type {Blob[]} */
const chunks = [];
let recorder;
try {
recorder = new MediaRecorder(stream, options);
} catch (err) {
console.error('MediaRecorder の初期化に失敗しました', err);
window.__captureRunning = false;
stream.getTracks().forEach(t => t.stop());
return;
}
recorder.ondataavailable = (e) => {
if (e.data && e.data.size > 0) {
chunks.push(e.data);
}
};
recorder.onstop = () => {
console.log('capture stop');
const blob = new Blob(chunks, { type: 'video/webm' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'capture.webm';
document.body.appendChild(a);
a.click();
a.remove();
URL.revokeObjectURL(url);
stream.getTracks().forEach(t => t.stop());
window.__captureRunning = false;
};
recorder.start();
// 一定時間後に停止
setTimeout(() => {
if (recorder.state === 'recording') {
recorder.stop();
}
}, DURATION_SEC * 1000);
})();
実行方法
- 先のスクリプトをクリップボードにコピー→Devtoolsのコンソールにペースト→エンター
- どのタブを動画に変換するかを聞かれるので選択
- これで、5秒後にダウンロードフォルダに動画が作成されます
面白ポイント
- CSSアニメーションを動画として保存したいときにちょうどいい
- キャプチャツールも機能拡張もなしに動画として保存できる
- JSではローカルファイルにアクセスできないけど、createObjectURLでblobのurlのアンカーを作ってそのアンカーをクリックすることでダウンロードさせてる
- よくある実装ではローカルでffmpeg使って動画ファイルを作るけどこの実装ではffmpegは必要ない
制約
当然著作権保護されてる動画などは保存できない(動画部分は黒くなる)。
あとメモリをめちゃ食う。
