vue2项目中使用videojs,超级详细篇幅。

12,943次阅读
没有评论

共计 9058 个字符,预计需要花费 23 分钟才能阅读完成。

        最近写了一个关于 video 标签预览视频的项目,后端是根据直播拉流的形式给前端一个播放地址,前端需要实现兼容不同格式(m3u8,flv 等)并做到在线预览时要根据分屏不同,实现多个窗口同时播放不同视频的功能;视频回放要做到根据后端返回的时刻进行播放而且需要自定义进度条实现精确到分钟级别的切换选择回放。话不多说开始整活。

 🎇 videojs 官网:Video.js API docs

videojs 民间 API:快速使用 – video.js 中文文档(英文不好的跟我来

💻 番外篇:再忙也别忘了 LeetCode

目录

 

目录

一、说了半天具体是要实现什么效果呢?来请看大屏幕

二、直播视频画面主要功能逻辑及代码实现(以下是片段代码示例不全哈,仅供思路参考)

1. 引入工具库(版本号对应尽量按照我这个来哈,避免未知 api 不兼容)

2. 分屏模式的逻辑及代码(时间仓促没有对视频进行模块化封装,后期有时间了补一个。)

3. 实例化视频方法

4. 自定义功能按钮(暂停播放,全屏非全屏,截屏,录制视频)

三、回放视频画面主要功能逻辑及代码实现(以下是片段代码示例不全哈,仅供思路参考)

1. 自定义进度条(按照我这个业务逻辑有个大前提啊,回放时间是按照一天 24 小时来计算的)

结语


前言

        在网上冲浪了好久虽然关于使用 videojs 的文章很多也很有技术含量,但是由于它的版本比较多不同的版本有些 api 不兼容,导致有些想当然的功能就是实现起来困难重重,而且我这个需求是要保证多个窗口同时直播网上案例更是少之又少,所以来吧,自己搞一个试试呀。

一、说了半天具体是要实现什么效果呢?来请看大屏幕

1、多个分屏直播视频效果 -CSDN 直播              2、回放视频模块的效果演示 -CSDN 直播

看完效果视频总的来说开发内容主要分为以下几点(个人认为哈,大佬可以有不同看法和建议)

1、自定义分屏效果,其中包含 1X1,2X2,3X3 和 4X4 四种模式效果(其实道理一样 nXn 都行)。

2、使用 videojs 进行实例化视频并预览播放出画面

3、自定义功能按钮,由于 video 自带的 control 功能不好看(领导说的哈),索性直接自定义开发了,其中最麻烦的要数回放视频的自定义进度条了(根据屏幕尺寸和 dom 尺寸以及一天当中固定不变的 24 小时进行的转化计算)。

4、自定义报错页面,同理,video 自带的长得不好看(领导说的哈)。

5、实现截图和录制任意一个分屏窗口视频的功能(纯前端实现,不考虑性能哈)

6、其他自定义组件(自己实现的 + 魔改的 elementui+ 抄袭(不对应该是借鉴)道友的)

展示下魔改 el-calendar 日历组件的效果(日历组件(el-calendar)禁用自定义日期范围_el-calendar 禁用某些日期 -CSDN 博客😜

vue2 项目中使用 videojs,超级详细篇幅。

展示下自定义加载错误时的效果哈(个人感觉没有好看到那里去😅)

vue2 项目中使用 videojs,超级详细篇幅。

展示下自定义多选框选择下拉框效果哈(单独一篇文章分享)😜

vue2 项目中使用 videojs,超级详细篇幅。

展示下自定义树形选择拉框效果哈(单独一篇文章分享)😜

vue2 项目中使用 videojs,超级详细篇幅。

二、直播视频画面主要功能逻辑及代码实现(以下是片段代码示例不全哈,仅供思路参考

1. 引入工具库(版本号对应尽量按照我这个来哈,避免未知 api 不兼容)

主要工具如下(示例):

"video.js": "^7.21.6",  // 使用 videojs 的前提

"videojs-contrib-hls": "^5.15.0",  // 支持.m3u8 格式视频流

"videojs-flvjs-es6": "^1.0.1",  // 支持.flv 格式视频流

"flv.js": "^1.6.2",  // 支持.flv 格式视频流

"recordrtc": "^5.6.2",  // 录制视频的工具

"moment": "^2.30.1",  // 时间格式转换的工具

2. 分屏模式的逻辑及代码(时间仓促没有对视频进行模块化封装,后期有时间了补一个。

        思路:dom 结构直接一个大盒子包裹所有视频有关的 dom,然后在大盒子上根据不同的分屏模式提前写好样式,最后对照着不同分屏模式的选择 class 的新增和移除进行结合。

主要代码如下(示例):





3. 实例化视频方法

        思路:使用 ref 选中 video 标签,然后进行 videojs 的实例操作,其中使用 videojs.hooks("beforeerror", function (player, err) {}) 钩子在视频加载错误处理错误之前进行自定义错误效果的处理,这个方法切记是个全局方法如果同一个项目中使用的话要进行隔离,否则会影响另一处使用改钩子的地方,比如单页面应用可以用 router 来隔离一下。

主要代码如下(示例):



4. 自定义功能按钮(暂停播放,全屏非全屏,截屏,录制视频)

        思路:videojs 自身携带的功能按钮不做赘述了,主要是利用 canvas 实现截图以及 canvas 和第三方工具recordrtc 实现录制视频,关键是要找到想要操作的正在播放视频的 video 标签,然后根根据 canvas 进行视频帧的抓取和连续绘制

主要代码如下(示例):

4.1 在工程化的入口中加载 recordrtc 方法

// 为了方便直接在 main.js 入口文件中引入并挂在 recordrtc

import RecordRTC from "recordrtc";
Vue.prototype.$recordRTC = RecordRTC;

4.2 截屏实现

export default {
  methods:{
    // 截图
    handleScreenshot(index) {
      let i = index - 1;
      let name = this.videoArr[i].videoName;
      const fileType = "png";
      // 找到需要截图的 video 标签
      // video 实列
      const video = this.myPlayerArr[i].el().querySelector("video");
      const canvas = document.createElement("canvas");
      canvas.width = video.videoWidth;
      canvas.height = video.videoHeight;
      // 图片大小和视频分辨率一致
      canvas
        .getContext("2d")
        .drawImage(video, 0, 0, canvas.width, canvas.height); 
      // canvas 中 video 中取一帧图片并转成 dataURL
      const strDataURL = canvas.toDataURL("image/" + fileType); 
      let arr = strDataURL.split(","),
        mime = arr[0].match(/:(.*?);/)[1],
        bstr = atob(arr[1]),
        n = bstr.length,
        u8arr = new Uint8Array(n);
      while (n--) {u8arr[n] = bstr.charCodeAt(n);
      }
      const blob = new Blob([u8arr], {type: mime,});
      const url = window.URL.createObjectURL(blob);
      this.downloadFile(url, fileType, name);
    },
    // 下载方法
    downloadFile: function (blob, fileType, name) {const a = document.createElement("a");
      a.style.display = "none";
      a.href = blob;
      let time = new Date().getTime();
      time = moment(time).format("YYYY-MM-DD_HHmmss");  // 用了 momentjs
      a.download = `${name}_${time}.${fileType}`;
      document.body.appendChild(a);
      a.click();
      setTimeout(function () {document.body.removeChild(a);
        window.URL.revokeObjectURL(blob);
      }, 1000);
    },
  }
}

4.3 屏幕录制的实现

export default {data(){
    return{videoArr: [],
      isRecorder: [], // 录制按钮
      recorderFlag: "", // 录制的视频实例
      animationFrame: null, // 录制影像
    }
  },
  methods:{
   // 开始录制
    handleRecording(index) {
      let i = index - 1;
      let name = this.videoArr[i].videoName;
      this.isRecorder[i] = !this.isRecorder[i];
      this.$forceUpdate(); // 为了改变功能按钮的图标状态,目前还没有好的方法,暂时牺牲性能
      this.transcribe(i, name);
    },
    transcribe(i, name) {
      const fileType = "mp4";
      if (this.isRecorder[i]) {if (!this.canvas) this.canvas = document.createElement("canvas");
        this.recorderFlag = this.$recordRTC(this.canvas, {type: "canvas",});
        this.recorderFlag.startRecording();
        this.drawMedia(i);
      } else {this.recorderFlag.stopRecording(() => {const url = window.URL.createObjectURL(this.recorderFlag.getBlob());
          this.downloadFile(url, fileType, name);
          cancelAnimationFrame(this.animationFrame);
          this.canvas = null;
          this.animationFrame = null;
        });
      }
    },
    // 刷新 canvas
    drawMedia(i) {const ctx = this.canvas.getContext("2d");
      // 找到需要截图的 video 标签
      const video = this.myPlayerArr[i].el().querySelector("video");
      this.canvas.setAttribute("width", video.videoWidth);
      this.canvas.setAttribute("height", video.videoHeight);
      ctx.drawImage(video, 0, 0, video.videoWidth, video.videoHeight);
      // requestAnimationFrame 根据电脑显示帧数进行循环
      this.animationFrame = requestAnimationFrame(() => this.drawMedia(i));
    },
    // 下载方法(通用)downloadFile: function (blob, fileType, name) {const a = document.createElement("a");
      a.style.display = "none";
      a.href = blob;
      let time = new Date().getTime();
      time = moment(time).format("YYYY-MM-DD_HHmmss");  // 用了 momentjs
      a.download = `${name}_${time}.${fileType}`;
      document.body.appendChild(a);
      a.click();
      setTimeout(function () {document.body.removeChild(a);
        window.URL.revokeObjectURL(blob);
      }, 1000);
    },
  }
}

三、回放视频画面主要功能逻辑及代码实现(以下是片段代码示例不全哈,仅供思路参考

概述:视频的初始化啥的同上,主要是自定义进度条的实现以及魔改 el-calendar(为了领导的需求,求放过啊)

1. 自定义进度条(按照我这个业务逻辑有个大前提啊,回放时间是按照一天 24 小时来计算的)

主要代码如下(示例):

  

  

结语

        总体实现了产品要求的大致功能,但周期短加上能力也有限,头一次处理这种视频相关的问题好多考虑不到位,比如更新视频功能按钮的状态时被迫使用了 $forceUpdate(),再比如进度条这块没有实现根据屏幕响应式重新计算对应的长度,再比如封装组件的时候借用了 elementui 的框架二次改动等

总而言之,小子我初来乍到,大家多多关照还望能不吝赐教,让我也进步进步,谢谢

原文地址: vue2 项目中使用 videojs,超级详细篇幅。

    正文完
     0
    Yojack
    版权声明:本篇文章由 Yojack 于2024-09-26发表,共计9058字。
    转载说明:
    1 本网站名称:优杰开发笔记
    2 本站永久网址:https://yojack.cn
    3 本网站的文章部分内容可能来源于网络,仅供大家学习与参考,如有侵权,请联系站长进行删除处理。
    4 本站一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
    5 本站所有内容均可转载及分享, 但请注明出处
    6 我们始终尊重原创作者的版权,所有文章在发布时,均尽可能注明出处与作者。
    7 站长邮箱:laylwenl@gmail.com
    评论(没有评论)