首页 > 其他分享 >多监控m3u8视频流,怎么获取每个监控的封面图(纯前端)

多监控m3u8视频流,怎么获取每个监控的封面图(纯前端)

时间:2025-01-18 12:29:34浏览次数:3  
标签:hlsPlayer 截图 videoUrl m3u8 视频流 video 监控 播放

文章目录

1.背景

有这样一个需求:

  1. 给你一个监控列表,每页展示多个监控(至少12个,m3u8格式);
  2. 且展示每个监控的第一帧画面的封面图,但是后端没给你返回封面图;
  3. 点击监控时可以查看具体的监控弹框,支持全屏;

那么、你会怎么办呢?

后端说:后端获取封面图会比较麻烦,还要单独引入一个模块,所以丢给前端来做喽
备注:本例仅为思路分析,具体代码需要具体实现

实现效果如下:
在这里插入图片描述

2.问题分析

  • 首先,有的vue2的视频流播放组件,支持多个视频流同时播放,但那是定制的4宫格或9宫格,不够自由;
  • 或者,有的支持多视频流播放,但是本人暂未找到,其实也可以自定义实现多流播放;
  • 其次,即使有这种组件,但是毕竟是网页端,如果一直播放,性能肯定会扛不住,毕竟一直接收视频片段,这个是巨量的。
  • 所以,还是老老实实地想办法获取第一帧封面图吧!

备注:前端用的vue2

下图为多视频流播放的示例图:
在这里插入图片描述
但是这样会出现一个问题,那就是你会获取无止境的m3u8推流,不久,你的浏览器就会内存溢出(内存将不断增大,下图非只是初始时的截图):
在这里插入图片描述
作为对比,看下只用封面截图的网页资源占用:
在这里插入图片描述

所以,上述方案作废!

由于上述方案作废,所以此处不做多视频流同时播放的代码示例了。

3.解决方案

3.1解决思路

  1. 在监控列表页放一个隐藏的div,div中放的是视频播放组件;
  2. 然后循环播放,在播放的时候截取封面,用的html2canvas
  3. 将截取的封面处理进监控列表的数组中;
  4. 销毁隐藏的视频流播放的div;

3.2解决过程

3.2.1 封装播放组件

首先,你要有一个支持m3u8播放的vue组件,本例用的是hls.min.js,将这个js文件放在/public/js/hls.min.js下。

然后封装的组件示例如下hlsVideo.vue

<!-- 视频巡检专用,其他组件勿用 -->
<template>
  <div >
    <video
      id="hls"
      class="img-responsive video-js vjs-default-skin"
      controls
      ref="videoRef"
      preload="auto"
      :autoplay="autoplay"
      :muted="muted"
      :style="{ width: width, height: height }"
    >
    </video>
  </div>
</template>

<script>
let hlsPlayer
export default {
  props: {
    // 监控地址
    videoUrl: { type: String, default: '' },
    // 监控宽高
    width: { type: String, default: '100%' },
    height: { type: String, default: '100%' },
    // 自动播放
    autoplay: { type: Boolean, default: true },
    // 是否静音,默认静音
    muted: { type: Boolean, default: true }
  },
  watch: {
    videoUrl: {
      deep: true,
      handler(val) {
        if ( hlsPlayer != null ) {
          hlsPlayer.destroy()
        }
        this.handlePlayer()
      }
    }
  },
  mounted() {
    this.handlePlayer()
  },

  beforeDestroy() {
    if ( hlsPlayer!= null ) {
      hlsPlayer.destroy()
      hlsPlayer = null
    }
  },

  methods: {
    // emit 发送播放状态
    handlePlayer() {
      if(this.videoUrl) {
        const video = this.$refs.videoRef
        hlsPlayer = new Hls();
        hlsPlayer.loadSource(this.videoUrl);
        hlsPlayer.attachMedia(video);//将视频元素绑定到此 HLS 对象
        hlsPlayer.on(Hls.Events.MANIFEST_PARSED, () => {
          video.play();
          this.$emit("playing", true);
        });
        hlsPlayer.on(Hls.Events.ERROR, (eventName, data) => {
          if ( data.fatal && data.type !== "networkError" ) {
            video.pause();
            this.$emit("playing", false);
          }
        });
      } else {
        if ( hlsPlayer != null ) {
          hlsPlayer.destroy()
        }
      }
    },
  }
}
</script>
<style lang="scss" scoped>
::v-deep {
  // 隐藏视频监控进度条
  video::-webkit-media-controls-timeline {
    display: none;
  }
  // 隐藏视频监控剩余时间
  video::-webkit-media-controls-time-remaining-display {
    display: none;
  }
}
</style>

3.2.2 隐形的视频div

有了视频播放组件,我们只需要引入即可:

import HlsVideo from "@/componentsUser/m3u8Video/hlsVideo.vue";

然后在页面中写一个div元素来放置该组件:

 <!--      隐藏区域,用于截取封面图     -->
  <div class="hide-video">
    <hls-video
      v-if="tempVideoUrl"
      :video-url="tempVideoUrl"
      id="hiddenVideo"
      ref="hiddenRef"
      :autoplay="true"
      @playing="changePlayStatus"
    />
  </div>

再加上样式,让我们看不见它,让它自己截图玩去吧,CSS样式如下:

.hide-video {
  width: 300px;
  height: 180px;
  position: absolute;
  top: 0;
  left: 0;
  z-index: -2;
}

同时在data中声明以下变量:

 tempVideoUrl: null, // 隐藏的m3u8播放路径
 tempVideoIndex: 0, // 隐藏播放的当前下标,用户循环
 monitorList: [], // 监控列表

3.2.3 截取封面图

获取监控列表,然后进行截图处理

请确保已引入如下插件:
import html2canvas from ‘html2canvas’;

获取监控列表,也就是正常的接口请求:

 // 获取监控列表
    getList() {
      this.loading = true
      listDevice(this.queryParams).then(res => {
        const tempArr = res.rows.map(item => {
          return {
            deviceCode: item.deviceCode,
            type1Name: item.type1Name,
            type2Name: item.type2Name,
            name: item.name,
            deviceLocation: item.deviceLocation,
            status: item.status,
            videoUrl: null, // 监控地址,接口未返回,下面单独的接口循环获取,最好还是让后端返回吧
            posterImg: null, // 默认封面为空,下面循环截取
          }
        })
        this.total = res.total
        this.loading = false
        this.isFirstLoading = false
        this.requestAllVideoUrl(tempArr)
      })
    },

由于监控列表未返回m3u8的地址,所以此处需要再次循环请求获取地址:

你们最好让你们的后端把地址也返回,不然前端循环获取不太好!

 /** 循环请求,获取监控地址,todo:并且截取封面图 */
    requestAllVideoUrl(tempArr) {
      for(let i = 0; i < tempArr.length; i++) {
        const id = tempArr[i].deviceCode
        // 离线(值为2)的直接空值,省略请求
        if(!!id && tempArr[i].status != 2) {
          getVideo({
            channelId: id,
          }).then(res => {
            tempArr[i].videoUrl = res.data || null
          })
        }
      }

      this.monitorList = tempArr

	 // 初始设置第一个监控地址给隐藏的视频模仿组件,然后下面才可以循环截图
      let timer2 = setInterval(() => {
        if(tempArr[0].videoUrl) {
          this.tempVideoUrl = tempArr[0].videoUrl
          clearInterval(timer2)
        }
      }, 100)
    },

我们在上面的hlsVideo.vue组件中写了:

this.$emit("playing", true);
this.$emit("playing", false);

目的是当一个m3u8播放成功后,就告诉组件:我播放完了,你可以截图了,并且可以切换下一个m3u8地址了。

具体的截图代码如下:

 // todo:视频改变播放状态,执行截图功能
    changePlayStatus(e) {
      if(e) {
        setTimeout(() => {
          this.$nextTick(() => {
            if(this.$refs.hiddenRef) {
              const video_width = 396
              const video_height = 180
              const dom = document.getElementById("hiddenVideo");

              html2canvas(dom, {
                windowWidth: video_width * 1.78,
                windowHeight: video_height * 1.78,
                x: 0,
                y: 0,
                useCORS: true, //跨域
                scale: 0.8,
              }).then(canvas => {
                // 截图的base64位图片
                const imgData = canvas.toDataURL('image/jpeg', 1.0);
                // console.log('index', this.tempVideoIndex, imgData)
                this.monitorList[this.tempVideoIndex].posterImg = imgData
                if(this.tempVideoIndex < this.monitorList.length - 1) {
                  this.tempVideoIndex++
                  if(this.monitorList[this.tempVideoIndex].status != 0) {
                    this.tempVideoUrl = this.monitorList[this.tempVideoIndex].videoUrl
                  } else {
                    this.tempVideoIndex++
                    this.tempVideoUrl = this.monitorList[this.tempVideoIndex].videoUrl
                  }
                } else {
                  this.tempVideoUrl = null
                }
              })
            }
          })
        }, 500)
      }

3.3 结束

至此,截图完毕!截图就是最上面放的截图,此处不重复放了

  • 也成功地把封面图赋值给监控列表了,M3u8也销毁了,
  • 监控列表现在放的是图片,
  • 也不存在内存溢出等性能问题了

本例仅做思路,具体代码具体对待

标签:hlsPlayer,截图,videoUrl,m3u8,视频流,video,监控,播放
From: https://blog.csdn.net/yan1915766026/article/details/145199470

相关文章

  • 单片机毕业设计之stm32单片机物联网远程心率血氧MAX30102健康监控系统,老人健康监测+行
    一、设计简介        本项目旨在利用STM32F103C8T6微控制器为核心,构建一个实时人体健康监测系统。该系统集成了多种传感器和模块,能够全面、准确地监测并显示人体的关键健康数据,同时提供异常报警功能,还通过蓝牙通信功能实现了数据的远程传输和记录,方便用户随时了解自己......
  • JVM虚拟机监控及性能调优实战
    大家好,欢迎来到程序视点!我是小二哥。今天我们再来聊聊jvisualvm目录jvisualvm介绍代码语言:txt复制1.jvisualvm是JDK自带的可以远程监控内存,跟踪垃圾回收,执行时内存,CPU/线程分析,生成堆快照等的工具。2.jvisualvm是从JDK1.6开始被继承到JDK中的。jvisualvm使用jvisualvm......
  • 基于STM32单片机自动售货机扫码支付无人超市语音播报无线蓝牙APP/WIFI-APP控制/WIFI视
    STM32-S147语音播报+二维码付+4种商品+4路电机出货+选货+手付+库存+缺货+找零+声光+按键+TFT屏+(无线方式选择)产品功能描述:本系统由STM32F103C8T6单片机核心板、1.44寸TFT彩屏、(无线蓝牙/无线WIFI/无线视频监控模块-可选)、步进电机控制电路、语音播报模块接口、蜂鸣器报警电......
  • DDR 带宽的计算与监控
    DDR带宽(DoubleDataRateBandwidth)是指DDR内存在一秒内可以传输的数据量,通常以GB/s(Gigabytespersecond)为单位。它是衡量内存系统性能的重要指标,直接影响系统的数据吞吐能力。1.如何计算DDR带宽计算DDR理论带宽的公式为:DDR主频*位宽=理论带宽其中,位宽(bitwid......
  • 线程每次iodelay监控及D状态开始和结束监控并做堆栈记录
    一、背景在之前的博客 获取进程或线程级别的iodelay的方法_io验证延时链-CSDN博客里,我们讲到了获取进程或线程的iodelay的方法,但是博客里讲到的获取iodelay的值是一个累积值,并不能准确的捕获到每个单次的iodelay具体是多少。这篇博客里是为了监控每个单次的iodelay,除了监控i......
  • 代码审计-PHP原生开发&SQL注入&数据库监控&正则搜索&文件定位&静态分析
    知识点1、PHP审计-原生态开发-SQL注入&数据库语句监控2、PHP审计-原生态开发-SQL注入&正则匹配搜索3、PHP审计-原生态开发-SQL注入&功能追踪代码审计分类:1、原生态开发-代码审计源码案例2、框架类开发-代码审计源码案例3、组件类开发-代码审计源码案例4、前端类开发-代码......
  • 监控室离岗智能监测摄像头
    监控室离岗智能监测摄像头是一种应用于监控室的智能设备,旨在监测监控室内工作人员的状态,及时警示相关部门或人员,保障监控室的安全和工作效率。这种智能监测摄像头结合了人脸识别技术和智能算法,能够实时监测监控室内工作人员的离岗情况。当监测到监控室内没有工作人员或工作人员长......
  • 中科大提出新视频流制作动画解决方案RAIN,可实现真人表情移植和动漫实时动画。
    中科大提出了一种新的视频流制作动画解决方案RAIN,能够使用单个RTX4090GPU实时低延迟地为无限视频流制作动画。RAIN的核心思想是有效地计算不同噪声水平和长时间间隔的帧标记注意力,同时对比以前基于流的方法多得多的帧标记进行去噪。这种设计允许RAIN生成具有更短延迟和更......
  • 云平台运维监控套件:确保业务稳定运行的关键工具
    云平台运维监控套件:确保业务稳定运行的关键工具随着云计算技术的不断发展和普及,越来越多的企业选择将业务迁移到云端,以提高灵活性和可扩展性。然而,这也带来了新的挑战,特别是在运维管理方面。云平台运维监控套件作为一种全面、高效的解决方案,能够实时监控云主机的各项性能指......
  • 不知道前端代码哪里报错了?我有七种方式去监控它!
    大家好,我是桃子,前端小菜鸟一枚,在日常工作中,有时候是不是不知道前端代码哪里报错了今天我给大家分享七中方法去监控它我们先来说说前端中的错误类型有哪一些错误类型1、SyntaxErrorSyntaxError 是解析时发生语法错误,这个错误是捕获不到的,因为它是发生在构建阶段,而不是运行阶......