vue2之jessibuca视频插件使用教程

jessibuca简介

Jessibuca是一款开源的纯H5直播流播放器,通过Emscripten将音视频解码库编译成Js(ams.js/wasm)运行于浏览器之中。兼容几乎所有浏览器,可以运行在PC、手机、微信中,无需额外安装插件。

前期准备

下载相关js

从官网下载相关压缩包将文件移入自身项目中,并根据自身vue版本放入Public或者Static文件夹下。
jessibuca官网-源码下载链接
在这里插入图片描述

解压后的文件

在这里插入图片描述

vue index.html文件引入

<script type="text/javascript" src="/jessibuca/jessibuca.js"></script>

组件封装

<template>
  <div
    ref="container"
    @dblclick="fullscreenSwich"
    style="width: 100%; height: 100%; background-color: #000000; margin: 0 auto; position: relative"
  >
    <div
      class="buttons-box"
      id="buttonsBox"
    >
      <div class="buttons-box-left">
        <i
          v-if="!playing"
          class="iconfont icon-play jessibuca-btn"
          @click="playBtnClick"
        ></i>
        <i
          v-if="playing"
          class="iconfont icon-pause jessibuca-btn"
          @click="pause"
        ></i>
        <i
          class="iconfont icon-stop jessibuca-btn"
          @click="destroy"
        ></i>
        <i
          v-if="isNotMute"
          class="iconfont icon-audio-high jessibuca-btn"
          @click="mute()"
        ></i>
        <i
          v-if="!isNotMute"
          class="iconfont icon-audio-mute jessibuca-btn"
          @click="cancelMute()"
        ></i>
      </div>
      <div class="buttons-box-right">
        <span class="jessibuca-btn">{{ kBps }} kb/s</span>
        <i
          class="iconfont icon-camera1196054easyiconnet jessibuca-btn"
          @click="screenshot"
          style="font-size: 1rem !important"
        ></i>
        <i
          class="iconfont icon-shuaxin11 jessibuca-btn"
          @click="playBtnClick"
        ></i>
        <i
          v-if="!fullscreen"
          class="iconfont icon-weibiaoti10 jessibuca-btn"
          @click="fullscreenSwich"
        ></i>
        <i
          v-if="fullscreen"
          class="iconfont icon-weibiaoti11 jessibuca-btn"
          @click="fullscreenSwich"
        ></i>
        <i
          style="font-size: 28px"
          class="iconfont icon-video-close jessibuca-btn"
          @click="closeVideo()"
        ></i>
      </div>
    </div>
  </div>
</template>

<script>
let jessibucaPlayer = {};
export default {
  name: "wkVideoPlayer",
  data() {
    return {
      playing: false,
      isNotMute: false,
      quieting: false,
      fullscreen: false,
      loaded: false, // mute
      speed: 0,
      performance: "", // 工作情况
      kBps: 0,
      btnDom: null,
    };
  },
  props: ["videoUrl", "error", "hasAudio", "height"],
  mounted() {
    this.$nextTick(() => {
      this.updatePlayerDomSize();
      this.btnDom = document.getElementById("buttonsBox");
      window.onresize = () => {
        this.updatePlayerDomSize();
      };
      if (this.videoUrl) {
        this.play(this.videoUrl);
      } else {
        return;
      }
    });
  },
  watch: {
    videoUrl(newData) {
      this.play(newData);
    },
    immediate: true,
  },
  methods: {
    updatePlayerDomSize() {
      let dom = this.$refs.container;
      let width = dom.parentNode.clientWidth;
      let height = dom.parentNode.clientHeight;

      const clientHeight = Math.min(
        document.body.clientHeight,
        document.documentElement.clientHeight
      );
      if (height > clientHeight) {
        height = clientHeight;
        width = (16 / 9) * height;
      }

      dom.style.width = width + "px";
      dom.style.height = height + "px";
    },
    create() {
      let options = {};
      jessibucaPlayer[this._uid] = new window.Jessibuca(
        Object.assign(
          {
            container: this.$refs.container,
            autoWasm: true, // 在使用MSE或者Webcodecs 播放H265的时候,是否自动降级到wasm模式。
            background: "", //背景图片
            controlAutoHide: false, //底部控制台是否自动隐藏
            debug: false, //是否开启控制台调试打印
            decoder: "/jessibuca/decoder.js",
            hasAudio: typeof this.hasAudio == "undefined" ? true : this.hasAudio, // 是否有音频,如果设置false,则不对音频数据解码,提升性能。
            hasVideo: true, //  是否开启控制台调试打印
            heartTimeout: 5, //设置超时时长, 单位秒播放中途,如果超过设定时长无数据返回,则回调timeout事件
            heartTimeoutReplay: true, //是否开启心跳超时之后自动再播放
            heartTimeoutReplayTimes: 3, //重试次数  heartTimeoutReplay 重试失败之后,不再重新播放视频地址。如果想无限次重试,可以设置为-1
            hiddenAutoPause: false, //是否开启当页面的'visibilityState'变为'hidden'的时候,自动暂停播放。
            hotKey: false, //是否开启键盘快捷键 esc -> 退出全屏;arrowUp -> 声音增加;arrowDown -> 声音减少;
            isFlv: false, //当为true的时候:ws协议不检验是否以.flv为依据,进行协议解析。
            isFullResize: false, //当为true的时候:视频画面做等比缩放后,完全填充canvas区域,画面不被拉伸,没有黑边,但画面显示不全
            isNotMute: this.isNotMute, // 是否开启声音,默认是关闭声音播放的。
            isResize: false, //当为true的时候:视频画面做等比缩放后,高或宽对齐canvas区域,画面不被拉伸,但有黑边。 当为false的时候:视频画面完全填充canvas区域,画面会被拉伸。
            keepScreenOn: false, //开启屏幕常亮,在手机浏览器上, canvas标签渲染视频并不会像video标签那样保持屏幕常亮。PC端不会生效,仅手机端生效
            loadingText: "请稍等, 视频加载中......", // 视频加载转圈时的提示文字
            loadingTimeout: 10, //当play()的时候,如果没有数据返回,则回调
            loadingTimeoutReplay: true, ///是否开启loading超时之后自动再播放
            loadingTimeoutReplayTimes: 3, //loadingTimeoutReplay 重试失败之后,不再重新播放视频地址。
            operateBtns: {
              // 配置操作按钮 其中
              fullscreen: false, //全屏按钮
              screenshot: false, //截图按钮
              play: false, //播放暂停按钮
              audio: false, //声音按钮
              record: false, //录制按钮
            },
            recordType: "webm", //默认录制的视频格式
            rotate: 0, //设置旋转角度
            showBandwidth: false, // 显示网速
            supportDblclickFullscreen: false, // 是否支持屏幕的双击事件,触发全屏,取消全屏事件。
            timeout: 10, //设置超时时长, 单位秒在连接成功之前(loading)和播放中途(heart),如果超过设定时长无数据返回,则回调timeout事件
            useMSE: location.hostname !== "localhost" && location.protocol !== "https:", //是否开启MediaSource硬解码
            useWCS: location.hostname === "localhost" || location.protocol === "https", //是否开启Webcodecs硬解码
            useWebFullScreen: false, //是否使用web全屏(旋转90度)(只会在移动端生效)。
            videoBuffer: 0, // 设置最大缓冲时长,单位秒,播放器会自动消除延迟。
            wasmDecodeErrorReplay: true, // 是否开启解码失败重新播放
            wcsUseVideoRender: true, //webcodecs硬解码是否通过video标签渲染
          },
          options
        )
      );
      let jessibuca = jessibucaPlayer[this._uid];
      let _this = this;

      // 监听 jessibuca 初始化事件。
      jessibuca.on("load", function () {
        // console.log("on load init");
      });

      // 信息,包含错误信息
      jessibuca.on("log", function (msg) {
        // console.log("on log", msg);
      });

      // 触发暂停事件
      jessibuca.on("pause", function () {
        _this.playing = false;
      });

      // 触发播放事件
      jessibuca.on("play", function () {
        _this.playing = true;
      });

      // 当前是否全屏
      jessibuca.on("fullscreen", function (msg) {
        // console.log("on fullscreen", msg);
        _this.fullscreen = msg;
      });

      // 触发声音事件,返回boolean值
      jessibuca.on("mute", function (msg) {
        // console.log("on mute", msg);
        _this.isNotMute = !msg;
      });

      // 当解析出音频信息时回调,2个回调参数
      // numOfChannels:声频通道
      // sampleRate 采样率
      // encTypeCode 音频编码类型(10:aac,7:ALAW(g711a),8:MULAW(g711u))
      // encType 音频编码类型(字符串)
      jessibuca.on("audioInfo", function (msg) {
        // console.log("audioInfo", msg);
      });

      let _ts = 0;
      // 当前视频帧pts,单位毫秒ms
      jessibuca.on("timeUpdate", function (ts) {
        _ts = ts;
      });

      // 当解析出视频信息时回调,2个回调参数
      //width:视频宽
      //height:视频高
      //encTypeCode 视频编码类型(10:h264,12:h265)
      //encType 视频编码类型(字符串)
      jessibuca.on("videoInfo", function (info) {
        // console.log("videoInfo", info);
      });

      // 错误信息
      // 目前已有的错误信息:
      // jessibuca.ERROR.playError ;播放错误,url 为空的时候,调用play方法
      // jessibuca.ERROR.fetchError ;http 请求失败
      // jessibuca.ERROR.websocketError; websocket 请求失败
      // jessibuca.ERROR.webcodecsH265NotSupport; webcodecs 解码 h265 失败
      // jessibuca.ERROR.mediaSourceH265NotSupport; mediaSource 解码 h265 失败
      // jessibuca.ERROR.wasmDecodeError ; wasm 解码失败
      jessibuca.on("error", function (error) {
        // console.log("error", error);
      });

      // 当设定的超时时间内无数据返回,则回调
      jessibuca.on("timeout", function () {
        // console.log("timeout");
      });

      // 渲染开始
      jessibuca.on("start", function () {
        // console.log("start");
      });

      // 渲染性能统计,流开始播放后回调,每秒1次。
      // 0: 表示卡顿
      // 1: 表示流畅
      // 2: 表示非常流程
      jessibuca.on("performance", function (performance) {
        let show = "卡顿";
        if (performance === 2) {
          show = "非常流畅";
        } else if (performance === 1) {
          show = "流畅";
        }
        _this.performance = show;
      });

      // 流状态统计,流开始播放后回调,每秒1次。
      // buf: 当前缓冲区时长,单位毫秒,
      // fps: 当前视频帧率,
      // abps: 当前音频码率,单位byte,
      // vbps: 当前视频码率,单位byte,
      // ts:当前视频帧pts,单位毫秒
      jessibuca.on("stats", function (stats) {});

      // 当前网速, 单位KB 每秒1次,
      jessibuca.on("kBps", function (kBps) {
        _this.kBps = Math.round(kBps);
      });

    },
    playBtnClick: function (event) {
      this.play(this.videoUrl);
    },
    play: function (url) {
      console.log(url);
      if (jessibucaPlayer[this._uid]) {
        this.destroy();
      }
      this.create();
      jessibucaPlayer[this._uid].on("play", () => {
        this.playing = true;
        this.loaded = true;
        this.quieting = jessibuca.quieting;
      });
      if (jessibucaPlayer[this._uid].hasLoaded()) {
        jessibucaPlayer[this._uid].play(url);
      } else {
        jessibucaPlayer[this._uid].on("load", () => {
          console.log("load 播放");
          jessibucaPlayer[this._uid].play(url);
        });
      }
    },
    pause: function () {
      if (jessibucaPlayer[this._uid]) {
        jessibucaPlayer[this._uid].pause();
      }
      this.playing = false;
      this.err = "";
      this.performance = "";
    },
    screenshot: function () {
      if (jessibucaPlayer[this._uid]) {
        jessibucaPlayer[this._uid].screenshot();
      }
    },
    mute: function () {
      if (jessibucaPlayer[this._uid]) {
        jessibucaPlayer[this._uid].mute();
      }
    },
    cancelMute: function () {
      if (jessibucaPlayer[this._uid]) {
        jessibucaPlayer[this._uid].cancelMute();
      }
    },
    destroy: function () {
      if (jessibucaPlayer[this._uid]) {
        jessibucaPlayer[this._uid].destroy();
      }
      if (document.getElementById("buttonsBox") == null) {
        this.$refs.container.appendChild(this.btnDom);
      }
      jessibucaPlayer[this._uid] = null;
      this.playing = false;
      this.err = "";
      this.performance = "";
    },
    eventcallbacK: function (type, message) {},
    fullscreenSwich: function () {
      let isFull = this.isFullscreen();
      jessibucaPlayer[this._uid].setFullscreen(!isFull);
      this.fullscreen = !isFull;
    },
    isFullscreen: function () {
      return (
        document.fullscreenElement ||
        document.msFullscreenElement ||
        document.mozFullScreenElement ||
        document.webkitFullscreenElement ||
        false
      );
    },
    closeVideo: function () {
      this.destroy();
      this.$emit("videoClose");
    },
  },
};
</script>

<style>
.buttons-box {
  width: 100%;
  height: 28px;
  background-color: rgba(43, 51, 63, 0.7);
  position: absolute;
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  left: 0;
  bottom: 0;
  user-select: none;
  z-index: 10;
}

.jessibuca-btn {
  width: 20px;
  color: rgb(255, 255, 255);
  line-height: 27px;
  margin: 0px 10px;
  padding: 0px 2px;
  cursor: pointer;
  text-align: center;
  font-size: 0.8rem !important;
}

.buttons-box-right {
  position: absolute;
  right: 0;
}
@font-face {
  font-family: "iconfont"; /* Project id 1291092 */
  src: url("~@/assets/iconfont/iconfont.woff2?t=1673251105600") format("woff2");
}

.iconfont {
  font-family: "iconfont" !important;
  font-size: 16px;
  font-style: normal;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

.icon-play:before {
  content: "\e603";
}

.icon-pause:before {
  content: "\e6c6";
}

.icon-stop:before {
  content: "\e6a8";
}

.icon-audio-high:before {
  content: "\e793";
}

.icon-audio-mute:before {
  content: "\e792";
}

.icon-shuaxin11:before {
  content: "\e720";
}

.icon-weibiaoti10:before {
  content: "\e78f";
}

.icon-weibiaoti11:before {
  content: "\e790";
}

.icon-camera1196054easyiconnet:before {
  content: "\e791";
}
</style>

使用

     <wk-video-player
       class="video"
       ref="player"
       :videoUrl="videoUrl"
       @videoClose="onVideoClose"
       />
---          
videoUrl:'直播流url地址'
onVideoClose() {
   this.$set(this.videoUrl, "");
},

小知识 引入iconfont

将iconfont 下载好的图标 放入assets即可,该字体已上传
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值