25
24

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

ラズパイ4とGStreamerでストリーミングサーバーを作ろう

Last updated at Posted at 2019-12-23

やること

ラズパイ4(Raspberry Pi 4 メモリ 4GB)にカメラをつけてストリーミング配信の環境を作ります。 ラズパイに付けられるマイクがなかったので、音声なし映像のみです。
※ラズパイ3 (Raspberry Pi 3 model B+でもインストールできることを確認しました)

とりあえずファイルが欲しい場合

ストリーミングサーバをたてず、.m3u8,.tsファイルが欲しい場合は、こちらからダウンロードください。

テスト用にHLSライブストリーミング配信データおいときます

参考

構成図

カメラを付けたラズパイを、GStreamerとNodejsでストリーミングサーバにします。

更に、CORSを設定し別のWEBサーバでもストリーミングデータが利用できるようにします。

環境

  • ラズパイ
    • Raspberry Pi 4 Model B 4GB
$ lsb_release -a
No LSB modules are available.
Distributor ID: Raspbian
Description:    Raspbian GNU/Linux 10 (buster)
Release:        10
Codename:       buster
  • カメラ

参照元

カメラがサポートするフォーマット

$ v4l2-ctl --list-formats-ext
ioctl: VIDIOC_ENUM_FMT
        Type: Video Capture

        [0]: 'YU12' (Planar YUV 4:2:0)
                Size: Stepwise 32x32 - 2592x1944 with step 2/2
        [1]: 'YUYV' (YUYV 4:2:2)
                Size: Stepwise 32x32 - 2592x1944 with step 2/2
        [2]: 'RGB3' (24-bit RGB 8-8-8)
                Size: Stepwise 32x32 - 2592x1944 with step 2/2
        [3]: 'JPEG' (JFIF JPEG, compressed)
                Size: Stepwise 32x32 - 2592x1944 with step 2/2
        [4]: 'H264' (H.264, compressed)
                Size: Stepwise 32x32 - 2592x1944 with step 2/2
        [5]: 'MJPG' (Motion-JPEG, compressed)
                Size: Stepwise 32x32 - 2592x1944 with step 2/2
        [6]: 'YVYU' (YVYU 4:2:2)
                Size: Stepwise 32x32 - 2592x1944 with step 2/2
        [7]: 'VYUY' (VYUY 4:2:2)
                Size: Stepwise 32x32 - 2592x1944 with step 2/2
        [8]: 'UYVY' (UYVY 4:2:2)
                Size: Stepwise 32x32 - 2592x1944 with step 2/2
        [9]: 'NV12' (Y/CbCr 4:2:0)
                Size: Stepwise 32x32 - 2592x1944 with step 2/2
        [10]: 'BGR3' (24-bit BGR 8-8-8)
                Size: Stepwise 32x32 - 2592x1944 with step 2/2
        [11]: 'YV12' (Planar YVU 4:2:0)
                Size: Stepwise 32x32 - 2592x1944 with step 2/2
        [12]: 'NV21' (Y/CrCb 4:2:0)
                Size: Stepwise 32x32 - 2592x1944 with step 2/2
        [13]: 'BGR4' (32-bit BGRA/X 8-8-8-8)
                Size: Stepwise 32x32 - 2592x1944 with step 2/2

このようにラズパイに接続します。(写真はイメージです。基板はラズパイ4ではありません)

GStreamerをインストールしよう

ストリーミング配信に必要なアプリGStreamerをインストールします。以下2つのコマンドを実行すればインストール完了です。(ということがわかるまで苦労しました)

$ sudo apt install autoconf automake libtool
$ sudo apt install gstreamer1.0-tools gstreamer1.0-plugins-good gstreamer1.0-plugins-ugly libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev

GStreamerの動作確認しよう

早速ストリーミングデータを作成してみます。

$ mkdir test
$ cd test
$ sudo gst-launch-1.0 -v -e v4l2src device=/dev/video0 \
 ! video/x-h264,width=640,height=480,framerate=15/1 \
 ! h264parse ! mpegtsmux \
 ! hlssink max-files=8 target-duration=5 \
 location=./segment%05d.ts \
 playlist-location=output.m3u8 \
 playlist-root=./

実行時はこんな感じです。

実行すると、このように.m3u8,.tsファイルが作成されます。

$ ls
output.m3u8  segment00000.ts  segment00001.ts  segment00002.ts

GStreamerの出力ファイルを確認しよう

.m3u8の中は、.tsファイルとの相対パスが書かれてました。実際の相対パスとずれていないか確認します。(これに気が付かず苦労しました)

$ cat output.m3u8
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-ALLOW-CACHE:NO
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-TARGETDURATION:9

#EXTINF:8.7807645797729492,
./segment00000.ts
#EXTINF:7.9985880851745605,
./segment00001.ts
#EXTINF:6.8206477165222168,
./segment00002.ts

.tsファイルを確認しよう

.tsファイルをWindowsにコピーしてダブルクリックで実行します。カメラ映像が再生されれば成功です。(.tsファイルは動画データなんですね、へぇー)

Nodejsをインストールしよう

GStreamerでストリーミングデータが作れるようになりました。そのデータをWebブラウザで開くことができるように、NodejsをインストールしてラズパイをWebサーバにします。

# npmを更新
sudo npm install npm@latest -g
# npmのバージョン確認
$ npm -v
# -> 6.13.4

$ sudo apt update
$ sudo apt install curl
$ curl -sL https://deb.nodesource.com/setup_12.x | sudo -E bash -
$ sudo apt install nodejs -y

# nodejsのバージョン確認
$ node -v
# -> v12.14.0

Nodejsがインストールできたので、プロジェクトを作成します。

$ mkdir nodejs
$ cd nodejs
$ npm init
$ npm install --save express
$ touch app.js
$ mkdir wwwroot
$ touch wwwroot/test.html

app.jsファイルを以下のようにします。

app.js
var express = require('express');
var app = express();

app.use(express.static('wwwroot'));

var port = 3000;
app.listen(port,function(){
	console.log("サーバがポート%dで起動しました。モード:%s",port,app.settings.env)
});

test.htmlファイルを以下のようにします。

wwwroot/test.html
<!DOCTYPE html>
<html><head></head><body>
TEST
</body></html>

Webサーバとして動作するか試運転します。

$ pwd
/home/pi/nodejs
 $ node app.js
サーバがポート3000で起動しました。モード:development

ブラウザでhttp://<ラズパイのIPアドレス>:3000/test.htmlを開き、Webサイトが開けば成功です。

ストリーミングサーバにしよう!

ストリーミングデータの作成とWebサーバを用意できました。これら2つを使ってストリーミングサーバを作ります。

具体的には、ストリーミングデータをhtmlの<video> </video>タグで表示できるようにします。そのためには、video.jsというモジュールを使うことでChromeでも表示できるようになります。

必要なファイル(.m3u8, .ts以外)は、githubに置きました。これをwwwroot配下に格納します。
https://github.com/zgw426/GStreamerSample/tree/master/sample01

ストリーミングデータ含め、各ファイルがこのように配置されるようにします。

$ pwd
/home/pi/nodejs/wwwroot
$ tree
.
├── output.m3u8
├── segment00056.ts
├── segment00057.ts
├── segment00058.ts
├── segment00059.ts
├── segment00060.ts
├── segment00061.ts
├── segment00062.ts
├── segment00063.ts
├── static
│   ├── css
│   │   └── video-js.min.css
│   └── js
│       ├── video.min.js
│       ├── videojs-contrib-hls.min.js
│       └── videojs-contrib-media-sources.min.js
└── streamtest.html

ストリーミングサイトを開いてみよう

http://<ラズパイのIPアドレス>:3000/streamtest.htmlを開くとこのような画面が表示されます。

動画を再生して、ラズパイに付けたカメラ映像が動画として表示されれば成功です。

これで、ストリーミングサーバが完成しました。

CORSを有効にしよう

冒頭に紹介した2つ目の構成にします。

別にWebサーバーを用意して、そちらのサイトでストリーミング配信ができるようにします。これには、CORS(オリジン間リソース共有)を有効にする必要があります。

CORSが有効でないと、Access to XMLHttpRequest at 'http://xxx' from origin 'http://yyy' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.というエラーが発生し再生できません。

NodejsにCORSモジュールをインストールしよう

ラズパイのNodejsにCORSを有効にするため、モジュールをインストールします。

$ npm install cors

app.jsを以下のようにします。これで、CORS設定が完了です。

※注意※
この設定では、どのサーバからもリソースが利用できる状態で、セキュリティ的には危険な状態です。本来なら、特定のサーバからのみアクセス許可するなど、許可する範囲を最小にします。

app.js
var express = require('express');
var cors = require('cors');
var app = express();

app.use(cors());
app.use(express.static('wwwroot'));

var port = 3000;
app.listen(port,function(){
        console.log("サーバがポート%dで起動しました。モード:%s",port,app.settings.env)
});

CORSを有効にすると、このように別PCのWebサーバでもストリーミング配信ができるようになります。

stream.html は、streamtest.htmlをコピーして、以下のように編集すると作れます。

[変更前] <source src="./output.m3u8" type="application/x-mpegURL">
[変更後] <source src="http://{ラズパイIP or ホスト名}:{ポート番号}/output.m3u8" type="application/x-mpegURL">

おまけ:遅延テスト

ストリーミング配信にはいくらか遅延があります。配信時間が長くなった場合、遅延がどうなるか検証してみました。16時間連続稼働でもそれほど遅くならず、個人的には満足な値でした。

結果

遅延
開始時 18秒
1.5時間後 42秒
16時間後 27秒
25
24
16

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
25
24

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?