ITで遊ぶ

Raspberry PiによるIPカメラのビデオストリーミング

まだ完成したわけではないが、ここ数日の苦闘を繰り返さないためにメモ。

Goproにはプレビューモードというビデオを録画しないで見る機能がある。
あとから写真を撮るのだが、状況を知るためにビデオでも使いたいと考える。

同様のケースは「家庭内にIPカメラを置き、自宅にWebサーバーをたてて外部からブラウザーで見たい」なんて場合にありえるはず。
でも解決策を書いた人はいないように思える。ここ何日も探したんだけど。。。

GoproのプレビューモードはQUIKで指定すると、GoproがアクセスポイントとなるWiFi接続となることはGoproユーザーならご存知のとおり。

Open Gopro APIでプレビューストリームを流すように命令すると、GoproのAP内でのURL (udp://10.5.5.9:8556)でビデオストリームが流れてくる。
このデータをなんとかhttp接続したブラウザーから見たい。

Goproだけではなんともならないので、Raspberry Piを使う。
世の中にあるRaspberry Piにカメラを接続する例は99%がRaspberry Pi標準のカメラモジュールを接続した話しだ。
そんなものは今さら私が記事を書かなくても、もっといい記事がいくらでもある。

USBカメラを接続した場合は、MJPG StreamerのRaspberry Pi版を使えば可能である。

問題は今回のようなネットワーク経由UDPデータストリームだ。
Raspberry Piに接続したディスプレイで見るのでよいならば、Intel様謹製のCV2でOK.

今回の事例は、ストリーミングをhttp経由で見たいのだ。
調べるとプロトコルは二種類。HLSというAppleが作ったものと、DASHという業界標準。HLSはGoogle Chromeではうまく処理されないという話しを見つけたのでDASHにする。どちらのプロトコルであっても考え方は似たりよったりで、マニフェストファイル(.m3u8はHLS、.mpdはDASH)を読み取り、ビデオファイルを再生するという方法を取っている。(この単純な考え方を示した文書が、なかなか見つからず苦労した)

だから解決するアイデアは、ffmjpgという動画変換でよく使われるパッケージを利用して、udpストリームをDASHに変換する。それを見られるHTMLファイルを作ればいいということになる。
WebサーバーはRaspiなので軽量なLighttpdにした。

1. Goproのプレビューストリームを開始する。

以下がGoproへコマンドを出すプログラム。開始前にちゃんとGoproのWiFiアクセスポイントに接続しておく必要がある。

import sys
import json
import requests

GOPRO_BASE_URL = "http://10.5.5.9:8080"
cmd = GOPRO_BASE_URL + "/gopro/camera/stream/stop"

response = requests.get(cmd,timeout=10)
response.raise_for_status()
print( cmd + " is OK")

cmd = GOPRO_BASE_URL + "/gopro/camera/stream/start?port=8556"
response = requests.get(cmd, timeout=10)
response.raise_for_status()
print(cmd + " is OK")

# GoPro default video stream port is; 8556

2. ffmpegでGoproのUDPストリームをDASHに変換

ffmpegをあらかじめaptでインストール。パラメーターの中で-iで入力udpを指定している。-f で出力フォーマットとマニフェストファイル名を指定している。このファイルは当然、今、ffmpegを動作させている環境にできる。htmlファイルはそこを参照できなければならない。


ffmpeg -i udp:10.5.5.9:8556 \
-c:v libx264 -b:v 1000k -g 48 -keyint_min 48 \
-sc_threshold 0 -an \
-f dash stream.mpd

3. Lighttpdの設定

DASHファイルをビデオとして認識させる。

mimetype.assign = (
    ".mpd" => "application/dash+xml",
    ".m4s" => "video/iso.segment"
)

シンボリックリンクをOKにする。

server.follow-symlink = "enable"

これくらいでいいようだ。

4. html

htmlファイルはlighttpdの場合は、/var/www/htmlにできるが、所有者はrootである。それゆえシンボリックリンクを自分のユーザーフォルダーを指すようにした。パスはすべてアクセス可能でなければならない。そうでないとwebサーバーは403 forbiddenを返す。
当たり前なのだが、解説されていない重要項目は黄色でマーカーをつけたファイルが目的のマニフェストファイルである。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Raspberry Pi DASH Streaming</title>
<script src="https://cdn.dashjs.org/latest/dash.all.min.js"></script>
</head>
<body>
<h1>DASH Video Streaming</h1>
<video id="video" controls autoplay style="width: 100%; max-width: 600px;"></video>
<script>
const video = document.getElementById('video');
if ('MediaSource' in window) {
const url = 'http://192.168.100.1/video/stream.mpd';
const player = dashjs.MediaPlayer().create();
player.initialize(video, url, true);
} else {
alert('Your browser does not support DASH.');
}
</script>
</body>
</html>

この例は私が探した限り、ネットで関係記事を見つけられなかった。
今日はここまで。

関連記事

  1. ついでにブートについていろいろ

  2. オープンソースの問題が表面化しつつある

  3. 障害発見のためのTool

  4. Googleの考えるクラウド

  5. FC over Ether

  6. CPU100%だから問題だ?

  7. メインフレーム

  8. ブラウザーのproxy