首页 > 其他分享 >记一次业务监控流flv播放的封装

记一次业务监控流flv播放的封装

时间:2023-11-27 20:47:34浏览次数:32  
标签:function 播放 封装 flvPlayer param flv player cameraInfo videoElement

[2023年11月27日20:31:09]

记一次业务监控流flv播放的封装

vue3封装flvjs,用于监控流。包括:判断可播放、推流、停流、播放、销毁功能。

/** useRender.ts */
import flvjs from "flv.js";
import type FlvJs from "flv.js";

const host = import.meta.env.VITE_APP_BASE_API;
let player: Flvjs.Player | undefined;
let timer: number | undefined;

/**
 * 判断是否可用flv
 * @returns 
 */
function canUseFlv(): boolean {
  return flvjs.isSupported();
}

/**
 * 初始化
 * @param camereInfo 
 * @param videoElement 
 */
function _init(camereInfo: any, videoElement: HTMLVideoElement) {
  play(camereInfo, videoElement);
}

/**
 * 销毁
 * @param flvPlayer 
 * @returns 
 */
function destroyPlayer(flvPlayer: FlvJs.Player | undefined) {
  if (!flvPlayer) return;
  flvPlayer?.pause();
  flvPlayer?.unload();
  flvPlayer?.detachMediaElement();
  flvPlayer?.destroy();
  flvPlayer = undefined;
}

/**
 * 补帧追帧
 * @param flvPlayer
 * @param videoElement
 */
function increaseFrame(
  flvPlayer: FlvJs.Player,
  videoElement: HTMLVideoElement
) {
  let end = flvPlayer.buffered.end(0);
  let delta = end - flvPlayer.currentTime;
  if (delta > 10 || delta < 0) {
    flvPlayer.currentTime = flvPlayer.buffered.end(0) - 1;
  } else if (delta > 1) {
    videoElement.playbackRate = 1.1;
  } else {
    videoElement.playbackRate = 1;
  }
}

/**
 * 播放
 * @param cameraInfo 
 * @param videoElement 
 */
function play(cameraInfo: any, videoElement: HTMLVideoElement) {
  let flvPlayer = flvjs.createPlayer(
    {
      type: "flv",
      isLive: true,
      hasAudio: false,
      url: cameraInfo.streamAddress,
    },
    {
      enableStashBuffer: false,
      stashInitialSize: 128,
    }
  );
  flvPlayer.mediaElement = videoElement
  flvPlayer.attachMediaElement(videoElement);
  flvPlayer.load();
  player = flvPlayer;

  flvPlayer.on(flvjs.Events.METADATA_ARRIVED, function () {
      console.log("获取视频流...");
      /** 监听进度补追帧 */
      videoElement.addEventListener("progress", function () {
        try {
          increaseFrame(flvPlayer, videoElement);
        } catch {};
      });
      /** 监听重回浏览器画面触发补追帧 */
      videoElement.addEventListener("visibilitychange", function () {
        try {
          increaseFrame(flvPlayer, videoElement);
        } catch {};
      });
      flvPlayer.play();
  });

  /** 断流重连 */
  flvPlayer.on(
    flvjs.Events.ERROR,
    function (errorType: FlvJs.ErrorTypes, errorDetails: FlvJs.ErrorDetails) {
      if(timer) return;
      timer = window.setTimeout(() => {
        console.log("播放时发生了一个错误");
        videoElement.removeEventListener("progress", function () {
          increaseFrame(flvPlayer, videoElement);
        });
        videoElement.removeEventListener("visibilitychange", function () {
          increaseFrame(flvPlayer, videoElement);
        });
        if(player) player = undefined;
        destroyPlayer(flvPlayer);
        _init(cameraInfo, videoElement);
        clearTimeout(timer);
        timer = undefined;
      }, 3000);
    }
  );
}

function killPlayer() {
  if (!player) return;
  player.mediaElement.removeEventListener("progress", function () {
    increaseFrame(player, player.mediaElement);
  })
  player.mediaElement.removeEventListener("visibilitychange", function () {
    increaseFrame(player, player.mediaElement);
  })
  player?.pause();
  player?.unload();
  player?.detachMediaElement();
  player?.destroy();
  player = undefined;
  clearTimeout(timer);
  timer = undefined;
}

/**
 * 开始推流
 * @param cameraInfo
 */
async function startPush(cameraInfo: any) {
  await fetch(host + "/api/Device/Camera/PushCamera", {
    method: "POST",
    headers: new Headers({
      "Content-Type": "application/json",
      "Authorization": userStore.token
    } as HeadersInit),
    body: JSON.stringify([
      {
        bizType: "HKMQTT",
        id: cameraInfo.id,
        cameraName: cameraInfo.cameraName,
        rtspPath: cameraInfo.rtspPath,
        rtmpPath: cameraInfo.rtmpPath,
        streamAddress: cameraInfo.streamAddress,
        no: cameraInfo.no
      }
    ]),
  })
}

/**
 * 停止推流
 * @param cameraInfo
 */
async function stopPush(cameraInfo: any) {
  await fetch(host + "/api/Device/Camera/StopCamera", {
    method: "POST",
    headers: new Headers({
      "Content-Type": "application/json",
      "Authorization": userStore.token
    } as HeadersInit),
    body: JSON.stringify([
      {
        bizType: "HKMQTT",
        id: cameraInfo.id,
        cameraName: cameraInfo.cameraName,
        rtspPath: cameraInfo.rtspPath,
        rtmpPath: cameraInfo.rtmpPath,
        streamAddress: cameraInfo.streamAddress,
        no: cameraInfo.no
      }
    ]),
  });
}

export default function useRender() {
  return {
    startPush,
    stopPush,
    play,
    killPlayer,
    canUseFlv
  };
}

标签:function,播放,封装,flvPlayer,param,flv,player,cameraInfo,videoElement
From: https://www.cnblogs.com/lastkiss/p/17860390.html

相关文章

  • 流媒体播放器EasyPlayer播放H.265与H.264时进度条样式异常该如何解决?
    H5无插件流媒体播放器EasyPlayer属于一款高效、精炼、稳定且免费的流媒体播放器,可支持多种流媒体协议播放,可支持H.264与H.265编码格式,性能稳定、播放流畅,能支持WebSocket-FLV、HTTP-FLV,HLS(m3u8)、WebRTC等格式的视频流,并且已实现网页端实时录像、在iOS上实现低延时直播等功能。有用......
  • 国标GB28181安防视频平台EasyGBS现场突发播放中断是什么原因?
    视频流媒体安防监控国标GB28181平台EasyGBS视频能力丰富,部署灵活,既能作为业务平台使用,也能作为安防监控视频能力层被业务管理平台调用。国标GB28181视频EasyGBS平台可提供流媒体接入、处理、转发等服务,支持内网、公网的安防视频监控设备通过国标GB/T28181协议进行视频监控直播。最......
  • vue指令封装(按钮权限、loading加载、slideIn窗口进入动画)
    vue指令vue本身具有一些指令,但是有些指令是vue作者自己写的,有些是第三方插件写的。v-ifv-if指令是用来控制元素是否显示的,如果值为true,则显示,如果值为false,则隐藏。<divid="app"><pv-if="isShow">我是显示的内容</p><pv-else>我是隐藏的内容</p></div><scri......
  • 流媒体播放器EasyPlayer播放H.265与H.264时进度条样式异常该如何解决?
    H5无插件流媒体播放器EasyPlayer属于一款高效、精炼、稳定且免费的流媒体播放器,可支持多种流媒体协议播放,可支持H.264与H.265编码格式,性能稳定、播放流畅,能支持WebSocket-FLV、HTTP-FLV,HLS(m3u8)、WebRTC等格式的视频流,并且已实现网页端实时录像、在iOS上实现低延时直播等功能。有......
  • Java三大特性:抽象、封装和多态
    Java是一种广泛使用的编程语言,它的三大基本特性是抽象、封装和多态。这些特性是Java的核心,也是理解Java的关键。以下是对这三个特性的详细解释,并通过示例进行说明。一、抽象抽象是Java的一个重要特性,它允许我们定义只展现关键细节的类或接口。抽象有两种形式:隐式抽象和显式抽象。隐......
  • 封装
    该露的露,该藏的藏我们程序设计要求“高内聚,低耦合”,高内聚就是类的内部数据操作细节自己完成,不允许外部干涉;低耦合:仅暴露少量的方法给外部使用封装(数据的隐藏)通常,应该禁止直接访问一个对象中数据的实际表示,而应该通过操作接口来访问,这称为信息隐藏属性私有private操作这个属性的方......
  • 基于FFmpeg和Qt实现简易视频播放器
    VideoPlay001记得一键三连哦使用qt+ffmpeg开发简单的视频播放器,无声音视频解码使用的是软解码即只用CPU进行QPainter绘制每一帧图像,CPU占用过高简单易学,适合小白入门学习FFMpeg视频解析的基本API遗留问题视频播放时间的处理,基匀速播放的实现原理项目代码videoPl......
  • 封装axios
    创建request.jsimportaxiosfrom'axios'import{Message}from'element-ui'importstorefrom'@/store'import{getToken}from'@/utils/auth'//创建axios实例constservice=axios.create({baseURL:process.env.BA......
  • DB107-ASEMI迷你整流桥DB107参数、封装、尺寸
    编辑:llDB107-ASEMI迷你整流桥DB107参数、封装、尺寸型号:DB107品牌:ASEMI封装:DB-4正向电流:1A反向电压:1000V引线数量:4芯片个数:4芯片尺寸:95MIL漏电流:<5ua恢复时间:>500ns浪涌电流:250A芯片材质:正向电压:1.10V封装尺寸:如图特性:插件、薄体扁桥工作结温:-55℃~150℃包装方......
  • 2W10-ASEMI整流圆桥2W10参数、尺寸、封装
    编辑:ll2W10-ASEMI整流圆桥2W10参数、尺寸、封装型号:2W10品牌:ASEMI封装:WOB-4特性:插件、整流圆桥正向电流:2A反向耐压:1000V恢复时间:>2000ns引脚数量:4芯片个数:4芯片尺寸:60MIL浪涌电流:60A漏电流:10ua工作温度:-55℃~150℃包装方式:500/盘;5000/箱备受欢迎的2W10-ASEMI整流......