Demos:
-
How to try:
- Open demo site with latest Chrome
- "Start Capture"
- "Record Start"
- Wait a moment
- "Record Stop"
- A ".webm" file is written automatically
Requires ffmpeg 4.2 or above.
How to convert:
$ ffmpeg -i 2019-08-14T04_15_29.612Z.webm out.mp4
Check those formats:
$ ffprobe 2019-08-14T04_15_29.612Z.webm
ffprobe version N-94530-g8cd96e13ee Copyright (c) 2007-2019 the FFmpeg developers
built with gcc 9.1.1 (GCC) 20190807
(...snip...)
Input #0, h264, from 'tmp/2019-08-14T04_15_29.612Z.webm':
Duration: N/A, bitrate: N/A
Stream #0:0: Video: h264 (Constrained Baseline), yuv420p(progressive), 300x192, 25 fps, 25 tbr, 1200k tbn, 50 tbc
$ ffprobe out.mp4
ffprobe version N-94530-g8cd96e13ee Copyright (c) 2007-2019 the FFmpeg developers
built with gcc 9.1.1 (GCC) 20190807
(...snip...)
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'tmp/out.mp4':
Metadata:
major_brand : isom
minor_version : 512
compatible_brands: isomiso2avc1mp41
encoder : Lavf58.30.100
Duration: 00:00:09.56, start: 0.840000, bitrate: 20 kb/s
Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p, 300x192, 17 kb/s, 25 fps, 25 tbr, 12800 tbn, 50 tbc (default)
Metadata:
handler_name : VideoHandler
$
Webブラウザによる画面キャプチャーと動画エンコードを実装するための要素は大きくわ けて3つあります。
navigator.mediaDevices.getDisplayMedia()
(以下getDisplayMedia()
)MediaStream
MediaRecorder
getDisplayMedia()
はキャプチャ対象の MediaStream
を返します。その
MediaStream
を MediaRecorder
のコンストラクタに渡すと動画エンコードが始まり
ます。エンコードされたデータは Blob
として MediaRecorder.ondataavailable
を
通じて渡されます。あとはこのデータを単に連結してファイルとして保存すれば、画面
キャプチャーと動画エンコードは完了です。
getDisplayMedia()
は Promise
を返します。この Promise
は MediaStream
と
共に resolve()
されます。getDisplayMedia()
はユーザーにキャプチャする画面を
選択するダイアログが表示し、その選択が確定すると、その画面の MediaStream
と共
に Promise.resolve()
されます。これはユーザーが知らないうちに任意の画面をキャ
プチャすることがないようにとの、セキュリティ上の配慮であると考えられます。
MediaStream
は getDisplayMedia()
から取得できるほかに、<video>
要素や
<canvas>
要素等からも取得できます。そのため動画エンコードの対象は多岐に渡りま
す。
getDisplayMedia()
には以下のようなオプションを指定できます。その定義の詳細は
MediaStreamConstraints を参照してください。ただし getDisplayMedia()
で
は元の画面のサイズに関わらず video.width
及び ``video.heightで指定したサイ ズにフィットした
MediaStream` になります。また `audio` はキャプチャーできませ
ん。
{
"video": { "width": 640, "height": 480 },
"audio": false
}
MediaRecorder
のコンストラクタには MediaStream
を渡します。同時にオプション
を指定する必要がありますが、その定義の詳細は MediaRecorder の options
を
参照してください。特に mimeType
で動画ファイルの形式=コンテナとコーデックを指
定することが重要です。サポートするファイル形式はブラウザによって異なりますが
Chrome に限定すれば以下の3つのいずれかを選択するのが良いでしょう。
video/webm; codecs=h264
video/webm; codecs=vp8
video/webm; codecs=vp9
コンテナはいずれも WEBM 形式で CODEC は H264, VP8 および VP9 です。CODECによる エンコード品質の違いはあまり感じられませんが、いずれも高解像で低周波の画像をう まく扱う傾向があります。裏を返せば低解像で高周波の画像は苦手です。おおざっぱで すが実例でいうとファミコンなどレトロゲームの画面を低解像・高周波、PlayStation4 など最新の3Dを用いたゲームを高解像・低周波と考えてください。
最後に具体的な手順を書き下します。
-
getDisplayMedia()
でMediaStream
を受け取るPromise
を作成する -
Promise.then
もしくはawait
でMediaStream
を受け取る -
MediaStream
からMediaRecorder
を作成する -
MediaRecorder
のondataavailable
およびonstop
にイベントハンドラを設定する動画データの保存方法に応じて異なる実装になる。
-
MediaRecorder.start()
で録画とエンコードを開始する -
MediaRecorder.ondataavailable
が呼び出されBlob
を受け取る別サーバに保存するか、ファイルに書き出すかはアプリ次第。ただしブラウザでは ファイルに書き出せないので、一時的にメモリ上に貯めて
onstop
時に連結して 書き出す必要が出てくる。 -
MediaRecorder.stop()
で録画を停止する -
MediaRecorder.onstop
が呼び出されるので、後始末をする。ファイルへの保存ならば、ここでメモリ上に貯めた
Blob
を連結し、<a>
要素 のhref
へURL.createObjectURL()
を設定してダウンロードさせる。例:let blob = new Blob(chunks, { 'type': 'video/webm' }); let anchor = document.createElement("a"); anchor.download = new Date().toISOString() + ".webm"; anchor.href = URL.createObjectURL(blob); anchor.click();