flv.js在vue中的使用方法

 更新时间:2023年11月14日 09:55:11   作者:irisMoon06  
flv.js是一个用于在浏览器中解码和播放FLV视频的JavaScript库,它可以将FLV视频流解码并显示在HTML5的video元素中,从而实现在浏览器中直接播放FLV格式的视频文件,本文给大家介绍flv.js在vue中的使用,感兴趣的朋友一起看看吧

Flv.js 是 HTML5 Flash 视频(FLV)播放器,纯原生 JavaScript 开发,没有用到 Flash。由 bilibili 网站开源。它的工作原理是将 FLV 文件流转码复用成 ISO BMFF(MP4 碎片)片段,然后通过 Media Source Extensions 将 MP4 片段喂进浏览器。

使用方法

<template>
  <div class="video" :style="{ height: voidHeight }">
    <video ref="videoElement"  muted controls autoplay controlslist="nodownload noplaybackrate noremoteplayback" disablePictureInPicture="true" v-if="!imgError"></video>
    <div class="img_error" v-if="imgError">
      <p>无法连接相关设备</p>
    </div>
  </div>
</template>
<script>
import flvjs from "flv.js";
export default {
  name: "assemblyFlv",
  props: ["url", "height", "destroy","playon"], // 视频流路径,播放器高度,是否销毁播放器
  data() {
    return {
      flvPlayer: "",
      imgError: false,
      voidHeight: "",
      playOn:true
    };
  },
  mounted() {
    // 判断是否传入高度,如果没有,高度100%
    this.height ? (this.voidHeight = this.height) : (this.voidHeight = "100%");
    // 页面加载完成后,初始化
    this.$nextTick(() => {
      this.init(this.url);
    });
  },
  methods: {
    // 初始化
    init(source) {
      if (flvjs.isSupported()) {
        this.flvPlayer = flvjs.createPlayer(
          {
            type: "flv",
            url: source,
            isLive: true,
          },
          {
            enableWorker: false, //不启用分离线程
            enableStashBuffer: false, //关闭IO隐藏缓冲区
            reuseRedirectedURL: true, //重用301/302重定向url,用于随后的请求,如查找、重新连接等。
            autoCleanupSourceBuffer: true, //自动清除缓存
          }
        );
        var videoElement = this.$refs.videoElement;
        this.flvPlayer.attachMediaElement(this.$refs.videoElement);
        if (this.url !== "" && this.url !== null) {
            this.flvPlayer.load();
            //this.flvPlayer.play();
            setTimeout(() => { this.flvPlayer.play(); }, 100);
            // 加载完成
            this.flvPlayer.on(flvjs.Events.LOADING_COMPLETE, () => {
              this.imgError = false;
            });
            // 加载失败
            this.flvPlayer.on(
              flvjs.Events.ERROR,
              () => {
                if (this.flvPlayer) {
                    this.reloadVideo(this.flvPlayer);
                }else{
                  this.imgError = true;
                }
              },
              (error) => {
                console.log(error);
              }
            );
            this.flvPlayer.on(flvjs.Events.STATISTICS_INFO, (res) =>{
                if(this.playon != false){
                   if (this.lastDecodedFrame == 0) {
                     this.lastDecodedFrame = res.decodedFrames;
                     console.log(this.lastDecodedFrame)
                     return;
                   }
                   if (this.lastDecodedFrame != res.decodedFrames) {
                     this.lastDecodedFrame = res.decodedFrames;
                   } else {
                       this.lastDecodedFrame = 0;
                       console.log('卡住重连')
                       if (this.flvPlayer) {
                         this.reloadVideo(this.flvPlayer);
                         console.log('卡住重连完成')
                     }
                   }
                  }
                 });
            videoElement.addEventListener("progress", () => {
              if(videoElement.buffered.length != 0){
                let end = videoElement.buffered.end(0); //获取当前buffered值(缓冲区末尾)
                let delta = end - videoElement.currentTime; //获取buffered与当前播放位置的差值
                // 延迟过大,通过跳帧的方式更新视频
                if (delta > 10 || delta < 0) {
                  this.flvPlayer.currentTime = this.flvPlayer.buffered.end(0) - 1;
                  console.log('跳帧')
                  return;
                }
                // 追帧
                if (delta > 1) {
                  videoElement.playbackRate = 1.1;
                  console.log('追帧')
                } else {
                  videoElement.playbackRate = 1;
                  console.log('正常')
                }
              }
            });
            // 点击播放按钮后,更新视频
            videoElement.addEventListener("play", () => {
              if(videoElement.buffered.length > 0){
              let end = videoElement.buffered.end(0) - 1;
              this.flvPlayer.currentTime = end;
              console.log('播放最新')
              }
            });
            // 网页重新激活后,更新视频
            window.onfocus = () => {
              if(videoElement.buffered.length > 0){
                let end1 = videoElement.buffered.end(0) - 1;
                this.flvPlayer.currentTime = end1;
                console.log('页面切换')
              }
            };
        }
      } else {
        this.imgError = true;
      }
    },
    //断线重连
    reloadVideo(flvPlayer) {
          this.detachMediaElement();
          this.init(this.url);
          console.log('断线重连')
    },
    // 销毁
    detachMediaElement() {
      this.flvPlayer.pause();
      this.flvPlayer.unload();
      this.flvPlayer.detachMediaElement();
      this.flvPlayer.destroy();
      this.flvPlayer = "";
    },
  },
  watch: {
    url() {
      this.imgError = false;
      // 切换流之前,判断之前的流是否销毁
      this.flvPlayer == "" ? "" : this.detachMediaElement();
      // 初始化
      this.init(this.url);
    },
    destroy() {
      // 传入开关值
      if (this.destroy) {
        this.init(this.url);
      } else {
        this.flvPlayer == "" ? "" : this.detachMediaElement();
      }
    },
    playon() {
      this.reloadVideo(this.flvPlayer);
    }
  },
  beforeDestroy() {
    this.detachMediaElement();
  },
};
</script>
<style scoped>
.video {
  position: relative;
  height: 100%;
}
.video video {
  width: 100%;
  height: 100%;
  object-fit: fill;
}
.video video::-webkit-media-controls-play-button{
  display: none;
}
.video video::-webkit-media-controls-toggle-closed-captions-button {
    display: none;
}
.video video::-webkit-media-controls-timeline {
    display: none;
}
.video video::-webkit-media-controls-current-time-display {
    display: none;
}
.video video::-webkit-media-controls-time-remaining-display {
    display: none;
}
.img_error {
  position: absolute;
  top: 30%;
  left: 50%;
  margin-left: -120px;
  text-align: center;
}
.img_error > img {
  margin-bottom: 1em;
}
.img_error > p {
  color: #00fdff;
  font-weight: bold;
  font-size: 1.2em;
}
</style>

封装:

 子组件封装:

<template>
    <div class="video-container">
      <video ref="videoElement" class="centeredVideo" controls autoplay muted></video>  
    </div>
</template>
<script>
import flvjs from "flv.js";  //引入flv
export default {
  props: {
    url : String,
  },
  data() {
    return {
      // src: ["http://172.21.1.111/live?port=1935&app=myapp&stream=streamname"],
    };
  },
  mounted() {
    this.flv_load(this.url);
  },
  methods: {
    flv_load(url) {
      if (flvjs.isSupported()) {
      let videoElement = this.$refs.videoElement;
        this.flvPlayer = flvjs.createPlayer(
          {
            type: "flv", //媒体类型
            url: url, //flv格式媒体URL
            isLive: true, //数据源是否为直播流
            hasAudio: false, //数据源是否包含有音频
            hasVideo: true, //数据源是否包含有视频
            enableStashBuffer: false, //是否启用缓存区
          },
          {
            enableWorker: false, // 是否启用分离的线程进行转换
            enableStashBuffer: false, //关闭IO隐藏缓冲区
            autoCleanupSourceBuffer: true, //自动清除缓存
          }
        );
        this.flvPlayer.attachMediaElement(videoElement); //将播放实例注册到节点
        this.flvPlayer.load(); //加载数据流
        this.flvPlayer.play(); //播放数据流
      }
    },
  },
};
</script>
<style scoped>
/* .video-container {
  display: inline-block;
  margin-right: 10px;
  width: 32%;
  height: 45%;
} */
.centeredVideo {
  width: 100%;
}
</style>

父组件调用:

<template>
  <el-card class="box-card">
    <div class="flvbox" v-for="(item,index) in src" :key="index">
    <!-- <VideoFlv url="http://172.21.1.111/live?port=1935&app=myapp&stream=streamname" /> -->
    <VideoFlv :url="item" />
    </div>
  </el-card>
</template>
<script>
import VideoFlv from "./VideoFlv.vue";
export default {
  components:{
    VideoFlv
  },
  data() {
    return {
      src: [
        "https://sf1-hscdn-tos.pstatp.com/obj/media-fe/xgplayer_doc_video/flv/xgplayer-demo-360p.flv",
        "https://sf1-hscdn-tos.pstatp.com/obj/media-fe/xgplayer_doc_video/flv/xgplayer-demo-360p.flv",
        "https://sf1-hscdn-tos.pstatp.com/obj/media-fe/xgplayer_doc_video/flv/xgplayer-demo-360p.flv",
        "https://sf1-hscdn-tos.pstatp.com/obj/media-fe/xgplayer_doc_video/flv/xgplayer-demo-360p.flv",
        "http://172.21.1.111/live?port=1935&app=myapp&stream=streamname",
        "https://sf1-hscdn-tos.pstatp.com/obj/media-fe/xgplayer_doc_video/flv/xgplayer-demo-360p.flv",
      ],
    };
  },
};
</script>
<style scoped>
.flvbox {
  display: inline-block;
  margin-right: 10px;
  width: 32%;
}
</style>

因为视频需要实时的 后边发现上边写法暂停之后和切换页面之后 会有延迟 所以开发让新加个刷新按钮 也已满足  然后这个api的写法我尝试很多 追帧啊 更新视频啊 都没生效  父组件重新传值 因为值没有变化 所以也没有重新渲染  所以用到了key 属性 vue每次渲染的时候会去拿这个key 值做对比,如果这一次的key 值和上一次的key值是不一样的才会重新渲染dom 元素,否则保持上一次的元素状态。所以我用了一个时间戳方法

flv.js常用方法

1:flvjs.isSupported():判断当前浏览器是否支持播放

2:flvPlayer = flvjs.createPlayer(mediaDataSource: MediaDataSource, config?: Config):创建一个播放实例

3:flvPlayer.attachMediaElement(mediaElement: HTMLMediaElement):将播放实例注册到video节点

4:flvPlayer.load():加载数据流

5:flvPlayer.play():播放数据流

6:flvPlayer.pause():暂停播放数据流

7:flvPlayer.unload():取消数据流加载

8:flvPlayer.detachMediaElement():将播放实例从节点中取出

9:flvPlayer.destroy():销毁播放实例

到此这篇关于flv.js在vue中的使用的文章就介绍到这了,更多相关vue使用flv.js内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • vue+elementUi 实现密码显示/隐藏+小图标变化功能

    vue+elementUi 实现密码显示/隐藏+小图标变化功能

    这篇文章主要介绍了vue+elementUi 实现密码显示/隐藏+小图标变化功能,需本文通过实例代码给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-01-01
  • Vuex中如何getters动态获取state的值

    Vuex中如何getters动态获取state的值

    这篇文章主要介绍了Vuex中如何getters动态获取state的值,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-08-08
  • vue3实现多个表格同时滚动并固定表头

    vue3实现多个表格同时滚动并固定表头

    这篇文章主要给大家介绍了vue3中多个表格怎么同时滚动并且固定表头,文中通过代码示例给大家讲解的非常详细,对大家的学习或工作有一定的帮助,需要的朋友可以参考下
    2024-02-02
  • Vue.js中的绑定样式实现

    Vue.js中的绑定样式实现

    这篇文章主要介绍了Vue.js中的绑定样式实现,展开的内容呦style绑定样式和绑定class样式,具体相关内容需要的小伙伴可以参考下面文章介绍
    2022-05-05
  • 详解用vue编写弹出框组件

    详解用vue编写弹出框组件

    本篇文章主要介绍了详解用vue编写弹出框组件,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-07-07
  • Vue项目部署到IIS后刷新报错404的问题及解决方法

    Vue项目部署到IIS后刷新报错404的问题及解决方法

    这篇文章主要介绍了Vue项目部署到IIS后,刷新报错404,这里需要用到URL重写工具 --URL Rewrite,需要的话需要自己下载安装,本文通过图文并茂的形式给大家介绍的非常详细,需要的朋友可以参考下
    2022-10-10
  • elementUI el-radio 无法点击的问题解决

    elementUI el-radio 无法点击的问题解决

    本文主要介绍了elementUI el-radio 无法点击的问题解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-07-07
  • vue中使用tinymce及插件powerpaste的使用

    vue中使用tinymce及插件powerpaste的使用

    这篇文章主要介绍了vue中使用tinymce,以及插件powerpaste的使用,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-07-07
  • Vue3中Composition的API用法详解

    Vue3中Composition的API用法详解

    这篇文章主要为大家详细介绍了Vue3中Composition的一些常见API的用法,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2023-06-06
  • vue跳转页面打开新窗口,并携带与接收参数方式

    vue跳转页面打开新窗口,并携带与接收参数方式

    这篇文章主要介绍了vue跳转页面打开新窗口,并携带与接收参数方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-04-04

最新评论