前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >如何手动停止 videojs 直播视频流 m3u8 请求?

如何手动停止 videojs 直播视频流 m3u8 请求?

原创
作者头像
喵喵侠
修改2024-06-10 17:40:44
6833
修改2024-06-10 17:40:44
举报

问题描述

在公司某个可视化大屏项目中,大屏页面会有多个 videojs 组件,每个组件都会对应一个视频流地址。每当视频开始播放,视频流m3u8 会不断请求,即便是暂停了播放,这个请求也不会终止。大量的请求会导致页面卡顿,长此以往会带来性能问题,导致浏览器卡死甚至崩溃。

而大屏操作中,经常会用到组件联动,点击百度地图的点位,出现一个视频弹窗,点击关闭视频,其实是隐藏了视频,而视频的请求还在继续。为了解决这个问题,我花了一些时间研究,找到了解决办法。

解决办法

从videojs官方文档可以查到,有一个 dispose 方法。这个方法是用来销毁 videojs 对象的。但这个方法不能直接使用,直接使用会导致一个新的问题,那就是销毁实例后 ,原本的 video 标签dom 元素也一并销毁了,这个特性从官方文档中可以看出。

Videojs Removing Players

其实我个人觉得,这个方法的操作 2 的特性非常不好,这样导致关闭后组件直接被销毁,导致下次触发视频弹窗(业务需求是点击百度地图图例,出现弹窗播放视频直播流),没有视频组件可以显示播放。

于是我针对这个项目组件,写了一个 Vue 的watch,用来监听监听 display 属性。在这个项目中,这个属性每个组件都有,display 为 false 是显示,true 是隐藏(别问为什么是反的,我也不知道)。代码示例如下:

代码语言:vue
复制
<template>
  <div :style="styleObject" ref="myvideojs">
    <!-- <video
      :id="videojsId"
      class="video-js vjs-big-play-centered vjs-fluid"
      style="width: 100%; height: 100%; object-fit: fill"
    ></video> -->
    <!-- padding-top: 0,解决减小高度到一定数值后,高度不能自适应的问题 -->
    <video :id="videojsId" class="video-js vjs-big-play-centered vjs-fluid" style="width: 100%; height: 100%; object-fit: fill; padding-top: 0" ref="videoPlayer"></video>
  </div>
</template>
代码语言:vue
复制
 watch: {
    ...
    display: {
      handler(newVal) {
        // true 代表隐藏
        if (newVal) {
          console.log("隐藏 :>> ")
          if (this.myVideo) {
            this.$nextTick(() => {
              // 必须先暂停,后销毁,销毁后 dom 元素也会被移除,所以需要手动添加相同 id 的 dom
              this.myVideo.dispose()
              // 下面这个 dom 跟 video 标签属性一致
              const videoElement = document.createElement("video")
              videoElement.setAttribute("id", this.videojsId) //注意 id 要一致
              videoElement.setAttribute("class", "video-js vjs-big-play-centered vjs-fluid")
              videoElement.setAttribute("style", "width: 100%; height: 100%; object-fit: fill; padding-top: 0")
              videoElement.setAttribute("ref", "videoPlayer")
              this.$refs.myvideojs.appendChild(videoElement) //添加相同 DOM
              this.myVideo = null
            })
          }
        } else {
          console.log("显示 :>> ")
        }
      },
    },
  }

下面是绘制组件的方法:

代码语言:vue
复制
methods: {
    // 绘制方法
    drawChar(result) {
      let that = this
      if (result.length > 1) {
        console.log(this.MapPoiChange)
        console.log(this.option.Playtype)
        let key = this.MapPoiChange ? this.MapPoiChange : this.option.Playtype ? this.option.Playtype : "SXT"
        result = result.filter(v => {
          return v.key == key
        })[0]
      } else {
        result = result[0]
      }
      // 这些options属性也可直接设置在video标签上,见 muted
      // 实例化过,修改最新的url
      if (this.myVideo) {
        this.myVideo.src({ type: result.type, src: result.value })
      } else {
        let options = {
          autoplay: this.option.autoplay, // 设置自动播放
          controls: true, // 显示播放的控件
          width: this.component.width,
          height: this.component.height,
          sources: [
            {
              src: result.value,
              type: result.type, // 告诉videojs,这是一个hls流
            },
          ],
        } // videojs的第一个参数表示的是,文档中video的id
        this.myVideo = Videojs(this.videojsId, options, function onPlayerReady() {
          this.on("error", function () {
            // 报错信息
            var mediaError = this.error()
            console.log("mediaError", mediaError)
            // 异常处理
            that.updateData()
          })
        })
      }
    },
  },

以上代码的核心有3点:

  1. 关闭的时候,销毁 videojs;
  2. 销毁后立即创建一个与先前videojs 相同的 dom,尤其是 id 要保持一致;
  3. 显示时候重新初始化渲染 videojs(因为全局方法默认会调用绘制 drawChar,否则需要再显示逻辑里面新增绘制方法)

只要注意到这三个核心点,类似的问题也能迎刃而解。

注意事项

1. 销毁要包裹在\$nextTick里面,不然会出现报错。

代码语言:vue
复制
Error:Invalid target for nutl#on;must be a DOM node or evented object
  1. 需要通过 appendChild,添加一个跟之前 videojs 一样的根 dom,不然会报错找不到这个元素的 id:
代码语言:vue
复制
TypeError: The element or ID supplied is not valid. (videojs)

总结

关于 videojs,实际项目用到的比较多,坑也是真的坑。文档不太好找,搜索查询了好长时间,才摸索出一套可行的解决方案。面对这类问题,需要善用搜索,从别人的文章和问答中寻找解决问题的思路和方案。查阅官方文档也是个不错的选择,但并不是每个类库框架的官方文档写的都易于理解。videojs 新版的文档和旧版本有些区别,很多 API 看起来并不十分直观,所以版本问题也要注意下。

以上是我解决这个问题的经验分享,欢迎评论区交流。

参考

vue使用videojs控制后台m3u8数据请求 - bomdeyada - 博客园


我正在参与2024腾讯技术创作特训营最新征文,快来和我瓜分大奖!

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 问题描述
  • 解决办法
  • 注意事项
  • 总结
  • 参考
相关产品与服务
云直播
云直播(Cloud Streaming Services,CSS)为您提供极速、稳定、专业的云端直播处理服务,根据业务的不同直播场景需求,云直播提供了标准直播、快直播、云导播台三种服务,分别针对大规模实时观看、超低延时直播、便捷云端导播的场景,配合腾讯云视立方·直播 SDK,为您提供一站式的音视频直播解决方案。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档