RaspberryPiからの動画配信について

これはRICORA言語班 Advent Calendarの8日目の記事です。

背景

研究に使う可能性があるのでメモとして載せておく。ローカルネットワークでの利用をまず考えている。

結論

ffmpegを使おう。

ffmpegは公式でA complete, cross-platform solution to record, convert and stream audio and video.と名乗っているわけなので、もちろんstreamもできるわけである。

構成はこんなかんじ。あまりにも図の出来が良すぎて失神している。

      +--------+
      | camera |
      +--------+
           |
          USB
      +--------+                                                      +--------+
      |  rspi  | [wifi IEEE 802.11/?] --- *LAN* --- [wifi / ethernet] | debian |
      +--------+                                                      +--------+

現在使っているのはデスクトップつきRaspibianであり、他の人があいまいにドライバを入れた可能性もあるが、カメラは一発で認識できていて、/dev/video0にある(もちろん、時と共に移ろいゆく)。動作確認はVLCとかで画面に映し、挙動を監視するとできる。

さて、いまRaspiberry Piで見えている画面をいい感じに同一LANの中にいるクライアントに送りたいとする。まず検討すべきことは

  • ffmpegのオプション
  • 配信におけるIPプロトコル(TCP / UDP どっち?)

の二点だと考えられる。もちろんffmpeg以外のツールもあるが、いまはffmpegの話をしているので多分これでよい。

RaspberryPiでやるべきこと

まず、オプションがありすぎるので適当に先人のログなどを拝見させてもらおう。ありがとうございます!1つ目に関しては、特に無自覚にraspividが使えるかのように書かれているものの、raspividが使えるのは専用のカメラモジュールに限定されているようなので、注意が必要。

そのうえで、オプションを考えよう。マニュアルが長いが、まあ-iがインプットでレート操作・動画サイズの変更などができることがわかればよい。とりあえずピクセルレートとかは最適にしてくれるっぽい(?)ので、適当なコーデックといい感じの-preset ultrafast-tune zerolatencyを指定することにする。動画のフォーマットはmpegtsにして、一旦は配信用にする。録画すると.tsの拡張子のファイルが生成されるが、それをぶち込んで.mp4のファイルを作ればよいはずなので、あまり問題はないと思っている。

コーデックに関しては、h264よりもh265の方が後継規格なのでよいが、まだ広まっていない(?)可能性もあるらしい。とりあえずh265を採用して見えなかったらh264にスイッチするという運用でもこのスケールなら問題ないように思える。付記しておくが、h266も策定されたようなので、数年のうちにはそちらへの移行が始まる可能性が高い。

パケットサイズについてはネットワーク依存なのでよくわからないという感想が強いので、一旦は指定していないが、今後指定する可能性はある。例えばTCPはPMTUDを利用してパケットサイズを決めている。1300byteとか1000byteとかに指定するのが妥当かもしれない。

で、これらを鑑みると

  ffmpeg \
    -i /dev/video0 \
    -vcodec libx265 \
    -preset ultrafast \ 
    -tune zerolatency \
    -f mpegts \
  udp://[client ip addr]:[port]&pkt_size=(...)

となる。画面の一部がほしければまた別のオプションを指定すれば良い。実際には、Client IPはもちろんクライアントのIP Addressを入力するし、ポートも同様にする。蛇足だが、こういう感じのコマンドでオプションが多くなるとNovelAIでanime girl, cute, ... {{loli, chubby}}などのプロンプトを入力するときの気持ちになるようになってしまった。

TCP / UDPの選択に関しては、どちらでもよいはずで、どうせそんなに輻輳とかが起きないだろという希望的観測と下調べが面倒くさいという理由で真面目に調べていない。一応ヘッダーの大きさがUDPだと小さいという話はあるものの、パケットサイズが大体1000byteくらいだとして、たかだか3%くらいしか効いてこないと思うので、300x300くらいの画面サイズでの動画の画質にどれくらい影響があるかわからない。動画にはUDPだろという短絡的な選択をしてしまっている。

クライアントサイドでやるべきこと

一方、こちらはクライアント側なので、自分のipをip addrとかで覗いてそれを書いておく。ポート番号は一応でかい数にしたほうがいい。サンプルで見たのは12000とか12001とかだが、他のサービスとポートがかぶらなければ正直なんでもいい。

クライアント側のツールもなんでもよいといえばなんでもよいのだが、まあ多機能であれば多少嬉しいのでffplayで動作確認をして、その後VLCを使うことにした。-fflags nobufferfflagsを指定してあげるとReduce the latency introduced by buffering during initial input streams analysis. ソースとのことで、簡単に訳すと初期のバッファリング分からの遅れを取り戻すみたいなオプションとのこと。

  ffplay [client ip addr]:[port]

と打つと、しばらくしてから画面が立ち上がる。

一方、VLCでは

  vlc udp://@:[port]

と入力するとVLCが勝手に受信するように立ち上がってくれる。

VLCを使うといい感じに録画もできて良い。このような構成で、実感としては、大体2〜3秒くらいの遅れだった。

終わりに

感想としてはかなり薄っぺらいが、こういう形で実際にポートとかIPアドレスとかを指定するとそのようなこともできるんですねという気持ちになって良い。我々はWIREDの中にいるのである。あ、いまlain見えましたよね。TCPに関しても使う可能性がある(データ取得で文句を言われたら重い腰を上げることにします。。。)ので追記したいと思っている。

また、twitterのアイコンとか見るとそれっぽいが、筆者はロリコンではない。