让我们使用树莓派4和GStreamer来创建一个流媒体服务器

做的事情

使用树莓派4(Raspberry Pi 4,内存4GB)连接摄像头创建流媒体环境。由于树莓派上没有麦克风,因此只能传输无声音的图像。另外,经确认也可以在树莓派3(Raspberry Pi 3 model B+)上安装该环境。

undefined

如果你暫時需要這份檔案的話

如果您没有建立流媒体服务器,但想要.m3u8、.ts文件,请从这里下载。

我会将HLS直播流数据存放在测试用途上。

1. 参考一下

ラズパイを映像展示用デバイスにした話

ラズパイにNodejsインストール

[メモ]video.jsでHLS配信をやってみた

Video.jsの使い方

Raspberry Pi + Node.jsでSkyWayを動かしてみる

GStreamerのインストール

图示

通过使用GStreamer和Nodejs将连接了摄像头的树莓派转变为流媒体服务器。

undefined

此外,还会设置CORS并使得流媒体数据能够在另一台WEB服务器上使用。

undefined

环境

    • ラズパイ

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
    カメラ
undefined

请参考指示参照原文。

相机支持的格式。

$ 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的基板)

undefined

让我们安装GStreamer。

请安装GStreamer应用程序以进行流媒体传输。只需执行以下两个命令即可完成安装。(费了很大努力才明白这一点)

$ 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=./

执行时的情况如下。

undefined

执行后,将会生成.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文件是视频数据呀,真有趣)

让我们安装Node.js

现在我能使用GStreamer创建流数据。为了能在Web浏览器中打开这些数据,需要安装Node.js并将树莓派设置为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文件设定为以下方式。

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文件设置如下。

<!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服务器。我将使用这两个来搭建一个流媒体服务器。

具体来说,我们将使流媒体数据能够在HTML的标签中进行显示。为此,我们将使用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,将显示此类画面。

undefined

只要能够播放视频,并能将连接到树莓派的摄像头画面显示为视频,那就是成功的。

undefined

现在,流媒体服务器已经完成了。

让跨域资源共享生效

我們會選擇第二種結構,根據前面的引言。

undefined

可以准备一个Web服务器,在那里可以进行流媒体传输。为了实现这一点,需要启用CORS(跨域资源共享)。

如果CORS未启用,则无法从’ http://yyy ‘源访问到 ‘http://xxx’ 的XMLHttpRequest被CORS策略阻止:所请求的资源上没有’Access-Control-Allow-Origin’头,因此无法再生。

无法进行CORS就会变成这样。 pic.twitter.com/bEVYQpEojs— j4amountain (@zsipparu) December 21, 2019

让我们在Node.js中安装CORS模块吧。

为了在树莓派的Node.js上启用CORS,需要安装一个模块。

$ npm install cors

将app.js文件修改如下。这样,CORS设置就完成了。

请注意:
这种设置使得资源可以从任何服务器访问,从安全角度来看,是非常危险的状态。理应只允许特定服务器访问,限制访问范围最小化。

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后,使得其他计算机的Web服务器也能进行流媒体传输。

undefined

stream.html可以通过复制streamtest.html并按以下方式进行编辑来创建。

【更改前】
【更改后】

额外福利:延迟测试

在进行流媒体直播时会存在一定的延迟。为了验证延迟在长时间直播时会如何变化,我进行了16小时连续直播的测试。结果表明延迟并未显著增加,我个人对其满意。

undefined

结果

遅延開始時18秒1.5時間後42秒16時間後27秒
广告
将在 10 秒后关闭
bannerAds