在网页上公开IP摄像头的视频

在网页上公开自己家里安装的IP摄像头的视频。

由于“愚蠢经济学”的影响,如今日本已变成了全球无遁形的穷人国家。作为生活在这个“美丽的日本”的人,我努力以尽可能低的预算实现我的目标。在这个过程中,我依靠的是:(1) 价格低廉、质量高的中国制造IP摄像头;(2) 免费且高质量的自由软件(开源软件);(3) 经过使用年限的二手笔记本电脑。

前提条件是,假设有(A)家庭内引入的光纤网络和(B)已经在互联网上设置好的网络服务器。其中(A)是必需的。(B)可以没有,但即使我们假设有它,本文的目标读者也不会抱怨。

1:IP摄像头

所使用的IP摄像机是SV3C品牌的SV-801W-1080P-HX型号,其主要规格如下:

    • アルミ・ダイカスト筐体、IP66 防水・防塵

 

    • 固定画角 200万画素 (1920 x 1080)

 

    • 有線 / WiFi 両対応

 

    • AC アダプタによる給電

 

    • 赤外線暗視撮影

 

    • 動体検知

 

    • マイクロ SD カード対応(64 GB まで)

 

    • RTSP 対応

 

    • ONVIF 対応

 

    • メール送信

 

    FTP アップロード

这款产品在亚马逊日本网站上的价格为4,899日元(截至2020年10月),属于最实惠的范畴,然而它看起来非常坚固,装备了一系列预期在这类监控摄像头上出现的功能。虽然还有其他类似的产品可供选择,但是由于SV3C的支持网站上的手册比较齐全,给人留下了较好的印象,因此我会选择它。

虽然支持RTSP和ONVIF很重要,但如今的IP摄像机很少不支持这些协议。

(追記)
使用了两个月后,发现稳定性存在问题。例如,CCD 会饱和导致图像过曝。此外,例如,拍摄的 JPEG 图片会变得不完整。还有,虽然也可能由其他原因引起,但 RTSP 通信经常不稳定。
感觉芯片的性能不足以满足所宣称的功能。这一点对应该说是与价格相符的感受。

1-1:安装IP摄像头

在安装摄像头到室外(房屋屋檐)之前,进行摄像头的设置。

以下的说明是基于SV3C SV-801W-1080P-HX摄像头,但我认为其他公司的摄像头也大致相似。如果有差异,我深感抱歉。

1-1-1: 微型SD卡.

最开始,将一起购买的64GB 1,596日元的微型SD卡装入相机中。

这款产品在卡槽上有一个镜头盖,如果不将其取下并取出内部内容,就无法访问卡槽上的芯片板,因此操作难度稍高。但是,一旦插入后,这是一张不再需要取出的卡片,所以我认为这样就可以了。

此外,相机可以在没有存储卡的情况下运作。我认为在进行视频直播时不需要存储卡,而且当用于防盗目的并连接到网络视频录制器(NVR)时也可以省略存储卡。

然而,只要安装卡片,就可以自动记录和保存视频和快照。而且,添加卡片后安装会很麻烦。由于价格廉价,最好从一开始就安装好。

1-1-2 : 连接到家庭内局域网

通过有线 LAN 电缆将家庭内的路由器(或者交换机等设备)与摄像机连接起来,并接通摄像机的电源。

通过这样设置,摄像机将通过路由器的DHCP获取动态IP地址。

1-1-3: 卡姆嗨 (Kǎ mǔ

在智能手机上安装并启动名为CamHi的应用程序。通过该应用程序,可以搜索并连接到连接到家庭局域网的IP摄像头,从而能够观看视频和访问摄像头的配置信息。不用说,智能手机需要事先通过WiFi连接到家庭局域网。

从现在开始,使用CamHi可以进行配置操作,但是为了方便起见,可以直接通过Web浏览器访问相机的配置界面,只需记录相机的IP地址,之后就可以暂时退出CamHi。(之后在室外安装工程时,再次使用以确认图像。)

1-1-4: 通过网络浏览器进行设置

在网络浏览器中访问摄像头的 IP 地址,并进行摄像头的设置。

我使用 Internet Explorer 浏览器。我被要求首先安装用于播放视频的 ActiveX 控件。虽然我觉得奇怪,但我还是按照指示去做。虽然其他浏览器也可以进行设置,但由于图片无法显示,所以不太方便。我最终放弃了,还是使用 IE 浏览器。

可以设置的项目有很多。对于不太清楚的项目,我们将保持默认设置,并进行下面列出的最低限度的初始化和设置更改。

    • 管理者パスワードを変更する

 

    • IP アドレスを静的アドレスとする (ここでは 192.168.0.101 とする)

 

    • タイム・ゾーンを GMT +09:00 に設定する

 

    • NTP サーバを ntp.nict.jp に設定する

 

    SD カードを初期化する

考虑到安装位置和稳定性,本次决定使用有线连接,关闭WiFi。此外,由于目的不同,设置将不使用红外夜视、动体检测、邮件和FTP报警等防犯功能。

1-2:户外IP摄像头安装工程

在家中拍摄视频的地方安装IP摄像头。

在智能手机的CamHi上查看图像,同时确定安装位置和拍摄方向并固定。虽然广角镜头周围会有些许失真,但人眼对水平方向的偏差非常敏感,所以需要特别注意图像中心部分的水平和垂直方向,以确定摄像机的角度。

由于这是一个暴雨区域,因此我们需要使用自融软塑带牢固地对局域网线和电源线的接头进行防水处理。

1-3: 靜止畫的直播

一旦达到 SV3C HX 系列的这一点,就可以实现静态图像的传输。

由于具有定期将快照上传到外部FTP服务器的功能,因此可以利用它,在Web服务器端进行适当处理,几乎可以实时地在网页上显示静态图像。

photo.png

为了准备在视频流无法播放的情况下,创建一个能够提供静止图片的页面。

1-3-1: 客户端(HTML + Javascript)

<img id="live-img" width="950" height="534" 
  src="/livecam/snapshot" 
  alt="ライブ・カメラのスナップ・ショット" />

画像的源地址是/livecam/snapshot的URL。相较于以文件名”snapshot.jpg”的方式指定,服务器端的工作会变得更轻松。也不需要担心文件缓存的负面影响。

function updateImage() {
    $('#live-img').attr('src', '/livecam/snapshot');
}
var timer = setInterval(updateImage, 30000);

然后使用 JavaScript 定时器,每 30 秒向服务器请求图像。

1-3-2 : 服务器方面

在服务器端,通过与/livecam/snapshot URL对应的操作,将图像数据发送给客户端。

由于摄像头不断将快照上传到预先指定的目录中,因此只需选择其中最新的文件并读取其内容,然后附上 ‘Content-Type: image/jpeg’ 的头信息进行发送即可。

如果要说细节的话,会需要一些繁琐的操作,比如调整图片大小、删除不必要的文件等等,具体细节就省略不说了。

2:视频流媒体服务

2-1:简化图

movie.png

要实现从IP摄像头传输视频,除了传统的 web 服务器之外,还需要视频转换服务器和视频分发服务器,如图所示。

首先,视频转换服务器将按照摄像机输出的RTSP(实时流传输协议)转换成符合RTMP(实时消息传送协议)的视频流数据。这个视频转换服务器的实体是一个名为ffmpeg的应用程序。

然后,视频转换服务器接收来自RTMP的输出,并将其转换为RTMP流或HLS(HTTP Live Streaming)协议的流,然后将其传送给Web客户端。这个视频传输服务器实际上是一个名为nginx-rtmp-module的插件,它配备在NGINX这个Web服务器程序上。

此外,本次不進行操作且圖中也未顯示,但此視頻傳輸伺服器也可以轉換為 MPEG-DASH協議(DASH代表動態自適應串流傳輸協議)並進行傳遞。

2-2: 影片伺服器

将二手笔记本电脑转换成兼具视频转换和视频发布功能的服务器,并将其安装在家庭局域网中。考虑到本次协作是通过从NGINX启动ffmpeg来实现的,因此将两个服务器整合成一个更加便利。

然而,根据情况而定,有时候只需要在家庭网络中设置视频转换服务器,而将视频分发服务器放在独立的互联网上,或者将视频分发与web服务器合为一体可能更好。

2-2-1: 阿尔马 Linux 8

在笔记本电脑上安装Alma Linux 8,无需进行特殊操作。

为什么选择 Alma Linux ?只是因为我们习惯了 CentOS,并且没有其他的理由。任何 Linux 发行版都可以。

这个视频服务器在家庭内的局域网上的IP地址设置为192.168.0.99。

2-2-2:ffmpeg

在互联网上,可以看到许多关于从源代码编译FFmpeg的文章,但是如果选择这条路通常会遇到困难。也许在过去我们别无选择,但是现在有软件包可用,我们没有必要遭受多余的麻烦。

使用 RPM Fusion 存储库来安装ffmpeg。

首先,需要安装EPEL存储库。

# dnf install epel-release
# dnf config-manager --enable epel 

接下来,启用 powertools 和 epel-playground 软件仓库。

# dnf config-manager --set-enabled powertools
# dnf config-manager --set-enabled epel-playground

以前名为PowerTools的powertools,不知何时全部变成了小写。

然后安装RPM Fusion软件仓库。

# rpm -ivh https://download1.rpmfusion.org/free/el/rpmfusion-free-release-8.noarch.rpm

用这个方法可以安装ffmpeg。

# dnf install ffmpeg

我想让您参考一下《在 CentOS 8 上使用 RPMFusion 存储库安装 FFmpeg》(https://www.rootlinks.net/2020/02/17/install-ffmpeg-on-centos-8-with-rpmfusion-repo/)这篇文章。尽管标题是英文,但这是一篇日文文章。

2-2-3: NGINX + nginx-rtmp-module can be expressed in Chinese as 两-两-三:NGINX + nginx-rtmp-module.

只要使用软件包就可以使用NGINX,但是为了使用nginx-rtmp-module,需要获取源代码并进行构建。

2-2-3-1 : 记录包装版设定

然而,作为顺序来说,最好先安装包装版。

在配置构建、服务注册等方面,记录并复用软件包版本的设置将使得 NGINX 的运维更轻松。

由于操作系统标准的软件包较为陈旧,建议使用NGINX官方仓库的软件包代替。请按照官方网页(nginx:Linux Packages)上的指示进行安装。

在安装后,使用 `nginx -V` 命令确认并记录构建配置,并将服务配置文件 `/usr/lib/systemd/system/nginx.service` 用另一个名称保存。

在构建之前,先卸载。

2-2-3-2: 进行构建

参考NGINX官方网站上的技术博客《使用NGINX和NGINX Plus实现远程学习的视频流技术》,来进行工作。

首先,安装用于构建的工具。

$ sudo yum update
$ sudo yum groupinstall "Development Tools"
$ sudo yum install git

然后,安装依赖包。

$ sudo yum install pcre-devel zlib-devel openssl-devel libxslt-devel gd-devel perl-ExtUtils-Embed

然后,创建一个适当的构建目录,并进入其中,从 GitHub 克隆获取nginx-rtmp-module和nginx的源代码。

$ cd /path/to/build/dir
$ git clone https://github.com/arut/nginx-rtmp-module.git
$ git clone https://github.com/nginx/nginx.git

进入Nginx目录,添加nginx-rtmp-module到配置中,并进行构建和安装。

$ cd nginx
$ ./auto/configure \
--prefix=/etc/nginx \
--sbin-path=/usr/sbin/nginx \
--modules-path=/usr/lib64/nginx/modules \
--conf-path=/etc/nginx/nginx.conf \
--error-log-path=/var/log/nginx/error.log \
--http-log-path=/var/log/nginx/access.log \
--pid-path=/var/run/nginx.pid \
--lock-path=/var/run/nginx.lock \
--http-client-body-temp-path=/var/cache/nginx/client_temp \
--http-proxy-temp-path=/var/cache/nginx/proxy_temp \
--http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp \
--http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp \
--http-scgi-temp-path=/var/cache/nginx/scgi_temp \
--user=nginx \
--group=nginx \
--with-compat \
--with-file-aio \
--with-threads \
--with-http_addition_module \
--with-http_auth_request_module \
--with-http_dav_module \
--with-http_flv_module \
--with-http_gunzip_module \
--with-http_gzip_static_module \
--with-http_mp4_module \
--with-http_random_index_module \
--with-http_realip_module \
--with-http_secure_link_module \
--with-http_slice_module \
--with-http_ssl_module \
--with-http_stub_status_module \
--with-http_sub_module \
--with-http_v2_module \
--with-mail \
--with-mail_ssl_module \
--with-stream \
--with-stream_realip_module \
--with-stream_ssl_module \
--with-stream_ssl_preread_module \
--with-cc-opt='-O2 -g -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fexceptions -fstack-protector-strong -grecord-gcc-switches -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -fPIC' \
--with-ld-opt='-Wl,-z,relro -Wl,-z,now -pie' \
--add-module=../nginx-rtmp-module
$ make
$ sudo make install

上述参数是在使用nginx -V命令启动并确认了包装版本后,添加了–add-module=../nginx-rtmp-module的配置。

既然NGINX已经运行了,为了保险起见,要确认一下。

$ sudo nginx

从连接到家庭内局域网的个人电脑访问动画服务器的主页(http://192.168.0.99/)时,应该会显示NGINX的欢迎页面。(但需要进行防火墙的设置,请见后续说明。)

创建”/usr/lib/systemd/system/nginx.service”文件(如果有备份文件请将其恢复),将NGINX注册为服务。

[Unit]
Description=The nginx HTTP and reverse proxy server
After=network.target remote-fs.target nss-lookup.target

[Service]
Type=forking
PIDFile=/run/nginx.pid
# Nginx will fail to start if /run/nginx.pid already exists but has the wrong
# SELinux context. This might happen when running `nginx -t` from the cmdline.
# https://bugzilla.redhat.com/show_bug.cgi?id=1268621
ExecStartPre=/usr/bin/rm -f /run/nginx.pid
ExecStartPre=/usr/sbin/nginx -t
ExecStart=/usr/sbin/nginx
ExecReload=/bin/kill -s HUP $MAINPID
KillSignal=SIGQUIT
TimeoutStopSec=5
KillMode=mixed
PrivateTmp=true

[Install]
WantedBy=multi-user.target

通过这个命令,您可以使用 systemctl (start|stop|restart|enable|disable) nginx。

尽管视频流媒体尚不可用(因为没有进行相应的设置,这是理所当然的),但只要安装ffmpeg和NGINX + nginx-rtmp-module,就可以说已经获得了胜利。

接下来需要进行的是通过FFmpeg进行视频转换的设置和通过NGINX进行视频分发的设置,但在此之前需要先完成视频服务器的运营所需的环境准备工作。

2-2-4: 视频服务器环境的建设

2-2-4-1: 防火墙

为了允许HTTP、HTTPS、RTSP和RTMP协议通过,需要开放相应的端口。

$ sudo firewall-cmd --permanent --add-service=http 
$ sudo firewall-cmd --permanent --add-service=https 
$ sudo firewall-cmd --permanent --add-service=rtsp
$ sudo firewall-cmd --permanent --add-port=1935/tcp
$ sudo firewall-cmd --reload

RTMP 的标准端口是1935/tcp。RTSP 的标准端口为554/tcp和554/udp,但在Alma Linux (CentOS) 8中可以使用 –add-service=rtsp 进行配置。

2-2-4-2:路由器的端口映射

为了能够通过互联网访问视频服务器,需要更改家庭局域网路由器的端口映射设置,以便将WAN侧的全局地址的请求转发到局域网内的视频服务器本地地址(192.168.0.99)。

只需将http(80)、https(443)和rtmp(1935)映射即可,但为了远程管理,还需要映射ssh(22)。

2-2-4-3: 动态 DNS(Dynamic DNS)

为了能够通过域名而非IP地址指定视频服务器,可以使用动态DNS(DDNS)服务。

将nginx.conf文件中的server_name更改为DDNS域名(假设为camsvr.on.ddns),然后重新启动NGINX。

http {
    server {
        server_name  camsvr.on.ddns;

我想确认一下在这个区域,路由器的端口映射和DDNS是否能够按预期工作,但为了做到这一点,必须离开家庭局域网。即使通过连接到家庭局域网的PC的网络浏览器访问http://camsvr.on.ddns/,视频服务器的NGINX欢迎页面也不会显示,而是显示路由器的主页(http://192.168.0.1/)。换句话说,端口映射对于局域网内的访问不起作用。为了测试,最好使用断开Wi-Fi连接的智能手机的浏览器。

有关DDNS的自动更新,请参考”CentOS8中DDNS的自动更新(仅适用于MyDNS.JP)”。

2-2-4-4:Let’s Encrypt → 两-两-四-四:让我们一起加密

按计划,视频流的网页将以现有的网页服务器提供的页面为基础,混合新设的视频服务器的内容。网页服务器已经配置了SSL,并提供了整个页面的https化。如果混合SSL未支持的http内容,则会出现问题。

那么,使用Let’s Encrypt来为视频服务器进行SSL加密。

请参考「CentOS8(nginx)使用certbot进行简单自由的SSL化和SSL自动更新」以了解详细步骤。

在完成以上所述的 (1) 防火墙、(2) 路由器端口映射和 (3) DDNS 设置之后,启动 NGINX 并运行 certbot。这样一来,在获取证书的同时,certbot 会自动在 nginx.conf 文件中进行适当的更改,实现将视频服务器进行 SSL 加密。

http {
    server {
        server_name  camsvr.on.ddns;
        listen 443 ssl; # managed by Certbot
        ssl_certificate /etc/letsencrypt/live/camsvr.on.ddns/fullchain.pem; # managed by Certbot
        ssl_certificate_key /etc/letsencrypt/live/camsvr.on.ddns/privkey.pem; # managed by Certbot
        include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
        ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
    }
    server {
        if ($host = camsvr.on.ddns) {
            return 301 https://$host$request_uri;
        } # managed by Certbot
        listen 80;
        server_name  camsvr.on.ddns;
        return 404; # managed by Certbot
    }
}

这篇文章中被标注为“由Certbot管理”的部分表示Certbot对其进行了修改或添加。

2-2-4-5 : 跨域资源共享(CORS)标头

すぐ上で述べたように、動画配信のウェブ・ページは、既存のウェブ・サーバが提供するページに、新設の動画サーバからのコンテンツが混じる形になる予定である。このとき CORS (Cross-Origin Resource Sharing) の問題が生じる。

これに対処するために、動画サーバからのレスポンスに CORS 対応のヘッダを追加する。

http {
    server {
        location / {
            # CORS start
            add_header 'Access-Control-Allow-Origin' 'https://my.web.server' always;
            # Allow CORS preflight requests
            if ($request_method = 'OPTIONS') {
                add_header 'Access-Control-Allow-Origin' 'https://my.web.server';
                add_header 'Access-Control-Max-Age' 1728000;
                add_header 'Content-Type' 'text/plain charset=UTF-8';
                add_header 'Content-Length' 0;
                return 204;
            }
            # CORS end
        }
    }
}

身許を知っている特定のオリジンのみを許すという設定である。正直に言うが、私には CORS はよく判らない。とりあえず安全側に振り切っておく。

2-2-5: 通过NGINX进行视频分发

参考《使用 NGINX 和 NGINX Plus 对远程学习进行视频流媒体》来在 nginx.conf 中添加视频流媒体配置。

以下是用于HLS的配置。

http { 
    server { 
        location / { 
            root /tmp/hls; 
        } 
    }
    types {
        application/vnd.apple.mpegurl m3u8;
        video/mp2t ts;
        text/html html;
    } 
}
rtmp { 
    server { 
        listen 1935; 
        application livecam { 
            live on; 
            interleave on;
            hls on; 
            hls_path /tmp/hls;
            hls_fragment 1s;
            hls_playlist_length 10s;
        } 
    } 
} 

http > server > location / の root を /tmp/hls に変更

http > types のブロックを追加設定

html に加えて、HLS 用の m3u8 と ts のタイプを設定

rtmp のブロックを追加設定

hls_path は /tmp/hls とする

hls_fragment は個々のフラグメント (= ts ファイル) の長さ。1 秒とする。

hls_playlist_length はプレイリスト全体の長さ。10 秒とする。

http 側の location > root の設定と rtmp 側の hls_path 設定が対になる。この動画サーバは / 直下で HLS 動画を配信する設定である。

hls_fragment と hls_playlist_length を短く設定すると再生遅延が小さくなる。ただし、ストリームのキー・フレーム間隔より短い hls_fragment を指定しても無視されるので、後述するように、ffmpeg による動画変換の際にキー・フレーム間隔を適切に設定する必要がある。

2-2-6 : 使用ffmpeg进行视频转换

最后,使用FFmpeg将IP摄像机的RTSP流转换为RTMP流,并将其发送到视频流媒体服务器。

最基本的设置如下。

$ ffmpeg -i rtsp://192.168.0.101/12.amp -c copy \
    -f flv rtmp://192.168.0.99/livecam/std

-i rtsp://192.168.0.101/12.amp … IP カメラの RTSP ストリームを入力として指定。

12 の部分は使用する IP カメラによって異なってくる。
SV3C SV-801W-1080P-HX は、11(1920 x 1080) と 12(640 x 352) の二つのストリームを提供している。ここでは後者を使用する。

-c copy … コーデックは入力のままとする。

-f flv … 出力形式の指定。FLV は、Flash Video。

rtmp://192.168.0.99/livecam/std … 出力先の指定。

livecam … application 名。

std … ストリーム名。

RTMP の URL は rtmp://camsvr.on.ddns/livecam/std となる。

HLS の URL は https://camsvr.on.ddns/std.m3u8 となる。

動画を加工しなくて良い場合は -c copy が使える。入力のデコードと出力のエンコードの手間が省けるので、CPU の負担がほぼ皆無になる。

当涉及到更改图像大小、指定关键帧间隔或调整颜色时,情况就变得稍微复杂起来,同时会增加CPU的负担。

$ ffmpeg -rtsp_transport tcp -i rtsp://192.168.0.101/12.amp \
    -c:v libx264 -b:v 512k -r 15 -x264-params keyint=30:scenecut=0 \
    -vf hue=h=10 -c:a aac -f flv rtmp://192.168.0.99/livecam/std

-rtsp_transport tcp … RTSP 通信を TCP で行う。

-i オプションより前に指定する必要がある。

max delay reached. need to consume packet / RTP: missed xx packets というエラーが頻発する場合に指定すると良いらしい。うちの環境では効果があった。

-c:v libx264 … ビデオ・コーデックの指定。H.264 である。

-b:v 512k … ビデオのビット・レートの指定。512kb/sec。

-r 15 … フレーム・レートの指定。15 fps。

-x264-params keyint=15:scenecut=0 … キーフレーム間隔の指定。15 フレーム、すなわち、1 秒。

HLS の hls_fragment 以下のキー・フレーム間隔を指定する必要がある。

-vf hue=h=10 … ビデオ・フィルタの指定。色相を 10 度回転。

-c:a aac … オーディオ・コーデックの指定。(※)

色相の調整は、この IP カメラの機種としての特性なのか、個体としての特性なのか、画像の赤みが強すぎるのを補正しようとするものだ。

(※) 音声トラックについて (2021年10月 追記)

以前は、音声について、-an (音声無し) を指定していた。それで特に問題は無かったのだが、2021年10月に iOS を 15 に上げた iPhone で、Safari でも Chrome でも、動画再生が開始されるまでに非常に長い時間待たされるようになった。試しに -an の代りに -c:a aac を指定すると、すんなりと動画再生が開始される。どうやら、iOS 15 が音声トラックを受信しようとして長い間リトライを繰り返すらしい。という次第なので、-an の指定はしない方が良いだろう。

2-2-6-1:ffmpeg的监视(已过时)

IP カメラの誤動作などで RTSP ストリームが乱れると ffmpeg が終了する場合がある。それでは動画変換サーバとして具合が悪いので、ffmpeg の動作を監視して止っていたら再起動するシェル・スクリプトを作成する。

#!/usr/bin/bash
# The script runs for 18 hours (12 x 60 x 18 = 12960)
limit=12960
counter=0
while [ $counter -le $limit ]; do
    sleep 5
    alive=`ps -aef | grep ffmpeg | grep livecam | wc -l`
    # echo `date` ":ffmpeg alive ="$alive
    if [ $alive = 0 ]; then
        echo `date` " : ffmpeg is not running."
        echo "starting ffmpeg ..."
        ffmpeg -rtsp_transport tcp -i rtsp://192.168.0.101/12.amp \
            -c:v libx264 -b:v 512k -r 15 -x264-params keyint=30:scenecut=0 \
            -vf hue=h=10 -c:a aac -f flv rtmp://192.168.0.99/livecam/std \
             2>>/var/log/nginx/ffmpeg.log &
        echo "done."
    fi
    ((counter++))
done

18時間にわたって、5秒ごとに ffmpeg の生存をチェックし、死んでいたら起動する。このスクリプトを cron で毎日 3:00 AM に起動する。9:00 PM から 3:00 AM の間は死んでいても良い、というズボラな設定である。

2-2-6-2: 在 NGINX 上启动 ffmpeg(已被弃用)

実は上記のように自分で ffmpeg を起動して監視する必要は無い。NGINX に ffmpeg を起動させればよい。

        application livecam { 
            live on; 
            interleave on;
            hls on; 
            hls_path /tmp/hls; 
            hls_fragment 1s;
            hls_playlist_length 10s;
            exec_static /usr/bin/ffmpeg -rtsp_transport tcp \
                -i rtsp://192.168.0.101/12.amp \
                -c:v libx264 -b:v 512k -r 15 -x264-params keyint=15:scenecut=0 \
                -vf hue=h=10 -c:a aac -f flv rtmp://192.168.0.99/livecam/std
                2>>/var/log/nginx/ffmpeg-std.log;
        } 

ここでは exec_static を使っているが、その理由は、何故か判らないが私の環境では exec_push が期待通りに ffmpeg を起動しない、ということにある。この障害は nginx-rtmp-module の github にも開いたままの issue として記録されており、大勢の人を悩ませているようである。

さいわい exec_static なら起動に成功する。そして起動された ffmpeg を殺しても、NGINX が監視しているのだろう、すかさず別のインスタンスが起動される。NGINX を終了させると ffmpeg も終了する。これで良い。

と思ったのだが、これではうまく行かない場合があった。ffmpeg が死なずに止ってしまう ことがある。つまり、ps で見ると生きているが、top で見ると全く働いていない状態に陥る場合がある。

2-2-6-3: FFmpeg的监视(再次)

当监控FFmpeg,如果它死掉或处于空闲状态,就运行一个脚本来重启整个NGINX。

#!/usr/bin/bash
# The script runs for 14 hours (60 x 60 x 14 = 50400) by default
LIMIT=50400
if [ $# -ge 1 ]; then
^Ilet LIMIT=$1
fi
echo "Going to check ffmpeg for $LIMIT seconds ..." 1>&2
# counter
DYING=0
# limit to restart nginx
DYING_LIMIT=5
$
while [ $I -lt $LIMIT ];
do
  echo -n "`date +"%m-%d %H:%M:%S"` " 1>&2
  TOPINFO=`top -b -n 1 | grep ffmpeg`
  INFO=($TOPINFO)
  if [ "$INFO" = "" ]; then
    let DYING++
    echo "--- warning $DYING." 1>&2
  else
    CPU=${INFO[8]}
    CPUX=${CPU/./}
    if [ $CPUX -ge 50 ]; then
      let DYING=0
      echo "$CPU" 1>&2
    else
      let DYING++
      echo "$CPU warning $DYING." 1>&2
    fi
  fi
  if [ $DYING -ge $DYING_LIMIT ]; then
    echo "Restarting nginx ..." 1>&2
    systemctl restart nginx
    let DYING=0
    sleep 3
  fi
  sleep 1
  let I++
done
echo "Finished." 1>&2

1秒ごとに top で ffmpeg の情報の取得を試みて、情報が取得できなかったり、CPU 使用率が 5% を割っている状態が5秒続いたら、NGINX を再起動する。

嗯,这件事情确实有些粗糙,可能会让专家们发笑。

目前,我們每天05:00通過cron在執行這個腳本。

0 5 * * * root /root/ffcheck.sh &> /var/log/nginx/ffcheck.log

2-3: 客户端

2-3-1 : RTMP ストリームの再生

VLC や MPC-HC などのプレーヤーでは、URL rtmp://camsvr.on.ddns/livecam/std を開くことによって、RTMP ストリームを再生することが出来る。

2-3-2:网页

在网页中使用JavaScript视频播放库VIDEO JS轻松播放HLS流。

<head>
    <link href="https://vjs.zencdn.net/8.3.0/video-js.min.css" rel="stylesheet" />
</head>

<body>
    <video id="live-cam" class="video-js" controls autoplay
            width="640" height="352" data-setup="{}">
        <source src="https://camsvr.on.ddns/std.m3u8" type="application/x-mpegURL" />
        <p class="vjs-no-js">
            この動画を見るためには JavaScript を有効にし、
            HTML5 の video タグをサポートするブラウザを使って下さい。
        </p>
    </video>

    <script src="https://vjs.zencdn.net/8.3.0/video.min.js"></script>
</body>

请参考VIDEO JS官方网站的“入门指南”和文档以获取更详细的信息。

(2023年8月 追記)在iPhone(iOS 16.x)上无法正确播放。

不明原因,但似乎是iPhone的问题。

2-4:将内容直播到YouTube。

如果要在YouTube上进行直播,可以按照以下方式操作。

        application youtube { 
            live on; 
            interleave on;
            exec_static /usr/bin/ffmpeg -rtsp_transport tcp \
                -i rtsp://192.168.0.101/12.amp -c:v libx264 -r 15 -s 640x360 -b:v 512k \
                -c:a aac -f flv rtmp: //192.168.0.99/youtube/you-tube-stream-key \
                2>>/var/log/nginx/ffmpeg-youtube.log;
            push rtmp://a.youtube.com/live2/you-tube-stream-key;
        }

-s 640×360 … 640×352 のサイズは受け付けてくれない。ちょっと手抜き。scale と pad を設定する方が良い。

-c:a aac … YouTube は音声無しのストリームを受け付けてくれない。

没有意识到没有声音的流媒体是不可行的,我纠结了三天。

如果使用YouTube直播的话,可以先打开应用程序,只在需要时启动ffmpeg也可以。

3:最后

IP摄像机的网页视频发布工作已经结束了。

我由衷地感谢那些使用自由软件(开源软件)的开发者们,以及在网络上公开分享他们的知识和经验的人们(无论是在本文中提供链接,还是在其他文档中参考过的)。

請對閱讀這篇文章的讀者們提出要求,如果發現任何錯誤或不正確之處,請務必指導改進。

广告
将在 10 秒后关闭
bannerAds