Spresenseカメラからのキャプチャ画像をリアルタイムにProcessingに転送してライブストリーミング再生する

# はじめに

Spresenseカメラから撮影したJPEG画像をリアルタイムにPC上に転送してPC上でストリーミング再生(っぽいことを)するアプリケーションを作成しました。SpresenseをUVC(USB Video Class)カメラデバイスとして使うようなイメージです。

PCアプリケーション側はProcessingツールを用いて動画再生、実際には動画ではなくJPEG画像のパラパラ漫画風再生、を行います。

https://processing.org

実際に動作している様子(Qiitaにアップするためにgif化しているのでカクカクしてます)
![UsbLiveStreaming2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/432852/2282a6e5-5114-70d4-43dc-5f441a7a2378.gif)
JPEGデータの転送は、USB UVCクラスの代わりにCDC/ACMクラスを使用してシリアル転送します。今回のアプリを実現するのに、UVCクラスドライバがあればそれで良いんですが、真の目的はストリーミング再生ではないのでCDCクラスの方が自分にとっては都合が良くて、このあたりは後述します。

# 用意するもの

- ハードウェア
 - SPRESENSEメインボード (https://www.switch-science.com/catalog/3900/)
 - SPRESENSE拡張ボード　(https://www.switch-science.com/catalog/3901/)
 - SPRESENSEカメラボード　(https://www.switch-science.com/catalog/4119/)
 - マイクロUSBケーブル x 2本 (メインボードと拡張ボードとで 1 本ずつ)
- ソフトウェア
 - Processing本体 (https://processing.org/download)
 - Arduino本体 (https://www.arduino.cc/en/software)
 - Spresense Arduinoパッケージ ([Spresense Arduino スタートガイド](https://developer.sony.com/develop/spresense/docs/arduino_set_up_ja.html))
 - USBSerialライブラリ (https://github.com/baggio63446333/USBSerial)
 - UsbLiveStreamingアプリケーション (https://github.com/baggio63446333/SpresenseCameraApps/tree/main/UsbLiveStreaming)

つらつらと挙げましたが、必要なボードはメイン、拡張、カメラボードの3点セット、ソフトウェアは、ProcessingとArduino IDEがインストールされていること、Spresense Arduinoパッケージを入れていない人は、公式サイトの[Spresense Arduinoスタートガイド](https://github.com/baggio63446333/SpresenseCameraApps/tree/main/UsbLiveStreaming)を参照してインストールしてください。また、USBSerialライブラリ(自作)を使用するので、Arduino/libraries以下にインスールしてください。
USBSerialについての過去記事は[こちら](https://qiita.com/baggio/items/e62cb26630fdb78881f2)

# 通信仕様

ProcessingとSpresenseとの通信仕様は超シンプルなものにしました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/432852/24fc3ee2-040d-74fc-c3a3-9296be10bb15.png)
Processingから開始トリガを送ったら、SpresenseからJPEG画像データのサイズ、実データの順番で転送します。サイズ分の転送が終わったら、最後にProcessingから終了トリガを送ります。

これをJPEG画像1枚ごとに繰り返し実行します。

転送間の同期や転送チェックサム等も省略したプロトコルなので、エラーが発生したらそのフレームは捨ててはじめからやり直すような簡単なエラーリカバリ処理を入れています。

# 使い方

## ハードウェア接続

1. メインボード、拡張ボード、カメラボードを接続します
2. メインボードとPCをUSBケーブルで接続します
3. 拡張ボードとPCをUSBケーブルで接続します

## Arduino

1. Arduino IDEを起動します
2. Arduino/UsbLiveStreaming/UsbLiveStreaming.ino スケッチをオープンします
3. 書き込みを行います

デフォルトの画サイズはVGAにしています。MainCoreしか使用しないので、[ツール]->[Memory]のサイズは、最大の1536KBを選択しておきます。
![ArduinoIDE](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/432852/f3cc104e-8219-8b5f-487c-8c50ce5c4618.png)

## Processing

1. Processingを起動します
2. Processing/UsbLiveStreaming/UsbLiveStreaming.pde スケッチをオープンします
3. スケッチ内のSERIAL_PORTNAMEをお使いの環境に合わせて変更します
   シリアルポートは、拡張ボード側のUSB CDC/ACMで接続されたシリアル番号を指定します。
SERIAL_PORTNAMEのデフォルトは、macOS用に`/dev/cu.usbmodem01`になっています。
画サイズのデフォルトはVGAです。変更する場合は、Arduinoスケッチと合わせて変更してください。
![Processing](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/432852/4e91da5c-f0d4-a3a1-76aa-86e67aee848e.png)
4. スケッチを実行すると、UsbLiveStreamingウィンドウが表示されます。
![UsbLiveStreaming](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/432852/d308223f-fd97-c035-126d-4f7003ff7232.png)
5. この画面をクリックすると、そのときのJPEG画像をdataディレクトリに保存します。

# さいごに

本当はライブストリーミングをしたかったわけではなく、AI機械学習するときに例えばカメラ画像をSDカードに保存してそれを取り出して、というのが面倒だったので、画像データをその場でラベリングできて直接PCに転送できれば便利だなと思って作成したのがきっかけです。単なるJPEG転送だけの表示に簡素化したものが本アプリケーションです。

今後の応用として、通信プロトコルのコマンド仕様をもっとちゃんと決めて、カメラの細かいパラメータを設定しつつ描画結果を確認できるような画づくりツールにしたり、画像データに限らず、音声データも含めて任意のデータをPCに転送できるようにしたり、ということを検討しています。

メインで使用している開発マシンのMacBookでは問題無く動作していたのですが、Windowsで試すとシリアル通信エラーが多発しました。なんちゃってプロトコルのせいもありますが、USB CDC/ACMの動作がPC側のスペックに大きく依存してしまってそうです。