Raspberry Pi 5 と USBカメラ と ffmpeg で作るライブストリーミング
背景
祖父の介護の関係で SwitchBot の見守りカメラを購入しました。値段もそこまで高くは無く機能は概ね満足しているのですが、特定の部屋の監視をしていると、やはりX分前の映像というものが気になってきます(何分前までこの部屋にいた、等です)。
クラウドサービスを契約すればそういった事を解決できそうですが、やはりもっとピンポイントな機能が欲しいと思ってしまいます。そこで今回は、かねてより興味があった Raspberry Pi を購入し、USBカメラを使ってそういった機能を作っていきたいと思います。
なお、本記事は安価に作成する事が目的ではなく、あくまで自前の見守りカメラを作成し自己満足する事が目的となります。
Raspberry Pi 5 は比較的最近のバージョンで(2024年2月より日本国内販売開始[1])、このバージョンに言及された開発記事はそれ以前のものと比較するとそこまで多くありませんでしたので、動作検証報告の意味も込めて記事にしてみようと思いました。
製品購入
Raspberry Pi 5
私は以下の Vesiri 社製の Raspberry Pi 5 を購入しました。
リンクが切れた時に備えて、製品の内容について軽く書いておきます。本製品の MicroSD カードにはOSはプリインストールされていません。
- raspberry pi 5 kit ラズベリーパイ5 8GBボード
- アクティブクーラー(冷却装置)
- PD電源アダプター
- 64GB MicroSDカード
- ABS黒色ケース
- MicroHDMIケーブル
USBカメラ
Raspberry Pi 5 の基盤にはカメラ用のインターフェースが付いており、専用のカメラを接続する事で高解像度なカメラでも高速にデータ通信が可能になりますが、確実に動作保証されたカメラをイマイチ発見できなかったため、汎用性を求めて以下の「バッファロー モデル名:BSW305MBK」USBカメラを購入しました。
こちらは問題無く動作しました。
OSインストール
この商品では、MicroSDカードにOSはインストールされていないので、自分で用意する必要があります。以下の記事を参考にする事で、すんなりインストールできました。
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
は何でも良いです。
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
次のファイルを準備します。
<!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 開発ライフを。
Discussion
こんにちは。知識もないのにラズパイ5を購入し、日々苦しんでおります。そんな中、たぬきネット?さんの記事が目に留まり、ただいまffmegによるライブストリーミングに挑戦中です。VLCによる遠隔操作、キーボード設定、IPアドレスの固定まではなんとかできました。
一つ質問があります。こんな私でも上記の分かりやすい説明のお陰でHLS用ファイルの出力まではできました。ストリーミングされたデータも保存することができ確認もできたところです。しかし、ライブストリーミング用HTMLファイル作成後、いざブラウザでアドレス(http://×××.×××.××.××/live.html)を開くとうまく表示されません。接続を拒否される画面になります。※ちなみに、http://×××.×××.××.××と入力すると”Hi”と表示される。
こんな状況ですが何かアドバイスを頂けるとありがたいです。
コメントいただきありがとうございます。何点か確認させてください。
「接続を拒否される画面になります」とは具体的にどんなメッセージか。
http://×××.×××.××.××/live.html の確認
例えば次のようにファイルを入れ替えた後
http://×××.×××.××.××/live.html にアクセスした場合に "hogehoge" が表示されるかどうか
※ちなみに、私はGoogle Chrome ブラウザを使っています。
早々のご連絡ありがとうございます。上記の1.2.3について早速試して報告させていただきます。本日は環境が整っていないため、明日の午前中に投稿させていただきます。もしお時間がありましたらお手数をお掛けしますがアドバイスをお願いします。※上記1.2.3について画像も一緒に投稿します。
おはようございます。アドバイス頂いた1.2.3について検証してみましたので報告させていただきます。
1. stream フォルダの中身が正常に更新され続けているか?
➡は画像を添付します。更新され続けている気がします。
https://storage.googleapis.com/zenn-user-upload/dfc1b95ebeca-20240830.png
https://storage.googleapis.com/zenn-user-upload/fc75c63ed9bc-20240830.png
3. http://×××.×××.××.××/live.html の確認
➡「cp /var/www/html/live.html /var/www/html/live.html.bk」の結果
https://storage.googleapis.com/zenn-user-upload/7d24f4647a33-20240830.png
3.について、そもそもファイルが存在しないといわれました。そこで、私も気になったので指定の場所?を
スクリーンショットします。参考になればいいのですが...。
https://storage.googleapis.com/zenn-user-upload/752b13caba82-20240830.png
以上です。宜しくお願いします。
※ラズパイのファイアーウォールは「無効」にしてあります。
原因
/var/www/html/live.html
が存在しないのが原因となります。http://XXX.XXX.XXX.XXX/ と
/var/www/html
の階層はリンクしています。デフォルトでは http://XXX.XXX.XXX.XXX/ へのアクセスは、http://XXX.XXX.XXX.XXX/index.html 、つまり、/var/www/html/index.html
のファイルを読み取っている事になります。http://XXX.XXX.XXX.XXX/live.html は、/var/www/html/live.html
を読み取る事になりますが、3.のスクリーンショットを見る限り、そのようなファイルが存在しません。2. のエラー画面も Not Found となり、これはファイルが存在しない事を意味します。対応
/var/www/html/live.html
を次の中身で作成します。返信ありがとうございます。また、丁寧に答えていただき感謝します。すごく理解できました。
初歩的な質問なのですが、
” /var/www/html/live.html を次の中身で作成します。 ”
について、まず、
1.sudo vi /var/www/html/live.html
を実行し、
2.上記のプログラムを書き込み
でよろしいでしょうか?方法が間違っていたらすいません。
※1を実行すると
とでます。こちらはもはやエディタの仕様なので、インターネットで対処を検索できます。
別の端末で中途半端に編集中のファイルがある場合や、正常保存できていないファイルの場合の警告です。
連絡ありがとうございます。度々すいません。
理解できました。swapファイルを 「:recover」で修復?削除?しようとしたものの・・・詰まりました。 すいません。アドバイス頂けますか?削除した方が早いと思うのですが仕方がわかりません。
教えて頂いたサイトは、警告ページの下部に4つの選択が出ますが、私のターミナルには存在しません。何か違うのでしょうか?
ls -la
などで確認してみてください。エディタの隠しファイルがあるんだと思います。おそらくそれらを削除してしまえば解決するかと。これらのご質問は本記事とはあまり関連が無く、Linuxやエディタの基本的な操作に関連しています。厳しい事を言うようですが、それらの対処方法はインターネットにたくさんの記事があると思われますので、まずは検索してみてはいかがでしょうか。エラーメッセージでググるなど。
Webサーバの仕組みやLinux OS の基本的操作についてあまり理解されていない場合は、まずは先にそれらを勉強するのも良いと思います。これらの基礎的な事は他に応用が効くので、勉強して損は無いはずです。
返信ありがとうございます。仰る通りだと思います。1から勉強し力をつけたいと思います。色々とアドバイスをいただきありがとうございました。