JSを使用して、サウンドレコーディング、ビデオレコーディング、スクリーンレコーディングツールライブラリを簡単に実装できます。

序文

みなさん、こんにちは。私は海の怪物です。

最近、プロジェクトでWebページに記録する必要が生じました。検索の波の後、react-media-recorder [1]ライブラリが見つかりました。今日は、このライブラリのソースコードを0から1まで調べて、React録画、ビデオ録画、および画面録画機能を実現しましょう。

完全なプロジェクトコードはGithubに配置されています[2]

ニーズとアイデア

まず、何を達成したいのかを明確にする必要があります。オーディオ録音ビデオ録画スクリーン録画です。

この記録メディアストリームの原理は、実際には非常に単純です。

69addac35fb7004985392a0ffc038a91.png

覚えておいてください:入力をstream保存blobListし、最後にプレビューに変換しblobUrlます。

82fb3279d1a768856828c0a05279156f.png

基本機能

上記の簡単なアイデアで、最初に簡単な録画およびビデオ録画機能を作成できます。

ここでは、最初に基本的なHTML構造を実装します。

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>恢复</button>
      <button onClick={stopRecord}>停止</button>
    </div>
  );
}

开始上記の、、、および4つの関数暂停に加えて、記録結果を表示するための関数があります。恢复停止<audio>

50abdc951b79799ab90bc67ba7927ed0.png

その後、達成するため开始停止

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 转成 blob 来存放
  recorder.current.ondataavailable = (blobEvent) => {
    mediaBlobs.current.push(blobEvent.data);
  }
  // 停止时生成预览的 blob url
  recorder.current.onstop = () => {
    const blob = new Blob(mediaBlobs.current, { type: 'audio/wav' })
    const mediaUrl = URL.createObjectURL(blob);
    setAudioUrl(mediaUrl);
  }

  recorder.current?.start();
}

// 结束,不仅让 MediaRecorder 停止,还要让所有音轨停止
const stopRecord = async () => {
  recorder.current?.stop()
  medisStream.current?.getTracks().forEach((track) => track.stop());
}

上記からわかるように、最初にから入力ストリームをgetUserMedia取得しmediaStream、後で開いvideo: trueて。

次に、にmediaStream渡してデータを現在のストリームに保存します。mediaRecorderondataavailableblob

最後のステップは、プレビューリンクURL.createObjectURLをです。このAPIは、フロントエンドで非常に便利です。たとえば、画像をアップロードするときに、実際に画像を送信せずに、画像のプレビューを実現するために呼び出すこともできます。プレビュー画像を表示するためのバックエンド。

开始クリックすると、現在のWebページが記録されていることがわかります。

d339d601cbaab156a2fbba240d97284f.png

次に、残りの部分と次の機能も暂停実装します。恢复

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

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

フック

単純な関数を実装した後、上記の関数をReact Hooksにカプセル化して、最初にこれらすべてのロジックを関数にスローしてから、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}>恢复</button>
      <button onClick={stopRecord}>停止</button>
    </div>
  );
}

パッケージ化したら、このフックに機能を追加します。

明確なデータ

blob URLを生成するとき、URL.createObjectURLこれを実現するためにAPIを呼び出します。生成されたURLは次のようになります。

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

URL.createObjectURLの参照は毎回生成されurl -> blob、そのような参照もリソースメモリを占有するため、この参照を破棄する方法を提供できます。

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

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

スクリーンレコーディング

上記のオーディオおよびビデオの記録getUserMediaは、画面の記録はgetDisplayMediaこのあります。

これら2つの状況をより適切に区別するために、開発者にaudiovideoおよびscreen3つのパラメーターを提供して、対応する入力ストリームデータを取得するために呼び出すインターフェイスを指定できます。

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();
  }
  
  ...
}

ユーザーがビデオとサウンドを記録できるようにしたため、URLを生成するときに、対応するメディアタイプblobPropertyblobUrl

最後に、フックが呼び出されるscreen: trueと、画面記録機能をオンにできます。

e71296e5fbde7802a173af858feb67d0.png

注:ビデオ録画、オーディオ録画、画面録画のいずれであっても、システムを呼び出す機能であり、Webページはブラウザにこの機能を要求するだけですが、ブラウザがすでにシステム権限を持っていることが前提です。システム設定での閲覧を許可する必要があります。デバイスには、画面を記録するためのこれらの権限があります。

9e81659871adaac3c47335aa9946b30d.png

メディアストリームを取得するロジックをgetMediaStream関数ユーザーのアクセス許可を取得するために簡単に使用できます。コンポーネントがロードされた直後にユーザーのカメラ、マイク、および画面の記録のアクセス許可を取得する場合は、これを使用できます。でuseEffectそれを呼び出します:

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

プレビュー

ビデオ録画を実現するgetUserMediaは、その。{ video: true }ユーザーが録画中にエフェクトをより見やすくするために、ビデオストリームをユーザーに返すこともできます。

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

これらを取得した後mediaStream、はsrcObjectプレビュー用に直接割り当てることができます。

<button onClick={() => previewVideo.current!.srcObject = getMediaStream() || null}>
    预览
</button>
5af9dd6a900af8adf5150b25e1fced08.png

ミュート

最後に、ミュート機能を実装しましょう。原理も同様に単純です。audioStream内部を取得し、それらaudioTrackを設定します。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>

要約する

上記では、WebRTC APIを使用して、録画、ビデオ、および画面録画ツールのフックを実装しています。簡単な要約は次のとおりです。

  • getUserMediaカメラだけでなくマイクからのストリームを取得するために使用できます

  • getDisplayMedia画面のビデオおよびオーディオストリームを取得するために使用されます

  • 物事を記録することの本質は、データを取得するためstream -> blobList -> blob urlにそれらを監視MediaRecorderできることですstreamblob

  • MediaRecorderまた、開始、終了、一時停止、再開などの複数のレコード関連のインターフェイスも提供します

  • createObjectURLrevokeObjectURLは反意語であり、一方は参照を作成し、もう一方は破棄します

  • ミューティングは、オーディオトラックをtrack.enabled = false閉じる

この小さなツールライブラリの実装はここにあります。詳細については、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

おすすめ

転載: blog.csdn.net/qq_36538012/article/details/123887655