RaspberryPi と ffmpeg で映像+音声ストリーミング

はじめに

最近カムロボを素体に遠隔操作ロボを作って遊んでいるが,遠隔操作にはカメラが欲しいということで,映像と音声をストリーミングする手段を模索していた.

構成

映像+音声ストリーミングにはいくつかの手段があるようだが,今回は ffmpeg を利用してみる.全体像はこんな感じ.

必要なものは次の通り.

Raspi 本体は Amazon で買うと馬鹿みたいに高いので秋月等で買ったほうが良さげです.なお今回はカムロボに組み込む都合上 Raspi Zero W を利用するが,ストリーミングにはそれなりに CPU 性能と NW 帯域が必要になるので,クアッドコア + Gigabit Ethernet + 5GHz な 3B+ 以降を利用したほうが良さげです.

$ cat /proc/device-tree/model 
Raspberry Pi Zero

映像+音声ストリーミング

raspi-config でカメラモジュールを有効化する.

$ sudo raspi-config

ffmpeg をインストールする.

$ sudo apt-get install ffmpeg

カメラの認識状態は次の通り.video0 として認識されている.

$ v4l2-ctl --list-device
bcm2835-codec-decode (platform:bcm2835-codec):
	/dev/video10
	/dev/video11
	/dev/video12

bcm2835-isp (platform:bcm2835-isp):
	/dev/video13
	/dev/video14
	/dev/video15
	/dev/video16

mmal service 16.1 (platform:bcm2835-v4l2-0):
	/dev/video0

マイクの設定は次の通り..asoundrc ファイルは無ければ作る.

$ arecord -l
**** ハードウェアデバイス CAPTURE のリスト ****
カード 1: Device [USB PnP Sound Device], デバイス 0: USB Audio [USB Audio]
  サブデバイス: 1/1
  サブデバイス #0: subdevice #0
$ cat ~/.asoundrc 
pcm.!default {
  type asym
  capture.pcm {
    type plug
   slave.pcm "input"
  }
}
pcm.input {
  type hw
  card 1
}

ffmpeg でストリーミングを開始する前に, VLC の方で メディア > ネットワークストリームを開く から udp://@:1234 を指定して,ユニキャストの待ち受け状態にしておく必要がある.

VLC の準備ができたら ffmpeg コマンドでストリーミングを開始する.

$ ffmpeg -f alsa -ac 1 -thread_queue_size 8192 -i hw:1                                    \
         -f video4linux2 -input_format yuyv422 -video_size 640x480 -r 12 -i /dev/video0   \
         -c:a copy -b:a 64k                                                               \
          -c:v h264_omx -b:v 512k -vf "rotate=PI"                                         \
         -fflags nobuffer -f mpegts                                                       \
         udp://{ユニキャスト先のIPアドレス}:1234

一応コマンドの書き方はこんな形.

SYNOPSIS
       ffmpeg [global_options] {[input_file_options] -i input_url} ... {[output_file_options] output_url} ...

一応見やすいよう改行を入れているものの,オプションが長すぎて初見だとわけわからないので一応内容メモしておく.

  • 音声入力の設定 (alsaの入力設定)
    • -f alsa
      • 入力を alsa に設定
    • -ac 1
      • オーディオチャンネル(audio channels)数を 1 に設定(モノラル)
    • -thread_queue_size 8192
      • キューのパケット数を設定
    • -i hw:1
      • 入力デバイスを arecord で確認した USB マイクに設定
  • 出力設定
    • -c:a copy
      • オーディオコーデックを入力のまま利用.
    • -b:a 64k
      • オーディオビットレートを設定
    • -c:v h264_omx
      • ビデオコーデックを設定
      • copy の方が処理しなくて済むので軽量化できるが,カメラの設置向きの都合上回転フィルタを入れる必要がありやむなし.
        • 回転有無によらずそれなりに遅延は発生したので大きな影響は無いのかもしれない
    • -b:v 512k
      • ビデオビットレートを設定
    • -vf “rotate=PI”
      • ビデオフィルタで pi[rad] 回転
    • -f mpegts
      • 出力形式を指定
    • udp://{ユニキャスト先のIPアドレス}:1234
      • 出力先を設定

私の環境では結構ばらつきがあって 2〜30 秒程度のラグ.Wi-Fi が混雑しているのか,このキャプチャでは 32 秒も遅れている.

この状態で loadavg≒1.4 くらい.

(ほぼ効果がなかった)遅延改善

ストリーミング中のロードアベレージは常に 1 を超えており CPU 性能が足りていない.またメモリは余裕があるものの,GPUはデフォルト 128M ではやや貧弱かも.

ffmepg のオプションで改善できる部分もあるらしいが,Raspi Zero ではほぼ効果が見られなかった.が,以下の設定変更でもほぼ改善は見られなかった.

How to minimize the delay in a live streaming with ffmpeg
I have a problem. I would to do a live streaming with ffmpeg from my webcam. I launch the ffserver and it works. From an...

GL Driver 有効化

raspi-config から GL Dirver を有効にする.

GPU増量

raspi-config から GPU を 128 → 256 に増量する.

クロックアップ

config.txt を編集して arm_freq にクロックアップする周波数を指定する.OS 動作中は負荷に合わせて周波数が変動するが,arm_freq を設定することで最大周波数が変更される.周波数固定のほうが動作が安定しそうなので,固定オプションも追加.編集が完了したら OS 再起動.

#uncomment to overclock the arm. 700 MHz is the default.
arm_freq=1100
force_turbo=1

CPU の周波数確認は次のコマンド.

$ vcgencmd measure_clock arm
frequency(48)=1100000000

おわりに

火星との通信遅延は 20 分もあるらしいが,ローカルで 30 秒の遅延は遅すぎる.このラグだとさながら自宅探査ロボ.一方で適当に実装中の操作プログラムのレスポンスはそれなりに早いので,映像を見ながら操作するのはかなり難しい.Raspi Zero で低遅延な映像+音声ストリーミングができた人がいればやり方教えてほしいところ.

カメラ固定パーツはこちら.

カムロボ用ラズパイカメラモジュールマウント - DMM.make クリエイターズマーケット
カムロボ用ラズパイカメラモジュールマウントです. 各所直径1mmの下穴が空けてあります. 手持ちのネジに合わせて適当に拡張してください. 次の3つの部品で構成されています. ①サーボモータ(SG90)固定パーツ ②カメラモジュール固定パーツ...

コメント

タイトルとURLをコピーしました