国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導航

node.js|vue.js|jquery|angularjs|React|json|js教程|

服務(wù)器之家 - 編程語言 - JavaScript - React - react-media-recorder輕松實現(xiàn)一個錄音、錄像、錄屏工具庫

react-media-recorder輕松實現(xiàn)一個錄音、錄像、錄屏工具庫

2022-03-07 23:02寫代碼的海怪 React

最近項目遇到一個要在網(wǎng)頁上錄音的需求,在一波搜索后,發(fā)現(xiàn)了 react-media-recorder[1] 這個庫。今天就跟大家一起研究一下這個庫的源碼吧,從 0 到 1 來實現(xiàn)一個 React 的錄音、錄像和錄屏功能。

前言

哈嘍,大家好,我是海怪。

最近項目遇到一個要在網(wǎng)頁上錄音的需求,在一波搜索后,發(fā)現(xiàn)了 react-media-recorder[1] 這個庫。今天就跟大家一起研究一下這個庫的源碼吧,從 0 到 1 來實現(xiàn)一個 React 的錄音、錄像和錄屏功能。完整項目代碼放在 Github[2]。

需求與思路

首先要明確我們要完成的事:錄音,錄像,錄屏。

這種錄制媒體流的原理其實很簡單。

只需要記住:把輸入 stream 存放在 blobList,最后轉(zhuǎn)成預(yù)覽blobUrl。

react-media-recorder輕松實現(xiàn)一個錄音、錄像、錄屏工具庫

基礎(chǔ)功能

有了上面的簡單思路后,我們可以先做一個簡單的錄音與錄像功能。

這里先把基礎(chǔ)的 HTML 結(jié)構(gòu)實現(xiàn)了:

const App = () => { const [audioUrl, setAudioUrl] = useState<string>(''); const startRecord = async () => {} const stopRecord = async () => {} return ( <div> <h1>react 錄音h1> <audio src={audioUrl} controls /> <button onClick={startRecord}>開始button> <button>暫停button> <button>恢復(fù)button> <button onClick={stopRecord}>停止button> div> ); }

上面有 開始,暫停,恢復(fù) 以及 停止 四個功能,還加加了一個 來查看錄音結(jié)果。

react-media-recorder輕松實現(xiàn)一個錄音、錄像、錄屏工具庫

之后來實現(xiàn) 開始 與 停止:

const medisStream = useRef<MediaStream>(); const recorder = useRef<MediaRecorder>(); const mediaBlobs = useRef<Blob[]>([]); // 開始
const startRecord = async () => { // 讀取輸入流
  medisStream.current = await navigator.mediaDevices.getUserMedia({ audio: true, video: false }); // 生成 MediaRecorder 對象
  recorder.current = new MediaRecorder(medisStream.current); // 將 stream 轉(zhuǎn)成 blob 來存放
  recorder.current.ondataavailable = (blobEvent) => { mediaBlobs.current.push(blobEvent.data); } // 停止時生成預(yù)覽的 blob url
  recorder.current.onstop = () => { const blob = new Blob(mediaBlobs.current, { type: 'audio/wav' }) const mediaUrl = URL.createObjectURL(blob); setAudioUrl(mediaUrl); } recorder.current?.start(); } // 結(jié)束,不僅讓 MediaRecorder 停止,還要讓所有音軌停止
const stopRecord = async () => { recorder.current?.stop() medisStream.current?.getTracks().forEach((track) => track.stop()); }

從上面可以看到,首先從 getUserMedia 獲取輸入流 mediaStream,以后還可以打開 video: true 來同步獲取視頻流。

然后將 mediaStream 傳給 mediaRecorder,通過 ondataavailable 來存放當前流中的 blob 數(shù)據(jù)。

最后一步,調(diào)用 URL.createObjectURL 來生成預(yù)覽鏈接,這個 API 在前端非常有用,比如上傳圖片時也可以調(diào)用它來實現(xiàn)圖片預(yù)覽,而不需要真的傳到后端才展示預(yù)覽圖片。

在點擊 開始 后,就可以看到當前網(wǎng)頁正在錄音啦:

react-media-recorder輕松實現(xiàn)一個錄音、錄像、錄屏工具庫

現(xiàn)在把剩下的 暫停 以及 恢復(fù) 也實現(xiàn)了:

const pauseRecord = async () => { mediaRecorder.current?.pause(); } const resumeRecord = async () => { mediaRecorder.current?.resume() }

Hooks

在實現(xiàn)簡單功能之后,我們來嘗試一下把上面的功能都封裝成 React Hook,首先把這些邏輯都扔在一個函數(shù)中,然后返回 API:

const useMediaRecorder = () => { const [mediaUrl, setMediaUrl] = useState<string>(''); const mediaStream = useRef<MediaStream>(); const mediaRecorder = useRef<MediaRecorder>(); const mediaBlobs = useRef<Blob[]>([]); const startRecord = async () => { mediaStream.current = await navigator.mediaDevices.getUserMedia({ audio: true, video: false }); mediaRecorder.current = new MediaRecorder(mediaStream.current); mediaRecorder.current.ondataavailable = (blobEvent) => { mediaBlobs.current.push(blobEvent.data); } mediaRecorder.current.onstop = () => { const blob = new Blob(mediaBlobs.current, { type: 'audio/wav' }) const url = URL.createObjectURL(blob); setMediaUrl(url); } mediaRecorder.current?.start(); } const pauseRecord = async () => { mediaRecorder.current?.pause(); } const resumeRecord = async () => { mediaRecorder.current?.resume() } const stopRecord = async () => { mediaRecorder.current?.stop() mediaStream.current?.getTracks().forEach((track) => track.stop()); mediaBlobs.current = []; } return { mediaUrl, startRecord, pauseRecord, resumeRecord, stopRecord, } }

在 App.tsx 里拿到返回值就可以了:

const App = () => { const { mediaUrl, startRecord, resumeRecord, pauseRecord, stopRecord } = useMediaRecorder(); return ( <div> <h1>react 錄音h1> <audio src={mediaUrl} controls /> <button onClick={startRecord}>開始button> <button onClick={pauseRecord}>暫停button> <button onClick={resumeRecord}>恢復(fù)button> <button onClick={stopRecord}>停止button> div> ); }

封裝好之后,現(xiàn)在就可以在這個 Hook 里添加更多的功能了。

清除數(shù)據(jù)

在生成 blob url 的時候我們調(diào)用了 URL.createObjectURL API 來實現(xiàn),生成后的 url 長這樣:

blob:http://localhost:3000/e571f5b7-13bd-4c93-bc53-0c84049deb0a

每次 URL.createObjectURL 后都會生成一個 url -> blob 的引用,這樣的引用也是會占用資源內(nèi)存的,所以我們可以提供一個方法來銷毀這個引用。

const useMediaRecorder = () => { const [mediaUrl, setMediaUrl] = useState<string>(''); ...

  return { ...
    clearBlobUrl: () => { if (mediaUrl) { URL.revokeObjectURL(mediaUrl); } setMediaUrl(''); } } }

錄屏

上面錄音和錄像使用 getUserMedia 來實現(xiàn),而 錄屏則需要調(diào)用 getDisplayMedia 這個接口來實現(xiàn)。

為了能更好地區(qū)分這兩種情況,可以給開發(fā)者提供 audio, video 以及 screen 三個參數(shù),告訴我們應(yīng)該調(diào)哪個接口去獲取對應(yīng)的輸入流數(shù)據(jù):

const useMediaRecorder = (params: Params) => { const { audio = true, video = false, screen = false, askPermissionOnMount = false, } = params; const [mediaUrl, setMediaUrl] = useState<string>(''); const mediaStream = useRef<MediaStream>(); const audioStream = useRef<MediaStream>(); const mediaRecorder = useRef<MediaRecorder>(); const mediaBlobs = useRef<Blob[]>([]); const getMediaStream = useCallback(async () => { if (screen) { // 錄屏接口
      mediaStream.current = await navigator.mediaDevices.getDisplayMedia({ video: true }); mediaStream.current?.getTracks()[0].addEventListener('ended', () => { stopRecord() }) if (audio) { // 添加音頻輸入流
        audioStream.current = await navigator.mediaDevices.getUserMedia({ audio: true }) audioStream.current?.getAudioTracks().forEach(audioTrack => mediaStream.current?.addTrack(audioTrack)); } } else { // 普通的錄像、錄音流
      mediaStream.current = await navigator.mediaDevices.getUserMedia(({ video, audio })) } }, [screen, video, audio]) // 開始錄
  const startRecord = async () => { // 獲取流
    await getMediaStream(); mediaRecorder.current = new MediaRecorder(mediaStream.current!); mediaRecorder.current.ondataavailable = (blobEvent) => { mediaBlobs.current.push(blobEvent.data); } mediaRecorder.current.onstop = () => { const [chunk] = mediaBlobs.current; const blobProperty: BlobPropertyBag = Object.assign( { type: chunk.type }, video ? { type: 'video/mp4' } : { type: 'audio/wav' } ); const blob = new Blob(mediaBlobs.current, blobProperty) const url = URL.createObjectURL(blob); setMediaUrl(url); onStop(url, mediaBlobs.current); } mediaRecorder.current?.start(); } ... }

由于我們已經(jīng)允許用戶來錄視頻以及聲音,所以在生成 URL 時,也要設(shè)置對應(yīng)的 blobProperty 來生成對應(yīng)媒體類型的 blobUrl。

最后在調(diào)用 hook 時傳入 screen: true,可以開啟錄屏功能:

react-media-recorder輕松實現(xiàn)一個錄音、錄像、錄屏工具庫

注意:無論是錄像、錄音、錄屏都是要調(diào)用系統(tǒng)的能力,而網(wǎng)頁只是問瀏覽器要這個能力,但這樣的前提是瀏覽器已經(jīng)擁有了系統(tǒng)權(quán)限了,所以必須在系統(tǒng)設(shè)置里允許瀏覽器有這些權(quán)限才能錄屏。

react-media-recorder輕松實現(xiàn)一個錄音、錄像、錄屏工具庫

上面把獲取媒體流的邏輯都扔在 getMediaStream 函數(shù)里的做法,能很方便地用它來獲取用戶權(quán)限,假如我們想在剛加載這個組件時就獲取用戶攝像頭、麥克風、錄屏權(quán)限,就可以在 useEffect 里調(diào)用它:

useEffect(() => { if (askPermissionOnMount) { getMediaStream().then(); } }, [audio, screen, video, getMediaStream, askPermissionOnMount])

預(yù)覽

錄像只需要在 getUserMedia 的時候設(shè)置 { video: true } 就可以實現(xiàn)錄像了。為了能更方便用戶在使用時能邊錄邊看效果,我們可以把視頻流也返回給用戶:

  return { ...
    getMediaStream: () => mediaStream.current, getAudioStream: () => audioStream.current }

用戶在拿到這些 mediaStream 之后就可以直接賦值到 srcObject 上來進行預(yù)覽了:

<button onClick={() => previewVideo.current!.srcObject = getMediaStream() || null}> 預(yù)覽 button>

react-media-recorder輕松實現(xiàn)一個錄音、錄像、錄屏工具庫

禁音

最后,我們來實現(xiàn)禁音功能,原理也同樣簡單。拿到 audioStream 里面的audioTrack,再將它們設(shè)置 enabled = false 就可以了。

const toggleMute = (isMute: boolean) => { mediaStream.current?.getAudioTracks().forEach(track => track.enabled = !isMute); audioStream.current?.getAudioTracks().forEach(track => track.enabled = !isMute) setIsMuted(isMute); }

使用時可以用它來禁用和開啟聲道:

<button onClick={() => toggleMute(!isMuted)}>{isMuted ? '打開聲音' : '禁音'}button>

總結(jié)上面用 WebRTC 的 API 簡單地實現(xiàn)了一個錄音、錄像、錄屏工具 Hook,這里稍微做下總結(jié)吧:

  • getUserMedia 可用于獲取麥克風以及攝像頭的流
  • getDisplayMedia 則用于獲取屏幕的視頻、音頻流
  • 錄東西的本質(zhì)是 stream -> blobList -> blob url,其中 MediaRecorder 可監(jiān)聽 stream 從而獲取 blob 數(shù)據(jù)
  • MediaRecorder 還提供了開始、結(jié)束、暫停、恢復(fù)等多個與 Record 相關(guān)的接口
  • createObjectURL 與 revokeObjectURL 是反義詞,一個是創(chuàng)建引用,另一個是銷毀
  • 禁音可通過 track.enabled = false 關(guān)閉音軌來實現(xiàn)

這個小工具庫的實現(xiàn)就給大家?guī)У竭@里了,詳情可以查看 react-media-recorder[3] 這個庫的源碼,非常簡潔易懂,很適合入門看源碼的同學!

參考資料

[1]react-media-recorder: https://github.com/0x006F/react-media-recorder

[2]項目代碼: https://github.com/haixiangyan/react-media-recorder

[3]react-media-recorder: https://github.com/0x006F/react-media-recorder

原文地址:https://mp.weixin.qq.com/s/NSahiP_-sa0hDhR0r4YcVQ

延伸 · 閱讀

精彩推薦
  • React詳解antd+react項目遷移vite的解決方案

    詳解antd+react項目遷移vite的解決方案

    這篇文章主要介紹了詳解antd+react項目遷移vite的解決方案,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋...

    福祿網(wǎng)絡(luò)技術(shù)團隊6322022-03-07
  • ReactReact useMemo和useCallback的使用場景

    React useMemo和useCallback的使用場景

    這篇文章主要介紹了React useMemo和useCallback的使用場景,幫助大家更好的理解和學習使用React框架,感興趣的朋友可以了解下...

    woking5012022-02-25
  • ReactReact中使用setInterval函數(shù)的實例

    React中使用setInterval函數(shù)的實例

    這篇文章主要介紹了React中使用setInterval函數(shù)的實例,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友...

    哈工大的許政7512022-02-23
  • ReactReact中useRef的具體使用

    React中useRef的具體使用

    這篇文章主要介紹了React中useRef的具體使用,它可以用來獲取組件實例對象或者是DOM對象,除此之外還有哪些用法,就一起來了解一下...

    Meskjei6382022-02-28
  • Reactreact antd表格中渲染一張或多張圖片的實例

    react antd表格中渲染一張或多張圖片的實例

    這篇文章主要介紹了react antd表格中渲染一張或多張圖片的實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧...

    豆芽不吃豆9062022-03-07
  • React詳解react的兩種動態(tài)改變css樣式的方法

    詳解react的兩種動態(tài)改變css樣式的方法

    這篇文章主要介紹了詳解react的兩種動態(tài)改變css樣式的方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的...

    獨步炎涼的大彬11012022-03-01
  • React詳解React 父組件和子組件的數(shù)據(jù)傳輸

    詳解React 父組件和子組件的數(shù)據(jù)傳輸

    這篇文章主要介紹了React 父組件和子組件的數(shù)據(jù)傳輸?shù)南嚓P(guān)資料,幫助大家更好的理解和學習使用React,感興趣的朋友可以了解下...

    拾階求上11892022-02-28
  • React詳解React中的不可變值

    詳解React中的不可變值

    這篇文章主要介紹了React中的不可變值的相關(guān)資料,幫助大家更好的理解和學習使用react.js,感興趣的朋友可以了解下...

    一個前端王10622022-02-27
主站蜘蛛池模板: 久久国产亚洲精品 | 9191国产视频 | 午夜看片网站 | 午夜激情视频在线 | 国产精品网站在线观看 | 日本黄色大片 | 天天插狠狠插 | 免费日韩在线 | 亚洲a精品 | 成人激情在线视频 | 精品在线视频一区 | 欧美一区二区三区在线视频 | 欧美一级欧美三级在线观看 | av在线电影网 | 福利视频1000 | 一区二区三区在线看 | 成人免费毛片aaaaaa片 | 欧美成人精品在线视频 | 欧美一级在线观看 | 久久视频在线看 | 久久久精品一区二区 | 国产精品亚洲第一区在线暖暖韩国 | 国产成人精品一区二 | 久久精品久久久久久久久久16 | 99在线精品视频 | 成人片免费看 | 综合色导航 | 成人黄色在线观看 | 不卡一二三区 | 中文av一区二区 | 成人久| 欧美一区二区在线播放 | 亚洲青涩在线 | 91亚洲精品一区 | 精品av| 国产成人精品免费视频 | 成人免费一区二区三区视频软件 | 久久综合一区二区三区 | 久久久久亚洲精品 | 一区久久| 久久精品无码一区二区日韩av |