首页 前端知识 vue3 video.js 加载多种视频流(HLS、FLV、RTMP、RTSP)封装开箱及用,发布npm

vue3 video.js 加载多种视频流(HLS、FLV、RTMP、RTSP)封装开箱及用,发布npm

2024-04-29 12:04:14 前端知识 前端哥 921 717 我要收藏

vue3 + video.js 加载多种视频流(HLS、FLV、RTMP、RTSP)封装开箱及用,发布npm

提示:这里兼容了rtmp数据流,但是前提需要下载支持flash插件的浏览器


文章目录

  • vue3 + video.js 加载多种视频流(HLS、FLV、RTMP、RTSP)封装开箱及用,发布npm
  • 前言
    • 封装组件


前言

上一偏我们使用vue3和vite封装了一个audio插件发布npm官网,这里我们将封装一个视频video插件并发布npm供大家参考


提示:下面不涉及新建项目和打包npm流程,需要的请看上一篇
vue3 + vite自定义封装vue+audio ,并发布到npm详情介绍

封装组件

一. 用video.js实现视频播放

  1. 安装video.js插件,这里我们使用的是在index.html中引入的本地css
       //引入video插件
     <script src="/public/static/js/video.min.js"></script>
     <script src="/public/static/js/videojs-contrib-hls.min.js"></script>
     //如果需要播放rtmp直播流,需安装一下插件
     <script src="/public/static/js/videojs-flash.min.js"></script>
     //引入键盘控制video插件
     <script src="/public/static/js/videojs.hotkeys.min.js"></script>
    
    1. 在组件代码里使用
     <template>
          <div class="videoBox">
             <video id="myVideoBig"
                class="video-js vjs-default-skin vjs-big-play-centered"
                loop="loop"
                :poster="posterSrc"
                 data-setup=''
                 muted="muted"
                 style="object-fit: fill; width: 100%; height: 100%">
             <source :src="videoSrc"
                 ref="videos"
                 id="source"
                :type="format" />
             <p class="vjs-no-js">不支持播放</p>
             </video>
           </div>
       </template>     

video的class “vjs-big-play-centered” 播放按钮默认在左上角,会遮挡,不过这个是可以根据参数修改的,只需要给video标签加一个class(vjs-big-play-centered)就可以居中显示了

  1. 定义常用video.js 配置项
  • autoplay:true/false 播放器准备好之后,是否自动播放 【默认false】
  • controls:true/false 是否拥有控制条 【默认true】,如果设为false, 界面上不会出现任何控制按钮,启动视频播放的唯一方法是使用autoplay 属性或通过Player API
  • height: 视频容器的高度,字符串或数字(以像素为单位),比如: height: 300 或者 height: ‘300px’
  • width: 视频容器的宽度, 字符串或数字(以像素为单位)
  • loop : true/false 视频播放结束后,是否循环播放
  • muted : true/false 是否静音
  • poster: 播放前显示的视频画面,播放开始之后自动移除。通常传入一个URL
  • language: “zh-CN”
  • errorDisplay :是否显示错误提示
  • fluid : 跟随外层容器变化大小,跟随的是外层宽度
  • controlBar: 是否显示控制条,设为false不渲染控制条DOM元素,只设置controls为false虽然不展示,但是存在
  • notSupportedMessage :允许覆盖Video.js无法播放媒体源时显示的默认信息
  • techOrder:定义Video.js技术首选的顺序 [‘html5’, ‘flash’]
  • plugins:放插件的地方是否支持热键
    • hotkeys:过键盘按键来控制视频播放的功能
      • volumeStep: 0.1 调整音量的步长
      • seekStep: 5, 快进/快退的时间(秒)
      • fullscreenKey:(event, player)=>{} 监听键盘按键
  • preload: 预加载
    • ‘auto’:立即开始加载视频(如果浏览器支持)。某些移动设备不会预加载视频,以保护用户的带宽/数据使用。
    • ‘metadata’:仅加载视频的元数据,其中包括视频的持续时间和尺寸等信息。有时,元数据将通过下载几帧视频来加载。
    • ‘none’:不要预加载任何数据。浏览器将等待用户点击“播放”开始下载。
  • children: Array | Object 可选子组件 从基础的Component组件继承而来的子组件,数组中的顺序将影响组件的创建顺序

这里我们设置一个变量储存videojs使用的配置项以便后期批量使用

const videoParameter = ref({
  autoplay: isautoplays.value, // 是否自动播放
  language: "zh-CN",
  controls: iscontrols.value, // 是否显示控制为false时用户不可以与之交互控件
  preload: "auto", // 自动加载 预加载 建议浏览器是否应在<video>加载元素后立即开始下载视频数据。
  errorDisplay: true,// 错误展示
  fluid: true, // 跟随外层容器变化大小,跟随的是外层宽度
  controlBar: iscontrolBar.value,
  // textTrackDisplay: false,  // 不渲染字幕相关DOM
  // 是否支持热键|过键盘按键来控制视频播放的功能
  plugins: {
   //这里需要引入本地插件videojs.hotkeys.min.js,这里我引入了v0.2.13版本,因为其他版本有线上依赖项
    hotkeys: {
      // 定义快捷键和对应的操作
      volumeStep: 0.1,  // 调整音量的步长
      seekStep: 5,      // 快进/快退的时间(秒)
      fullscreenKey: function (event, player) {
        // 自定义全屏快捷键,按下 F 键时触发全屏切换
        if (!document.fullscreenElement) {
          player.requestFullscreen();
        } else {
          document.exitFullscreen();
        }
      }
    }
  },
  notSupportedMessage: '此视频暂无法播放,请稍后再试', //允许覆盖Video.js无法播放媒体源时显示的默认信息
  techOrder: PlayOrder.value, // 定义Video.js技术首选的顺序
  //自动播放属性,muted:静音播放
  muted: true,
})
  1. 这里我们就开始初始化video,这里还做了监听error并做出处理重新加载,里面还控制了是否禁用键盘事件,播放rtmp时我把键盘和暂停/播放/快进等禁用了,这里是因为在播放rtmp直播流时这些暂停RTMP直播后,VideoJS无法播放,大家有什么好的解决办法欢迎来共商大计♡
//初始化视频
const showvideo = (val, url) => {
  nextTick(() => {
  //这里是因为要支持rtmp需要使用flash
  //因为,这种播放方式html已经不能很好的进行播放了,需要用到flash来播放,videojs在这个地方就用到了这个。代码就是下面这样。
    videojs.options.flash.swf = 'public/static/js/video-js.swf';
    player.value = videojs(
      "myVideoBig",
      videoParameter.value,
      function () {
        videojs.log('播放量+1!'); // 比如: 播放量+1请求
        player.value.on('ended', function () {
          videojs.log('Awww...这么快就结束了?!');
        });
        //监听error在页面插入一个重播按钮
        player.value.on("error", function () {
          var errorMessage = player.value.error().message;
          console.log('Video.js 播放器遇到错误:', errorMessage);
          var myVideoDivles = document.querySelectorAll("#myVideoBig");
          if (myVideoDivles.length == 0) return
          myVideoDivles[0].innerHTML = `<div class='Boxvideo' style='width: 100%;height:100%;position: relative;background:#030202;'><div class='Refresh' style='width: 100px; height: 100px;border-radius: 50%;position: absolute; left: 50%; top: 50%;transform: translate(-50%, -50%);'></div></div>`;
          // 获取按钮元素并添加事件
          RefreshButton.value = document.querySelector('.Refresh');
          RefreshButton.value.addEventListener('click', function (event) {
            clickRefresh()
          });
          return ElMessage({
            message: "视频播放失败,请检查并刷新",
            type: "warning",
            duration: 5000,
            offset: 80,
          });
        });
      }
    );
    videojs("myVideoBig").src({
      type: format.value,
      src: url,
    });
    // 禁用键盘事件
    if (val == 1) {
      disableKeyboardControl(player.value)
    }
  });
}

初始化的时候插入了一个重播按钮需要初始化video,上代码

//刷新视频
const clickRefresh = async (val) => {
  var myVideoDivles = document.querySelectorAll("#myVideoBig");
  if (myVideoDivles.length == 0) return
  myVideoDivles[0].innerHTML =
    "<video id='myVideoBigs' class='video-js vjs-default-skin vjs-big-play-centered'  muted='muted' autoplay='autoplay' loop='loop' data-setup='{}' style='object-fit: fill; width: 100%; height: 100%'><source src=" +
    videoedit.value +
    " style='width: 100%;height: 100%' type=" + format.value + "></video>";
  nextTick(() => {
    playerolder.value = videojs("myVideoBigs", videoParameter.value, function () {
      playerolder.value.on("error", function () {
        var myVideoDivles = document.querySelectorAll("#myVideoBig");
        if (myVideoDivles.length == 0) return
        myVideoDivles[0].innerHTML = `<div class='Boxvideo' style='width: 100%;height:100%;position: relative;background:#030202;'><div class='Refresh' style='width: 100px; height: 100px;border-radius: 50%;position: absolute; left: 50%; top: 50%;transform: translate(-50%, -50%);'></div></div>`;
        // 获取按钮元素
        RefreshButton.value = document.querySelector('.Refresh');
        RefreshButton.value.addEventListener('click', function (event) {
          clickRefresh()
        });
        return ElMessage({
          message: "视频播放失败,请检查并刷新",
          type: "warning",
          duration: 5000,
          offset: 80,
        });
      });
    });
    videojs("myVideoBigs").src({
      type: format.value,
      src: props.videoSrc,
    });
    //videojs("myVideoBigs").play();
  }, 100);
}

这样就可以刷新重新播放☝

  1. 处理rtmp
    代码中需要同时支持MP4,m3u8和rtmp,所以要做一些处理
//初始化监听vieo的src是什么格式做处理
watch(() => props.videoSrc, (newVal, oldVal) => {
  if (newVal) {
    console.log(newVal)
    if (newVal.includes('rtmp')) {
      videoParameter.value.controls = false
      videoParameter.value.controlBar = false
      videoParameter.value.autoplay = true
      //以flash为先
      videoParameter.value.techOrder = ['flash', 'html5']
      isautoplays.value = true
      iscontrols.value = false
      iscontrolBar.value = false
      PlayOrder.value = ['flash', 'html5']
     //修改格式
      format.value = 'rtmp/flv'
      showvideo(1, newVal)
    } else if (newVal.includes('.mp4')) {
      format.value = 'video/mp4'
      currency(newVal)
    } else if (newVal.includes('.m3u8')) {
      format.value = 'application/x-mpegURL'
      currency(newVal)
    }
  }
}, { deep: true, immediate: true });
//通用
const currency = (newVal) => {
  videoParameter.value.controls = true
  videoParameter.value.controlBar = true
  videoParameter.value.autoplay = props.isautoplay
  videoParameter.value.techOrder = ['html5', 'flash']
  isautoplays.value = props.isautoplay
  iscontrols.value = true
  iscontrolBar.value = true
  PlayOrder.value = ['html5', 'flash']
  showvideo(2, newVal)
}

★★★★★★提示一下rtmp格式需要支持flash的浏览器
谷歌,360,火狐,qq浏览器都是不支持的
在这里插入图片描述
在这里插入图片描述
只有falsh官网的浏览器所支持
在这里插入图片描述

  1. 常用事件
  • 播放 this.play()
  • 停止 – video没有stop方法,可以用pause 暂停获得同样的效果
  • 暂停 this.pause()
  • 销毁 this.dispose()
  • 监听 this.on(‘click‘,fn)
  • 触发事件this.trigger(‘dispose‘)

这里我还做了一个销毁参数closeVideo传值true,做了两个销毁,第一次判断是否有重播时的渲染,第二个销毁初始化的video

watch(() => props.closeVideo, (newVal, oldVal) => {
  if (newVal) {
    handleLog()
  }
}, {
  deep: true, immediate: true
})
//关闭销毁vieobox
const handleLog = () => {
  var myVideoDivles = document.querySelectorAll("#myVideoBigs");
  if (myVideoDivles.length > 0) {
    playerolder.value.dispose();
    playerolder.value = null;
  }
  player.value.dispose();
  player.value = null;
}

video.min.js:18 VIDEOJS: ERROR: (CODE:4 MEDIA_ERR_SRC_NOT_SUPPORTED) No compatible source was found for this media.
报错是因为所加载的url不支持

  1. 测试地址

https://sdk-release.qnsdk.com/VID_20220207_144828.mp4
rtmp://liteavapp.qcloud.com/live/liteavdemoplayerstreamid
http://cdn3.toronto360.tv:8081/toronto360/hd/playlist.m3u8
//失败测试
https://sdk-release.qnsdk.com/1080_60_5390.mp4

  1. 插件参数
videoSrcvideo 的 url
isautoplay是否自动播放,默认false,rtmp格式强制true
posterSrc播放前的图片展示
closeVideo是否销毁vido ,默认false

好啦啦啦!!!这里我们就完成了代码部分直接npm publish发布☺☺

请下载使用吧,有什么问题或者有更好的可以联系我哦,谢谢大家☺☺

npm i l-vue3-video

源码

转载请注明出处或者链接地址:https://www.qianduange.cn//article/6524.html
标签
arcgis
评论
发布的文章

什么是JSON 为什么使用它

2024-05-07 13:05:36

大家推荐的文章
会员中心 联系我 留言建议 回顶部
复制成功!