@videojs-player/vue 直播fiv 组件封装 添加flv-extend 延迟问题

news/2025/3/24 22:29:13/文章来源:https://www.cnblogs.com/zxh-bug/p/18787724

包的版本

 

"@videojs-player/vue": "^1.0.0",
"flv.js": "1.6.2",
"video.js": "^8.22.0",
"flv-extend": "^0.3.0",

 

<template><!-- 封装的视频播放器组件 --><video-player ref="videRef" :options="state.playerOptions" :src="videoSrc"  @mounted="handleMounted" @unmounted="handleUnmounted" />
</template><script setup lang="ts">
import { reactive, defineProps, defineEmits, getCurrentInstance, watch,ref } from "vue";
import { VideoPlayer } from '@videojs-player/vue'
import videojs from 'video.js'
import 'video.js/dist/video-js.css'
import video_zhCN from 'video.js/dist/lang/zh-CN.json'
import { FlvJsTech } from './flv-video-tech'
videojs.addLanguage('zh-CN', video_zhCN)
const { proxy } = getCurrentInstance();
// 注册 FlvJsTech
videojs.registerTech('Flvjs', FlvJsTech);
// 定义 props 类型
type Props = {// 视频源地址videoSrc: string;// 是否显示控制栏showControls: boolean;// 是否自动播放autoplay: boolean;// 是否静音muted: boolean;// 是否循环播放loop: boolean;// 音量大小volume: number;// 是否禁用画中画disablePictureInPicture: boolean;// v-model 绑定的值,用于控制播放状态modelValue: boolean;
};// 定义 props
const props = defineProps<Props>();/*** 定义视频播放器可能触发的所有事件列表* 这些事件将用于监听视频播放器的各种状态变化* 例如加载开始、播放、暂停、结束等*/
const eventsArr = [// 视频开始加载时触发'loadstart',// 视频加载暂停时触发'suspend',// 视频加载中止时触发'abort',// 视频加载出错时触发'error',// 视频元素被清空时触发'emptied',// 视频加载停滞时触发'stalled',// 视频元数据加载完成时触发'loadedmetadata',// 视频的第一帧数据加载完成时触发'loadeddata',// 视频可以开始播放时触发'canplay',// 视频可以流畅播放时触发'canplaythrough',// 视频开始播放时触发'playing',// 视频暂停等待数据时触发'waiting',// 视频开始跳转时触发'seeking',// 视频跳转完成时触发'seeked',// 视频播放结束时触发'ended',// 视频时长发生变化时触发'durationchange',// 视频播放时间更新时触发'timeupdate',// 视频加载进度更新时触发'progress',// 视频开始播放时触发'play',// 视频暂停时触发'pause',// 视频播放速率改变时触发'ratechange',// 视频播放器尺寸改变时触发'resize',// 视频音量改变时触发'volumechange',// 视频海报改变时触发'posterchange',// 视频语言设置改变时触发'languagechange',// 视频全屏状态改变时触发'fullscreenchange',// 视频播放速率选项改变时触发'playbackrateschange',// 视频控制栏禁用时触发'controlsdisabled',// 视频控制栏启用时触发'controlsenabled',// 视频进入全屏窗口时触发'enterFullWindow',// 视频退出全屏窗口时触发'exitFullWindow',// 视频进入画中画模式时触发'enterpictureinpicture',// 视频离开画中画模式时触发'leavepictureinpicture',// 视频源设置完成时触发'sourceset',// 视频文本轨道改变时触发'texttrackchange',// 视频文本数据更新时触发'textdata',// 用户活动时触发'useractive',// 用户不活动时触发'userinactive',// 视频使用自定义控制栏时触发'usingcustomcontrols',// 视频使用原生控制栏时触发'usingnativecontrols',// 视频播放器销毁时触发'dispose',// 视频插件设置前触发'beforepluginsetup',// 视频插件设置完成时触发'pluginsetup',// 视频组件尺寸改变时触发'componentresize',// 视频播放器尺寸改变时触发'playerresize',// 视频播放器被点击时触发'tap',// 视频播放器准备好时触发'ready'
];// 定义事件
const emits = defineEmits();type VideoJsPlayer = ReturnType<typeof videojs>;
const state = reactive({playerOptions: {// 是否显示控制栏,从 props 获取controls: props.showControls,// 是否等浏览器准备好后自动播放,从 props 获取autoplay: props.autoplay,// 是否静音,从 props 获取muted: props.muted,// 结束后是否重新开始,从 props 获取loop: props.loop,// 播放视频源,从 props 获取// sources: [{ type: 'video/flv', src: props.videoSrc }],// 为 true 时,播放器具有流畅的大小fluid: true,// 播放顺序techOrder: [ 'flvjs','html5'],// 音量,从 props 获取volume: props.volume,language: 'zh-CN',// 禁用画中画,从 props 获取disablePictureInPicture: props.disablePictureInPicture}
});const handleMounted = ({ player }: { player: VideoJsPlayer }) => {// 设置视频源// 触发自定义事件,将 player 对象传递给父组件emits('update:playerReady', player);eventsArr.forEach(event => {player.on(event, (e) => {let parameter = {event: e,theNameOfTheEvent: event,videoJsPlayer: player,}emits('update:' + event, parameter);});});// 监听播放和暂停事件,更新 v-model 绑定的值player.on('play', () => {emits('update:modelValue', true);});player.on('pause', () => {emits('update:modelValue', false);});// 根据 v-model 绑定的值控制播放状态if (props.modelValue) {player.play();} else {player.pause();}
};const handleUnmounted = () => {};</script><style lang="scss" scoped>
/* 组件样式 */
</style>

flv-video-tech.ts  文件

 

import flvjs from "flv.js";
import FlvExtend from "flv-extend";
import videojs from "video.js";// 获取 Video.js 的 Html5 技术类实例
const Html5 = videojs.getTech("Html5")! as any;/*** 自定义的 FlvJsTech 类,继承自 Video.js 的 Html5 技术类* 用于支持 FLV 视频的播放,并集成 FlvExtend 以实现自动追帧等功能*/
export class FlvJsTech extends Html5 {private flvPlayer: flvjs.Player | null = null;private flvExtendInstance: FlvExtend | null = null; // 新增 FlvExtend 实例constructor(options: any, ready: any) {super(options, ready);}/*** 设置视频源* @param {string} src - 视频源的 URL*/setSrc(src: string) {this.dispose(); // 销毁之前的播放器// 初始化 FlvExtend 实例this.flvExtendInstance = new FlvExtend({element: this.el_, // 绑定的 HTML 元素frameTracking: true, // 开启追帧设置updateOnStart: true, // 点击播放后更新视频updateOnFocus: true, // 获得焦点后更新视频reconnect: true, // 开启断流重连trackingDelta: 1, // 追帧最大延迟,延迟超过1s即开启追帧showLog: false // 是否显示插件的 log 信息});// 初始化 flvPlayer 实例,并将其与 FlvExtend 关联this.flvPlayer = this.flvExtendInstance.init({type: "flv", // 视频类型url: src, // 视频源 URLisLive: true, // 是否为直播hasAudio: false, // 是否包含音频cors: true // 显式启用跨域},{enableStashBuffer: true, // 是否启用缓存缓冲区autoCleanupSourceBuffer: true, // 是否自动清理源缓冲区stashInitialSize: 128, // 初始缓存大小enableWorker: false // 是否启用 Web Worker}) as unknown as flvjs.Player;this.flvEvent(); // 绑定事件this.flvPlayer.load(); // 加载视频this.flvPlayer.play(); // 开始播放}/*** 绑定 flvPlayer 的事件*/flvEvent() {if (this.flvPlayer) {this.flvPlayer.on(flvjs.Events.ERROR, (errorType, errorDetail, errorInfo) => {this.trigger("error"); // 触发错误事件});}}/*** 销毁实例并清理资源*/dispose() {if (this.flvPlayer) {this.flvPlayer.pause();this.flvPlayer.unload();this.flvPlayer.detachMediaElement();this.flvPlayer.destroy();this.flvPlayer = null;}if (this.flvExtendInstance) {// 清理 FlvExtend 实例(this.flvExtendInstance as any).destroy();this.flvExtendInstance = null;}}/*** 支持的视频格式* @type {{ 'video/flv': string; 'video/x-flv': string }}*/static formats = {"video/flv": "FLV","video/x-flv": "FLV"};/*** 检查当前环境是否支持 FLV 视频播放* @returns {boolean} - 如果支持则返回 true,否则返回 false*/static isSupported = () => flvjs.isSupported();/*** 检查指定的视频类型是否可以播放* @param {string} type - 视频类型* @returns {string} - 如果支持则返回 'maybe',否则返回空字符串*/static canPlayType = (type: string) =>FlvJsTech.isSupported() && type in FlvJsTech.formats ? "maybe" : "";/*** 检查指定的视频源是否可以播放* @param {any} source - 视频源对象* @returns {string} - 如果支持则返回 'maybe',否则返回空字符串*/static canPlaySource = (source: any) =>FlvJsTech.isSupported() && source.src.endsWith(".flv") ? "maybe" : "";
}

使用方式

 

<VideoPlayerWrapper v-model="state.isPlaying" :videoSrc="state.videoSrc" :showControls="true":autoplay="true" :muted="true" :loop="false" :volume="0.6" :disablePictureInPicture="true"@update:usingnativecontrols="onTap" />
import VideoPlayerWrapper from '@/components/VideoPlayerWrapper/index.vue'

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/904167.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

# 集美大学课程实验报告-实验3:栈和队列

集美大学课程实验报告-实验2:线性表项目名称 内容课程名称 数据结构班级 网安2411指导教师 郑如滨学生姓名 李斌财学号 202421336021实验项目名称 站和队列上机实践日期上机实践时间 2学时一、目的(本次实验所涉及并要求掌握的知识点) 掌握STL中栈和队列的基本存储结构 掌握…

L3 设计,开发,认证

我都想笑了之十万八千个视频需要看。L3 设计,开发,认证 这里我暂时跳过了那些PPT里面要求看的视频,过一会再整理。 利益相关者和需求 ​ 从图中我们可以得到如下信息:航空器的生命周期:设计——生产——认证——运营 原始设备制造商(original equipment manufacturer,OE…

KMP 入门

前传:BF 算法 BF 算法即为暴力解法,一位一位向下匹配。 时间复杂度约为 \(O(n \times m)\)。KMP KMP 算法的主要思想是利用部分匹配信息,避免重复匹配,提高字符串查找效率。 KMP 算法总时间复杂度是 \(O(n + m)\),匹配用时 \(O(n)\)。 \(m\) 为模式串长度,\(n\) 为目标串…

web-CodeInject

<?php#Author: h1xaerror_reporting(0); show_source(__FILE__);eval("var_dump((Object)$_POST[1]);");eval("var_dump((Object)$_POST[1]);");:这行代码使用了eval()函数,这是一个非常危险的函数,因为它会执行传递给它的字符串作为PHP代码。这意味…

kettle插件-dm达梦数人大金仓Vastbase数据库插件

在国家大力倡导原创技术、推动信息技术应用创新(信创)的政策背景下,摆脱对国外技术的依赖、构建自主可控的信息技术体系成为重要发展方向。大数据作为信息技术的重要组成部分,国产大数据技术和产品迎来了前所未有的发展机遇。 信创旨在实现核心技术自主可控,保障国家信息安…

广义优势估计(GAE):端策略优化PPO中偏差与方差平衡的关键技术

广义优势估计(Generalized Advantage Estimation, GAE)由Schulman等人在2016年的论文中提出,是近端策略优化(PPO)算法的重要基础理论,也是促使PPO成为高效强化学习算法的核心因素之一。 GAE的理论基础建立在资格迹(eligibility traces)和时序差分λ(TD-λ)之上,为深入理解GA…

集合体系介绍、collection的使用--java进阶day09

1.集合体系结构 我们要学习的集合大体分为两种,一种是单列集合,一种是双列集合2.单列集合 单列集合又分为两个派系,分别为list接口和set接口,这两个接口皆是collection接口的子接口3.Collection接口既然要使用,那就必然要创建对象,但我们知道Collection是接口,不能实例化…

mybatis组件SqlSource的种类

SqlSource是mybatis重要的组件,是对你写的sql语句的简单封装。public interface SqlSource {BoundSql getBoundSql(Object parameterObject);}这个接口有很多种实现:VelocitySqlSource这个实现类是一个测试。实际上mybatis根本就不会使用这个实现类。 那么在mybatis内部是在哪…

静雅斋目录2

托管于国内企业顶想云的使用目录前情概要 本来已经有一个使用目录了,但是实在是受不了 GitHub 时不时卡壳的表现,就重新启用这个国内的搜索目录,外观要稍微差一点,但使用体验要好得多。 托管地址 托管于 顶想云 平台的目录样式 .编辑地址:顶想云.iframe-container { /* 容…

ARP高级欺骗-配置路由转发

引出问题: 当我们发起一次ARP欺骗之后,目标主机会出现断网情况。这种很容易就会被目标主机A发现。那我们怎么让目标主机发现不了自己被ARP欺骗了呢?问题描述: 1.受害主机A断网: 当目标主机A上网时,会进行TCP的连接,但是因为ARP欺骗之后,主机A的路由转发到的是主机B而不…

使用XIAO ESP32C6, XIAO扩展板和SHT31温湿度传感器构建温湿度计

我很高兴与您分享我的最新项目:我使用XIAO ESP32C6, XIAO扩展板和SHT31温湿度传感器构建的DIY温湿度计。我的目标是创造一种设备,可以帮助我监测家里的湿度水平,特别是因为我住在沿海热带地区,那里的湿度波动很大。这个想法来自于我需要保持一个舒适的室内环境。有时空气会…