1. 前言

前面几章我们已经把基础环境都已经搭建完成,这一章我们通过使用 nginx-http-flv-module 搭建一个可以通过HTTP请求并且通过flv.js实现在HTML网页播放实时视频的应用场景。

2. 安装nginx-http-flv-module模块

2.1 简述

nginx-http-flv-module是基于nginx-rtmp-module 的流媒体服务器。它具备了所有nginx-rtmp-module的功能,并且新增多种新功能,功能对比如下。

功能

nginx-http-flv-module

nginx-rtmp-module

备注

HTTP-FLV (播放)


x

支持 HTTPS-FLV 和 chunked 回复

GOP 缓存


x

虚拟主机


x

省略 listen 配置


见备注

配置中必须有一个 listen

纯音频支持


见备注

wait_video 或 wait_key 开启后无法工作

reuseport 支持


x

定时打印访问记录


x

JSON 风格的 stat


x

stat 中包含录制详情


x

2.2 兼容性

NGINX 的版本应该大于或者等于 1.2.6,与其他版本的兼容性未知。

2.3 支持的系统

  • Linux(推荐)/ FreeBSD / MacOS / Windows(受限)。

2.4 支持的播放器

  • VLC (RTMP & HTTP-FLV) / OBS (RTMP & HTTP-FLV) / JW Player (RTMP) / flv.js (HTTP-FLV)。

2.5 其他

其余详见 nginx-http-flv-module 下的 README.CN.md

2.6 下载

下载地址:https://github.com/winshining/nginx-http-flv-module 选择一个版本然后点击Code --> Download ZIP,这里最新版本为 v1.2.10,我选择的是 v1.2.8 版本。

nginx部署flask项目怎么配置 nginx flv module_ide


然后通过xftp远程工具将文件上传至服务器。

nginx部署flask项目怎么配置 nginx flv module_ffmpeg_02

2.7 编译安装

将已上传的nginx-http-flv-module解压。

[root@localhost download]# unzip nginx-http-flv-module-1.2.8.zip

对文件夹进行重命名(看个人习惯,不重命名也一样可以)。

[root@localhost download]# mv nginx-http-flv-module-1.2.8 nginx-http-flv-module
# 移动文件夹到 /usr/local/下
[root@localhost download]# mv ./nginx-http-flv-module /usr/local/

下面就可以重新编译nginx了,并将nginx-http-flv-module模块编译到nginx中。
进入最开始解压出来的nginx目录下。

[root@localhost download]# cd /opt/download/nginx-1.18.0/
# 执行编译命令
[root@localhost nginx-1.18.0]# ./configure --add-module=/usr/local/nginx-http-flv-module
[root@localhost nginx-1.18.0]# make && make install

接下来查看nginx是否安装成功nginx-http-flv-module模块,执行命令。

[root@localhost nginx-1.18.0]# nginx -V

nginx部署flask项目怎么配置 nginx flv module_nginx部署flask项目怎么配置_03


这里就说明我们安装成功了。

3. 配置nginx配置文件文件

修改nginx配置文件。

[root@localhost nginx-1.18.0]# cd /usr/local/nginx/conf/
[root@localhost conf]# vim ./live.conf

配置文件如下:

#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;
}

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 7933;
        
        application myapp {
            live on;
        }
       application hls {
            live on;
            hls on;
            hls_path /tmp/hls;
        }
        
        application dash {
            live on;
            dash on;
            dash_path /tmp/dash;
        }
    }

}

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;

        #access_log  logs/host.access.log  main;

        location / {
            add_header 'Access-Control-Allow-Origin' '*';
            root   html;
            index  index.html index.htm;
        }

        location /live {
            flv_live on;
            chunked_transfer_encoding on; #支持'Transfer-Encoding: chunked'方式回复 
            add_header 'Access-Control-Allow-Origin' '*'; #添加额外的 HTTP 头
            add_header 'Access-Control-Allow-Credentials' 'true'; #添加额外的 HTTP 头      
         }

        location /flv {
            add_header 'Access-Control-Allow-Origin' '*';
            flv_live on;
            chunked_transfer_encoding on;
        }

	# control控制器
	location /control {
	    rtmp_control all;
	}
        location /stat {
            #推流播放和录制统计数据的配置
            rtmp_stat all;
            rtmp_stat_stylesheet stat.xsl;
         }
         location /stat.xsl {
             root /usr/local/nginx-http-flv-module/; #指定 stat.xsl 的位置
         }
        #error_page  404              /404.html;

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
}

主要配置为: rtmp标签下的server配置其监听7933端口,并配置location myapp设置属性live on 表示开启直播。http标签下的server配置其监听80端口,并配置location /live设置属性 flv_live on。注意其中的 add_header ‘Access-Control-Allow-Origin’ ‘*’add_header ‘Access-Control-Allow-Credentials’ ‘true’ 很重要,主要解决了前端通过HTTP方式拉流是的跨域问题。
目前nginx-http-flv-module模块配置完成,并且nginx配置文件也已经配置完成 下面进行推流与拉流测试。
执行推流命令:

ffmpeg -rtsp_transport tcp -i rtsp://admin:Admin12345@192.168.1.65:554/h264/ch0/main/av_stream -c:v libx264 -c:a aac -f flv -an rtmp://192.168.5.177:7933/myapp/room

nginx部署flask项目怎么配置 nginx flv module_nginx部署flask项目怎么配置_04


推流成功。这里我说明一下 我使用的是海康威视的网络摄像头 rtsp://admin:Admin12345@192.168.1.65:554/h264/ch0/main/av_stream 这个地址是我的摄像头播放地址,请查看并使用你使用的摄像头播放地址。

下面通过VLC播放器进行拉流播放。

播放URL为 http://192.168.5.177/live?port=7933&app=myapp&stream=room 其中192.168.5.177换成你的服务器ip ,live是nginx配置文件中配置的请求地址,可以查看nginx配置文件中的配置,port为nginx配置文件中rtmp标签下server监听的端口号(注意开放服务器防火墙),app=myapp这个myapp与rtmp标签下 server下的location myapp所对应,stream=room这个room与你推流地址所对应。

nginx部署flask项目怎么配置 nginx flv module_音视频_05


点击播放。

nginx部署flask项目怎么配置 nginx flv module_ide_06


播放成功。

4. 通过VUE播放实时视频流

首先创建一个新的vue项目,并通过编辑器打开项目。

E:\vueCode>vue create live
# 执行命令运行项目
E:\vueCode\live> npm run serve

nginx部署flask项目怎么配置 nginx flv module_ffmpeg_07


由于我们只需要使用一个页面那么我就直接在app.vue页面直接写了。

下面先安装flv.js,执行命令。

E:\vueCode\live> npm install --save flv.js

nginx部署flask项目怎么配置 nginx flv module_音视频_08


安装完成,下面进行编码。

<template>
  <div id="app">
    <video
      id="videoLive"
      crossorigin="anonymous"
      controls
      autoplay
      width="100%"
      height="100%"
      style="object-fit: fill"
    ></video>
  </div>
</template>

<script>
import flvjs from "flv.js";

export default {
  name: "App",
  data() {
    return {
      flvPlayer: null,
    };
  },
  mounted() {
    this.createVideo('http://192.168.5.177/live?port=7933&app=myapp&stream=room',"videoLive")
  },
  methods: {
    createVideo(url, elementId) {
      if (flvjs.isSupported()) {
        let videoElement = document.getElementById(elementId);
        this.flvPlayer = flvjs.createPlayer({
          type: "flv",
          enableWorker: true, //浏览器端开启flv.js的worker,多进程运行flv.js
          isLive: true, //直播模式
          hasAudio: false, //关闭音频
          hasVideo: true,
          stashInitialSize: 128,
          enableStashBuffer: true, //播放flv时,设置是否启用播放缓存,只在直播起作用。
          url: url,
        });
        this.flvPlayer.attachMediaElement(videoElement);
        this.flvPlayer.load();
        this.flvPlayer.play();
      }
    },
  },
};
</script>

<style>
#app {
  width: 640px;
  height: 480px;
  border: 1px red solid;
  margin: 0 auto;
}
</style>

保存并查看页面。

nginx部署flask项目怎么配置 nginx flv module_nginx部署flask项目怎么配置_09


此时页面就能够正常的播放摄像头的实时视频流了,不过这里两个问题,第一个问题是视频延时大概在6~7秒左右,这是延时是我们无法接受的,第二个问题是当我们在浏览器切换了一个标签后,我们发现视频默认暂停了,当我们再次回到页面的时候就需要手动调整进度条,这个是不行的不够友好。下面先来解决第一个延时问题。

这个延时问题主要是因为ffmpeg在对视频进行转码时的延迟,这时我们来优化ffmpeg转码参数,命令如下。

ffmpeg -rtsp_transport tcp -i rtsp://admin:Admin12345@192.168.1.65:554/h264/ch0/main/av_stream -c:v libx264 -c:a aac -threads 5 -preset ultrafast -max_delay 100000 -f flv -an rtmp://192.168.5.177:7933/myapp/room

对比第一条参数我们多加了 -threads 5 -preset ultrafast -max_delay 100000 参数,-threads 5的意思是 设置编解码等工作的线程数,线程数多了速度自然比一个线程处理的快 -preset ultrafast 用来指定视频的输出质量,它共有以下几个可以用的值:

  • ultrafast 超快的
  • superfast 超高速的
  • veryfast 非常快
  • faster 更快
  • fast 快
  • medium 中等
  • slow 缓慢的
  • slower 较慢的
  • veryslow 非常慢
    我们这里使用的是 ultrafast 超快的,-max_delay 100000 表示指定视频的最大延迟,这里设置100ms。调优参数就设置到这里,下面设置flv.js的参数。
createVideo(url, elementId) {
      if (flvjs.isSupported()) {
        let videoElement = document.getElementById(elementId);
        this.flvPlayer = flvjs.createPlayer({
          type: "flv",
          enableWorker: true, //浏览器端开启flv.js的worker,多进程运行flv.js
          isLive: true, //直播模式
          hasAudio: false, //关闭音频
          hasVideo: true,
          stashInitialSize: 128,
          enableStashBuffer: true, //播放flv时,设置是否启用播放缓存,只在直播起作用。
          url: url,
        }, {
          enableStashBuffer: false, //禁用IO存储缓存区
        });
        this.flvPlayer.attachMediaElement(videoElement);
        this.flvPlayer.load();
        this.flvPlayer.play();
      }
    }

主要参数为:

{
     enableStashBuffer: false, //禁用IO存储缓存区
  }

下面重新执行命令,并刷新页面,查看延迟效果。

nginx部署flask项目怎么配置 nginx flv module_ffmpeg_10


可以发现目前延迟大概在500ms左右,如果觉得还有有点慢的话可以调整转码的分辨率和视频大小等参数,可以自行百度查找。

下面解决第二个问题,切换标签页后页面自动暂停问题。

mounted() {
    this.createVideo('http://192.168.5.177/live?port=7933&app=myapp&stream=room',"videoLive")
    this.monitorVideo()
  },
  methods: {
    createVideo(url, elementId) {
      if (flvjs.isSupported()) {
        let videoElement = document.getElementById(elementId);
        this.flvPlayer = flvjs.createPlayer({
          type: "flv",
          enableWorker: true, //浏览器端开启flv.js的worker,多进程运行flv.js
          isLive: true, //直播模式
          hasAudio: false, //关闭音频
          hasVideo: true,
          stashInitialSize: 128,
          enableStashBuffer: true, //播放flv时,设置是否启用播放缓存,只在直播起作用。
          url: url,
        }, {
          enableStashBuffer: false, //禁用IO存储缓存区
        });
        this.flvPlayer.attachMediaElement(videoElement);
        this.flvPlayer.load();
        this.flvPlayer.play();
      }
    },
    monitorVideo(){
      let videoElement = document.getElementById("videoLive");
      videoElement.onpause =function(){
        //监听video标签是否暂停,如果暂停就让他继续播放
        if (videoElement.paused){
          videoElement.play()
        }
      }
    }
  },

主要参数如下:

nginx部署flask项目怎么配置 nginx flv module_ffmpeg_11


其思想就是监听video标签是否暂停,如果暂停了就让他继续播放,这就相当于做了一个后台播放效果出来了。

5. 掉线重连

这时如果视频服务器突然掉线了怎么办,解决方法如下。

methods: {
    createVideo(url, elementId) {
      if (flvjs.isSupported()) {
        let videoElement = document.getElementById(elementId);
        this.flvPlayer = flvjs.createPlayer(
          {
            type: "flv",
            enableWorker: true, //浏览器端开启flv.js的worker,多进程运行flv.js
            isLive: true, //直播模式
            hasAudio: false, //关闭音频
            hasVideo: true,
            stashInitialSize: 128,
            enableStashBuffer: true, //播放flv时,设置是否启用播放缓存,只在直播起作用。
            url: url,
          },
          {
            enableStashBuffer: false, //禁用IO存储缓存区
          }
        );
        this.flvPlayer.attachMediaElement(videoElement);
        if (url != null && url !== "") {
          this.flvPlayer.load();
          this.flvPlayer.play();
        }
        let _then = this;
        // 重连 监听flvPlayer异常
        this.flvPlayer.on(flvjs.Events.ERROR, function (errType, errDetail) {
          console.error("连接异常,正在尝试重新连接", errType, errDetail);
          //如果flvPlayer不为空
          if (_then.flvPlayer) {
            _then.reloadVideo(_then.flvPlayer, elementId, url);
          }
        });
      }
    },
    reloadVideo(flvPlayer, elementId, url) {
      this.destoryVideo(flvPlayer);
      // 重新执行createVideo方法
      this.createVideo(url, elementId);
    },
    //销毁flvPlayer
    destoryVideo(flvPlayer) {
      flvPlayer.pause();
      flvPlayer.unload();
      flvPlayer.detachMediaElement();
      flvPlayer.destroy();
      flvPlayer = null;
    },
    monitorVideo() {
      let videoElement = document.getElementById("videoLive");
      videoElement.onpause = function () {
        //监听video标签是否暂停,如果暂停就让他继续播放
        if (videoElement.paused) {
          videoElement.play();
        }
      };
    },
  }

主要代码如下:

nginx部署flask项目怎么配置 nginx flv module_ide_12


其思想就是通过flvPlayer的on方法监听flvjs的异常,如果出现异常就先将当前的flvPlayer销毁,然后重新调用createVideo方法,不过on监听时间为15秒,也就是说断线15秒以后才会重新连接。