首頁  >  文章  >  web前端  >  WebCodec - 發送和接收

WebCodec - 發送和接收

Patricia Arquette
Patricia Arquette原創
2024-10-09 16:35:02565瀏覽

介紹

您好! ?

在本教學中,我將向您展示如何使用 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 結構
    • 視訊元素顯示來自使用者相機的即時視訊
    • canvas 元素用於顯示視訊來源的各個影格。這提供了每個編碼幀的視覺預覽
  2. JavaScript 程式碼
    • initWebSocket 函數連接到 WebSocket 伺服器。此連接對於將編碼幀串流傳輸到接收器至關重要
    • initEncoder 函式建立一個 VideoEncoder 物件。它定義了一個輸出回調,該回調在編碼器每次生成新區塊時運行
    • videoEncoder.configure() 將編解碼器設定為 VP8,碼率 1Mbps,FPS 30,確保流暢、高品質的編碼
    • getUserMedia 呼叫用於請求存取相機。視訊來源被分配給視訊元素,VideoTrackProcessor 允許即時處理每一幀
    • processFrames 函數從影片中讀取幀,將它們顯示在 canvas 元素上,並使用 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
    • canvas 元素是解碼視訊畫面的主要顯示區域。它有固定的寬度、高度和邊框,與寄件者頁面相同。
  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/ehand91/webcodec-stream

快樂編碼! ?


喜歡我的作品嗎?我的貼文內容很豐富,如果你想看更多,請按讚並追蹤我。
我也喜歡咖啡。

WebCodec - Sending and Receiving

如果您想學習演算法模式以在程式設計面試中取得好成績,我推薦[以下課程](https://algolab.so/p/algorithms-and-data-struct-video-course?affcode=1413380_bzrepgch

以上是WebCodec - 發送和接收的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn