サマリ
ブラウザでアクセスするだけで、Webcamの動画ストリーミングにアクセスできるツールを作成しました。任意のタイミングでキャプチャし、PNG画像として保存することもできます。
成果物
こちらにアクセスするだけで使えます。ソースコードもOSSでどうぞ。
開発モチベーション
日頃開発をしていると、机の上の状況をPC上で画像として貼り付けたくなる事が多々あります。当然スマホで撮影することが多いのですが、PC側で扱うにはクラウドサービスを経由したり、Directな無線通信やケーブルで接続したりと転送に少し手間がかかります。
そんな時Webcamが常設されている環境であればキャプチャが出来るはずですが、気軽にキャプチャできるツールが無かったので、作成した次第です。
使い方
- PCにWebcamを接続します。
- このツールを開いてください. Google Chromeを強く推奨します。
- 自動的に以下のダイアログがでてくるので、カメラを使うことを許可してください。(「許可」を押します。)

SWのポイント
HTML5 ビデオストリーミングの開始
10数行で実現出来る。いい世の中になりまりました。
<video autoplay="true" id="video"></video>
// On Streaming
const startStreamingVideo = () => {
const video = document.querySelector( "#video" );
if( navigator.mediaDevices.getUserMedia ){
navigator.mediaDevices.getUserMedia( { video: true } )
.then( ( stream ) => {
video.srcObject = stream;
} );
}
}
startStreamingVideo();
静止画のキャプチャ
少しトリッキーな事をしています。
CAPUTRE
ボタンが押されたら、見えないcanvas
にその時点のデータを描画します。その後canvas
の内容をDataURL形式に変換しlink
と紐付け、ダウンロード可能にした状態で最後にlink
をclick()
します。
このあたりは、こちらの記事を参考にさせていただきました。
<div id="hiddenContainer">
<a id="hiddenLink"></a>
<canvas id="hiddenCanvas" width="500" height="375"></canvas>
</div>
const btCapture = document.getElementById( 'btCapture' );
btCapture.addEventListener( 'click', () => {
// Capture: draw to hidden canvas
const hiddenCanvas = document.getElementById( 'hiddenCanvas' );
const ctx = hiddenCanvas.getContext('2d');
const WIDTH = 500;
const HEIGHT = 375;
ctx.drawImage( video, 0, 0, WIDTH, HEIGHT );
// Download: load DataURL and convert to png
const link = document.getElementById( 'hiddenLink' );
link.href = hiddenCanvas.toDataURL();
// document.getElementById('hiddenCanvas').src = hiddenCanvas.toDataURL();
link.download = getYYYYMMDD_hhmmss( true ) + ".png";
link.click();
});
btCapture.disabled = false;
JavascriptでYYYYMMDD_hhmmss
なんか毎回こんな関数をつくっているような気がしますが、今回は下記の通りで実装。
こちらを参考にさせていただきました。
const getYYYYMMDD_hhmmss = ( isNeedUS ) => {
const now = new Date();
let retVal = '';
// YYMMDD
retVal += now.getFullYear();
retVal += padZero2Digit( now.getMonth() + 1 );
retVal += padZero2Digit( now.getDate() );
if( isNeedUS ){ retVal += '_'; }
// hhmmss
retVal += padZero2Digit( now.getHours() );
retVal += padZero2Digit( now.getMinutes() );
retVal += padZero2Digit( now.getSeconds() );
return retVal;
}
// padding function
const padZero2Digit = ( num ) => {
return ( num < 10 ? "0" : "" ) + num;
}
所感と考察
- Videoデータの取り扱い、楽になったものだなぁ。
-
Captureした後のデータサイズは決め打ちにしてしまっているのですが、videoのMAX解像度を知ることができると画像もキレイに保存できて良いなと。ただ、ちょっと調べたくらいでは出来なかったので今回は断念しています。Version1.1.0で解消しました。単にWidth/Heightをこちらで指定してしまっているのが原因でした。指定がなければブラウザ側でよきに計らってサイズ設定されました。(2020/2/16追記) - 今回の本筋とは関係ないのですが、本ツールはVSCodeのLiveServerを使って実装しました。めちゃめちゃ楽でQoD爆上がり。詳しくはこちらの記事をどうぞ。
追記(20200216)
Version 1.1.0および1.2.0をリリースしました。1.2.0の機能については別途記事書きます。
1.1.0では、下記の機能を追加しています。
- iOS(Safariのみ)からも使えるように。
- リア/フロント カメラの切り替え
iOSで使えるように
残念ながら本日(20200216)時点ではChromeでは非対応で、Safariでしか確認できませんが、iOSでも動作するようになりました。具体的には、iOSでautoplayとするには下記のようにplaysinline
及びmuted
を入れる必要がありました。これで自動再生できるようになりました。
<video playsinline muted autoplay id="video"></video>
リア/フロントカメラの切り替え
そもそも何も設定しないとセルフィ―スタイルの方のカメラ(facingMode: user)しか起動せず困っていたので、初期設定を外側を向いているカメラ(facingMode: environment)との切り替えを用意しました。
解決方法は簡単で、getUserMedia
したときの引数に、facingMode: environment
などを指定してあげるだけで終了です。
// Camera facing mode = flip mode
const FACING_MODE_ENVIRONMENT = "environment";
const FACING_MODE_USER = "user";
let gCurrentCameraFacingMode = FACING_MODE_ENVIRONMENT;
navigator.mediaDevices.getUserMedia(
{ video: { facingMode: gCurrentCameraFacingMode } }
)
// Flip Cmera
filpCameraElem.addEventListener( "click", async ev => {
switchCamera();
});
// Flip camera
const switchCamera = () => {
if( gCurrentCameraFacingMode === FACING_MODE_ENVIRONMENT ){
gCurrentCameraFacingMode = FACING_MODE_USER;
}else{
gCurrentCameraFacingMode = FACING_MODE_ENVIRONMENT;
}
startStreamingVideo();
}