ffmpegでラズパイゼロからカメラ画像をUDP配信する方法


※ 当ページには【広告/PR】を含む場合があります。
2021/07/21
ffmpeg/ffserverで保存した動画ファイルをRTSP配信を試す
WezTerm&libsixelでSSH接続したラズパイから即興の監視カメラ的な使い方を試す
蛸壺の中の工作室|ffmpegでラズパイゼロからカメラ画像をUDP配信する方法

前回ではffmpeg/ffserverを使ったテスト動画の送信・受信を簡単に試してみました。

合同会社タコスキングダム|タコツボの中の工作室
ffmpeg/ffserverで保存した動画ファイルをRTSP配信を試す

ffmpegとDocker版のffserverを使った動画配信用のテスト環境を作る方法を取りまとめます。

しかしながら、ffserverなどのようにWebサーバーを経由せずともffmpegから直接UDP配信で動画のストリーミング先を指定するやり方でも配信することが可能です。この場合には、送信元と受信先が一対一になりますが、特に自分用に動画を観るだけであればわざわざサーバーを立てなくてもよいこちらの方式の方が便利です。

今回は簡単にできる自分専用動画配信サービスをffmpegでどう実現するかを解説します。


ラズベリーパイ4B 4GB 技適対応品

Raspberry Pi Zero W (ヘッダーハンダ付け済)

Raspberry Pi Zero 2 W 技適取得済

ラズベリーパイピコ

ラズベリーパイ カメラモジュールV2

ラズパイZere/Zero W用カメラFFCケーブル 2本セット(15ピン22ピン15cm)

RAVPower USB充電器 2ポート 24W 【最大出力5V,4.8A】

ラズパイマガジン 2019年12月号 カメラ&センサー工作入門

IoTの基本・仕組み・重要事項が全部わかる教科書

ffmpeg(Linux)でUDP送受信

まずはもっともシンプルな仕組みの一方方向のデータ転送であるUDPでの動画の送信から試します。

なお手元の検証した環境では、動画送信側としてラズパイゼロ(
192.168.0.101)から、受信側として別のLinuxデスクトップ(192.168.0.102)へストリーミングするものとします。

動画受送信のテスト

まずは動画送信側からffmpegを使って、ラズパイ側に接続している現在のカメラモジュール(
/dev/video0)の設定を覗いてみます。

ラズパイ(Linux)の場合のビデオドライバの形式は
video4linux2v4l2を指定します。

            $ ffmpeg -f video4linux2 -list_formats all -i /dev/video0
ffmpeg version 4.1.6-1~deb10u1+rpt2 Copyright (c) 2000-2020 the FFmpeg developers
  built with gcc 8 (Raspbian 8.3.0-6+rpi1)
  configuration: --prefix=/usr --extra-version='1~deb10u1+rpt2' --toolchain=hardened --incdir=/usr/include/arm-linux-gnueabihf --enable-gpl --disable-stripping --enable-avresample --disable-filter=resample --enable-avisynth --enable-gnutls --enable-ladspa --enable-libaom --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libcdio --enable-libcodec2 --enable-libflite --enable-libfontconfig --enable-libfreetype --enable-libfribidi --enable-libgme --enable-libgsm --enable-libjack --enable-libmp3lame --enable-libmysofa --enable-libopenjpeg --enable-libopenmpt --enable-libopus --enable-libpulse --enable-librsvg --enable-librubberband --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libssh --enable-libtheora --enable-libtwolame --enable-libvidstab --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx265 --enable-libxml2 --enable-libxvid --enable-libzmq --enable-libzvbi --enable-lv2 --enable-omx --enable-openal --enable-opengl --enable-sdl2 --enable-omx-rpi --enable-mmal --enable-neon --enable-rpi --enable-vout-drm --enable-v4l2-request --enable-libudev --enable-libdc1394 --enable-libdrm --enable-libiec61883 --enable-chromaprint --enable-frei0r --enable-libx264 --enable-shared --libdir=/usr/lib/arm-linux-gnueabihf --cpu=arm1176jzf-s --arch=arm
  libavutil      56. 22.100 / 56. 22.100
  libavcodec     58. 35.100 / 58. 35.100
  libavformat    58. 20.100 / 58. 20.100
  libavdevice    58.  5.100 / 58.  5.100
  libavfilter     7. 40.101 /  7. 40.101
  libavresample   4.  0.  0 /  4.  0.  0
  libswscale      5.  3.100 /  5.  3.100
  libswresample   3.  3.100 /  3.  3.100
  libpostproc    55.  3.100 / 55.  3.100
[video4linux2,v4l2 @ 0x1e93e40] Raw       :     yuv420p :     Planar YUV 4:2:0 : {32-3280, 2}x{32-2464, 2}
[video4linux2,v4l2 @ 0x1e93e40] Raw       :     yuyv422 :           YUYV 4:2:2 : {32-3280, 2}x{32-2464, 2}
[video4linux2,v4l2 @ 0x1e93e40] Raw       :       rgb24 :     24-bit RGB 8-8-8 : {32-3280, 2}x{32-2464, 2}
[video4linux2,v4l2 @ 0x1e93e40] Compressed:       mjpeg :            JFIF JPEG : {32-3280, 2}x{32-2464, 2}
[video4linux2,v4l2 @ 0x1e93e40] Compressed:        h264 :                H.264 : {32-3280, 2}x{32-2464, 2}
[video4linux2,v4l2 @ 0x1e93e40] Compressed:       mjpeg :          Motion-JPEG : {32-3280, 2}x{32-2464, 2}
[video4linux2,v4l2 @ 0x1e93e40] Raw       : Unsupported :           YVYU 4:2:2 : {32-3280, 2}x{32-2464, 2}
[video4linux2,v4l2 @ 0x1e93e40] Raw       : Unsupported :           VYUY 4:2:2 : {32-3280, 2}x{32-2464, 2}
[video4linux2,v4l2 @ 0x1e93e40] Raw       :     uyvy422 :           UYVY 4:2:2 : {32-3280, 2}x{32-2464, 2}
[video4linux2,v4l2 @ 0x1e93e40] Raw       :        nv12 :         Y/CbCr 4:2:0 : {32-3280, 2}x{32-2464, 2}
[video4linux2,v4l2 @ 0x1e93e40] Raw       :       bgr24 :     24-bit BGR 8-8-8 : {32-3280, 2}x{32-2464, 2}
[video4linux2,v4l2 @ 0x1e93e40] Raw       :     yuv420p :     Planar YVU 4:2:0 : {32-3280, 2}x{32-2464, 2}
[video4linux2,v4l2 @ 0x1e93e40] Raw       : Unsupported :         Y/CrCb 4:2:0 : {32-3280, 2}x{32-2464, 2}
[video4linux2,v4l2 @ 0x1e93e40] Raw       : Unsupported :  32-bit XBGR 8-8-8-8 : {32-3280, 2}x{32-2464, 2}
        
結果、このカメラモジュールから指定できる出力動画フォーマットの一覧を得ることができます。

では動画受送用マシーンで以下のコマンドから、UDPで転送されてくるデータを受け取ります。

            $ ffplay -fflags nobuffer udp://192.168.0.102:12000
#もしくは
$ ffplay -fflags nobuffer udp://localhost:12000
        
これで動画が転送されてくるまで待機して、動画を受け取り次第ffplayのプレイヤーが起動してきます。

またここではUDP用に12000番のポートを開けていますが、特に問題のないポートであれば任意の番号を利用できます。

では配信側のLinuxマシーン(ラズパイ)側に戻り、カメラモジュールからの撮影動画をUDPストリームで流します。ソフトウェアエンコード(libx264)する場合には以下のようなコマンドで送信できます。(※ただし低画質モードです)

            $ ffmpeg \
    -f v4l2 \
    -s 320x240 \
    -r 15 \
    -thread_queue_size 8192 \
    -i /dev/video0 \
    -c:v libx264 \
    -preset ultrafast \
    -tune zerolatency \
    -f h264 \
    udp://192.168.0.102:12000?pkt_size=1024
        
これで受信側のマシーンのffplayが起動して動画が確認できていればOKです。

合同会社タコスキングダム|蛸壺の中の工作室

またラズパイのカメラモジュールからハードウェアエンコーダである
h264_omxが利用できます。

            $ ffmpeg \
    -f v4l2 \
    -s 320x240 \
    -r 15 \
    -thread_queue_size 8192 \
    -i /dev/video0 \
    -c:v h264_omx \
    -b:v 2048k \
    -preset ultrafast \
    -tune zerolatency \
    -f h264 \
    udp://192.168.0.102:12000?pkt_size=1024
        
注意点としてはh264_omxのデフォルトビデオビットレートが200kbpsでかなりの低画質出力で設定してあるので、-b:vオプションで適当な画質で送れるように引き上げておく必要があります。

余談〜raspividコマンドを使う

なおffmpegほど細かくオプションを指定できませんが、ラズパイのビルドインユーティリティ
raspividからでも簡単なUDP配信が可能です。

            $ raspivid -t 0 -w 320 -h 240 \
    -hf -ih -fps 15 \
    -o udp://192.168.0.102:12000
        

ラズベリーパイ4B 4GB 技適対応品

Raspberry Pi Zero W (ヘッダーハンダ付け済)

Raspberry Pi Zero 2 W 技適取得済

ラズベリーパイピコ

ラズベリーパイ カメラモジュールV2

ラズパイZere/Zero W用カメラFFCケーブル 2本セット(15ピン22ピン15cm)

RAVPower USB充電器 2ポート 24W 【最大出力5V,4.8A】

ラズパイマガジン 2019年12月号 カメラ&センサー工作入門

IoTの基本・仕組み・重要事項が全部わかる教科書

マルチキャスト配信にする

先程は受信側のIPを指定してから動画を流し込こむユニキャスト方式と呼ばれるものでUDPを利用しましたが、マルチキャストアドレスと呼ばれる特別なIPアドレス値を利用すると、UDP配信した動画がネットワーク内の不特定多数のマシーンへの同時受信ができるようになります。

ということは、前回のようにffserverが無くても、1対多の画像配信が可能になるわけです。

それでは適当にマルチキャストアドレスの
239.1.1.1を使って先程と同様にUDP送受信をやってみます。

映像の受け手側は以下で配信を待ち構えます。

            $ ffplay -fflags nobuffer udp://239.1.1.1:12345
        
ポートは12345を開けておきます。

では先程と全く同じオプションでマルチキャストアドレスに配信を開始してみます。

            $ ffmpeg \
    -f v4l2 \
    -s 320x240 \
    -r 15 \
    -thread_queue_size 8192 \
    -i /dev/video0 \
    -c:v h264_omx \
    -b:v 2048k \
    -preset ultrafast \
    -tune zerolatency \
    -f h264 \
    udp://239.1.1.1:12345?pkt_size=1024
        
確かに画像が映し出されているのが確認できますが、ffplayでデコードが失敗したり、パケットの欠落エラーが続出して、ブロックノイズ乱れが酷いし、遅延も大きいようです。

合同会社タコスキングダム|蛸壺の中の工作室

一見マルチキャストでUDP配信を行うと簡単に1対多のブロードキャストが実現しそうでしたが、マルチキャスト転送される過程でデータが大きく破損しやすいという欠点があり実用には向かないと感じました。


ラズベリーパイ4B 4GB 技適対応品

Raspberry Pi Zero W (ヘッダーハンダ付け済)

Raspberry Pi Zero 2 W 技適取得済

ラズベリーパイピコ

ラズベリーパイ カメラモジュールV2

ラズパイZere/Zero W用カメラFFCケーブル 2本セット(15ピン22ピン15cm)

RAVPower USB充電器 2ポート 24W 【最大出力5V,4.8A】

ラズパイマガジン 2019年12月号 カメラ&センサー工作入門

IoTの基本・仕組み・重要事項が全部わかる教科書

まとめ

今回は動画をUDPでリアルタイム配信を試してみた内容をまとめてみました。

またユニキャストとマルチキャストを比較してみたりもしました。マルチキャストではネットワーク内の全てのマシーンから映像を受信できる便利さはあるものの、受信できる画像の質が著しく落ちるというデメリットもあり、利用にはそのトレードオフを考慮しないといけないということが分かりました。

参考サイト

RaspberryPiをWebカメラとして使用する

記事を書いた人

記事の担当:taconocat

ナンデモ系エンジニア

電子工作を身近に知っていただけるように、材料調達からDIYのハウツーまで気になったところをできるだけ細かく記事にしてブログ配信してます。