ホームページ  >  記事  >  ウェブフロントエンド  >  WebCodec - 送受信

WebCodec - 送受信

Patricia Arquette
Patricia Arquetteオリジナル
2024-10-09 16:35:02678ブラウズ

導入

こんにちは! ?

このチュートリアルでは、WebCodec API を使用してビデオの送信と受信の両方を行う方法を説明します。

まず、サーバーのコーディングを始めましょう。


サーバーのセットアップ

ピア間でパケットを送受信するには、WebSocket サーバーが必要です。

このために、nodejs を使用して非常に基本的なサーバーを作成します。まずプロジェクトを初期化します:

npm init -y

次に、必要なモジュールをインストールします。

npm i ws express

次に、「index.js」という新しいファイルを作成し、次のコードを入力します。

// server.js
const WebSocket = require('ws');
const express = require('express');

const app = express();
const port = 3000;
const connectedClients = new Set();

app.use(express.static(__dirname + '/public'));

const wss = new WebSocket.Server({ noServer: true });

wss.on('connection', ws => {
  console.log('new connection');
  connectedClients.add(ws);

  ws.on('message', message => {
    connectedClients.forEach(client => {
      if (client !== ws && client.readyState === WebSocket.OPEN) {
        client.send(message);
      }
    });
  });

  ws.once('close', () => {
    connectedClients.delete(ws);
    console.log('connection closed');
  });
});

const server = app.listen(port, () => {
  console.log(`server running on port ${port}`);
});

server.on('upgrade', (request, socket, head) => {
  wss.handleUpgrade(request, socket, head, (ws) => {
    wss.emit('connection', ws, request);
  });
});

上記のコードはそれほど複雑なことはなく、パブリック ディレクトリにサービスを提供し、接続されているすべてのピアにパケットを送信する WebSocket 接続を処理します。 ?

次に送信側の部分を処理しますが、最初に「public」という名前の新しいディレクトリを作成します

mkdir public

送信者の作成

最初に作成するフロントエンド ファイルはブロードキャストするもので、public の下に「sender.html」という新しいファイルを作成し、次の HTML を入力します。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    <title>Sender</title>
    <style>
      video, canvas {
        width: 640px;
        height: 480px;
        border: 2px solid black;
        margin: 10px;
      }
    </style>
  </head>
  <body>
    <video id="video" autoplay playsinline></video>
    <canvas id="canvas" width="640" height="480"></canvas>

    <script>
      const videoElement = document.getElementById('video');
      const canvas = document.getElementById('canvas');
      const ctx = canvas.getContext('2d');
      let videoEncoder;
      let socket;

      const initWebSocket = () => {
        socket = new WebSocket('ws://localhost:3000');

        socket.onopen = () => console.log('WebSocket connected');
        socket.onerror = error => console.error('WebSocket error:', error);
      };

      const initEncoder = () => {
        videoEncoder = new VideoEncoder({
          output: (encodedChunk) => {
            const chunkData = new Uint8Array(encodedChunk.byteLength);
            encodedChunk.copyTo(chunkData);

            if (socket.readyState === WebSocket.OPEN) {
              socket.send(chunkData.buffer);
            }
          },
          error: (error) => console.error('Encoding error:', error)
        });

        videoEncoder.configure({
          codec: 'vp8',
          width: 640,
          height: 480,
          bitrate: 1_000_000,
          framerate: 30
        });
      };

      navigator.mediaDevices.getUserMedia({ video: true })
        .then((stream) => {
          videoElement.srcObject = stream;
          const videoTrack = stream.getVideoTracks()[0];
          const processor = new MediaStreamTrackProcessor(videoTrack);
          const reader = processor.readable.getReader();

          const processFrames = async () => {
            while (true) {
              const { value: videoFrame, done } = await reader.read();
              if (done) break;

              ctx.drawImage(videoFrame, 0, 0, canvas.width, canvas.height);
              videoEncoder.encode(videoFrame, { keyFrame: true });
              videoFrame.close();
            }
          };

          processFrames();
        })
        .catch((error) => console.error('Failed to get camera', error));

        initEncoder();
        initWebSocket();
    </script>
  </body>
</html>

コードの動作を詳細に説明します。

  1. HTML 構造
    • video 要素は、ユーザーのカメラからのライブビデオを表示します
    • canvas 要素は、ビデオ フィードの個々のフレームを表示するために使用されます。これにより、エンコードされた各フレームの視覚的なプレビューが提供されます
  2. JavaScript コード
    • initWebSocket 関数は WebSocket サーバーに接続します。この接続は、エンコードされたフレームを受信機にストリーミングするために不可欠です
    • initEncoder 関数は VideoEncoder オブジェクトを作成します。エンコーダーが新しいチャンクを生成するたびに実行される出力コールバックを定義します
    • videoEncoder.configure() は、コーデックを 1Mbps ビットレートおよび 30 FPS の VP8 に設定し、スムーズで高品質のエンコードを保証します
    • getUserMedia 呼び出しは、カメラへのアクセスをリクエストするために使用されます。ビデオ フィードは video 要素に割り当てられ、VideoTrackProcessor により各フレームをリアルタイムで処理できます
    • processFrames 関数は、ビデオからフレームを読み取り、キャンバス要素に表示し、videoEncoder.encode() を使用して各フレームをエンコードします。その後、各フレームはエンコードされたチャンクとしてサーバーに送信されます。

ふぅ!ご理解いただければ幸いです。次にストリームを受信するファイルを作成します。 ?


レシーバーの作成

このファイルは、WebSocket 経由でエンコードされたビデオ チャンクを受信し、デコードして、キャンバス要素に表示します。

パブリック ディレクトリの下に「receiver.html」という名前の新しいファイルを作成し、次の情報を入力します。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    <title>Receiver</title>
    <style>
      canvas {
        width: 640px;
        height: 480px;
        border: 2px solid black;
        margin: 10px;
      }
    </style>
  </head>
  <body>
    <canvas id="canvas" width="640" height="480"></canvas>

    <script>
      const canvas = document.getElementById('canvas');
      const ctx = canvas.getContext('2d');
      let videoDecoder;

      const initWebSocket = () => {
        const socket = new WebSocket('ws://localhost:3000');
        socket.binaryType = 'arraybuffer';

        socket.onmessage = event => {
          decodeFrame(event.data);
        };
        socket.onerror = error => console.error('WebSocket error:', error);
      };

      const initDecoder = () => {
        videoDecoder = new VideoDecoder({
          output: (videoFrame) => {
            ctx.drawImage(videoFrame, 0, 0, canvas.width, canvas.height);
            videoFrame.close();
          },
          error: (error) => console.error('Decoding error:', error)
        });

        videoDecoder.configure({
          codec: 'vp8',
          width: 640,
          height: 480
        });
      };

      const decodeFrame = (encodedData) => {
        const chunk = new EncodedVideoChunk({
          type: 'key',
          timestamp: performance.now(),
          data: new Uint8Array(encodedData)
        });

        videoDecoder.decode(chunk);
      };

      initDecoder();
      initWebSocket();
    </script>
  </body>
</html>

上記のファイルを分解するには:

  1. HTML
    • キャンバス要素は、デコードされたビデオ フレームの主な表示領域です。送信者ページと同じように、幅、高さ、境界線が固定されています。
  2. JavaScript
    • initWebSocket 関数は新しい WebSocket 接続を作成し、送信者からエンコードされたフレームを受信し、デコードのためにそれらを decodeFrame() に渡します。
    • initDecoder は、VP8 コーデック用に構成された VideoDecoder オブジェクトを初期化します。デコーダは各フレームをキャンバスに出力します。
    • decodeFrame は、エンコードされたデータを取得し、(現在のタイムスタンプを持つキーフレームとして) EncodedVideoChunk にラップし、videoDecoder.decode() を介してデコードします。各フレームはリアルタイムでキャンバスに表示されます

ふぅ!必要な要素がすべて揃ったので、実際に実行してみましょう。 ?


コードの実行

コードを実行するには、次のコマンドを実行するだけです:

node index.js

次に、ブラウザで http://localhost:3000/sender.html にアクセスします
カメラへのアクセスを許可してから、別のタブを開いて
http://localhost:3000/receiver.html

以下のように、送信者から送信されたストリームが表示されるはずです。

WebCodec - Sending and Receiving


結論

このチュートリアルでは、カメラにアクセスし、それをエンコードし、WebSocket 経由でチャンクを送信し、受信側でデコードして表示する方法を説明しました。このチュートリアルがお役に立てば幸いです。 ?

いつものように、コードは私の github から入手できます:
https://github.com/ethand91/webcodec-stream

コーディングを楽しんでください! ?


私の作品が好きですか?さまざまなトピックについて投稿しています。もっと見たい場合は、「いいね!」とフォローしてください。
あとコーヒーも大好きです。

WebCodec - Sending and Receiving

コーディング面接に合格するためにアルゴリズム パターンを学習したい場合は、[次のコース](https://algolab.so/p/algorithms-and-data-structural-video-course?affcode=1413380_bzrepgch

以上がWebCodec - 送受信の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。