使用FFmpeg + nginx + flv.js 实现RTSP格式视频流在web网页进行播放

1 篇文章 0 订阅

近期,出于项目需要,要求支持web网页播放RTSP格式的监控视频。因之前并没有相关的项目经验及技术积累。并且H5中的video默认并不支持RTSP格式的视频播放,接下来花了一周时间,都在进行调研和实践网上搜到的方案。

1、vlc插件 + video标签

起初,找到的实现方式,是利用第三方插件,vlc播放器或者在谷歌浏览器上安装vlc视频插件的方案。在实践过程中发现,该方案,依赖于谷歌浏览器支持NPAPI插件。谷歌浏览器目前已经不知道该插件,即使后来费了很多时间在网上找谷歌浏览器40-44版本,尝试进行播放,页面也提示“该插件不支持”。同时,低版本谷歌浏览器基本是2015年之前的,对于ES6语法还有样式上的兼容,也多少存在一些问题,还有就是下载的版本居然连打开开发者工具都闪退,果断放弃了在低版本谷歌浏览器的开发计划。

之后有尝试谷歌浏览器能不能播放RTMP格式的视频流,结果依旧没有成功;究其原因,是由于2021年之后的谷歌浏览器版本已不再支持flash插件,且之前的任何浏览器版本都不再支持flash插件,即使在设置中打开的flash的控制,页面依然显示“adobe flash player 不再支持”的字样。。。

2、nginx + ffmpeg + flv.js

翻找了很多相关的技术文章,esayPlayer也安装过,加开发群咨询技术问题,反馈都说前端H5无法直接播放RTSP视频流,只能转格式,但是推荐的服务又是付费的,目前项目并不打算使用第三方服务,将视频放在公网环境进行存储播放,所以也就作罢了。

最终,选择了这个看上去技术实践并不是很困难的方式。该方式的实现原理,通过服务端将其 RTSP / RTMP 流实时转为 http-flv 流,从而浏览器可直接使用该流进行直播(使用bilibili提供的 flv.js )。

该实现方式的前提条件:
(1)nginx

(2)nginx-http-flv-module

(3)ffmpeg

  (4)  flv.js

2.1 配置流程

2.1.1 nginx 补充 nginx-http-flv-module模块

// 步骤:

// 1、下载 nginx-http-flv-module

下载 https://github.com/winshining/nginx-http-flv-module 项目


// 2、下载 nginx 安装包,解压后进入对应包文件夹中

cd /usr/local

tar -zxvf nginx-1.8.1.tar.gz

cd nginx-1.21.1 


// 3、在nginx安装文件夹中,执行以下命令,安装nginx-http-flv-module,--add-module后拼接的是nginx-http-flv-module 项目的存放路径

./configure --prefix=/usr/local/nginx  --add-module=/usr/local/nginx/nginx-http-flv-module


// 4、手动编译并重新安装nginx,此时nginx将被安装到 

make && make install


// 5、重启nginx

nginx -s reload 

遇到的问题:

(1)已有nginx,安装路径下,并没有 configure文件

我是在mac上直接进行配置操作的,但是进入nginx的安装路径 /usr/local/Cellar/nginx下(之前通过brew install nginx 进行安装的),并没有找到 congfigure文件。在网上找了nginx的安装压缩包,拷贝其中的 congfigure 进行了补充。但由于是第一次搞这个配置,怕又出什么幺蛾子,就先用 brew uninstall nginx 把之前的卸载了。重新按照上边的方式,一步步进行了操作;

(2)nginx补充模块时报openssl库缺失

./configure: error: SSL modules require the OpenSSL library.
You can either do not enable the modules, or install the OpenSSL library
into the system, or build the OpenSSL library statically from the source
with nginx by using --with-openssl=<path> option.


依照该报文提示,先检查是否已经安装openssl库

如果没有, 执行安装命令  brew  install openssl

然后,修改 nginx 安装第三方模块的命令, --with-openssl=拼接openssl的安装路径:

./configure --prefix=/usr/local/nginx  --add-module=/usr/local/nginx/nginx-http-flv-module --with-openssl=/usr/local/Cellar/openssl@1.1/1.1.1i

出现以下类似文案,表明命令执行成功:

Configuration summary
  + using system PCRE library
  + using OpenSSL library: /usr/local/Cellar/openssl@1.1/1.1.1i
  + using system zlib library

  nginx path prefix: "/usr/local/nginx"
  nginx binary file: "/usr/local/nginx/sbin/nginx"
  nginx modules path: "/usr/local/nginx/modules"
  nginx configuration prefix: "/usr/local/nginx/conf"
  nginx configuration file: "/usr/local/nginx/conf/nginx.conf"
  nginx pid file: "/usr/local/nginx/logs/nginx.pid"
  nginx error log file: "/usr/local/nginx/logs/error.log"
  nginx http access log file: "/usr/local/nginx/logs/access.log"
  nginx http client request body temporary files: "client_body_temp"
  nginx http proxy temporary files: "proxy_temp"
  nginx http fastcgi temporary files: "fastcgi_temp"
  nginx http uwsgi temporary files: "uwsgi_temp"
  nginx http scgi temporary files: "scgi_temp"

 

 (3)执行make install 提示没有权限

// 错误报文

/Library/Developer/CommandLineTools/usr/bin/make -f objs/Makefile install
test -d '/usr/local/nginx' || mkdir -p '/usr/local/nginx'
mkdir: /usr/local/nginx: Permission denied
make[1]: *** [install] Error 1
make: *** [install] Error 2

处理方案:

sudo make install  // 需要输入密码

  (4)nginx 不存在

// 错误报文
app@xxx local% nginx -v
zsh: command not found: nginx

处理方案:

修改/etc/profile文件

进入文件编辑 vim /etc/profile 

输入 i 进入编辑状态

# System-wide .profile for sh(1)

if [ -x /usr/libexec/path_helper ]; then
	eval `/usr/libexec/path_helper -s`
fi

if [ "${BASH-no}" != "no" ]; then
	[ -r /etc/bashrc ] && . /etc/bashrc
fi

// 在该文件末尾补充以下文字,注意nginx安装后的路径

PATH=$PATH:/usr/local/nginx/sbin
export PATH

按 esc 退出编辑状态
按 :wq 强制更新文件
cat  /etc/profile 查看编辑后的文件内容

最后,记得执行   source /etc/profile  重启该配置文件

输入以下结果表明全局可使用nginx

app@xxx local% nginx -v
nginx version: nginx/1.21.1

2.1.2 修改 nginx 配置文件

该配置,按照nginx-http-flv-module 项目中提供的配置进行修改即可,以下是我的nginx.conf中相关的配置——标记“重要”的配置。

配置修改完成之后,记得重启nginx服务: nginx -s reload

#user  nobody;
worker_processes  1;

#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#pid        logs/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       mime.types;
    default_type  application/octet-stream;

    #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
    #                  '$status $body_bytes_sent "$http_referer" '
    #                  '"$http_user_agent" "$http_x_forwarded_for"';

    #access_log  logs/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  65;

    #gzip  on;

    server {
        listen       80;
        server_name  localhost;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {
            root   html;
            index  index.html index.htm;
        }



        # 重要 http-flv  转流配置

        location /live {
            flv_live on; #打开 HTTP 播放 FLV 直播流功能
            chunked_transfer_encoding on; #支持 'Transfer-Encoding: chunked' 方式回复

            add_header 'Access-Control-Allow-Origin' '*'; #添加额外的 HTTP 头
            add_header 'Access-Control-Allow-Credentials' 'true'; #添加额外的 HTTP 头
            add_header 'Cache-Control' 'no-cache';
        }





        #error_page  404              /404.html;

        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }

}

# 重要  rtmp推流相关配置

rtmp_auto_push on;
rtmp_auto_push_reconnect 1s;
rtmp_socket_dir /tmp;
 
rtmp {
    out_queue           4096;
    out_cork            8;
    max_streams         128;
    timeout             15s;
    drop_idle_publisher 15s;
 
    log_interval 5s; #log模块在access.log中记录日志的间隔时间,对调试非常有用
    log_size     1m; #log模块用来记录日志的缓冲区大小
 
    server {
        listen 1935;
        # server_name www.test.*;  #当模块中,只有一个server时,可以不配置server_name,nginx对于请求,当找不到匹配的server_name时,会默认发给第一个server进行处理。
 
        application myapp {
            live on;
            gop_cache on; #打开GOP缓存,减少首屏等待时间
        }

    }
}

2.2 执行拉流、推流操作

// ffmpeg的拉流、推流命令,可自行搜索,以下命令,是将一个本地RTSP的视频流,转为http-flv的过程,
其中视频、音频格式直接复制,没有进行转码操作

ffmpeg -rtsp_transport tcp -i  rtsp://admin:xxx@127.0.0.1:554/Streaming/Channels/101 -c copy -f flv rtmp://127.0.0.1:1935/live/101

遇到的问题

(1)无法执行以上命令,报错: RTMP_ReadPacket, failed to read RTMP packet header

// 错误报文
[rtsp @ 0x7f8429008200] Missing PPS in sprop-parameter-sets, ignoring
Input #0, rtsp, from 'rtsp://admin:xxx@127.0.0.1:554/Streaming/Channels/101':
  Metadata:
    title           : Media Presentation
  Duration: N/A, start: 0.240000, bitrate: N/A
    Stream #0:0: Video: h264 (Main), yuvj420p(pc, bt709, progressive), 1280x720, 25 fps, 25 tbr, 90k tbn, 50 tbc
RTMP_ReadPacket, failed to read RTMP packet header
rtmp://127.0.0.1:1935/live/101: Unknown error occurred

处理方案:

以上报文,表明拉流操作正常,推流出现了问题,
排查了很久,最后,对比了之前的nginx配置发现

rtmp://127.0.0.1:1935/live/101  中的 live 没有对应配置,将其修改为 myapp 后成功执行


注意: 推流的地址格式———— rtmp://ip:port/appname/streamname  

其中,port  指nginx配置中rtmp相关配置下的监听端口 1935(可自行修改nginx中对应端口,注意不要与其他使用端口冲突)
appname  指 application 后的名称,可配置多个application,注意名称不可重复

nginx配置示例如下:

rtmp {
    out_queue           4096;
    out_cork            8;
    max_streams         128;
    timeout             15s;
    drop_idle_publisher 15s;
 
    log_interval 5s; #log模块在access.log中记录日志的间隔时间,对调试非常有用
    log_size     1m; #log模块用来记录日志的缓冲区大小
 
    server {
        listen 1935;
        # server_name www.test.*;  #当模块中,只有一个server时,可以不配置server_name,nginx对于请求,当找不到匹配的server_name时,会默认发给第一个server进行处理。
 
        application myapp {
            live on;
            gop_cache on; #打开GOP缓存,减少首屏等待时间
        }

    }
}

(2)无法执行以上命令,报错:RTMP_Connect0, failed to connect socket. 61 (Connection refused)

// 错误报文

[rtsp @ 0x7fd41d011000] Missing PPS in sprop-parameter-sets, ignoring
Input #0, rtsp, from 'rtsp://admin:xxx@127.0.0.1:554/Streaming/Channels/101':
  Metadata:
    title           : Media Presentation
  Duration: N/A, start: 0.240000, bitrate: N/A
    Stream #0:0: Video: h264 (Main), yuvj420p(pc, bt709, progressive), 1280x720, 25 fps, 25 tbr, 90k tbn, 50 tbc
RTMP_Connect0, failed to connect socket. 61 (Connection refused)
rtmp://127.0.0.1:1935/myapp/test: Unknown error occurred


处理方案:

网上搜索,提示是nginx服务未开启导致的,重启nginx即可

(3)延迟较大,超过10s以上

       通过以下操作,延迟明显缩小,但是在使用浏览器播放视频源地址,与页面上进行播放的视频进行对比,发现页面上的时间与播放器上的时间,依旧存在3-5s的差距,这个问题待后续跟进处理;

// 修改ffmpeg的命名,
// 补充 -tune zerolatency 控制延迟
// 补充 -preset ultrafast 转码速度


ffmpeg -rtsp_transport tcp -i "rtsp://admin:xxx@127.0.0.1:554/Streaming/Channels/102" -vcodec copy -acodec copy -f flv -tune zerolatency  -preset ultrafast "rtmp://127.0.0.1:1935/myapp/test" 

2.3 前端页面的输出

2.3.1 flv.js 安装

npm i flv.js

2.3.1 vue 页面导入flv.js

播放器组件封装,基本上都是按照flv.js 提供的demo进行配置的

<template>
  <div class="app-container">
    <div>原生video</div>
    <video id="videoElement" class="centeredVideo" controls autoplay width="480" height="320" muted>
      Your browser is too old which doesn't support HTML5 video.
    </video>
  </div>
</template>

<script>
import flvjs from 'flv.js'
export default {

  data() {
    return {
      
    }
  },
  mounted() {
    this.$nextTick(() => {
      if (flvjs.isSupported()) {
        const videoElement = document.getElementById('videoElement')
        var flvPlayer = flvjs.createPlayer(
          {
            type: 'flv',
            url: 'http://127.0.0.1/live?port=1935&app=myapp&stream=test',
            isLive: true, // <====加个这个
            hasAudio: false,
            hasVideo: true
            // withCredentials: false,
            // cors: true
          },
          {
            enableWorker: true, // 开启多线程
            enableStashBuffer: false,
            lazyLoad: false,
            lazyLoadMaxDuration: 0,
            lazyLoadRecoverDuration: 0,
            deferLoadAfterSourceOpen: false,
            fixAudioTimestampGap: true,
            autoCleanupSourceBuffer: true
          }
        )
        flvPlayer.attachMediaElement(videoElement)
        flvPlayer.load() // 加载
        videoElement.play()
      }
    })
  },
  methods: {
   
  }
}
</script>

遗留问题

(1)前端页面支持多个视频同时播放的处理,目前chrome等现代浏览器的同源策略限制,最多播放6个直播视频流;

(2)延迟5s以上的问题,同一个视频源,页面播放与使用vlc播放器直接播放RTSP视频流之间存在3-5s的延迟问题,有待后续跟进处理;

参考文档:

1、web实现RTSP无插件低延迟播放方案整理

2、基于nginx-rtmp-module模块实现的HTTP-FLV直播模块nginx-http-flv-module(一)

3、直播流转码 RTMP 转 HTTP-FLV 用于 WEB 播放解决流程

4、【入门】无插件web直播解决方案,ffmpeg+nginx-http-flv-module+flv.js

  • 2
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
PowerDesigner是一款功能强大的建模工具,可以帮助用户进行数据建模、业务流程建模等工作。本文将从下载、安装以及汉化的角度,介绍如何获取并使用PowerDesigner。 首先,我们需要前往官方网站或可靠的软件下载网站,例如CSDN,搜索并下载PowerDesigner的安装包。在CSDN网站上,我们可以找到PowerDesigner的最新版本,并获取一个稳定的下载链接。 下载完成后,双击安装包运行程序。按照安装向导的指引,选择安装路径和相关设置。安装过程可能会持续几分钟,取决于您的计算机性能。 安装完成后,打开PowerDesigner。首次打开时,需要进行激活操作。如果已经有了有效的许可证密钥,输入相关信息并激活即可。如果没有许可证密钥,可以选择试用模式,以获得30天的免费试用期。 接下来,我们来谈论汉化。通常情况下,PowerDesigner默认是英文界面,但希望使用汉化版本的用户可以选择在安装或使用进行汉化操作。 在CSDN网站上,我们可以找到PowerDesigner的汉化补丁,并进行下载。下载完成后,解压汉化补丁文件。 打开PowerDesigner,选择“工具”菜单,然后选择“选项”。在选项对话框中,找到“界面”选项,并点击“浏览”按钮。选择已经解压的汉化文件,并点击“确定”。 重新启动PowerDesigner,界面将会显示为汉化版本。现在,用户可以使用中文界面进行工作。 综上所述,要下载、安装和汉化PowerDesigner,我们可以通过在可靠的软件下载网站如CSDN上搜索并下载最新版本的安装包。安装完成后,进行激活操作,如果需要汉化,则可以下载汉化补丁并进行配置。这样,用户就可以方便地使用PowerDesigner进行工作了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值