FFmpeg+SRT（その１）

# FFmpegでSRTを確認する
いまさらながら、FFmpegでSRT（Secure Reliable Transport）をサポートしていることを知ったので動作確認してみた。

## 参考URL
#### SRT
- [Secure Reliable Transport](https://en.wikipedia.org/wiki/Secure_Reliable_Transport)
- [次世代映像伝送プロトコル「SRT」とは何か](https://www.explorer-inc.co.jp/column/srt/media1902.html)
- [パケットフォーマットから読み解く映像伝送プロトコル「SRT」の特長](https://www.toyo.co.jp/ict/casestudy/detail/id=42445)

#### FFmpeg+SRT
- [【入門編】いつかどこかで使えるかもしれない FFmpeg コマンドの紹介](https://developers.play.jp/entry/2023/08/18/155602)
- [ffmpeg 4.0 に入った新しい映像伝送プロトコルSRTを試す](https://qiita.com/tetsu_koba/items/b8e1868a726c6201d3ab)
- [3.37 srt](https://ffmpeg.org/ffmpeg-protocols.html#srt)
- [FFmpeg](https://srtlab.github.io/srt-cookbook/apps/ffmpeg.html)

当初は正しく動作させることができず、ChatGPTに聞きながら、トライ＆エラーを実施。

## インストール
#### Windows
下記を参考にインストール
- [WindowsにFFmpegをインストールする方法](https://qiita.com/Tadataka_Takahashi/items/9dcb0cf308db6f5dc31b)

#### Linux(Lubuntu)
ここはノーコメント。

```
$ apt -y install ffmpeg
```

## やること
SRTを利用して、下記を実施。
- 動画ファイルの転送
- リアルタイムに動画を転送
- 途中経路でパケットをロスさせ、SRTの再送などを確認

## 環境
![Env-Fig.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/5797032c-2c7a-4de8-bee0-74baeb9a15d2.png)

Windows PC（Macですが）上のVM（Lubuntu）から、ホストであるWindowsにSRTによる通信（転送）を実施。また、VM上のI/Fである”enp0s3”でパケットをロスさせる。

## FFmpegコマンド
利用したコマンド＋オプションを紹介。

### カメラ情報
コマンドで指定するカメラ情報を取得する。なおオプションの詳細（説明）は、参考URLなどを参照されたし。

#### Windows
まずはカメラ名を見つける。

```
>ffmpeg -list_devices true -f dshow -i dummy

[dshow @ 00000258222ce400] "FaceTime HD Camera" (video)
[dshow @ 00000258222ce400]   Alternative name "@device_pnp_\\?\pci#ven_14e4&dev_1570&subsys_157014e4&rev_00#000000ffff00000000#{65e8773d-8f56-11d0-a3b9-00a0c9223196}\global"
[dshow @ 00000258222ce400] "Internal Microphone (Cirrus Logic CS4208 (AB 126))" (audio)
[dshow @ 00000258222ce400]   Alternative name "@device_cm_{33D9A762-90C8-11D0-BD43-00A0C911CE86}\wave_{6EF45010-B330-48B3-8C88-9D30D7580AB8}"
```

- -f dshow：入力フォーマットWindowsのカメラ/オーディオデバイス（DirectShow）
- -list_devices true：デバイス一覧表示
- -i dummy：ダミー入力（表示のみ）

”FaceTime HD Camera”が用いるPCのカメラデバイスとなる。”FaceTime HD Camera”の能力は下記のとおり。

```
>ffmpeg -f dshow -list_options true -i video="FaceTime HD Camera"

[dshow @ 0000020a5e70f2c0] DirectShow video device options (from video devices)
[dshow @ 0000020a5e70f2c0]  Pin "キャプチャ" (alternative pin name "0")
[dshow @ 0000020a5e70f2c0]   pixel_format=yuyv422  min s=320x240 fps=30 max s=320x240 fps=30
[dshow @ 0000020a5e70f2c0]   pixel_format=yuyv422  min s=640x480 fps=30 max s=640x480 fps=30
[dshow @ 0000020a5e70f2c0]   pixel_format=yuyv422  min s=1280x720 fps=30 max s=1280x720 fps=30
```

- -f dshow：入力フォーマットWindowsのカメラ/オーディオデバイス（DirectShow）
- -list_options true：カメラ能力表示
- -i video="FaceTime HD Camera"：カメラデバイス

#### Lubuntu
カメラデバイスを見つける。

```
$ v4l2-ctl --list-devices
VirtualBox Webcam - FaceTime HD (usb-0000:00:06.0-2):
        /dev/video0
        /dev/video1
        /dev/media0
```

コマンド（v4l2-ctl）は、Windowsと異なる。”--list-devices”により対応デバイスファイルを見つける。通常、”/dev/video0”を使えばいいらしい。カメラデバイスの能力は下記となる。

```
$ ffmpeg -f v4l2 -list_formats all -i /dev/video0
[video4linux2,v4l2 @ 0x637c773d8380] Compressed:       mjpeg :          Motion-JPEG : 320x240 640x480 1280x720

 v4l2-ctl --list-formats-ext
ioctl: VIDIOC_ENUM_FMT
        Type: Video Capture

        [0]: 'MJPG' (Motion-JPEG, compressed)
                Size: Discrete 320x240
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 640x480
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 1280x720
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
```

- -f v4l2：入力フォーマットVideo4Linux2
- -list_formats all：対応フォーマット表示
- -i /dev/video0：カメラデバイス

### 待ち受け（受信側）
Windows、Lubuntu共通である。画面上に動画が表示される。

```
ffplay -fflags nobuffer -autoexit "srt://192.168.56.1:8888?mode=listener"
```

- 192.168.56.1：待ち受けする機器のIPアドレス
- 8888：ポート番号
- mode=listener：待ち受け
- -fflags nobuffer：バッファを減らして低遅延化
- -autoexit：転送完了後プログラムを終了

### ファイル転送（送信側）
こちらもWindows、Lubuntu共通である。

```
ffmpeg -re -i ファイル -f mpegts srt://192.168.56.1:8888
```

- 192.168.56.1：送信先機器のIPアドレス
- 8888：ポート番号
- -i：送信する動画ファイル名
- -re：リアルタイムで入力を読む（ストリーミング向け）
- -f mpegts：出力フォーマットをMPEG-TSに指定（ストリーミングやデジタル放送向け）

### リアルタイム転送（送信側）
#### Windows
```
ffmpeg -f dshow -video_size 640x480 -framerate 30 -pixel_format yuyv422 -i video="FaceTime HD Camera" -pix_fmt yuv420p -c:v libx264 -preset ultrafast -f mpegts "srt://192.168.56.1:8888?pkt_size=1316"
```

- -f dshow：入力フォーマットWindowsのカメラ/オーディオデバイス（DirectShow）
- -video_size 640x480：解像度
- -framerate 30：フレームレート（1秒間に30フレーム）
- -pixel_format yuyv422：ピクセルフォーマットyuyv422（YUYV 4:2:2）
- -i video="FaceTime HD Camera": カメラデバイス
- -pix_fmt yuv420p：出力フォーマットyuv420p（YUV 4:2:0）
- -c:v libx264：ビデオコーデックH.264
- -preset ultrafast：エンコード速度を最速（低遅延化）
- -f mpegts：出力フォーマットMPEG-TS（SRT向け）
- 192.168.56.1：転送先IPアドレス
- 8888：転送先ポート
- pkt_size=1316：パケットサイズ1316（MPEG-TS向け）

#### Lubuntu
```
ffmpeg -f v4l2 -video_size 640x480 -framerate 30 -input_format yuyv422 -i /dev/video0 -pix_fmt yuv420p -c:v libx264 -preset ultrafast -f mpegts "srt://192.168.56.1:8888?pkt_size=1316"
```

- -f v4l2：入力フォーマットVideo4Linux2
- -video_size 640x480：解像度
- -framerate 30：フレームレート（1秒間に30フレーム）
- -pixel_format yuyv422：ピクセルフォーマットyuyv422（YUYV 4:2:2）
- -i /dev/video0: カメラデバイス
- -pix_fmt yuv420p：出力フォーマットyuv420p（YUV 4:2:0）
- -c:v libx264：ビデオコーデックH.264
- -preset ultrafast：エンコード速度を最速（低遅延化）
- -f mpegts：出力フォーマットMPEG-TS（SRT向け）
- 192.168.56.1：転送先IPアドレス
- 8888：転送先ポート
- pkt_size=1316：パケットサイズ1316（MPEG-TS向け）

### ファイル作成（参考）
#### Windows
```
ffmpeg -f dshow -video_size 640x480 -framerate 30 -pixel_format yuyv422 -i video="FaceTime HD Camera" -pix_fmt yuv420p -c:v libx264 -preset ultrafast -t 10 ファイル
```

- -f dshow：入力フォーマットWindowsのカメラ/オーディオデバイス（DirectShow）
- -video_size 640x480：解像度
- -framerate 30：フレームレート（1秒間に30フレーム）
- -pixel_format yuyv422：ピクセルフォーマットyuyv422（YUYV 4:2:2）
- -i video="FaceTime HD Camera": カメラデバイス
- -pix_fmt yuv420p：出力フォーマットyuv420p（YUV 4:2:0）
- -c:v libx264：ビデオコーデックH.264
- -preset ultrafast：エンコード速度を最速（低遅延化）
- -t 10：録画時間（10秒）
- -an：音声なし
- ファイル：作成するファイル名

#### Lubuntu
```
ffmpeg -f v4l2 -video_size 1280x720 -framerate 30 -input_format yuyv422 -i /dev/video0 -pix_fmt yuv420p -c:v libx264 -preset ultrafast -an -t 10 ファイル
```


- -f v4l2：入力フォーマットVideo4Linux2
- -video_size 640x480：解像度
- -framerate 30：フレームレート（1秒間に30フレーム）
- -input_format yuyv422：ピクセルフォーマットyuyv422（YUYV 4:2:2）
- -i /dev/video0: カメラデバイス
- -pix_fmt yuv420p：出力フォーマットyuv420p（YUV 4:2:0）
- -c:v libx264：ビデオコーデックH.264
- -preset ultrafast：エンコード速度を最速（低遅延化）
- -t 10：録画時間（10秒）
- -an：音声なし
- ファイル：作成するファイル名

## 検証
FFmpegでSRT転送を行い、Wiresharkで取得したデータの解説。

### 正常
![Start_NoLoss - コピー.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/cfd21970-1094-452c-92be-9fa70a3d58d6.png)

- 送信側IPアドレス”10.0.2.15”、受信側IPアドレス”192.168.56.1”（以降共通）
- 相互のControl:UMSG_HANDSHAKEによるネゴシエーション（赤枠）
- DATAによる実際のデータ送信（赤枠）
- 受信側Control:UMSG_ACK/送信側Control:UMSG＿ACKACKによるデータ受信確認（青枠）

![MiddleNoLoss - コピー.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/fdd972b9-1ff7-40ac-89f2-416715bbcb42.png)

- Control:UMSG_ACK：シーケンス番号”1869575761”まで受信確認（1868575760かもしれない）
- Control:UMSG_ACKACK：UMSG_ACKの確認

![End_NoLoss - コピー.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/38693d53-1c4d-4204-8b02-278a575e560f.png)

- 送信側Control:UMSG_SHUTDOWNによる転送終了（赤枠）
- 青枠DATAの受信側のデータ受領確認は行っていないかもしれない（？）

### パケットロス
下記Linuxコマンドにより、Lubuntu（送信側）からWindows（受信側）へのパケットを20%ドロップさせる。

```
$ sudo tc qdisc add dev enp0s3 root netem drop 20%
```

![Lost1 - コピー.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/32571d63-1381-4e09-9ff9-24bd9f2d4e20.png)

- Control:UMSG_LOSSREPORTにより、受信側”192.168.56.1”がシーケンス番号”1340075526”を受信していないことを送信側に通知

![ReTransmit1 - コピー.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/8368f286-363e-46fd-bb57-67a62fc3c730.png)

- シーケンス番号”1340075526”のDATA再送（Retransmitted）（赤枠）
- 青枠のメッセージ番号”msgno”と比べると、まとめて再送を実施している様子

![OriginalSent - コピー.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/cabd58ab-633b-45b9-8415-dffa18137389.png)

- 参考：再送でない場合、”Original”

![FilterOnlyLossコピー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/a936df29-85ed-439e-b5c6-a897ccdffb14.png)

- ”srt.type == 3”でフィルターすると、Control:UMSG_LOSSREPORTのみ表示
- 20%Loss設定だが、実際には12.3%のロス（詳細不明）

参考、下記は入出力グラフ（上：SRT全体、下：Control:UMSG_LOSSREPORTのみ）。

![20%Loss入出力グラフ+パケットロス.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/a699e32c-3cdb-4ec6-ac1e-96f60917140e.png)

## 終わりに
FFmpegは多数のオプションあり。低ビットレートの回線を想定した転送もオプションにより実現できるようだ。

EOF