Edited at

Raspberry Pi 3 の標準カメラで撮影した動画をブラウザに配信する方法まとめ

More than 1 year has passed since last update.


はじめに

最近、Raspberry Pi 3 と CSI 接続の標準カメラモジュールを入手しました。

せっかくカメラも入手したので、カメラで撮影した動画をリアルタイムで、できれば遅延を減らして高fpsでブラウザから閲覧したいなと思って色々方法を試してみたので、まとめてみます。

なお Raspberry Pi 3 の OS は Raspbian Jessie が前提となります。

$ uname -a

Linux raspberrypi 4.4.45-v7+ #954 SMP Fri Jan 27 19:06:40 GMT 2017 armv7l GNU/Linux


配信方法1 - mjpg-streamer

この方法は motion jpeg で配信します。いろんなところで紹介されている標準的な方法だと思います。


インストール

$ sudo apt-get install -y cmake libv4l-dev libjpeg-dev imagemagick

$ git clone https://github.com/jacksonliam/mjpg-streamer.git
$ cd mjpg-streamer/mjpg-streamer-experimental
$ make


動画の配信

$ ./mjpg_streamer -o "./output_http.so -w ./www" -i "./input_raspicam.so -x 640 -y 480 -fps 30 -q 10"

-q は jpeg の画質指定で、1が最小100が最大です。こいつを小さくすると高レートで配信できます。↑の例だと 10 なので画質は無茶苦茶粗いですが、fps はけっこう出ます。遅延は回線によりますが、LAN内なら WiFi とかでもほぼリアルタイムで見られました。


動画の受信

ブラウザで http://[ラズパイのIP]:8080/ を開くだけです。


配信方法2 - uv4l-raspicam

mjpg-streamer と同じく、 motion jpeg での配信となります。デーモンとして動作するので、ちゃんと使うおうとするとちょっと設定が手間かも。


インストール

linux-projects.org のリポジトリを参照しますので、まずは apt-key で鍵を登録します。

$ curl http://www.linux-projects.org/listing/uv4l_repo/lrkey.asc | sudo apt-key add -

登録できたら、/etc/apt/sources.list に以下を追加します。

deb http://www.linux-projects.org/listing/uv4l_repo/raspbian/ jessie main

その後、

$ sudo apt-get update

$ sudo apt-get install uv4l-webrtc uv4l-raspicam-extras

でインストール完了です。インストール完了後 uv4l_raspicam サービスが勝手に起動します。


動画の配信

本来は /etc/uv4l_raspicam/ 以下の設定を書き換えてサービスを起動すべきなのですが、説明が長くなるので端折ります。まずは、uv4l_raspicam サービスを止めます。

$ sudo service uv4l_raspicam stop

次にコマンドラインから uv4l を直接起動します。

$ uv4l --auto-video_nr --driver raspicam --encoding mjpeg --width 640 --height 480 --quality 15 --server-option '--port=9000'


動画の受信

ブラウザで http://[ラズパイのIP]:9000/stream/video.mjpeg を開くとストリームが見られます。


配信方法3 - gstreamer で h264動画 を HLS (MPEG-2 TS) 形式にして配信

gstreamer の tcpserversink 経由で動画ストリームをそのままブラウザに渡す(HTML5 タグのソースとして使う)という豪快な方法を紹介している記事がいくつか見つかります。HTTPプロトコルまるっきり無視な気がするけど、ブラウザから GET 来た時だけ HTTP 喋ったりするんですかね...?よく分かりません。

しかし、ラズパイが生成できる h264 ストリームをそのままvideoタグに突っ込んで再生できるブラウザはないようです。

しかたないので以下では h264 ストリームを gstreamer を使って HLS 化して配信します。この方法は遅延が数十秒になるのと最近のブラウザだと Android の Chrome あたりでしか再生できないのですが、いちおう参考ということで。


インストール

まずは gstreamer 本体をインストールします。

$ sudo apt-get install -y gstreamer1.0 gstreamer1.0-tools

gstreamer は raspivid コマンドの出力をそのままパイプで入力することも出来ますが、せっかくなので Raspberry Pi の標準カメラを直接入力ソースとして使える gst-rpicamsrc もインストールします。

$ git clone https://github.com/thaytan/gst-rpicamsrc.git

$ cd gst-rpicamsrc
$ ./autogen.sh --prefix=/usr --libdir=/usr/lib/arm-linux-gnueabihf/
$ make
$ sudo make install

生成したHLSファイル一式を配信するために Web サーバーがいるので、 nginx を入れます。

$ sudo apt-get install -y nginx

HLSファイルを /var/www/html/stream/ に生成するので mkdir します。

$ sudo mkdir /var/www/html/stream/

以下の内容でindex.html ファイルを /var/www/html/stream/index.html に置きます。


/var/www/html/stream/index.html

<!DOCTYPE html>

<html><head></head><body>
<video src="./stream/output.m3u8" width="640" height="480"/>
</body></html>


動画の配信

次のコマンドで、カメラ画像のストリーミングを開始します。

$ gst-launch-1.0 -v -e rpicamsrc ! video/x-h264,width=640,height=480,bitrate=800000 ! h264parse ! mpegtsmux ! hlssink max-files=8 target-duration=5 location=/var/www/html/stream/segment%05d.ts playlist-location=/var/www/html/stream/output.m3u8 playlist-root=./


動画の受信

ブラウザで http://[ラズパイのIP]/stream/ を開きます。


補足

gstreamer + Janus WebRTC Gateway という配信方法もあるようです。こちらは VP8 になるので Chrome 専用(だと思う)のと、 Raspberry Pi で VP8 エンコードはちょっと重いかな...と思って今回は試しておりません。


配信方法4 - h264-live-player

Javascript で h264 デコードして canvas タグ上で再生するというぶっちぎりアプローチです。最初ネタだと思ったんですが、PC はおろか iPhone 7の Safari でも普通に動いてしまいました。ラズパイ側では raspivid の出力を WebSocket 経由でブラウザに垂れ流すというシンプルな構成。ちなみに h264-live-player が使っている h264 デコーダは Broadway.js は Android のデコーダを emscripten でビルドしたものらしいです。


インストール

まず、nodejs をインストールします。普通に apt-get するとむちゃくちゃ古い nodejs が入ってしまうので、本家の記事に従って6系をインストールします。

$ curl -sL https://deb.nodesource.com/setup_6.x | sudo -E bash -

$ sudo apt-get install -y nodejs

次に h264-live-player をインストール

$ git clone https://github.com/131/h264-live-player

$ cd h264-live-player
$ npm install


動画の配信

以下を実行します。内部的には raspivid とウェブサーバーが起動してブラウザからの接続を待つ状態になります。

$ node server-rpi.js


動画の再生

ブラウザで http://${ラズパイのIP}:8080/ を開きます。


補足

ブラウザが WebSocket を切断したタイミングで server-rpi.js がクラッシュします。クラッシュした場合は raspivid のプロセスが残っているので、それを kill してから node server-rpi.js を再度実行する必要があります。

ちなみに切断時にクラッシュする現象は h264-live-player の lib/_server.js の 79行目 self.readstream.end() をコメントアウトすると抑えられます。

78:    socket.on('close', function() {

79: self.readStream.end();
80: console.log('stopping client interval');
81: });


おわりに

低解像度なら mjpeg 形式の配信であまり困らないと思います。h264 はビットレートが安定するので突然のラグは少ない反面、ブロックノイズは目立つことがあります。

再生遅延については画質と解像度によって mjpeg と h264 どちらが良いかは一概に言えない印象なので、色々設定を変えながら両方とも試すのが良いかなと思います。