📹

Raspberry Pi 5 と USBカメラ と ffmpeg で作るライブストリーミング

2024/06/04に公開

背景

祖父の介護の関係で SwitchBot の見守りカメラを購入しました。値段もそこまで高くは無く機能は概ね満足しているのですが、特定の部屋の監視をしていると、やはりX分前の映像というものが気になってきます(何分前までこの部屋にいた、等です)。

クラウドサービスを契約すればそういった事を解決できそうですが、やはりもっとピンポイントな機能が欲しいと思ってしまいます。そこで今回は、かねてより興味があった Raspberry Pi を購入し、USBカメラを使ってそういった機能を作っていきたいと思います。

なお、本記事は安価に作成する事が目的ではなく、あくまで自前の見守りカメラを作成し自己満足する事が目的となります。

Raspberry Pi 5 は比較的最近のバージョンで(2024年2月より日本国内販売開始[1])、このバージョンに言及された開発記事はそれ以前のものと比較するとそこまで多くありませんでしたので、動作検証報告の意味も込めて記事にしてみようと思いました。

製品購入

Raspberry Pi 5

私は以下の Vesiri 社製の Raspberry Pi 5 を購入しました。
https://www.amazon.co.jp/dp/B0CTQRCH8H

リンクが切れた時に備えて、製品の内容について軽く書いておきます。本製品の MicroSD カードにはOSはプリインストールされていません。

  • raspberry pi 5 kit ラズベリーパイ5 8GBボード
  • アクティブクーラー(冷却装置)
  • PD電源アダプター
  • 64GB MicroSDカード
  • ABS黒色ケース
  • MicroHDMIケーブル

USBカメラ

Raspberry Pi 5 の基盤にはカメラ用のインターフェースが付いており、専用のカメラを接続する事で高解像度なカメラでも高速にデータ通信が可能になりますが、確実に動作保証されたカメラをイマイチ発見できなかったため、汎用性を求めて以下の「バッファロー モデル名:BSW305MBK」USBカメラを購入しました。

https://www.amazon.co.jp/dp/B09241T966

こちらは問題無く動作しました。

OSインストール

この商品では、MicroSDカードにOSはインストールされていないので、自分で用意する必要があります。以下の記事を参考にする事で、すんなりインストールできました。

https://zenn.dev/thorie/articles/548emb-raspberry-pi-5-os-setup

OSについて記載しておきます。uname -a の結果は以下です。

Linux raspberrypi 6.6.20+rpt-rpi-2712 #1 SMP PREEMPT Debian 1:6.6.20-1+rpt1 (2024-03-07) aarch64 GNU/Linux

構築環境

以下のようなシンプルな環境を構築しました。今回、SSH のみで操作するので、Raspberry Pi にはキーボードもディスプレイも接続していません。

ライブストリーミング

配信方式

今回、結論としては HLS(HTTP Live Streaming) 方式を採用します。

本記事を書くまでライブ配信の方法について知らなかったのですが、やはり実装する上で以下の点は重要と考えました。

  • ブラウザで簡単に確認できる
  • 実装のステップが短い

配信方式としては他にも、Real-Time Messaging Protocol (RTMP) や WebRTC などがありますが、HLS に比べて非常に手間がかかりそうだったため、断念しました。HLS は数十秒程度の遅延が発生しますのでご留意ください。

ソフトウェア構成

ソフトウェア構成としては非常に単純で、Webサービスとして Nginx を、HLS配信の配備として FFmpeg を使います。

また本記事は、この記事を非常に参考にして(ほぼ丸パクリ)作られました。

USBカメラの動作確認

まずは SSH で Raspberry Pi に接続します。OS書き込み時に設定した username と hostname を入力します。

ssh username@hostname

ffmpeg を使って動画撮影をテストしてみます。下記のコマンドで作成された output.mp4 をダウンロードして、VLC media player などで確認します。動画が正常に確認できれば、テスト完了です。

ffmpeg -f v4l2 -i /dev/video0 -f alsa -i plughw:2,0 -c:v libx264 -crf 23 -preset veryfast -c:a aac -b:a 128k output.mp4

ChatGPT に聞いてみたところ、以下のオプションの説明を得ました。

  • -f v4l2 -i /dev/video0: USBカメラからV4L2(Video4Linux2)形式で映像を取得。
  • -f alsa -i hw:0: ALSA(Advanced Linux Sound Architecture)形式でオーディオデバイスから音声を取得。
  • -c:v libx264: 映像コーデックとしてH.264を使用。
  • -crf 23: 映像品質を23に設定。
  • -preset veryfast: 高速なエンコーディング設定。
  • -c:a aac: 音声コーデックとしてAACを使用。
  • -b:a 128k: 音声ビットレートを128 kbpsに設定。
  • output.mp4: 出力ファイル名。

-iで入力しているデバイス識別番号は各環境に依存しますので、下記を参考にしてください。

USBデバイスの Video 識別番号のチェック方法

次のコマンドを入力すると

v4l2-ctl --list-devices

次のように得られるので、一番上の /dev/video0 がデバイスの識別番号になります。

USB 2.0 Camera: USB 2.0 Camera (usb-xhci-hcd.1-1):
        /dev/video0
        /dev/video1
        /dev/media0
USBデバイスの Audio 識別番号のチェック方法

次のコマンドを入力すると

arecord -l

次のように得られるので、card A, XXXXXXXXX, device B: XXXXXX の A,B が識別番号になります。plughw:A,B のように入力します。

**** List of CAPTURE Hardware Devices ****
card 2: Camera [USB 2.0 Camera], device 0: USB Audio [USB Audio]
  Subdevices: 1/1
  Subdevice #0: subdevice #0

Nginx

Webサービスとして Nginx を利用します。以下のコマンドでインストールします。

apt update
apt install -y nginx

次に設定ファイルを作成します。今回セキュリティを考慮せず http プロトコルしか使用しないので、留意して実装してください。

sudo vi /etc/nginx/conf.d/stream.conf

次のように追加します。server_name は何でも良いです。

/etc/nginx/conf.d/stream.conf
server {
    listen      80;
    server_name raspberrypi;
}

テストのため、次のようなファイルを作成しておきます。

sudo sh -c 'echo "Hi" > /var/www/html/index.html'

サービスをリスタートします。

sudo /etc/init.d/nginx restart

次のコマンドで、Hiが表示されればテストは完了です。

curl http://127.0.0.1/

FFmpeg で HLS 用ファイルの出力

以下のコマンドで FFmpeg をインストールします。

sudo apt update
sudo apt install ffmpeg

専用のディレクトリを作成します。

sudo mkdir /var/www/html/stream

以下のコマンドで HLS 用のファイルが作成されます。Ctrl + C でキャンセルするまでずっと出力され続けます。

sudo ffmpeg -y -f v4l2 -s 640x480 -thread_queue_size 8192 -i /dev/video0 -f alsa -thread_queue_size 8192 -i plughw:2,0 -c:v libx264 -crf 23 -preset veryfast -c:a aac -b:a 128k -f hls -hls_time 9 -hls_list_size 30 -hls_allow_cache 1 -m3u8_hold_counters 5 -http_persistent 1 -http_multiple 1 -hls_segment_filename /var/www/html/stream/stream_%d.ts -hls_base_url ./ -hls_flags delete_segments /var/www/html/stream/playlist.m3u8

バックグラウンド実行したい方は、上のコマンドを nohup XXXXXX & で囲んでください。XXXXXX はコマンドが入ります。

コマンドが正常であれば、次のようにファイルが出力され続けます。

xxxxx@yyyyy:/var/www/html/stream $ ll
total XXXXXX
-rw-r--r-- 1 root root   1152 Jun  4 13:31 playlist.m3u8
-rw-r--r-- 1 root root 376188 Jun  4 13:27 stream_8405.ts
-rw-r--r-- 1 root root 373744 Jun  4 13:27 stream_8406.ts
-rw-r--r-- 1 root root 368480 Jun  4 13:27 stream_8407.ts
-rw-r--r-- 1 root root 375248 Jun  4 13:27 stream_8408.ts
...
-rw-r--r-- 1 root root 416232 Jun  4 13:31 stream_8432.ts
-rw-r--r-- 1 root root 409652 Jun  4 13:31 stream_8433.ts
-rw-r--r-- 1 root root 391416 Jun  4 13:31 stream_8434.ts
-rw-r--r-- 1 root root 370360 Jun  4 13:31 stream_8435.ts
-rw-r--r-- 1 root root    119 Jun  2 22:38 stream.m3u8

ライブストリーミング用HTML

次のファイルを準備します。

/var/www/html/live.html
<!DOCTYPE html>
<html>
  <head>
      <!-- <script src="https://cdn.jsdelivr.net/npm/hls.js@1"></script> -->
    <!-- Or if you want the latest version from the main branch -->
    <!-- <script src="https://cdn.jsdelivr.net/npm/hls.js@canary"></script> -->
    <script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
  </head>
  <body>
    <video id="video" controls width="640" height="480" preload="none"></video>
    <script>
      var video = document.getElementById('video');
      var videoSrc = './stream/playlist.m3u8';

      if (Hls.isSupported()) {
        var hls = new Hls();
        hls.loadSource(videoSrc);
        hls.attachMedia(video);
      }
      else if (video.canPlayType('application/vnd.apple.mpegurl')) {
        video.src = videoSrc;
      }
    </script>
  </body>
</html>

ブラウザで確認

同じ Home network にいる端末からブラウザを開いて、http://XXX.XXX.XXX.XXX/live.html に接続してください(XXX.XXX.XXX.XXX は Raspberry Pi の IP アドレス)。ブラウザで映像が確認できれば、完了です。

今後の開発

本記事は以上になりますが、個人的にもう少し改良を続けます。具体的には、FFmpeg と並行して Python の OpenCV を使ってビデオファイルを読み込み、定期的なスナップショットを保存したり、動作検知を起点とした別ファイルでのビデオ保存などです。

その技術に関しては Raspberry Pi のみに依存する話では無いので記事にはしないと思いますが、何か共有できる知見やエラーがあれば、記事にして共有したいと思います。

では、良い Raspberry Pi 開発ライフを。

脚注
  1. https://raspberry-pi.ksyic.com/news/page/nwp.id/130 ↩︎

Discussion