Adroid の Camera2 API と MediaCodec を使って カメラの画像を RTSP で配信する

[Adroid の Camera2 API と MediaCodec を使って カメラの画像をH264形式で転送する](https://qiita.com/ohwada/items/dd69fdd5297e042d237d)

の続きです。

### 概要

前回の記事では、カメラの画像をH264形式で転送した。

今回は、下図のように Android 端末を サーバーにして、RTSP で配信する。

![rtsp_system_overview.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64075/b0646a65-e264-8dfc-e89c-941f2a04c05d.png)


クライアントアプリとしてVLC を使用する。

VLCは、フリーなマルチプラットフォーム対応のマルチメディアプレイヤーです。

参考 [VLC](https://www.videolan.org/vlc/index.ja.html)

### RTSP

RTSP (Real Time Streaming Protocol) は、リアルタイムデータの配信を制御するためのプロトコルです。
リアルタイムデータ自体の配信は RTP (Real-time Transport Protocol) が使用される。


[wikipedia : RTSP](https://ja.wikipedia.org/wiki/Real_Time_Streaming_Protocol)

[wikipedia : RTP](https://ja.wikipedia.org/wiki/Real-time_Transport_Protocol)

### カメラの画像を RTSP で配信する

アプリは大きくRTSPサーバーとRTP配信の２つのブロックに分かれる。

RTP　配信は下図の構成となる。

![rtsp_app_overview.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64075/49a4b70a-44c3-cc1d-95fd-cc996f3f1751.png)


カメラデバイス
- ImageReader
- ImageFormatConverter
- MediaCodec
- Packetizer


カメラデバイスからMediaCodecまでは前回のH264形式と同様です。

RTSPサーバーもRTP配信も、スクラッチから作るのは難儀です。

今回は、両方の機能を持つ libstream を使用する。
libstreaming は、RTP over UDPを使用して、Android端末のカメラやマイクをストリーミングできるAPIです。

 libstream は旧来の Camera API 用にコーデングされているので、
Camera2API 向けに変更する。

[github : libstream](https://github.com/fyhertz/libstreaming)

### RTSPサーバー

RTSP は RFC2326 により標準化されている。

配信を制御するためのメソッドが規定されている。
重要なのは　SETUP　とPLAY の２つ。

SETUPは、下記のように データを受信するクライアントのポートが指定されている。

> SETUP rtsp://example.com/foo/bar/baz.rm RTSP/1.0
> CSeq: 302
> Transport: RTP/AVP;unicast;client_port=4588-4589

PLAY は配信の開始。
SETUPで配信を開始しても、運用上は支障ないようです。
 libstream の実装はそうなっている。


> PLAY rtsp://audio.example.com/audio RTSP/1.0
> CSeq: 835
> Session: 12345678
> Range: npt=10-15


参考 [RFC2326: RTSP](https://tools.ietf.org/html/rfc2326)


### Packetizer

 MediaCodec の出力をRTP形式に変換する。

RTP は、エンコードの種類毎に異なる形式が規定されている。
 libstream には、H264とH263の２つ形式に対応した Packetizer が用意されている。
H264を使用する。

- [H264 : RFC6184](https://tools.ietf.org/html/rfc6184)

- [H263 : RFC 4629](http://pentan.info/doc/rfc/4628.html)

- [VP8 : RFC7741](https://tools.ietf.org/html/rfc7741)


### VLC で受信する


VLC をダウンロードする。

[Download VLC](https://www.videolan.org/vlc/)

Android端末からのビデオストリームを受信する
メニューバーから ファイル ->　ネットワークを開く
URL欄にプロトコルとAndroid端末のIPアドレスとポートを入力する
￥
> rtsp://IPアドレス:ポート/
![vlc_on_mac_open_stream-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64075/14d8bac0-b927-1da7-b8a9-e6c39b5b0d4d.png)


### 画像の大きさ


 画像の大きさによって、現象が異なる。

- SD Low quality( 176x144)

黒い画面になる

![vlc_on_mac_176x144.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64075/2b0b23e8-3482-011d-001f-f27c15673c9d.png)


- QVGA (480x360x240)

黒い画面になる

- SD High quality ( 480x360)

緑の画面になる

![vlc_on_mac_480x360.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64075/f9c13a46-ed71-bf28-5577-39841abb9131.png)

- VGA ( 640x 480 ) 
表示されるが、反応が遅い
カメラの向きを変えてもなかなか反映されない
10秒くらいかかる

- SVGA (800x600)
表示されるが、反応が遅い

- HD (1280x720)
表示されるが、反応が遅い


### オーディオの同時配信


RTPでは、ビデオとオーディオの同時配信ができる。

libstream では、オーディオのエンコードは、MediaRecorderを使用している。

エンコードの種類により、
AMRNB と AAC の２種類が用意されている。
libstreamでデファルトになっている AMRNB を使用する。

[wikipedia : AMRNB](https://ja.wikipedia.org/wiki/Adaptive_Multi-Rate)

[wikipedia : AAC](https://ja.wikipedia.org/wiki/AAC)

[reference : MediaRecorder.AudioEncoder](https://developer.android.com/reference/android/media/MediaRecorder.AudioEncoder.html)


サンプルコードをgithub に公開した。
https://github.com/ohwada/Android_Samples/tree/master/Camera223