ラズパイカメラから NDI 送信してみた。(※ Raspberry Pi 4 に対応！実用的になりました)

こんにちは。野良ハックチーム ざっきーと申します。

※ 2020 年 4 月 29 日更新
2020 年 GW アドベントカレンダー「配信系」の記事を兼ねて Raspberry Pi 4 Model B に対応するため、内容を更新しました。

IoTLT ひとつめ！ Advent Calendar 2018 の 4 日目を担当します。
IoTLT 放送部員としての歩みを書き残して年を越したいと思います。

## IoTLT 放送部とは
IoTLT vol.42 @ ナビタイムで IoTLT 放送部の部長、IoT・設備制御系・YouTuber「なかちょん」こと、中畑隆拓さんが勝手にぶち上げた部活動です。

「なかちょん」のYouTubeチャネルはこちら。
https://www.youtube.com/nakachon

その時のLT資料はこちら。
https://www.slideshare.net/nakachong/iotlt-110645853

普段は Facebook グループで活動しています。
やってみたい方、興味がある方は誰でもウェルカムです！是非、お気軽に申請を！
https://www.facebook.com/groups/1357384727725773/

これまで IoTLT では参加者は Tweet をメインとして参加し、Togetter で情報をまとめたり、登壇者が LT 資料を connpass のページへアップするスタイルですが、

- 行きたくても行けないときがある、、
- 過去の発表を調べたい、、スライドはあるけど・・

というニーズに応えるべく、YouTube 配信＆アーカイブを開始することになりました！

## IoTLT の YouTube チャネル
実は以前から IoTLT の YouTube チャネルは存在していたのですが、
IoTLT vol.30 @ DMM の動画がアーカイブされているだけで有効活用されていない状態でした。
IoTLT の YouTube チャネルはこちら。
https://www.youtube.com/channel/UCE8qgjhgQVEdxmVa6hIAieA/
IoTLT YouTube チャネルの紹介動画はこちら。
https://www.youtube.com/watch?v=djKPVg1LMB4
IoTLT vol.41 @ 富士通クラウドテクノロジーズから活動を開始し、2018 年 11 月 29 日時点で <FONT COLOR="#FF0000"><B>20</B></FONT> 回の配信を行いました！

- <A HREF="https://www.youtube.com/channel/UCE8qgjhgQVEdxmVa6hIAieA/">「 IoTLT 」チャネル</A>

| No. | 日付 | 勉強会 |
|---|---|---|---|
| 1 | 2018/7/30 | IoTLT vol.41 |
| 2 | 2018/8/27 | SIerIoTLT vol.11 |
| 3 | 2018/9/11 | Healthcare IoTLT vol.4 |
| 4 | 2018/9/26 | Control IoTLT vol.1 |
| 5 | 2018/10/5 | SIerIoTLT vol.12 |
| 6 | 2018/10/15 | AIoTLT vol.2 |
| 7 | 2018/10/22 | IoTLT vol.44 |
| 8 | 2018/10/30 | AIoTLT ハンズオン |
| 9 | 2018/11/6 | エンタープライズ IoTLT vol.14 |
| 10 | 2018/11/12 | VUILT vol.7 |
| 11 | 2018/11/16 | Control IoTLT vol.2 |
| 12 | 2018/11/27 | obniz x M5Stack x NefryBT 三つ巴 meetup！【ESP32開発ボードLT祭】|
| 13 | 2018/11/29 | IoTLT vol.45 |

- <A HREF="https://www.youtube.com/nakachon">「なかちょん」チャネル</A>

| No. | 日付 | 勉強会 |
|---|---|---|
| 1 | 2018/8/10 | RPALT vol.4 with Tech Night！ |
| 2 | 2018/9/27 | enebular developer Meetup vol.3 |
| 3 | 2018/9/28 | RPALT vol.5 |
| 4 | 2018/10/25 | enebular developer Meetup vol.4 |

- <A HREF="https://www.youtube.com/channel/UCeTHNNe9_kfz9AglUja_j-A">「ざっきー」チャネル

| No. | 日付 | 勉強会 |
|---|---|---|
| 1 | 2018/8/20 | IoTLT vol.42  |
| 2 | 2018/11/22 | enebular developer Meetup vol.5 |
| 3 | 2018/11/28 | Node-RED UG勉強会 2018 年末LTパーティ|

動画編集、字幕作成、翻訳、動画の案内もやりたいと考えていますが、まだできていません。。(´・ω・`)

## 配信機材と身についた (かもしれない？！) スキル
普段は PC(Mac または Windows) へ USB 接続したウェブカメラで撮影し、OBS Studio というソフトウェアから YouTube へ配信しています。
ズーム機能が付いて画質が良いビデオカメラを PC へ接続するために AverMedia の Live Gamer Portable 2 (AVT-C878) を使用しています。この製品は ゲームプレイをライブ配信するための HDMI ゲームキャプチャー ですが、遅延が少ないのと USB 2.0 にも対応しているので使用しています。PC を HDMI 入力へ接続すれば PC 画面も配信可能ですが、Mac と iPhone / iPad は HDCP というコピーガードが掛かっているため、ツール (Mac の場合は LGP2 Setup tool、Windows の場合は RECentral) を使用して HDCP 検出機能をオフにする必要があるので注意です。(Windows とラズパイの画面はそのままでも OK。)
また、<A HREF="https://github.com/Palakis/obs-ndi/releases">OBS-NDI</A> というプラグインを使用すれば、ネットワークを介して他の PC の映像を中継して配信することも可能です。

![IoTLT放送部.png](https://qiita-image-store.s3.amazonaws.com/0/72479/156d5441-0f62-a86d-2adf-d7e53ca93cb6.png)

- RTMP : Real Time Messaging Protocol
Adobe 社が開発している Adobe Flash プレーヤーとサーバーの間で、音声・動画・データをやり取りするストリーミングのプロトコル。

- OBS Studio : <A HREF="https://obsproject.com/ja">Open Broadcaster Software</A>
OBS Project が開発保守しているレコーディングとライブストリーミングに特化したフリー・オープンソースソフトウェア。

- HDCP : High-bandwidth Digital Content Protection
映像再生機器からディスプレイなどの表示機器にデジタル信号を送受信する経路を暗号化し、コンテンツが不正にコピーされるのを防止する著作権保護技術 (コピーガード) のひとつ。

- NDI: Network Device Interface
NewTek 社によって開発された複数の映像システムを IP ネットワークを介して双方向にやり取りすることができ、リアルタイムに大量の高品質、低遅延かつ高フレーム精度でエンコードし、ビデオ制作ワークフロー支援プロトコル。SDK が無償で配布されています。

## ラズパイカメラから YouTube 配信
ラズパイのカメラは USB 接続のウェブカメラを使用することができるが、CSI-2 (Camera Serial Interface) コネクタに接続するカメラモジュールを使用した。

- 機器
 - Raspberry Pi 3
 - Raspberry Pi 3 Model B+

- OS
 - Raspbian stretch with Desktop (Release 9.6)

- カメラモジュール
 - Raspberry Pi Camera v1.3

カメラモジュールを使用するためには raspi-config コマンドで有効化する必要がある。

```bash
$ sudo raspi-config
```

![スクリーンショット 2018-11-26 15.20.59.png](https://qiita-image-store.s3.amazonaws.com/0/72479/9d6ebd4e-20e9-3897-1071-12e817777f00.png)

![スクリーンショット 2018-11-26 15.21.14.png](https://qiita-image-store.s3.amazonaws.com/0/72479/211b4063-1519-d26b-d556-755f00b08c19.png)

YouTube 配信には raspivid コマンド と ffmpeg コマンドを使用する。最後の [ストリームキー] は YouTube ライブストリーミング管理画面から情報を取得する。

```bash
$ raspivid -o - -t 0 -vf -hf -fps 25 -b 500000 | ffmpeg -re -ar 44100 -ac 2 -acodec pcm_s16le -f s16le -ac 2 -i /dev/zero -f h264 -i - -vcodec copy -acodec aac -ab 128k -g 50 -s 640x320 -strict experimental -f flv rtmp://a.rtmp.youtube.com/live2/[ストリームキー]
```

![Screenshot_2018-11-26 ライブ ダッシュボード - YouTube.png](https://qiita-image-store.s3.amazonaws.com/0/72479/b73c94ea-50c4-cb4d-92f8-c9004e194d7d.png)

※ 使用した OS には ffmpeg が既にインストールされていたため、インストール等の作業は行なっていないが、もし ffmpeg コマンドが見つからないエラーが出る場合は以下のコマンドでインストールする。

```bash
$ sudo apt update
$ sudo apt install ffmpeg
```

※ USB 接続のウェブカメラを使用する場合は ffmpeg コマンドのみでライブ配信可能。使用するウェブカメラにマイクが付いている場合は音声含めて配信されるが、モノラルマイクとステレオマイクで ffmpeg コマンドの引数が異なるので注意。
(Logicool C270 などのモノラルマイクの場合は -ac 1、BUFFALO BSW20KM11 などのステレオマイクの場合は -ac 2。)

```bash
$ ffmpeg -f v4l2 -f alsa -ac 2 -thread_queue_size 4096 -i hw:1 -i /dev/video0 -s 640x360 -r 20 -vcodec h264 -acodec aac -g 50 -strict experimental -f flv rtmp://a.rtmp.youtube.com/live2/[ストリームキー]
```

## ラズパイカメラから NDI 送信
やっと本題です。FFmpeg 3.4 で NDI をサポートしたというニュースを見つけて試してみることにしました。
ニュース記事はこちら。
https://www.newtek.com/blog/ffmpeg-3-4-adds-ndi-io/
ただ、使用した OS にインストールされている ffmpeg のバージョンは 3.2.10-1 で 残念ながら NDI を使用することができません。

```bash
$ ffmpeg -version
ffmpeg version 3.2.10-1~deb9u1+rpt2 Copyright (c) 2000-2018 the FFmpeg developers
built with gcc 6.3.0 (Raspbian 6.3.0-18+rpi1+deb9u1) 20170516
configuration: --prefix=/usr --extra-version='1~deb9u1+rpt2' --toolchain=hardened --libdir=/usr/lib/arm-linux-gnueabihf --incdir=/usr/include/arm-linux-gnueabihf --enable-gpl --disable-stripping --enable-avresample --enable-avisynth --enable-gnutls --enable-ladspa --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libcdio --enable-libebur128 --enable-libflite --enable-libfontconfig --enable-libfreetype --enable-libfribidi --enable-libgme --enable-libgsm --enable-libmp3lame --enable-libopenjpeg --enable-libopenmpt --enable-libopus --enable-libpulse --enable-librubberband --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libssh --enable-libtheora --enable-libtwolame --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx265 --enable-libxvid --enable-libzmq --enable-libzvbi --enable-omx-rpi --enable-mmal --enable-openal --enable-opengl --enable-sdl2 --enable-libdc1394 --enable-libiec61883 --arch=armhf --enable-chromaprint --enable-frei0r --enable-libopencv --enable-libx264 --enable-shared
libavutil      55. 34.101 / 55. 34.101
libavcodec     57. 64.101 / 57. 64.101
libavformat    57. 56.101 / 57. 56.101
libavdevice    57.  1.100 / 57.  1.100
libavfilter     6. 65.100 /  6. 65.100
libavresample   3.  1.  0 /  3.  1.  0
libswscale      4.  2.100 /  4.  2.100
libswresample   2.  3.100 /  2.  3.100
libpostproc    54.  1.100 / 54.  1.100
```

そこで、以下の記事を参考にして NDI に対応した ffmpeg をビルドすることにしました。

- <A HREF="https://www.kaoriya.net/blog/2017/10/07/">Raspberry Pi 3 のハードウェアエンコーダーを使う ffmpeg のビルドのしかた</A>

まず、ffmpeg をビルドするのに必要な依存ライブラリやツール類をインストールするため、ソースパッケージを有効化する。

```text:/etc/apt/sources.list
deb http://raspbian.raspberrypi.org/raspbian/ stretch main contrib non-free rpi
# Uncomment line below then 'apt-get update' to enable 'apt-get source'
#deb-src http://raspbian.raspberrypi.org/raspbian/ stretch main contrib non-free rpi
```

↓ (最後の行をコメントインする。)

```text:/etc/apt/sources.list
deb http://raspbian.raspberrypi.org/raspbian/ stretch main contrib non-free rpi
# Uncomment line below then 'apt-get update' to enable 'apt-get source'
deb-src http://raspbian.raspberrypi.org/raspbian/ stretch main contrib non-free rpi
```

apt コマンドを実行して依存ライブラリやツール類をインストールする。

```bash
$ sudo apt update
$ sudo apt build-dep ffmpeg
```

次に NDI SDK をダウンロードしてライブラリを配置する。使用する機器によって配置するライブラリが異なるので注意。
(NewTek 社のホームページから NDI SDK をダウンロードには登録が必要だが、登録後に送られてくるメールに記載されているダウンロード用の URL を記載する。)

```bash
$ mkdir NDI
$ cd NDI
$ wget http://new.tk/NDISDKLINUX
$ mv NDISDKLINUX InstallNDISDK_v3_Linux.sh
$ sh InstallNDISDK_v3_Linux.sh
$ sudo mkdir /usr/include/ndi
$ sudo cp NDI\ SDK\ for\ Linux/include/* /usr/include/ndi/
$ sudo cp -r NDI\ SDK\ for\ Linux/lib/armv8-rpi3-linux-gnueabihf/* /usr/lib/
```

次に ffmpeg のソースコードを取得します。

```bash
$ git clone https://git.ffmpeg.org/ffmpeg.git
```

最後にビルドします。ビルドは時間が掛かる (Raspberry Pi 3 Model B+ の場合で 30 分くらい) ので気長に待ちます。(・ω・)

```bash
$ cd ffmpeg
$ ./configure --enable-nonfree --enable-libndi_newtek --extra-cflags="-I/usr/include/ndi/" --extra-ldflags="-L/usr/include/ndi/" --enable-libx264 --enable-gpl
$ make
```

無事にビルドが完了したら raspivid コマンドと ffmpeg コマンドを実行して NDI 送信を試してみます。

```bash
$ raspivid -o - -t 0 -vf -hf -fps 25 -b 500000 | ./ffmpeg -re -f h264 -i - -vcodec wrapped_avframe -g 50 -strict experimental -f libndi_newtek -pix_fmt uyvy422 -s 640x360 RPiCamera
```

※ USB 接続のウェブカメラを使用する場合は ffmpeg コマンドのみで NDI 送信可能。

```bash
$ ./ffmpeg -f alsa -ac 2 -thread_queue_size 4096 -i hw:1 -i /dev/video0 -s 640x360 -vcodec wrapped_avframe -g 50 -strict experimental -f libndi_newtek -pix_fmt uyvy422 RPiCamera
```

NDI 受信は OBS Studio を使用して確認します。
NDI™️ Source の設定で Source name のプルダウンメニューに 「RASPBERRYPI (RPiCamera)」と表示されれば成功です。
![スクリーンショット 2018-11-26 21.49.22.png](https://qiita-image-store.s3.amazonaws.com/0/72479/4ba74b42-e30b-2083-8269-571654d720f8.png)

## まとめ
iOS アプリ や Android アプリで NewTek NDI Camera application がリリースされている (有償) ので、どこまでニーズがあるかどうか分かりませんが、ラズパイを使用するだけで少しだけ「IoT 感」が出ていれば幸いです！

![46728651_1940906525978304_8542868648153317376_o.jpg](https://qiita-image-store.s3.amazonaws.com/0/72479/ccaa9de3-64d5-f95a-e4ee-34e7750436b9.jpeg)

※ 追伸 ( 2018 年 12 月 18 日時点 )
NDI® Version 3.8 SDK がリリースされたが、状況は変わらず・・。

※ 追伸 ( 2018 年 11 月 26 日時点 )
Raspberry Pi Zero W でも試していますが、armv6 用のライブラリだと ffmpeg のビルドは問題無く完了しますが、ffmpeg コマンドを実行した際にライブラリの読み込みでエラーが出て失敗します。ビルドは非常に時間が掛かる (6 時間くらい) ので、あまり試行錯誤できていません。(´・ω・`)

```bash
(ライブラリのコピー)
$ sudo cp -r NDI\ SDK\ for\ Linux/lib/armv6-rpi-linux-gnueabi/* /usr/lib/

$ ./ffmpeg -version
./ffmpeg: error while loading shared libraries: libndi.so.3: cannot open shared object file: No such file or directory
$ ldd ./ffmpeg | grep libndi
	libndi.so.3 => not found
$  file /usr/lib/libndi.so.3.7.1
/usr/lib/libndi.so.3.7.1: ELF 32-bit LSB shared object, ARM, EABI5 version 1 (GNU/Linux), dynamically linked, BuildID[sha1]=ac90b861b0daa9449e3e31662d34fc107f92bf7c, stripped
```

# Raspberry Pi 4 Model B 対応
## 環境
- Raspberry Pi 4 (メモリ 4GB)
- OS イメージ Raspbian buster (2020-02-13-raspbian-buster-full.zip)  
  - Raspbian GNU/Linux 10 (buster)
- ウェブカメラ (Logitech, Inc. Webcam C270)

## ビルド手順
2020 年 4 月 29 日時点で <a href="https://www.ndi.tv/sdk/">NDI SDK LINUX</a> のバージョンは 4.5 でした。
<img width="50%" alt="NDI_SDK_LINUX.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/a5a6e44b-e3ea-1f4f-a6c7-c012afb2a5bb.png">

FFmpeg 4.1 系以降は GPL ライセンス違反により NDI がサポートされなくなったため、4.0 系 (最終 4.0.5 ) でビルドします。

```bash
# NDI SDK LINUX のインストール
$ mkdir NDI
$ cd NDI
$ wget http://new.tk/NDISDKLINUX
$ mv NDISDKLINUX InstallNDISDK_v4_Linux.tar.gz
$ tar xvzf InstallNDISDK_v4_Linux.tar.gz
$ sh InstallNDISDK_v4_Linux.sh
$ sudo mkdir /usr/include/ndi
$ sudo cp NDI\ SDK\ for\ Linux/include/* /usr/include/ndi/
$ sudo cp -r NDI\ SDK\ for\ Linux/lib/arm-rpi3-linux-gnueabihf/* /usr/lib/

# FFmpeg のビルド
$ git clone git://source.ffmpeg.org/ffmpeg.git -b release/4.0 --depth=1
$ cd ffmpeg
$ ./configure --enable-nonfree --enable-libndi_newtek --extra-cflags="-I/usr/include/ndi/" --extra-ldflags="-L/usr/include/ndi/" --enable-libx264 --enable-gpl
$ make -j3
```

## 実行手順
以下のコマンドオプションで NDI 送信することができました。
ウェブカメラのデバイス (/dev/video0)、マイク (hw:1)、画像サイズ (-s 1280x720)、フレームレート (-r 30) はウェブカメラのデバイス認識、性能に応じて変更します。

```bash
$ ./ffmpeg -f alsa -ac 1 -thread_queue_size 4096 -i hw:1 -i /dev/video0 -s 1280x720 -r 30 -vcodec wrapped_avframe -g 50 -strict experimental -f libndi_newtek -pix_fmt uyvy422 RPiCamera
```

(負荷状況)
top コマンドで確認したところ、NDI はソフトウェアエンコーディングなので 50% 程度の負荷でした。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/ce962ad1-92da-0919-d2c7-ce4e946a5b0a.png" width="75%">

(参考) ウェブカメラは /dev/video0 で認識されていました。

```bash
$ lsusb
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 003: ID 046d:0825 Logitech, Inc. Webcam C270　　　← ウェブカメラ
Bus 001 Device 002: ID 2109:3431 VIA Labs, Inc. Hub
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
$ ls -la /dev/video*
crw-rw----+ 1 root video 81, 3  4月 28 11:10 /dev/video0　　　　← ウェブカメラ
crw-rw----+ 1 root video 81, 0  4月 25 17:29 /dev/video10
crw-rw----+ 1 root video 81, 1  4月 25 17:29 /dev/video11
crw-rw----+ 1 root video 81, 2  4月 25 17:29 /dev/video12
```

(参考) ウェブカメラのマイクは カード 1 で認識されていました。

```bash

$ arecord -l
**** ハードウェアデバイス CAPTURE のリスト ****
カード 1: U0x46d0x825 [USB Device 0x46d:0x825], デバイス 0: USB Audio [USB Audio]
  サブデバイス: 1/1
  サブデバイス #0: subdevice #0
```