uniapp微信小程序视频实时流+pc端预览方案_uniapp预览视频
纯前端实现
帧率极低
超低频监控
(部分有免费额度)
支持高并发
SDK可能收费
完全可控
维护成本高
(免费试用)
全球节点
绑定厂商
支持CDN分发
❌ 人力成本高
过审风险
免费方案选择建议:
-
完全零成本:
- WebSocket图片帧(仅适合原型验证)
- 开源WebRTC(需技术储备)
-
轻度付费:
- 腾讯云RTMP(免费10GB/月流量)
- 阿里云直播(免费20GB/月流量)
-
企业级推荐:
- 声网Agora(首月赠送1万分钟)
- 即构科技(首月免费)
下面我将介绍WebSocket+图片帧的实现方法:
WebSocket + 图片帧传输方案详解
该方案是 Uniapp微信小程序 + PC端视频实时预览 的一种 低成本、纯前端实现 的技术方案,适用于 低帧率、非严格实时 的场景。
🔹 方案原理
-
小程序端:
- 使用
组件获取实时画面。
- 通过
uni.createCameraContext().takePhoto()
定时拍照(如300ms/次)。 - 将图片转为 Base64 格式,通过 WebSocket 发送到服务器。
- 使用
-
PC端:
- 建立 WebSocket 连接,接收 Base64 图片数据。
- 使用
或连续渲染图片,模拟视频流效果。
uniapp微信小程序端:
export default { data() { return { pushState: \"未连接\", devicePosition: \'front\', flash: \'off\', timer: null, ws: null } }, methods: { flipCamera() { this.devicePosition = this.devicePosition === \'back\' ? \'front\' : \'back\'; }, switchFlash() { this.flash = this.flash === \'off\' ? \'torch\' : \'off\'; }, startPushing() { // 如果已连接,则不再重复连接 if (this.pushState === \'连接成功\') return; const randomToken = new Date().getTime(); const url = \'ws://192.168.1.34:7097/liveWebSocket?linkInfo=a-\' + randomToken; this.ws = uni.connectSocket({ url, success: () => { console.log(\'正在尝试连接WebSocket\', url); } }); this.ws.onOpen(() => { uni.showToast({ title: \'连接成功\' }); this.pushState = \'连接成功\'; this.startCapture(); }); this.ws.onError((err) => { uni.showToast({ title: \'连接异常\', icon: \'none\' }); this.pushState = \'连接异常\'; this.stopPushing(); }); this.ws.onClose(() => { this.pushState = \'已关闭\'; this.stopPushing(); }); }, stopPushing() { if (this.timer) { clearInterval(this.timer); this.timer = null; } if (this.ws) { this.ws.close(); this.ws = null; this.pushState = \"未连接\"; } }, startCapture() { const context = uni.createCameraContext(this); // 调整为300ms间隔,减轻设备压力 this.timer = setInterval(() => { context.takePhoto({ quality: \'low\', success: (res) => { this.processAndSendImage(res.tempImagePath); }, fail: (err) => { console.error(\'拍照失败:\', err); } }); }, 300); }, processAndSendImage(tempImagePath) { uni.getFileSystemManager().readFile({ filePath: tempImagePath, encoding: \'base64\', success: (res) => { const base64Image = `data:image/jpeg;base64,${res.data}`; if (this.ws) { this.ws.send({ data: base64Image, success: () => { console.log(\'图片发送成功\'); this.cleanTempFile(tempImagePath); }, fail: (err) => { console.warn(\'图片发送失败:\', err); } }); } }, fail: (err) => { console.warn(\'读取图片失败:\', err); } }); }, cleanTempFile(filePath) { setTimeout(() => { uni.getFileSystemManager().removeSavedFile({ filePath, success: () => { console.log(\'临时文件已删除\'); }, fail: (err) => { console.warn(\'删除临时文件失败:\', err); } }); }, 2000); }, error(e) { console.error(\'摄像头错误:\', e); } }, onUnload() { this.stopPushing(); }}
pc端预览:
管理员监控页面 0\" style=\"display: flex;\"> 状态:{{item.status}}
接口数据: 视频列表: 0\"> {{item2}}
new Vue({ el: \'#app\', data: { datas: \"\", videos: [ // { // sessionId: \'1\', // status: \'未连接\', // videoSrc: \'\' //图片帧 // } ] }, mounted() { }, methods: { // 开始请求 toSend() { //断开所有webscoket连接 if (this.videos && this.videos.length > 0) { this.videos.forEach(item => { if (item.ws) { item.ws.close(); } }); } this.datas = \"\"; this.videos = []; // 请求直播人员列表 fetch(\'http://192.168.1.34:7097/liveWebStock/getAcceptList\') .then(response => response.json()) .then(data => { if (data.code == 200) { // console.log(6666, data.data); this.datas = data.data; // 初始化每个视频流对象并建立 WebSocket this.videos = data.data.map(item => ({ ...item, status: \'未连接\', videoSrc: \'\', ws: null })); // 建立 WebSocket 连接 this.videos.forEach(item => { this.initWebSocket(item.sessionId); }); } }) .catch(error => { console.error(\'请求直播人员列表失败:\', error); }); }, initWebSocket(sessionId) { if (!sessionId) return; const wsUrl = `ws://192.168.1.34:7097/liveWebSocket?linkInfo=b-${sessionId}`; const index = this.videos.findIndex(v => v.sessionId === sessionId); if (index === -1) return; const ws = new WebSocket(wsUrl); ws.onopen = () => { this.$set(this.videos, index, { ...this.videos[index], status: \'已连接到服务器\', ws }); }; // 处理接收到的数据 ws.onmessage = (event) => { console.log(\"接收到base64图片\", event); // 假设是 base64 数据 const base64Data = event.data; const url = base64Data; this.$set(this.videos, index, { ...this.videos[index], videoSrc: url }); }; ws.onerror = (error) => { this.$set(this.videos, index, { ...this.videos[index], status: `WebSocket 错误: ${error.message}` }); console.error(`WebSocket 错误 (${sessionId}):`, error); }; ws.onclose = () => { this.$set(this.videos, index, { ...this.videos[index], status: \'WebSocket 连接已关闭\' }); }; } } });