Webカメラ"Qwatch TS-WLCAM"をUWPアプリケーションから扱ってみた

手元にIO-Dataから発売されていたWebカメラ"Qwatch TS-WLCAM"があったので、これをUWPアプリケーションから映像及びスナップショット画像を取得してみたので、備忘録的にここに記す。

##Qwatch TS-WLCAMについて
- [製品ページ](http://www.iodata.jp/product/lancam/lancam/ts-wlcam/index.htm)
- 無線LAN/有線LANに対応
- 映像はMJPEG形式取得可能
- Webサーバ機能が内蔵されており、HTTPリクエストで映像、スナップショット画像が取得できる。
 - 映像の取得 : http://[QwatchのIPアドレス]/snapshot.cgi
 - スナップショット画像の取得 : http://[QwatchのIPアドレス]/snapshot.jpg

##準備
UWPアプリケーションでQwatchの映像／画像を扱うには、
[Media Reader](http://mmaitre314.github.io/MediaReader/)が必要になるので、あらかじめプロジェクトに[NuGet](https://www.nuget.org/packages/MMaitre.MediaCaptureReader/)で追加しておく。
MJPEGを扱うには、以前は[MJPEG Decoder](https://github.com/BrianPeek/mjpeg)が定番で、ググるとこちらで試されているケースが多く出てくるのだが、Windows 10 UWPアプリケーションには対応しておらず、NuGetで追加すらできない。現状、Windows 10 UWPアプリケーションでは、上記Media Readerぐらいしかないのではないかと思う。

##映像の取得と表示
UWPアプリケーションで、QwatchのMJPEG映像を表示するには、MediaElementコントロールを使う。あらかじめコントロールを配置して名前を"mediaElement"とでもしておく。以下のコードで、MediaElementにQwatchから取得したMJPEG映像を表示することができる。
アプリケーションを起動して以下のコードを実行すると、初回接続時にユーザー名とパスワードが求められるので、Qwatchの設定で登録したユーザー名とパスワードを入力する。（これを回避可能か不明。まだ試していない）

```sample.xaml.cs
using MediaCaptureReader;

string webcamUri = "http://[QwatchのIPアドレス]/snapshot.cgi";
HttpMjpegCaptureSource client = await HttpMjpegCaptureSource.CreateFromUriAsync(webcamUri);
mediaElement.SetMediaStreamSource(client.Source);
```

##スナップショット画像の取得と表示
つづいて、映像を表示するだけでなく、適時に映像をスナップショットで取得して、画像加工やComputer Visionなどで画像解析をするためにスナップショット画像を取得してみたい。

UWPでは、RenderTargetBitmapの[RenderAsync](https://social.technet.microsoft.com/wiki/contents/articles/20648.using-the-rendertargetbitmap-in-windows-store-apps-with-xaml-and-c.aspx)を使ってコントロールの表示内容を画像データとして取得する以下のコードのような方法があるが、MediaElementは著作権的な制限により真っ黒な画像となり表示された映像を取得することができない。

```renderTargetBitmap.xaml.cs
var bitmap = new RenderTargetBitmap();
await bitmap.RenderAsync(elementToRender);
image.Source = bitmap;
```

そこで、今回はQwatchのスナップショット画像取得を行うAPIを使ってみる。このAPIは上記の通りsnapshot.jpgを取得すれば良いのだが、このときDigest認証が必要になる。認証無しだと、初回接続時に、映像取得と同じようにユーザー名とパスワードを求められる。

そこで以下のようにsnapshot.jpgを取得する際に、httpClientにDigest認証のためのハンドルを設定しておくと、ユーザー名とパスワードを手入力しなくて済む。以下のコードでは、取得したデータ"data"(Byte[]形式）をビットマップにしてimageコントロールに表示している。

```sample.xaml.cs
using System.Net.Http;

var uri = "http://「QwatchのIPアドレス]/snapshot.jpg";
var credCache = new CredentialCache();
credCache.Add(new Uri(uri), "Digest", new NetworkCredential("Qwatchの登録ユーザー名", "パスワード"));
var HttpHandler = new HttpClientHandler();
HttpHandler.Credentials = credCache.GetCredential(new Uri(uri), "Digest");

HttpClient httpclient = new HttpClient(HttpHandler);
var data = await httpclient.GetByteArrayAsync(uri);

MemoryStream mStream = new MemoryStream(data);
BitmapImage bitmapImage = new BitmapImage();
await bitmapImage.SetSourceAsync(mStream.AsRandomAccessStream());
image.Source = bitmapImage;
```

取得したデータ"data"(Byte[]形式）を、さらにhttpClientでPOSTしてやれば、例えばMicrosoft Cognitive ServicesのComputer VisionやCustom Vision ServiceのAPIに投げられるので、Webカメラに映った画像を定期的に画像解析するなんてことも可能になる。

##参考資料
- [Qwatch TS-WLCAM 製品ページ](http://www.iodata.jp/product/lancam/lancam/ts-wlcam/index.htm)
- [Media Reader](http://mmaitre314.github.io/MediaReader/)
- [参考にしたstackoverflowの記事 : Digest authentication in Windows Store app using HttpClient (C#)](https://stackoverflow.com/questions/30240556/digest-authentication-in-windows-store-app-using-httpclient-c)