JavaScriptでWebカメラとマイクを使って音声付きビデオ録画する方法
JavaScriptを使えば、ライブラリ不要でWebカメラとマイクの録画を簡単に実装できます。
本記事では、その方法をサンプルコード付きで解説します。
実装手順
メディアストリームの取得
まず、メディアストリームを取得するためにnavigator.mediaDevices.getUserMediaメソッドを使用します。
このメソッドは、ユーザーのカメラとマイクにアクセスするための許可を求めます。
ただし、iOS(iPhone)に対応するには「click」イベントでnavigator.mediaDevices.getUserMediaメソッドを呼び出す必要があります。
<button id="start" onclick="startRecording()">録画開始</button> <script> let chunks, recorder, mediaStream; function startRecording(){ chunks=[]; navigator.mediaDevices.getUserMedia( { audio:true, video:{facingMode:"user", width:320, height:240} } ).then( function(stream){ mediaStream = stream; //ストリームからメディアレコーダーを作成する recorder = new MediaRecorder(stream); recorder.ondataavailable = function(el){ //録音録画データが届いたら配列変数 chunks に追加保存する if (el.data.size>0){ chunks.push(el.data); } } recorder.onstop = onStop; //録画の開始(1000ミリ秒録画される毎にdataavailableイベントが発生) recorder.start(1000); } ); } </script>
録画停止ボタンの設置
録画停止のボタンを設置します。録画停止ボタンクリック時のJavascriptを記述します。
<button id="stop" onclick="endRecording()">録画停止</button> <script> function endRecording(){ if(recorder){ recorder.stop(); } } </script>
録画が停止された時にstopイベントが発生するのでその時に実行するonStop関数のJavavscriptを記述します
録画停止のボタンが押されたら、recorderのstopイベント発生するのでその関数onStopを記述します。
chunks 配列変数に記録されているビデオ録画データを処理します。
<video id="video" playsInline controls></video> <script> //録画停止時に呼び出される関数 function onStop(){ //停止時の処理を行う //録画データが無かったら何もしないで関数を抜ける if (!chunks.length){return;} let obj=new Blob(chunks, {type:recorder.mimeType}); let v=document.getElementById("video"); v.src=URL.createObjectURL(obj); } </script>
実際のサンプル
ソースコード
このソースコードを使えば、1秒ごとに録画データを保存し、録画した動画をそのまま再生したり、ファイルとしてダウンロードすることができます。
<button id="start" onclick="startRecording()">録画開始</button><br> <button id="stop" onclick="endRecording()" disabled>録画停止</button><br> <video id="video" playsInline controls></video><br> <a id="a"></a> <script> let chunks, recorder, mediaStream; function startRecording(){ chunks=[]; navigator.mediaDevices.getUserMedia({audio:true, video:{facingMode:"user",width:320,height:240}}).then( function(stream){ mediaStream=stream; document.querySelector("#stop").removeAttribute("disabled"); document.querySelector("#start").setAttribute("disabled",""); recorder = new MediaRecorder(stream); recorder.ondataavailable = function(el){ //録画データを配列に保存する if (el.data.size>0){ chunks.push(el.data); } } recorder.onstop = onStop; //1000ミリ秒録画されるごとにdataavailableイベントが発生 recorder.start(1000); } ).catch( function(e){ console.log(e); } ); } function endRecording(){ if(recorder){ recorder.stop(); //ストリームを解放 if (mediaStream) { mediaStream.getTracks().forEach(function(track){ track.stop(); }); mediaStream = null; } } } function onStop(){ if (!chunks.length){return;} document.querySelector("#stop").setAttribute("disabled",""); document.querySelector("#start").removeAttribute("disabled"); let obj=new Blob(chunks,{type:recorder.mimeType}); let a=document.getElementById("a"); let v=document.getElementById("video"); // 古いURLを解放(メモリリーク防止) if (v.src) URL.revokeObjectURL(v.src); if (a.href) URL.revokeObjectURL(a.href); a.href=URL.createObjectURL(obj); if(recorder.mimeType.match(/x-matroska/)){ a.download="test.mkv"; }else if(recorder.mimeType.match(/mp4/)){ a.download="test.mp4"; }else if(recorder.mimeType.match(/mpg/)){ a.download="test.mpg"; }else{ a.download="test.webm"; } a.innerHTML="ダウンロード("+a.download+")"; v.src=URL.createObjectURL(obj); recorder = null; } </script>
