1
1

More than 1 year has passed since last update.

お題は不問!Qiita Engineer Festa 2023で記事投稿!

[悪用禁止] ブラウザだけでカメラ、キャプチャ、VideoやCanvasを録画してダウンロード

Last updated at Posted at 2023-07-21

TL;DR

MediaStreamの取得

// mediaStreamの取得(video/canvas)
stream = document.querySelector('canvas').captureStream()

// mediaStreamの取得(画面キャプチャー)
stream = await navigator.mediaDevices.getDisplayMedia()

// mediaStreamの取得(Webカメラ)
stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true })

MediaRecorderの作成

function processMediaWhenStop(stream, onStop) {
  const mime = MediaRecorder.isTypeSupported("video/webm; codecs=vp9") ? "video/webm; codecs=vp9" : "video/webm";
  const mediaRecorder = new MediaRecorder(stream, { mimeType: mime })
  // start record
  const chunks = []
  mediaRecorder.addEventListener('dataavailable', e => chunks.push(e.data))

  // call on stop callback
  mediaRecorder.addEventListener('stop', async () => {
    const blob = new Blob(chunks, { type: chunks[0].type })
    await onStop(blob)
  })

  return mediaRecorder
}

onStop Callbackの一例(ファイルとしてダウンロード)

function downloadWebm(blob) {
  const url = URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.href = url;
  a.download = 'video.webm';
  a.click();
}

おまけ: FFmpegで.mp4に変換

$ ffmpeg -i video.webm -c:v copy -c:a copy video.mp4

はじめに

JS直書きでGoogle DoodleのCanvasを録画してGifにという記事を書きましたが、最近はより汎用性の高い方法を見つかりました。

操作Demo

Three.jsのサンプルを拝借いたします。

関数投入

processMediaWhenStop()downloadWebm()を先に投入します。

Cursor_と_three_js_examples_と_app_js_—_ES6_demos.png

録画開始

該当するcanvasまたはvideoを特定出来たら、下記のコードを一気にコンソールに投入します。

stream = document.querySelector('canvas').captureStream()
recorder = processMediaWhenStop(stream, downloadWebm)
recorder.start() // 録画開始

Cursor_と_three_js_examples.png

録画終了&ファイルDL

手動でrecorder.stop()をCallすれば、勝手に録画が停止し、video.webmというファイルがダウンロードされます。

Cursor_と_three_js_examples.png

Cursor_と_ダウンロード.png

こんなビデオファイルがDLされます。
Cursor_と_video__1__webm_と_three_js_examples.png

必要であれば、MP4に変換

$ ffmpeg -i video.webm -c:v copy -c:a copy video.mp4

上記コマンドで一瞬で出来ます。

ffmpeg version 6.0 Copyright (c) 2000-2023 the FFmpeg developers
  built with Apple clang version 13.0.0 (clang-1300.0.29.30)
  configuration: --prefix=/usr/local/Cellar/ffmpeg/6.0 --enable-shared --enable-pthreads --enable-version3 --cc=clang --host-cflags= --host-ldflags= --enable-ffplay --enable-gnutls --enable-gpl --enable-libaom --enable-libaribb24 --enable-libbluray --enable-libdav1d --enable-libmp3lame --enable-libopus --enable-librav1e --enable-librist --enable-librubberband --enable-libsnappy --enable-libsrt --enable-libsvtav1 --enable-libtesseract --enable-libtheora --enable-libvidstab --enable-libvmaf --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxml2 --enable-libxvid --enable-lzma --enable-libfontconfig --enable-libfreetype --enable-frei0r --enable-libass --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libspeex --enable-libsoxr --enable-libzmq --enable-libzimg --disable-libjack --disable-indev=jack --enable-videotoolbox --enable-audiotoolbox
  libavutil      58.  2.100 / 58.  2.100
  libavcodec     60.  3.100 / 60.  3.100
  libavformat    60.  3.100 / 60.  3.100
  libavdevice    60.  1.100 / 60.  1.100
  libavfilter     9.  3.100 /  9.  3.100
  libswscale      7.  1.100 /  7.  1.100
  libswresample   4. 10.100 /  4. 10.100
  libpostproc    57.  1.100 / 57.  1.100
Input #0, matroska,webm, from 'video.webm':
  Metadata:
    encoder         : Chrome
  Duration: N/A, start: 0.000000, bitrate: N/A
  Stream #0:0(eng): Video: vp9 (Profile 0), yuv420p(tv), 1039x860, SAR 1:1 DAR 1039:860, 1k tbr, 1k tbn (default)
    Metadata:
      alpha_mode      : 1
Output #0, mp4, to 'video.mp4':
  Metadata:
    encoder         : Lavf60.3.100
  Stream #0:0(eng): Video: vp9 (Profile 0) (vp09 / 0x39307076), yuv420p(tv), 1039x860 [SAR 1:1 DAR 1039:860], q=2-31, 1k tbr, 16k tbn (default)
    Metadata:
      alpha_mode      : 1
Stream mapping:
  Stream #0:0 -> #0:0 (copy)
Press [q] to stop, [?] for help
frame=  580 fps=0.0 q=-1.0 Lsize=    1833kB time=00:00:21.70 bitrate= 691.7kbits/s speed=2.2e+03x
video:1825kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.397173%

Cursor_と_ダウンロード.png

余談1: FFmpeg.wasmについて

理論上FFmpeg.wasmを活用すれば、ブラウザのみでMP4ファイルの出力が可能ですが、実際やってみたら以下の問題が発覚しました。

1、 FFmpeg.wasmを利用するには、該当ページのHEADに下記の記述がないと動きません。

Cross-Origin-Embedder-Policy: require-corp
Cross-Origin-Opener-Policy: same-origin

なので、そこら中のサイトですぐでも録画したいことは出来ないです。

2、FFmpeg.wasmの変換速度が恐ろしく遅いです。
先ほどのvideo.webmをコンソール版のFFmpegで変換する際の速度は、2200倍速でした。実際の所要時間も一瞬でした。
しかしFFmpeg.wasmだと、約0.02倍速でした(つまり1分間の動画を変換するには、50倍の50分間が必要です)。

Cursor_と_FFMPEG_WASM.png

余談2: GIFを出力

FFmpegはGIF画像としての出力も可能ですが、webmファイルから直接変換はできないみたいです。
一回mp4ファイルに変換してから、下記のコマンドで変換すればできます。

ffmpeg -i video.mp4 -r 5 -vf scale=640:-1 video.gif

output3.gif

詳しい設定はこちらの記事を読んでください: FFmpegで動画をGIFに変換

参考

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1