超簡単! ffmpeg + rtmp + nginxを使ってraspberry pi + webカメラのストリーミング環境を作る(raspbian buster版)

遠隔の監視カメラ(USB Webカメラ)で音も聞きたいと思い立ち、nginx + rtmp + ffmpeg を使ってラズパイでストリーミングサーバーを構築する方法を試していたところ、Raspbian busterになってからapt一発でいけるようになっていました!

自宅の様子とか、ペットの様子とか、異変にも気付きやすい!

自宅監視用カメラ。マイク付きWebカメラで音声も同時配信、iPhoneでも見る事ができて便利!

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の情報が表示されていれば成功!

phpinfo()の実行結果

テストが終わったら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 &

停止スクリプト

次に、停止用スクリプト。

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

こんな感じで。

Basic認証の様子。

まとめ: raspbian busterなら、nginx + rtmp + ffmpeg のストリーミングサーバーを、aptで簡単に構築できる!

USB Webカメラを用いた映像と音声の同時配信用に、nginx + rtmp + ffmpeg を用いたストリーミング環境を構築しました。

一般的なMJPG-streamserを用いた方法では音が聞こえないという弱点があり、音声同時配信のため、従来はnginxのソースを持ってきてrtmpを有効化して〜、というちょっと二の足を踏むものでした。

今回aptでほとんどインストール完了することができたので、ストリーミング環境の構築がグッと楽になりました。

今後外からアクセスできるようにすれば、外出先から遠隔モニタリングができるようになります。これで不在時の訪問者対応ができるかも!?

お世話になったサイト