【Raspberry Pi】FFmpegでHLS配信ライブストリーミング
この記事では、Raspberry Pi(ラズパイ)に取り付けたカメラで撮影した映像を、リアルタイムで外部のブラウザから確認できるようなストリーミングサーバーの構築を行っていく。ただし、マイクは取り付けていないので音声は対象外となる。
▼ GStreamerを使ったライブストリーミングはこちら。
▼ RTMPでニコ生などへ配信したい場合はこちら。
はじめに
はじめにラズパイ用カメラモジュールを紹介します。
ズーム機能付だったり、赤外線で夜間も撮影できるカメラモジュールもある。
動画など重い処理をRaspberry Piで行う場合、CPUが発熱して本体が壊れる恐れがある。ヒートシンクや放熱性のあるケースに入れて必ず熱対策をしよう。 過去にRaspberry Piを壊してしまったことがある。
▼ ネットワークカメラも人気です。
FFmpegのインストール
今回使用した環境は以下の通り。
環境
項目 | バージョン |
---|---|
ラズパイ | Raspberry Pi3 Model B+ |
カメラモジュール | OV5647 |
OS | Raspbian 9.13 |
Python | 2.7.13/3.7.0 |
また、こちらの記事を参考にあらかじめRaspberry Piでカメラを使えるようにしておこう。
カメラモジュールの設定方法はこちらの記事を参考
カメラモジュールを/dev/video0に認識させておこう
FFmpegのインストール
それではRaspberry PiにFFmpegをインストールする。次のコマンドで簡単にインストールできる。
$ sudo apt -y install ffmpeg
FFmpegの公式サイト FFmpeg
こちらの環境では、こんな感じでインストールが完了している。
$ ffmpeg --version
ffmpeg version 3.2.15-0+deb9u1 Copyright (c) 2000-2020 the FFmpeg developers
built with gcc 6.3.0 (Raspbian 6.3.0-18+rpi1+deb9u1) 20170516
configuration: --prefix=/usr --extra-version=0+deb9u1 --toolchain=hardened --libdir=/usr/lib/arm-linux-gnueabihf --incdir=/usr/include/arm-linux-gnueabihf --enable-gpl --disable-stripping --enable-avresample --enable-avisynth --enable-gnutls --enable-ladspa --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libcdio --enable-libebur128 --enable-libflite --enable-libfontconfig --enable-libfreetype --enable-libfribidi --enable-libgme --enable-libgsm --enable-libmp3lame --enable-libopenjpeg --enable-libopenmpt --enable-libopus --enable-libpulse --enable-librubberband --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libssh --enable-libtheora --enable-libtwolame --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx265 --enable-libxvid --enable-libzmq --enable-libzvbi --enable-omx --enable-openal --enable-opengl --enable-sdl2 --enable-libdc1394 --enable-libiec61883 --enable-chromaprint --enable-frei0r --enable-libopencv --enable-libx264 --enable-shared
libavutil 55. 34.101 / 55. 34.101
libavcodec 57. 64.101 / 57. 64.101
libavformat 57. 56.101 / 57. 56.101
libavdevice 57. 1.100 / 57. 1.100
libavfilter 6. 65.100 / 6. 65.100
libavresample 3. 1. 0 / 3. 1. 0
libswscale 4. 2.100 / 4. 2.100
libswresample 2. 3.100 / 2. 3.100
libpostproc 54. 1.100 / 54. 1.100
FFmpegでHLS動画の作成
FFmpegのインストールができたら、HLS動画の作成をテストしてみよう。今回はソフトウェアエンコーディングとなるので libx264 を指定している。
$ ffmpeg -f v4l2 -thread_queue_size 16384 -s 640x480 -vsync -1 -i /dev/video0 \
-c:v libx264 -b:v 1000k -bufsize 1000k \
-flags +cgop+loop-global_header \
-bsf:v h264_mp4toannexb \
-f segment -segment_format mpegts -segment_time 10 -segment_list stream.m3u8 segment%06d.ts
上記コマンドを実行すれば、.m3u8ファイルと .tsファイルができているはず。.tsファイルが、映像や音声データが含まれている動画ファイルであり、それを順番管理しているテキストファイルが.m3u8ファイルである。
ブラウザから動画を閲覧できるかテスト
最後にパソコンのウェブブラウザからRaspberry Piへアクセスして、動画が再生できるかテストしてみよう。
PythonでWebサーバーを作成
前回と同様、Pythonで簡易的なWebサーバーを作った。このプログラムをPython3で実行すると、ウェブブラウザから http://<Raspberry PiのIPアドレス>:5555 へアクセスできるようになる。
from http.server import HTTPServer, SimpleHTTPRequestHandler
import os
import ipget # $ sudo pip3 install ipget==0.0.3
os.chdir("./www")
a = ipget.ipget()
ip, bit = a.ipaddr("eth0").split('/')
port = 5555
httpd = HTTPServer(('', port), SimpleHTTPRequestHandler)
print('HTTPServer began -> http://{}:{}'.format(ip, port))
httpd.serve_forever()
Videoタグを使ったHTMLファイルを用意
次の内容のHTMLファイルを用意した。
<!DOCTYPE html>
<html lang="ja">
<head>
<title>HTTP Live Streaming Test</title>
</head>
<body>
<h1>HTTP Live Streaming Test</h1>
<video width="640"
height="360"
src="stream.m3u8"
preload="none"
onclick="this.play()"
controls />
</body>
</html>
ディレクトリ構成
こちらでは、次のディレクトリ構成となっているので参考に。
$ pwd
/home/pi/ffmpeg
$ tree
.
|-- hls.sh
|-- item_apps.html~
|-- server.py
`-- www
|-- item_apps.html
|-- segment000000.ts
|-- segment000001.ts
|-- segment000002.ts
|-- segment000003.ts
`-- stream.m3u8
HLSサーバーのシェルスクリプト
WebサーバーとFFmpegの実行を簡単にできるよう、シェルスクリプトを作ってみたので参考に。
#!/bin/sh
python3 server.py > /dev/null 2>&1 &
cd www
rm -Rf *.m3u8 *.ts
ffmpeg -f v4l2 -thread_queue_size 16384 -s 640x480 -vsync -1 -i /dev/video0 \
-c:v libx264 -b:v 1000k -bufsize 1000k \
-flags +cgop+loop-global_header \
-bsf:v h264_mp4toannexb \
-f segment -segment_format mpegts -segment_time 10 -segment_list stream.m3u8 segment%06d.ts
ちなみに上記シェルは ctrl + c で終了できるが、server.py だけはバックグラウンドで動き続けているため、$ ps -x でPIDを探して $ kill PID する。
以上を実行してテストしたところ、MacのSafariからは映像が確認できたがChromeからは映像を見ることができなかった。それもそのはず、HTTPリクエストを確認するとChromeでは.tsファイルへのリクエストが投げられていない。
Safari(macOS)
Chrome(macOS)
HLSのブラウザ対応状況
さらに調べると、そもそもMacのChromeではHLS再生にデフォルト対応していないことがわかった。
Can I use... Support tables for HTML5, CSS3, etc
ただし、hls.jsライブラリを使うことで、ChromeでもHLS動画の再生が可能なようだ。こちらはそのうち試してみたい。とりあえず、前回のGStreamerでは再生できなかったmacOSのSafariでも、FFmpegでなら再生できたので良しとしよう。
GitHub - video-dev/hls.js: JavaScript HLS client using Media Source Extension
今後の課題
- 映像がptpt止まってしまう。
- ChromeでのHLS動画再生対応。
- Raspberry Piのハードウェアデコーダを使った動画変換。