最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

前端獲取設(shè)備視頻流踩坑實戰(zhàn)記錄

 更新時間:2026年02月12日 11:09:14   作者:悠哉摸魚大王  
在前端開發(fā)中,使用JavaScript讀取視頻流并將其保存為視頻文件是一個常見的需求,尤其是在涉及用戶上傳、本地處理和下載的場景中,這篇文章主要介紹了前端獲取設(shè)備視頻流踩坑實戰(zhàn)的相關(guān)資料,需要的朋友可以參考下

前言

眾所周知,當使用http訪問設(shè)備攝像頭、麥克風(fēng)等,需要在瀏覽器中配置安全策略。但是也會有其他問題。

最近,博主遇到了這樣一個問題,在本地開發(fā)時,可以正常訪問攝像頭和麥克風(fēng),在局域網(wǎng)內(nèi),其他用戶通過IP訪問我的開發(fā)環(huán)境,在配置了瀏覽器安全策略后,也可以訪問麥克風(fēng)攝像頭。但是當項目上線時,在同樣未配置證書的情況下,使用http訪問前端,則無法訪問攝像頭,調(diào)用截圖方法時卻能正確調(diào)用,可以拿到當前視頻幀,瀏覽器也沒有任何報錯。

本來是通過https訪問的,但是由于后端未通過加密通道傳輸,項目也沒有正式上線,只是處于demo狀態(tài),所以還是改為http訪問。如果一定要通過https訪問,那么訪問接口的地址也必須是https/wss,否則屬于混合內(nèi)容,會被瀏覽器攔截。 使用https的情況下,有兩種解決方案:

  1. 后端需要支持TLS握手并提供“可信證書 + 主體匹配”(證書的 SAN 需匹配域名/IP)。否則會變成 TLS/證書錯誤(如NET::ERR_CERT_AUTHORITY_INVALID)
  2. 在前端同源的網(wǎng)關(guān)/Ingress/Nginx 暴露一個 WSS 路徑(同源同證書),再反向代理到后端。

排除問題

一、檢查元素大小是否被影響?

通過devtools發(fā)現(xiàn)元素布局正常,大小無變化,未被遮擋。

二、沒有正確設(shè)置autoplay/playsinline屬性

在一些瀏覽器中,尤其是移動端,如果沒有 autoplay(頁面加載后“嘗試”自動播放視頻。)muted(將音軌靜音)、playsinline(允許在頁面內(nèi)聯(lián)播放) 屬性,視頻流會卡在“有流但不播放”的狀態(tài),導(dǎo)致黑屏但能截圖。 但是我全加了,排除

三、檢查 CSP、安全頭或者 iframe sandbox 限制

如果視頻是在 iframe 或某個帶有 CSP 頭的環(huán)境中(例如 Content-Security-Policy: default-src 'self'),可能媒體流被允許但渲染被限制。

查看頭部信息,未發(fā)現(xiàn)任何限制

四、video 還沒進入播放狀態(tài)

在以上答案都排除后,發(fā)現(xiàn)有流但是未被播放(因為截圖能拿到視頻幀),考慮是video標簽為正確綁定流。 在控制臺中打印video的狀態(tài):

const video = document.querySelector('video');
console.log(video.readyState, video.paused);

獲得的結(jié)果:

0 true

補充說明 readyState 的取值含義:

含義說明
0HAVE_NOTHING還沒有任何關(guān)于視頻的信息
1HAVE_METADATA讀取到了元數(shù)據(jù)(寬高、時長等)
2HAVE_CURRENT_DATA有當前幀數(shù)據(jù),但可能不足以播放
3HAVE_FUTURE_DATA有未來幀,但可能不夠流暢
4HAVE_ENOUGH_DATA可以正常播放

理想情況下,應(yīng)該看到 readyState === 4,并且 video.paused === false。 如果 readyState 長期卡在 2 或 3,而 pausedtrue,那就是 video 播放沒有真正觸發(fā)。這種情況下就算截圖有幀,頁面也會一直黑屏。

也就是說,srcObject 并沒有被正確賦值或者 video 元素還沒在文檔流中,或者被瀏覽器靜默攔截。

我之前的代碼為:

useEffect(() => {
  let isMounted = true
  setIsLoading(true)
  const startCamera = async () => {
    try {
      const stream = await navigator.mediaDevices.getUserMedia({
        video: { facingMode: 'user' },
        audio: false
      })
      if (!isMounted) return
      streamRef.current = stream
      if (videoRef.current) {
        videoRef.current.srcObject = stream
        await videoRef.current.play().catch(() => {})
      }
    } catch {
      setError('無法訪問攝像頭,請檢查權(quán)限')
    } finally {
      setIsLoading(false)
    }
  }
  startCamera()
  return () => {
    isMounted = false
    if (streamRef.current) {
      streamRef.current.getTracks().forEach(track => track.stop())
      streamRef.current = null
    }
  }
}, [])

首先考慮是否自動播放被攔截了,由于await videoRef.current.play().catch(() => {})catch塊里沒有任何處理,如果是被攔截了不會報錯,我們加上錯誤處理后,發(fā)現(xiàn)并沒有走到catch塊了,證明并非是播放被攔截。

查看整個代碼邏輯,如果沒有任何報錯,srcObject也賦值了視頻流。那就只有一個可能:video標簽掛載時間比獲取媒體流的時間要晚,尤其是在dom結(jié)構(gòu)上,設(shè)置了loading狀態(tài)結(jié)束后才渲染video標簽,更能證明這一點。

{isLoading ? (
    <div className='text-white'>加載中...</div>
  ) : error ? (
    <div className='text-white gap-4 flex flex-col items-center'>
      <SvgIcon iconName='Error' />
      {error}
    </div>
  ) : (
    <>
      <video
        ref={videoRef}
        autoPlay
        playsInline
        muted
        className='w-full h-full object-contain rounded-2xl'
      />
    </>
  )}

但是為什么開發(fā)環(huán)境下可以正常訪問呢?就是“時序競態(tài)”問題: 在生產(chǎn)環(huán)境里 getUserMedia 返回得比<video>掛載更早,首次調(diào)用發(fā)生在 videoRef 還為 null 時,綁定被丟失;開發(fā)環(huán)境因為 StrictMode/HMR 導(dǎo)致 effect 被再次執(zhí)行或整體更慢,恰好補上了這次遺漏,所以看不出問題。 按照我的理解,通過設(shè)置斷點:

useEffect(() => {
  let isMounted = true
  setIsLoading(true)
  debugger // 1
  const startCamera = async () => {
    debugger // 2
    try {
      const stream = await navigator.mediaDevices.getUserMedia({
        video: { facingMode: 'user' },
        audio: false
      })
      console.log(isLoading)
      debugger // 3
      setVideoId(videoId + 1)
      if (!isMounted) return
      streamRef.current = stream
      if (videoRef.current) {
        videoRef.current.srcObject = stream
        await videoRef.current.play().catch(() => {})
      }
    } catch {
      setError('無法訪問攝像頭,請檢查權(quán)限')
    } finally {
      debugger //4
      setIsLoading(false)
    }
  }
  startCamera()
  return () => {
    debugger // 5
    isMounted = false
    if (streamRef.current) {
      streamRef.current.getTracks().forEach(track => track.stop())
      streamRef.current = null
    }
  }
}, [])

開發(fā)環(huán)境執(zhí)行順序為:

  1. 執(zhí)行第一次useEffct,執(zhí)行到debugger2處,遇到await掛起,effect返回。
  2. 執(zhí)行第二次useEffct,依舊執(zhí)行到debugger2處,遇到await掛起
  3. 等待第一次await恢復(fù),執(zhí)行到setLoading(false)處,video掛載。
  4. 等待第二次await恢復(fù),執(zhí)行到debugger3處,videoRef.current此時已有值,成功掛載視頻流。

總結(jié)

到此這篇關(guān)于前端獲取設(shè)備視頻流踩坑實戰(zhàn)的文章就介紹到這了,更多相關(guān)前端獲取設(shè)備視頻流內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 基于JavaScript實現(xiàn)網(wǎng)紅太空人表盤的完整代碼

    基于JavaScript實現(xiàn)網(wǎng)紅太空人表盤的完整代碼

    這篇文章主要介紹了基于JavaScript實現(xiàn)網(wǎng)紅太空人表盤的完整代碼,代碼簡單易懂,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-03-03
  • echarts圖表設(shè)置寬度100%結(jié)果為100px的解決辦法

    echarts圖表設(shè)置寬度100%結(jié)果為100px的解決辦法

    在開發(fā)一個前端項目時需要用到Element-ui的el-tabs組件和Echart開源庫,當兩者嵌套使用時,我給Echart中的圖表寬度設(shè)置為了100%,但是實際的寬度卻只有100px,這篇文章主要給大家介紹了關(guān)于echarts圖表設(shè)置寬度100%結(jié)果為100px的解決辦法,需要的朋友可以參考下
    2022-12-12
  • Google 二維條碼 API 整理

    Google 二維條碼 API 整理

    Google 二維條碼 API 整理,需要的朋友可以參考下。
    2010-11-11
  • 分享一款超好用的JavaScript 打包壓縮工具

    分享一款超好用的JavaScript 打包壓縮工具

    這篇文章主要介紹了寫一個飛快的 JavaScript 打包壓縮工具,非常好用,本文給大家分享實現(xiàn)思路,需要的朋友可以參考下
    2020-04-04
  • layui table checked獲取選中數(shù)據(jù)方式

    layui table checked獲取選中數(shù)據(jù)方式

    這篇文章主要介紹了layui table checked獲取選中數(shù)據(jù)方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-10-10
  • 使用JavaScript動態(tài)設(shè)置樣式實現(xiàn)代碼(2)

    使用JavaScript動態(tài)設(shè)置樣式實現(xiàn)代碼(2)

    使用onmouseover和onmouseout事件實現(xiàn)不同的效果而且是使用js動態(tài)實現(xiàn),本文有利于鞏固你js與css方面的知識,感興趣的你可以了解下哦,希望本文對你有所幫助
    2013-01-01
  • JavaScript與Image加載事件(onload)、加載狀態(tài)(complete)

    JavaScript與Image加載事件(onload)、加載狀態(tài)(complete)

    以前寫過一個圖片等比縮放的Js函數(shù),缺陷是要等到所有圖片都加載完畢了,才能進行等比縮放。
    2011-02-02
  • 在JS中如何使用css變量詳解

    在JS中如何使用css變量詳解

    這篇文章主要給大家介紹了關(guān)于如何在JS中如何使用css變量以及export之javascript關(guān)鍵字的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2021-09-09
  • js/jQuery實現(xiàn)全選效果

    js/jQuery實現(xiàn)全選效果

    這篇文章主要為大家詳細介紹了js/jQuery兩種代碼實現(xiàn)全選效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-06-06
  • uni-app h5端在jenkins構(gòu)建報錯解決

    uni-app h5端在jenkins構(gòu)建報錯解決

    這篇文章主要為大家介紹了uni-app h5端在jenkins構(gòu)建報錯解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-06-06

最新評論

湛江市| 临江市| 昌都县| 兰溪市| 岳阳县| 瓮安县| 克拉玛依市| 通海县| 格尔木市| 磐石市| 永嘉县| 土默特左旗| 黎城县| 保亭| 玉环县| 邹平县| 蒙山县| 恭城| 鲁甸县| 资源县| 桦南县| 正定县| 天镇县| 闵行区| 旬邑县| 慈利县| 灵宝市| 北宁市| 重庆市| 宁乡县| 徐水县| 定安县| 清徐县| 汉沽区| 莱州市| 深州市| 舞钢市| 西吉县| 从江县| 栖霞市| 筠连县|