<script setup> import { onMounted } from 'vue' import { getDictByCode } from '@/api/system/dict' const props = defineProps({ id: { type: String, }, showOperateBtns: { type: Boolean, default: false, }, }) // 定义变量 // const showOperateBtns = false // 是否显示按钮 const secretUserLevelList = ref([]) const forceNoOffscreen = true let jessibuca = null const isfullscreen = ref(false) // 创建播放器的函数 function create() { console.log('执行jessibuca初始化', props.id) const $container = document.getElementById(props.id) if (!$container) { console.error('未找到播放器容器:', props.id) return } jessibuca = new Jessibuca({ container: $container, // 播放器容器 若为 string ,则底层调用的是 document.getElementById('id') videoBuffer: 0.2, // 设置最大缓冲时长,单位秒,播放器会自动消除延迟 isResize: false, // 1. 当为`true`的时候:视频画面做等比缩放后,高或宽对齐canvas区域,画面不被拉伸,但有黑边。 等同于 `setScaleMode(1)` 2. 当为`false`的时候:视频画面完全填充canvas区域,画面会被拉伸。等同于 `setScaleMode(0)` loadingText: '视频加载中', // 加载过程中文案 useMSE: true, // 是否开启MediaSource硬解码 视频编码只支持H.264视频(Safari on iOS不支持)不支持 forceNoOffscreen 为 false (开启离屏渲染) useWCS: false, // 是否开启Webcodecs硬解码 视频编码只支持H.264视频 (需在chrome 94版本以上,需要https或者localhost环境) 支持 forceNoOffscreen 为 false (开启离屏渲染) debug: false, // 是否开启控制台调试 showBandwidth: false, // 是否显示显示网速 loadingTimeout: 60, // flv地址请求超时时间 operateBtns: { // 配置操作按钮 fullscreen: false, // 是否显示全屏按钮 screenshot: false, // 是否显示截图按钮 play: false, // 是否显示播放暂停按钮 audio: false, // 是否显示声音按钮 recorder: false, // 是否显示录制按 }, forceNoOffscreen, // 是否不使用离屏模式(提升渲染能力) isNotMute: false, // 是否开启声音,默认是关闭声音播放的 hotKey: false, // 是否开启键盘快捷键 目前支持的键盘快捷键有:esc -> 退出全屏;arrowUp -> 声音增加;arrowDown -> 声音减少; keepScreenOn: false, // 开启屏幕常亮,在手机浏览器上, canvas标签渲染视频并不会像video标签那样保持屏幕常亮 supportDblclickFullscreen: true, // 是否支持屏幕的双击事件,触发全屏,取消全屏事件 hasAudio: false, // 如果不需要播放音频,可以设置hasAudio为false,这样就不会解码音频数据了,可以提升性能。 autoWasm: true, // 在使用MSE或者Webcodecs 播放H265的时候,是否自动降级到wasm模式。 controlAutoHide: false, // 底部控制台是否自动隐藏 只有鼠标聚焦到播放器内部才会显示,移除之后,会消失。 wasmDecodeErrorReplay: true, // wasm解码报错之后,不再抛出异常,而是直接重新播放视频地址。 wcsUseVideoRender: true, // webcodecs硬解码是否通过video标签渲染, 提升渲染性能。 }) jessibuca.on('videoInfo', (data) => { console.log('videoInfo:', 'width:', data.width, 'height:', data.width) }) jessibuca.on('playFailedAndPaused', (error) => { console.log('playFailedAndPaused事件:监听流断掉', error) }) jessibuca.on('timeout', (error) => { console.log('timeout当设定的超时时间内无数据返回,则回调:', error) }) jessibuca.on('loadingTimeout', () => { console.log('loadingTimeout当play()的时候,如果没有数据返回,则回调: timeout') }) jessibuca.on('pause', (flag) => { console.log('pause触发暂停事件') }) jessibuca.on('fullscreen', (flag) => { console.log('当前是否全屏', flag) isfullscreen.value = flag }) jessibuca.on('play', (flag) => { console.log('play触发播放事件', props.showOperateBtns) // 实现把插件原有截图提醒改成抓拍两字 if (props.showOperateBtns) { const screenshotBtn = $container.querySelector('.jessibuca-screenshot') if (screenshotBtn) { screenshotBtn.title = '抓拍' // 修改按钮内的文本 const textElement = screenshotBtn.querySelector('.icon-title') if (textElement) { textElement.textContent = '抓拍' } } } }) jessibuca.on('playToRenderTimes', (times) => { console.log('监听调用play方法 经过 初始化-> 网络请求-> 解封装 -> 解码 -> 渲染 一系列过程的时间消耗:', times) }) } // 获取视频流地址并播放视频 function play(playUrl = '') { console.log('播放视频路径: ', playUrl) console.log('jessibuca: ', jessibuca) // 播放视频 playUrl && jessibuca.play(playUrl) } // 暂停 function pause() { jessibuca && jessibuca.pause().then(() => { console.log('pause success') }) } // 恢复 function restore() { jessibuca && jessibuca.play().then(() => { console.log('restore success') }) } // 切换播放源 function changeUrl(playUrl = '') { jessibuca && jessibuca.destroy() console.log('切换url', props.id) setTimeout(() => { create(props.id) jessibuca && jessibuca.play(playUrl) }, 100) } // 抓拍 function handleScreenshot() { const systemType = window.localStorage.getItem('systemType') const level = window.sessionStorage.getItem('secretUserLevel') const index = secretUserLevelList.value.findIndex(item => item.value === level) let title = '抓拍图片' if (index !== -1 && systemType === 'gm') { title = `【${secretUserLevelList.value[index].name}】${title}` } console.log(title); jessibuca && jessibuca.screenshot(title, 'png') } // 全屏 function handleFull() { console.log('操作全屏', isfullscreen.value) jessibuca.setFullscreen(!isfullscreen.value) } // 销毁视频 function destroy() { jessibuca && jessibuca.destroy() setTimeout(() => { create(props.id) }, 100) } onBeforeUnmount(() => { destroy() }) // 组件挂载后执行的操作 onMounted(() => { getDictByCode('secretUserLevel').then((response) => { if (response.code === 200) { secretUserLevelList.value = response.data } }) create(props.id) }) // ----------------------- 以下是暴露的方法内容 ---------------------------- defineExpose({ play, destroy, pause, restore, changeUrl }) </script> <template> <div :id="props.id" class="container"> <div> <slot name="drawarea"></slot> </div> <!-- 识别关注要点 --> <div v-if="!isfullscreen"> <slot name="identifyKey"></slot> </div> <!-- title --> <div> <slot name="titles"></slot> </div> <div v-if="props.showOperateBtns" class="button-area"> <div class="screenshot-wrapper" style="margin-right: 6px;"> <img src="../../assets/bigScreen/shot.png" alt="抓拍" @click="handleScreenshot"> </div> <div class="screenshot-wrapper full-wrapper"> <img src="../../assets/bigScreen/full.png" alt="全屏" @click="handleFull"> </div> </div> </div> <slot name="draw" /> </template> <style scoped> .container { /* position: relative; */ background: rgba(13, 14, 27, 0.7); height: 100%; width: 100%; } .button-area { position: absolute; bottom: 1%; right: 1%; z-index: 999999; background-color: rgba(81, 82, 92, 0.7); border-radius: 3px; padding: 1px 6px 0px 6px; } .screenshot-wrapper { position: relative; display: inline-block; } .screenshot-wrapper img { display: block; width: 26px; height: 26px; cursor: pointer; } .screenshot-wrapper::after { content: '抓拍'; position: absolute; bottom: 100%; /* 修改为 bottom: 100% 使文字显示在图片上方 */ left: 50%; transform: translateX(-50%); background-color: rgba(0, 0, 0, 0.7); color: white; padding: 4px 8px; border-radius: 4px; opacity: 0; visibility: hidden; transition: opacity 0.2s, visibility 0.2s; white-space: nowrap; } .full-wrapper::after { content: '全屏'; position: absolute; bottom: 100%; /* 修改为 bottom: 100% 使文字显示在图片上方 */ left: 50%; transform: translateX(-50%); background-color: rgba(0, 0, 0, 0.7); color: white; padding: 4px 8px; border-radius: 4px; opacity: 0; visibility: hidden; transition: opacity 0.2s, visibility 0.2s; white-space: nowrap; } .screenshot-wrapper:hover::after { opacity: 1; visibility: visible; } </style>