vue3+setup使用rtsp视频流实现实时监控,全屏,拍摄,自动拍摄等功能(纯前端)

vue3+setup使用rtsp视频流实现实时监控,全屏,拍摄,自动拍摄等功能(纯前端)

概要

本文介绍了如何在Vue应用中通过WebRTC技术获取摄像头的rtsp视频流,同时展示了实时监控,全屏,拍摄,自动拍摄等功能。

一、获取rtsp流并确保其可用

1.因为是纯前端角度,所以从后端可以获取http开头的视频流地址(其实是在后端电脑打开,然后本地接入后端电脑,进行查看或修改配置)因为rstp流需要转码,所以在摄像头配置里面要修改转码格式
2.前端自己可以下载安装VLC播放器然后进行调试设置
在这里插入图片描述

二、在vue3项目里引入rtsp流

1.下载webrtc-streamer
下载地址:https://github.com/mpromonet/webrtc-streamer/releases
下载版本根据自己电脑进行选择,双击webrtc-streamer.exe可执行文件后在浏览器访问http://127.0.0.1:8000,可以看到自己电脑正在操作的内容。
2.将/html/libs目录下的adapter.min.js和/html目录下面的webrtcstreamer.js文件分别拷贝到vue项目public中,并在index.html文件全局引入。

 <script src="/adapter.min.js"></script><script src="/webrtcstreamer.js"></script>

三、具体代码,video封装

1.父页面

<script setup>import { ref } from 'vue'import videoRtmp from './videoRtmp.vue'
const list = ref([])
const idlist = ref([])
const imgArr = ref([]) // 手动抓拍的图片
const screenshotUrl = ref([]) // 自动抓拍的图片const total = ref(0)
const currentPage = ref(1)
const keyWord = ref('')
const rtmpUrl = ref('rtsp://用户:密码@电脑网址:554')
// videoFlag 判断是单个还是多个video 对应不同的样式 false是单个 true是多个
const form = ref({ videoFlag: false, videoList: [] })
const openVideo = ref(false)
const screenButton = ref(false) // 默认解禁 点击抓拍按钮后禁止 抓拍完成后解禁
const sButton = ref(true) // 默认禁止 加载完成后解禁
let screenNums = 0 // 加载完成的数量const loadData = (pageNum = currentPage.value, pageSize = 10) => {list.value = [{id: 1,idName: 'id1',name: '设备1',rtmpUrl: 'rtsp://用户:密码@电脑网址:554',userName: 'admin',screenFlag: false,},{id: 2,idName: 'id2',name: '设备2',code: '002',userName: 'admin',password: 'VWEFKS',screenFlag: false,rtmpUrl: 'rtsp://用户:密码@电脑网址:554',},]total.value = list.value.length
}//分页
const handlePageChange = (page) => {currentPage.value = pageloadData()
}
// 搜索
const searchHandle = async () => {currentPage.value = 1loadData()
}
/** 选择条数  */
function handleSelectionChange(selection) {console.log(selection)idlist.value = selection
}
//单个点击观看
const videoLook = (row) => {console.log(row)form.value.videoList = [row]form.value.videoFlag = falseopenVideo.value = true
}
//多个观看
const videoAllLook = (row) => {console.log(row)form.value.videoList = idlist.valueform.value.videoFlag = idlist.value.length > 1 ? true : falseopenVideo.value = true
}//点击叉号
const closeHandle = () => {resetData()
}
//清空数据
const resetData = () => {openVideo.value = falseimgArr.value = []  screenshotUrl.value = []screenNums = 0screenButton.value = falseform.value = {}loadData()
}
// 抓拍
const screenshot = () => {form.value.videoList.forEach((v) => {v.screenFlag = true})screenButton.value = true
}
//父子传值 获取抓拍的
const handleScreenshot = (data, flag) => {console.log(data.id, data,flag)if (!flag) {// 自动抓拍screenshotUrl.value.push(data.image)imageVideoApi()return}// 手动抓拍form.value.videoList.forEach((v) => {if (v.id == data.id) {v.screenFlag = false}})imgArr.value.push(data.image)if (!form.value.videoList.some((a) => a.screenFlag)) {screenButton.value = falseimageVideoApi()}
}
// 父子传值 获取video是否成功
// 因为video加载需要一段时间,在这段时间里,不能抓拍,所以要在这段时间给它禁用掉,等到video加载完后,在解禁
// 这里做判断 在子页面加载完成emit返回主页面 然后判断返回的数量 符合video的数量,说明都加载完了
const screenButtonS = () => {screenNums++if (form.value.videoList.length == screenNums) {sButton.value = false}
}
// 图片检测接口
const imageVideoApi = async () => {let files = base64ToFile(imgArr.value[0], 'image.png')let res = await imageVideo({ file: files })
}
// base64转file
function base64ToFile(base64Data, filename) {// 将base64的数据部分提取出来const arr = base64Data.split(',')const mime = arr[0].match(/:(.*?);/)[1]const bstr = atob(arr[1])let n = bstr.lengthconst u8arr = new Uint8Array(n)while (n--) {u8arr[n] = bstr.charCodeAt(n)}// 将Uint8Array转换为Blob对象const blob = new Blob([u8arr], { type: mime })// 创建File对象const file = new File([blob], filename, { type: mime })return file
}
loadData()
</script>
<template><div><el-form class="main-form" :inline="true"><el-form-item label="设备名称:"><el-input v-model="keyWord" placeholder="请输入设备名称" /></el-form-item><el-form-item><el-button :icon="Search" type="primary" @click="searchHandle">搜索</el-button></el-form-item><el-form-item><el-button :icon="Search" type="primary" :disabled="idlist.length <= 0" @click="videoAllLook">多流播放</el-button></el-form-item></el-form><!-- 列表部分 --><el-table border :data="list" height="460" scrollbar-always-on="true" @selection-change="handleSelectionChange"><el-table-column align="center" type="selection" width="50" /><el-table-column label="设备名称" prop="name" /><el-table-column label="账号" prop="userName" width="100" /><el-table-column fixed="right" label="操作" width="160"><template #default="scope"><el-button size="small" type="primary" @click="videoLook(scope.row)">播放</el-button></template></el-table-column></el-table><el-paginationbackground:current-page="currentPage":hide-on-single-page="true"layout="prev, pager, next":total="total"@current-change="handlePageChange"/><el-dialog title="实时监控" width="900px" :close-on-click-modal="false" @close="closeHandle" v-model="openVideo"><div v-if="!form.videoFlag"><h2 style="text-align: center">{{ form.videoList[0]?.name }}</h2><video-rtmp:rtspUrl="form.videoList[0]?.rtmpUrl":id="form.videoList[0]?.idName":screenFlag="form.videoList[0]?.screenFlag":data="form.videoList[0]"@screenshot="handleScreenshot"@screenButton="screenButtonS"/></div><div class="videoAll" v-else><div v-for="(item, index) in form.videoList" :key="index"><h2 style="text-align: center">{{ item?.name }}</h2><video-rtmp:rtspUrl="item?.rtmpUrl":id="item?.idName":screenFlag="item?.screenFlag":data="item"@screenshot="handleScreenshot"@screenButton="screenButtonS"/></div></div><div><el-button type="primary" :disabled="screenButton || sButton" v-preventReClick @click="screenshot">抓拍</el-button></div><div>手动抓拍<img style="width: 300px; height: 100px" v-for="(item, index) in imgArr" :key="index" :src="item" /></div><div>自动抓拍<img style="width: 100px; height: 50px" v-for="(item, index) in screenshotUrl" :key="index" :src="item" /></div></el-dialog></div>
</template><style scoped lang="scss">
.videoAll {> div {width: 45%;height: 45%;display: inline-block;}> div:nth-child(odd) {margin-right: 5%;}
}
</style>

2.子页面

<script setup>
defineOptions({name: 'VideoRtmp',
})
// 如果不想放到public里面并在index.html里面引入,也可以选择其他位置
// import WebRtcStreamer from './webrtcstreamer.js'
import { ref } from 'vue'const emit = defineEmits()
const props = defineProps({rtspUrl: {type: String,default: '',},id: {type: String,default: '',},data: {type: Object,default: '',},screenFlag: {type: Boolean,default: '',},
})
const videoRef = ref(null)
const webRtcServer = ref(null)
const srcUrl = ref(process.env.NODE_ENV === 'development' ? 'http://网址:端口' : 'http://网址:端口') //这里看自己的需要,也可以传入另一台电脑的ip,前提是都得在在一个局域网内
// 设置抓拍间隔时间,单位为毫秒,这里设置为5000毫秒(即5秒)
const captureInterval = 5000
// 新增:用于存储定时器标识
const captureTimer = ref(null)watch(() => props.rtspUrl,(val) => {if (val) {// 这里放开会报错,还没有找到原因//   webRtcServer.value.disconnect()nextTick(() => {initVideo()})}},{ deep: true, immediate: true }
)
watch(() => props.screenFlag,(val) => {if (val) {handleScreenshot(true)}},{ deep: true, immediate: true }
)
function initVideo() {try {//video:需要绑定的video控件ID//127.0.0.1:8000:启动webrtc-streamer的设备IP和端口,默认8000//连接后端的IP地址和端口// 静音videoRef.value.volume = 0webRtcServer.value = new WebRtcStreamer(props.id, srcUrl.value)//需要查看的rtsp地址,根据自己的摄像头传入对应的rtsp地址即可。注意:视频编码格式必须是H264的,否则无法正常显示,编码格式可在摄像头的后台更改//向后端发送rtsp地址webRtcServer.value.connect(props.rtspUrl)setTimeout(() => {emit('screenButton')}, 1000)} catch (error) {console.log(error)}
}/* 处理双击 视频全屏*/
const dbClick = () => {const elVideo = document.getElementById(props.id)if (elVideo.webkitRequestFullScreen) {elVideo.webkitRequestFullScreen()} else if (elVideo.mozRequestFullScreen) {elVideo.mozRequestFullScreen()} else if (elVideo.requestFullscreen) {elVideo.requestFullscreen()}
}
/* 抓拍*/
function handleScreenshot(flag) {let video = document.getElementById(props.id) //获取dom节点let canvas = document.createElement('canvas') //创建canvas节点let w = window.innerWidthlet h = (window.innerWidth / 16) * 9canvas.width = wcanvas.height = h //设置canvas宽高const ctx = canvas.getContext('2d')ctx.drawImage(video, 0, 0, w, h) //video写入到canvaslet obj = {name: props.data.name,id: props.data.id,image: canvas.toDataURL('image/jpge'), //生成截图地址flags: flag,}// flag  true 手动抓拍  false 自动抓拍emit('screenshot', obj, flag)
}// 开始自动抓拍
const startAutoCapture = () => {captureTimer.value = setInterval(() => {handleScreenshot(false)}, captureInterval)
}
// 新增:停止自动抓拍功能
const stopAutoCapture = () => {if (captureTimer.value) {clearInterval(captureTimer.value)captureTimer.value = null}
}
onMounted(() => {startAutoCapture()
})
//销毁视频流
onUnmounted(() => {webRtcServer.value.disconnect()stopAutoCapture()
})
</script>
<!-- style="object-fit: fill; 设置视频内容撑满整个video标签 -->
<template><div class="video-contianer"><video ref="videoRef" :id="id" controls autoplay muted width="100%" height="100%" style="object-fit: fill"></video><div class="mask" @dblclick="dbClick"></div></div>
</template><style scoped lang="scss">.video-contianer {position: relative;.mask {position: absolute;cursor: pointer;top: 25%;left: 0;width: 100%;height: 50%;}
}
</style>

小结

第一次写这种实时监控加抓拍的功能,可能还有一些不足,后面再看看有没有其他更好的办法。 本地开发的时候要双击运行webrtc-streamer.exe可执行文件后,vue项目才能展示实时监控,打包发布到线上的时候可能要让后台在服务器上安装webrtc-streamer并提供真实的地址,关于这点现在还没来得及试

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

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

相关文章

【源码阅读系列】(五)进程间通信(二)

进程间通信(二) 这一部分主要会介绍Android中特有的几个IPC机制。分别是: Intent、Binder、AIDL、ContentProvider https://juejin.cn/post/7244018340880007226 https://juejin.cn/post/6844903764986462221 Binder https://juejin.cn/post/7244018340880007226 https://j…

机器学习(ML)在发射机识别与资源管理的应用

电子战&#xff08;EW&#xff09;涉及在受干扰的频谱环境中&#xff0c;通过多个无线电频率传感和发射平台进行非合作交互。操作人员需要管理频谱资源、共享关键情报&#xff0c;并有效干扰威胁发射器。现代RF系统的复杂性和威胁发射器的敏捷性&#xff0c;要求系统能够以机器…

高项 - 信息化发展

个人总结&#xff0c;仅供参考&#xff0c;欢迎加好友一起讨论 博文更新参考时间点&#xff1a;2024-11-09 高项 - 章节与知识点汇总&#xff1a;点击跳转 文章目录 高项 - 信息化发展信息与信息化信息信息系统信息化 现代化基础设施新型基础设施建设工业互联网车联网 现代化创…

TaskBuilder内设置任擎服务器

TaskBuilder内设置任擎服务器 在使用TaskBuilder进行软件开发时&#xff0c;必须要先连接到任擎服务器&#xff08;后续文档所说的服务器如果不特别注明&#xff0c;皆指任擎服务器&#xff09;才能继续操作&#xff0c;因为使用TaskBuilder开发所需的数据模型、后台服务和前端…

六、nginx负载均衡

负载均衡&#xff1a;将四层或者七层的请求分配到多台后端的服务器上。 从而分担整个业务的负载。提高系统的稳定性&#xff0c;也可以提高高可用&#xff08;备灾&#xff0c;其中一台后端服务器如果发生故障不影响整体业务&#xff09;. 负载均衡的算法 round robin 轮询 r…

代码随想录训练营第十七天| 654.最大二叉树 617.合并二叉树 700.二叉搜索树中的搜索 98.验证二叉搜索树

654.最大二叉树 题目链接/文章讲解&#xff1a; 代码随想录 视频讲解&#xff1a;又是构造二叉树&#xff0c;又有很多坑&#xff01;| LeetCode&#xff1a;654.最大二叉树_哔哩哔哩_bilibili 创建一个根节点&#xff0c;其值为 nums 中的最大值。递归地在最大值 左边 的 子…

面向对象进阶:多态

黑马程序员Java个人笔记 BV17F411T7Ao p129~132 目录 多态 多态调用成员的特点 调用成员变量 调用成员方法 理解 多态的优势 解耦合 多态的弊端 解决方案&#xff1a;强制类型转换 instanceof jdk14新特性&#xff0c;将判断和强转放一起 总结 多态 多态调…

系统思考沙盘模拟

今天《收获季节》沙盘模拟的第一天课程圆满结束&#xff0c;不仅从管理技巧的角度深入展开&#xff0c;还让大家体验了决策带来的直接影响。明天&#xff0c;我们将带领学员从系统思考和全局视角来重新审视这些问题&#xff0c;找到更深层的因果关系和系统性改进的思路。期待更…

AI 赋能直播新玩法 —— 无人直播,它到底藏着多少未知?

​ 在数字浪潮汹涌澎湃的时代&#xff0c;直播领域正历经一场前所未有的变革&#xff0c;AI 赋能的无人直播宛如一颗神秘新星&#xff0c;闯入大众视野&#xff0c;撩拨着人们的好奇心&#xff0c;可它究竟潜藏着多少待解谜团&#xff0c;尚无人能完全洞悉。 从技术的幽微深处…

【深度学习】热力图绘制

热力图&#xff08;Heatmap&#xff09;是一种数据可视化方法&#xff0c;通过颜色来表示数据矩阵中的数值大小&#xff0c;以便更直观地展示数据的分布和模式。热力图在许多领域中都有应用&#xff0c;尤其在统计分析、机器学习、数据挖掘等领域&#xff0c;能够帮助我们快速识…

ssm-springmvc-学习笔记

简介 简单的来说&#xff0c;就是一个在表述层负责和前端数据进行交互的框架 帮我们简化了许多从前端获取数据的步骤 springmvc基本流程 用户在原本的没有框架的时候请求会直接调用到controller这个类&#xff0c;但是其步骤非常繁琐 所以我们就使用springmvc进行简化 当用…

Axure原型设计:打造科技感可视化大屏元件

在数字化时代&#xff0c;数据可视化大屏已成为企业展示数据、监控业务状态的重要工具。一个设计精良的大屏不仅要有丰富的信息展示&#xff0c;更需具备强烈的科技感&#xff0c;以吸引观众的注意力并提升数据解读的效率。Axure&#xff0c;作为一款功能强大的原型设计工具&am…

supervision - 好用的计算机视觉 AI 工具库

Supervision库是一款出色的Python计算机视觉低代码工具&#xff0c;其设计初衷在于为用户提供一个便捷且高效的接口&#xff0c;用以处理数据集以及直观地展示检测结果。简化了对象检测、分类、标注、跟踪等计算机视觉的开发流程。开发者仅需加载数据集和模型&#xff0c;就能轻…

探索 Cesium 的未来:3D Tiles Next 标准解析

探索 Cesium 的未来&#xff1a;3D Tiles Next 标准解析 随着地理信息系统&#xff08;GIS&#xff09;和 3D 空间数据的快速发展&#xff0c;Cesium 作为领先的开源 3D 地球可视化平台&#xff0c;已成为展示大规模三维数据和进行实时渲染的强大工具。近年来&#xff0c;随着…

Launcher启动流程

Launcher启动流程分2个阶段&#xff1a; AMS systemReady() 会启动一个临时Activity&#xff1a;com.android.settings.FallbackHome&#xff0c;如下流程等到用户解锁成功后&#xff0c;FallbackHome轮询到有可用的RealHome包&#xff0c;会销毁掉自己&#xff0c;AMS发现没有…

链式栈的实现及其应用

目录 一、链式栈结构模型 二、链式栈的实现 2.1创建 2.2压栈 2.3出栈 2.4判断栈是否为空 2.5查看栈顶 2.6释放栈 三、应用 链式栈实际上就是基于链表&#xff0c;压栈和弹栈可分别看作头插和头删&#xff0c;链表尾部就是栈底&#xff0c;头指针就是栈顶指针 一、链式…

视频监控汇聚平台方案设计:Liveweb视频智能监管系统方案技术特点与应用

随着科技的发展&#xff0c;视频监控平台在各个领域的应用越来越广泛。然而&#xff0c;当前的视频监控平台仍存在一些问题&#xff0c;如视频质量不高、监控范围有限、智能化程度不够等。这些问题不仅影响了监控效果&#xff0c;也制约了视频监控平台的发展。 为了解决这些问…

Ubuntu 20.04LTS 系统离线安装5.7.44mysql数据库

Ubuntu 20.04LTS 系统离线安装5.7.44mysql数据库 环境下载 MySQL 5.7.44 包安装标题检查服务是否启动成功遇到的问题登陆&修改密码&远程访问 环境 操作系统&#xff1a;Ubuntu 20.04.4 LTS 数据库&#xff1a;MySQL 5.7.34 内核版本&#xff1a;x86_64&#xff08;amd…

国信华源科技赋能长江蓄滞洪区水闸管护项目验收成果报道

“碧水悠悠绕古城&#xff0c;闸启长江万象新。”近日&#xff0c;由北京国信华源科技有限公司倾力打造的万里长江蓄滞洪区水闸管护项目&#xff0c;圆满通过验收&#xff0c;为这片鱼米之乡的防洪安全注入了新的科技活力。 长江之畔&#xff0c;水闸挺立&#xff0c;犹如干堤上…