HTML5Experts.jp

カメラを使ってみよう ーWebRTC入門2016

連載: WebRTC入門2016 (1)

こんにちは! がねこまさしです。2014年に連載した「WebRTCを使ってみよう!」シリーズですが、内容がすっかり古くなってしまいました。そこで2016年6月の最新情報に基づき、内容をアップデートして改めてお届けしたいと思います。

WebRTCとは?

WebRTCとは”Web Real-Time Communication”の略で、Webブラウザ上でビデオ/オーディオの通信や、データ通信を行うための規格です。HTML5で新しく策定されたもので、複数の技術の連携で成り立っています。 ちなみに策定には複数の団体が絡んでいています。

APIの策定作業はWebRTC 1.0に向けて大詰めに入っています。またより詳細な低レベルのAPIを定義しているORTCも登場し、将来の統合に向けた動きも始まっています。

コーデックの選定では、ブラウザがサポートしなければならないビデオコーデックに、既にデファクトスタンダードともいえるH.264が加わりました。また、Googleが開発しているオープンソースのビデオコーデック「VP9」をサポートするブラウザも増えています。

WebRTCで何ができるの?

WebRTCは厳密に言うとビデオ/オーディオ/データ通信を行うための仕組みですが、他にも関連が深い技術があります。この連載では3つをまとめてWebRTC(とその仲間たち)ということで扱います。

この3兄弟に、HTML5の様々な要素を組み合わせて活用することができます。

新しいAPIでカメラを使ってみよう

カメラやマイクと言ったデバイスにアクセスするには、従来はnavigator.getUserMedia()というAPIを使いました。2016年6月現在では、これに代わる新しいAPIが登場しています。

またデスクトップブラウザの場合は次のブラウザで利用することができます。

サンプルコード

それではカメラから映像を取得してみましょう。サンプルコードはこちらです。

<!doctype html>
<html>
<head>
 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
 <title>Camera with mediaDevice</title>
</head>
<body>
  <button onclick="startVideo()">Start</button>
  <br />
  <video id="local_video" autoplay style="width: 320px; height: 240px; border: 1px solid black;"></video>
</body>
<script type="text/javascript">
  let localVideo = document.getElementById('local_video');
  let localStream;

// start local video function startVideo() { navigator.mediaDevices.getUserMedia({video: true, audio: false}) .then(function (stream) { // success localStream = stream; localVideo.src = window.URL.createObjectURL(localStream); }).catch(function (error) { // error console.error('mediaDevice.getUserMedia() error:', error); return; }); } </script> </html>

このHTMLファイルに、(Webサーバ経由で)ブラウザからアクセスしてみてください。GitHub Pagesでも公開していますので、すぐに試すことができます。

ブラウザで[Start]ボタンをクリックすると、カメラへのアクセスの許可を求めるダイアログが表示されますので、許可してください。
Firefoxの場合

Chromeの場合

Edgeの場合

ウィンドウの下の部分にこのように表示されます。他のブラウザと違うので、ちょっと気が付きにくいかもしれません。

すると、このようにカメラの映像が表示されるはずです。

HTMLファイルの置き場所

カメラやマイクにアクセスするには、サンプルのHTMLファイルをWebサーバーに配置する必要がありますが、実はブラウザによって条件が異なります。

FirefoxやEdgeの場合は、ローカルのHTMLファイルを直接読み込んでも、利用可能です。

トラブルシューティング

カメラのアクセスの許可を求められた際に「常に拒否」すると、そのサイトからはカメラの映像を取得することができなくなります。その場合は明示的に再許可してあげる必要があります。

Firefoxの場合で「許可」または「毎回確認する」を選択

Chromeの場合「常に許可する」を選択

Edgeの場合
※いまのところ「常に拒否」することはできないようなので、このケースは発生しません。

新旧 getUserMedia() をラップしてみると

新しいAPIである navigator.mediaDevices.getUserMedia()は、まだChromeではデフォルトの状態では使えません。これは、引数で渡すオプションの指定方法が、まだ新しい書き方に沿っていないことが原因です。

let deviceID = getSelectedIDsomehow(); // デバイスIDを指定する

// Firefoxの場合 let constraints = { audio: false, video: { deviceId: {exact: deviceID} } };

// Chromeの場合 let constraintsForChrome = { audio: false, video: { optional: [{sourceId: deviceID}] } };

そのため、Chromeではしばらく新しいAPIはデフォルトでは使えない状態が続くと思われます。そこで古いAPIをPromise型にラップする例を用意してみました。(オプション指定の違いは吸収できていません)

  // --- prefix -----
  navigator.getUserMedia  = navigator.getUserMedia    || navigator.webkitGetUserMedia ||
                            navigator.mozGetUserMedia || navigator.msGetUserMedia;

// ---- 新旧APIをPromiseでラップする ---- function getDeviceStream(option) { if ('getUserMedia' in navigator.mediaDevices) { console.log('navigator.mediaDevices.getUserMadia'); return navigator.mediaDevices.getUserMedia(option); } else { console.log('wrap navigator.getUserMadia with Promise'); return new Promise(function(resolve, reject){
navigator.getUserMedia(option, resolve, reject ); });
} }

// 利用例 function startVideo() { getDeviceStream({video: true, audio: false}) .then(function (stream) { // success localStream = stream; localVideo.src = window.URL.createObjectURL(localStream); }).catch(function (error) { // error console.error('getUserMedia error:', error); return; }); }

これを使ってカメラ映像を取得する例もご用意しました。Chrome 51でもデフォルトのままで利用できます。

様々なWebRTC関連のブラウザの違いを吸収する adapter.js本家のGitHubで公開されています。より便利に使いたい場合は、そちらをご利用ください。

CSS3と組み合わせてみよう

WebRTCは他の要素と組み合わせて使うことができると書きました。実際にCSS3と組み合わせてみましょう。

  <!-- 通常 -->
  <video id="local_video" autoplay style="width: 320px; height: 240px; border: 1px solid black;"></video>

<!-- 左右反転 --> <video id="flip_video" autoplay style="transform: scaleX(-1); width: 320px; height: 240px; border: 1px solid black;"></video>

<!-- 角丸 --> <video id="round_video" autoplay style="border-radius: 80px 80px 80px 80px; width: 320px; height: 240px; border: 1px solid black;"></video>

<!-- セピア --> <video id="filter_video" autoplay style="filter: sepia(100%); -webkit-filter: sepia(100%); width: 320px; height: 240px; border: 1px solid black;"></video>

ほかにも様々なバリエーションが考えられます。ぜひ自分でもいろいろ試してみてください。

また、CSS3アニメーションを使うこともできます。例えばこんな感じです。

<!doctype html>
<html>
<head>
 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
 <title>Camera with mediaDevice</title>
 <style type="text/css">
   #rotate_video
   {
    animation-duration:4s;
    animation-iteration-count:infinite;
    animation-timing-function:linear;
    animation-name:rotate360;
}

#shake_video { animation-duration:0.5s; animation-iteration-count:infinite; animation-timing-function:ease-in-out; animation-name:shake;
}

@keyframes rotate360 { 0%{transform:rotate(0deg);} 100%{transform:rotate(360deg);} }

@keyframes shake { 0%{transform:rotate(-20deg);} 50%{transform:rotate(20deg);} 100%{transform:rotate(-20deg);} } </style> </head> <body> Camera with mediaDevice.getUserMedia()<br /> <button onclick="startVideo()">Start</button> <br /> <!-- 通常 --> <video id="local_video" autoplay style="width: 320px; height: 240px; border: 1px solid black;"></video> <br />

<!-- 回転アニメーション --> <video id="rotate_video" autoplay style="width: 320px; height: 240px; border: 1px solid black;"></video>

<!-- 振動アニメーション --> <video id="shake_video" autoplay style="width: 320px; height: 240px; border: 1px solid black;"></video>

</body> <script type="text/javascript"> // --- prefix ----- navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;

let localVideo = document.getElementById('local_video'); let localStream;

// start local video function startVideo() { getDeviceStream({video: true, audio: false}) .then(function (stream) { // success localStream = stream; localVideo.src = window.URL.createObjectURL(localStream);

  document.getElementById('rotate_video').src = localVideo.src;
  document.getElementById('shake_video').src = localVideo.src;
}).catch(function (error) { // error
  console.error('mediaDevice.getUserMedia() error:', error);
  return;
});

}

// ---- 新旧APIをPromiseでラップする ---- function getDeviceStream(option) { if ('getUserMedia' in navigator.mediaDevices) { console.log('navigator.mediaDevices.getUserMadia'); return navigator.mediaDevices.getUserMedia(option); } else { console.log('wrap navigator.getUserMadia with Promise'); return new Promise(function(resolve, reject){
navigator.getUserMedia(option, resolve, reject ); });
} } </script> </html>

CSS3と組み合わせたサンプルも、GitHub Pagesでも公開していますので、試してみてください。(ラップ関数を使っているので、デフォルトのChrome 51でも利用できます)

次回は

今回は新しいAPIを使って、カメラの映像を取得してみました。次回はWebRTCによる通信を手動で接続してみます。