RaspberryPi AI CameraをMediaMTXとffmpegで高速に映像配信

# 1. はじめに

https://qiita.com/todateman/items/a9dad9b1995d1d42100e

の記事を書いて早々ですが、トラブルシューティングの欄に書いた映像のカクつきが気になって仕方がないので、↓の記事を参考にMediaMTXとffmpegでストリーミングを高速化しました！

https://www.instructables.com/Comparing-Raspberry-Pi-5-Camera-Module-V3-Video-St/

前の記事の[4. AI Cameraのセットアップ～RTSP配信の自動実行まで 4.1. セットアップ](https://qiita.com/todateman/items/a9dad9b1995d1d42100e#41-%E3%82%BB%E3%83%83%E3%83%88%E3%82%A2%E3%83%83%E3%83%97)が完了したら、以降は下記の手順に従ってください。

# 2. 必要なソフトのインストール

[ffmpeg](https://www.ffmpeg.org/)が必要なのでインストールします。

```bash:bash
sudo apt update && sudo apt install ffmpeg
```

次に[MediaMTX](https://github.com/bluenviron/mediamtx)をインストールします。

```bash:bash
# 作業ディレクトリにmediamtxディレクトリを作成します。
mkdir mediamtx && cd mediamtx

# WGET コマンドを使用してgithubからビルド済みのアーカイブファイルをダウンロードします。
# 環境とバージョンは2024.12.22時点の最新版なので、実施時期のバージョンや自身の環境に合わせて都度読み替えてください。
# 32bitの場合
wget https://github.com/bluenviron/mediamtx/releases/download/v1.10.0/mediamtx_v1.10.0_linux_armv7.tar.gz
# 64bitの場合
wget https://github.com/bluenviron/mediamtx/releases/download/v1.10.0/mediamtx_v1.10.0_linux_arm64v8.tar.gz

# アーカイブを解凍します。
# 32bitの場合
tar -xvzf mediamtx_v1.10.0_linux_armv7.tar.gz

# 64bitの場合
tar -xvzf mediamtx_v1.10.0_linux_arm64v8.tar.gz
```

# 3. MediaMTXの設定と配信実行

`mediamtx`ディレクトリ内の`mediamtx.yml`ファイルを開いて編集します。
以下、作業の続きで作業ディレクトリが`mediamtx`にあるものとして続けます。

```bash:bash
nano mediamtx.yml
```

`mediamtx.yml`ファイルは最下部の`paths:`に`stream1:`からの3行を追記します。
※`post-process-file`のパスは各自の環境に合わせて修正してください。

```yaml:mediamtx.yml
paths:
  # example:
  # my_camera:
  #   source: rtsp://my_camera

  # Settings under path "all_others" are applied to all paths that
  # do not match another entry.
  all_others:

  stream1: 
    runOnInit: bash -c 'rpicam-vid -t 0 --post-process-file /home/{username}/imx500_mobilenet_ssd_annotate.json --camera 0 --codec yuv420 --width 1280 --height 720 --inline --listen -o - | ffmpeg -f rawvideo -pix_fmt yuv420p -s:v 1280x720 -i /dev/stdin -c:v libx264 -preset ultrafast -tune zerolatency -f rtsp rtsp://localhost:$RTSP_PORT/$MTX_PATH' 
    runOnInitRestart: yes
```

## 3.1. `runOnInit:`のコマンドオプション解説

- `bash -c`: 以降のコマンドをbashコマンドとして実行します
  - `rpicam-vid` コマンドのオプション
    - `-t 0`: 撮影時間を指定。0は無制限を意味します。
    - `--post-process-file`: 画像処理設定を指定。指定したJSONファイルを使い、AIモデルや映像の注釈を適用します
    - `--camera 0`: 使用するカメラを指定。0はデフォルトのカメラ（通常は接続されたカメラモジュール）を示します
    - `--codec yuv420`: 使用する映像のエンコード形式を指定。この場合、YUV 4:2:0フォーマットでデータをエンコードします
    - `--width 1280 --height 720`: 出力映像の解像度を指定。幅1280ピクセル、高さ720ピクセル（720p HD解像度）
    - `--inline`: H.264データストリームにすべてのイントラフレーム情報を挿入。ストリーム途中からでも再生を可能にします
    - `--listen`: ビデオをエンコードする前に、クライアントからの接続を待つ。(=クライアントが接続されるまで映像出力を一時停止し、接続がない場合はカメラの負荷を軽減する？) TCP/IP によるネットワークストリーミングを想定している。 値は受け付けない。
    - `-o -`: 出力を標準出力（stdout）に送ります。この出力は次のコマンド（パイプ|以降）で処理されます。
  - `ffmpeg` コマンドのオプション
    - `-f rawvideo`: 入力フォーマットを「生映像データ（Raw Video）」として指定
    - `-pix_fmt yuv420p`: 入力映像のピクセルフォーマットを指定。ここではYUV 4:2:0フォーマット
    - `-s:v 1280x720`: 入力映像の解像度を指定。幅1280ピクセル、高さ720ピクセル
    - `-i /dev/stdin`: 標準入力から映像データを受け取る設定。rpicam-vidからのデータを受け取ります
    - `-c:v libx264`: 映像コーデックをH.264（libx264）に指定
    - `-preset ultrafast`: エンコードの速度を最速に設定。遅延を最小限にするための設定
    - `-tune zerolatency`: 低遅延モードを有効にする設定。リアルタイムストリーミングに適しています
    - `-f rtsp`: 出力形式をRTSP（Real-Time Streaming Protocol）に指定
    - `rtsp://localhost:$RTSP_PORT/$MTX_PATH`: 出力先のRTSP URLを指定
      - `localhost`: ストリームを配信するローカルホスト
      - `$RTSP_PORT`: 使用するRTSPサーバーのポート番号（環境変数で指定）
      - `$MTX_PATH`: ストリームのパス（環境変数で指定）
- `runOnInitRestart: yes`: トラブルがあった際などに自動で再起動します


## 3.2. 配信映像の再生

`mediamtx`セットアップ先のディレクトリで下記のbashコマンドを実行するとMediaMTXが起動します。

```bash:bash
./mediamtx
```

VLCやMPC-HCなどからは下記のアドレスでRTSPストリームで再生できます。
相変わらずローカルネットワーク内で5秒程度の遅延はありますが、前の記事のcvlcを使うよりも格段にスムースです。

```
rtsp://<Raspberry PiのIPアドレス>:8554/stream1
```

![RTSP](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360166/eeb58e6e-d9d6-e882-0c9e-377c68ee53e3.png)



さらに、WebRTCでも配信しています。こちらは以下のアドレスで再生できます。
**こちらの方がスマホやタブレットなどで再生しやすいですし、遅延もほぼないのでオススメです。**
IMX500の能力を活用しているとはいえ、非力なRaspberryPi Zero 2 Wでほぼ遅延なくAIでの物体認識ができ、結果がリモートで確認できるの、ちょっと感動です。

```
http://<Raspberry PiのIPアドレス>:8889/stream1/
```

左のディスプレイがRaspberryPi Zero 2 Wから直接HDMIで出力した映像、右のノートPCはWebRTCで配信された映像をブラウザで表示しているところです。
![WebRTC](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360166/5ee67e2f-c1bb-6920-c68e-0799b284b15e.jpeg)

0.01秒刻みのストップウォッチ画面を撮影した結果では、ざっくりですがRaspberrypiでの映像処理と表示で0.15秒、更にWebRTCで配信先での表示に0.15秒、合計で0.3秒程度の遅延のようです。
![遅延時間の確認](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360166/9a20fd3d-3170-b1e7-9120-3febac4e4005.jpeg)


# 4. 自動実行の設定方法

## 4.1. `mediamtx.service` の作成
スクリプトを`systemd`サービスとして登録します。

```bash:bash
sudo nano /etc/systemd/system/mediamtx.service
```

`rpicam-stream.service`には以下を記述します。


```ini:mediamtx.service
[Unit]
Description=Raspberry Pi Camera MediaMTX
After=network.target

[Service]
ExecStart=/home/{username}/mediamtx/mediamtx /home/{username}/mediamtx/mediamtx.yml

[Install]
WantedBy=multi-user.target
```

## 4.2. サービスを有効化

デーモンをリロードし、作成したサービスを認識させます。

```bash:bash
sudo systemctl daemon-reload
```

サービスを起動します。

```bash:bash
sudo systemctl start mediamtx.service
```

上記コマンドの実行後に状態を確認します。

```bash:bash
sudo systemctl status mediamtx.service
```

このように`Active: active`と表示されていれば正常に動作しています。
```bash:bash
● mediamtx.service - Raspberry Pi Camera MediaMTX
     Loaded: loaded (/etc/systemd/system/mediamtx.service; disabled; preset: enabled)
     Active: active (running) since Sun 2024-12-22 13:01:31 JST; 7s ago
   Main PID: 20456 (mediamtx)
      Tasks: 19 (limit: 388)
        CPU: 3.092s
     CGroup: /system.slice/mediamtx.service
             ├─20456 /home/{username}/mediamtx/mediamtx /home/{username}/mediamtx/mediamtx.yml
             ├─20466 bash -c "rpicam-vid -t 0 --post-process-file /home/{username}/rpicam-stream/imx500_mobilenet_ssd.json --camera 0 --codec yuv420 --width 1280 >
             ├─20467 rpicam-vid -t 0 --post-process-file /home/{username}/rpicam-stream/imx500_mobilenet_ssd.json --camera 0 --codec yuv420 --width 1280 --height >
             └─20468 ffmpeg -f rawvideo -pix_fmt yuv420p -s:v 1280x720 -i /dev/stdin -c:v libx264 -preset ultrafast -tune zerolatency -f rtsp rtsp://localhost:8>

12月 22 13:01:35 pizero2 mediamtx[20467]: ------------------------------------------------------------------------------------------------------------------
12月 22 13:01:35 pizero2 mediamtx[20467]: NOTE: Loading network firmware onto the IMX500 can take several minutes, please do not close down the application.
12月 22 13:01:35 pizero2 mediamtx[20467]: ------------------------------------------------------------------------------------------------------------------
12月 22 13:01:35 pizero2 mediamtx[20467]: Reading post processing stage "object_detect_draw_cv"
12月 22 13:01:35 pizero2 mediamtx[20467]: Mode selection for 1280:720:12:P
12月 22 13:01:35 pizero2 mediamtx[20467]:     SRGGB10_CSI2P,2028x1520/0 - Score: 2717.7
12月 22 13:01:35 pizero2 mediamtx[20467]:     SRGGB10_CSI2P,4056x3040/0 - Score: 3604.7
12月 22 13:01:35 pizero2 mediamtx[20467]: Stream configuration adjusted
12月 22 13:01:35 pizero2 mediamtx[20467]: [1:38:38.173192486] [20467]  INFO Camera camera.cpp:1197 configuring streams: (0) 1280x720-YUV420 (1) 2028x1520-SRGGB1>

```

サービスを停止させる(=カメラの撮影・画像認識・映像配信を止める)ときは下記のコマンドです。

```bash:bash
sudo systemctl stop mediamtx.service
```

問題なければ、下記のコマンドで起動時に自動実行されるようサービスを有効にします。
再起動後、自動的にRTSP配信が開始されます。

```bash:bash
sudo systemctl enable mediamtx.service
```

もし自動実行を中止するときは下記のコマンドです。

```bash:bash
sudo systemctl disenable mediamtx.service
```

エラーや動作状況を確認する場合、以下のコマンドを使用してください：

```bash:bash
journalctl -u mediamtx.service
```

以上です。


# 5. 参考

https://www.instructables.com/Comparing-Raspberry-Pi-5-Camera-Module-V3-Video-St/

https://zenn.dev/bitkey_dev/articles/c2659e9113b596