超簡単! ffmpeg + rtmp + nginxを使ってraspberry pi + webカメラのストリーミング環境を作る(raspbian buster版)
遠隔の監視カメラ(USB Webカメラ)で音も聞きたいと思い立ち、nginx + rtmp + ffmpeg を使ってラズパイでストリーミングサーバーを構築する方法を試していたところ、Raspbian busterになってからapt一発でいけるようになっていました!
自宅の様子とか、ペットの様子とか、異変にも気付きやすい!
raspbian busterの実行環境を構築する
用意した物はこちら
- Raspberry pi 3B (raspbian buster 4.19.58-v7+)一式
- SDカード 32GB(8GBぐらいあれば十分だけど、安くなってきたので。)
- USB Webカメラ Logicool C310
OSのインストール
まっさらなraspbianを用意します。
最近はbalenaEtcherでイメージをsdカードに書き込む方法がオススメ!速い。
ラズパイ公式サイトからraspbian buster for desktop をダウンロードします。1GB程ありますが気長に待ちましょう。
待っている間に、SD Card Formatter ver. 5 でSDカードを初期化しておきます。(一瞬で終わるんですけどね)
Raspbian busterがダウンロードできたら、balenaEthcerを起動してSDカードとOSイメージを選択してFlush!
起動と初期設定
SDカードをラズパイにセットして起動したら初期設定を行います。
Desktop版であれば、初回起動時に設定ツールが起動するので指示に従って設定を行います。
その後、メニューのラズパイ設定から、SSHやVNCを有効化しておきましょう。
nginx + rtmp + ffmpegをaptで一発インストール
Raspbian busterになってから凄く簡単になりました!
以前はソースを持ってきてモジュールを有効化するためビルドして、、、と大変手間でしたが、今やaptコマンドで一発インストール!
関連するツールと、ストリーミングには直接関係ないのですが、ついでにphp-fpmも入れておきます。
sudo apt update
sudo apt install nginx php-fpm libnginx-mod-rtmp apache2-utils ffmpeg
nginxのバージョンは1.14.2
$ nginx -v
nginx version: nginx/1.14.2
インストール完了したら自動で起動していると思いますが、念のため確認。
$ systemctl status nginx
● nginx.service - A high performance web server and a reverse proxy server
Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled)
Active: active (running) since Mon 2019-08-12 02:24:59 JST; 9h ago
...
nginx のPHP設定(おまけ)
PHPの設定はおまけなので、飛ばしてもOKです。
sudo vim /etc/nginx/sites-enabled/default
- phpを許可(アンコメント)
- indexに index.php を追加
- .ht*へのアクセスを禁止
変更した部分はこの辺り
...
# Add index.php to the list if you are using PHP
index index.php index.html index.htm index.nginx-debian.html;
...
# With php-fpm (or other unix sockets):
fastcgi_pass unix:/run/php/php7.3-fpm.sock;
# With php-cgi (or other tcp sockets):
# fastcgi_pass 127.0.0.1:9000;
...
location ~ /\.ht {
deny all;
}
...
nginxを再起動します。
sudo systemctl daemon-reload
sudo systemctl restart nginx
テストファイルを作成。
sudo vim /var/www/html/index.php
<?php
phpinfo();
?>
webブラウザでアクセスして、phpの情報が表示されていれば成功!
テストが終わったらindex.phpは消しちゃってください。
映像・音声入力デバイスの確認
webカメラをusbポートに接続してカメラ映像、カメラ音声が利用できるか確認します。
使用できるカメラの確認
USB Webカメラ(Logicool C310)をラズパイに接続して、以下のコマンドを実行します。
v4l2-ctl --list-device
USB Camera(/dev/video0)が表示されていればOK!
$ v4l2-ctl --list-device
bcm2835-codec (platform:bcm2835-codec):
/dev/video10
/dev/video11
/dev/video12
UVC Camera (046d:081b) (usb-3f980000.usb-1.3):
/dev/video0
/dev/video1
音声入力デバイス一覧確認
Webカメラのマイクが認識されているか確認します。
arecord -l
カード1として認識されていました。
$ arecord -l
**** ハードウェアデバイス CAPTURE のリスト ****
カード 1: U0x46d0x81b [USB Device 0x46d:0x81b], デバイス 0: USB Audio [USB Audio]
サブデバイス: 1/1
サブデバイス #0: subdevice #0
録画テスト
macなどから動画ファイルを開いて確認するための下準備です。
mkdir -p ~/public_html/temp
cd /var/www/html/
sudo ln -s ~/public_html/temp .
いざ、録画!
ffmpeg -f alsa -ac 1 -i hw:1 -f v4l2 -s 640x480 -i /dev/video0 ~/public_html/temp/output.mpg
※カード1を使用するため、hw:1 を指定します。
適当に20秒ぐらい動かしたら ctrl + c で止めます。
webブラウザでアクセスするか、curlコマンドなどでDLして確認しましょう。
http://{ラズパイのホスト名}.local/temp/output.mpg
curlでダウンロードする場合
curl http://{ラズパイのホスト名}.local/temp/output.mpg -o output.mpg
何度もテストしてSDカードの寿命が気になる場合は、共有メモリに保存した後、上記フォルダにコピーすると良いです。
ffmpeg -f alsa -ac 1 -i hw:1 -f video4linux2 -input_format mjpeg -s 640x480 -i /dev/video0 /dev/shm/output.mpg
cp /dev/shm/output.mpg ~/public_html/temp/
ライブストリーミング用の環境設定
ストリーミングデータの保存場所を作成します。SDカード上に作ると寿命が一気に縮みそうなので、RAM(共有メモリ)を利用します。
sudo mkdir -p /var/www/html/live/
cd /var/www/html/live/
sudo ln -s /dev/shm hls
hls.min.js 取得
※CDNを使って動的に取得する場合(後述のindex.html)、この操作は不要です。
curlを使って最新版をダウンロードします。
sudo curl https://cdn.jsdelivr.net/hls.js/latest/hls.min.js -o /var/www/html/hls.min.js
HLS 配信用 index.htmlの作成
hls.jsのgithubを参照しながら、index.htmlを作成します。
sudo vim /var/www/html/index.html
中身は下記の通り。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8"/>
<script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
</head>
<body>
<video id="video" controls width="100%"></video>
<script>
if(Hls.isSupported()) {
var video = document.getElementById('video');
var hls = new Hls();
hls.loadSource('live/hls/stream.m3u8');
hls.attachMedia(video);
hls.on(Hls.Events.MANIFEST_PARSED,function() {
video.play();
});
}
</script>
<p>
iPhoneなどで再生されない場合は、<a href="live/hls/stream.m3u8">こちら</a>をクリック。
</p>
</body>
</html>
- hls.jsはCDNを使って最新版を読み込んでいます。
- iOSのSafariなどは、HLSの Media Source Extensions (MSE) に対応していないので、リンクを貼って直接アクセスできるようにしています。
nginxのrtmp用コンフィグレーションの作成
コンフィグレーションファイルを作成します。
※conf.dの下に置きますが、拡張子を.confにするとエラーになる(自動で読み込もうとして失敗する)ので注意が必要。
sudo vim /etc/nginx/conf.d/rtmp
中身はHLSを使ったライブ配信の設定です。
rtmp {
server {
listen 1935;
chunk_size 4096;
allow play all;
access_log /var/log/nginx/rtmp_access.log;
application live {
live on;
hls on;
record off;
hls_path /var/www/html/live/hls;
hls_fragment 1s;
hls_type live;
}
}
}
nginxの設定ファイルで上記rtmpコンフィグレーションの読み込み
/etc/nginx/nginx.conf
の末尾にrtmpコンフィグレーションファイルを読み込むコードinclude /etc/nginx/conf.d/rtmp;
を追加します。
sudo sh -c "echo \"include /etc/nginx/conf.d/rtmp;\" >> /etc/nginx/nginx.conf"
vim等で開いて編集しても大丈夫です。
待ち受け用の設定
8090ポートでアクセスを待ち受けるように設定します。ポート番号はなんでもいいと思いす。
sudo vim /etc/nginx/conf.d/default.conf
中身はほぼデフォルトのまま。
server {
listen 8090;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
access_log /var/log/nginx/access.log combined;
error_log /var/log/nginx/error.log warn;
location = /favicon.ico {
access_log off;
empty_gif;
expires 30d;
}
location / {
#auth_basic "Web Cam Streaming";
#auth_basic_user_file /var/www/.htpasswd;
root /var/www/html;
index index.html;
set_real_ip_from 127.0.0.1;
real_ip_header X-Forwarded-For;
}
}
Basic認証は動作が確認できるまで無効にしておきます。後で設定。
nginxを再起動
sudo systemctl daemon-reload
sudo systemctl restart nginx
ストリーミングの開始・停止スクリプト
簡単に開始・停止ができるようにシェルスクリプトを作成します。シェルスクリプト用にフォルダを作っておきましょう。
mkdir ~/scripts/
開始スクリプト
まずはストリーミングの開始用スクリプト
vim ~/scripts/streaming-start.sh
中身はこちら。
#!/bin/bash
NUM=`ps aux | grep ffmpeg | grep -v grep | wc -l`
if [ $NUM -gt 0 ]; then
echo "Already running."
exit
fi
sudo ffmpeg \
-f alsa -ac 1 -thread_queue_size 8192 \
-i hw:1 -f v4l2 \
-thread_queue_size 8192 \
-input_format yuyv422 -video_size 432x240 \
-framerate 30 -i /dev/video0 -c:v h264_omx \
-b:v 768k -bufsize 768k -vsync 1 -g 16 \
-c:a aac -b:a 128k -ar 44100 -af "volume=30dB" \
-f flv rtmp://localhost/live/stream > /dev/null 2>&1 </dev/null &
- 前半部分で他に起動していないことを確認しています(多重起動の防止)。
- バックグラウンドでffmpegを動かすにはコツが必要で、こちらのサイトの情報を参考にしました。
- ref. シェルスクリプト バックグラウンド実行が失敗する際の対応策
- 末尾のこの辺り
... live/stream > /dev/null 2>&1 </dev/null &
停止スクリプト
次に、停止用スクリプト。
vim ~/scripts/streaming-stop.sh
こちらは凄くシンプル。ffmpegにシグナルを送るだけ。
#!/bin/bash
sudo killall -INT ffmpeg
最後に実行権を付けておきます。
chmod +x ~/scripts/streaming-*.sh
いざ、ストリーミング!
先ほど作ったスクリプトでストリーミングを開始します。
./streaming-start.sh
その後、Safariなどのwebブラウザでラズパイにアクセスします。
http://{ラズパイのホスト名}.local:8090/
うまくいってる!
動作を確認したら停止しておきます。
./streaming-stop.sh
ハウリングに注意!
webブラウザを動かしているPCの近くにWebカメラがある場合、PCの音がスピーカーから出ないようにヘッドホンを接続しておきましょう。スピーカーから音が出ているとハウリングが起きてヒドイ状況になります。
Basic認証をかける
ネットワーク越しに見られると恥ずかしいので、Basic認証をかけます。
まずはパスワードファイルの作成。
ユーザーとパスワードを設定します。
sudo htpasswd -c /var/www/.htpasswd userName
※userNameは任意の文字列(ユーザー名)に置き換えてください。
当初コメントアウトしていた/etc/nginx/conf.d/default.confの以下の2行をアンコメント(先頭の#を消して保存)します。
#auth_basic "Web Cam Streaming";
#auth_basic_user_file /var/www/.htpasswd;
問題が無いかチェック
$ sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
これで、nginxを再起動してWebブラウザでアクセスすると認証が求められるようになります。
sudo systemctl daemon-reload
sudo systemctl restart nginx
こんな感じで。
まとめ: raspbian busterなら、nginx + rtmp + ffmpeg のストリーミングサーバーを、aptで簡単に構築できる!
USB Webカメラを用いた映像と音声の同時配信用に、nginx + rtmp + ffmpeg を用いたストリーミング環境を構築しました。
一般的なMJPG-streamserを用いた方法では音が聞こえないという弱点があり、音声同時配信のため、従来はnginxのソースを持ってきてrtmpを有効化して〜、というちょっと二の足を踏むものでした。
今回aptでほとんどインストール完了することができたので、ストリーミング環境の構築がグッと楽になりました。
今後外からアクセスできるようにすれば、外出先から遠隔モニタリングができるようになります。これで不在時の訪問者対応ができるかも!?
ディスカッション
コメント一覧
記事に従い試していますが、以下のように stream.m3u8 が生成されません。
2019/11/08 11:19:16 [error] 2172#2172: *2 open() “/var/www/html/live/hls/stream.m3u8” failed (2: No such file or directory), client: 192.168.13.3, server: , request: “GET /live/hls/stream.m3u8 HTTP/1.1”, host: “192.168.13.212:8090”, referrer: “http://192.168.13.212:8090/”
阿部さま、
errorにて、「No such file or directory」と出ていますので、
1. webサーバーの設定ミス
2. hlsフォルダが存在しない
3. ffmpegが正しく実行されていない
などの可能性があります。
確認するとすれば、
1. index.htmlは表示されるか?
2&3. ターミナルで該当するフォルダ(/var/www/html/live/hls/)を見て、stream.m3u8が存在するか?
辺りかと思います。
「遠隔の監視カメラ(USB Webカメラ)で音も聞きたい」というので、これは探していたものだ!
・・・ということで、早速実行させていただきました。
いざ、録画︕・・・で録画・録音したものは、画像は粗いですが、音声もそれなりに採れていました。
次に、「ライブストリーミング」を実行すべく、ご指示されている通りに実行して、外部のブラウザから観れるようになりました。
私のやり方が悪いのかどうか分からないのですが、ハウリングが出ない別の部屋でモニターしても、音質が非常に悪い。また、画像・音は、リアルよりも約5秒おくれになっています。
つまり、撮影して、別の部屋のパソコンに走っていくと、先ほど撮影されたものを観ることができます。
これは、こういうものなのでしょうか?
リアルタイム(といっても多少の遅れはある)にする方法があれば、追加で教えていただけるとありがたいです。
余分な書き込みで済みませんが、0.5秒遅れくらいで、かつ音がクリアになれば言うことはありません。
以上、時間がとれましたら、よろしくお願い申し上げます。
配信が5秒ほど遅れるのは、仕様の問題なのでしょうね。
ただ、音がものすごく汚い!
streaming-start.shの中の “volume=30dB” を10dBくらいしたら少し改善しました。
このマイクは、MIC内蔵・USBカメラのものです。Skypeなどでは音声も、まったく問題なく使えていました。常時、雨が降るような、またホワイトノイズのようなものが重なっています。
これはどのあたりを触れば、良くなるのでしょうか。Skypeの時は、そのようなノイズはなくクリアでした。
少しでも改善できる方法があれば、対処してみますので、教えていただければ、ありがたいです。
山田時生さま、
コメントありがとうございます。
1)配信が5秒ほど遅れる
仕様のようです。私の環境でも5〜6秒遅れて表示されますので、なんちゃって衛星放送になります。
こちらのサイトの遅延を見ても、5秒ぐらいというのは良い値なのかなと思います。
https://logic-design.zendesk.com/hc/ja/articles/221609807
2)マイクの音が悪い
問題点を切り分けるために音だけ録音して再生してみることをオススメします。
こちらの記事を参考に、マイクの感度やボリュームを調整して普通に音が記録・再生できるか試してみてください。
https://iot-plus.net/make/raspi/rpi3-julius-speech-recognition/#toc_id_2_2
USBカメラなので電気的なノイズが問題になることはそれほど無いかと思いますが、ハードウェアの故障、設定の問題など要因が複数考えられます。
ご参考になりましたら幸いです。
ラズパイ初心者です。USBカメラではなくてラズパイ用のpiカメラでの設定とした場合
何か設定上変えなければならない部分はあるでしょうか?
宜しくお願いいたします。
尚http://ogane.com/homebrew/rpi/1524/index.html で設定した場合は遅延は1秒くらいで
Piカメラモジュール映像はきれいに配信出来ましたが拝見させて頂きましたがどうしても
http で見たいと思っています。
ryoさま、
遅くなりました。ご自身の環境でラズパイ用のカメラが使えていないということでしょうか?
まずは接続したカメラが動作しているか、コチラの記事を参考に確認してみて下さい。
https://iot-plus.net/make/raspi/setup-raspbian-stretch-lite-on-raspi-zero-w-with-camera-module-v2/#toc_id_6
“どうしてもhttpで見たい”という所の問題点をもう少し詳しく教えていただけますでしょうか。
どのような環境で、何が起きているのかわかれば、何かアドバイスできるかもしれません。