uniapp微信小程序視頻實時流+pc端預覽方案

方案類型技術實現是否免費優點缺點適用場景延遲范圍開發復雜度
?WebSocket+圖片幀?定時拍照+Base64傳輸? 完全免費無需服務器
純前端實現
高延遲高流量
幀率極低
個人demo測試
超低頻監控
500ms-2s??
?RTMP推流?TRTC/即構SDK推流? 付費方案
(部分有免費額度)
專業直播方案
支持高并發
需流媒體服務器
SDK可能收費
中小型直播場景1-3s????
?開源WebRTC?自建coturn+mediasoup? 開源免費超低延遲
完全可控
需自建信令服務器
維護成本高
技術團隊內網項目200-500ms?????
?商業WebRTC?騰訊TRTC/聲網Agora? 付費方案
(免費試用)
企業級服務
全球節點
按流量/時長計費
綁定廠商
商業視頻通話應用200-800ms????
?HLS切片方案?FFmpeg切片+nginx? 服務器可自建免費兼容所有瀏覽器
支持CDN分發
延遲10秒以上非實時錄播場景10s+???
?UDP自定義協議?開發原生插件? 協議層免費
? 人力成本高
完全自定義優化需原生開發能力
過審風險
軍工/工業特殊場景200-500ms??????

免費方案選擇建議:

  1. ?完全零成本?:

    • WebSocket圖片幀(僅適合原型驗證)
    • 開源WebRTC(需技術儲備)
  2. ?輕度付費?:

    • 騰訊云RTMP(免費10GB/月流量)
    • 阿里云直播(免費20GB/月流量)
  3. ?企業級推薦?:

    • 聲網Agora(首月贈送1萬分鐘)
    • 即構科技(首月免費)

下面我將介紹WebSocket+圖片幀的實現方法:

?

?WebSocket + 圖片幀傳輸方案詳解?

該方案是 ?Uniapp微信小程序 + PC端視頻實時預覽? 的一種 ?低成本、純前端實現? 的技術方案,適用于 ?低幀率、非嚴格實時? 的場景。


?🔹 方案原理?

  1. ?小程序端?:

    • 使用?<camera>?組件獲取實時畫面。
    • 通過?uni.createCameraContext().takePhoto()??定時拍照?(如300ms/次)。
    • 將圖片轉為 ?Base64? 格式,通過 ?WebSocket? 發送到服務器。
  2. ?PC端?:

    • 建立 WebSocket 連接,接收 Base64 圖片數據。
    • 使用?<img>?或?<canvas>??連續渲染圖片,模擬視頻流效果。

uniapp微信小程序端:

<template><view><camera :device-position="devicePosition" :flash="flash" @error="error" style="width:100%; height:300px;"></camera><button @click="startPushing">開始推流</button><button @click="stopPushing">停止推流</button><button @click="switchFlash">切換閃光燈</button><button @click="flipCamera">翻轉攝像頭</button><button style="font-size: 24rpx;">webscoket連接狀態:{{pushState}}</button></view>
</template><script>
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();}
}
</script>

pc端預覽:

<!DOCTYPE html>
<html lang="zh-CN"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>管理員監控頁面</title><script src="./vue2.js"></script>
</head><body><div id="app"><button @click="toSend">開始請求</button><div v-if="videos && videos.length> 0" style="display: flex;"><div v-for="item in videos" :key="item.sessionId" style="margin: 10px;display: flex;flex-flow: column;":id="item.sessionId">狀態:{{item.status}}<img :src="item.videoSrc" style="width: 200px; height: 200px; border: 1px solid red;" alt=""></div></div><div style="background-color: green;margin: 20px 0;display: flex;width: 50%;word-wrap: break-word">接口數據:<div v-html="datas"></div></div><div style="background-color: red;width: 50%">視頻列表:<template v-if="videos && videos.length> 0"><p v-for="item2 in videos">{{item2}}</p></template></div></div><script>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 連接已關閉'});};}}});</script>
</body></html>

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/86507.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/86507.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/86507.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

分布式鎖實戰:Redisson vs. Redis 原生指令的性能對比

分布式鎖實戰&#xff1a;Redisson vs. Redis 原生指令的性能對比 引言 在DIY主題模板系統中&#xff0c;用戶可自定義聊天室的背景、圖標、動畫等元素。當多個運營人員或用戶同時修改同一模板時&#xff0c;若沒有鎖機制&#xff0c;可能出現“甲修改了背景色&#xff0c;乙…

C++ 設計模式《復制粘貼的奇跡:小明的原型工廠》

&#x1f468;?&#x1f393; 模式名稱&#xff1a;原型模式&#xff08;Prototype Pattern&#xff09; &#x1f4d6; 背景故事 創業初期&#xff0c;小明每天加班寫配送路線、配送策略、營銷套餐。可當業務做大后&#xff0c;他發現大家常常下單“上次那個套餐”—— “老…

【Elasticsearch】映射:fielddata 詳解

映射&#xff1a;fielddata 詳解 1.fielddata 是什么2.fielddata 的工作原理3.主要用法3.1 啟用 fielddata&#xff08;通常在 text 字段上&#xff09;3.2 監控 fielddata 使用情況3.3 清除 fielddata 緩存 4.使用場景示例示例 1&#xff1a;對 text 字段進行聚合示例 2&#…

開源 vGPU 方案:HAMi,實現細粒度 GPU 切分

本文主要分享一個開源的 GPU 虛擬化方案&#xff1a;HAMi&#xff0c;包括如何安裝、配置以及使用。 相比于上一篇分享的 TimeSlicing 方案&#xff0c;HAMi 除了 GPU 共享之外還可以實現 GPU core、memory 得限制&#xff0c;保證共享同一 GPU 的各個 Pod 都能拿到足夠的資源。…

PlayDiffusion上線:AI語音編輯進入“無痕時代”

在語音合成與語音編輯領域&#xff0c;一個長期存在的挑戰是如何在修改語音內容的同時&#xff0c;保持原始語音的自然性、連貫性和說話人特征。近日&#xff0c;一款名為 PlayDiffusion 的新型 AI 語音修復模型應運而生&#xff0c;成功實現了這一目標。 PlayDiffusion 是一個…

2025年能源電力系統與流體力學國際會議 (EPSFD 2025)

2025年能源電力系統與流體力學國際會議&#xff08;EPSFD 2025&#xff09;將于本年度在美麗的杭州盛大召開。作為全球能源、電力系統以及流體力學領域的頂級盛會&#xff0c;EPSFD 2025旨在為來自世界各地的科學家、工程師和研究人員提供一個展示最新研究成果、分享實踐經驗及…

微信小程序前端面經

一、技術棧與編碼能力&#xff08;10min&#xff09; 1. Vue 3 & Composition API Q1&#xff1a;請解釋一下 ref 和 reactive 的區別&#xff1f;你在項目中是如何使用的&#xff1f; 答&#xff1a;ref是包裝一個原始值或對象&#xff0c;通過.value訪問&#xff0c;r…

rknn toolkit2搭建和推理

安裝Miniconda Miniconda - Anaconda Miniconda 選擇一個 新的 版本 &#xff0c;不用和RKNN的python版本保持一致 使用 ./xxx.sh進行安裝 下面配置一下載源 # 清華大學源&#xff08;最常用&#xff09; conda config --add channels https://mirrors.tuna.tsinghua.edu.cn…

WordPress插件:AI多語言寫作與智能配圖、免費AI模型、SEO文章生成

厭倦手動寫WordPress文章&#xff1f;AI自動生成&#xff0c;效率提升10倍&#xff01; 支持多語言、自動配圖、定時發布&#xff0c;讓內容創作更輕松&#xff01; AI內容生成 → 不想每天寫文章&#xff1f;AI一鍵生成高質量內容&#xff01;多語言支持 → 跨境電商必備&am…

Houdini POP入門學習07 - 分組

使用PopGroup可對粒子進行分組操作&#xff0c;并通過表達式從而更靈活的處理粒子行為。 1.創建box作為發射器&#xff0c;連接popnet節點。 2.雙擊進入popnet&#xff0c;添加popwind添加向上風力。現在播放粒子可見粒子向上方移動。 3.添加popgroup進行分組&#xff0c;開啟…

機器學習復習3--模型評估

誤差與過擬合 我們將學習器對樣本的實際預測結果與樣本的真實值之間的差異稱為&#xff1a;誤差&#xff08;error&#xff09;。 誤差定義&#xff1a; ①在訓練集上的誤差稱為訓練誤差&#xff08;training error&#xff09;或經驗誤差&#xff08;empirical error&#x…

Docker 鏡像上傳到 AWS ECR:從構建到推送的全流程

一、在 EC2 實例中安裝 Docker&#xff08;適用于 Amazon Linux 2&#xff09; 步驟 1&#xff1a;連接到 EC2 實例 ssh -i your-key.pem ec2-useryour-ec2-public-ip步驟 2&#xff1a;安裝 Docker sudo yum update -y sudo amazon-linux-extras enable docker sudo yum in…

MobileNet 改進:基于MobileNetV2和SSPP的圖像分類

1.創新點分析 在計算機視覺領域,高效的圖像分類模型一直是研究熱點。 本文將詳細解析一個結合了MobileNetV2和空間金字塔池化(SSPP)的深度學習模型實現。 模型概述 這個代碼實現了一個輕量級但功能強大的圖像分類器,主要包含兩個核心組件: MobileNetV2作為特征提取器 自定…

Java中List的forEach用法詳解

在 Java 中&#xff0c;List.forEach() 是 Java 8 引入的一種簡潔的遍歷集合元素的方法。它基于函數式編程思想&#xff0c;接受一個 Consumer 函數式接口作為參數&#xff0c;用于對集合中的每個元素執行操作。 基本語法 java 復制 下載 list.forEach(consumer); 使用示…

涂鴉T5AI手搓語音、emoji、otto機器人從入門到實戰

“&#x1f916;手搓TuyaAI語音指令 &#x1f60d;秒變表情包大師&#xff0c;讓萌系Otto機器人&#x1f525;玩出智能新花樣&#xff01;開整&#xff01;” &#x1f916; Otto機器人 → 直接點明主體 手搓TuyaAI語音 → 強調 自主編程/自定義 語音控制&#xff08;TuyaAI…

計算機視覺與深度學習 | 基于MATLAB的相機標定

基于MATLAB的相機標定:原理、步驟與代碼實現 相機標定 基于MATLAB的相機標定:原理、步驟與代碼實現MATLAB相機標定完整流程1. 準備工作2. 采集標定圖像3. 導入圖像并檢測角點4. 生成世界坐標5. 執行相機標定6. 分析標定結果7. 應用標定結果校正圖像相機標定關鍵概念相機參數類…

物聯網專業核心課程以及就業方向

物聯網專業作為信息技術與產業應用深度融合的交叉學科&#xff0c;其課程體系覆蓋硬件、軟件、網絡、數據等全鏈條技術&#xff0c;就業方向則隨智能技術普及呈現多元化趨勢。以下是基于最新行業動態與教育實踐的系統分析&#xff1a; &#x1f4da; 一、物聯網專業核心課程體系…

mac 安裝homebrew (nvm 及git)

mac 安裝nvm 及git 萬惡之源 mac 安裝這些東西離不開Xcode。及homebrew 一、先說安裝git步驟 通用&#xff1a; 方法一&#xff1a;使用 Homebrew 安裝 Git&#xff08;推薦&#xff09; 步驟如下&#xff1a;打開終端&#xff08;Terminal.app&#xff09; 1.安裝 Homebrew…

vue3 定時器-定義全局方法 vue+ts

1.創建ts文件 路徑&#xff1a;src/utils/timer.ts 完整代碼&#xff1a; import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 創建定時器con…

線性代數證明:把行列式的某一行(列)的k倍加到另一行(列),行列式的值不變

線性代數證明 把行列式的某一行&#xff08;列&#xff09;的k倍加到另一行&#xff08;列&#xff09;&#xff0c;行列式的值不變&#xff1a; 注意五角星的位置要用到另一條性質&#xff1a;若行列式的某一行&#xff08;列&#xff09;的元素都是兩數之和&#xff0c;則可以…