nginx + nginx-http-flv-module-1.2.10(包含nginx-rtmp-module) + video标签播放 http-flv 视频

1. nginx安装nginx-http-flv-module-1.2.10插件 下载地址nginx-http-flv-module-1.2.10

或者去git下载最新版本 github

安装nginx-http-flv-module-1.2.10去百度 切记 不能和nginx-rtmp-module一起装 因为 nginx-http-flv-module-1.2.10里面已经包含了nginx-rtmp-module

2. 配置nginx rmtp服务


server
    {
        listen 7703;
        location /live { # 拉流时的 uri ,可以自行修改
            flv_live on; # 打开 http-flv 服务
            chunked_transfer_encoding on;
            add_header Access-Control-Allow-Origin *; # 允许跨域
            add_header Access-Control-Allow-Credentials true;
        }
        location /hls {
            types {
                application/vnd.apple.mpegurl m3u8;
                #application/x-mpegURL;
                video/mp2t ts;
            }
            root /www/wwwroot/;
            expires -1;
            add_header Cache-Control no-cache;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            add_header Access-Control-Allow-Methods *;
            add_header Access-Control-Max-Age 3600;
            add_header Access-Control-Allow-Credentials true;
            add_header Access-Control-Allow-Origin *;
        }
        location /stat {
            rtmp_stat all;
            rtmp_stat_stylesheet stat.xsl;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            add_header Access-Control-Allow-Methods *;
            add_header Access-Control-Max-Age 3600;
            add_header Access-Control-Allow-Credentials true;
            add_header Access-Control-Allow-Origin *;
        }
        location /stat.xsl {
            # XML stylesheet to view RTMP stats.
            # Copy stat.xsl wherever you want
            # and put the full directory path here
            root /www/server/nginx-http-flv-module-1.2.10;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            add_header Access-Control-Allow-Methods *;
            add_header Access-Control-Max-Age 3600;
            add_header Access-Control-Allow-Credentials true;
            add_header Access-Control-Allow-Origin *;
        }
    }
include /www/server/panel/vhost/nginx/*.conf;
include /www/server/nginx/conf/vhost/*.conf;
}

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 7702;
        chunk_size 8192;
        application play {
            play /www/wwwroot/html7702;
        }
    
        application hls {
            live on; # 打开直播
            hls on;
            meta off;# 为了兼容网页前端的 flv.js,设置为 off 可以避免报错
            gop_cache on; # 支持GOP缓存,以减少首屏时间
            allow play all; # 允许来自任何 ip 的人拉流
            hls_path /www/wwwroot/hls;
            hls_fragment 1s;
            hls_playlist_length 4s;
        }
    
        application myapp { # myapp 模块,可以自行更换名字
            live on; # 打开直播
            #hls on;
            meta off;# 为了兼容网页前端的 flv.js,设置为 off 可以避免报错
            gop_cache on; # 支持GOP缓存,以减少首屏时间
            allow play all; # 允许来自任何 ip 的人拉流
            #hls_path /www/wwwroot/myapp;
            #hls_fragment 1s;
            #hls_playlist_length 4s;
        }
    }
}

rmtp 推流地址:rmtp:域名:7702/myapp/yjx
拉流地址:http://域名:7703/live?port=7702&app=myapp&stream=yjx

3. vue播放

vue 安装flv.js
npm install --save flv.js
封装成vue组件
videoFlv.vue

<template>
  <div>
    <div class="hello" style="width:100%; height:100%;background-color:#000000;">
      <section v-if="!loadStatus" style="width:100%; height:100%;">
        <div class="video-box">
          <video autoplay controls width="100%" height="220px" :id="id" muted></video>
          <div class="left-up-video-img" @click="leftUpVideoImgClick"></div>
          <div class="left-down-video-img" @click="leftDownVideoImgClick"></div>
          <div class="right-up-video-img" @click="rightUpVideoImgClick"></div>
          <div class="right-down-video-img" @click="rightDownVideoImgClick"></div>
        </div>
      </section>
      <div v-else
           style="width: 100%;height: 100%;display: flex;justify-content:center;align-items:center;cursor: pointer">
      <span style="color: wheat;font-size: 14px;"><i class="el-icon-warning-outline"
                                                     style="margin-right: 10px"></i>{{ statusMsg }}</span>
      </div>
    </div>
  </div>
</template>

<script>
import flvjs from "flv.js";
export default {
  name: 'videoFlv',
  comments() {
  },
  data() {
    return {
      src: "",  //flv格式的地址
      timerId: null,
      loadStatus: true,
      id: 'videoElement' + Math.random(),
      statusMsg: '摄像机未开启,请联系',
      flvPlayer: null,
      lastDecodedFrame: 0,
      videoElement: null,
      headerData: {
        // 页面设置属性
        name: '直播', //页面名称
        details: '', //页面描述
        isPerson: false, // 是否显示个人中心
        isBack: false, // 是否返回按钮
        titleHeight: 35, // 高度
        bgColor: 'rgba(249, 249, 249, 10)', //背景颜色
        bgImg: '' // 背景图片
      }
    };
  },
  created() {
    if (this.timerId) {
      clearInterval(this.timerId)
      this.timerId = null
    }
  },
  mounted() {
    this.$nextTick(() => {
      this.setsrc();
    })
  },
  destroyed() {
    console.log("destorying video");
    if (this.timerId) {
      clearInterval(this.timerId)
      this.timerId = null
    }
    if (this.flvPlayer !== null) {
      this.flvPlayer.pause();
      this.flvPlayer.destroy();
      this.flvPlayer = null;
    }
  },
  methods: {
    createVideo() {
      let that = this
      console.log(that.flvPlayer);
      if (that.flvPlayer) {
        that.flvPlayer.pause();
        that.flvPlayer.destroy();
        that.flvPlayer = null;
      }
      if (that.timerId !== null) {
        clearInterval(that.timerId);
      }
      that.videoElement = document.getElementById(that.id)
      if (flvjs.isSupported()) {
        that.flvPlayer = flvjs.createPlayer({
          type: 'flv',
          url: that.src,
          isLive: true,
        }, {
          // cors: true, // 是否跨域
          // enableWorker: true, // 是否多线程工作
          // enableStashBuffer: false, // 是否启用缓存
          // stashInitialSize: 128, // 缓存大小(kb)  默认384kb
          // autoCleanupSourceBuffer: true // 是否自动清理缓存
          enableWorker: false, //不启用分离线程
          enableStashBuffer: false, //关闭IO隐藏缓冲区
          isLive: true,
          lazyLoad: false,
        })
      }
      that.flvPlayer.on(flvjs.Events.ERROR, (errorType, errorDetail, errorInfo) => {
        console.log("errorType:", errorType);
        console.log("errorDetail:", errorDetail);
        console.log("errorInfo:", errorInfo);
        this.loadStatus = true
        this.statusMsg = "正在重连。。。"
        //视频出错后销毁重新创建
        if (that.flvPlayer) {
          that.flvPlayer.pause();
          that.flvPlayer.unload();
          that.flvPlayer.detachMediaElement();
          that.flvPlayer.destroy();
          that.flvPlayer = null;
        }
        that.createVideo();
      });
      that.flvPlayer.on("statistics_info", function (res) {
        if (that.lastDecodedFrame == 0) {
          that.lastDecodedFrame = res.decodedFrames;
          return;
        }
        if (that.lastDecodedFrame != res.decodedFrames) {
          that.lastDecodedFrame = res.decodedFrames;
        } else {
          that.lastDecodedFrame = 0;
          if (that.flvPlayer) {
            that.flvPlayer.pause();
            that.flvPlayer.unload();
            that.flvPlayer.detachMediaElement();
            that.flvPlayer.destroy();
            that.flvPlayer = null;
            that.createVideo();
          }

        }
      });

      that.flvPlayer.attachMediaElement(this.videoElement)
      that.flvPlayer.load()
      that.flvPlayer.play()
      if (that.timerId !== null) {
        clearInterval(that.timerId);
      }
      that.timerId = setInterval(() => {
        if (that.videoElement.buffered.length > 0) {
          const end = that.videoElement.buffered.end(0);  // 视频结尾时间
          const current = that.videoElement.currentTime;  //  视频当前时间
          const diff = end - current;// 相差时间
          console.log(diff);
          const diffCritical = 4; // 这里设定了超过4秒以上就进行跳转
          const diffSpeedUp = 1; // 这里设置了超过1秒以上则进行视频加速播放
          const maxPlaybackRate = 4;// 自定义设置允许的最大播放速度
          let playbackRate = 1.0; // 播放速度
          if (diff > diffCritical) {
            console.log("相差超过4秒,进行跳转");
            that.videoElement.currentTime = end - 1.5;
            playbackRate = Math.max(1, Math.min(diffCritical, 16));
          } else if (diff > diffSpeedUp) {
            console.log("相差超过1秒,进行加速");
            playbackRate = Math.max(1, Math.min(diff, maxPlaybackRate, 16))
          }
          that.videoElement.playbackRate = playbackRate;
          if (that.videoElement.paused) {
            that.flvPlayer.play()
          }
        }
      }, 1000);
    },
    setsrc() {
      if (this.url) {
        this.src = this.url;
        this.createVideo();
      }
    },
    leftUpVideoImgClick() {
      this.$toast("我是左上按钮")
    },
    leftDownVideoImgClick() {
      this.$toast("我是左下按钮")
    },
    rightUpVideoImgClick(){
      this.$toast("我是右上按钮")
    },
    rightDownVideoImgClick(){
      this.$toast("我是右下按钮")
    }

  },
  props: {
    url: {
      default: null,
      required: true,
      type: String | null
    },
  },
  watch: {
    url: {
      handler(newValue) {
        if (newValue != null) {
          this.loadStatus = false
          this.src = newValue
          this.$nextTick(() => {
            this.setsrc();
          })
        }
      },
      deep: true,
      immediate: true,
    }
  },
}
</script>

<style scoped>
h3 {
  margin: 40px 0 0;
}

ul {
  list-style-type: none;
  padding: 0;
}

li {
  display: inline-block;
  margin: 0 10px;
}

a {
  color: #42b983;
}

.video-box {
  position: relative;
}

.video-box video {
  display: inline-block;
  vertical-align: baseline;
}

.video-box .left-up-video-img {
  position: absolute;
  top: 100px;
  bottom: 10px;
  left: 20px;
  /*right: 20px;*/
  width: 10px;
  height: 10px;
  z-index: 999;
  background: url(../../../assets/images/icon_jt.png) no-repeat;
  background-size: 100% 100%;
  cursor: pointer
}
.video-box .left-down-video-img {
  position: absolute;
  top: 150px;
  bottom: 10px;
  left: 20px;
  /*right: 20px;*/
  width: 10px;
  height: 10px;
  z-index: 999;
  background: url(../../../assets/images/icon_jt.png) no-repeat;
  background-size: 100% 100%;
  cursor: pointer
}
.video-box .right-up-video-img {
  position: absolute;
  top: 100px;
  bottom: 10px;
  /*left: 20px;*/
  right: 20px;
  width: 10px;
  height: 10px;
  z-index: 999;
  background: url(../../../assets/images/icon_jt.png) no-repeat;
  background-size: 100% 100%;
  cursor: pointer
}
.video-box .right-down-video-img {
  position: absolute;
  top: 150px;
  bottom: 10px;
  /*left: 20px;*/
  right: 20px;
  width: 10px;
  height: 10px;
  z-index: 999;
  background: url(../../../assets/images/icon_jt.png) no-repeat;
  background-size: 100% 100%;
  cursor: pointer
}
</style>

调用方法

<template>
  <div>
    <!--    <video-flv :url="src"></video-flv>-->
    <div style="width: 100%; height:220px" v-for="(item,index) in urllist" :key="index">
      <video-flv :url="item.url"/>
    </div>

  </div>
</template>

<script>
import VideoFlv from "@/views/tabbar/live/flvVideo";

export default {
  components: {VideoFlv},
  data() {
    return {
      urllist: [
        {
          //nginx 流媒体服务器
          // url: "http://ip:7703/live?port=7702&app=myapp&stream=yjx"//推流地址  rtmp://yjx.yjx-show.top:7702/myapp     /yjx
          url: "http://ip:7703/live?port=7702&app=myapp&stream=yjx"//推流地址  rtmp://yjx.yjx-show.top:7702/myapp     /yj
        },
        // {
        //   url: "http://yjx.yjx-show.top:7703/live?port=7702&app=myapp&stream=ypt"
        // },
      ]
    }
  },
  comments() {
    flvVideo
  }
}
</script>
<style lang="less" scoped>
//.dplayer {
//  width: 500px;
//}
</style>

使用obs进行推流
在这里插入图片描述
在这里插入图片描述
直播延迟1-3秒

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值